• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

workspace.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 #include "workspace.h"
00013 
00014 #include <tdeapplication.h>
00015 #include <tdestartupinfo.h>
00016 #include <fixx11h.h>
00017 #include <tdeconfig.h>
00018 #include <tdeglobal.h>
00019 #include <tqpopupmenu.h>
00020 #include <tdelocale.h>
00021 #include <tqregexp.h>
00022 #include <tqpainter.h>
00023 #include <tqbitmap.h>
00024 #include <tqclipboard.h>
00025 #include <tdemenubar.h>
00026 #include <kprocess.h>
00027 #include <kglobalaccel.h>
00028 #include <dcopclient.h>
00029 #include <kipc.h>
00030 
00031 #include "plugins.h"
00032 #include "client.h"
00033 #include "popupinfo.h"
00034 #include "tabbox.h"
00035 #include "atoms.h"
00036 #include "placement.h"
00037 #include "notifications.h"
00038 #include "group.h"
00039 #include "rules.h"
00040 
00041 #include <X11/XKBlib.h>
00042 #include <X11/extensions/shape.h>
00043 #include <X11/keysym.h>
00044 #include <X11/keysymdef.h>
00045 #include <X11/cursorfont.h>
00046 
00047 #include <pwd.h>
00048 
00049 #include "config.h"
00050 
00051 namespace KWinInternal
00052 {
00053 
00054 extern int screen_number;
00055 
00056 Workspace *Workspace::_self = 0;
00057 
00058 TDEProcess* kompmgr = 0;
00059 TDESelectionOwner* kompmgr_selection;
00060 
00061 bool allowKompmgrRestart = TRUE;
00062 extern bool disable_twin_composition_manager;
00063 
00064 bool supportsCompMgr()
00065 {
00066     if (disable_twin_composition_manager) {
00067         return false;
00068     }
00069 
00070     int i;
00071 
00072     bool damageExt = XQueryExtension(tqt_xdisplay(), "DAMAGE", &i, &i, &i);
00073     bool compositeExt = XQueryExtension(tqt_xdisplay(), "Composite", &i, &i, &i);
00074     bool xfixesExt = XQueryExtension(tqt_xdisplay(), "XFIXES", &i, &i, &i);
00075 
00076     return damageExt && compositeExt && xfixesExt;
00077 }
00078 
00079 pid_t getCompositorPID() {
00080     // Attempt to load the compton-tde pid file
00081     char *filename;
00082     const char *pidfile = "compton-tde.pid";
00083     char uidstr[sizeof(uid_t)*8+1];
00084     sprintf(uidstr, "%d", getuid());
00085     int n = strlen(P_tmpdir)+strlen(uidstr)+strlen(pidfile)+3;
00086     filename = (char*)malloc(n*sizeof(char)+1);
00087     memset(filename,0,n);
00088     strcat(filename, P_tmpdir);
00089     strcat(filename, "/.");
00090     strcat(filename, uidstr);
00091     strcat(filename, "-");
00092     strcat(filename, pidfile);
00093 
00094     // Now that we did all that by way of introduction...read the file!
00095     FILE *pFile;
00096     char buffer[255];
00097     pFile = fopen(filename, "r");
00098     pid_t kompmgrpid = 0;
00099     if (pFile)
00100         {
00101         printf("[twin-workspace] Using '%s' as compton-tde pidfile\n\n", filename);
00102         // obtain file size
00103         fseek (pFile , 0 , SEEK_END);
00104         unsigned long lSize = ftell (pFile);
00105         if (lSize > 254)
00106             lSize = 254;
00107         rewind (pFile);
00108         size_t result = fread (buffer, 1, lSize, pFile);
00109         fclose(pFile);
00110         if (result > 0)
00111             {
00112             kompmgrpid = atoi(buffer);
00113             }
00114         }
00115 
00116     free(filename);
00117     filename = NULL;
00118 
00119     return kompmgrpid;
00120 }
00121 
00122 // Rikkus: This class is too complex. It needs splitting further.
00123 // It's a nightmare to understand, especially with so few comments :(
00124 
00125 // Matthias: Feel free to ask me questions about it. Feel free to add
00126 // comments. I disagree that further splittings makes it easier. 2500
00127 // lines are not too much. It's the task that is complex, not the
00128 // code.
00129 Workspace::Workspace( bool restore )
00130   : DCOPObject        ("KWinInterface"),
00131     TQObject           (0, "workspace"),
00132     current_desktop   (0),
00133     number_of_desktops(0),
00134     active_screen     (0),
00135     active_popup( NULL ),
00136     active_popup_client( NULL ),
00137     desktop_widget    (0),
00138     temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ),
00139     rules_updates_disabled( false ),
00140     active_client     (0),
00141     last_active_client     (0),
00142     next_active_client     (0),
00143     most_recently_raised (0),
00144     movingClient(0),
00145     pending_take_activity ( NULL ),
00146     delayfocus_client (0),
00147     showing_desktop( false ),
00148     block_showing_desktop( 0 ),
00149     was_user_interaction (false),
00150     session_saving    (false),
00151     control_grab      (false),
00152     tab_grab          (false),
00153     mouse_emulation   (false),
00154     block_focus       (0),
00155     tab_box           (0),
00156     popupinfo         (0),
00157     popup             (0),
00158     advanced_popup    (0),
00159     desk_popup        (0),
00160     desk_popup_index  (0),
00161     keys              (0),
00162     client_keys       ( NULL ),
00163     client_keys_dialog ( NULL ),
00164     client_keys_client ( NULL ),
00165     disable_shortcuts_keys ( NULL ),
00166     global_shortcuts_disabled( false ),
00167     global_shortcuts_disabled_for_client( false ),
00168     root              (0),
00169     workspaceInit     (true),
00170     startup(0), electric_have_borders(false),
00171     electric_current_border(0),
00172     electric_top_border(None),
00173     electric_bottom_border(None),
00174     electric_left_border(None),
00175     electric_right_border(None),
00176     layoutOrientation(Qt::Vertical),
00177     layoutX(-1),
00178     layoutY(2),
00179     workarea(NULL),
00180     screenarea(NULL),
00181     managing_topmenus( false ),
00182     topmenu_selection( NULL ),
00183     topmenu_watcher( NULL ),
00184     topmenu_height( 0 ),
00185     topmenu_space( NULL ),
00186     set_active_client_recursion( 0 ),
00187     block_stacking_updates( 0 ),
00188     forced_global_mouse_grab( false )
00189     {
00190     _self = this;
00191     mgr = new PluginMgr;
00192     root = tqt_xrootwin();
00193     default_colormap = DefaultColormap(tqt_xdisplay(), tqt_xscreen() );
00194     installed_colormap = default_colormap;
00195     session.setAutoDelete( TRUE );
00196 
00197     connect( &temporaryRulesMessages, TQT_SIGNAL( gotMessage( const TQString& )),
00198         this, TQT_SLOT( gotTemporaryRulesMessage( const TQString& )));
00199     connect( &rulesUpdatedTimer, TQT_SIGNAL( timeout()), this, TQT_SLOT( writeWindowRules()));
00200 
00201     updateXTime(); // needed for proper initialization of user_time in Client ctor
00202 
00203     delayFocusTimer = 0; 
00204     
00205     electric_time_first = GET_QT_X_TIME();
00206     electric_time_last = GET_QT_X_TIME();
00207 
00208     if ( restore )
00209       loadSessionInfo();
00210 
00211     loadWindowRules();
00212 
00213     (void) TQApplication::desktop(); // trigger creation of desktop widget
00214 
00215     desktop_widget =
00216       new TQWidget(
00217         0,
00218         "desktop_widget",
00219         (WFlags)(TQt::WType_Desktop | TQt::WPaintUnclipped)
00220     );
00221 
00222     kapp->setGlobalMouseTracking( true ); // so that this doesn't mess eventmask on root window later
00223     // call this before XSelectInput() on the root window
00224     startup = new TDEStartupInfo(
00225         TDEStartupInfo::DisableKWinModule | TDEStartupInfo::AnnounceSilenceChanges, this );
00226 
00227     // select windowmanager privileges
00228     XSelectInput(tqt_xdisplay(), root,
00229                  KeyPressMask |
00230                  PropertyChangeMask |
00231                  ColormapChangeMask |
00232                  SubstructureRedirectMask |
00233                  SubstructureNotifyMask |
00234                  FocusChangeMask // for NotifyDetailNone
00235                  );
00236 
00237     Shape::init();
00238 
00239     // compatibility
00240     long data = 1;
00241 
00242     XChangeProperty(
00243       tqt_xdisplay(),
00244       tqt_xrootwin(),
00245       atoms->twin_running,
00246       atoms->twin_running,
00247       32,
00248       PropModeAppend,
00249       (unsigned char*) &data,
00250       1
00251     );
00252 
00253     client_keys = new TDEGlobalAccel( this );
00254     initShortcuts();
00255     tab_box = new TabBox( this );
00256     popupinfo = new PopupInfo( this );
00257 
00258     init();
00259 
00260 #if (TQT_VERSION-0 >= 0x030200) // XRANDR support
00261     connect( kapp->desktop(), TQT_SIGNAL( resized( int )), TQT_SLOT( desktopResized()));
00262 #endif
00263 
00264     if (!supportsCompMgr()) {
00265         options->useTranslucency = false;
00266     }
00267 
00268     // start kompmgr - i wanted to put this into main.cpp, but that would prevent dcop support, as long as Application was no dcop_object
00269 
00270     // If compton-tde is already running, send it SIGTERM
00271     pid_t kompmgrpid = getCompositorPID();
00272 
00273     if (options->useTranslucency)
00274         {
00275         kompmgr = new TDEProcess;
00276         connect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
00277         *kompmgr << TDE_COMPOSITOR_BINARY;
00278         if (kompmgrpid)
00279             {
00280             if (kill(kompmgrpid, 0) < 0)
00281                 {
00282                 // Stale PID file detected; (re)start compositor!
00283                 startKompmgr();
00284                 }
00285             }
00286         else
00287             {
00288             startKompmgr();
00289             }
00290         }
00291     else if (!disable_twin_composition_manager)
00292         {
00293 
00294         if (kompmgrpid)
00295             {
00296             kill(kompmgrpid, SIGTERM);
00297             }
00298         else
00299             {
00300             stopKompmgr();
00301             }
00302         }
00303     }
00304 
00305 
00306 void Workspace::init()
00307     {
00308     checkElectricBorders();
00309 
00310 // not used yet
00311 //     topDock = 0L;
00312 //     maximizedWindowCounter = 0;
00313     
00314     supportWindow = new TQWidget;
00315     XLowerWindow( tqt_xdisplay(), supportWindow->winId()); // see usage in layers.cpp
00316 
00317     XSetWindowAttributes attr;
00318     attr.override_redirect = 1;
00319     null_focus_window = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), -1,-1, 1, 1, 0, CopyFromParent,
00320         InputOnly, CopyFromParent, CWOverrideRedirect, &attr );
00321     XMapWindow(tqt_xdisplay(), null_focus_window);
00322 
00323     unsigned long protocols[ 5 ] =
00324         {
00325         NET::Supported |
00326         NET::SupportingWMCheck |
00327         NET::ClientList |
00328         NET::ClientListStacking |
00329         NET::DesktopGeometry |
00330         NET::NumberOfDesktops |
00331         NET::CurrentDesktop |
00332         NET::ActiveWindow |
00333         NET::WorkArea |
00334         NET::CloseWindow |
00335         NET::DesktopNames |
00336         NET::KDESystemTrayWindows |
00337         NET::WMName |
00338         NET::WMVisibleName |
00339         NET::WMDesktop |
00340         NET::WMWindowType |
00341         NET::WMState |
00342         NET::WMStrut |
00343         NET::WMIconGeometry |
00344         NET::WMIcon |
00345         NET::WMPid |
00346         NET::WMMoveResize |
00347         NET::WMKDESystemTrayWinFor |
00348         NET::WMFrameExtents |
00349         NET::WMPing
00350         ,
00351         NET::NormalMask |
00352         NET::DesktopMask |
00353         NET::DockMask |
00354         NET::ToolbarMask |
00355         NET::MenuMask |
00356         NET::DialogMask |
00357         NET::OverrideMask |
00358         NET::TopMenuMask |
00359         NET::UtilityMask |
00360         NET::SplashMask |
00361         0
00362         ,
00363         NET::Modal |
00364 //        NET::Sticky |  // large desktops not supported (and probably never will be)
00365         NET::MaxVert |
00366         NET::MaxHoriz |
00367         NET::Shaded |
00368         NET::SkipTaskbar |
00369         NET::KeepAbove |
00370 //        NET::StaysOnTop |  the same like KeepAbove
00371         NET::SkipPager |
00372         NET::Hidden |
00373         NET::FullScreen |
00374         NET::KeepBelow |
00375         NET::DemandsAttention |
00376         0
00377         ,
00378         NET::WM2UserTime |
00379         NET::WM2StartupId |
00380         NET::WM2AllowedActions |
00381         NET::WM2RestackWindow |
00382         NET::WM2MoveResizeWindow |
00383         NET::WM2ExtendedStrut |
00384         NET::WM2KDETemporaryRules |
00385         NET::WM2ShowingDesktop |
00386         NET::WM2FullPlacement |
00387         NET::WM2DesktopLayout |
00388         0
00389         ,
00390         NET::ActionMove |
00391         NET::ActionResize |
00392         NET::ActionMinimize |
00393         NET::ActionShade |
00394 //        NET::ActionStick | // Sticky state is not supported
00395         NET::ActionMaxVert |
00396         NET::ActionMaxHoriz |
00397         NET::ActionFullScreen |
00398         NET::ActionChangeDesktop |
00399         NET::ActionClose |
00400         0
00401         ,
00402         };
00403 
00404     rootInfo = new RootInfo( this, tqt_xdisplay(), supportWindow->winId(), "KWin",
00405         protocols, 5, tqt_xscreen() );
00406 
00407     loadDesktopSettings();
00408     updateDesktopLayout();
00409     // extra NETRootInfo instance in Client mode is needed to get the values of the properties
00410     NETRootInfo client_info( tqt_xdisplay(), NET::ActiveWindow | NET::CurrentDesktop );
00411     int initial_desktop;
00412     if( !kapp->isSessionRestored())
00413         initial_desktop = client_info.currentDesktop();
00414     else
00415         {
00416         TDEConfigGroupSaver saver( kapp->sessionConfig(), "Session" );
00417         initial_desktop = kapp->sessionConfig()->readNumEntry( "desktop", 1 );
00418         }
00419     if( !setCurrentDesktop( initial_desktop ))
00420         setCurrentDesktop( 1 );
00421 
00422     // now we know how many desktops we'll, thus, we initialise the positioning object
00423     initPositioning = new Placement(this);
00424 
00425     connect(&reconfigureTimer, TQT_SIGNAL(timeout()), this,
00426             TQT_SLOT(slotReconfigure()));
00427     connect( &updateToolWindowsTimer, TQT_SIGNAL( timeout()), this, TQT_SLOT( slotUpdateToolWindows()));
00428 
00429     connect(kapp, TQT_SIGNAL(appearanceChanged()), this,
00430             TQT_SLOT(slotReconfigure()));
00431     connect(kapp, TQT_SIGNAL(settingsChanged(int)), this,
00432             TQT_SLOT(slotSettingsChanged(int)));
00433     connect(kapp, TQT_SIGNAL( kipcMessage( int, int )), this, TQT_SLOT( kipcMessage( int, int )));
00434 
00435     active_client = NULL;
00436     rootInfo->setActiveWindow( None );
00437     focusToNull();
00438     if( !kapp->isSessionRestored())
00439         ++block_focus; // because it will be set below
00440 
00441     char nm[ 100 ];
00442     sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( tqt_xdisplay()));
00443     Atom topmenu_atom = XInternAtom( tqt_xdisplay(), nm, False );
00444     topmenu_selection = new TDESelectionOwner( topmenu_atom );
00445     topmenu_watcher = new TDESelectionWatcher( topmenu_atom );
00446 // TODO grabXServer(); - where exactly put this? topmenu selection claiming down belong must be before
00447 
00448         { // begin updates blocker block
00449         StackingUpdatesBlocker blocker( this );
00450 
00451         if( options->topMenuEnabled() && topmenu_selection->claim( false ))
00452             setupTopMenuHandling(); // this can call updateStackingOrder()
00453         else
00454             lostTopMenuSelection();
00455 
00456         unsigned int i, nwins;
00457         Window root_return, parent_return, *wins;
00458         XQueryTree(tqt_xdisplay(), root, &root_return, &parent_return, &wins, &nwins);
00459         for (i = 0; i < nwins; i++) 
00460             {
00461             XWindowAttributes attr;
00462             XGetWindowAttributes(tqt_xdisplay(), wins[i], &attr);
00463             if (attr.override_redirect )
00464                 continue;
00465             if( topmenu_space && topmenu_space->winId() == wins[ i ] )
00466                 continue;
00467             if (attr.map_state != IsUnmapped) 
00468                 {
00469                 if ( addSystemTrayWin( wins[i] ) )
00470                     continue;
00471                 Client* c = createClient( wins[i], true );
00472                 if ( c != NULL && root != tqt_xrootwin() ) 
00473                     { // TODO what is this?
00474                 // TODO may use TQWidget:.create
00475                     XReparentWindow( tqt_xdisplay(), c->frameId(), root, 0, 0 );
00476                     c->move(0,0);
00477                     }
00478                 }
00479             }
00480         if ( wins )
00481             XFree((void *) wins);
00482     // propagate clients, will really happen at the end of the updates blocker block
00483         updateStackingOrder( true );
00484 
00485         updateClientArea();
00486         raiseElectricBorders();
00487 
00488     // NETWM spec says we have to set it to (0,0) if we don't support it
00489         NETPoint* viewports = new NETPoint[ number_of_desktops ];
00490         rootInfo->setDesktopViewport( number_of_desktops, *viewports );
00491         delete[] viewports;
00492         TQRect geom = TQApplication::desktop()->geometry();
00493         NETSize desktop_geometry;
00494         desktop_geometry.width = geom.width();
00495         desktop_geometry.height = geom.height();
00496         rootInfo->setDesktopGeometry( -1, desktop_geometry );
00497         setShowingDesktop( false );
00498 
00499         } // end updates blocker block
00500 
00501     Client* new_active_client = NULL;
00502     if( !kapp->isSessionRestored())
00503         {
00504         --block_focus;
00505         new_active_client = findClient( WindowMatchPredicate( client_info.activeWindow()));
00506         }
00507     if( new_active_client == NULL
00508         && activeClient() == NULL && should_get_focus.count() == 0 ) // no client activated in manage()
00509         {
00510         if( new_active_client == NULL )
00511             new_active_client = topClientOnDesktop( currentDesktop());
00512         if( new_active_client == NULL && !desktops.isEmpty() )
00513             new_active_client = findDesktop( true, currentDesktop());
00514         }
00515     if( new_active_client != NULL )
00516         activateClient( new_active_client );
00517     // SELI TODO this won't work with unreasonable focus policies,
00518     // and maybe in rare cases also if the selected client doesn't
00519     // want focus
00520     workspaceInit = false;
00521 // TODO ungrabXServer()
00522     }
00523 
00524 Workspace::~Workspace()
00525     {
00526     if (kompmgr)
00527         delete kompmgr;
00528     blockStackingUpdates( true );
00529 // TODO    grabXServer();
00530     // use stacking_order, so that twin --replace keeps stacking order
00531     for( ClientList::ConstIterator it = stacking_order.begin();
00532          it != stacking_order.end();
00533          ++it )
00534         {
00535     // only release the window
00536         (*it)->releaseWindow( true );
00537         // No removeClient() is called, it does more than just removing.
00538         // However, remove from some lists to e.g. prevent performTransiencyCheck()
00539         // from crashing.
00540         clients.remove( *it );
00541         desktops.remove( *it );
00542         }
00543     delete desktop_widget;
00544     delete tab_box;
00545     delete popupinfo;
00546     delete popup;
00547     if ( root == tqt_xrootwin() )
00548         XDeleteProperty(tqt_xdisplay(), tqt_xrootwin(), atoms->twin_running);
00549 
00550     writeWindowRules();
00551     TDEGlobal::config()->sync();
00552 
00553     delete rootInfo;
00554     delete supportWindow;
00555     delete mgr;
00556     delete[] workarea;
00557     delete[] screenarea;
00558     delete startup;
00559     delete initPositioning;
00560     delete topmenu_watcher;
00561     delete topmenu_selection;
00562     delete topmenu_space;
00563     delete client_keys_dialog;
00564     while( !rules.isEmpty())
00565         {
00566         delete rules.front();
00567         rules.pop_front();
00568         }
00569     XDestroyWindow( tqt_xdisplay(), null_focus_window );
00570 // TODO    ungrabXServer();
00571     _self = 0;
00572     }
00573 
00574 Client* Workspace::createClient( Window w, bool is_mapped )
00575     {
00576     StackingUpdatesBlocker blocker( this );
00577     Client* c = new Client( this );
00578     if( !c->manage( w, is_mapped ))
00579         {
00580         Client::deleteClient( c, Allowed );
00581         return NULL;
00582         }
00583     addClient( c, Allowed );
00584     return c;
00585     }
00586 
00587 void Workspace::addClient( Client* c, allowed_t )
00588     {
00589     // waited with trans settings until window figured out if active or not ;)
00590 //     tqWarning("%s", (const char*)(c->resourceClass()));
00591     c->setBMP(c->resourceName() == "beep-media-player" || c->decorationId() == None);
00592     // first check if the window has it's own opinion of it's translucency ;)
00593     c->getWindowOpacity();
00594     if (c->isDock())
00595         {
00596 //         if (c->x() == 0 && c->y() == 0 && c->width() > c->height()) topDock = c;
00597         if (!c->hasCustomOpacity()) // this xould be done slightly more efficient, but we want to support the topDock in future
00598             {
00599             c->setShadowSize(options->dockShadowSize);
00600             c->setOpacity(options->translucentDocks, options->dockOpacity);
00601             }
00602         }
00603 
00604     if (c->isMenu() || c->isTopMenu())
00605         {
00606             c->setShadowSize(options->menuShadowSize);
00607         }
00608 //------------------------------------------------
00609     Group* grp = findGroup( c->window());
00610     if( grp != NULL )
00611         grp->gotLeader( c );
00612 
00613     if ( c->isDesktop() )
00614         {
00615         desktops.append( c );
00616         if( active_client == NULL && should_get_focus.isEmpty() && c->isOnCurrentDesktop())
00617             requestFocus( c ); // CHECKME? make sure desktop is active after startup if there's no other window active
00618         }
00619     else
00620         {
00621         updateFocusChains( c, FocusChainUpdate ); // add to focus chain if not already there
00622         clients.append( c );
00623         }
00624     if( !unconstrained_stacking_order.contains( c ))
00625         unconstrained_stacking_order.append( c );
00626     if( !stacking_order.contains( c )) // it'll be updated later, and updateToolWindows() requires
00627         stacking_order.append( c );    // c to be in stacking_order
00628     if( c->isTopMenu())
00629         addTopMenu( c );
00630     updateClientArea(); // this cannot be in manage(), because the client got added only now
00631     updateClientLayer( c );
00632     if( c->isDesktop())
00633         {
00634         raiseClient( c );
00635     // if there's no active client, make this desktop the active one
00636         if( activeClient() == NULL && should_get_focus.count() == 0 )
00637             activateClient( findDesktop( true, currentDesktop()));
00638         }
00639     c->checkActiveModal();
00640     checkTransients( c->window()); // SELI does this really belong here?
00641     updateStackingOrder( true ); // propagate new client
00642     if( c->isUtility() || c->isMenu() || c->isToolbar())
00643         updateToolWindows( true );
00644     checkNonExistentClients();
00645     }
00646 
00647 /*
00648   Destroys the client \a c
00649  */
00650 void Workspace::removeClient( Client* c, allowed_t )
00651     {
00652     if (c == active_popup_client)
00653         closeActivePopup();
00654 
00655     if( client_keys_client == c )
00656         setupWindowShortcutDone( false );
00657     if( !c->shortcut().isNull())
00658         c->setShortcut( TQString::null ); // remove from client_keys
00659 
00660     if( c->isDialog())
00661         Notify::raise( Notify::TransDelete );
00662     if( c->isNormalWindow())
00663         Notify::raise( Notify::Delete );
00664 
00665     Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
00666     clients.remove( c );
00667     desktops.remove( c );
00668     unconstrained_stacking_order.remove( c );
00669     stacking_order.remove( c );
00670     for( int i = 1;
00671          i <= numberOfDesktops();
00672          ++i )
00673         focus_chain[ i ].remove( c );
00674     global_focus_chain.remove( c );
00675     attention_chain.remove( c );
00676     showing_desktop_clients.remove( c );
00677     if( c->isTopMenu())
00678         removeTopMenu( c );
00679     Group* group = findGroup( c->window());
00680     if( group != NULL )
00681         group->lostLeader();
00682 
00683     if ( c == most_recently_raised )
00684         most_recently_raised = 0;
00685     should_get_focus.remove( c );
00686     Q_ASSERT( c != active_client );
00687     if ( c == last_active_client )
00688         last_active_client = 0;
00689     if( c == pending_take_activity )
00690         pending_take_activity = NULL;
00691     if( c == delayfocus_client )
00692         cancelDelayFocus();
00693 
00694     updateStackingOrder( true );
00695 
00696     if (tab_grab)
00697        tab_box->repaint();
00698 
00699     updateClientArea();
00700     }
00701 
00702 void Workspace::updateFocusChains( Client* c, FocusChainChange change )
00703     {
00704     if( !c->wantsTabFocus()) // doesn't want tab focus, remove
00705         {
00706         for( int i=1;
00707              i<= numberOfDesktops();
00708              ++i )
00709             focus_chain[i].remove(c);
00710         global_focus_chain.remove( c );
00711         return;
00712         }
00713     if(c->desktop() == NET::OnAllDesktops)
00714         { //now on all desktops, add it to focus_chains it is not already in
00715         for( int i=1; i<= numberOfDesktops(); i++)
00716             { // making first/last works only on current desktop, don't affect all desktops
00717             if( i == currentDesktop()
00718                 && ( change == FocusChainMakeFirst || change == FocusChainMakeLast ))
00719                 {
00720                 focus_chain[ i ].remove( c );
00721                 if( change == FocusChainMakeFirst )
00722                     focus_chain[ i ].append( c );
00723                 else
00724                     focus_chain[ i ].prepend( c );
00725                 }
00726             else if( !focus_chain[ i ].contains( c ))
00727                 { // add it after the active one
00728                 if( active_client != NULL && active_client != c
00729                     && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
00730                     focus_chain[ i ].insert( focus_chain[ i ].fromLast(), c );
00731                 else
00732                     focus_chain[ i ].append( c ); // otherwise add as the first one
00733                 }
00734             }
00735         }
00736     else    //now only on desktop, remove it anywhere else
00737         {
00738         for( int i=1; i<= numberOfDesktops(); i++)
00739             {
00740             if( i == c->desktop())
00741                 {
00742                 if( change == FocusChainMakeFirst )
00743                     {
00744                     focus_chain[ i ].remove( c );
00745                     focus_chain[ i ].append( c );
00746                     }
00747                 else if( change == FocusChainMakeLast )
00748                     {
00749                     focus_chain[ i ].remove( c );
00750                     focus_chain[ i ].prepend( c );
00751                     }
00752                 else if( !focus_chain[ i ].contains( c ))
00753                     {
00754                     if( active_client != NULL && active_client != c
00755                         && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
00756                         focus_chain[ i ].insert( focus_chain[ i ].fromLast(), c );
00757                     else
00758                         focus_chain[ i ].append( c ); // otherwise add as the first one
00759                     }
00760                 }
00761             else
00762                 focus_chain[ i ].remove( c );
00763             }
00764         }
00765     if( change == FocusChainMakeFirst )
00766         {
00767         global_focus_chain.remove( c );
00768         global_focus_chain.append( c );
00769         }
00770     else if( change == FocusChainMakeLast )
00771         {
00772         global_focus_chain.remove( c );
00773         global_focus_chain.prepend( c );
00774         }
00775     else if( !global_focus_chain.contains( c ))
00776         {
00777         if( active_client != NULL && active_client != c
00778             && !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client )
00779             global_focus_chain.insert( global_focus_chain.fromLast(), c );
00780         else
00781             global_focus_chain.append( c ); // otherwise add as the first one
00782         }
00783     }
00784 
00785 void Workspace::updateOverlappingShadows(unsigned long window)
00786     {
00787     Client *client;
00788     
00789     if ((client = findClient(WindowMatchPredicate((WId)window))))
00790         // Redraw overlapping shadows without waiting for the specified window
00791         // to redraw its own shadow
00792         client->drawOverlappingShadows(false);
00793     }
00794 
00795 void Workspace::setShadowed(unsigned long window, bool shadowed)
00796     {
00797     Client *client;
00798     
00799     if ((client = findClient(WindowMatchPredicate((WId)window))))
00800         client->setShadowed(shadowed);
00801     }
00802 
00803 void Workspace::updateCurrentTopMenu()
00804     {
00805     if( !managingTopMenus())
00806         return;
00807     // toplevel menubar handling
00808     Client* menubar = 0;
00809     bool block_desktop_menubar = false;
00810     if( active_client )
00811         {
00812         // show the new menu bar first...
00813         Client* menu_client = active_client;
00814         for(;;)
00815             {
00816             if( menu_client->isFullScreen())
00817                 block_desktop_menubar = true;
00818             for( ClientList::ConstIterator it = menu_client->transients().begin();
00819                  it != menu_client->transients().end();
00820                  ++it )
00821                 if( (*it)->isTopMenu())
00822                     {
00823                     menubar = *it;
00824                     break;
00825                     }
00826             if( menubar != NULL || !menu_client->isTransient())
00827                 break;
00828             if( menu_client->isModal() || menu_client->transientFor() == NULL )
00829                 break; // don't use mainwindow's menu if this is modal or group transient
00830             menu_client = menu_client->transientFor();
00831             }
00832         if( !menubar )
00833             { // try to find any topmenu from the application (#72113)
00834             for( ClientList::ConstIterator it = active_client->group()->members().begin();
00835                  it != active_client->group()->members().end();
00836                  ++it )
00837                 if( (*it)->isTopMenu())
00838                     {
00839                     menubar = *it;
00840                     break;
00841                     }
00842             }
00843         }
00844     if( !menubar && !block_desktop_menubar && options->desktopTopMenu())
00845         {
00846         // Find the menubar of the desktop
00847         Client* desktop = findDesktop( true, currentDesktop());
00848         if( desktop != NULL )
00849             {
00850             for( ClientList::ConstIterator it = desktop->transients().begin();
00851                  it != desktop->transients().end();
00852                  ++it )
00853                 if( (*it)->isTopMenu())
00854                     {
00855                     menubar = *it;
00856                     break;
00857                     }
00858             }
00859         // TODO to be cleaned app with window grouping
00860         // Without qt-copy patch #0009, the topmenu and desktop are not in the same group,
00861         // thus the topmenu is not transient for it :-/.
00862         if( menubar == NULL )
00863             {
00864             for( ClientList::ConstIterator it = topmenus.begin();
00865                  it != topmenus.end();
00866                  ++it )
00867                 if( (*it)->wasOriginallyGroupTransient()) // kdesktop's topmenu has WM_TRANSIENT_FOR
00868                     {                                     // set pointing to the root window
00869                     menubar = *it;                        // to recognize it here
00870                     break;                                // Also, with the xroot hack in kdesktop,
00871                     }                                     // there's no NET::Desktop window to be transient for
00872             }
00873         }
00874 
00875 //    kdDebug() << "CURRENT TOPMENU:" << menubar << ":" << active_client << endl;
00876     if ( menubar )
00877         {
00878         if( active_client && !menubar->isOnDesktop( active_client->desktop()))
00879             menubar->setDesktop( active_client->desktop());
00880         menubar->hideClient( false );
00881         topmenu_space->hide();
00882         // make it appear like it's been raised manually - it's in the Dock layer anyway,
00883         // and not raising it could mess up stacking order of topmenus within one application,
00884         // and thus break raising of mainclients in raiseClient()
00885         unconstrained_stacking_order.remove( menubar );
00886         unconstrained_stacking_order.append( menubar );
00887         }
00888     else if( !block_desktop_menubar )
00889         { // no topmenu active - show the space window, so that there's not empty space
00890         topmenu_space->show();
00891         }
00892 
00893     // ... then hide the other ones. Avoids flickers.
00894     for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) 
00895         {
00896         if( (*it)->isTopMenu() && (*it) != menubar )
00897             (*it)->hideClient( true );
00898         }
00899     }
00900 
00901 
00902 void Workspace::updateToolWindows( bool also_hide )
00903     {
00904     // TODO what if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
00905     if( !options->hideUtilityWindowsForInactive )
00906         {
00907         for( ClientList::ConstIterator it = clients.begin();
00908              it != clients.end();
00909              ++it )
00910             (*it)->hideClient( false );
00911         return;
00912         }
00913     const Group* group = NULL;
00914     const Client* client = active_client;
00915 // Go up in transiency hiearchy, if the top is found, only tool transients for the top mainwindow
00916 // will be shown; if a group transient is group, all tools in the group will be shown
00917     while( client != NULL )
00918         {
00919         if( !client->isTransient())
00920             break;
00921         if( client->groupTransient())
00922             {
00923             group = client->group();
00924             break;
00925             }
00926         client = client->transientFor();
00927         }
00928     // use stacking order only to reduce flicker, it doesn't matter if block_stacking_updates == 0,
00929     // i.e. if it's not up to date
00930 
00931     // SELI but maybe it should - what if a new client has been added that's not in stacking order yet?
00932     ClientList to_show, to_hide;
00933     for( ClientList::ConstIterator it = stacking_order.begin();
00934          it != stacking_order.end();
00935          ++it )
00936         {
00937         if( (*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar())
00938             {
00939             bool show = true;
00940             if( !(*it)->isTransient())
00941                 {
00942                 if( (*it)->group()->members().count() == 1 ) // has its own group, keep always visible
00943                     show = true;
00944                 else if( client != NULL && (*it)->group() == client->group())
00945                     show = true;
00946                 else
00947                     show = false;
00948                 }
00949             else
00950                 {
00951                 if( group != NULL && (*it)->group() == group )
00952                     show = true;
00953                 else if( client != NULL && client->hasTransient( (*it), true ))
00954                     show = true;
00955                 else
00956                     show = false;
00957                 }
00958             if( !show && also_hide )
00959                 {
00960                 const ClientList mainclients = (*it)->mainClients();
00961                 // don't hide utility windows which are standalone(?) or
00962                 // have e.g. kicker as mainwindow
00963                 if( mainclients.isEmpty())
00964                     show = true;
00965                 for( ClientList::ConstIterator it2 = mainclients.begin();
00966                      it2 != mainclients.end();
00967                      ++it2 )
00968                     {
00969                     if( (*it2)->isSpecialWindow())
00970                         show = true;
00971                     }
00972                 if( !show )
00973                     to_hide.append( *it );
00974                 }
00975             if( show )
00976                 to_show.append( *it );
00977             }
00978         } // first show new ones, then hide
00979     for( ClientList::ConstIterator it = to_show.fromLast();
00980          it != to_show.end();
00981          --it ) // from topmost
00982         // TODO since this is in stacking order, the order of taskbar entries changes :(
00983         (*it)->hideClient( false );
00984     if( also_hide )
00985         {
00986         for( ClientList::ConstIterator it = to_hide.begin();
00987              it != to_hide.end();
00988              ++it ) // from bottommost
00989             (*it)->hideClient( true );
00990         updateToolWindowsTimer.stop();
00991         }
00992     else // setActiveClient() is after called with NULL client, quickly followed
00993         {    // by setting a new client, which would result in flickering
00994         updateToolWindowsTimer.start( 50, true );
00995         }
00996     }
00997 
00998 void Workspace::slotUpdateToolWindows()
00999     {
01000     updateToolWindows( true );
01001     }
01002 
01006 void Workspace::updateColormap()
01007     {
01008     Colormap cmap = default_colormap;
01009     if ( activeClient() && activeClient()->colormap() != None )
01010         cmap = activeClient()->colormap();
01011     if ( cmap != installed_colormap ) 
01012         {
01013         XInstallColormap(tqt_xdisplay(), cmap );
01014         installed_colormap = cmap;
01015         }
01016     }
01017 
01018 void Workspace::reconfigure()
01019     {
01020     reconfigureTimer.start(200, true);
01021     }
01022 
01023 
01024 void Workspace::slotSettingsChanged(int category)
01025     {
01026     kdDebug(1212) << "Workspace::slotSettingsChanged()" << endl;
01027     if( category == (int) TDEApplication::SETTINGS_SHORTCUTS )
01028         readShortcuts();
01029     }
01030 
01034 KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
01035 
01036 void Workspace::slotReconfigure()
01037     {
01038     kdDebug(1212) << "Workspace::slotReconfigure()" << endl;
01039     reconfigureTimer.stop();
01040 
01041     TDEGlobal::config()->reparseConfiguration();
01042     unsigned long changed = options->updateSettings();
01043     tab_box->reconfigure();
01044     popupinfo->reconfigure();
01045     initPositioning->reinitCascading( 0 );
01046     readShortcuts();
01047     forEachClient( CheckIgnoreFocusStealingProcedure());
01048     updateToolWindows( true );
01049 
01050     if( mgr->reset( changed ))
01051         { // decorations need to be recreated
01052 #if 0 // This actually seems to make things worse now
01053         TQWidget curtain;
01054         curtain.setBackgroundMode( NoBackground );
01055         curtain.setGeometry( TQApplication::desktop()->geometry() );
01056         curtain.show();
01057 #endif
01058         for( ClientList::ConstIterator it = clients.begin();
01059                 it != clients.end();
01060                 ++it )
01061             {
01062             (*it)->updateDecoration( true, true );
01063             }
01064         mgr->destroyPreviousPlugin();
01065         }
01066     else
01067         {
01068         forEachClient( CheckBorderSizesProcedure());
01069         }
01070 
01071     checkElectricBorders();
01072 
01073     if( options->topMenuEnabled() && !managingTopMenus())
01074         {
01075         if( topmenu_selection->claim( false ))
01076             setupTopMenuHandling();
01077         else
01078             lostTopMenuSelection();
01079         }
01080     else if( !options->topMenuEnabled() && managingTopMenus())
01081         {
01082         topmenu_selection->release();
01083         lostTopMenuSelection();
01084         }
01085     topmenu_height = 0; // invalidate used menu height
01086     if( managingTopMenus())
01087         {
01088         updateTopMenuGeometry();
01089         updateCurrentTopMenu();
01090         }
01091 
01092     loadWindowRules();
01093     for( ClientList::Iterator it = clients.begin();
01094          it != clients.end();
01095          ++it )
01096         {
01097         (*it)->setupWindowRules( true );
01098         (*it)->applyWindowRules();
01099         discardUsedWindowRules( *it, false );
01100         }
01101 
01102     if (options->resetKompmgr) // need restart
01103         {
01104         bool tmp = options->useTranslucency;
01105 
01106         // If compton-tde is already running, sending SIGUSR2 will force a reload of its settings
01107         // Attempt to load the compton-tde pid file
01108         char *filename;
01109         const char *pidfile = "compton-tde.pid";
01110         char uidstr[sizeof(uid_t)*8+1];
01111         sprintf(uidstr, "%d", getuid());
01112         int n = strlen(P_tmpdir)+strlen(uidstr)+strlen(pidfile)+3;
01113         filename = (char*)malloc(n*sizeof(char)+1);
01114         memset(filename,0,n);
01115         strcat(filename, P_tmpdir);
01116         strcat(filename, "/.");
01117         strcat(filename, uidstr);
01118         strcat(filename, "-");
01119         strcat(filename, pidfile);
01120 
01121         // Now that we did all that by way of introduction...read the file!
01122         FILE *pFile;
01123         char buffer[255];
01124         pFile = fopen(filename, "r");
01125         int kompmgrpid = 0;
01126         if (pFile)
01127             {
01128             printf("[twin-workspace] Using '%s' as compton-tde pidfile\n\n", filename);
01129             // obtain file size
01130             fseek (pFile , 0 , SEEK_END);
01131             unsigned long lSize = ftell (pFile);
01132             if (lSize > 254)
01133                 lSize = 254;
01134             rewind (pFile);
01135             size_t result = fread (buffer, 1, lSize, pFile);
01136             fclose(pFile);
01137             if (result > 0)
01138                 {
01139                 kompmgrpid = atoi(buffer);
01140                 }
01141             }
01142 
01143         free(filename);
01144         filename = NULL;
01145 
01146         if (tmp)
01147             {
01148             if (kompmgrpid)
01149                 {
01150                 kill(kompmgrpid, SIGUSR2);
01151                 }
01152             else
01153                 {
01154                 stopKompmgr();
01155                 if (!kompmgr)
01156                     {
01157                     kompmgr = new TDEProcess;
01158                     connect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
01159                     *kompmgr << TDE_COMPOSITOR_BINARY;
01160                     }
01161                 TQTimer::singleShot( 200, this, TQT_SLOT(startKompmgr()) ); // wait some time to ensure system's ready for restart
01162                 }
01163             }
01164         else
01165             {
01166             if (kompmgrpid)
01167                 {
01168                 kill(kompmgrpid, SIGTERM);
01169                 }
01170             else
01171                 {
01172                 stopKompmgr();
01173                 }
01174             }
01175         }
01176     }
01177 
01178 void Workspace::loadDesktopSettings()
01179     {
01180     TDEConfig* c = TDEGlobal::config();
01181     TQCString groupname;
01182     if (screen_number == 0)
01183         groupname = "Desktops";
01184     else
01185         groupname.sprintf("Desktops-screen-%d", screen_number);
01186     TDEConfigGroupSaver saver(c,groupname);
01187 
01188     int n = c->readNumEntry("Number", 4);
01189     number_of_desktops = n;
01190     delete workarea;
01191     workarea = new TQRect[ n + 1 ];
01192     delete screenarea;
01193     screenarea = NULL;
01194     rootInfo->setNumberOfDesktops( number_of_desktops );
01195     desktop_focus_chain.resize( n );
01196     // make it +1, so that it can be accessed as [1..numberofdesktops]
01197     focus_chain.resize( n + 1 );
01198     for(int i = 1; i <= n; i++) 
01199         {
01200         TQString s = c->readEntry(TQString("Name_%1").arg(i),
01201                                 i18n("Desktop %1").arg(i));
01202         rootInfo->setDesktopName( i, s.utf8().data() );
01203         desktop_focus_chain[i-1] = i;
01204         }
01205     }
01206 
01207 void Workspace::saveDesktopSettings()
01208     {
01209     TDEConfig* c = TDEGlobal::config();
01210     TQCString groupname;
01211     if (screen_number == 0)
01212         groupname = "Desktops";
01213     else
01214         groupname.sprintf("Desktops-screen-%d", screen_number);
01215     TDEConfigGroupSaver saver(c,groupname);
01216 
01217     c->writeEntry("Number", number_of_desktops );
01218     for(int i = 1; i <= number_of_desktops; i++) 
01219         {
01220         TQString s = desktopName( i );
01221         TQString defaultvalue = i18n("Desktop %1").arg(i);
01222         if ( s.isEmpty() ) 
01223             {
01224             s = defaultvalue;
01225             rootInfo->setDesktopName( i, s.utf8().data() );
01226             }
01227 
01228         if (s != defaultvalue) 
01229             {
01230             c->writeEntry( TQString("Name_%1").arg(i), s );
01231             }
01232         else 
01233             {
01234             TQString currentvalue = c->readEntry(TQString("Name_%1").arg(i));
01235             if (currentvalue != defaultvalue)
01236                 c->writeEntry( TQString("Name_%1").arg(i), "" );
01237             }
01238         }
01239     }
01240 
01241 TQStringList Workspace::configModules(bool controlCenter)
01242     {
01243     TQStringList args;
01244     args <<  "tde-twindecoration.desktop";
01245     if (controlCenter)
01246         args << "tde-twinoptions.desktop";
01247     else if (kapp->authorizeControlModule("tde-twinoptions.desktop"))
01248         args  << "twinactions" << "twinfocus" <<  "twinmoving" << "twinadvanced" << "twinrules" << "twintranslucency";
01249     return args;
01250     }
01251 
01252 void Workspace::configureWM()
01253     {
01254     TDEApplication::tdeinitExec( "tdecmshell", configModules(false) );
01255     }
01256 
01260 void Workspace::doNotManage( TQString title )
01261     {
01262     doNotManageList.append( title );
01263     }
01264 
01268 bool Workspace::isNotManaged( const TQString& title )
01269     {
01270     for ( TQStringList::Iterator it = doNotManageList.begin(); it != doNotManageList.end(); ++it ) 
01271         {
01272         TQRegExp r( (*it) );
01273         if (r.search(title) != -1) 
01274             {
01275             doNotManageList.remove( it );
01276             return TRUE;
01277             }
01278         }
01279     return FALSE;
01280     }
01281 
01285 void Workspace::refresh() 
01286     {
01287     TQWidget w;
01288     w.setGeometry( TQApplication::desktop()->geometry() );
01289     w.show();
01290     w.hide();
01291     TQApplication::flushX();
01292     }
01293 
01301 class ObscuringWindows
01302     {
01303     public:
01304         ~ObscuringWindows();
01305         void create( Client* c );
01306     private:
01307         TQValueList<Window> obscuring_windows;
01308         static TQValueList<Window>* cached;
01309         static unsigned int max_cache_size;
01310     };
01311 
01312 TQValueList<Window>* ObscuringWindows::cached = 0;
01313 unsigned int ObscuringWindows::max_cache_size = 0;
01314 
01315 void ObscuringWindows::create( Client* c )
01316     {
01317     if( cached == 0 )
01318         cached = new TQValueList<Window>;
01319     Window obs_win;
01320     XWindowChanges chngs;
01321     int mask = CWSibling | CWStackMode;
01322     if( cached->count() > 0 ) 
01323         {
01324         cached->remove( obs_win = cached->first());
01325         chngs.x = c->x();
01326         chngs.y = c->y();
01327         chngs.width = c->width();
01328         chngs.height = c->height();
01329         mask |= CWX | CWY | CWWidth | CWHeight;
01330         }
01331     else 
01332         {
01333         XSetWindowAttributes a;
01334         a.background_pixmap = None;
01335         a.override_redirect = True;
01336         obs_win = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), c->x(), c->y(),
01337             c->width(), c->height(), 0, CopyFromParent, InputOutput,
01338             CopyFromParent, CWBackPixmap | CWOverrideRedirect, &a );
01339         }
01340     chngs.sibling = c->frameId();
01341     chngs.stack_mode = Below;
01342     XConfigureWindow( tqt_xdisplay(), obs_win, mask, &chngs );
01343     XMapWindow( tqt_xdisplay(), obs_win );
01344     obscuring_windows.append( obs_win );
01345     }
01346 
01347 ObscuringWindows::~ObscuringWindows()
01348     {
01349     max_cache_size = TQMAX( max_cache_size, obscuring_windows.count() + 4 ) - 1;
01350     for( TQValueList<Window>::ConstIterator it = obscuring_windows.begin();
01351          it != obscuring_windows.end();
01352          ++it ) 
01353         {
01354         XUnmapWindow( tqt_xdisplay(), *it );
01355         if( cached->count() < max_cache_size )
01356             cached->prepend( *it );
01357         else
01358             XDestroyWindow( tqt_xdisplay(), *it );
01359         }
01360     }
01361 
01362 
01369 bool Workspace::setCurrentDesktop( int new_desktop )
01370     {
01371     if (new_desktop < 1 || new_desktop > number_of_desktops )
01372         return false;
01373 
01374     closeActivePopup();
01375     ++block_focus;
01376 // TODO    Q_ASSERT( block_stacking_updates == 0 ); // make sure stacking_order is up to date
01377     StackingUpdatesBlocker blocker( this );
01378 
01379     int old_desktop = current_desktop;
01380     if (new_desktop != current_desktop) 
01381         {
01382         ++block_showing_desktop;
01383         /*
01384           optimized Desktop switching: unmapping done from back to front
01385           mapping done from front to back => less exposure events
01386         */
01387         Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop));
01388 
01389         ObscuringWindows obs_wins;
01390 
01391         current_desktop = new_desktop; // change the desktop (so that Client::updateVisibility() works)
01392 
01393         bool desktopHasCompositing = kapp->isCompositionManagerAvailable(); // Technically I should call isX11CompositionAvailable(), but it isn't initialized via my kapp constructir, and in this case it doesn't really matter anyway....
01394         if (!desktopHasCompositing) {
01395             // If composition is not in use then we can hide the old windows before showing the new ones
01396             for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
01397                 if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
01398                 {
01399                     if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop )) {
01400                         obs_wins.create( *it );
01401                     }
01402                     (*it)->updateVisibility();
01403                 }
01404             }
01405         }
01406 
01407         rootInfo->setCurrentDesktop( current_desktop ); // now propagate the change, after hiding, before showing
01408 
01409         if( movingClient && !movingClient->isOnDesktop( new_desktop ))
01410             movingClient->setDesktop( new_desktop );
01411 
01412         for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
01413             if ( (*it)->isOnDesktop( new_desktop ) ) {
01414                 (*it)->updateVisibility();
01415             }
01416         }
01417 
01418         if (desktopHasCompositing) {
01419             // If composition is in use then we cannot hide the old windows before showing the new ones, 
01420             // unless you happen to like the "flicker annoyingly to desktop" effect... :-P
01421             XSync( tqt_xdisplay(), false);  // Make absolutely certain all new windows are shown before hiding the old ones
01422             for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
01423                 if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
01424                 {
01425                     if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop )) {
01426                         obs_wins.create( *it );
01427                     }
01428                     (*it)->updateVisibility();
01429                 }
01430             }
01431         }
01432 
01433         --block_showing_desktop;
01434         if( showingDesktop()) // do this only after desktop change to avoid flicker
01435             resetShowingDesktop( false );
01436         }
01437 
01438     // restore the focus on this desktop
01439     --block_focus;
01440     Client* c = 0;
01441 
01442     if ( options->focusPolicyIsReasonable()) 
01443         {
01444         // Search in focus chain
01445         if ( movingClient != NULL && active_client == movingClient
01446             && focus_chain[currentDesktop()].contains( active_client )
01447             && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
01448             {
01449             c = active_client; // the requestFocus below will fail, as the client is already active
01450             }
01451         if ( !c ) 
01452             {
01453             for( ClientList::ConstIterator it = focus_chain[currentDesktop()].fromLast();
01454                  it != focus_chain[currentDesktop()].end();
01455                  --it )
01456                 {
01457                 if ( (*it)->isShown( false ) && (*it)->isOnCurrentDesktop())
01458                     {
01459                     c = *it;
01460                     break;
01461                     }
01462                 }
01463             }
01464         }
01465 
01466     //if "unreasonable focus policy"
01467     // and active_client is on_all_desktops and under mouse (hence == old_active_client),
01468     // conserve focus (thanks to Volker Schatz <V.Schatz at thphys.uni-heidelberg.de>)
01469     else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
01470       c = active_client;
01471 
01472     if( c == NULL && !desktops.isEmpty())
01473         c = findDesktop( true, currentDesktop());
01474 
01475     if( c != active_client )
01476         setActiveClient( NULL, Allowed );
01477 
01478     if ( c ) 
01479         requestFocus( c );
01480     else 
01481         focusToNull();
01482 
01483     updateCurrentTopMenu();
01484 
01485     // Update focus chain:
01486     //  If input: chain = { 1, 2, 3, 4 } and current_desktop = 3,
01487     //   Output: chain = { 3, 1, 2, 4 }.
01488 //    kdDebug(1212) << TQString("Switching to desktop #%1, at focus_chain[currentDesktop()] index %2\n")
01489 //      .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() ));
01490     for( int i = desktop_focus_chain.find( currentDesktop() ); i > 0; i-- )
01491         desktop_focus_chain[i] = desktop_focus_chain[i-1];
01492     desktop_focus_chain[0] = currentDesktop();
01493 
01494 //    TQString s = "desktop_focus_chain[] = { ";
01495 //    for( uint i = 0; i < desktop_focus_chain.size(); i++ )
01496 //        s += TQString::number(desktop_focus_chain[i]) + ", ";
01497 //    kdDebug(1212) << s << "}\n";
01498 
01499     if( old_desktop != 0 )  // not for the very first time
01500         popupinfo->showInfo( desktopName(currentDesktop()) );
01501     return true;
01502     }
01503 
01504 // called only from DCOP
01505 void Workspace::nextDesktop()
01506     {
01507     int desktop = currentDesktop() + 1;
01508     setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
01509     }
01510 
01511 // called only from DCOP
01512 void Workspace::previousDesktop()
01513     {
01514     int desktop = currentDesktop() - 1;
01515     setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
01516     }
01517 
01518 int Workspace::desktopToRight( int desktop ) const
01519     {
01520     int x,y;
01521     calcDesktopLayout(x,y);
01522     int dt = desktop-1;
01523     if (layoutOrientation == Qt::Vertical)
01524         {
01525         dt += y;
01526         if ( dt >= numberOfDesktops() ) 
01527             {
01528             if ( options->rollOverDesktops )
01529               dt -= numberOfDesktops();
01530             else
01531               return desktop;
01532             }
01533         }
01534     else
01535         {
01536         int d = (dt % x) + 1;
01537         if ( d >= x ) 
01538             {
01539             if ( options->rollOverDesktops )
01540               d -= x;
01541             else
01542               return desktop;
01543             }
01544         dt = dt - (dt % x) + d;
01545         }
01546     return dt+1;
01547     }
01548 
01549 int Workspace::desktopToLeft( int desktop ) const
01550     {
01551     int x,y;
01552     calcDesktopLayout(x,y);
01553     int dt = desktop-1;
01554     if (layoutOrientation == Qt::Vertical)
01555         {
01556         dt -= y;
01557         if ( dt < 0 ) 
01558             {
01559             if ( options->rollOverDesktops )
01560               dt += numberOfDesktops();
01561             else
01562               return desktop;
01563             }
01564         }
01565     else
01566         {
01567         int d = (dt % x) - 1;
01568         if ( d < 0 ) 
01569             {
01570             if ( options->rollOverDesktops )
01571               d += x;
01572             else
01573               return desktop;
01574             }
01575         dt = dt - (dt % x) + d;
01576         }
01577     return dt+1;
01578     }
01579 
01580 int Workspace::desktopUp( int desktop ) const
01581     {
01582     int x,y;
01583     calcDesktopLayout(x,y);
01584     int dt = desktop-1;
01585     if (layoutOrientation == Qt::Horizontal)
01586         {
01587         dt -= x;
01588         if ( dt < 0 ) 
01589             {
01590             if ( options->rollOverDesktops )
01591               dt += numberOfDesktops();
01592             else
01593               return desktop;
01594             }
01595         }
01596     else
01597         {
01598         int d = (dt % y) - 1;
01599         if ( d < 0 ) 
01600             {
01601             if ( options->rollOverDesktops )
01602               d += y;
01603             else
01604               return desktop;
01605             }
01606         dt = dt - (dt % y) + d;
01607         }
01608     return dt+1;
01609     }
01610 
01611 int Workspace::desktopDown( int desktop ) const
01612     {
01613     int x,y;
01614     calcDesktopLayout(x,y);
01615     int dt = desktop-1;
01616     if (layoutOrientation == Qt::Horizontal)
01617         {
01618         dt += x;
01619         if ( dt >= numberOfDesktops() ) 
01620             {
01621             if ( options->rollOverDesktops )
01622               dt -= numberOfDesktops();
01623             else
01624               return desktop;
01625             }
01626         }
01627     else
01628         {
01629         int d = (dt % y) + 1;
01630         if ( d >= y ) 
01631             {
01632             if ( options->rollOverDesktops )
01633               d -= y;
01634             else
01635               return desktop;
01636             }
01637         dt = dt - (dt % y) + d;
01638         }
01639     return dt+1;
01640     }
01641 
01642 
01646 void Workspace::setNumberOfDesktops( int n )
01647     {
01648     if ( n == number_of_desktops )
01649         return;
01650     int old_number_of_desktops = number_of_desktops;
01651     number_of_desktops = n;
01652 
01653     if( currentDesktop() > numberOfDesktops())
01654         setCurrentDesktop( numberOfDesktops());
01655 
01656     // if increasing the number, do the resizing now,
01657     // otherwise after the moving of windows to still existing desktops
01658     if( old_number_of_desktops < number_of_desktops ) 
01659         {
01660         rootInfo->setNumberOfDesktops( number_of_desktops );
01661         NETPoint* viewports = new NETPoint[ number_of_desktops ];
01662         rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01663         delete[] viewports;
01664         updateClientArea( true );
01665         focus_chain.resize( number_of_desktops + 1 );
01666         }
01667 
01668     // if the number of desktops decreased, move all
01669     // windows that would be hidden to the last visible desktop
01670     if( old_number_of_desktops > number_of_desktops ) 
01671         {
01672         for( ClientList::ConstIterator it = clients.begin();
01673               it != clients.end();
01674               ++it) 
01675             {
01676             if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
01677                 sendClientToDesktop( *it, numberOfDesktops(), true );
01678             }
01679         }
01680     if( old_number_of_desktops > number_of_desktops ) 
01681         {
01682         rootInfo->setNumberOfDesktops( number_of_desktops );
01683         NETPoint* viewports = new NETPoint[ number_of_desktops ];
01684         rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01685         delete[] viewports;
01686         updateClientArea( true );
01687         focus_chain.resize( number_of_desktops + 1 );
01688         }
01689 
01690     saveDesktopSettings();
01691 
01692     // Resize and reset the desktop focus chain.
01693     desktop_focus_chain.resize( n );
01694     for( int i = 0; i < (int)desktop_focus_chain.size(); i++ )
01695         desktop_focus_chain[i] = i+1;
01696     }
01697 
01703 void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
01704     {
01705     bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
01706     c->setDesktop( desk );
01707     if ( c->desktop() != desk ) // no change or desktop forced
01708         return;
01709     desk = c->desktop(); // Client did range checking
01710 
01711     if ( c->isOnDesktop( currentDesktop() ) )
01712         {
01713         if ( c->wantsTabFocus() && options->focusPolicyIsReasonable()
01714             && !was_on_desktop // for stickyness changes
01715             && !dont_activate )
01716             requestFocus( c );
01717         else
01718             restackClientUnderActive( c );
01719         }
01720     else 
01721         {
01722         raiseClient( c );
01723         }
01724 
01725     ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01726     for( ClientList::ConstIterator it = transients_stacking_order.begin();
01727          it != transients_stacking_order.end();
01728          ++it )
01729         sendClientToDesktop( *it, desk, dont_activate );
01730     updateClientArea();
01731     }
01732 
01733 int Workspace::numScreens() const
01734     {
01735     if( !options->xineramaEnabled )
01736         return 0;
01737     return tqApp->desktop()->numScreens();
01738     }
01739 
01740 int Workspace::activeScreen() const
01741     {
01742     if( !options->xineramaEnabled )
01743         return 0;
01744     if( !options->activeMouseScreen )
01745         {
01746         if( activeClient() != NULL && !activeClient()->isOnScreen( active_screen ))
01747             return tqApp->desktop()->screenNumber( activeClient()->geometry().center());
01748         return active_screen;
01749         }
01750     return tqApp->desktop()->screenNumber( TQCursor::pos());
01751     }
01752 
01753 // check whether a client moved completely out of what's considered the active screen,
01754 // if yes, set a new active screen
01755 void Workspace::checkActiveScreen( const Client* c )
01756     {
01757     if( !options->xineramaEnabled )
01758         return;
01759     if( !c->isActive())
01760         return;
01761     if( !c->isOnScreen( active_screen ))
01762         active_screen = c->screen();
01763     }
01764 
01765 // called e.g. when a user clicks on a window, set active screen to be the screen
01766 // where the click occured
01767 void Workspace::setActiveScreenMouse( TQPoint mousepos )
01768     {
01769     if( !options->xineramaEnabled )
01770         return;
01771     active_screen = tqApp->desktop()->screenNumber( mousepos );
01772     }
01773 
01774 TQRect Workspace::screenGeometry( int screen ) const
01775     {
01776     if (( !options->xineramaEnabled ) || (kapp->desktop()->numScreens() < 2))
01777         return tqApp->desktop()->geometry();
01778     return tqApp->desktop()->screenGeometry( screen );
01779     }
01780 
01781 int Workspace::screenNumber( TQPoint pos ) const
01782     {
01783     if( !options->xineramaEnabled )
01784         return 0;
01785     return tqApp->desktop()->screenNumber( pos );
01786     }
01787 
01788 void Workspace::sendClientToScreen( Client* c, int screen )
01789     {
01790     if( c->screen() == screen ) // don't use isOnScreen(), that's true even when only partially
01791         return;
01792     GeometryUpdatesPostponer blocker( c );
01793     TQRect old_sarea = clientArea( MaximizeArea, c );
01794     TQRect sarea = clientArea( MaximizeArea, screen, c->desktop());
01795     c->setGeometry( sarea.x() - old_sarea.x() + c->x(), sarea.y() - old_sarea.y() + c->y(),
01796         c->size().width(), c->size().height());
01797     c->checkWorkspacePosition();
01798     ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01799     for( ClientList::ConstIterator it = transients_stacking_order.begin();
01800          it != transients_stacking_order.end();
01801          ++it )
01802         sendClientToScreen( *it, screen );
01803     if( c->isActive())
01804         active_screen = screen;
01805     }
01806 
01807 
01808 void Workspace::setDesktopLayout( int, int, int )
01809     { // DCOP-only, unused
01810     }
01811 
01812 void Workspace::updateDesktopLayout()
01813     {
01814     // rootInfo->desktopLayoutCorner(); // I don't find this worth bothering, feel free to
01815     layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal
01816         ? Qt::Horizontal : Qt::Vertical );
01817     layoutX = rootInfo->desktopLayoutColumnsRows().width();
01818     layoutY = rootInfo->desktopLayoutColumnsRows().height();
01819     if( layoutX == 0 && layoutY == 0 ) // not given, set default layout
01820         layoutY = 2;
01821     }
01822 
01823 void Workspace::calcDesktopLayout(int &x, int &y) const
01824     {
01825     x = layoutX; // <= 0 means compute it from the other and total number of desktops
01826     y = layoutY;
01827     if((x <= 0) && (y > 0))
01828        x = (numberOfDesktops()+y-1) / y;
01829     else if((y <=0) && (x > 0))
01830        y = (numberOfDesktops()+x-1) / x;
01831 
01832     if(x <=0)
01833        x = 1;
01834     if (y <= 0)
01835        y = 1;
01836     }
01837 
01842 bool Workspace::addSystemTrayWin( WId w )
01843     {
01844     if ( systemTrayWins.contains( w ) )
01845         return TRUE;
01846 
01847     NETWinInfo ni( tqt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
01848     WId trayWinFor = ni.kdeSystemTrayWinFor();
01849     if ( !trayWinFor )
01850         return FALSE;
01851     systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
01852     XSelectInput( tqt_xdisplay(), w,
01853                   StructureNotifyMask
01854                   );
01855     XAddToSaveSet( tqt_xdisplay(), w );
01856     propagateSystemTrayWins();
01857     return TRUE;
01858     }
01859 
01864 bool Workspace::removeSystemTrayWin( WId w, bool check )
01865     {
01866     if ( !systemTrayWins.contains( w ) )
01867         return FALSE;
01868     if( check )
01869         {
01870     // When getting UnmapNotify, it's not clear if it's the systray
01871     // reparenting the window into itself, or if it's the window
01872     // going away. This is obviously a flaw in the design, and we were
01873     // just lucky it worked for so long. Kicker's systray temporarily
01874     // sets _TDE_SYSTEM_TRAY_EMBEDDING property on the window while
01875     // embedding it, allowing KWin to figure out. Kicker just mustn't
01876     // crash before removing it again ... *shrug* .
01877         int num_props;
01878         Atom* props = XListProperties( tqt_xdisplay(), w, &num_props );
01879         if( props != NULL )
01880             {
01881             for( int i = 0;
01882                  i < num_props;
01883                  ++i )
01884                 if( props[ i ] == atoms->kde_system_tray_embedding )
01885                     {
01886                     XFree( props );
01887                     return false;
01888                     }
01889             XFree( props );
01890             }
01891         }
01892     systemTrayWins.remove( w );
01893     XRemoveFromSaveSet (tqt_xdisplay (), w);
01894     propagateSystemTrayWins();
01895     return TRUE;
01896     }
01897 
01898 
01902 void Workspace::propagateSystemTrayWins()
01903     {
01904     Window *cl = new Window[ systemTrayWins.count()];
01905 
01906     int i = 0;
01907     for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it ) 
01908         {
01909         cl[i++] =  (*it).win;
01910         }
01911 
01912     rootInfo->setKDESystemTrayWindows( cl, i );
01913     delete [] cl;
01914     }
01915 
01916 
01917 void Workspace::killWindowId( Window window_to_kill )
01918     {
01919     if( window_to_kill == None )
01920         return;
01921     Window window = window_to_kill;
01922     Client* client = NULL;
01923     for(;;) 
01924         {
01925         client = findClient( FrameIdMatchPredicate( window ));
01926         if( client != NULL ) // found the client
01927             break;
01928         Window parent = 0L;
01929         Window root = 0L;
01930         Window* children = 0L;
01931         unsigned int children_count;
01932         XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
01933         if( children != NULL )
01934             XFree( children );
01935         if( window == root ) // we didn't find the client, probably an override-redirect window
01936             break;
01937         window = parent; // go up
01938         if( window == 0L )
01939             break;
01940         }
01941     if( client != NULL )
01942         client->killWindow();
01943     else
01944         XKillClient( tqt_xdisplay(), window_to_kill );
01945     }
01946 
01947 void Workspace::suspendWindowId( Window window_to_suspend )
01948     {
01949     if( window_to_suspend == None )
01950         return;
01951     Window window = window_to_suspend;
01952     Client* client = NULL;
01953     for(;;)
01954         {
01955         client = findClient( FrameIdMatchPredicate( window ));
01956         if( client != NULL ) // found the client
01957             break;
01958         Window parent = 0L;
01959         Window root = 0L;
01960         Window* children = 0L;
01961         unsigned int children_count;
01962         XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
01963         if( children != NULL )
01964             XFree( children );
01965         if( window == root ) // we didn't find the client, probably an override-redirect window
01966             break;
01967         window = parent; // go up
01968         if( window == 0L )
01969             break;
01970         }
01971     if( client != NULL )
01972         client->suspendWindow();
01973     else
01974         return;
01975     }
01976 
01977 void Workspace::resumeWindowId( Window window_to_resume )
01978     {
01979     if( window_to_resume == None )
01980         return;
01981     Window window = window_to_resume;
01982     Client* client = NULL;
01983     for(;;)
01984         {
01985         client = findClient( FrameIdMatchPredicate( window ));
01986         if( client != NULL ) // found the client
01987             break;
01988         Window parent = 0L;
01989         Window root = 0L;
01990         Window* children = 0L;
01991         unsigned int children_count;
01992         XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
01993         if( children != NULL )
01994             XFree( children );
01995         if( window == root ) // we didn't find the client, probably an override-redirect window
01996             break;
01997         window = parent; // go up
01998         if( window == 0L )
01999             break;
02000         }
02001     if( client != NULL )
02002         client->resumeWindow();
02003     else
02004         return;
02005     }
02006 
02007 
02008 bool Workspace::isResumeableWindowID( Window window_to_check )
02009     {
02010     if( window_to_check == None )
02011         return false;
02012     Window window = window_to_check;
02013     Client* client = NULL;
02014     for(;;)
02015         {
02016         client = findClient( FrameIdMatchPredicate( window ));
02017         if( client != NULL ) // found the client
02018             break;
02019         Window parent = 0L;
02020         Window root = 0L;
02021         Window* children = 0L;
02022         unsigned int children_count;
02023         XQueryTree( tqt_xdisplay(), window, &root, &parent, &children, &children_count );
02024         if( children != NULL )
02025             XFree( children );
02026         if( window == root ) // we didn't find the client, probably an override-redirect window
02027             break;
02028         window = parent; // go up
02029         if( window == 0L )
02030             break;
02031         }
02032     if( client != NULL )
02033         return client->isResumeable();
02034     else
02035         return false;
02036     }
02037 
02038 
02039 void Workspace::sendPingToWindow( Window window, Time timestamp )
02040     {
02041     rootInfo->sendPing( window, timestamp );
02042     }
02043 
02044 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
02045     {
02046     rootInfo->takeActivity( c->window(), timestamp, flags );
02047     pending_take_activity = c;
02048     }
02049 
02050 
02054 void Workspace::slotGrabWindow()
02055     {
02056     if ( active_client ) 
02057         {
02058         TQPixmap snapshot = TQPixmap::grabWindow( active_client->frameId() );
02059 
02060     //No XShape - no work.
02061         if( Shape::available()) 
02062             {
02063         //As the first step, get the mask from XShape.
02064             int count, order;
02065             XRectangle* rects = XShapeGetRectangles( tqt_xdisplay(), active_client->frameId(),
02066                                                      ShapeBounding, &count, &order);
02067         //The ShapeBounding region is the outermost shape of the window;
02068         //ShapeBounding - ShapeClipping is defined to be the border.
02069         //Since the border area is part of the window, we use bounding
02070         // to limit our work region
02071             if (rects) 
02072                 {
02073         //Create a TQRegion from the rectangles describing the bounding mask.
02074                 TQRegion contents;
02075                 for (int pos = 0; pos < count; pos++)
02076                     contents += TQRegion(rects[pos].x, rects[pos].y,
02077                                         rects[pos].width, rects[pos].height);
02078                 XFree(rects);
02079 
02080         //Create the bounding box.
02081                 TQRegion bbox(0, 0, snapshot.width(), snapshot.height());
02082 
02083         //Get the masked away area.
02084                 TQRegion maskedAway = bbox - contents;
02085                 TQMemArray<TQRect> maskedAwayRects = maskedAway.rects();
02086 
02087         //Construct a bitmap mask from the rectangles
02088                 TQBitmap mask( snapshot.width(), snapshot.height());
02089                 TQPainter p(&mask);
02090                 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
02091                 for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
02092                     p.fillRect(maskedAwayRects[pos], Qt::color0);
02093                 p.end();
02094                 snapshot.setMask(mask);
02095                 }
02096             }
02097 
02098         TQClipboard *cb = TQApplication::clipboard();
02099         cb->setPixmap( snapshot );
02100         }
02101     else
02102         slotGrabDesktop();
02103     }
02104 
02108 void Workspace::slotGrabDesktop()
02109     {
02110     TQPixmap p = TQPixmap::grabWindow( tqt_xrootwin() );
02111     TQClipboard *cb = TQApplication::clipboard();
02112     cb->setPixmap( p );
02113     }
02114 
02115 
02119 void Workspace::slotMouseEmulation()
02120     {
02121 
02122     if ( mouse_emulation ) 
02123         {
02124         XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME());
02125         mouse_emulation = FALSE;
02126         return;
02127         }
02128 
02129     if ( XGrabKeyboard(tqt_xdisplay(),
02130                        root, FALSE,
02131                        GrabModeAsync, GrabModeAsync,
02132                        GET_QT_X_TIME()) == GrabSuccess ) 
02133         {
02134         mouse_emulation = TRUE;
02135         mouse_emulation_state = 0;
02136         mouse_emulation_window = 0;
02137         }
02138     }
02139 
02146 WId Workspace::getMouseEmulationWindow()
02147     {
02148     Window root;
02149     Window child = tqt_xrootwin();
02150     int root_x, root_y, lx, ly;
02151     uint state;
02152     Window w;
02153     Client * c = 0;
02154     do 
02155         {
02156         w = child;
02157         if (!c)
02158             c = findClient( FrameIdMatchPredicate( w ));
02159         XQueryPointer( tqt_xdisplay(), w, &root, &child,
02160                        &root_x, &root_y, &lx, &ly, &state );
02161         } while  ( child != None && child != w );
02162 
02163     if ( c && !c->isActive() )
02164         activateClient( c );
02165     return (WId) w;
02166     }
02167 
02171 unsigned int Workspace::sendFakedMouseEvent( TQPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
02172     {
02173     if ( !w )
02174         return state;
02175     TQWidget* widget = TQWidget::find( w );
02176     if ( (!widget ||  widget->inherits(TQTOOLBUTTON_OBJECT_NAME_STRING) ) && !findClient( WindowMatchPredicate( w )) ) 
02177         {
02178         int x, y;
02179         Window xw;
02180         XTranslateCoordinates( tqt_xdisplay(), tqt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
02181         if ( type == EmuMove ) 
02182             { // motion notify events
02183             XEvent e;
02184             e.type = MotionNotify;
02185             e.xmotion.window = w;
02186             e.xmotion.root = tqt_xrootwin();
02187             e.xmotion.subwindow = w;
02188             e.xmotion.time = GET_QT_X_TIME();
02189             e.xmotion.x = x;
02190             e.xmotion.y = y;
02191             e.xmotion.x_root = pos.x();
02192             e.xmotion.y_root = pos.y();
02193             e.xmotion.state = state;
02194             e.xmotion.is_hint = NotifyNormal;
02195             XSendEvent( tqt_xdisplay(), w, TRUE, ButtonMotionMask, &e );
02196             }
02197         else 
02198             {
02199             XEvent e;
02200             e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
02201             e.xbutton.window = w;
02202             e.xbutton.root = tqt_xrootwin();
02203             e.xbutton.subwindow = w;
02204             e.xbutton.time = GET_QT_X_TIME();
02205             e.xbutton.x = x;
02206             e.xbutton.y = y;
02207             e.xbutton.x_root = pos.x();
02208             e.xbutton.y_root = pos.y();
02209             e.xbutton.state = state;
02210             e.xbutton.button = button;
02211             XSendEvent( tqt_xdisplay(), w, TRUE, ButtonPressMask, &e );
02212 
02213             if ( type == EmuPress ) 
02214                 {
02215                 switch ( button ) 
02216                     {
02217                     case 2:
02218                         state |= Button2Mask;
02219                         break;
02220                     case 3:
02221                         state |= Button3Mask;
02222                         break;
02223                     default: // 1
02224                         state |= Button1Mask;
02225                         break;
02226                     }
02227                 }
02228             else 
02229                 {
02230                 switch ( button ) 
02231                     {
02232                     case 2:
02233                         state &= ~Button2Mask;
02234                         break;
02235                     case 3:
02236                         state &= ~Button3Mask;
02237                         break;
02238                     default: // 1
02239                         state &= ~Button1Mask;
02240                         break;
02241                     }
02242                 }
02243             }
02244         }
02245     return state;
02246     }
02247 
02251 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
02252     {
02253     if ( root != tqt_xrootwin() )
02254         return FALSE;
02255     int kc = XkbKeycodeToKeysym(tqt_xdisplay(), ev.keycode, 0, 0);
02256     int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
02257 
02258     bool is_control = km & ControlMask;
02259     bool is_alt = km & Mod1Mask;
02260     bool is_shift = km & ShiftMask;
02261     int delta = is_control?1:is_alt?32:8;
02262     TQPoint pos = TQCursor::pos();
02263 
02264     switch ( kc ) 
02265         {
02266         case XK_Left:
02267         case XK_KP_Left:
02268             pos.rx() -= delta;
02269             break;
02270         case XK_Right:
02271         case XK_KP_Right:
02272             pos.rx() += delta;
02273             break;
02274         case XK_Up:
02275         case XK_KP_Up:
02276             pos.ry() -= delta;
02277             break;
02278         case XK_Down:
02279         case XK_KP_Down:
02280             pos.ry() += delta;
02281             break;
02282         case XK_F1:
02283             if ( !mouse_emulation_state )
02284                 mouse_emulation_window = getMouseEmulationWindow();
02285             if ( (mouse_emulation_state & Button1Mask) == 0 )
02286                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
02287             if ( !is_shift )
02288                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02289             break;
02290         case XK_F2:
02291             if ( !mouse_emulation_state )
02292                 mouse_emulation_window = getMouseEmulationWindow();
02293             if ( (mouse_emulation_state & Button2Mask) == 0 )
02294                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
02295             if ( !is_shift )
02296                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
02297             break;
02298         case XK_F3:
02299             if ( !mouse_emulation_state )
02300                 mouse_emulation_window = getMouseEmulationWindow();
02301             if ( (mouse_emulation_state & Button3Mask) == 0 )
02302                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
02303             if ( !is_shift )
02304                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02305             break;
02306         case XK_Return:
02307         case XK_space:
02308         case XK_KP_Enter:
02309         case XK_KP_Space: 
02310             {
02311             if ( !mouse_emulation_state ) 
02312                 {
02313             // nothing was pressed, fake a LMB click
02314                 mouse_emulation_window = getMouseEmulationWindow();
02315                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
02316                 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02317                 }
02318             else 
02319                 { // release all
02320                 if ( mouse_emulation_state & Button1Mask )
02321                     mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02322                 if ( mouse_emulation_state & Button2Mask )
02323                     mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
02324                 if ( mouse_emulation_state & Button3Mask )
02325                     mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02326                 }
02327             }
02328     // fall through
02329         case XK_Escape:
02330             XUngrabKeyboard(tqt_xdisplay(), GET_QT_X_TIME());
02331             mouse_emulation = FALSE;
02332             return TRUE;
02333         default:
02334             return FALSE;
02335         }
02336 
02337     TQCursor::setPos( pos );
02338     if ( mouse_emulation_state )
02339         mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0,  mouse_emulation_state );
02340     return TRUE;
02341 
02342     }
02343 
02349 TQWidget* Workspace::desktopWidget()
02350     {
02351     return desktop_widget;
02352     }
02353 
02354 //Delayed focus functions
02355 void Workspace::delayFocus()
02356     {
02357     requestFocus( delayfocus_client );
02358     cancelDelayFocus();
02359     }
02360     
02361 void Workspace::requestDelayFocus( Client* c )
02362     {
02363     delayfocus_client = c;
02364     delete delayFocusTimer;
02365     delayFocusTimer = new TQTimer( this );
02366     connect( delayFocusTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( delayFocus() ) );
02367     delayFocusTimer->start( options->delayFocusInterval, TRUE  );
02368     }
02369     
02370 void Workspace::cancelDelayFocus()
02371     {
02372     delete delayFocusTimer;
02373     delayFocusTimer = 0;
02374     }
02375 
02376 // Electric Borders
02377 //========================================================================//
02378 // Electric Border Window management. Electric borders allow a user
02379 // to change the virtual desktop by moving the mouse pointer to the
02380 // borders. Technically this is done with input only windows. Since
02381 // electric borders can be switched on and off, we have these two
02382 // functions to create and destroy them.
02383 void Workspace::checkElectricBorders( bool force )
02384     {
02385     if( force )
02386         destroyBorderWindows();
02387     
02388     electric_current_border = 0;
02389 
02390     TQRect r = TQApplication::desktop()->geometry();
02391     electricTop = r.top();
02392     electricBottom = r.bottom();
02393     electricLeft = r.left();
02394     electricRight = r.right();
02395 
02396     if (options->electricBorders() == Options::ElectricAlways)
02397        createBorderWindows();
02398     else
02399        destroyBorderWindows();
02400     }
02401 
02402 void Workspace::createBorderWindows()
02403     {
02404     if ( electric_have_borders )
02405         return;
02406 
02407     electric_have_borders = true;
02408 
02409     TQRect r = TQApplication::desktop()->geometry();
02410     XSetWindowAttributes attributes;
02411     unsigned long valuemask;
02412     attributes.override_redirect = True;
02413     attributes.event_mask =  ( EnterWindowMask | LeaveWindowMask );
02414     valuemask=  (CWOverrideRedirect | CWEventMask | CWCursor );
02415     attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
02416                                           XC_sb_up_arrow);
02417     electric_top_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
02418                                 0,0,
02419                                 r.width(),1,
02420                                 0,
02421                                 CopyFromParent, InputOnly,
02422                                 CopyFromParent,
02423                                 valuemask, &attributes);
02424     XMapWindow(tqt_xdisplay(), electric_top_border);
02425 
02426     attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
02427                                           XC_sb_down_arrow);
02428     electric_bottom_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
02429                                    0,r.height()-1,
02430                                    r.width(),1,
02431                                    0,
02432                                    CopyFromParent, InputOnly,
02433                                    CopyFromParent,
02434                                    valuemask, &attributes);
02435     XMapWindow(tqt_xdisplay(), electric_bottom_border);
02436 
02437     attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
02438                                           XC_sb_left_arrow);
02439     electric_left_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
02440                                  0,0,
02441                                  1,r.height(),
02442                                  0,
02443                                  CopyFromParent, InputOnly,
02444                                  CopyFromParent,
02445                                  valuemask, &attributes);
02446     XMapWindow(tqt_xdisplay(), electric_left_border);
02447 
02448     attributes.cursor = XCreateFontCursor(tqt_xdisplay(),
02449                                           XC_sb_right_arrow);
02450     electric_right_border = XCreateWindow (tqt_xdisplay(), tqt_xrootwin(),
02451                                   r.width()-1,0,
02452                                   1,r.height(),
02453                                   0,
02454                                   CopyFromParent, InputOnly,
02455                                   CopyFromParent,
02456                                   valuemask, &attributes);
02457     XMapWindow(tqt_xdisplay(),  electric_right_border);
02458     // Set XdndAware on the windows, so that DND enter events are received (#86998)
02459     Atom version = 4; // XDND version
02460     XChangeProperty( tqt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
02461         32, PropModeReplace, ( unsigned char* )&version, 1 );
02462     XChangeProperty( tqt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
02463         32, PropModeReplace, ( unsigned char* )&version, 1 );
02464     XChangeProperty( tqt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
02465         32, PropModeReplace, ( unsigned char* )&version, 1 );
02466     XChangeProperty( tqt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
02467         32, PropModeReplace, ( unsigned char* )&version, 1 );
02468     }
02469 
02470 
02471 // Electric Border Window management. Electric borders allow a user
02472 // to change the virtual desktop by moving the mouse pointer to the
02473 // borders. Technically this is done with input only windows. Since
02474 // electric borders can be switched on and off, we have these two
02475 // functions to create and destroy them.
02476 void Workspace::destroyBorderWindows()
02477     {
02478     if( !electric_have_borders)
02479       return;
02480 
02481     electric_have_borders = false;
02482 
02483     if(electric_top_border)
02484       XDestroyWindow(tqt_xdisplay(),electric_top_border);
02485     if(electric_bottom_border)
02486       XDestroyWindow(tqt_xdisplay(),electric_bottom_border);
02487     if(electric_left_border)
02488       XDestroyWindow(tqt_xdisplay(),electric_left_border);
02489     if(electric_right_border)
02490       XDestroyWindow(tqt_xdisplay(),electric_right_border);
02491 
02492     electric_top_border    = None;
02493     electric_bottom_border = None;
02494     electric_left_border   = None;
02495     electric_right_border  = None;
02496     }
02497 
02498 void Workspace::clientMoved(const TQPoint &pos, Time now)
02499     {
02500     if (options->electricBorders() == Options::ElectricDisabled)
02501        return;
02502 
02503     if ((pos.x() != electricLeft) &&
02504         (pos.x() != electricRight) &&
02505         (pos.y() != electricTop) &&
02506         (pos.y() != electricBottom))
02507        return;
02508 
02509     Time treshold_set = options->electricBorderDelay(); // set timeout
02510     Time treshold_reset = 250; // reset timeout
02511     int distance_reset = 30; // Mouse should not move more than this many pixels
02512 
02513     int border = 0;
02514     if (pos.x() == electricLeft)
02515        border = 1;
02516     else if (pos.x() == electricRight)
02517        border = 2;
02518     else if (pos.y() == electricTop)
02519        border = 3;
02520     else if (pos.y() == electricBottom)
02521        border = 4;
02522 
02523     if ((electric_current_border == border) &&
02524         (timestampDiff(electric_time_last, now) < treshold_reset) &&
02525         ((pos-electric_push_point).manhattanLength() < distance_reset))
02526         {
02527         electric_time_last = now;
02528 
02529         if (timestampDiff(electric_time_first, now) > treshold_set)
02530             {
02531             electric_current_border = 0;
02532 
02533             TQRect r = TQApplication::desktop()->geometry();
02534             int offset;
02535 
02536             int desk_before = currentDesktop();
02537             switch(border)
02538                 {
02539                 case 1:
02540                  slotSwitchDesktopLeft();
02541                  if (currentDesktop() != desk_before) 
02542                     {
02543                     offset = r.width() / 5;
02544                     TQCursor::setPos(r.width() - offset, pos.y());
02545                     }
02546                 break;
02547 
02548                case 2:
02549                 slotSwitchDesktopRight();
02550                 if (currentDesktop() != desk_before) 
02551                     {
02552                     offset = r.width() / 5;
02553                     TQCursor::setPos(offset, pos.y());
02554                     }
02555                 break;
02556 
02557                case 3:
02558                 slotSwitchDesktopUp();
02559                 if (currentDesktop() != desk_before) 
02560                     {
02561                     offset = r.height() / 5;
02562                     TQCursor::setPos(pos.x(), r.height() - offset);
02563                     }
02564                 break;
02565 
02566                case 4:
02567                 slotSwitchDesktopDown();
02568                 if (currentDesktop() != desk_before) 
02569                     {
02570                     offset = r.height() / 5;
02571                     TQCursor::setPos(pos.x(), offset);
02572                     }
02573                 break;
02574                 }
02575             return;
02576             }
02577         }
02578     else 
02579         {
02580         electric_current_border = border;
02581         electric_time_first = now;
02582         electric_time_last = now;
02583         electric_push_point = pos;
02584         }
02585 
02586     int mouse_warp = 1;
02587 
02588   // reset the pointer to find out wether the user is really pushing
02589     switch( border)
02590         {
02591         case 1: TQCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
02592         case 2: TQCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
02593         case 3: TQCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
02594         case 4: TQCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
02595         }
02596     }
02597 
02598 // this function is called when the user entered an electric border
02599 // with the mouse. It may switch to another virtual desktop
02600 bool Workspace::electricBorder(XEvent *e)
02601     {
02602     if( !electric_have_borders )
02603         return false;
02604     if( e->type == EnterNotify )
02605         {
02606         if( e->xcrossing.window == electric_top_border ||
02607             e->xcrossing.window == electric_left_border ||
02608             e->xcrossing.window == electric_bottom_border ||
02609             e->xcrossing.window == electric_right_border)
02610             // the user entered an electric border
02611             {
02612             clientMoved( TQPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
02613             return true;
02614             }
02615         }
02616     if( e->type == ClientMessage )
02617         {
02618         if( e->xclient.message_type == atoms->xdnd_position
02619             && ( e->xclient.window == electric_top_border
02620                  || e->xclient.window == electric_bottom_border
02621                  || e->xclient.window == electric_left_border
02622                  || e->xclient.window == electric_right_border ))
02623             {
02624             updateXTime();
02625             clientMoved( TQPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), GET_QT_X_TIME() );
02626             return true;
02627             }
02628         }
02629     return false;
02630     }
02631 
02632 // electric borders (input only windows) have to be always on the
02633 // top. For that reason kwm calls this function always after some
02634 // windows have been raised.
02635 void Workspace::raiseElectricBorders()
02636     {
02637 
02638     if(electric_have_borders)
02639         {
02640         XRaiseWindow(tqt_xdisplay(), electric_top_border);
02641         XRaiseWindow(tqt_xdisplay(), electric_left_border);
02642         XRaiseWindow(tqt_xdisplay(), electric_bottom_border);
02643         XRaiseWindow(tqt_xdisplay(), electric_right_border);
02644         }
02645     }
02646 
02647 void Workspace::addTopMenu( Client* c )
02648     {
02649     assert( c->isTopMenu());
02650     assert( !topmenus.contains( c ));
02651     topmenus.append( c );
02652     if( managingTopMenus())
02653         {
02654         int minsize = c->minSize().height();
02655         if( minsize > topMenuHeight())
02656             {
02657             topmenu_height = minsize;
02658             updateTopMenuGeometry();
02659             }
02660         updateTopMenuGeometry( c );
02661         updateCurrentTopMenu();
02662         }
02663 //        kdDebug() << "NEW TOPMENU:" << c << endl;
02664     }
02665 
02666 void Workspace::removeTopMenu( Client* c )
02667     {
02668 //    if( c->isTopMenu())
02669 //        kdDebug() << "REMOVE TOPMENU:" << c << endl;
02670     assert( c->isTopMenu());
02671     assert( topmenus.contains( c ));
02672     topmenus.remove( c );
02673     updateCurrentTopMenu();
02674     // TODO reduce topMenuHeight() if possible?
02675     }
02676 
02677 void Workspace::lostTopMenuSelection()
02678     {
02679 //    kdDebug() << "lost TopMenu selection" << endl;
02680     // make sure this signal is always set when not owning the selection
02681     disconnect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
02682     connect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
02683     if( !managing_topmenus )
02684         return;
02685     connect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
02686     disconnect( topmenu_selection, TQT_SIGNAL( lostOwnership()), this, TQT_SLOT( lostTopMenuSelection()));
02687     managing_topmenus = false;
02688     delete topmenu_space;
02689     topmenu_space = NULL;
02690     updateClientArea();
02691     for( ClientList::ConstIterator it = topmenus.begin();
02692          it != topmenus.end();
02693          ++it )
02694         (*it)->checkWorkspacePosition();
02695     }
02696 
02697 void Workspace::lostTopMenuOwner()
02698     {
02699     if( !options->topMenuEnabled())
02700         return;
02701 //    kdDebug() << "TopMenu selection lost owner" << endl;
02702     if( !topmenu_selection->claim( false ))
02703         {
02704 //        kdDebug() << "Failed to claim TopMenu selection" << endl;
02705         return;
02706         }
02707 //    kdDebug() << "claimed TopMenu selection" << endl;
02708     setupTopMenuHandling();
02709     }
02710 
02711 void Workspace::setupTopMenuHandling()
02712     {
02713     if( managing_topmenus )
02714         return;
02715     connect( topmenu_selection, TQT_SIGNAL( lostOwnership()), this, TQT_SLOT( lostTopMenuSelection()));
02716     disconnect( topmenu_watcher, TQT_SIGNAL( lostOwner()), this, TQT_SLOT( lostTopMenuOwner()));
02717     managing_topmenus = true;
02718     topmenu_space = new TQWidget;
02719     Window stack[ 2 ];
02720     stack[ 0 ] = supportWindow->winId();
02721     stack[ 1 ] = topmenu_space->winId();
02722     XRestackWindows(tqt_xdisplay(), stack, 2);
02723     updateTopMenuGeometry();
02724     topmenu_space->show();
02725     updateClientArea();
02726     updateCurrentTopMenu();
02727     }
02728 
02729 int Workspace::topMenuHeight() const
02730     {
02731     if( topmenu_height == 0 )
02732         { // simply create a dummy menubar and use its preffered height as the menu height
02733         KMenuBar tmpmenu;
02734         tmpmenu.insertItem( "dummy" );
02735         topmenu_height = tmpmenu.sizeHint().height();
02736         }
02737     return topmenu_height;
02738     }
02739 
02740 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
02741     {
02742     return mgr->createDecoration( bridge );
02743     }
02744 
02745 TQString Workspace::desktopName( int desk ) const
02746     {
02747     return TQString::fromUtf8( rootInfo->desktopName( desk ) );
02748     }
02749 
02750 bool Workspace::checkStartupNotification( Window w, TDEStartupInfoId& id, TDEStartupInfoData& data )
02751     {
02752     return startup->checkStartup( w, id, data ) == TDEStartupInfo::Match;
02753     }
02754 
02759 void Workspace::focusToNull()
02760     {
02761     XSetInputFocus(tqt_xdisplay(), null_focus_window, RevertToPointerRoot, GET_QT_X_TIME() );
02762     }
02763 
02764 void Workspace::helperDialog( const TQString& message, const Client* c )
02765     {
02766     TQStringList args;
02767     TQString type;
02768     if( message == "noborderaltf3" )
02769         {
02770         TQString shortcut = TQString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02771             .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02772         args << "--msgbox" <<
02773               i18n( "You have selected to show a window without its border.\n"
02774                     "Without the border, you will not be able to enable the border "
02775                     "again using the mouse: use the window operations menu instead, "
02776                     "activated using the %1 keyboard shortcut." )
02777                 .arg( shortcut );
02778         type = "altf3warning";
02779         }
02780     else if( message == "fullscreenaltf3" )
02781         {
02782         TQString shortcut = TQString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02783             .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02784         args << "--msgbox" <<
02785               i18n( "You have selected to show a window in fullscreen mode.\n"
02786                     "If the application itself does not have an option to turn the fullscreen "
02787                     "mode off you will not be able to disable it "
02788                     "again using the mouse: use the window operations menu instead, "
02789                     "activated using the %1 keyboard shortcut." )
02790                 .arg( shortcut );
02791         type = "altf3warning";
02792         }
02793     else
02794         assert( false );
02795     TDEProcess proc;
02796     proc << "kdialog" << args;
02797     if( !type.isEmpty())
02798         {
02799         TDEConfig cfg( "twin_dialogsrc" );
02800         cfg.setGroup( "Notification Messages" ); // this depends on KMessageBox
02801         if( !cfg.readBoolEntry( type, true )) // has don't show again checked
02802             return;                           // save launching kdialog
02803         proc << "--dontagain" << "twin_dialogsrc:" + type;
02804         }
02805     if( c != NULL )
02806         proc << "--embed" << TQString::number( c->window());
02807     proc.start( TDEProcess::DontCare );
02808     }
02809 
02810 
02811 // kompmgr stuff
02812 
02813 void Workspace::startKompmgr()
02814 {
02815     // See if the desktop is loaded yet
02816     Atom type;
02817     int format;
02818     unsigned long length, after;
02819     unsigned char* data_root;
02820     Atom prop_root;
02821     prop_root = XInternAtom(tqt_xdisplay(), "_XROOTPMAP_ID", False);
02822     if( XGetWindowProperty( tqt_xdisplay(), tqt_xrootwin(), prop_root, 0L, 1L, False, AnyPropertyType, &type, &format, &length, &after, &data_root) == Success && data_root != NULL ) {
02823         // Root pixmap is available; OK to load...
02824     }
02825     else {
02826         // Try again a bit later!
02827         TQTimer::singleShot( 200, this, TQT_SLOT(startKompmgr()) );
02828         return;
02829     }
02830     pid_t kompmgrpid = getCompositorPID();
02831     if (kompmgrpid && kill(kompmgrpid, 0) >= 0)
02832         {
02833         // Active PID file detected; do not attempt to restart
02834         return;
02835         }
02836     if (!kompmgr || kompmgr->isRunning()) {
02837         kompmgrReloadSettings();
02838         return;
02839     }
02840     if (!kompmgr->start(TDEProcess::OwnGroup, TDEProcess::Stderr))
02841     {
02842         options->useTranslucency = FALSE;
02843         TDEProcess proc;
02844         proc << "kdialog" << "--error"
02845             << i18n("The Composite Manager could not be started.\\nMake sure you have \"" TDE_COMPOSITOR_BINARY "\" in a $PATH directory.")
02846             << "--title" << "Composite Manager Failure";
02847         proc.start(TDEProcess::DontCare);
02848     }
02849     else
02850     {
02851         delete kompmgr_selection;
02852         char selection_name[ 100 ];
02853         sprintf( selection_name, "_NET_WM_CM_S%d", DefaultScreen( tqt_xdisplay()));
02854         kompmgr_selection = new TDESelectionOwner( selection_name );
02855         connect( kompmgr_selection, TQT_SIGNAL( lostOwnership()), TQT_SLOT( stopKompmgr()));
02856         kompmgr_selection->claim( true );
02857         connect(kompmgr, TQT_SIGNAL(processExited(TDEProcess*)), TQT_SLOT(restartKompmgr(TDEProcess*)));
02858         options->useTranslucency = TRUE;
02859         //allowKompmgrRestart = FALSE;
02860         //TQTimer::singleShot( 60000, this, TQT_SLOT(unblockKompmgrRestart()) );
02861         TQByteArray ba;
02862         TQDataStream arg(ba, IO_WriteOnly);
02863         arg << "";
02864         kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStarted()", ba);
02865     }
02866     if (popup){ delete popup; popup = 0L; } // to add/remove opacity slider
02867 }
02868 
02869 void Workspace::stopKompmgr()
02870 {
02871     if (!kompmgr || !kompmgr->isRunning()) {
02872         return;
02873     }
02874     delete kompmgr_selection;
02875     kompmgr_selection = NULL;
02876     kompmgr->disconnect(this, TQT_SLOT(restartKompmgr(TDEProcess*)));
02877     options->useTranslucency = FALSE;
02878     if (popup){ delete popup; popup = 0L; } // to add/remove opacity slider
02879     kompmgr->kill(SIGKILL);
02880     TQByteArray ba;
02881     TQDataStream arg(ba, IO_WriteOnly);
02882     arg << "";
02883     kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStopped()", ba);
02884 }
02885 
02886 void Workspace::kompmgrReloadSettings()
02887 {
02888     if (!kompmgr || !kompmgr->isRunning()) {
02889         return;
02890     }
02891     kompmgr->kill(SIGUSR2);
02892 }
02893 
02894 bool Workspace::kompmgrIsRunning()
02895 {
02896    return kompmgr && kompmgr->isRunning();
02897 }
02898 
02899 void Workspace::unblockKompmgrRestart()
02900 {
02901     allowKompmgrRestart = TRUE;
02902 }
02903 
02904 void Workspace::restartKompmgr( TDEProcess *proc )
02905 // this is for inernal purpose (crashhandling) only, usually you want to use workspace->stopKompmgr(); TQTimer::singleShot(200, workspace, TQT_SLOT(startKompmgr()));
02906 {
02907     bool crashed;
02908     if (proc->signalled()) {    // looks like kompmgr may have crashed
02909       int exit_signal_number = proc->exitSignal();
02910       if ( (exit_signal_number == SIGILL) || (exit_signal_number == SIGTRAP) || (exit_signal_number == SIGABRT) || (exit_signal_number == SIGSYS) || (exit_signal_number == SIGFPE) || (exit_signal_number == SIGBUS) || (exit_signal_number == SIGSEGV) ) {
02911         crashed = true;
02912       }
02913       else {
02914         crashed = false;
02915       }
02916       if (!allowKompmgrRestart)   // uh oh, it exited recently already
02917       {
02918           delete kompmgr_selection;
02919           kompmgr_selection = NULL;
02920           options->useTranslucency = FALSE;
02921           if (crashed) {
02922             TDEProcess proc;
02923             proc << "kdialog" << "--error"
02924                 << i18n( "The Composite Manager crashed twice within a minute and is therefore disabled for this session.")
02925                 << "--title" << i18n("Composite Manager Failure");
02926             proc.start(TDEProcess::DontCare);
02927           }
02928           return;
02929       }
02930       if (!kompmgr)
02931             return;
02932 // this should be useless, i keep it for maybe future need
02933 //         if (!kcompmgr)
02934 //             {
02935 //             kompmgr = new TDEProcess;
02936 //             kompmgr->clearArguments();
02937 //             *kompmgr << TDE_COMPOSITOR_BINARY;
02938 //             }
02939 // -------------------
02940         if (!kompmgr->start(TDEProcess::NotifyOnExit, TDEProcess::Stderr))
02941         {
02942             delete kompmgr_selection;
02943             kompmgr_selection = NULL;
02944             options->useTranslucency = FALSE;
02945             TDEProcess proc;
02946             proc << "kdialog" << "--error"
02947                 << i18n("The Composite Manager could not be started.\\nMake sure you have \"" TDE_COMPOSITOR_BINARY "\" in a $PATH directory.")
02948                 << "--title" << i18n("Composite Manager Failure");
02949             proc.start(TDEProcess::DontCare);
02950         }
02951         else
02952         {
02953             allowKompmgrRestart = FALSE;
02954             TQTimer::singleShot( 60000, this, TQT_SLOT(unblockKompmgrRestart()) );
02955         }
02956     }
02957 }
02958 
02959 void Workspace::handleKompmgrOutput( TDEProcess* , char *buffer, int buflen)
02960 {
02961     TQString message;
02962     TQString output = TQString::fromLocal8Bit( buffer, buflen );
02963     if (output.contains("Started",false))
02964         ; // don't do anything, just pass to the connection release
02965     else if (output.contains("Can't open display",false))
02966         message = i18n("<qt><b>The TDE composition manager failed to open the display</b><br>There is probably an invalid display entry in your ~/.compton-tde.conf file.</qt>");
02967     else if (output.contains("No render extension",false))
02968         message = i18n("<qt><b>The TDE composition manager cannot find the Xrender extension</b><br>You are using either an outdated or a crippled version of XOrg.<br>Get XOrg &ge; 6.8 from www.freedesktop.org.<br></qt>");
02969     else if (output.contains("No composite extension",false))
02970         message = i18n("<qt><b>Composite extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.<br>Additionally, you need to add a new section to your X config file:<br>"
02971         "<i>Section \"Extensions\"<br>"
02972         "Option \"Composite\" \"Enable\"<br>"
02973         "EndSection</i></qt>");
02974     else if (output.contains("No damage extension",false))
02975         message = i18n("<qt><b>Damage extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.</qt>");
02976     else if (output.contains("No XFixes extension",false))
02977         message = i18n("<qt><b>XFixes extension not found</b><br>You <i>must</i> use XOrg &ge; 6.8 for translucency and shadows to work.</qt>");
02978     else return; //skip others
02979     // kompmgr startup failed or succeeded, release connection
02980     kompmgr->closeStderr();
02981     disconnect(kompmgr, TQT_SIGNAL(receivedStderr(TDEProcess*, char*, int)), this, TQT_SLOT(handleKompmgrOutput(TDEProcess*, char*, int)));
02982     if( !message.isEmpty())
02983         {
02984         TDEProcess proc;
02985         proc << "kdialog" << "--error"
02986             << message
02987             << "--title" << i18n("Composite Manager Failure");
02988         proc.start(TDEProcess::DontCare);
02989         }
02990 }
02991     
02992         
02993 void Workspace::setOpacity(unsigned long winId, unsigned int opacityPercent)
02994 {
02995     if (opacityPercent > 100) opacityPercent = 100;
02996     for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02997         if (winId == (*it)->window())
02998             {
02999             (*it)->setOpacity(opacityPercent < 100, (unsigned int)((opacityPercent/100.0)*0xFFFFFFFF));
03000             return;
03001             }
03002 }
03003 
03004 void Workspace::setShadowSize(unsigned long winId, unsigned int shadowSizePercent)
03005 {
03006     //this is open to the user by dcop - to avoid stupid trials, we limit the max shadow size to 400%
03007     if (shadowSizePercent > 400) shadowSizePercent = 400;
03008     for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
03009         if (winId == (*it)->window())
03010             {
03011             (*it)->setShadowSize(shadowSizePercent);
03012             return;
03013             }
03014 }
03015 
03016 void Workspace::setUnshadowed(unsigned long winId)
03017 {
03018     for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
03019         if (winId == (*it)->window())
03020             {
03021             (*it)->setShadowSize(0);
03022             return;
03023             }
03024 }
03025 
03026 void Workspace::setShowingDesktop( bool showing )
03027     {
03028     rootInfo->setShowingDesktop( showing );
03029     showing_desktop = showing;
03030     ++block_showing_desktop;
03031     if( showing_desktop )
03032         {
03033         showing_desktop_clients.clear();
03034         ++block_focus;
03035         ClientList cls = stackingOrder();
03036         // find them first, then minimize, otherwise transients may get minimized with the window
03037         // they're transient for
03038         for( ClientList::ConstIterator it = cls.begin();
03039              it != cls.end();
03040              ++it )
03041             {
03042             if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
03043                 showing_desktop_clients.prepend( *it ); // topmost first to reduce flicker
03044             }
03045         for( ClientList::ConstIterator it = showing_desktop_clients.begin();
03046              it != showing_desktop_clients.end();
03047              ++it )
03048             (*it)->minimize(true);
03049         --block_focus;
03050         if( Client* desk = findDesktop( true, currentDesktop()))
03051             requestFocus( desk );
03052         }
03053     else
03054         {
03055         for( ClientList::ConstIterator it = showing_desktop_clients.begin();
03056              it != showing_desktop_clients.end();
03057              ++it )
03058             (*it)->unminimize(true);
03059         if( showing_desktop_clients.count() > 0 )
03060             requestFocus( showing_desktop_clients.first());
03061         showing_desktop_clients.clear();
03062         }
03063     --block_showing_desktop;
03064     }
03065 
03066 // Following Kicker's behavior:
03067 // Changing a virtual desktop resets the state and shows the windows again.
03068 // Unminimizing a window resets the state but keeps the windows hidden (except
03069 // the one that was unminimized).
03070 // A new window resets the state and shows the windows again, with the new window
03071 // being active. Due to popular demand (#67406) by people who apparently
03072 // don't see a difference between "show desktop" and "minimize all", this is not
03073 // true if "showDesktopIsMinimizeAll" is set in twinrc. In such case showing
03074 // a new window resets the state but doesn't show windows.
03075 void Workspace::resetShowingDesktop( bool keep_hidden )
03076     {
03077     if( block_showing_desktop > 0 )
03078         return;
03079     rootInfo->setShowingDesktop( false );
03080     showing_desktop = false;
03081     ++block_showing_desktop;
03082     if( !keep_hidden )
03083         {
03084         for( ClientList::ConstIterator it = showing_desktop_clients.begin();
03085              it != showing_desktop_clients.end();
03086              ++it )
03087             (*it)->unminimize(true);
03088         }
03089     showing_desktop_clients.clear();
03090     --block_showing_desktop;
03091     }
03092 
03093 // Activating/deactivating this feature works like this:
03094 // When nothing is active, and the shortcut is pressed, global shortcuts are disabled
03095 //   (using global_shortcuts_disabled)
03096 // When a window that has disabling forced is activated, global shortcuts are disabled.
03097 //   (using global_shortcuts_disabled_for_client)
03098 // When a shortcut is pressed and global shortcuts are disabled (either by a shortcut
03099 // or for a client), they are enabled again.
03100 void Workspace::slotDisableGlobalShortcuts()
03101     {
03102     if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
03103         disableGlobalShortcuts( false );
03104     else
03105         disableGlobalShortcuts( true );
03106     }
03107 
03108 static bool pending_dfc = false;
03109 
03110 void Workspace::disableGlobalShortcutsForClient( bool disable )
03111     {
03112     if( global_shortcuts_disabled_for_client == disable )
03113         return;
03114     if( !global_shortcuts_disabled )
03115         {
03116         if( disable )
03117             pending_dfc = true;
03118         KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
03119         // twin will get the kipc message too
03120         }
03121     }
03122 
03123 void Workspace::disableGlobalShortcuts( bool disable )
03124     {
03125     KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
03126     // twin will get the kipc message too
03127     }
03128 
03129 void Workspace::kipcMessage( int id, int data )
03130     {
03131     if( id != KIPC::BlockShortcuts )
03132         return;
03133     if( pending_dfc && data )
03134         {
03135         global_shortcuts_disabled_for_client = true;
03136         pending_dfc = false;
03137         }
03138     else
03139         {
03140         global_shortcuts_disabled = data;
03141         global_shortcuts_disabled_for_client = false;
03142         }
03143     // update also Alt+LMB actions etc.
03144     for( ClientList::ConstIterator it = clients.begin();
03145          it != clients.end();
03146          ++it )
03147         (*it)->updateMouseGrab();
03148     }
03149 
03150 } // namespace
03151 
03152 #include "workspace.moc"

twin

Skip menu "twin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.6.3
This website is maintained by Timothy Pearson.