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