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