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

kwin

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

kwin

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

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.5.6
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |