00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "workspace.h"
00025
00026 #include <kapplication.h>
00027 #include <kstartupinfo.h>
00028 #include <fixx11h.h>
00029 #include <kconfig.h>
00030 #include <kglobal.h>
00031 #include <klocale.h>
00032 #include <QRegExp>
00033 #include <QPainter>
00034 #include <QBitmap>
00035 #include <QClipboard>
00036 #include <kmenubar.h>
00037 #include <kprocess.h>
00038 #include <kglobalaccel.h>
00039 #include <QDesktopWidget>
00040 #include <QToolButton>
00041 #include <kactioncollection.h>
00042 #include <kaction.h>
00043 #include <kconfiggroup.h>
00044 #include <QtDBus/QtDBus>
00045
00046 #include "plugins.h"
00047 #include "client.h"
00048 #include "popupinfo.h"
00049 #include "tabbox.h"
00050 #include "atoms.h"
00051 #include "placement.h"
00052 #include "notifications.h"
00053 #include "group.h"
00054 #include "rules.h"
00055 #include "kwinadaptor.h"
00056 #include "unmanaged.h"
00057 #include "scene.h"
00058 #include "deleted.h"
00059 #include "effects.h"
00060 #include "kdecorationfactory.h"
00061
00062 #include <X11/extensions/shape.h>
00063 #include <X11/keysym.h>
00064 #include <X11/keysymdef.h>
00065 #include <X11/cursorfont.h>
00066 #include <QX11Info>
00067 #include <stdio.h>
00068 #include <kauthorized.h>
00069 #include <ktoolinvocation.h>
00070 #include <kglobalsettings.h>
00071
00072 namespace KWin
00073 {
00074
00075 extern int screen_number;
00076
00077 Workspace *Workspace::_self = 0;
00078
00079
00080
00081
00082
00083
00084
00085
00086 Workspace::Workspace( bool restore )
00087 : QObject (0),
00088 current_desktop (0),
00089 number_of_desktops(0),
00090 active_popup( NULL ),
00091 active_popup_client( NULL ),
00092 temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ),
00093 rules_updates_disabled( false ),
00094 active_client (0),
00095 last_active_client (0),
00096 most_recently_raised (0),
00097 movingClient(0),
00098 pending_take_activity ( NULL ),
00099 active_screen (0),
00100 delayfocus_client (0),
00101 force_restacking( false ),
00102 showing_desktop( false ),
00103 block_showing_desktop( 0 ),
00104 was_user_interaction (false),
00105 session_saving (false),
00106 control_grab (false),
00107 tab_grab (false),
00108 mouse_emulation (false),
00109 block_focus (0),
00110 tab_box (0),
00111 popupinfo (0),
00112 popup (0),
00113 advanced_popup (0),
00114 trans_popup (0),
00115 desk_popup (0),
00116 keys (0),
00117 client_keys ( NULL ),
00118 client_keys_dialog ( NULL ),
00119 client_keys_client ( NULL ),
00120 disable_shortcuts_keys ( NULL ),
00121 global_shortcuts_disabled( false ),
00122 global_shortcuts_disabled_for_client( false ),
00123 workspaceInit (true),
00124 startup(0),
00125 layoutOrientation(Qt::Vertical),
00126 layoutX(-1),
00127 layoutY(2),
00128 managing_topmenus( false ),
00129 topmenu_selection( NULL ),
00130 topmenu_watcher( NULL ),
00131 topmenu_height( 0 ),
00132 topmenu_space( NULL ),
00133 set_active_client_recursion( 0 ),
00134 block_stacking_updates( 0 ),
00135 forced_global_mouse_grab( false ),
00136 cm_selection( NULL ),
00137 compositingSuspended( false ),
00138 compositeRate( 0 ),
00139 overlay( None ),
00140 overlay_visible( true ),
00141 overlay_shown( false ),
00142 transSlider( NULL ),
00143 transButton( NULL )
00144 {
00145 (void) new KWinAdaptor( this );
00146 QDBusConnection dbus = QDBusConnection::sessionBus();
00147 dbus.registerObject("/KWin", this);
00148 dbus.connect(QString(), "/KWin", "org.kde.KWin", "reloadConfig", this, SLOT(slotReloadConfig()));
00149 dbus.connect(QString(), "/KWin", "org.kde.KWin", "reinitCompositing", this, SLOT(slotReinitCompositing()));
00150 _self = this;
00151 mgr = new PluginMgr;
00152 QX11Info info;
00153 default_colormap = DefaultColormap(display(), info.screen() );
00154 installed_colormap = default_colormap;
00155
00156 for( int i = 0;
00157 i < ELECTRIC_COUNT;
00158 ++i )
00159 {
00160 electric_reserved[ i ] = 0;
00161 electric_windows[ i ] = None;
00162 }
00163
00164 connect( &temporaryRulesMessages, SIGNAL( gotMessage( const QString& )),
00165 this, SLOT( gotTemporaryRulesMessage( const QString& )));
00166 connect( &rulesUpdatedTimer, SIGNAL( timeout()), this, SLOT( writeWindowRules()));
00167
00168 updateXTime();
00169
00170 delayFocusTimer = 0;
00171
00172 if ( restore )
00173 loadSessionInfo();
00174
00175 loadWindowRules();
00176
00177 (void) QApplication::desktop();
00178
00179
00180 startup = new KStartupInfo(
00181 KStartupInfo::DisableKWinModule | KStartupInfo::AnnounceSilenceChanges, this );
00182
00183
00184 XSelectInput(display(), rootWindow(),
00185 KeyPressMask |
00186 PropertyChangeMask |
00187 ColormapChangeMask |
00188 SubstructureRedirectMask |
00189 SubstructureNotifyMask |
00190 FocusChangeMask |
00191 ExposureMask
00192 );
00193
00194 Extensions::init();
00195 setupCompositing();
00196
00197
00198 long data = 1;
00199
00200 XChangeProperty(
00201 display(),
00202 rootWindow(),
00203 atoms->kwin_running,
00204 atoms->kwin_running,
00205 32,
00206 PropModeAppend,
00207 (unsigned char*) &data,
00208 1
00209 );
00210
00211 client_keys = new KActionCollection( this );
00212 initShortcuts();
00213 tab_box = new TabBox( this );
00214 popupinfo = new PopupInfo( this );
00215
00216 init();
00217
00218 connect( kapp->desktop(), SIGNAL( resized( int )), SLOT( desktopResized()));
00219 }
00220
00221 void Workspace::init()
00222 {
00223 if( options->electricBorders() == Options::ElectricAlways )
00224 reserveElectricBorderSwitching( true );
00225 updateElectricBorders();
00226
00227
00228
00229
00230
00231 supportWindow = new QWidget;
00232 XLowerWindow( display(), supportWindow->winId());
00233
00234 XSetWindowAttributes attr;
00235 attr.override_redirect = 1;
00236 null_focus_window = XCreateWindow( display(), rootWindow(), -1,-1, 1, 1, 0, CopyFromParent,
00237 InputOnly, CopyFromParent, CWOverrideRedirect, &attr );
00238 XMapWindow(display(), null_focus_window);
00239
00240 unsigned long protocols[ 5 ] =
00241 {
00242 NET::Supported |
00243 NET::SupportingWMCheck |
00244 NET::ClientList |
00245 NET::ClientListStacking |
00246 NET::DesktopGeometry |
00247 NET::NumberOfDesktops |
00248 NET::CurrentDesktop |
00249 NET::ActiveWindow |
00250 NET::WorkArea |
00251 NET::CloseWindow |
00252 NET::DesktopNames |
00253 NET::WMName |
00254 NET::WMVisibleName |
00255 NET::WMDesktop |
00256 NET::WMWindowType |
00257 NET::WMState |
00258 NET::WMStrut |
00259 NET::WMIconGeometry |
00260 NET::WMIcon |
00261 NET::WMPid |
00262 NET::WMMoveResize |
00263 NET::WMFrameExtents |
00264 NET::WMPing
00265 ,
00266 NET::NormalMask |
00267 NET::DesktopMask |
00268 NET::DockMask |
00269 NET::ToolbarMask |
00270 NET::MenuMask |
00271 NET::DialogMask |
00272 NET::OverrideMask |
00273 NET::TopMenuMask |
00274 NET::UtilityMask |
00275 NET::SplashMask |
00276
00277 0
00278 ,
00279 NET::Modal |
00280
00281 NET::MaxVert |
00282 NET::MaxHoriz |
00283 NET::Shaded |
00284 NET::SkipTaskbar |
00285 NET::KeepAbove |
00286
00287 NET::SkipPager |
00288 NET::Hidden |
00289 NET::FullScreen |
00290 NET::KeepBelow |
00291 NET::DemandsAttention |
00292 0
00293 ,
00294 NET::WM2UserTime |
00295 NET::WM2StartupId |
00296 NET::WM2AllowedActions |
00297 NET::WM2RestackWindow |
00298 NET::WM2MoveResizeWindow |
00299 NET::WM2ExtendedStrut |
00300 NET::WM2KDETemporaryRules |
00301 NET::WM2ShowingDesktop |
00302 NET::WM2DesktopLayout |
00303 NET::WM2FullPlacement |
00304 0
00305 ,
00306 NET::ActionMove |
00307 NET::ActionResize |
00308 NET::ActionMinimize |
00309 NET::ActionShade |
00310
00311 NET::ActionMaxVert |
00312 NET::ActionMaxHoriz |
00313 NET::ActionFullScreen |
00314 NET::ActionChangeDesktop |
00315 NET::ActionClose |
00316 0
00317 ,
00318 };
00319
00320 QX11Info info;
00321 rootInfo = new RootInfo( this, display(), supportWindow->winId(), "KWin",
00322 protocols, 5, info.screen() );
00323
00324 loadDesktopSettings();
00325 updateDesktopLayout();
00326
00327 NETRootInfo client_info( display(), NET::ActiveWindow | NET::CurrentDesktop );
00328 int initial_desktop;
00329 if( !kapp->isSessionRestored())
00330 initial_desktop = client_info.currentDesktop();
00331 else
00332 {
00333 KConfigGroup group( kapp->sessionConfig(), "Session" );
00334 initial_desktop = group.readEntry( "desktop", 1 );
00335 }
00336 if( !setCurrentDesktop( initial_desktop ))
00337 setCurrentDesktop( 1 );
00338
00339
00340 initPositioning = new Placement(this);
00341
00342 reconfigureTimer.setSingleShot( true );
00343 updateToolWindowsTimer.setSingleShot( true );
00344
00345 connect(&reconfigureTimer, SIGNAL(timeout()), this,
00346 SLOT(slotReconfigure()));
00347 connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows()));
00348 connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing()));
00349
00350 connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this,
00351 SLOT(slotReconfigure()));
00352 connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this,
00353 SLOT(slotSettingsChanged(int)));
00354 connect(KGlobalSettings::self(), SIGNAL(blockShortcuts(int)), this,
00355 SLOT(slotBlockShortcuts(int)));
00356
00357 active_client = NULL;
00358 rootInfo->setActiveWindow( None );
00359 focusToNull();
00360 if( !kapp->isSessionRestored())
00361 ++block_focus;
00362
00363 char nm[ 100 ];
00364 sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( display()));
00365 Atom topmenu_atom = XInternAtom( display(), nm, False );
00366 topmenu_selection = new KSelectionOwner( topmenu_atom );
00367 topmenu_watcher = new KSelectionWatcher( topmenu_atom );
00368
00369
00370 {
00371 StackingUpdatesBlocker blocker( this );
00372
00373 if( options->topMenuEnabled() && topmenu_selection->claim( false ))
00374 setupTopMenuHandling();
00375 else
00376 lostTopMenuSelection();
00377
00378 unsigned int i, nwins;
00379 Window root_return, parent_return, *wins;
00380 XQueryTree(display(), rootWindow(), &root_return, &parent_return, &wins, &nwins);
00381 for (i = 0; i < nwins; i++)
00382 {
00383 XWindowAttributes attr;
00384 XGetWindowAttributes(display(), wins[i], &attr);
00385 if (attr.override_redirect )
00386 {
00387 createUnmanaged( wins[ i ] );
00388 continue;
00389 }
00390 if( topmenu_space && topmenu_space->winId() == wins[ i ] )
00391 continue;
00392 if (attr.map_state != IsUnmapped)
00393 createClient( wins[i], true );
00394 }
00395 if ( wins )
00396 XFree((void *) wins);
00397
00398 updateStackingOrder( true );
00399
00400 updateClientArea();
00401
00402
00403 NETPoint* viewports = new NETPoint[ number_of_desktops ];
00404 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
00405 delete[] viewports;
00406 QRect geom = QApplication::desktop()->geometry();
00407 NETSize desktop_geometry;
00408 desktop_geometry.width = geom.width();
00409 desktop_geometry.height = geom.height();
00410 rootInfo->setDesktopGeometry( -1, desktop_geometry );
00411 setShowingDesktop( false );
00412
00413 }
00414
00415 Client* new_active_client = NULL;
00416 if( !kapp->isSessionRestored())
00417 {
00418 --block_focus;
00419 new_active_client = findClient( WindowMatchPredicate( client_info.activeWindow()));
00420 }
00421 if( new_active_client == NULL
00422 && activeClient() == NULL && should_get_focus.count() == 0 )
00423 {
00424 if( new_active_client == NULL )
00425 new_active_client = topClientOnDesktop( currentDesktop());
00426 if( new_active_client == NULL && !desktops.isEmpty() )
00427 new_active_client = findDesktop( true, currentDesktop());
00428 }
00429 if( new_active_client != NULL )
00430 activateClient( new_active_client );
00431
00432
00433
00434 workspaceInit = false;
00435
00436 }
00437
00438 Workspace::~Workspace()
00439 {
00440 finishCompositing();
00441 blockStackingUpdates( true );
00442
00443
00444 for( ClientList::ConstIterator it = stacking_order.begin();
00445 it != stacking_order.end();
00446 ++it )
00447 {
00448
00449 (*it)->releaseWindow( true );
00450
00451
00452
00453 clients.removeAll( *it );
00454 desktops.removeAll( *it );
00455 }
00456 for( UnmanagedList::ConstIterator it = unmanaged.begin();
00457 it != unmanaged.end();
00458 ++it )
00459 (*it)->release();
00460 delete tab_box;
00461 delete popupinfo;
00462 delete popup;
00463 XDeleteProperty(display(), rootWindow(), atoms->kwin_running);
00464
00465 writeWindowRules();
00466 KGlobal::config()->sync();
00467
00468 delete rootInfo;
00469 delete supportWindow;
00470 delete mgr;
00471 delete startup;
00472 delete initPositioning;
00473 delete topmenu_watcher;
00474 delete topmenu_selection;
00475 delete topmenu_space;
00476 delete client_keys_dialog;
00477 while( !rules.isEmpty())
00478 {
00479 delete rules.front();
00480 rules.pop_front();
00481 }
00482 foreach ( SessionInfo* s, session )
00483 delete s;
00484 XDestroyWindow( display(), null_focus_window );
00485
00486 _self = 0;
00487 }
00488
00489 Client* Workspace::createClient( Window w, bool is_mapped )
00490 {
00491 StackingUpdatesBlocker blocker( this );
00492 Client* c = new Client( this );
00493 if( !c->manage( w, is_mapped ))
00494 {
00495 Client::deleteClient( c, Allowed );
00496 return NULL;
00497 }
00498 addClient( c, Allowed );
00499 if( scene )
00500 scene->windowAdded( c );
00501 if( effects )
00502 static_cast<EffectsHandlerImpl*>(effects)->windowAdded( c->effectWindow());
00503 return c;
00504 }
00505
00506 Unmanaged* Workspace::createUnmanaged( Window w )
00507 {
00508 if( w == overlay )
00509 return NULL;
00510 Unmanaged* c = new Unmanaged( this );
00511 if( !c->track( w ))
00512 {
00513 Unmanaged::deleteUnmanaged( c, Allowed );
00514 return NULL;
00515 }
00516 addUnmanaged( c, Allowed );
00517 if( scene )
00518 scene->windowAdded( c );
00519 if( effects )
00520 static_cast<EffectsHandlerImpl*>(effects)->windowAdded( c->effectWindow());
00521 return c;
00522 }
00523
00524 void Workspace::addClient( Client* c, allowed_t )
00525 {
00526 Group* grp = findGroup( c->window());
00527 if( grp != NULL )
00528 grp->gotLeader( c );
00529
00530 if ( c->isDesktop() )
00531 {
00532 desktops.append( c );
00533 if( active_client == NULL && should_get_focus.isEmpty() && c->isOnCurrentDesktop())
00534 requestFocus( c );
00535 }
00536 else
00537 {
00538 updateFocusChains( c, FocusChainUpdate );
00539 clients.append( c );
00540 }
00541 if( !unconstrained_stacking_order.contains( c ))
00542 unconstrained_stacking_order.append( c );
00543 if( !stacking_order.contains( c ))
00544 stacking_order.append( c );
00545 if( c->isTopMenu())
00546 addTopMenu( c );
00547 updateClientArea();
00548 updateClientLayer( c );
00549 if( c->isDesktop())
00550 {
00551 raiseClient( c );
00552
00553 if( activeClient() == NULL && should_get_focus.count() == 0 )
00554 activateClient( findDesktop( true, currentDesktop()));
00555 }
00556 c->checkActiveModal();
00557 checkTransients( c->window());
00558 updateStackingOrder( true );
00559 if( c->isUtility() || c->isMenu() || c->isToolbar())
00560 updateToolWindows( true );
00561 checkNonExistentClients();
00562 if( tab_grab )
00563 tab_box->reset( true );
00564 }
00565
00566 void Workspace::addUnmanaged( Unmanaged* c, allowed_t )
00567 {
00568 unmanaged.append( c );
00569 }
00570
00571
00572
00573
00574 void Workspace::removeClient( Client* c, allowed_t )
00575 {
00576 if (c == active_popup_client)
00577 closeActivePopup();
00578
00579 if( client_keys_client == c )
00580 setupWindowShortcutDone( false );
00581 if( !c->shortcut().isEmpty())
00582 c->setShortcut( QString() );
00583
00584 if( c->isDialog())
00585 Notify::raise( Notify::TransDelete );
00586 if( c->isNormalWindow())
00587 Notify::raise( Notify::Delete );
00588
00589 if( tab_grab )
00590 {
00591 if( tab_box->currentClient() == c )
00592 tab_box->nextPrev( true );
00593 }
00594
00595 Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
00596 clients.removeAll( c );
00597 desktops.removeAll( c );
00598 unconstrained_stacking_order.removeAll( c );
00599 stacking_order.removeAll( c );
00600 for( int i = 1;
00601 i <= numberOfDesktops();
00602 ++i )
00603 focus_chain[ i ].removeAll( c );
00604 global_focus_chain.removeAll( c );
00605 attention_chain.removeAll( c );
00606 showing_desktop_clients.removeAll( c );
00607 if( c->isTopMenu())
00608 removeTopMenu( c );
00609 Group* group = findGroup( c->window());
00610 if( group != NULL )
00611 group->lostLeader();
00612
00613 if ( c == most_recently_raised )
00614 most_recently_raised = 0;
00615 should_get_focus.removeAll( c );
00616 Q_ASSERT( c != active_client );
00617 if ( c == last_active_client )
00618 last_active_client = 0;
00619 if( c == pending_take_activity )
00620 pending_take_activity = NULL;
00621 if( c == delayfocus_client )
00622 cancelDelayFocus();
00623
00624 updateStackingOrder( true );
00625
00626 if( tab_grab )
00627 tab_box->reset( true );
00628
00629 updateClientArea();
00630 }
00631
00632 void Workspace::removeUnmanaged( Unmanaged* c, allowed_t )
00633 {
00634 assert( unmanaged.contains( c ));
00635 unmanaged.removeAll( c );
00636 }
00637
00638 void Workspace::addDeleted( Deleted* c, allowed_t )
00639 {
00640 assert( !deleted.contains( c ));
00641 deleted.append( c );
00642 }
00643
00644 void Workspace::removeDeleted( Deleted* c, allowed_t )
00645 {
00646 assert( deleted.contains( c ));
00647 if( scene )
00648 scene->windowDeleted( c );
00649 if( effects )
00650 static_cast<EffectsHandlerImpl*>(effects)->windowDeleted( c->effectWindow());
00651 deleted.removeAll( c );
00652 }
00653
00654 void Workspace::updateFocusChains( Client* c, FocusChainChange change )
00655 {
00656 if( !c->wantsTabFocus())
00657 {
00658 for( int i=1;
00659 i<= numberOfDesktops();
00660 ++i )
00661 focus_chain[i].removeAll(c);
00662 global_focus_chain.removeAll( c );
00663 return;
00664 }
00665 if(c->desktop() == NET::OnAllDesktops)
00666 {
00667 for( int i=1; i<= numberOfDesktops(); i++)
00668 {
00669 if( i == currentDesktop()
00670 && ( change == FocusChainMakeFirst || change == FocusChainMakeLast ))
00671 {
00672 focus_chain[ i ].removeAll( c );
00673 if( change == FocusChainMakeFirst )
00674 focus_chain[ i ].append( c );
00675 else
00676 focus_chain[ i ].prepend( c );
00677 }
00678 else if( !focus_chain[ i ].contains( c ))
00679 {
00680 if( active_client != NULL && active_client != c
00681 && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
00682 focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
00683 else
00684 focus_chain[ i ].append( c );
00685 }
00686 }
00687 }
00688 else
00689 {
00690 for( int i=1; i<= numberOfDesktops(); i++)
00691 {
00692 if( i == c->desktop())
00693 {
00694 if( change == FocusChainMakeFirst )
00695 {
00696 focus_chain[ i ].removeAll( c );
00697 focus_chain[ i ].append( c );
00698 }
00699 else if( change == FocusChainMakeLast )
00700 {
00701 focus_chain[ i ].removeAll( c );
00702 focus_chain[ i ].prepend( c );
00703 }
00704 else if( !focus_chain[ i ].contains( c ))
00705 {
00706 if( active_client != NULL && active_client != c
00707 && !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
00708 focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
00709 else
00710 focus_chain[ i ].append( c );
00711 }
00712 }
00713 else
00714 focus_chain[ i ].removeAll( c );
00715 }
00716 }
00717 if( change == FocusChainMakeFirst )
00718 {
00719 global_focus_chain.removeAll( c );
00720 global_focus_chain.append( c );
00721 }
00722 else if( change == FocusChainMakeLast )
00723 {
00724 global_focus_chain.removeAll( c );
00725 global_focus_chain.prepend( c );
00726 }
00727 else if( !global_focus_chain.contains( c ))
00728 {
00729 if( active_client != NULL && active_client != c
00730 && !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client )
00731 global_focus_chain.insert( global_focus_chain.size() - 1, c );
00732 else
00733 global_focus_chain.append( c );
00734 }
00735 }
00736
00737 void Workspace::updateCurrentTopMenu()
00738 {
00739 if( !managingTopMenus())
00740 return;
00741
00742 Client* menubar = 0;
00743 bool block_desktop_menubar = false;
00744 if( active_client )
00745 {
00746
00747 Client* menu_client = active_client;
00748 for(;;)
00749 {
00750 if( menu_client->isFullScreen())
00751 block_desktop_menubar = true;
00752 for( ClientList::ConstIterator it = menu_client->transients().begin();
00753 it != menu_client->transients().end();
00754 ++it )
00755 if( (*it)->isTopMenu())
00756 {
00757 menubar = *it;
00758 break;
00759 }
00760 if( menubar != NULL || !menu_client->isTransient())
00761 break;
00762 if( menu_client->isModal() || menu_client->transientFor() == NULL )
00763 break;
00764 menu_client = menu_client->transientFor();
00765 }
00766 if( !menubar )
00767 {
00768 for( ClientList::ConstIterator it = active_client->group()->members().begin();
00769 it != active_client->group()->members().end();
00770 ++it )
00771 if( (*it)->isTopMenu())
00772 {
00773 menubar = *it;
00774 break;
00775 }
00776 }
00777 }
00778 if( !menubar && !block_desktop_menubar && options->desktopTopMenu())
00779 {
00780
00781 Client* desktop = findDesktop( true, currentDesktop());
00782 if( desktop != NULL )
00783 {
00784 for( ClientList::ConstIterator it = desktop->transients().begin();
00785 it != desktop->transients().end();
00786 ++it )
00787 if( (*it)->isTopMenu())
00788 {
00789 menubar = *it;
00790 break;
00791 }
00792 }
00793
00794
00795
00796 if( menubar == NULL )
00797 {
00798 for( ClientList::ConstIterator it = topmenus.begin();
00799 it != topmenus.end();
00800 ++it )
00801 if( (*it)->wasOriginallyGroupTransient())
00802 {
00803 menubar = *it;
00804 break;
00805 }
00806 }
00807 }
00808
00809
00810 if ( menubar )
00811 {
00812 if( active_client && !menubar->isOnDesktop( active_client->desktop()))
00813 menubar->setDesktop( active_client->desktop());
00814 menubar->hideClient( false );
00815 topmenu_space->hide();
00816
00817
00818
00819 unconstrained_stacking_order.removeAll( menubar );
00820 unconstrained_stacking_order.append( menubar );
00821 }
00822 else if( !block_desktop_menubar )
00823 {
00824 topmenu_space->show();
00825 }
00826
00827
00828 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00829 {
00830 if( (*it)->isTopMenu() && (*it) != menubar )
00831 (*it)->hideClient( true );
00832 }
00833 }
00834
00835
00836 void Workspace::updateToolWindows( bool also_hide )
00837 {
00838
00839 if( !options->hideUtilityWindowsForInactive )
00840 {
00841 for( ClientList::ConstIterator it = clients.begin();
00842 it != clients.end();
00843 ++it )
00844 (*it)->hideClient( false );
00845 return;
00846 }
00847 const Group* group = NULL;
00848 const Client* client = active_client;
00849
00850
00851 while( client != NULL )
00852 {
00853 if( !client->isTransient())
00854 break;
00855 if( client->groupTransient())
00856 {
00857 group = client->group();
00858 break;
00859 }
00860 client = client->transientFor();
00861 }
00862
00863
00864
00865
00866 ClientList to_show, to_hide;
00867 for( ClientList::ConstIterator it = stacking_order.begin();
00868 it != stacking_order.end();
00869 ++it )
00870 {
00871 if( (*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar())
00872 {
00873 bool show = true;
00874 if( !(*it)->isTransient())
00875 {
00876 if( (*it)->group()->members().count() == 1 )
00877 show = true;
00878 else if( client != NULL && (*it)->group() == client->group())
00879 show = true;
00880 else
00881 show = false;
00882 }
00883 else
00884 {
00885 if( group != NULL && (*it)->group() == group )
00886 show = true;
00887 else if( client != NULL && client->hasTransient( (*it), true ))
00888 show = true;
00889 else
00890 show = false;
00891 }
00892 if( !show && also_hide )
00893 {
00894 const ClientList mainclients = (*it)->mainClients();
00895
00896
00897 if( mainclients.isEmpty())
00898 show = true;
00899 for( ClientList::ConstIterator it2 = mainclients.begin();
00900 it2 != mainclients.end();
00901 ++it2 )
00902 {
00903 if( (*it2)->isSpecialWindow())
00904 show = true;
00905 }
00906 if( !show )
00907 to_hide.append( *it );
00908 }
00909 if( show )
00910 to_show.append( *it );
00911 }
00912 }
00913 for( int i = to_show.size() - 1;
00914 i >= 0;
00915 --i )
00916
00917 to_show.at( i )->hideClient( false );
00918 if( also_hide )
00919 {
00920 for( ClientList::ConstIterator it = to_hide.begin();
00921 it != to_hide.end();
00922 ++it )
00923 (*it)->hideClient( true );
00924 updateToolWindowsTimer.stop();
00925 }
00926 else
00927 {
00928 updateToolWindowsTimer.start( 50 );
00929 }
00930 }
00931
00932 void Workspace::slotUpdateToolWindows()
00933 {
00934 updateToolWindows( true );
00935 }
00936
00940 void Workspace::updateColormap()
00941 {
00942 Colormap cmap = default_colormap;
00943 if ( activeClient() && activeClient()->colormap() != None )
00944 cmap = activeClient()->colormap();
00945 if ( cmap != installed_colormap )
00946 {
00947 XInstallColormap(display(), cmap );
00948 installed_colormap = cmap;
00949 }
00950 }
00951
00952 void Workspace::slotReloadConfig()
00953 {
00954 reconfigure();
00955 }
00956
00957 void Workspace::reconfigure()
00958 {
00959 reconfigureTimer.start( 200 );
00960 }
00961
00962
00963 void Workspace::slotSettingsChanged(int category)
00964 {
00965 kDebug(1212) << "Workspace::slotSettingsChanged()";
00966 if( category == KGlobalSettings::SETTINGS_SHORTCUTS )
00967 readShortcuts();
00968 }
00969
00973 KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes( true ) );
00974
00975 void Workspace::slotReconfigure()
00976 {
00977 kDebug(1212) << "Workspace::slotReconfigure()";
00978 reconfigureTimer.stop();
00979
00980 if( options->electricBorders() == Options::ElectricAlways )
00981 reserveElectricBorderSwitching( false );
00982
00983 KGlobal::config()->reparseConfiguration();
00984 unsigned long changed = options->updateSettings();
00985 tab_box->reconfigure();
00986 popupinfo->reconfigure();
00987 initPositioning->reinitCascading( 0 );
00988 readShortcuts();
00989 forEachClient( CheckIgnoreFocusStealingProcedure());
00990 updateToolWindows( true );
00991
00992 if( mgr->reset( changed ))
00993 {
00994 #if 0 // This actually seems to make things worse now
00995 QWidget curtain;
00996 curtain.setBackgroundMode( NoBackground );
00997 curtain.setGeometry( QApplication::desktop()->geometry() );
00998 curtain.show();
00999 #endif
01000 for( ClientList::ConstIterator it = clients.begin();
01001 it != clients.end();
01002 ++it )
01003 {
01004 (*it)->updateDecoration( true, true );
01005 }
01006 mgr->destroyPreviousPlugin();
01007 }
01008 else
01009 {
01010 forEachClient( CheckBorderSizesProcedure());
01011 foreach( Client* c, clients )
01012 c->repaintDecoration();
01013 }
01014
01015 if( options->electricBorders() == Options::ElectricAlways )
01016 reserveElectricBorderSwitching( true );
01017 updateElectricBorders();
01018
01019 if( options->topMenuEnabled() && !managingTopMenus())
01020 {
01021 if( topmenu_selection->claim( false ))
01022 setupTopMenuHandling();
01023 else
01024 lostTopMenuSelection();
01025 }
01026 else if( !options->topMenuEnabled() && managingTopMenus())
01027 {
01028 topmenu_selection->release();
01029 lostTopMenuSelection();
01030 }
01031 topmenu_height = 0;
01032 if( managingTopMenus())
01033 {
01034 updateTopMenuGeometry();
01035 updateCurrentTopMenu();
01036 }
01037
01038 if( options->useCompositing && !compositingSuspended )
01039 {
01040 setupCompositing();
01041 if( effects )
01042 effects->reconfigure();
01043 addRepaintFull();
01044 }
01045 else
01046 finishCompositing();
01047
01048 loadWindowRules();
01049 for( ClientList::Iterator it = clients.begin();
01050 it != clients.end();
01051 ++it )
01052 {
01053 (*it)->setupWindowRules( true );
01054 (*it)->applyWindowRules();
01055 discardUsedWindowRules( *it, false );
01056 }
01057 }
01058
01059 void Workspace::slotReinitCompositing()
01060 {
01061
01062 KGlobal::config()->reparseConfiguration();
01063 options->updateSettings();
01064
01065
01066 finishCompositing();
01067
01068 setupCompositing();
01069 if( effects )
01070 effects->reconfigure();
01071 }
01072
01073 void Workspace::loadDesktopSettings()
01074 {
01075 KSharedConfig::Ptr c = KGlobal::config();
01076 QString groupname;
01077 if (screen_number == 0)
01078 groupname = "Desktops";
01079 else
01080 groupname.sprintf("Desktops-screen-%d", screen_number);
01081 KConfigGroup group(c,groupname);
01082
01083 int n = group.readEntry("Number", 4);
01084 number_of_desktops = n;
01085 workarea.clear();
01086 workarea.resize( n + 1 );
01087 screenarea.clear();
01088 rootInfo->setNumberOfDesktops( number_of_desktops );
01089 desktop_focus_chain.resize( n );
01090
01091 focus_chain.resize( n + 1 );
01092 for(int i = 1; i <= n; i++)
01093 {
01094 QString s = group.readEntry(QString("Name_%1").arg(i),
01095 i18n("Desktop %1", i));
01096 rootInfo->setDesktopName( i, s.toUtf8().data() );
01097 desktop_focus_chain[i-1] = i;
01098 }
01099 }
01100
01101 void Workspace::saveDesktopSettings()
01102 {
01103 KSharedConfig::Ptr c = KGlobal::config();
01104 QString groupname;
01105 if (screen_number == 0)
01106 groupname = "Desktops";
01107 else
01108 groupname.sprintf("Desktops-screen-%d", screen_number);
01109 KConfigGroup group(c,groupname);
01110
01111 group.writeEntry("Number", number_of_desktops );
01112 for(int i = 1; i <= number_of_desktops; i++)
01113 {
01114 QString s = desktopName( i );
01115 QString defaultvalue = i18n("Desktop %1", i);
01116 if ( s.isEmpty() )
01117 {
01118 s = defaultvalue;
01119 rootInfo->setDesktopName( i, s.toUtf8().data() );
01120 }
01121
01122 if (s != defaultvalue)
01123 {
01124 group.writeEntry( QString("Name_%1").arg(i), s );
01125 }
01126 else
01127 {
01128 QString currentvalue = group.readEntry(QString("Name_%1").arg(i), QString());
01129 if (currentvalue != defaultvalue)
01130 group.writeEntry( QString("Name_%1").arg(i), "" );
01131 }
01132 }
01133 }
01134
01135 QStringList Workspace::configModules(bool controlCenter)
01136 {
01137 QStringList args;
01138 args << "kwindecoration";
01139 if (controlCenter)
01140 args << "kwinoptions";
01141 else if (KAuthorized::authorizeControlModule("kde-kwinoptions.desktop"))
01142 args << "kwinactions" << "kwinfocus" << "kwinmoving" << "kwinadvanced" << "kwinrules" << "kwincompositing";
01143 return args;
01144 }
01145
01146 void Workspace::configureWM()
01147 {
01148 KToolInvocation::kdeinitExec( "kcmshell4", configModules(false) );
01149 }
01150
01154 void Workspace::doNotManage( const QString &title )
01155 {
01156 doNotManageList.append( title );
01157 }
01158
01162 bool Workspace::isNotManaged( const QString& title )
01163 {
01164 for ( QStringList::Iterator it = doNotManageList.begin(); it != doNotManageList.end(); ++it )
01165 {
01166 QRegExp r( (*it) );
01167 if (r.indexIn(title) != -1)
01168 {
01169 doNotManageList.erase( it );
01170 return true;
01171 }
01172 }
01173 return false;
01174 }
01175
01179 void Workspace::refresh()
01180 {
01181 QWidget w;
01182 w.setGeometry( QApplication::desktop()->geometry() );
01183 w.show();
01184 w.hide();
01185 QApplication::flush();
01186 }
01187
01195 class ObscuringWindows
01196 {
01197 public:
01198 ~ObscuringWindows();
01199 void create( Client* c );
01200 private:
01201 QList<Window> obscuring_windows;
01202 static QList<Window>* cached;
01203 static unsigned int max_cache_size;
01204 };
01205
01206 QList<Window>* ObscuringWindows::cached = 0;
01207 unsigned int ObscuringWindows::max_cache_size = 0;
01208
01209 void ObscuringWindows::create( Client* c )
01210 {
01211 if( compositing())
01212 return;
01213 if( cached == 0 )
01214 cached = new QList<Window>;
01215 Window obs_win;
01216 XWindowChanges chngs;
01217 int mask = CWSibling | CWStackMode;
01218 if( cached->count() > 0 )
01219 {
01220 cached->removeAll( obs_win = cached->first());
01221 chngs.x = c->x();
01222 chngs.y = c->y();
01223 chngs.width = c->width();
01224 chngs.height = c->height();
01225 mask |= CWX | CWY | CWWidth | CWHeight;
01226 }
01227 else
01228 {
01229 XSetWindowAttributes a;
01230 a.background_pixmap = None;
01231 a.override_redirect = True;
01232 obs_win = XCreateWindow( display(), rootWindow(), c->x(), c->y(),
01233 c->width(), c->height(), 0, CopyFromParent, InputOutput,
01234 CopyFromParent, CWBackPixmap | CWOverrideRedirect, &a );
01235 }
01236 chngs.sibling = c->frameId();
01237 chngs.stack_mode = Below;
01238 XConfigureWindow( display(), obs_win, mask, &chngs );
01239 XMapWindow( display(), obs_win );
01240 obscuring_windows.append( obs_win );
01241 }
01242
01243 ObscuringWindows::~ObscuringWindows()
01244 {
01245 max_cache_size = qMax( ( int )max_cache_size, obscuring_windows.count() + 4 ) - 1;
01246 for( QList<Window>::ConstIterator it = obscuring_windows.begin();
01247 it != obscuring_windows.end();
01248 ++it )
01249 {
01250 XUnmapWindow( display(), *it );
01251 if( cached->count() < ( int )max_cache_size )
01252 cached->prepend( *it );
01253 else
01254 XDestroyWindow( display(), *it );
01255 }
01256 }
01257
01258
01265 bool Workspace::setCurrentDesktop( int new_desktop )
01266 {
01267 if (new_desktop < 1 || new_desktop > number_of_desktops )
01268 return false;
01269
01270 closeActivePopup();
01271 ++block_focus;
01272
01273 StackingUpdatesBlocker blocker( this );
01274
01275 int old_desktop = current_desktop;
01276 if (new_desktop != current_desktop)
01277 {
01278 ++block_showing_desktop;
01279
01280
01281
01282
01283 Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop));
01284
01285 ObscuringWindows obs_wins;
01286
01287 current_desktop = new_desktop;
01288
01289 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
01290 if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
01291 {
01292 if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop ))
01293 obs_wins.create( *it );
01294 (*it)->updateVisibility();
01295 }
01296
01297 rootInfo->setCurrentDesktop( current_desktop );
01298
01299 if( movingClient && !movingClient->isOnDesktop( new_desktop ))
01300 movingClient->setDesktop( new_desktop );
01301
01302 for( int i = stacking_order.size() - 1; i >= 0 ; --i )
01303 if ( stacking_order.at( i )->isOnDesktop( new_desktop ) )
01304 stacking_order.at( i )->updateVisibility();
01305
01306 --block_showing_desktop;
01307 if( showingDesktop())
01308 resetShowingDesktop( false );
01309 }
01310
01311
01312 --block_focus;
01313 Client* c = 0;
01314
01315 if ( options->focusPolicyIsReasonable())
01316 {
01317
01318 if ( movingClient != NULL && active_client == movingClient
01319 && focus_chain[currentDesktop()].contains( active_client )
01320 && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
01321 {
01322 c = active_client;
01323 }
01324 if( !c )
01325 {
01326 for( int i = focus_chain[ currentDesktop() ].size() - 1;
01327 i >= 0;
01328 --i )
01329 {
01330 if( focus_chain[ currentDesktop() ].at( i )->isShown( false )
01331 && focus_chain[ currentDesktop() ].at( i )->isOnCurrentDesktop())
01332 {
01333 c = focus_chain[ currentDesktop() ].at( i );
01334 break;
01335 }
01336 }
01337 }
01338 }
01339
01340
01341
01342
01343 else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
01344 c = active_client;
01345
01346 if( c == NULL && !desktops.isEmpty())
01347 c = findDesktop( true, currentDesktop());
01348
01349 if( c != active_client )
01350 setActiveClient( NULL, Allowed );
01351
01352 if ( c )
01353 requestFocus( c );
01354 else if( !desktops.isEmpty() )
01355 requestFocus( findDesktop( true, currentDesktop()));
01356 else
01357 focusToNull();
01358
01359 updateCurrentTopMenu();
01360
01361
01362
01363
01364
01365
01366 for( int i = desktop_focus_chain.indexOf( currentDesktop() ); i > 0; i-- )
01367 desktop_focus_chain[i] = desktop_focus_chain[i-1];
01368 desktop_focus_chain[0] = currentDesktop();
01369
01370
01371
01372
01373
01374
01375 if( old_desktop != 0 )
01376 popupinfo->showInfo( desktopName(currentDesktop()) );
01377
01378 if( effects != NULL && old_desktop != 0 && old_desktop != new_desktop )
01379 static_cast<EffectsHandlerImpl*>(effects)->desktopChanged( old_desktop );
01380 if( compositing())
01381 addRepaintFull();
01382
01383 return true;
01384 }
01385
01386
01387 void Workspace::nextDesktop()
01388 {
01389 int desktop = currentDesktop() + 1;
01390 setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
01391 }
01392
01393
01394 void Workspace::previousDesktop()
01395 {
01396 int desktop = currentDesktop() - 1;
01397 setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
01398 }
01399
01400 int Workspace::desktopToRight( int desktop, bool wrap ) const
01401 {
01402 int x,y;
01403 Qt::Orientation orientation;
01404 calcDesktopLayout( &x, &y, &orientation );
01405 int dt = desktop-1;
01406 if (orientation == Qt::Vertical)
01407 {
01408 dt += y;
01409 if ( dt >= numberOfDesktops() )
01410 {
01411 if ( wrap )
01412 dt -= numberOfDesktops();
01413 else
01414 return desktop;
01415 }
01416 }
01417 else
01418 {
01419 int d = (dt % x) + 1;
01420 if ( d >= x )
01421 {
01422 if ( wrap )
01423 d -= x;
01424 else
01425 return desktop;
01426 }
01427 dt = dt - (dt % x) + d;
01428 }
01429 return dt+1;
01430 }
01431
01432 int Workspace::desktopToLeft( int desktop, bool wrap ) const
01433 {
01434 int x,y;
01435 Qt::Orientation orientation;
01436 calcDesktopLayout( &x, &y, &orientation );
01437 int dt = desktop-1;
01438 if (orientation == Qt::Vertical)
01439 {
01440 dt -= y;
01441 if ( dt < 0 )
01442 {
01443 if ( wrap )
01444 dt += numberOfDesktops();
01445 else
01446 return desktop;
01447 }
01448 }
01449 else
01450 {
01451 int d = (dt % x) - 1;
01452 if ( d < 0 )
01453 {
01454 if ( wrap )
01455 d += x;
01456 else
01457 return desktop;
01458 }
01459 dt = dt - (dt % x) + d;
01460 }
01461 return dt+1;
01462 }
01463
01464 int Workspace::desktopUp( int desktop, bool wrap ) const
01465 {
01466 int x,y;
01467 Qt::Orientation orientation;
01468 calcDesktopLayout( &x, &y, &orientation);
01469 int dt = desktop-1;
01470 if (orientation == Qt::Horizontal)
01471 {
01472 dt -= x;
01473 if ( dt < 0 )
01474 {
01475 if ( wrap )
01476 dt += numberOfDesktops();
01477 else
01478 return desktop;
01479 }
01480 }
01481 else
01482 {
01483 int d = (dt % y) - 1;
01484 if ( d < 0 )
01485 {
01486 if ( wrap )
01487 d += y;
01488 else
01489 return desktop;
01490 }
01491 dt = dt - (dt % y) + d;
01492 }
01493 return dt+1;
01494 }
01495
01496 int Workspace::desktopDown( int desktop, bool wrap ) const
01497 {
01498 int x,y;
01499 Qt::Orientation orientation;
01500 calcDesktopLayout( &x, &y, &orientation);
01501 int dt = desktop-1;
01502 if (orientation == Qt::Horizontal)
01503 {
01504 dt += x;
01505 if ( dt >= numberOfDesktops() )
01506 {
01507 if ( wrap )
01508 dt -= numberOfDesktops();
01509 else
01510 return desktop;
01511 }
01512 }
01513 else
01514 {
01515 int d = (dt % y) + 1;
01516 if ( d >= y )
01517 {
01518 if ( wrap )
01519 d -= y;
01520 else
01521 return desktop;
01522 }
01523 dt = dt - (dt % y) + d;
01524 }
01525 return dt+1;
01526 }
01527
01528
01532 void Workspace::setNumberOfDesktops( int n )
01533 {
01534 if ( n == number_of_desktops )
01535 return;
01536 int old_number_of_desktops = number_of_desktops;
01537 number_of_desktops = n;
01538
01539 if( currentDesktop() > numberOfDesktops())
01540 setCurrentDesktop( numberOfDesktops());
01541
01542
01543
01544 if( old_number_of_desktops < number_of_desktops )
01545 {
01546 rootInfo->setNumberOfDesktops( number_of_desktops );
01547 NETPoint* viewports = new NETPoint[ number_of_desktops ];
01548 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01549 delete[] viewports;
01550 updateClientArea( true );
01551 focus_chain.resize( number_of_desktops + 1 );
01552 }
01553
01554
01555
01556 if( old_number_of_desktops > number_of_desktops )
01557 {
01558 for( ClientList::ConstIterator it = clients.begin();
01559 it != clients.end();
01560 ++it)
01561 {
01562 if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
01563 sendClientToDesktop( *it, numberOfDesktops(), true );
01564 }
01565 }
01566 if( old_number_of_desktops > number_of_desktops )
01567 {
01568 rootInfo->setNumberOfDesktops( number_of_desktops );
01569 NETPoint* viewports = new NETPoint[ number_of_desktops ];
01570 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01571 delete[] viewports;
01572 updateClientArea( true );
01573 focus_chain.resize( number_of_desktops + 1 );
01574 }
01575
01576 saveDesktopSettings();
01577
01578
01579 desktop_focus_chain.resize( n );
01580 for( int i = 0; i < (int)desktop_focus_chain.size(); i++ )
01581 desktop_focus_chain[i] = i+1;
01582 }
01583
01589 void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
01590 {
01591 bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
01592 c->setDesktop( desk );
01593 if ( c->desktop() != desk )
01594 return;
01595 desk = c->desktop();
01596
01597 if ( c->isOnDesktop( currentDesktop() ) )
01598 {
01599 if ( c->wantsTabFocus() && options->focusPolicyIsReasonable()
01600 && !was_on_desktop
01601 && !dont_activate )
01602 requestFocus( c );
01603 else
01604 restackClientUnderActive( c );
01605 }
01606 else
01607 {
01608 raiseClient( c );
01609 }
01610
01611 ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01612 for( ClientList::ConstIterator it = transients_stacking_order.begin();
01613 it != transients_stacking_order.end();
01614 ++it )
01615 sendClientToDesktop( *it, desk, dont_activate );
01616 updateClientArea();
01617 }
01618
01619 int Workspace::numScreens() const
01620 {
01621 if( !options->xineramaEnabled )
01622 return 1;
01623 return qApp->desktop()->numScreens();
01624 }
01625
01626 int Workspace::activeScreen() const
01627 {
01628 if( !options->xineramaEnabled )
01629 return 0;
01630 if( !options->activeMouseScreen )
01631 {
01632 if( activeClient() != NULL && !activeClient()->isOnScreen( active_screen ))
01633 return qApp->desktop()->screenNumber( activeClient()->geometry().center());
01634 return active_screen;
01635 }
01636 return qApp->desktop()->screenNumber( cursorPos());
01637 }
01638
01639
01640
01641 void Workspace::checkActiveScreen( const Client* c )
01642 {
01643 if( !options->xineramaEnabled )
01644 return;
01645 if( !c->isActive())
01646 return;
01647 if( !c->isOnScreen( active_screen ))
01648 active_screen = c->screen();
01649 }
01650
01651
01652
01653 void Workspace::setActiveScreenMouse( const QPoint &mousepos )
01654 {
01655 if( !options->xineramaEnabled )
01656 return;
01657 active_screen = qApp->desktop()->screenNumber( mousepos );
01658 }
01659
01660 QRect Workspace::screenGeometry( int screen ) const
01661 {
01662 if( !options->xineramaEnabled )
01663 return qApp->desktop()->geometry();
01664 return qApp->desktop()->screenGeometry( screen );
01665 }
01666
01667 int Workspace::screenNumber( const QPoint &pos ) const
01668 {
01669 if( !options->xineramaEnabled )
01670 return 0;
01671 return qApp->desktop()->screenNumber( pos );
01672 }
01673
01674 void Workspace::sendClientToScreen( Client* c, int screen )
01675 {
01676 if( c->screen() == screen )
01677 return;
01678 GeometryUpdatesBlocker blocker( c );
01679 QRect old_sarea = clientArea( MaximizeArea, c );
01680 QRect sarea = clientArea( MaximizeArea, screen, c->desktop());
01681 c->setGeometry( sarea.x() - old_sarea.x() + c->x(), sarea.y() - old_sarea.y() + c->y(),
01682 c->size().width(), c->size().height());
01683 c->checkWorkspacePosition();
01684 ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01685 for( ClientList::ConstIterator it = transients_stacking_order.begin();
01686 it != transients_stacking_order.end();
01687 ++it )
01688 sendClientToScreen( *it, screen );
01689 if( c->isActive())
01690 active_screen = screen;
01691 }
01692
01693 void Workspace::updateDesktopLayout()
01694 {
01695
01696 layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal
01697 ? Qt::Horizontal : Qt::Vertical );
01698 layoutX = rootInfo->desktopLayoutColumnsRows().width();
01699 layoutY = rootInfo->desktopLayoutColumnsRows().height();
01700 if( layoutX == 0 && layoutY == 0 )
01701 layoutY = 2;
01702 }
01703
01704 void Workspace::calcDesktopLayout(int* xp, int* yp, Qt::Orientation* orientation) const
01705 {
01706 int x = layoutX;
01707 int y = layoutY;
01708 if((x <= 0) && (y > 0))
01709 x = (numberOfDesktops()+y-1) / y;
01710 else if((y <=0) && (x > 0))
01711 y = (numberOfDesktops()+x-1) / x;
01712
01713 if(x <=0)
01714 x = 1;
01715 if (y <= 0)
01716 y = 1;
01717 *xp = x;
01718 *yp = y;
01719 *orientation = layoutOrientation;
01720 }
01721
01722 void Workspace::killWindowId( Window window_to_kill )
01723 {
01724 if( window_to_kill == None )
01725 return;
01726 Window window = window_to_kill;
01727 Client* client = NULL;
01728 for(;;)
01729 {
01730 client = findClient( FrameIdMatchPredicate( window ));
01731 if( client != NULL )
01732 break;
01733 Window parent, root;
01734 Window* children;
01735 unsigned int children_count;
01736 XQueryTree( display(), window, &root, &parent, &children, &children_count );
01737 if( children != NULL )
01738 XFree( children );
01739 if( window == root )
01740 break;
01741 window = parent;
01742 }
01743 if( client != NULL )
01744 client->killWindow();
01745 else
01746 XKillClient( display(), window_to_kill );
01747 }
01748
01749
01750 void Workspace::sendPingToWindow( Window window, Time timestamp )
01751 {
01752 rootInfo->sendPing( window, timestamp );
01753 }
01754
01755 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
01756 {
01757 rootInfo->takeActivity( c->window(), timestamp, flags );
01758 pending_take_activity = c;
01759 }
01760
01761
01765 void Workspace::slotGrabWindow()
01766 {
01767 if ( active_client )
01768 {
01769 QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
01770
01771
01772 if( Extensions::shapeAvailable())
01773 {
01774
01775 int count, order;
01776 XRectangle* rects = XShapeGetRectangles( display(), active_client->frameId(),
01777 ShapeBounding, &count, &order);
01778
01779
01780
01781
01782 if (rects)
01783 {
01784
01785 QRegion contents;
01786 for (int pos = 0; pos < count; pos++)
01787 contents += QRegion(rects[pos].x, rects[pos].y,
01788 rects[pos].width, rects[pos].height);
01789 XFree(rects);
01790
01791
01792 QRegion bbox(0, 0, snapshot.width(), snapshot.height());
01793
01794
01795 QRegion maskedAway = bbox - contents;
01796 QVector<QRect> maskedAwayRects = maskedAway.rects();
01797
01798
01799 QBitmap mask( snapshot.width(), snapshot.height());
01800 QPainter p(&mask);
01801 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
01802 for (int pos = 0; pos < maskedAwayRects.count(); pos++)
01803 p.fillRect(maskedAwayRects[pos], Qt::color0);
01804 p.end();
01805 snapshot.setMask(mask);
01806 }
01807 }
01808
01809 QClipboard *cb = QApplication::clipboard();
01810 cb->setPixmap( snapshot );
01811 }
01812 else
01813 slotGrabDesktop();
01814 }
01815
01819 void Workspace::slotGrabDesktop()
01820 {
01821 QPixmap p = QPixmap::grabWindow( rootWindow() );
01822 QClipboard *cb = QApplication::clipboard();
01823 cb->setPixmap( p );
01824 }
01825
01826
01830 void Workspace::slotMouseEmulation()
01831 {
01832 if ( mouse_emulation )
01833 {
01834 ungrabXKeyboard();
01835 mouse_emulation = false;
01836 return;
01837 }
01838
01839 if( grabXKeyboard())
01840 {
01841 mouse_emulation = true;
01842 mouse_emulation_state = 0;
01843 mouse_emulation_window = 0;
01844 }
01845 }
01846
01853 WId Workspace::getMouseEmulationWindow()
01854 {
01855 Window root;
01856 Window child = rootWindow();
01857 int root_x, root_y, lx, ly;
01858 uint state;
01859 Window w;
01860 Client * c = 0;
01861 do
01862 {
01863 w = child;
01864 if (!c)
01865 c = findClient( FrameIdMatchPredicate( w ));
01866 XQueryPointer( display(), w, &root, &child,
01867 &root_x, &root_y, &lx, &ly, &state );
01868 } while ( child != None && child != w );
01869
01870 if ( c && !c->isActive() )
01871 activateClient( c );
01872 return (WId) w;
01873 }
01874
01878 unsigned int Workspace::sendFakedMouseEvent( const QPoint &pos, WId w, MouseEmulation type, int button, unsigned int state )
01879 {
01880 if ( !w )
01881 return state;
01882 QWidget* widget = QWidget::find( w );
01883 if ( (!widget || qobject_cast<QToolButton*>(widget)) && !findClient( WindowMatchPredicate( w )) )
01884 {
01885 int x, y;
01886 Window xw;
01887 XTranslateCoordinates( display(), rootWindow(), w, pos.x(), pos.y(), &x, &y, &xw );
01888 if ( type == EmuMove )
01889 {
01890 XEvent e;
01891 e.type = MotionNotify;
01892 e.xmotion.window = w;
01893 e.xmotion.root = rootWindow();
01894 e.xmotion.subwindow = w;
01895 e.xmotion.time = xTime();
01896 e.xmotion.x = x;
01897 e.xmotion.y = y;
01898 e.xmotion.x_root = pos.x();
01899 e.xmotion.y_root = pos.y();
01900 e.xmotion.state = state;
01901 e.xmotion.is_hint = NotifyNormal;
01902 XSendEvent( display(), w, true, ButtonMotionMask, &e );
01903 }
01904 else
01905 {
01906 XEvent e;
01907 e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
01908 e.xbutton.window = w;
01909 e.xbutton.root = rootWindow();
01910 e.xbutton.subwindow = w;
01911 e.xbutton.time = xTime();
01912 e.xbutton.x = x;
01913 e.xbutton.y = y;
01914 e.xbutton.x_root = pos.x();
01915 e.xbutton.y_root = pos.y();
01916 e.xbutton.state = state;
01917 e.xbutton.button = button;
01918 XSendEvent( display(), w, true, ButtonPressMask, &e );
01919
01920 if ( type == EmuPress )
01921 {
01922 switch ( button )
01923 {
01924 case 2:
01925 state |= Button2Mask;
01926 break;
01927 case 3:
01928 state |= Button3Mask;
01929 break;
01930 default:
01931 state |= Button1Mask;
01932 break;
01933 }
01934 }
01935 else
01936 {
01937 switch ( button )
01938 {
01939 case 2:
01940 state &= ~Button2Mask;
01941 break;
01942 case 3:
01943 state &= ~Button3Mask;
01944 break;
01945 default:
01946 state &= ~Button1Mask;
01947 break;
01948 }
01949 }
01950 }
01951 }
01952 return state;
01953 }
01954
01958 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
01959 {
01960 int kc = XKeycodeToKeysym(display(), ev.keycode, 0);
01961 int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
01962
01963 bool is_control = km & ControlMask;
01964 bool is_alt = km & Mod1Mask;
01965 bool is_shift = km & ShiftMask;
01966 int delta = is_control?1:is_alt?32:8;
01967 QPoint pos = cursorPos();
01968
01969 switch ( kc )
01970 {
01971 case XK_Left:
01972 case XK_KP_Left:
01973 pos.rx() -= delta;
01974 break;
01975 case XK_Right:
01976 case XK_KP_Right:
01977 pos.rx() += delta;
01978 break;
01979 case XK_Up:
01980 case XK_KP_Up:
01981 pos.ry() -= delta;
01982 break;
01983 case XK_Down:
01984 case XK_KP_Down:
01985 pos.ry() += delta;
01986 break;
01987 case XK_F1:
01988 if ( !mouse_emulation_state )
01989 mouse_emulation_window = getMouseEmulationWindow();
01990 if ( (mouse_emulation_state & Button1Mask) == 0 )
01991 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01992 if ( !is_shift )
01993 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01994 break;
01995 case XK_F2:
01996 if ( !mouse_emulation_state )
01997 mouse_emulation_window = getMouseEmulationWindow();
01998 if ( (mouse_emulation_state & Button2Mask) == 0 )
01999 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
02000 if ( !is_shift )
02001 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
02002 break;
02003 case XK_F3:
02004 if ( !mouse_emulation_state )
02005 mouse_emulation_window = getMouseEmulationWindow();
02006 if ( (mouse_emulation_state & Button3Mask) == 0 )
02007 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
02008 if ( !is_shift )
02009 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02010 break;
02011 case XK_Return:
02012 case XK_space:
02013 case XK_KP_Enter:
02014 case XK_KP_Space:
02015 {
02016 if ( !mouse_emulation_state )
02017 {
02018
02019 mouse_emulation_window = getMouseEmulationWindow();
02020 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
02021 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02022 }
02023 else
02024 {
02025 if ( mouse_emulation_state & Button1Mask )
02026 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02027 if ( mouse_emulation_state & Button2Mask )
02028 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
02029 if ( mouse_emulation_state & Button3Mask )
02030 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02031 }
02032 }
02033
02034 case XK_Escape:
02035 ungrabXKeyboard();
02036 mouse_emulation = false;
02037 return true;
02038 default:
02039 return false;
02040 }
02041
02042 QCursor::setPos( pos );
02043 if ( mouse_emulation_state )
02044 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
02045 return true;
02046
02047 }
02048
02049
02050 void Workspace::delayFocus()
02051 {
02052 requestFocus( delayfocus_client );
02053 cancelDelayFocus();
02054 }
02055
02056 void Workspace::requestDelayFocus( Client* c )
02057 {
02058 delayfocus_client = c;
02059 delete delayFocusTimer;
02060 delayFocusTimer = new QTimer( this );
02061 connect( delayFocusTimer, SIGNAL( timeout() ), this, SLOT( delayFocus() ) );
02062 delayFocusTimer->setSingleShot( true );
02063 delayFocusTimer->start( options->delayFocusInterval );
02064 }
02065
02066 void Workspace::cancelDelayFocus()
02067 {
02068 delete delayFocusTimer;
02069 delayFocusTimer = 0;
02070 }
02071
02072
02073
02074
02075
02076
02077
02078 void Workspace::updateElectricBorders()
02079 {
02080 electric_time_first = xTime();
02081 electric_time_last = xTime();
02082 electric_current_border = ElectricNone;
02083 QRect r = QApplication::desktop()->geometry();
02084 electricTop = r.top();
02085 electricBottom = r.bottom();
02086 electricLeft = r.left();
02087 electricRight = r.right();
02088
02089 for( int pos = 0;
02090 pos < ELECTRIC_COUNT;
02091 ++pos )
02092 {
02093 if( electric_reserved[ pos ] == 0 )
02094 {
02095 if( electric_windows[ pos ] != None )
02096 XDestroyWindow( display(), electric_windows[ pos ] );
02097 electric_windows[ pos ] = None;
02098 continue;
02099 }
02100 if( electric_windows[ pos ] != None )
02101 continue;
02102 XSetWindowAttributes attributes;
02103 attributes.override_redirect = True;
02104 attributes.event_mask = EnterWindowMask | LeaveWindowMask;
02105 unsigned long valuemask = CWOverrideRedirect | CWEventMask;
02106 int xywh[ ELECTRIC_COUNT ][ 4 ] =
02107 {
02108 { r.left() + 1, r.top(), r.width() - 2, 1 },
02109 { r.right(), r.top(), 1, 1 },
02110 { r.right(), r.top() + 1, 1, r.height() - 2 },
02111 { r.right(), r.bottom(), 1, 1 },
02112 { r.left() + 1, r.bottom(), r.width() - 2, 1 },
02113 { r.left(), r.bottom(), 1, 1 },
02114 { r.left(), r.top() + 1, 1, r.height() - 2 },
02115 { r.left(), r.top(), 1, 1 }
02116 };
02117 electric_windows[ pos ] = XCreateWindow( display(), rootWindow(),
02118 xywh[ pos ][ 0 ], xywh[ pos ][ 1 ], xywh[ pos ][ 2 ], xywh[ pos ][ 3 ],
02119 0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes );
02120 XMapWindow( display(), electric_windows[ pos ]);
02121
02122 Atom version = 4;
02123 XChangeProperty( display(), electric_windows[ pos ], atoms->xdnd_aware, XA_ATOM,
02124 32, PropModeReplace, ( unsigned char* )&version, 1 );
02125 }
02126 }
02127
02128 void Workspace::destroyElectricBorders()
02129 {
02130 for( int pos = 0;
02131 pos < ELECTRIC_COUNT;
02132 ++pos )
02133 {
02134 if( electric_windows[ pos ] != None )
02135 XDestroyWindow( display(), electric_windows[ pos ] );
02136 electric_windows[ pos ] = None;
02137 }
02138 }
02139
02140 void Workspace::reserveElectricBorderSwitching( bool reserve )
02141 {
02142 for( int pos = 0;
02143 pos < ELECTRIC_COUNT;
02144 ++pos )
02145 if( reserve )
02146 reserveElectricBorder( static_cast< ElectricBorder >( pos ));
02147 else
02148 unreserveElectricBorder( static_cast< ElectricBorder >( pos ));
02149 }
02150
02151 void Workspace::reserveElectricBorder( ElectricBorder border )
02152 {
02153 if( border == ElectricNone )
02154 return;
02155 if( electric_reserved[ border ]++ == 0 )
02156 QTimer::singleShot( 0, this, SLOT( updateElectricBorders()));
02157 }
02158
02159 void Workspace::unreserveElectricBorder( ElectricBorder border )
02160 {
02161 if( border == ElectricNone )
02162 return;
02163 assert( electric_reserved[ border ] > 0 );
02164 if( --electric_reserved[ border ] == 0 )
02165 QTimer::singleShot( 0, this, SLOT( updateElectricBorders()));
02166 }
02167
02168 void Workspace::checkElectricBorder(const QPoint &pos, Time now)
02169 {
02170 if ((pos.x() != electricLeft) &&
02171 (pos.x() != electricRight) &&
02172 (pos.y() != electricTop) &&
02173 (pos.y() != electricBottom))
02174 return;
02175
02176 bool have_borders = false;
02177 for( int i = 0;
02178 i < ELECTRIC_COUNT;
02179 ++i )
02180 if( electric_windows[ i ] != None )
02181 have_borders = true;
02182 if( !have_borders )
02183 return;
02184
02185 Time treshold_set = options->electricBorderDelay();
02186 Time treshold_reset = 250;
02187 int distance_reset = 30;
02188
02189 ElectricBorder border;
02190 if( pos.x() == electricLeft && pos.y() == electricTop )
02191 border = ElectricTopLeft;
02192 else if( pos.x() == electricRight && pos.y() == electricTop )
02193 border = ElectricTopRight;
02194 else if( pos.x() == electricLeft && pos.y() == electricBottom )
02195 border = ElectricBottomLeft;
02196 else if( pos.x() == electricRight && pos.y() == electricBottom )
02197 border = ElectricBottomRight;
02198 else if( pos.x() == electricLeft )
02199 border = ElectricLeft;
02200 else if( pos.x() == electricRight )
02201 border = ElectricRight;
02202 else if( pos.y() == electricTop )
02203 border = ElectricTop;
02204 else if( pos.y() == electricBottom )
02205 border = ElectricBottom;
02206 else
02207 abort();
02208
02209 if( electric_windows[ border ] == None )
02210 return;
02211
02212 if ((electric_current_border == border) &&
02213 (timestampDiff(electric_time_last, now) < treshold_reset) &&
02214 ((pos-electric_push_point).manhattanLength() < distance_reset))
02215 {
02216 electric_time_last = now;
02217
02218 if (timestampDiff(electric_time_first, now) > treshold_set)
02219 {
02220 electric_current_border = ElectricNone;
02221 if( effects && static_cast<EffectsHandlerImpl*>(effects)->borderActivated( border ))
02222 {}
02223 else
02224 electricBorderSwitchDesktop( border, pos );
02225 return;
02226 }
02227 }
02228 else
02229 {
02230 electric_current_border = border;
02231 electric_time_first = now;
02232 electric_time_last = now;
02233 electric_push_point = pos;
02234 }
02235
02236
02237
02238 const int xdiff[ ELECTRIC_COUNT ] = { 0, -1, -1, -1, 0, 1, 1, 1 };
02239 const int ydiff[ ELECTRIC_COUNT ] = { 1, 1, 0, -1, -1, -1, 0, 1 };
02240 QCursor::setPos( pos.x() + xdiff[ border ], pos.y() + ydiff[ border ] );
02241 }
02242
02243 void Workspace::electricBorderSwitchDesktop( ElectricBorder border, const QPoint& _pos )
02244 {
02245 QPoint pos = _pos;
02246 int desk = currentDesktop();
02247 const int OFFSET = 2;
02248 if( border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft )
02249 {
02250 desk = desktopToLeft( desk, options->rollOverDesktops );
02251 pos.setX( displayWidth() - 1 - OFFSET );
02252 }
02253 if( border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight )
02254 {
02255 desk = desktopToRight( desk, options->rollOverDesktops );
02256 pos.setX( OFFSET );
02257 }
02258 if( border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight )
02259 {
02260 desk = desktopUp( desk, options->rollOverDesktops );
02261 pos.setY( displayHeight() - 1 - OFFSET );
02262 }
02263 if( border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight )
02264 {
02265 desk = desktopDown( desk, options->rollOverDesktops );
02266 pos.setY( OFFSET );
02267 }
02268 int desk_before = currentDesktop();
02269 setCurrentDesktop( desk );
02270 if( currentDesktop() != desk_before )
02271 QCursor::setPos( pos );
02272 }
02273
02274
02275
02276 bool Workspace::electricBorderEvent(XEvent *e)
02277 {
02278 if( e->type == EnterNotify )
02279 {
02280 for( int i = 0;
02281 i < ELECTRIC_COUNT;
02282 ++i )
02283 if( electric_windows[ i ] != None && e->xcrossing.window == electric_windows[ i ] )
02284 {
02285 checkElectricBorder( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
02286 return true;
02287 }
02288 }
02289 if( e->type == ClientMessage )
02290 {
02291 if( e->xclient.message_type == atoms->xdnd_position )
02292 {
02293 for( int i = 0;
02294 i < ELECTRIC_COUNT;
02295 ++i )
02296 if( electric_windows[ i ] != None && e->xclient.window == electric_windows[ i ] )
02297 {
02298 updateXTime();
02299 checkElectricBorder( QPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), xTime() );
02300 return true;
02301 }
02302 }
02303 }
02304 return false;
02305 }
02306
02307 void Workspace::addTopMenu( Client* c )
02308 {
02309 assert( c->isTopMenu());
02310 assert( !topmenus.contains( c ));
02311 topmenus.append( c );
02312 if( managingTopMenus())
02313 {
02314 int minsize = c->minSize().height();
02315 if( minsize > topMenuHeight())
02316 {
02317 topmenu_height = minsize;
02318 updateTopMenuGeometry();
02319 }
02320 updateTopMenuGeometry( c );
02321 updateCurrentTopMenu();
02322 }
02323
02324 }
02325
02326 void Workspace::removeTopMenu( Client* c )
02327 {
02328
02329
02330 assert( c->isTopMenu());
02331 assert( topmenus.contains( c ));
02332 topmenus.removeAll( c );
02333 updateCurrentTopMenu();
02334
02335 }
02336
02337 void Workspace::lostTopMenuSelection()
02338 {
02339
02340
02341 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02342 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02343 if( !managing_topmenus )
02344 return;
02345 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02346 disconnect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02347 managing_topmenus = false;
02348 delete topmenu_space;
02349 topmenu_space = NULL;
02350 updateClientArea();
02351 for( ClientList::ConstIterator it = topmenus.begin();
02352 it != topmenus.end();
02353 ++it )
02354 (*it)->checkWorkspacePosition();
02355 }
02356
02357 void Workspace::lostTopMenuOwner()
02358 {
02359 if( !options->topMenuEnabled())
02360 return;
02361
02362 if( !topmenu_selection->claim( false ))
02363 {
02364
02365 return;
02366 }
02367
02368 setupTopMenuHandling();
02369 }
02370
02371 void Workspace::setupTopMenuHandling()
02372 {
02373 if( managing_topmenus )
02374 return;
02375 connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02376 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02377 managing_topmenus = true;
02378 topmenu_space = new QWidget;
02379 Window stack[ 2 ];
02380 stack[ 0 ] = supportWindow->winId();
02381 stack[ 1 ] = topmenu_space->winId();
02382 XRestackWindows(display(), stack, 2);
02383 updateTopMenuGeometry();
02384 topmenu_space->show();
02385 updateClientArea();
02386 updateCurrentTopMenu();
02387 }
02388
02389 int Workspace::topMenuHeight() const
02390 {
02391 if( topmenu_height == 0 )
02392 {
02393 KMenuBar tmpmenu;
02394 tmpmenu.addAction( "dummy" );
02395 topmenu_height = tmpmenu.sizeHint().height();
02396 }
02397 return topmenu_height;
02398 }
02399
02400 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
02401 {
02402 return mgr->createDecoration( bridge );
02403 }
02404
02405
02406
02407 QList< int > Workspace::decorationSupportedColors() const
02408 {
02409 KDecorationFactory* factory = mgr->factory();
02410 QList< int > ret;
02411 for( Ability ab = ABILITYCOLOR_FIRST;
02412 ab < ABILITYCOLOR_END;
02413 ab = static_cast< Ability>( ab + 1 ))
02414 {
02415 if( factory->supports( ab ))
02416 ret << ab;
02417 }
02418 return ret;
02419 }
02420
02421 QString Workspace::desktopName( int desk ) const
02422 {
02423 return QString::fromUtf8( rootInfo->desktopName( desk ) );
02424 }
02425
02426 bool Workspace::checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data )
02427 {
02428 return startup->checkStartup( w, id, data ) == KStartupInfo::Match;
02429 }
02430
02435 void Workspace::focusToNull()
02436 {
02437 XSetInputFocus(display(), null_focus_window, RevertToPointerRoot, xTime() );
02438 }
02439
02440 void Workspace::helperDialog( const QString& message, const Client* c )
02441 {
02442 QStringList args;
02443 QString type;
02444 if( message == "noborderaltf3" )
02445 {
02446 KAction* action = qobject_cast<KAction*>(keys->action( "Window Operations Menu" ));
02447 if (action==0) assert( false );
02448 QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
02449 .arg( action->globalShortcut().primary().toString());
02450 args << "--msgbox" <<
02451 i18n( "You have selected to show a window without its border.\n"
02452 "Without the border, you will not be able to enable the border "
02453 "again using the mouse: use the window operations menu instead, "
02454 "activated using the %1 keyboard shortcut." ,
02455 shortcut );
02456 type = "altf3warning";
02457 }
02458 else if( message == "fullscreenaltf3" )
02459 {
02460 KAction* action = qobject_cast<KAction*>(keys->action( "Window Operations Menu" ));
02461 if (action==0) assert( false );
02462 QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
02463 .arg( action->globalShortcut().primary().toString());
02464 args << "--msgbox" <<
02465 i18n( "You have selected to show a window in fullscreen mode.\n"
02466 "If the application itself does not have an option to turn the fullscreen "
02467 "mode off you will not be able to disable it "
02468 "again using the mouse: use the window operations menu instead, "
02469 "activated using the %1 keyboard shortcut." ,
02470 shortcut );
02471 type = "altf3warning";
02472 }
02473 else
02474 assert( false );
02475 if( !type.isEmpty())
02476 {
02477 KConfig cfg( "kwin_dialogsrc" );
02478 KConfigGroup cg(&cfg, "Notification Messages" );
02479 if( !cg.readEntry( type, true ))
02480 return;
02481 args <<"--dontagain" << "kwin_dialogsrc:" + type;
02482 }
02483 if( c != NULL )
02484 args <<"--embed" << QString::number( c->window());
02485 KProcess::startDetached("kdialog",args);
02486 }
02487
02488 void Workspace::setShowingDesktop( bool showing )
02489 {
02490 rootInfo->setShowingDesktop( showing );
02491 showing_desktop = showing;
02492 ++block_showing_desktop;
02493 if( showing_desktop )
02494 {
02495 showing_desktop_clients.clear();
02496 ++block_focus;
02497 ClientList cls = stackingOrder();
02498
02499
02500 for( ClientList::ConstIterator it = cls.begin();
02501 it != cls.end();
02502 ++it )
02503 {
02504 if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
02505 showing_desktop_clients.prepend( *it );
02506 }
02507 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02508 it != showing_desktop_clients.end();
02509 ++it )
02510 (*it)->minimize();
02511 --block_focus;
02512 if( Client* desk = findDesktop( true, currentDesktop()))
02513 requestFocus( desk );
02514 }
02515 else
02516 {
02517 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02518 it != showing_desktop_clients.end();
02519 ++it )
02520 (*it)->unminimize();
02521 if( showing_desktop_clients.count() > 0 )
02522 requestFocus( showing_desktop_clients.first());
02523 showing_desktop_clients.clear();
02524 }
02525 --block_showing_desktop;
02526 }
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537 void Workspace::resetShowingDesktop( bool keep_hidden )
02538 {
02539 if( block_showing_desktop > 0 )
02540 return;
02541 rootInfo->setShowingDesktop( false );
02542 showing_desktop = false;
02543 ++block_showing_desktop;
02544 if( !keep_hidden )
02545 {
02546 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02547 it != showing_desktop_clients.end();
02548 ++it )
02549 (*it)->unminimize();
02550 }
02551 showing_desktop_clients.clear();
02552 --block_showing_desktop;
02553 }
02554
02555
02556
02557
02558
02559
02560
02561
02562 void Workspace::slotDisableGlobalShortcuts()
02563 {
02564 if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
02565 disableGlobalShortcuts( false );
02566 else
02567 disableGlobalShortcuts( true );
02568 }
02569
02570 static bool pending_dfc = false;
02571
02572 void Workspace::disableGlobalShortcutsForClient( bool disable )
02573 {
02574 if( global_shortcuts_disabled_for_client == disable )
02575 return;
02576 if( !global_shortcuts_disabled )
02577 {
02578 if( disable )
02579 pending_dfc = true;
02580 KGlobalSettings::self()->emitChange( KGlobalSettings::BlockShortcuts, disable );
02581
02582 }
02583 }
02584
02585 void Workspace::disableGlobalShortcuts( bool disable )
02586 {
02587 KGlobalSettings::self()->emitChange( KGlobalSettings::BlockShortcuts, disable );
02588
02589 }
02590
02591 void Workspace::slotBlockShortcuts( int data )
02592 {
02593 if( pending_dfc && data )
02594 {
02595 global_shortcuts_disabled_for_client = true;
02596 pending_dfc = false;
02597 }
02598 else
02599 {
02600 global_shortcuts_disabled = data;
02601 global_shortcuts_disabled_for_client = false;
02602 }
02603
02604 for( ClientList::ConstIterator it = clients.begin();
02605 it != clients.end();
02606 ++it )
02607 (*it)->updateMouseGrab();
02608 }
02609
02610
02611
02612 static QPoint last_cursor_pos;
02613 static int last_buttons = 0;
02614 static Time last_cursor_timestamp = CurrentTime;
02615 static QTimer* last_cursor_timer;
02616
02617 QPoint Workspace::cursorPos() const
02618 {
02619 if( last_cursor_timestamp == CurrentTime
02620 || last_cursor_timestamp != QX11Info::appTime())
02621 {
02622 last_cursor_timestamp = QX11Info::appTime();
02623 Window root;
02624 Window child;
02625 int root_x, root_y, win_x, win_y;
02626 uint state;
02627 XQueryPointer( display(), rootWindow(), &root, &child,
02628 &root_x, &root_y, &win_x, &win_y, &state );
02629 last_cursor_pos = QPoint( root_x, root_y );
02630 last_buttons = state;
02631 if( last_cursor_timer == NULL )
02632 {
02633 Workspace* ws = const_cast< Workspace* >( this );
02634 last_cursor_timer = new QTimer( ws );
02635 last_cursor_timer->setSingleShot( true );
02636 connect( last_cursor_timer, SIGNAL( timeout()), ws, SLOT( resetCursorPosTime()));
02637 }
02638 last_cursor_timer->start( 0 );
02639 }
02640 return last_cursor_pos;
02641 }
02642
02643
02644
02645
02646 void Workspace::resetCursorPosTime()
02647 {
02648 last_cursor_timestamp = CurrentTime;
02649 }
02650
02651 void Workspace::checkCursorPos()
02652 {
02653 QPoint last = last_cursor_pos;
02654 int lastb = last_buttons;
02655 cursorPos();
02656 if( last != last_cursor_pos || lastb != last_buttons )
02657 static_cast< EffectsHandlerImpl* >( effects )->mouseChanged( cursorPos(), last,
02658 x11ToQtMouseButtons( last_buttons ), x11ToQtMouseButtons( lastb ),
02659 x11ToQtKeyboardModifiers( last_buttons ), x11ToQtKeyboardModifiers( lastb ));
02660 }
02661
02662 }
02663
02664 #include "workspace.moc"