[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#456315: kdelibs, kdebase: KDE Xinerama improvement patches



Package: kdebase
Version: 4:3.5.8.dfsg.1-4
Severity: wishlist
Tags: patch, upstream

The patches were made originally by Lubos Lunak 
(http://ktown.kde.org/~seli/xinerama/). Patches add these improvements:

* Alt+tab list of windows can be restriced to a single screen;
* shortcut for moving the active window to a specific/other Xinerama screen;
* possibility of configuring on which Xinerama screen new windows will be
  placed;
* newly launched applications appear on the same Xinerama screen where minicli
  was shown;
* possibility of configuring the active Xinerama screen to be the one with the
  active window instead of the one with the cursor;
* shortcut for activating specific/other Xinerama screen.

For details please see the website.

I have adapted them for Debian packages without Qt modifications.

Aleksey
diff -padurx debian kdelibs-3.5.8.dfsg.1/kdecore/kstartupinfo.cpp kdelibs-3.5.8.dfsg.1-patched/kdecore/kstartupinfo.cpp
--- kdelibs-3.5.8.dfsg.1/kdecore/kstartupinfo.cpp	2007-12-14 16:03:25.000000000 +0300
+++ kdelibs-3.5.8.dfsg.1-patched/kdecore/kstartupinfo.cpp	2007-12-14 16:08:23.000000000 +0300
@@ -1109,7 +1109,7 @@ unsigned long KStartupInfoId::timestamp(
 struct KStartupInfoDataPrivate
     {
     KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
-	silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {}
+	silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ), xinerama( -1 ), launched_by( 0 ) {}
     QString bin;
     QString name;
     QString description;
@@ -1121,6 +1121,8 @@ struct KStartupInfoDataPrivate
     KStartupInfoData::TriState silent;
     unsigned long timestamp;
     int screen;
+    int xinerama;
+    WId launched_by;
     };
 
 QString KStartupInfoData::to_text() const
@@ -1151,6 +1153,10 @@ QString KStartupInfoData::to_text() cons
         ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
     if( d->screen != -1 )
         ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
+    if( d->xinerama != -1 )
+        ret += QString::fromLatin1( " XINERAMA=%1" ).arg( d->xinerama );
+    if( d->launched_by != 0 )
+        ret += QString::fromLatin1( " LAUNCHED_BY=%1" ).arg( d->launched_by );
     return ret;
     }
 
@@ -1169,6 +1175,8 @@ KStartupInfoData::KStartupInfoData( cons
     const QString silent_str = QString::fromLatin1( "SILENT=" );
     const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" );
     const QString screen_str = QString::fromLatin1( "SCREEN=" );
+    const QString xinerama_str = QString::fromLatin1( "XINERAMA=" );
+    const QString launched_by_str = QString::fromLatin1( "LAUNCHED_BY=" );
     for( QStringList::Iterator it = items.begin();
          it != items.end();
          ++it )
@@ -1199,6 +1207,10 @@ KStartupInfoData::KStartupInfoData( cons
             d->timestamp = get_unum( *it );
         else if( ( *it ).startsWith( screen_str ))
             d->screen = get_num( *it );
+        else if( ( *it ).startsWith( xinerama_str ))
+            d->xinerama = get_num( *it );
+        else if( ( *it ).startsWith( launched_by_str ))
+            d->launched_by = get_num( *it );
         }
     }
 
@@ -1242,6 +1254,10 @@ void KStartupInfoData::update( const KSt
         d->timestamp = data_P.timestamp();
     if( data_P.screen() != -1 )
         d->screen = data_P.screen();
+    if( data_P.xinerama() != -1 && xinerama() != -1 ) // don't overwrite
+        d->xinerama = data_P.xinerama();
+    if( data_P.launchedBy() != 0 && launchedBy() != 0 ) // don't overwrite
+        d->launched_by = data_P.launchedBy();
     }
 
 KStartupInfoData::KStartupInfoData()
@@ -1412,6 +1428,26 @@ int KStartupInfoData::screen() const
     return d->screen;
     }
 
+void KStartupInfoData::setXinerama( int xinerama )
+    {
+    d->xinerama = xinerama;
+    }
+
+int KStartupInfoData::xinerama() const
+    {
+    return d->xinerama;
+    }
+
+void KStartupInfoData::setLaunchedBy( WId window )
+    {
+    d->launched_by = window;
+    }
+
+WId KStartupInfoData::launchedBy() const
+    {
+    return d->launched_by;
+    }
+
 static
 long get_num( const QString& item_P )
     {
diff -padurx debian kdelibs-3.5.8.dfsg.1/kdecore/kstartupinfo.h kdelibs-3.5.8.dfsg.1-patched/kdecore/kstartupinfo.h
--- kdelibs-3.5.8.dfsg.1/kdecore/kstartupinfo.h	2007-01-15 14:34:17.000000000 +0300
+++ kdelibs-3.5.8.dfsg.1-patched/kdecore/kstartupinfo.h	2007-12-14 16:05:14.000000000 +0300
@@ -635,6 +635,30 @@ class KDECORE_EXPORT KStartupInfoData
          * This is usually not necessary to set, as it's set by default to qt_xscreen().
          */
         void setScreen( int screen );
+        
+        /**
+         * The Xinerama screen for the startup notification, -1 if unknown.
+         */
+        int xinerama() const;
+
+        /**        
+	 * Sets the Xinerama screen for the startup notification ( i.e. the screeen on which
+	 * the starting application should appear ).
+	 * @param xinerama the Xinerama screen for the startup notification
+         */
+        void setXinerama( int xinerama );
+
+        /**
+         * The toplevel window of the application that caused this startup notification,
+         * 0 if unknown.
+         */
+        WId launchedBy() const;
+        
+        /**
+	 * Sets the toplevel window of the application that caused this startup notification.
+	 * @param window window ID of the toplevel window that is responsible for this startup
+         */
+        void setLaunchedBy( WId window );
 
 	/**
 	 * Updates the notification data from the given data. Some data, such as the desktop
diff -padurx debian kdelibs-3.5.8.dfsg.1/kio/kio/krun.cpp kdelibs-3.5.8.dfsg.1-patched/kio/kio/krun.cpp
--- kdelibs-3.5.8.dfsg.1/kio/kio/krun.cpp	2006-10-01 21:33:32.000000000 +0400
+++ kdelibs-3.5.8.dfsg.1-patched/kio/kio/krun.cpp	2007-12-14 16:05:14.000000000 +0300
@@ -77,6 +77,7 @@ public:
     QString m_localPath;
     QString m_suggestedFileName;
     QGuardedPtr <QWidget> m_window;
+    QCString m_asn;
 };
 
 pid_t KRun::runURL( const KURL& u, const QString& _mimetype )
@@ -109,14 +110,20 @@ bool KRun::isExecutableFile( const KURL&
   return false;
 }
 
-// This is called by foundMimeType, since it knows the mimetype of the URL
 pid_t KRun::runURL( const KURL& u, const QString& _mimetype, bool tempFile, bool runExecutables, const QString& suggestedFileName )
 {
+    return runURL( u, _mimetype, NULL, "", tempFile, runExecutables, suggestedFileName );
+}
+
+// This is called by foundMimeType, since it knows the mimetype of the URL
+pid_t KRun::runURL( const KURL& u, const QString& _mimetype, QWidget* window, const QCString& asn,
+    bool tempFile, bool runExecutables, const QString& suggestedFileName )
+{
   bool noRun = false;
   bool noAuth = false;
   if ( _mimetype == "inode/directory-locked" )
   {
-    KMessageBoxWrapper::error( 0L,
+    KMessageBoxWrapper::error( window,
             i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>").arg(u.htmlURL()) );
     return 0;
   }
@@ -133,7 +140,7 @@ pid_t KRun::runURL( const KURL& u, const
       {
         QString path = u.path();
         shellQuote( path );
-        return (KRun::runCommand(path)); // just execute the url as a command
+        return (KRun::runCommand(path, QString::null, QString::null, window, asn)); // just execute the url as a command
         // ## TODO implement deleting the file if tempFile==true
       }
       else
@@ -155,14 +162,14 @@ pid_t KRun::runURL( const KURL& u, const
 
   if ( noRun )
   {
-    KMessageBox::sorry( 0L,
+    KMessageBox::sorry( window,
         i18n("<qt>The file <b>%1</b> is an executable program. "
              "For safety it will not be started.</qt>").arg(u.htmlURL()));
     return 0;
   }
   if ( noAuth )
   {
-    KMessageBoxWrapper::error( 0L,
+    KMessageBoxWrapper::error( window,
         i18n("<qt>You do not have permission to run <b>%1</b>.</qt>").arg(u.htmlURL()) );
     return 0;
   }
@@ -182,7 +189,7 @@ pid_t KRun::runURL( const KURL& u, const
     return displayOpenWithDialog( lst, tempFile, suggestedFileName );
   }
 
-  return KRun::run( *offer, lst, 0 /*window*/, tempFile, suggestedFileName );
+  return KRun::run( *offer, lst, window, asn, tempFile, suggestedFileName );
 }
 
 bool KRun::displayOpenWithDialog( const KURL::List& lst )
@@ -536,13 +543,13 @@ QString KRun::binaryName( const QString 
 }
 
 static pid_t runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
-    const QString &execName, const QString & iconName )
+    const QString &execName, const QString & iconName, QWidget* window, QCString asn )
 {
   if (service && !service->desktopEntryPath().isEmpty()
       && !KDesktopFile::isAuthorizedDesktopFile( service->desktopEntryPath() ))
   {
      kdWarning() << "No authorization to execute " << service->desktopEntryPath() << endl;
-     KMessageBox::sorry(0, i18n("You are not authorized to execute this file."));
+     KMessageBox::sorry(window, i18n("You are not authorized to execute this file."));
      return 0;
   }
   QString bin = KRun::binaryName( binName, true );
@@ -550,10 +557,10 @@ static pid_t runCommandInternal( KProces
   bool silent;
   QCString wmclass;
   KStartupInfoId id;
-  bool startup_notify = KRun::checkStartupNotify( binName, service, &silent, &wmclass );
+  bool startup_notify = ( asn != "0" && KRun::checkStartupNotify( binName, service, &silent, &wmclass ));
   if( startup_notify )
   {
-      id.initId();
+      id.initId( asn );
       id.setupStartupEnv();
       KStartupInfoData data;
       data.setHostname();
@@ -572,6 +579,8 @@ static pid_t runCommandInternal( KProces
       if( silent )
           data.setSilent( KStartupInfoData::Yes );
       data.setDesktop( KWin::currentDesktop());
+      if( window )
+          data.setLaunchedBy( window->winId());
       KStartupInfo::sendStartup( id, data );
   }
   pid_t pid = KProcessRunner::run( proc, binName, id );
@@ -629,7 +638,8 @@ bool KRun::checkStartupNotify( const QSt
   return true;
 }
 
-static pid_t runTempService( const KService& _service, const KURL::List& _urls, bool tempFiles, const QString& suggestedFileName )
+static pid_t runTempService( const KService& _service, const KURL::List& _urls, QWidget* window,
+    const QCString& asn, bool tempFiles, const QString& suggestedFileName )
 {
   if (!_urls.isEmpty()) {
     kdDebug(7010) << "runTempService: first url " << _urls.first().url() << endl;
@@ -648,7 +658,7 @@ static pid_t runTempService( const KServ
       {
          KURL::List singleUrl;
          singleUrl.append(*it);
-         runTempService( _service, singleUrl, tempFiles, suggestedFileName );
+         runTempService( _service, singleUrl, window, "", tempFiles, suggestedFileName );
       }
       KURL::List singleUrl;
       singleUrl.append(_urls.first());
@@ -667,7 +677,7 @@ static pid_t runTempService( const KServ
      proc->setWorkingDirectory(_service.path());
 
   return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
-                             _service.name(), _service.icon() );
+                             _service.name(), _service.icon(), window, asn );
 }
 
 // WARNING: don't call this from processDesktopExec, since klauncher uses that too...
@@ -728,11 +738,22 @@ pid_t KRun::run( const KService& _servic
 
 pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles )
 {
-    return run( _service, _urls, window, tempFiles, QString::null );
+    return run( _service, _urls, window, "", tempFiles, QString::null );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, const QCString& asn, bool tempFiles )
+{
+    return run( _service, _urls, window, asn, tempFiles, QString::null );
 }
 
 pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles, const QString& suggestedFileName )
 {
+    return run( _service, _urls, window, "", tempFiles, suggestedFileName );
+}
+
+pid_t KRun::run( const KService& _service, const KURL::List& _urls, QWidget* window, const QCString& asn,
+    bool tempFiles, const QString& suggestedFileName )
+{
   if (!_service.desktopEntryPath().isEmpty() &&
       !KDesktopFile::isAuthorizedDesktopFile( _service.desktopEntryPath()))
   {
@@ -753,7 +774,7 @@ pid_t KRun::run( const KService& _servic
 
   if ( tempFiles || _service.desktopEntryPath().isEmpty() || !suggestedFileName.isEmpty() )
   {
-     return runTempService(_service, _urls, tempFiles, suggestedFileName);
+     return runTempService(_service, _urls, window, asn, tempFiles, suggestedFileName);
   }
 
   kdDebug(7010) << "KRun::run " << _service.desktopEntryPath() << endl;
@@ -767,9 +788,25 @@ pid_t KRun::run( const KService& _servic
 
   QString error;
   int pid = 0;
-
+  
+  QCString myasn = asn;
+  // startServiceByDesktopPath() doesn't take QWidget*, add it to the startup info now
+  if( window != NULL )
+  {
+    if( myasn.isEmpty())
+        myasn = KStartupInfo::createNewStartupId();
+    if( myasn != "0" )
+    {
+        KStartupInfoId id;
+        id.initId( myasn );
+        KStartupInfoData data;
+        data.setLaunchedBy( window->winId());
+        KStartupInfo::sendChange( id, data );
+    }
+  }
+  
   int i = KApplication::startServiceByDesktopPath(
-        _service.desktopEntryPath(), urls.toStringList(), &error, 0L, &pid
+        _service.desktopEntryPath(), urls.toStringList(), &error, 0L, &pid, myasn
         );
 
   if (i != 0)
@@ -794,33 +831,47 @@ pid_t KRun::run( const QString& _exec, c
 
 pid_t KRun::runCommand( QString cmd )
 {
-  return KRun::runCommand( cmd, QString::null, QString::null );
+  return KRun::runCommand( cmd, QString::null, QString::null, NULL, "" );
 }
 
 pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName )
 {
+  return KRun::runCommand( cmd, execName, iconName, NULL, "" );
+}
+
+pid_t KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName,
+    QWidget* window, const QCString& asn )
+{
   kdDebug(7010) << "runCommand " << cmd << "," << execName << endl;
   KProcess * proc = new KProcess;
   proc->setUseShell(true);
   *proc << cmd;
   KService::Ptr service = KService::serviceByDesktopName( binaryName( execName, true ) );
-  return runCommandInternal( proc, service.data(), binaryName( execName, false ), execName, iconName );
+  return runCommandInternal( proc, service.data(), binaryName( execName, false ), execName, iconName,
+      window, asn );
 }
 
 KRun::KRun( const KURL& url, mode_t mode, bool isLocalFile, bool showProgressInfo )
      :m_timer(0,"KRun::timer")
 {
-  init (url, 0, mode, isLocalFile, showProgressInfo);
+  init (url, 0, "", mode, isLocalFile, showProgressInfo);
 }
 
 KRun::KRun( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
             bool showProgressInfo )
      :m_timer(0,"KRun::timer")
 {
-  init (url, window, mode, isLocalFile, showProgressInfo);
+  init (url, window, "", mode, isLocalFile, showProgressInfo);
 }
 
-void KRun::init ( const KURL& url, QWidget* window, mode_t mode, bool isLocalFile,
+KRun::KRun( const KURL& url, QWidget* window, const QCString& asn, mode_t mode, bool isLocalFile,
+            bool showProgressInfo )
+     :m_timer(0,"KRun::timer")
+{
+  init (url, window, asn, mode, isLocalFile, showProgressInfo);
+}
+
+void KRun::init ( const KURL& url, QWidget* window, const QCString& asn, mode_t mode, bool isLocalFile,
                   bool showProgressInfo )
 {
   m_bFault = false;
@@ -836,6 +887,7 @@ void KRun::init ( const KURL& url, QWidg
   d = new KRunPrivate;
   d->m_runExecutables = true;
   d->m_window = window;
+  d->m_asn = asn;
   setEnableExternalBrowser(true);
 
   // Start the timer. This means we will return to the event
@@ -936,7 +988,7 @@ void KRun::init()
        KService::Ptr service = KService::serviceByStorageId( exec );
        if (service)
        {
-          run( *service, urls );
+          run( *service, urls, d->m_window, d->m_asn );
           ok = true;
        }
     }
@@ -1229,7 +1281,7 @@ void KRun::foundMimeType( const QString&
       {
           KURL::List lst;
           lst.append( m_strURL );
-          m_bFinished = KRun::run( *serv, lst );
+          m_bFinished = KRun::run( *serv, lst, d->m_window, d->m_asn );
           /// Note: the line above means that if that service failed, we'll
           /// go to runURL to maybe find another service, even though a dialog
           /// box was displayed. That's good if runURL tries another service,
@@ -1244,7 +1296,7 @@ void KRun::foundMimeType( const QString&
     m_strURL.setPath( d->m_localPath );
   }
 
-  if (!m_bFinished && KRun::runURL( m_strURL, type, false, d->m_runExecutables, d->m_suggestedFileName )){
+  if (!m_bFinished && KRun::runURL( m_strURL, type, d->m_window, d->m_asn, false, d->m_runExecutables, d->m_suggestedFileName )){
     m_bFinished = true;
   }
   else{
diff -padurx debian kdelibs-3.5.8.dfsg.1/kio/kio/krun.h kdelibs-3.5.8.dfsg.1-patched/kio/kio/krun.h
--- kdelibs-3.5.8.dfsg.1/kio/kio/krun.h	2006-05-22 22:14:17.000000000 +0400
+++ kdelibs-3.5.8.dfsg.1-patched/kio/kio/krun.h	2007-12-14 16:05:14.000000000 +0300
@@ -111,6 +111,8 @@ public:
    */
   KRun( const KURL& url, QWidget* window, mode_t mode = 0,
 	bool isLocalFile = false, bool showProgressInfo = true );
+  KRun( const KURL& url, QWidget* window, const QCString& asn, mode_t mode = 0,
+	bool isLocalFile = false, bool showProgressInfo = true );
 
   /**
    * Destructor. Don't call it yourself, since a KRun object auto-deletes
@@ -210,6 +212,8 @@ public:
    * @since 3.5.2
    */
   static pid_t run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles = false );
+  static pid_t run( const KService& _service, const KURL::List& _urls, QWidget* window,
+      const QCString& asn, bool tempFiles = false );
   /**
    * Open a list of URLs with a certain service (application).
    *
@@ -226,6 +230,8 @@ public:
   /// @since 3.5.3
   /// @internal
   static pid_t run( const KService& _service, const KURL::List& _urls, QWidget* window, bool tempFiles, const QString& suggestedFileName );
+  static pid_t run( const KService& _service, const KURL::List& _urls, QWidget* window,
+      const QCString& asn, bool tempFiles, const QString& suggestedFileName );
 
   /**
    * Open a list of URLs with.
@@ -269,6 +275,7 @@ public:
   static pid_t runURL( const KURL& _url, const QString& _mimetype );
   /// @since 3.5.3
   /// @internal
+  static pid_t runURL( const KURL& _url, const QString& _mimetype, QWidget* window, const QCString& asn, bool tempFile, bool runExecutables, const QString& suggestedFileName );
   static pid_t runURL( const KURL& _url, const QString& _mimetype, bool tempFile, bool runExecutables, const QString& suggestedFileName );
 
   /**
@@ -299,6 +306,8 @@ public:
    * of running command) if command was unsafe for map notification.
    */
   static pid_t runCommand( const QString& cmd, const QString & execName, const QString & icon );
+  static pid_t runCommand( const QString& cmd, const QString & execName, const QString & icon,
+      QWidget* window, const QCString& asn );
 
   /**
    * Display the Open-With dialog for those URLs, and run the chosen application.
@@ -438,7 +447,7 @@ protected:
   virtual void virtual_hook( int id, void* data );
 
 private:
-  void init (const KURL& url, QWidget* window, mode_t mode,
+  void init (const KURL& url, QWidget* window, const QCString& asn, mode_t mode,
              bool isLocalFile, bool showProgressInfo);
 private:
   class KRunPrivate;
diff -padurx debian kdebase-3.5.8.dfsg.1/kdesktop/minicli.cpp kdebase-3.5.8.dfsg.1-patched/kdesktop/minicli.cpp
--- kdebase-3.5.8.dfsg.1/kdesktop/minicli.cpp	2007-01-15 14:32:10.000000000 +0300
+++ kdebase-3.5.8.dfsg.1-patched/kdesktop/minicli.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -369,6 +369,17 @@ int Minicli::runCommand()
     cmd = uri.path();
   else
     cmd = uri.url();
+    
+  QCString asn;
+  if( qApp->desktop()->isVirtualDesktop())
+  {
+    asn = KStartupInfo::createNewStartupId();
+    KStartupInfoId id;
+    id.initId( asn );
+    KStartupInfoData data;
+    data.setXinerama( qApp->desktop()->screenNumber( this ));
+    KStartupInfo::sendChange( id, data );
+  }
 
   // Determine whether the application should be run through
   // the command line (terminal) interface...
@@ -504,7 +515,7 @@ int Minicli::runCommand()
         case KURIFilterData::HELP:
         {
           // No need for kfmclient, KRun does it all (David)
-          (void) new KRun( m_filterData->uri(), parentWidget());
+          (void) new KRun( m_filterData->uri(), parentWidget(), asn );
           return 0;
         }
         case KURIFilterData::EXECUTABLE:
@@ -516,7 +527,7 @@ int Minicli::runCommand()
             if (service && service->isValid() && service->type() == "Application")
             {
               notifyServiceStarted(service);
-              KRun::run(*service, KURL::List());
+              KRun::run(*service, KURL::List(), parentWidget(), asn );
               return 0;
             }
           }
@@ -551,7 +562,7 @@ int Minicli::runCommand()
           if (service && service->isValid() && service->type() == "Application")
           {
             notifyServiceStarted(service);
-            KRun::run(*service, KURL::List(), this);
+            KRun::run(*service, KURL::List(), parentWidget(), asn );
             return 0;
           }
 
@@ -559,7 +570,7 @@ int Minicli::runCommand()
           if (service && service->isValid() && service->type() == "Application")
           {
             notifyServiceStarted(service);
-            KRun::run(*service, KURL::List(), this);
+            KRun::run(*service, KURL::List(), parentWidget(), asn );
             return 0;
           }
 
@@ -571,7 +582,7 @@ int Minicli::runCommand()
       }
     }
 
-    if ( KRun::runCommand( cmd, exec, m_iconName ) )
+    if ( KRun::runCommand( cmd, exec, m_iconName, parentWidget(), asn ) )
       return 0;
     else
     {
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/activation.cpp kdebase-3.5.8.dfsg.1-patched/kwin/activation.cpp
--- kdebase-3.5.8.dfsg.1/kwin/activation.cpp	2007-10-08 13:51:32.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/activation.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -360,6 +360,8 @@ void Workspace::takeActivity( Client* c,
         return;
         }
     c->takeActivity( flags, handled, Allowed );
+    if( !c->isOnScreen( active_screen ))
+        active_screen = c->screen();
     }
 
 void Workspace::handleTakeActivity( Client* c, Time /*timestamp*/, int flags )
@@ -413,6 +415,13 @@ bool Workspace::activateNextClient( Clie
                 {
                 if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
                     continue;
+                if( options->separateScreenFocus )
+                    {
+                    if( c != NULL && !(*it)->isOnScreen( c->screen()))
+                        continue;
+                    if( c == NULL && !(*it)->isOnScreen( activeScreen()))
+                        continue;
+                    }
                 if( mainwindows.contains( *it ))
                     {
                     get_focus = *it;
@@ -438,6 +447,31 @@ bool Workspace::activateNextClient( Clie
     return true;
     }
 
+void Workspace::setCurrentScreen( int new_screen )
+    {
+    if (new_screen < 0 || new_screen > numScreens())
+        return;
+    if ( !options->focusPolicyIsReasonable())
+        return;
+    closeActivePopup();
+    Client* get_focus = NULL;
+    for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast();
+         it != focus_chain[currentDesktop()].end();
+         --it )
+        {
+        if( !(*it)->isShown( false ) || !(*it)->isOnCurrentDesktop())
+            continue;
+        if( !(*it)->screen() == new_screen )
+            continue;
+        get_focus = *it;
+        break;
+        }
+    if( get_focus == NULL )
+        get_focus = findDesktop( true, currentDesktop());
+    if( get_focus != NULL && get_focus != mostRecentlyActivatedClient())
+        requestFocus( get_focus );
+    active_screen = new_screen;
+    }
 
 void Workspace::gotFocusIn( const Client* c )
     {
@@ -860,6 +894,8 @@ void Client::startupIdChanged()
         desktop = asn_data.desktop();
     if( !isOnAllDesktops())
         workspace()->sendClientToDesktop( this, desktop, true );
+    if( asn_data.xinerama() != -1 )
+        workspace()->sendClientToScreen( this, asn_data.xinerama());
     Time timestamp = asn_id.timestamp();
     if( timestamp == 0 && asn_data.timestamp() != -1U )
         timestamp = asn_data.timestamp();
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/client.cpp kdebase-3.5.8.dfsg.1-patched/kwin/client.cpp
--- kdebase-3.5.8.dfsg.1/kwin/client.cpp	2007-05-14 11:55:48.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/client.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -1255,6 +1255,20 @@ bool Client::isOnCurrentDesktop() const
     return isOnDesktop( workspace()->currentDesktop());
     }
 
+int Client::screen() const
+    {
+    if( !options->xineramaEnabled )
+        return 0;
+    return workspace()->screenNumber( geometry().center());
+    }
+
+bool Client::isOnScreen( int screen ) const
+    {
+    if( !options->xineramaEnabled )
+        return screen == 0;
+    return workspace()->screenGeometry( screen ).intersects( geometry());
+    }
+
 // performs activation and/or raising of the window
 void Client::takeActivity( int flags, bool handled, allowed_t )
     {
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/client.h kdebase-3.5.8.dfsg.1-patched/kwin/client.h
--- kdebase-3.5.8.dfsg.1/kwin/client.h	2007-05-14 11:55:48.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/client.h	2007-12-14 15:23:26.000000000 +0300
@@ -118,6 +118,9 @@ class Client : public QObject, public KD
         bool isOnCurrentDesktop() const;
         bool isOnAllDesktops() const;
         void setOnAllDesktops( bool set );
+        
+        bool isOnScreen( int screen ) const; // true if it's at least partially there
+        int screen() const; // the screen where the center is
 
     // !isMinimized() && not hidden, i.e. normally visible on some virtual desktop
         bool isShown( bool shaded_is_shown ) const;
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/geometry.cpp kdebase-3.5.8.dfsg.1-patched/kwin/geometry.cpp
--- kdebase-3.5.8.dfsg.1/kwin/geometry.cpp	2007-05-14 11:55:48.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/geometry.cpp	2007-12-14 15:29:11.000000000 +0300
@@ -211,14 +211,11 @@ void Workspace::updateClientArea()
 
   \sa geometry()
  */
-QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const
+QRect Workspace::clientArea( clientAreaOption opt, int screen, int desktop ) const
     {
     if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
         desktop = currentDesktop();
     QDesktopWidget *desktopwidget = KApplication::desktop();
-    int screen = desktopwidget->isVirtualDesktop() ? desktopwidget->screenNumber( p ) : desktopwidget->primaryScreen();
-    if( screen < 0 )
-        screen = desktopwidget->primaryScreen();
     QRect sarea = screenarea // may be NULL during KWin initialization
         ? screenarea[ desktop ][ screen ]
         : desktopwidget->screenGeometry( screen );
@@ -263,11 +260,21 @@ QRect Workspace::clientArea( clientAreaO
     return QRect();
     }
 
+QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const
+    {
+    QDesktopWidget *desktopwidget = KApplication::desktop();
+    int screen = desktopwidget->screenNumber( p );
+    if( screen < 0 )
+        screen = desktopwidget->primaryScreen();
+    return clientArea( opt, screen, desktop );
+    }
+
 QRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
     {
     return clientArea( opt, c->geometry().center(), c->desktop());
     }
 
+
 /*!
   Client \a c is moved around to position \a pos. This gives the
   workspace the opportunity to interveniate and to implement
@@ -896,10 +903,6 @@ void Client::checkWorkspacePosition()
             setGeometry( area );
         return;
         }
-    if( maximizeMode() != MaximizeRestore )
-	// TODO update geom_restore?
-        changeMaximize( false, false, true ); // adjust size
-
     if( isFullScreen())
         {
         QRect area = workspace()->clientArea( FullScreenArea, this );
@@ -926,6 +929,10 @@ void Client::checkWorkspacePosition()
         return;
         }
 
+    if( maximizeMode() != MaximizeRestore )
+	// TODO update geom_restore?
+        changeMaximize( false, false, true ); // adjust size
+
     if( !isShade()) // TODO
         {
         int old_diff_x = workarea_diff_x;
@@ -1721,6 +1728,7 @@ void Client::setGeometry( int x, int y, 
     sendSyntheticConfigureNotify();
     updateWindowRules();
     checkMaximizeGeometry();
+    workspace()->checkActiveScreen( this );
     }
 
 void Client::plainResize( int w, int h, ForceGeometry_t force )
@@ -1774,6 +1782,7 @@ void Client::plainResize( int w, int h, 
     sendSyntheticConfigureNotify();
     updateWindowRules();
     checkMaximizeGeometry();
+    workspace()->checkActiveScreen( this );
     }
 
 /*!
@@ -1794,6 +1803,7 @@ void Client::move( int x, int y, ForceGe
     sendSyntheticConfigureNotify();
     updateWindowRules();
     checkMaximizeGeometry();
+    workspace()->checkActiveScreen( this );
     }
 
 
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/kcmkwin/kwinoptions/windows.cpp kdebase-3.5.8.dfsg.1-patched/kwin/kcmkwin/kwinoptions/windows.cpp
--- kdebase-3.5.8.dfsg.1/kwin/kcmkwin/kwinoptions/windows.cpp	2006-10-01 21:32:07.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/kcmkwin/kwinoptions/windows.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -76,6 +76,8 @@
 #define KWIN_SHADEHOVER_INTERVAL   "ShadeHoverInterval"
 #define KWIN_FOCUS_STEALING        "FocusStealingPreventionLevel"
 #define KWIN_HIDE_UTILITY          "HideUtilityWindowsForInactive"
+#define KWIN_SEPARATE_SCREEN_FOCUS "SeparateScreenFocus"
+#define KWIN_ACTIVE_MOUSE_SCREEN   "ActiveMouseScreen"
 
 // kwm config keywords
 #define KWM_ELECTRIC_BORDER                  "ElectricBorders"
@@ -209,6 +211,27 @@ KFocusConfig::KFocusConfig (bool _standA
     QWhatsThis::add( delayFocus, i18n("This is the delay after which the window the mouse pointer is over"
                                        " will automatically receive focus.") );
 
+    separateScreenFocus = new QCheckBox( i18n( "S&eparate screen focus" ), fcsBox );
+    fLay->addWidget( separateScreenFocus );
+    wtstr = i18n( "When this option is enabled, focus operations are limited only to the active Xinerama screen" );
+    QWhatsThis::add( separateScreenFocus, wtstr );
+
+    activeMouseScreen = new QCheckBox( i18n( "Active &mouse screen" ), fcsBox );
+    fLay->addWidget( activeMouseScreen );
+    wtstr = i18n( "When this option is enabled, active Xinerama screen (where for example new windows appear)"
+                  " is the screen with the mouse pointer. When disabled, the active Xinerama screen is the screen"
+                  " with the focused window. This option is by default disabled for Click to focus and"
+                  " enabled for other focus policies." );
+    QWhatsThis::add( activeMouseScreen, wtstr );
+    connect(focusCombo, SIGNAL(activated(int)), this, SLOT(updateActiveMouseScreen()));
+
+    if (!QApplication::desktop()->isVirtualDesktop() ||
+        QApplication::desktop()->numScreens() == 1) // No Ximerama 
+    {
+        separateScreenFocus->hide();
+        activeMouseScreen->hide();
+    }
+
     lay->addWidget(fcsBox);
 
     kbdBox = new QButtonGroup(i18n("Navigation"), this);
@@ -260,6 +283,8 @@ KFocusConfig::KFocusConfig (bool _standA
     connect(fcsBox, SIGNAL(clicked(int)), SLOT(changed()));
     connect(autoRaise, SIGNAL(valueChanged(int)), SLOT(changed()));
     connect(delayFocus, SIGNAL(valueChanged(int)), SLOT(changed()));
+    connect(separateScreenFocus, SIGNAL(clicked()), SLOT(changed()));
+    connect(activeMouseScreen, SIGNAL(clicked()), SLOT(changed()));
     connect(altTabPopup, SIGNAL(clicked()), SLOT(changed()));
     connect(traverseAll, SIGNAL(clicked()), SLOT(changed()));
     connect(rollOverDesktops, SIGNAL(clicked()), SLOT(changed()));
@@ -366,6 +391,22 @@ void KFocusConfig::delayFocusOnTog(bool 
 void KFocusConfig::clickRaiseOnTog(bool ) {
 }
 
+void KFocusConfig::setSeparateScreenFocus(bool s) {
+    separateScreenFocus->setChecked(s);
+}
+
+void KFocusConfig::setActiveMouseScreen(bool a) {
+    activeMouseScreen->setChecked(a);
+}
+
+void KFocusConfig::updateActiveMouseScreen()
+{
+    // on by default for non click to focus policies
+    KConfigGroup cfg( config, "Windows" );
+    if( !cfg.hasKey( KWIN_ACTIVE_MOUSE_SCREEN ))
+        setActiveMouseScreen( focusCombo->currentItem() != 0 );
+}
+
 void KFocusConfig::setAltTabMode(bool a) {
     altTabPopup->setChecked(a);
 }
@@ -412,6 +453,10 @@ void KFocusConfig::load( void )
     setClickRaise(key != "off");
     setAutoRaiseEnabled();      // this will disable/hide the auto raise delay widget if focus==click
     setDelayFocusEnabled();
+    
+    setSeparateScreenFocus( config->readBoolEntry(KWIN_SEPARATE_SCREEN_FOCUS, false));
+    // on by default for non click to focus policies
+    setActiveMouseScreen( config->readBoolEntry(KWIN_ACTIVE_MOUSE_SCREEN, focusCombo->currentItem() != 0 ));
 
     key = config->readEntry(KWIN_ALTTABMODE, "KDE");
     setAltTabMode(key == "KDE");
@@ -467,6 +512,9 @@ void KFocusConfig::save( void )
     else
         config->writeEntry(KWIN_CLICKRAISE, "off");
 
+    config->writeEntry(KWIN_SEPARATE_SCREEN_FOCUS, separateScreenFocus->isChecked());
+    config->writeEntry(KWIN_ACTIVE_MOUSE_SCREEN, activeMouseScreen->isChecked());
+
     if (altTabPopup->isChecked())
         config->writeEntry(KWIN_ALTTABMODE, "KDE");
     else
@@ -500,6 +548,9 @@ void KFocusConfig::defaults()
     setAutoRaise(false);
     setDelayFocus(false);
     setClickRaise(true);
+    setSeparateScreenFocus( false );
+    // on by default for non click to focus policies
+    setActiveMouseScreen( focusCombo->currentItem() != 0 );
     setAltTabMode(true);
     setTraverseAll( false );
     setRollOverDesktops(true);
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/kcmkwin/kwinoptions/windows.h kdebase-3.5.8.dfsg.1-patched/kwin/kcmkwin/kwinoptions/windows.h
--- kdebase-3.5.8.dfsg.1/kwin/kcmkwin/kwinoptions/windows.h	2006-05-22 22:13:01.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/kcmkwin/kwinoptions/windows.h	2007-12-14 15:23:26.000000000 +0300
@@ -86,6 +86,7 @@ private slots:
   void delayFocusOnTog(bool);
   void clickRaiseOnTog(bool);
   void updateAltTabMode();
+  void updateActiveMouseScreen();
 	void changed() { emit KCModule::changed(true); }
 
 
@@ -101,6 +102,8 @@ private:
   void setDelayFocusInterval(int);
   void setDelayFocus(bool);
   void setClickRaise(bool);
+  void setSeparateScreenFocus(bool);
+  void setActiveMouseScreen(bool);
   void setAltTabMode(bool);
   void setTraverseAll(bool);
   void setRollOverDesktops(bool);
@@ -113,6 +116,8 @@ private:
   QCheckBox *clickRaiseOn;
   KIntNumInput *autoRaise;
   KIntNumInput *delayFocus;
+  QCheckBox *separateScreenFocus;
+  QCheckBox *activeMouseScreen;
 
   QButtonGroup *kbdBox;
   QCheckBox    *altTabPopup;
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/kwinbindings.cpp kdebase-3.5.8.dfsg.1-patched/kwin/kwinbindings.cpp
--- kdebase-3.5.8.dfsg.1/kwin/kwinbindings.cpp	2005-10-10 19:04:22.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/kwinbindings.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -104,6 +104,15 @@
 	DEF( I18N_NOOP("Window One Desktop to the Left"),      0, 0, slotWindowToDesktopLeft() );
 	DEF( I18N_NOOP("Window One Desktop Up"),               0, 0, slotWindowToDesktopUp() );
 	DEF( I18N_NOOP("Window One Desktop Down"),             0, 0, slotWindowToDesktopDown() );
+	DEF( I18N_NOOP("Window to Screen 0"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 1"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 2"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 3"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 4"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 5"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 6"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Screen 7"),                  0, 0, slotWindowToScreen(int) );
+	DEF( I18N_NOOP("Window to Next Screen"),               0, 0, slotWindowToNextScreen() );
 
 	keys->insert( "Group:Desktop Switching", i18n("Desktop Switching") );
 	DEF( I18N_NOOP("Switch to Desktop 1"),  CTRL+Qt::Key_F1, WIN+Qt::Key_F1, slotSwitchToDesktop(int) );
@@ -132,6 +141,15 @@
 	DEF( I18N_NOOP("Switch One Desktop to the Left"),      0, 0, slotSwitchDesktopLeft() );
 	DEF( I18N_NOOP("Switch One Desktop Up"),               0, 0, slotSwitchDesktopUp() );
 	DEF( I18N_NOOP("Switch One Desktop Down"),             0, 0, slotSwitchDesktopDown() );
+	DEF( I18N_NOOP("Switch to Screen 0"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 1"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 2"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 3"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 4"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 5"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 6"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Screen 7"),                  0, 0, slotSwitchToScreen(int) );
+	DEF( I18N_NOOP("Switch to Next Screen"),               0, 0, slotSwitchToNextScreen() );
 
 	keys->insert( "Group:Miscellaneous", i18n("Miscellaneous") );
 	DEF( I18N_NOOP("Mouse Emulation"),                     ALT+Qt::Key_F12, 0, slotMouseEmulation() );
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/kwin.kcfg kdebase-3.5.8.dfsg.1-patched/kwin/kwin.kcfg
--- kdebase-3.5.8.dfsg.1/kwin/kwin.kcfg	2007-10-08 13:51:32.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/kwin.kcfg	2007-12-14 15:32:44.000000000 +0300
@@ -60,7 +60,10 @@
   <entry key="IgnorePositionClasses" type="StringList" />
   <entry key="KillPingTimeout" type="Int" />
   <entry key="ShowDesktopIsMinimizeAll" type="Bool" />
-  </group>
+  <entry key="SeparateScreenFocus" type="Bool" />
+  <entry key="ActiveMouseScreen" type="Bool" />
+  <entry key="XineramaPlacementScreen" type="Int" />
+ </group>
 
  <group name="WM" >
   <entry key="frame" type="Color" />
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/manage.cpp kdebase-3.5.8.dfsg.1-patched/kwin/manage.cpp
--- kdebase-3.5.8.dfsg.1/kwin/manage.cpp	2007-01-15 14:32:14.000000000 +0300
+++ kdebase-3.5.8.dfsg.1-patched/kwin/manage.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -166,7 +166,7 @@ bool Client::manage( Window w, bool isMa
                  it != mainclients.end();
                  ++it )
                 {
-                if( (*it)->isSpecialWindow())
+                if( mainclients.count() > 1 && (*it)->isSpecialWindow())
                     continue; // don't consider toolbars etc when placing
                 maincl = *it;
                 if( (*it)->isOnCurrentDesktop())
@@ -202,9 +202,14 @@ bool Client::manage( Window w, bool isMa
     if( isMapped || session )
         area = workspace()->clientArea( FullArea, geom.center(), desktop());
     else if( options->xineramaPlacementEnabled )
-        area = workspace()->clientArea( PlacementArea, QCursor::pos(), desktop());
+        {
+        int screen = options->xineramaPlacementScreen;
+        if( screen == -1 ) // active screen
+            screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama();
+        area = workspace()->clientArea( PlacementArea, workspace()->screenGeometry( screen ).center(), desktop());
+        }
     else
-        area = workspace()->clientArea( PlacementArea, geom.center(), desktop());
+        area = workspace()->clientArea( PlacementArea, QCursor::pos(), desktop());
 
     if( int type = checkFullScreenHack( geom ))
         {
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/options.cpp kdebase-3.5.8.dfsg.1-patched/kwin/options.cpp
--- kdebase-3.5.8.dfsg.1/kwin/options.cpp	2007-10-08 13:51:32.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/options.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -71,6 +71,9 @@ unsigned long Options::updateSettings()
     altTabStyle = KDE; // what a default :-)
     if ( val == "CDE" )
         altTabStyle = CDE;
+        
+    separateScreenFocus = config->readBoolEntry( "SeparateScreenFocus", false );
+    activeMouseScreen = config->readBoolEntry( "ActiveMouseScreen", focusPolicy != ClickToFocus );
 
     rollOverDesktops = config->readBoolEntry("RollOverDesktops", TRUE);
     
@@ -100,9 +103,10 @@ unsigned long Options::updateSettings()
     delete gc;
 
     placement = Placement::policyFromString( config->readEntry("Placement"), true );
+    xineramaPlacementScreen = KCLAMP( config->readNumEntry( "XineramaPlacementScreen", -1 ),
+        -1, qApp->desktop()->numScreens() - 1 );
 
     animateShade = config->readBoolEntry("AnimateShade", TRUE );
-
     animateMinimize = config->readBoolEntry("AnimateMinimize", TRUE );
     animateMinimizeSpeed = config->readNumEntry("AnimateMinimizeSpeed", 5 );
 
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/options.h kdebase-3.5.8.dfsg.1-patched/kwin/options.h
--- kdebase-3.5.8.dfsg.1/kwin/options.h	2007-05-14 11:55:48.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/options.h	2007-12-14 15:23:26.000000000 +0300
@@ -124,6 +124,11 @@ class Options : public KDecorationOption
          */
         enum AltTabStyle { KDE, CDE };
         AltTabStyle altTabStyle;
+        
+        // whether to see Xinerama screens separately for focus (in Alt+Tab, when activating next client)
+        bool separateScreenFocus;
+        // whether active Xinerama screen is the one with mouse (or with the active window)
+        bool activeMouseScreen;
 
         /**
          * Xinerama options
@@ -133,6 +138,9 @@ class Options : public KDecorationOption
         bool xineramaMovementEnabled;
         bool xineramaMaximizeEnabled;
         bool xineramaFullscreenEnabled;
+        
+        // number, or -1 = active screen (Workspace::activeScreen())
+        int xineramaPlacementScreen;
 
         /**
            MoveResizeMode, either Tranparent or Opaque.
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/placement.cpp kdebase-3.5.8.dfsg.1-patched/kwin/placement.cpp
--- kdebase-3.5.8.dfsg.1/kwin/placement.cpp	2006-01-19 20:01:07.000000000 +0300
+++ kdebase-3.5.8.dfsg.1-patched/kwin/placement.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -473,7 +473,7 @@ void Placement::placeOnMainWindow(Client
          it != mainwindows.end();
          ++it )
         {
-        if( (*it)->isSpecialWindow())
+        if( mainwindows.count() > 1 && (*it)->isSpecialWindow())
             continue; // don't consider toolbars etc when placing
         ++mains_count;
         place_on2 = *it;
@@ -502,6 +502,11 @@ void Placement::placeOnMainWindow(Client
             }
         place_on = place_on2; // use the only window filtered together with 'mains_count'
         }
+    if( place_on->isDesktop())
+        {
+        place( c, area, Centered );
+        return;
+        }
     QRect geom = c->geometry();
     geom.moveCenter( place_on->geometry().center());
     c->move( geom.topLeft());
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/popupinfo.cpp kdebase-3.5.8.dfsg.1-patched/kwin/popupinfo.cpp
--- kdebase-3.5.8.dfsg.1/kwin/popupinfo.cpp	2006-05-22 22:13:01.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/popupinfo.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -25,7 +25,6 @@ License. See the file "COPYING" for the 
 #include <klocale.h>
 #include <qapplication.h>
 #include <qdesktopwidget.h>
-#include <qcursor.h>
 #include <kstringhandler.h>
 #include <kglobalsettings.h>
 
@@ -34,8 +33,8 @@ License. See the file "COPYING" for the 
 namespace KWinInternal
 {
 
-PopupInfo::PopupInfo( const char *name )
-    : QWidget( 0, name )
+PopupInfo::PopupInfo( Workspace* ws, const char *name )
+    : QWidget( 0, name ), workspace( ws )
     {
     m_infoString = "";
     m_shown = false;
@@ -60,7 +59,7 @@ PopupInfo::~PopupInfo()
  */
 void PopupInfo::reset()
     {
-    QRect r = KGlobalSettings::desktopGeometry(QCursor::pos());
+    QRect r = workspace->screenGeometry( workspace->activeScreen());
 
     int w = fontMetrics().width( m_infoString ) + 30;
 
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/popupinfo.h kdebase-3.5.8.dfsg.1-patched/kwin/popupinfo.h
--- kdebase-3.5.8.dfsg.1/kwin/popupinfo.h	2005-09-10 12:26:03.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/popupinfo.h	2007-12-14 15:23:26.000000000 +0300
@@ -24,7 +24,7 @@ class PopupInfo : public QWidget
     {
     Q_OBJECT
     public:
-        PopupInfo( const char *name=0 );
+        PopupInfo( Workspace* ws, const char *name=0 );
         ~PopupInfo();
 
         void reset();
@@ -43,6 +43,7 @@ class PopupInfo : public QWidget
         bool m_show;
         bool m_shown;
         QString m_infoString;
+        Workspace* workspace;
     };
 
 } // namespace
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/tabbox.cpp kdebase-3.5.8.dfsg.1-patched/kwin/tabbox.cpp
--- kdebase-3.5.8.dfsg.1/kwin/tabbox.cpp	2007-05-14 11:55:48.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/tabbox.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -23,7 +23,6 @@ License. See the file "COPYING" for the 
 #include <klocale.h>
 #include <qapplication.h>
 #include <qdesktopwidget.h>
-#include <qcursor.h>
 #include <kstringhandler.h>
 #include <stdarg.h>
 #include <kdebug.h>
@@ -110,26 +109,36 @@ void TabBox::createClientList(ClientList
 
     while ( c )
         {
+        Client* add = NULL;
         if ( ((desktop == -1) || c->isOnDesktop(desktop))
              && c->wantsTabFocus() )
+            { // don't add windows that have modal dialogs
+            Client* modal = c->findModal();
+            if( modal == NULL || modal == c )
+                add = c;
+            else if( !list.contains( modal ))
+                add = modal;
+            else
+                {
+                // nothing
+                }
+            }
+
+        if( options->separateScreenFocus && options->xineramaEnabled )
             {
-            if ( start == c )
+            if( c->screen() != workspace()->activeScreen())
+                add = NULL;
+            }
+
+        if( add != NULL )
+            {
+            if ( start == add )
                 {
-                list.remove( c );
-                list.prepend( c );
+                list.remove( add );
+                list.prepend( add );
                 }
             else
-                { // don't add windows that have modal dialogs
-                Client* modal = c->findModal();
-                if( modal == NULL || modal == c )
-                    list += c;
-                else if( !list.contains( modal ))
-                    list += modal;
-                else
-                    {
-                    // nothing
-                    }
-                }
+                list += add;
             }
 
         if ( chain )
@@ -156,7 +165,7 @@ void TabBox::reset()
     {
     int w, h, cw = 0, wmax = 0;
 
-    QRect r = KGlobalSettings::desktopGeometry(QCursor::pos());
+    QRect r = workspace()->screenGeometry( workspace()->activeScreen());
 
     // calculate height of 1 line
     // fontheight + 1 pixel above + 1 pixel below, or 32x32 icon + 2 pixel above + below
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/useractions.cpp kdebase-3.5.8.dfsg.1-patched/kwin/useractions.cpp
--- kdebase-3.5.8.dfsg.1/kwin/useractions.cpp	2006-10-01 21:32:07.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/useractions.cpp	2007-12-14 15:23:26.000000000 +0300
@@ -482,27 +482,33 @@ bool Client::performMouseCommand( Option
         case Options::MouseActivateAndRaise:
             replay = isActive(); // for clickraise mode
             workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled && replay );
+            workspace()->setActiveScreenMouse( globalPos );
             break;
         case Options::MouseActivateAndLower:
             workspace()->requestFocus( this );
             workspace()->lowerClient( this );
+            workspace()->setActiveScreenMouse( globalPos );
             break;
         case Options::MouseActivate:
             replay = isActive(); // for clickraise mode
             workspace()->takeActivity( this, ActivityFocus, handled && replay );
+            workspace()->setActiveScreenMouse( globalPos );
             break;
         case Options::MouseActivateRaiseAndPassClick:
             workspace()->takeActivity( this, ActivityFocus | ActivityRaise, handled );
+            workspace()->setActiveScreenMouse( globalPos );
             replay = TRUE;
             break;
         case Options::MouseActivateAndPassClick:
             workspace()->takeActivity( this, ActivityFocus, handled );
+            workspace()->setActiveScreenMouse( globalPos );
             replay = TRUE;
             break;
         case Options::MouseActivateRaiseAndMove:
         case Options::MouseActivateRaiseAndUnrestrictedMove:
             workspace()->raiseClient( this );
             workspace()->requestFocus( this );
+            workspace()->setActiveScreenMouse( globalPos );
             if( options->moveMode == Options::Transparent && isMovable())
                 move_faked_activity = workspace()->fakeRequestedActivity( this );
         // fallthrough
@@ -709,6 +715,40 @@ void Workspace::slotWindowToDesktop( int
             sendClientToDesktop( c, i, true );
     }
 
+void Workspace::slotSwitchToScreen( int i )
+    {
+    setCurrentScreen( i );
+    }
+
+void Workspace::slotSwitchToNextScreen()
+    {
+    slotSwitchToScreen(( activeScreen() + 1 ) % numScreens());
+    }
+
+void Workspace::slotWindowToScreen( int i )
+    {
+    Client* c = active_popup_client ? active_popup_client : active_client;
+    if( i >= 0 && i <= numScreens() && c
+        && !c->isDesktop()
+        && !c->isDock()
+        && !c->isTopMenu())
+        {
+        sendClientToScreen( c, i );
+        }
+    }
+
+void Workspace::slotWindowToNextScreen()
+    {
+    Client* c = active_popup_client ? active_popup_client : active_client;
+    if( c
+        && !c->isDesktop()
+        && !c->isDock()
+        && !c->isTopMenu())
+        {
+        sendClientToScreen( c, ( c->screen() + 1 ) % numScreens());
+        }
+    }
+
 /*!
   Maximizes the popup client
  */
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/workspace.cpp kdebase-3.5.8.dfsg.1-patched/kwin/workspace.cpp
--- kdebase-3.5.8.dfsg.1/kwin/workspace.cpp	2007-10-08 13:51:32.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/workspace.cpp	2007-12-14 15:37:57.000000000 +0300
@@ -71,6 +71,7 @@ Workspace::Workspace( bool restore )
     QObject           (0, "workspace"),
     current_desktop   (0),
     number_of_desktops(0),
+    active_screen     (0),
     active_popup( NULL ),
     active_popup_client( NULL ),
     desktop_widget    (0),
@@ -191,7 +192,7 @@ Workspace::Workspace( bool restore )
     client_keys = new KGlobalAccel( this );
     initShortcuts();
     tab_box = new TabBox( this );
-    popupinfo = new PopupInfo( );
+    popupinfo = new PopupInfo( this );
 
     init();
 
@@ -1523,6 +1524,80 @@ void Workspace::sendClientToDesktop( Cli
     updateClientArea();
     }
 
+int Workspace::numScreens() const
+    {
+    if( !options->xineramaEnabled )
+        return 0;
+    return qApp->desktop()->numScreens();
+    }
+
+int Workspace::activeScreen() const
+    {
+    if( !options->xineramaEnabled )
+        return 1;
+    if( !options->activeMouseScreen )
+        {
+        if( activeClient() != NULL && !activeClient()->isOnScreen( active_screen ))
+            return qApp->desktop()->screenNumber( activeClient()->geometry().center());
+        return active_screen;
+        }
+    return qApp->desktop()->screenNumber( QCursor::pos());
+    }
+
+// check whether a client moved completely out of what's considered the active screen,
+// if yes, set a new active screen
+void Workspace::checkActiveScreen( const Client* c )
+    {
+    if( !options->xineramaEnabled )
+        return;
+    if( !c->isActive())
+        return;
+    if( !c->isOnScreen( active_screen ))
+        active_screen = c->screen();
+    }
+
+// called e.g. when a user clicks on a window, set active screen to be the screen
+// where the click occured
+void Workspace::setActiveScreenMouse( QPoint mousepos )
+    {
+    if( !options->xineramaEnabled )
+        return;
+    active_screen = qApp->desktop()->screenNumber( mousepos );
+    }
+
+QRect Workspace::screenGeometry( int screen ) const
+    {
+    if( !options->xineramaEnabled )
+        return qApp->desktop()->geometry();
+    return qApp->desktop()->screenGeometry( screen );
+    }
+
+int Workspace::screenNumber( QPoint pos ) const
+    {
+    if( !options->xineramaEnabled )
+        return 0;
+    return qApp->desktop()->screenNumber( pos );
+    }
+
+void Workspace::sendClientToScreen( Client* c, int screen )
+    {
+    if( c->screen() == screen ) // don't use isOnScreen(), that's true even when only partially
+        return;
+    GeometryUpdatesPostponer blocker( c );
+    QRect old_sarea = clientArea( MaximizeArea, c );
+    QRect sarea = clientArea( MaximizeArea, screen, c->desktop());
+    c->setGeometry( sarea.x() - old_sarea.x() + c->x(), sarea.y() - old_sarea.y() + c->y(),
+        c->size().width(), c->size().height());
+    c->checkWorkspacePosition();
+    ClientList transients_stacking_order = ensureStackingOrder( c->transients());
+    for( ClientList::ConstIterator it = transients_stacking_order.begin();
+         it != transients_stacking_order.end();
+         ++it )
+        sendClientToScreen( *it, screen );
+    if( c->isActive())
+        active_screen = screen;
+    }
+
 void Workspace::setDesktopLayout( int, int, int )
     { // DCOP-only, unused
     }
diff -padurx debian kdebase-3.5.8.dfsg.1/kwin/workspace.h kdebase-3.5.8.dfsg.1-patched/kwin/workspace.h
--- kdebase-3.5.8.dfsg.1/kwin/workspace.h	2007-10-08 13:51:32.000000000 +0400
+++ kdebase-3.5.8.dfsg.1-patched/kwin/workspace.h	2007-12-14 15:23:26.000000000 +0300
@@ -91,6 +91,7 @@ class Workspace : public QObject, public
 
         QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const;
         QRect clientArea( clientAreaOption, const Client* c ) const;
+        QRect clientArea( clientAreaOption, int screen, int desktop ) const;
 
         /**
          * @internal
@@ -161,6 +162,13 @@ class Workspace : public QObject, public
          */
         int numberOfDesktops() const;
         void setNumberOfDesktops( int n );
+        
+        int activeScreen() const;
+        int numScreens() const;
+        void checkActiveScreen( const Client* c );
+        void setActiveScreenMouse( QPoint mousepos );
+        QRect screenGeometry( int screen ) const;
+        int screenNumber( QPoint pos ) const;
 
         QWidget* desktopWidget();
 
@@ -186,6 +194,7 @@ class Workspace : public QObject, public
         void sendClientToDesktop( Client* c, int desktop, bool dont_activate );
         void windowToPreviousDesktop( Client* c );
         void windowToNextDesktop( Client* c );
+        void sendClientToScreen( Client* c, int screen );
 
     // KDE4 remove me - and it's also in the DCOP interface :(
         void showWindowMenuAt( unsigned long id, int x, int y );
@@ -224,6 +233,7 @@ class Workspace : public QObject, public
         void nextDesktop();
         void previousDesktop();
         void circulateDesktopApplications();
+        void setCurrentScreen( int new_screen );
 
         QString desktopName( int desk ) const;
         virtual void setDesktopLayout(int , int , int );
@@ -301,6 +311,10 @@ class Workspace : public QObject, public
     //void slotSwitchToWindow( int );
         void slotWindowToDesktop( int );
     //void slotWindowToListPosition( int );
+        void slotSwitchToScreen( int );
+        void slotWindowToScreen( int );
+        void slotSwitchToNextScreen();
+        void slotWindowToNextScreen();
 
         void slotWindowMaximize();
         void slotWindowMaximizeVertical();
@@ -481,6 +495,7 @@ class Workspace : public QObject, public
         int current_desktop;
         int number_of_desktops;
         QMemArray<int> desktop_focus_chain;
+        int active_screen;
 
         QWidget* active_popup;
         Client* active_popup_client;

Reply to: