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 void Workspace::setDesktopLayout( int, int, int )
01529 {
01530 }
01531
01532 int Workspace::numScreens() const
01533 {
01534 if( !options->xineramaEnabled )
01535 return 0;
01536 return qApp->desktop()->numScreens();
01537 }
01538
01539 int Workspace::activeScreen() const
01540 {
01541 if( !options->xineramaEnabled )
01542 return 0;
01543 if( !options->activeMouseScreen )
01544 {
01545 if( activeClient() != NULL && !activeClient()->isOnScreen( active_screen ))
01546 return qApp->desktop()->screenNumber( activeClient()->geometry().center());
01547 return active_screen;
01548 }
01549 return qApp->desktop()->screenNumber( QCursor::pos());
01550 }
01551
01552
01553
01554 void Workspace::checkActiveScreen( const Client* c )
01555 {
01556 if( !options->xineramaEnabled )
01557 return;
01558 if( !c->isActive())
01559 return;
01560 if( !c->isOnScreen( active_screen ))
01561 active_screen = c->screen();
01562 }
01563
01564
01565
01566 void Workspace::setActiveScreenMouse( QPoint mousepos )
01567 {
01568 if( !options->xineramaEnabled )
01569 return;
01570 active_screen = qApp->desktop()->screenNumber( mousepos );
01571 }
01572
01573 QRect Workspace::screenGeometry( int screen ) const
01574 {
01575 if( !options->xineramaEnabled )
01576 return qApp->desktop()->geometry();
01577 return qApp->desktop()->screenGeometry( screen );
01578 }
01579
01580 int Workspace::screenNumber( QPoint pos ) const
01581 {
01582 if( !options->xineramaEnabled )
01583 return 0;
01584 return qApp->desktop()->screenNumber( pos );
01585 }
01586
01587
01588 void Workspace::sendClientToScreen( Client* c, int screen )
01589 {
01590 if( c->screen() == screen )
01591
01592 return;
01593 GeometryUpdatesPostponer blocker( c );
01594 QRect old_sarea = clientArea( MaximizeArea, c );
01595 QRect sarea = clientArea( MaximizeArea, screen, c->desktop());
01596 c->setGeometry( sarea.x() - old_sarea.x() + c->x(), sarea.y() - old_sarea.y() + c->y(),
01597 c->size().width(), c->size().height());
01598 c->checkWorkspacePosition();
01599 ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01600 for( ClientList::ConstIterator it = transients_stacking_order.begin();
01601 it != transients_stacking_order.end();
01602 ++it )
01603 sendClientToScreen( *it, screen );
01604 if( c->isActive())
01605 active_screen = screen;
01606 }
01607
01608
01609 void Workspace::updateDesktopLayout()
01610 {
01611
01612 layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal
01613 ? Qt::Horizontal : Qt::Vertical );
01614 layoutX = rootInfo->desktopLayoutColumnsRows().width();
01615 layoutY = rootInfo->desktopLayoutColumnsRows().height();
01616 if( layoutX == 0 && layoutY == 0 )
01617 layoutY = 2;
01618 }
01619
01620 void Workspace::calcDesktopLayout(int &x, int &y) const
01621 {
01622 x = layoutX;
01623 y = layoutY;
01624 if((x <= 0) && (y > 0))
01625 x = (numberOfDesktops()+y-1) / y;
01626 else if((y <=0) && (x > 0))
01627 y = (numberOfDesktops()+x-1) / x;
01628
01629 if(x <=0)
01630 x = 1;
01631 if (y <= 0)
01632 y = 1;
01633 }
01634
01639 bool Workspace::addSystemTrayWin( WId w )
01640 {
01641 if ( systemTrayWins.contains( w ) )
01642 return TRUE;
01643
01644 NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
01645 WId trayWinFor = ni.kdeSystemTrayWinFor();
01646 if ( !trayWinFor )
01647 return FALSE;
01648 systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
01649 XSelectInput( qt_xdisplay(), w,
01650 StructureNotifyMask
01651 );
01652 XAddToSaveSet( qt_xdisplay(), w );
01653 propagateSystemTrayWins();
01654 return TRUE;
01655 }
01656
01661 bool Workspace::removeSystemTrayWin( WId w, bool check )
01662 {
01663 if ( !systemTrayWins.contains( w ) )
01664 return FALSE;
01665 if( check )
01666 {
01667
01668
01669
01670
01671
01672
01673
01674 int num_props;
01675 Atom* props = XListProperties( qt_xdisplay(), w, &num_props );
01676 if( props != NULL )
01677 {
01678 for( int i = 0;
01679 i < num_props;
01680 ++i )
01681 if( props[ i ] == atoms->kde_system_tray_embedding )
01682 {
01683 XFree( props );
01684 return false;
01685 }
01686 XFree( props );
01687 }
01688 }
01689 systemTrayWins.remove( w );
01690 propagateSystemTrayWins();
01691 return TRUE;
01692 }
01693
01694
01698 void Workspace::propagateSystemTrayWins()
01699 {
01700 Window *cl = new Window[ systemTrayWins.count()];
01701
01702 int i = 0;
01703 for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it )
01704 {
01705 cl[i++] = (*it).win;
01706 }
01707
01708 rootInfo->setKDESystemTrayWindows( cl, i );
01709 delete [] cl;
01710 }
01711
01712
01713 void Workspace::killWindowId( Window window_to_kill )
01714 {
01715 if( window_to_kill == None )
01716 return;
01717 Window window = window_to_kill;
01718 Client* client = NULL;
01719 for(;;)
01720 {
01721 client = findClient( FrameIdMatchPredicate( window ));
01722 if( client != NULL )
01723 break;
01724 Window parent, root;
01725 Window* children;
01726 unsigned int children_count;
01727 XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
01728 if( children != NULL )
01729 XFree( children );
01730 if( window == root )
01731 break;
01732 window = parent;
01733 }
01734 if( client != NULL )
01735 client->killWindow();
01736 else
01737 XKillClient( qt_xdisplay(), window_to_kill );
01738 }
01739
01740
01741 void Workspace::sendPingToWindow( Window window, Time timestamp )
01742 {
01743 rootInfo->sendPing( window, timestamp );
01744 }
01745
01746 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
01747 {
01748 rootInfo->takeActivity( c->window(), timestamp, flags );
01749 pending_take_activity = c;
01750 }
01751
01752
01756 void Workspace::slotGrabWindow()
01757 {
01758 if ( active_client )
01759 {
01760 QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
01761
01762
01763 if( Shape::available())
01764 {
01765
01766 int count, order;
01767 XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), active_client->frameId(),
01768 ShapeBounding, &count, &order);
01769
01770
01771
01772
01773 if (rects)
01774 {
01775
01776 QRegion contents;
01777 for (int pos = 0; pos < count; pos++)
01778 contents += QRegion(rects[pos].x, rects[pos].y,
01779 rects[pos].width, rects[pos].height);
01780 XFree(rects);
01781
01782
01783 QRegion bbox(0, 0, snapshot.width(), snapshot.height());
01784
01785
01786 QRegion maskedAway = bbox - contents;
01787 QMemArray<QRect> maskedAwayRects = maskedAway.rects();
01788
01789
01790 QBitmap mask( snapshot.width(), snapshot.height());
01791 QPainter p(&mask);
01792 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
01793 for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
01794 p.fillRect(maskedAwayRects[pos], Qt::color0);
01795 p.end();
01796 snapshot.setMask(mask);
01797 }
01798 }
01799
01800 QClipboard *cb = QApplication::clipboard();
01801 cb->setPixmap( snapshot );
01802 }
01803 else
01804 slotGrabDesktop();
01805 }
01806
01810 void Workspace::slotGrabDesktop()
01811 {
01812 QPixmap p = QPixmap::grabWindow( qt_xrootwin() );
01813 QClipboard *cb = QApplication::clipboard();
01814 cb->setPixmap( p );
01815 }
01816
01817
01821 void Workspace::slotMouseEmulation()
01822 {
01823
01824 if ( mouse_emulation )
01825 {
01826 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01827 mouse_emulation = FALSE;
01828 return;
01829 }
01830
01831 if ( XGrabKeyboard(qt_xdisplay(),
01832 root, FALSE,
01833 GrabModeAsync, GrabModeAsync,
01834 qt_x_time) == GrabSuccess )
01835 {
01836 mouse_emulation = TRUE;
01837 mouse_emulation_state = 0;
01838 mouse_emulation_window = 0;
01839 }
01840 }
01841
01848 WId Workspace::getMouseEmulationWindow()
01849 {
01850 Window root;
01851 Window child = qt_xrootwin();
01852 int root_x, root_y, lx, ly;
01853 uint state;
01854 Window w;
01855 Client * c = 0;
01856 do
01857 {
01858 w = child;
01859 if (!c)
01860 c = findClient( FrameIdMatchPredicate( w ));
01861 XQueryPointer( qt_xdisplay(), w, &root, &child,
01862 &root_x, &root_y, &lx, &ly, &state );
01863 } while ( child != None && child != w );
01864
01865 if ( c && !c->isActive() )
01866 activateClient( c );
01867 return (WId) w;
01868 }
01869
01873 unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
01874 {
01875 if ( !w )
01876 return state;
01877 QWidget* widget = QWidget::find( w );
01878 if ( (!widget || widget->inherits("QToolButton") ) && !findClient( WindowMatchPredicate( w )) )
01879 {
01880 int x, y;
01881 Window xw;
01882 XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
01883 if ( type == EmuMove )
01884 {
01885 XEvent e;
01886 e.type = MotionNotify;
01887 e.xmotion.window = w;
01888 e.xmotion.root = qt_xrootwin();
01889 e.xmotion.subwindow = w;
01890 e.xmotion.time = qt_x_time;
01891 e.xmotion.x = x;
01892 e.xmotion.y = y;
01893 e.xmotion.x_root = pos.x();
01894 e.xmotion.y_root = pos.y();
01895 e.xmotion.state = state;
01896 e.xmotion.is_hint = NotifyNormal;
01897 XSendEvent( qt_xdisplay(), w, TRUE, ButtonMotionMask, &e );
01898 }
01899 else
01900 {
01901 XEvent e;
01902 e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
01903 e.xbutton.window = w;
01904 e.xbutton.root = qt_xrootwin();
01905 e.xbutton.subwindow = w;
01906 e.xbutton.time = qt_x_time;
01907 e.xbutton.x = x;
01908 e.xbutton.y = y;
01909 e.xbutton.x_root = pos.x();
01910 e.xbutton.y_root = pos.y();
01911 e.xbutton.state = state;
01912 e.xbutton.button = button;
01913 XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, &e );
01914
01915 if ( type == EmuPress )
01916 {
01917 switch ( button )
01918 {
01919 case 2:
01920 state |= Button2Mask;
01921 break;
01922 case 3:
01923 state |= Button3Mask;
01924 break;
01925 default:
01926 state |= Button1Mask;
01927 break;
01928 }
01929 }
01930 else
01931 {
01932 switch ( button )
01933 {
01934 case 2:
01935 state &= ~Button2Mask;
01936 break;
01937 case 3:
01938 state &= ~Button3Mask;
01939 break;
01940 default:
01941 state &= ~Button1Mask;
01942 break;
01943 }
01944 }
01945 }
01946 }
01947 return state;
01948 }
01949
01953 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
01954 {
01955 if ( root != qt_xrootwin() )
01956 return FALSE;
01957 int kc = XKeycodeToKeysym(qt_xdisplay(), ev.keycode, 0);
01958 int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
01959
01960 bool is_control = km & ControlMask;
01961 bool is_alt = km & Mod1Mask;
01962 bool is_shift = km & ShiftMask;
01963 int delta = is_control?1:is_alt?32:8;
01964 QPoint pos = QCursor::pos();
01965
01966 switch ( kc )
01967 {
01968 case XK_Left:
01969 case XK_KP_Left:
01970 pos.rx() -= delta;
01971 break;
01972 case XK_Right:
01973 case XK_KP_Right:
01974 pos.rx() += delta;
01975 break;
01976 case XK_Up:
01977 case XK_KP_Up:
01978 pos.ry() -= delta;
01979 break;
01980 case XK_Down:
01981 case XK_KP_Down:
01982 pos.ry() += delta;
01983 break;
01984 case XK_F1:
01985 if ( !mouse_emulation_state )
01986 mouse_emulation_window = getMouseEmulationWindow();
01987 if ( (mouse_emulation_state & Button1Mask) == 0 )
01988 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01989 if ( !is_shift )
01990 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01991 break;
01992 case XK_F2:
01993 if ( !mouse_emulation_state )
01994 mouse_emulation_window = getMouseEmulationWindow();
01995 if ( (mouse_emulation_state & Button2Mask) == 0 )
01996 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
01997 if ( !is_shift )
01998 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01999 break;
02000 case XK_F3:
02001 if ( !mouse_emulation_state )
02002 mouse_emulation_window = getMouseEmulationWindow();
02003 if ( (mouse_emulation_state & Button3Mask) == 0 )
02004 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
02005 if ( !is_shift )
02006 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02007 break;
02008 case XK_Return:
02009 case XK_space:
02010 case XK_KP_Enter:
02011 case XK_KP_Space:
02012 {
02013 if ( !mouse_emulation_state )
02014 {
02015
02016 mouse_emulation_window = getMouseEmulationWindow();
02017 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
02018 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02019 }
02020 else
02021 {
02022 if ( mouse_emulation_state & Button1Mask )
02023 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
02024 if ( mouse_emulation_state & Button2Mask )
02025 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
02026 if ( mouse_emulation_state & Button3Mask )
02027 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
02028 }
02029 }
02030
02031 case XK_Escape:
02032 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
02033 mouse_emulation = FALSE;
02034 return TRUE;
02035 default:
02036 return FALSE;
02037 }
02038
02039 QCursor::setPos( pos );
02040 if ( mouse_emulation_state )
02041 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
02042 return TRUE;
02043
02044 }
02045
02051 QWidget* Workspace::desktopWidget()
02052 {
02053 return desktop_widget;
02054 }
02055
02056
02057 void Workspace::delayFocus()
02058 {
02059 requestFocus( delayfocus_client );
02060 cancelDelayFocus();
02061 }
02062
02063 void Workspace::requestDelayFocus( Client* c )
02064 {
02065 delayfocus_client = c;
02066 delete delayFocusTimer;
02067 delayFocusTimer = new QTimer( this );
02068 connect( delayFocusTimer, SIGNAL( timeout() ), this, SLOT( delayFocus() ) );
02069 delayFocusTimer->start( options->delayFocusInterval, TRUE );
02070 }
02071
02072 void Workspace::cancelDelayFocus()
02073 {
02074 delete delayFocusTimer;
02075 delayFocusTimer = 0;
02076 }
02077
02078
02079
02080
02081
02082
02083
02084
02085 void Workspace::checkElectricBorders( bool force )
02086 {
02087 if( force )
02088 destroyBorderWindows();
02089
02090 electric_current_border = 0;
02091
02092 QRect r = QApplication::desktop()->geometry();
02093 electricTop = r.top();
02094 electricBottom = r.bottom();
02095 electricLeft = r.left();
02096 electricRight = r.right();
02097
02098 if (options->electricBorders() == Options::ElectricAlways)
02099 createBorderWindows();
02100 else
02101 destroyBorderWindows();
02102 }
02103
02104 void Workspace::createBorderWindows()
02105 {
02106 if ( electric_have_borders )
02107 return;
02108
02109 electric_have_borders = true;
02110
02111 QRect r = QApplication::desktop()->geometry();
02112 XSetWindowAttributes attributes;
02113 unsigned long valuemask;
02114 attributes.override_redirect = True;
02115 attributes.event_mask = ( EnterWindowMask | LeaveWindowMask );
02116 valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
02117 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02118 XC_sb_up_arrow);
02119 electric_top_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02120 0,0,
02121 r.width(),1,
02122 0,
02123 CopyFromParent, InputOnly,
02124 CopyFromParent,
02125 valuemask, &attributes);
02126 XMapWindow(qt_xdisplay(), electric_top_border);
02127
02128 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02129 XC_sb_down_arrow);
02130 electric_bottom_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02131 0,r.height()-1,
02132 r.width(),1,
02133 0,
02134 CopyFromParent, InputOnly,
02135 CopyFromParent,
02136 valuemask, &attributes);
02137 XMapWindow(qt_xdisplay(), electric_bottom_border);
02138
02139 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02140 XC_sb_left_arrow);
02141 electric_left_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02142 0,0,
02143 1,r.height(),
02144 0,
02145 CopyFromParent, InputOnly,
02146 CopyFromParent,
02147 valuemask, &attributes);
02148 XMapWindow(qt_xdisplay(), electric_left_border);
02149
02150 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02151 XC_sb_right_arrow);
02152 electric_right_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02153 r.width()-1,0,
02154 1,r.height(),
02155 0,
02156 CopyFromParent, InputOnly,
02157 CopyFromParent,
02158 valuemask, &attributes);
02159 XMapWindow(qt_xdisplay(), electric_right_border);
02160
02161 Atom version = 4;
02162 XChangeProperty( qt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
02163 32, PropModeReplace, ( unsigned char* )&version, 1 );
02164 XChangeProperty( qt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
02165 32, PropModeReplace, ( unsigned char* )&version, 1 );
02166 XChangeProperty( qt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
02167 32, PropModeReplace, ( unsigned char* )&version, 1 );
02168 XChangeProperty( qt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
02169 32, PropModeReplace, ( unsigned char* )&version, 1 );
02170 }
02171
02172
02173
02174
02175
02176
02177
02178 void Workspace::destroyBorderWindows()
02179 {
02180 if( !electric_have_borders)
02181 return;
02182
02183 electric_have_borders = false;
02184
02185 if(electric_top_border)
02186 XDestroyWindow(qt_xdisplay(),electric_top_border);
02187 if(electric_bottom_border)
02188 XDestroyWindow(qt_xdisplay(),electric_bottom_border);
02189 if(electric_left_border)
02190 XDestroyWindow(qt_xdisplay(),electric_left_border);
02191 if(electric_right_border)
02192 XDestroyWindow(qt_xdisplay(),electric_right_border);
02193
02194 electric_top_border = None;
02195 electric_bottom_border = None;
02196 electric_left_border = None;
02197 electric_right_border = None;
02198 }
02199
02200 void Workspace::clientMoved(const QPoint &pos, Time now)
02201 {
02202 if (options->electricBorders() == Options::ElectricDisabled)
02203 return;
02204
02205 if ((pos.x() != electricLeft) &&
02206 (pos.x() != electricRight) &&
02207 (pos.y() != electricTop) &&
02208 (pos.y() != electricBottom))
02209 return;
02210
02211 Time treshold_set = options->electricBorderDelay();
02212 Time treshold_reset = 250;
02213 int distance_reset = 30;
02214
02215 int border = 0;
02216 if (pos.x() == electricLeft)
02217 border = 1;
02218 else if (pos.x() == electricRight)
02219 border = 2;
02220 else if (pos.y() == electricTop)
02221 border = 3;
02222 else if (pos.y() == electricBottom)
02223 border = 4;
02224
02225 if ((electric_current_border == border) &&
02226 (timestampDiff(electric_time_last, now) < treshold_reset) &&
02227 ((pos-electric_push_point).manhattanLength() < distance_reset))
02228 {
02229 electric_time_last = now;
02230
02231 if (timestampDiff(electric_time_first, now) > treshold_set)
02232 {
02233 electric_current_border = 0;
02234
02235 QRect r = QApplication::desktop()->geometry();
02236 int offset;
02237
02238 int desk_before = currentDesktop();
02239 switch(border)
02240 {
02241 case 1:
02242 slotSwitchDesktopLeft();
02243 if (currentDesktop() != desk_before)
02244 {
02245 offset = r.width() / 5;
02246 QCursor::setPos(r.width() - offset, pos.y());
02247 }
02248 break;
02249
02250 case 2:
02251 slotSwitchDesktopRight();
02252 if (currentDesktop() != desk_before)
02253 {
02254 offset = r.width() / 5;
02255 QCursor::setPos(offset, pos.y());
02256 }
02257 break;
02258
02259 case 3:
02260 slotSwitchDesktopUp();
02261 if (currentDesktop() != desk_before)
02262 {
02263 offset = r.height() / 5;
02264 QCursor::setPos(pos.x(), r.height() - offset);
02265 }
02266 break;
02267
02268 case 4:
02269 slotSwitchDesktopDown();
02270 if (currentDesktop() != desk_before)
02271 {
02272 offset = r.height() / 5;
02273 QCursor::setPos(pos.x(), offset);
02274 }
02275 break;
02276 }
02277 return;
02278 }
02279 }
02280 else
02281 {
02282 electric_current_border = border;
02283 electric_time_first = now;
02284 electric_time_last = now;
02285 electric_push_point = pos;
02286 }
02287
02288 int mouse_warp = 1;
02289
02290
02291 switch( border)
02292 {
02293 case 1: QCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
02294 case 2: QCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
02295 case 3: QCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
02296 case 4: QCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
02297 }
02298 }
02299
02300
02301
02302 bool Workspace::electricBorder(XEvent *e)
02303 {
02304 if( !electric_have_borders )
02305 return false;
02306 if( e->type == EnterNotify )
02307 {
02308 if( e->xcrossing.window == electric_top_border ||
02309 e->xcrossing.window == electric_left_border ||
02310 e->xcrossing.window == electric_bottom_border ||
02311 e->xcrossing.window == electric_right_border)
02312
02313 {
02314 clientMoved( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
02315 return true;
02316 }
02317 }
02318 if( e->type == ClientMessage )
02319 {
02320 if( e->xclient.message_type == atoms->xdnd_position
02321 && ( e->xclient.window == electric_top_border
02322 || e->xclient.window == electric_bottom_border
02323 || e->xclient.window == electric_left_border
02324 || e->xclient.window == electric_right_border ))
02325 {
02326 updateXTime();
02327 clientMoved( QPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), qt_x_time );
02328 return true;
02329 }
02330 }
02331 return false;
02332 }
02333
02334
02335
02336
02337 void Workspace::raiseElectricBorders()
02338 {
02339
02340 if(electric_have_borders)
02341 {
02342 XRaiseWindow(qt_xdisplay(), electric_top_border);
02343 XRaiseWindow(qt_xdisplay(), electric_left_border);
02344 XRaiseWindow(qt_xdisplay(), electric_bottom_border);
02345 XRaiseWindow(qt_xdisplay(), electric_right_border);
02346 }
02347 }
02348
02349 void Workspace::addTopMenu( Client* c )
02350 {
02351 assert( c->isTopMenu());
02352 assert( !topmenus.contains( c ));
02353 topmenus.append( c );
02354 if( managingTopMenus())
02355 {
02356 int minsize = c->minSize().height();
02357 if( minsize > topMenuHeight())
02358 {
02359 topmenu_height = minsize;
02360 updateTopMenuGeometry();
02361 }
02362 updateTopMenuGeometry( c );
02363 updateCurrentTopMenu();
02364 }
02365
02366 }
02367
02368 void Workspace::removeTopMenu( Client* c )
02369 {
02370
02371
02372 assert( c->isTopMenu());
02373 assert( topmenus.contains( c ));
02374 topmenus.remove( c );
02375 updateCurrentTopMenu();
02376
02377 }
02378
02379 void Workspace::lostTopMenuSelection()
02380 {
02381
02382
02383 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02384 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02385 if( !managing_topmenus )
02386 return;
02387 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02388 disconnect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02389 managing_topmenus = false;
02390 delete topmenu_space;
02391 topmenu_space = NULL;
02392 updateClientArea();
02393 for( ClientList::ConstIterator it = topmenus.begin();
02394 it != topmenus.end();
02395 ++it )
02396 (*it)->checkWorkspacePosition();
02397 }
02398
02399 void Workspace::lostTopMenuOwner()
02400 {
02401 if( !options->topMenuEnabled())
02402 return;
02403
02404 if( !topmenu_selection->claim( false ))
02405 {
02406
02407 return;
02408 }
02409
02410 setupTopMenuHandling();
02411 }
02412
02413 void Workspace::setupTopMenuHandling()
02414 {
02415 if( managing_topmenus )
02416 return;
02417 connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02418 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02419 managing_topmenus = true;
02420 topmenu_space = new QWidget;
02421 Window stack[ 2 ];
02422 stack[ 0 ] = supportWindow->winId();
02423 stack[ 1 ] = topmenu_space->winId();
02424 XRestackWindows(qt_xdisplay(), stack, 2);
02425 updateTopMenuGeometry();
02426 topmenu_space->show();
02427 updateClientArea();
02428 updateCurrentTopMenu();
02429 }
02430
02431 int Workspace::topMenuHeight() const
02432 {
02433 if( topmenu_height == 0 )
02434 {
02435 KMenuBar tmpmenu;
02436 tmpmenu.insertItem( "dummy" );
02437 topmenu_height = tmpmenu.sizeHint().height();
02438 }
02439 return topmenu_height;
02440 }
02441
02442 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
02443 {
02444 return mgr->createDecoration( bridge );
02445 }
02446
02447 QString Workspace::desktopName( int desk ) const
02448 {
02449 return QString::fromUtf8( rootInfo->desktopName( desk ) );
02450 }
02451
02452 bool Workspace::checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data )
02453 {
02454 return startup->checkStartup( w, id, data ) == KStartupInfo::Match;
02455 }
02456
02461 void Workspace::focusToNull()
02462 {
02463 XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, qt_x_time );
02464 }
02465
02466 void Workspace::helperDialog( const QString& message, const Client* c )
02467 {
02468 QStringList args;
02469 QString type;
02470 if( message == "noborderaltf3" )
02471 {
02472 QString shortcut = QString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02473 .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02474 args << "--msgbox" <<
02475 i18n( "You have selected to show a window without its border.\n"
02476 "Without the border, you will not be able to enable the border "
02477 "again using the mouse: use the window operations menu instead, "
02478 "activated using the %1 keyboard shortcut." )
02479 .arg( shortcut );
02480 type = "altf3warning";
02481 }
02482 else if( message == "fullscreenaltf3" )
02483 {
02484 QString shortcut = QString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02485 .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02486 args << "--msgbox" <<
02487 i18n( "You have selected to show a window in fullscreen mode.\n"
02488 "If the application itself does not have an option to turn the fullscreen "
02489 "mode off you will not be able to disable it "
02490 "again using the mouse: use the window operations menu instead, "
02491 "activated using the %1 keyboard shortcut." )
02492 .arg( shortcut );
02493 type = "altf3warning";
02494 }
02495 else
02496 assert( false );
02497 KProcess proc;
02498 proc << "kdialog" << args;
02499 if( !type.isEmpty())
02500 {
02501 KConfig cfg( "kwin_dialogsrc" );
02502 cfg.setGroup( "Notification Messages" );
02503 if( !cfg.readBoolEntry( type, true ))
02504 return;
02505 proc << "--dontagain" << "kwin_dialogsrc:" + type;
02506 }
02507 if( c != NULL )
02508 proc << "--embed" << QString::number( c->window());
02509 proc.start( KProcess::DontCare );
02510 }
02511
02512
02513
02514
02515 void Workspace::startKompmgr()
02516 {
02517 if (!kompmgr || kompmgr->isRunning())
02518 return;
02519 if (!kompmgr->start(KProcess::OwnGroup, KProcess::Stderr))
02520 {
02521 options->useTranslucency = FALSE;
02522 KProcess proc;
02523 proc << "kdialog" << "--error"
02524 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02525 << "--title" << "Composite Manager Failure";
02526 proc.start(KProcess::DontCare);
02527 }
02528 else
02529 {
02530 delete kompmgr_selection;
02531 char selection_name[ 100 ];
02532 sprintf( selection_name, "_NET_WM_CM_S%d", DefaultScreen( qt_xdisplay()));
02533 kompmgr_selection = new KSelectionOwner( selection_name );
02534 connect( kompmgr_selection, SIGNAL( lostOwnership()), SLOT( stopKompmgr()));
02535 kompmgr_selection->claim( true );
02536 connect(kompmgr, SIGNAL(processExited(KProcess*)), SLOT(restartKompmgr()));
02537 options->useTranslucency = TRUE;
02538 allowKompmgrRestart = FALSE;
02539 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02540 QByteArray ba;
02541 QDataStream arg(ba, IO_WriteOnly);
02542 arg << "";
02543 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStarted()", ba);
02544 }
02545 if (popup){ delete popup; popup = 0L; }
02546 }
02547
02548 void Workspace::stopKompmgr()
02549 {
02550 if (!kompmgr || !kompmgr->isRunning())
02551 return;
02552 delete kompmgr_selection;
02553 kompmgr_selection = NULL;
02554 kompmgr->disconnect(this, SLOT(restartKompmgr()));
02555 options->useTranslucency = FALSE;
02556 if (popup){ delete popup; popup = 0L; }
02557 kompmgr->kill();
02558 QByteArray ba;
02559 QDataStream arg(ba, IO_WriteOnly);
02560 arg << "";
02561 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStopped()", ba);
02562 }
02563
02564 bool Workspace::kompmgrIsRunning()
02565 {
02566 return kompmgr && kompmgr->isRunning();
02567 }
02568
02569 void Workspace::unblockKompmgrRestart()
02570 {
02571 allowKompmgrRestart = TRUE;
02572 }
02573
02574 void Workspace::restartKompmgr()
02575
02576 {
02577 if (!allowKompmgrRestart)
02578 {
02579 delete kompmgr_selection;
02580 kompmgr_selection = NULL;
02581 options->useTranslucency = FALSE;
02582 KProcess proc;
02583 proc << "kdialog" << "--error"
02584 << i18n( "The Composite Manager crashed twice within a minute and is therefore disabled for this session.")
02585 << "--title" << i18n("Composite Manager Failure");
02586 proc.start(KProcess::DontCare);
02587 return;
02588 }
02589 if (!kompmgr)
02590 return;
02591
02592
02593
02594
02595
02596
02597
02598
02599 if (!kompmgr->start(KProcess::NotifyOnExit, KProcess::Stderr))
02600 {
02601 delete kompmgr_selection;
02602 kompmgr_selection = NULL;
02603 options->useTranslucency = FALSE;
02604 KProcess proc;
02605 proc << "kdialog" << "--error"
02606 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02607 << "--title" << i18n("Composite Manager Failure");
02608 proc.start(KProcess::DontCare);
02609 }
02610 else
02611 {
02612 allowKompmgrRestart = FALSE;
02613 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02614 }
02615 }
02616
02617 void Workspace::handleKompmgrOutput( KProcess* , char *buffer, int buflen)
02618 {
02619 QString message;
02620 QString output = QString::fromLocal8Bit( buffer, buflen );
02621 if (output.contains("Started",false))
02622 ;
02623 else if (output.contains("Can't open display",false))
02624 message = i18n("<qt><b>kompmgr failed to open the display</b><br>There is probably an invalid display entry in your ~/.xcompmgrrc.</qt>");
02625 else if (output.contains("No render extension",false))
02626 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>");
02627 else if (output.contains("No composite extension",false))
02628 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>"
02629 "<i>Section \"Extensions\"<br>"
02630 "Option \"Composite\" \"Enable\"<br>"
02631 "EndSection</i></qt>");
02632 else if (output.contains("No damage extension",false))
02633 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>");
02634 else if (output.contains("No XFixes extension",false))
02635 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>");
02636 else return;
02637
02638 kompmgr->closeStderr();
02639 disconnect(kompmgr, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(handleKompmgrOutput(KProcess*, char*, int)));
02640 if( !message.isEmpty())
02641 {
02642 KProcess proc;
02643 proc << "kdialog" << "--error"
02644 << message
02645 << "--title" << i18n("Composite Manager Failure");
02646 proc.start(KProcess::DontCare);
02647 }
02648 }
02649
02650
02651 void Workspace::setOpacity(unsigned long winId, unsigned int opacityPercent)
02652 {
02653 if (opacityPercent > 100) opacityPercent = 100;
02654 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02655 if (winId == (*it)->window())
02656 {
02657 (*it)->setOpacity(opacityPercent < 100, (unsigned int)((opacityPercent/100.0)*0xFFFFFFFF));
02658 return;
02659 }
02660 }
02661
02662 void Workspace::setShadowSize(unsigned long winId, unsigned int shadowSizePercent)
02663 {
02664
02665 if (shadowSizePercent > 400) shadowSizePercent = 400;
02666 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02667 if (winId == (*it)->window())
02668 {
02669 (*it)->setShadowSize(shadowSizePercent);
02670 return;
02671 }
02672 }
02673
02674 void Workspace::setUnshadowed(unsigned long winId)
02675 {
02676 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02677 if (winId == (*it)->window())
02678 {
02679 (*it)->setShadowSize(0);
02680 return;
02681 }
02682 }
02683
02684 void Workspace::setShowingDesktop( bool showing )
02685 {
02686 rootInfo->setShowingDesktop( showing );
02687 showing_desktop = showing;
02688 ++block_showing_desktop;
02689 if( showing_desktop )
02690 {
02691 showing_desktop_clients.clear();
02692 ++block_focus;
02693 ClientList cls = stackingOrder();
02694
02695
02696 for( ClientList::ConstIterator it = cls.begin();
02697 it != cls.end();
02698 ++it )
02699 {
02700 if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
02701 showing_desktop_clients.prepend( *it );
02702 }
02703 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02704 it != showing_desktop_clients.end();
02705 ++it )
02706 (*it)->minimize(true);
02707 --block_focus;
02708 if( Client* desk = findDesktop( true, currentDesktop()))
02709 requestFocus( desk );
02710 }
02711 else
02712 {
02713 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02714 it != showing_desktop_clients.end();
02715 ++it )
02716 (*it)->unminimize(true);
02717 if( showing_desktop_clients.count() > 0 )
02718 requestFocus( showing_desktop_clients.first());
02719 showing_desktop_clients.clear();
02720 }
02721 --block_showing_desktop;
02722 }
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733 void Workspace::resetShowingDesktop( bool keep_hidden )
02734 {
02735 if( block_showing_desktop > 0 )
02736 return;
02737 rootInfo->setShowingDesktop( false );
02738 showing_desktop = false;
02739 ++block_showing_desktop;
02740 if( !keep_hidden )
02741 {
02742 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02743 it != showing_desktop_clients.end();
02744 ++it )
02745 (*it)->unminimize(true);
02746 }
02747 showing_desktop_clients.clear();
02748 --block_showing_desktop;
02749 }
02750
02751
02752
02753
02754
02755
02756
02757
02758 void Workspace::slotDisableGlobalShortcuts()
02759 {
02760 if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
02761 disableGlobalShortcuts( false );
02762 else
02763 disableGlobalShortcuts( true );
02764 }
02765
02766 static bool pending_dfc = false;
02767
02768 void Workspace::disableGlobalShortcutsForClient( bool disable )
02769 {
02770 if( global_shortcuts_disabled_for_client == disable )
02771 return;
02772 if( !global_shortcuts_disabled )
02773 {
02774 if( disable )
02775 pending_dfc = true;
02776 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02777
02778 }
02779 }
02780
02781 void Workspace::disableGlobalShortcuts( bool disable )
02782 {
02783 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02784
02785 }
02786
02787 void Workspace::kipcMessage( int id, int data )
02788 {
02789 if( id != KIPC::BlockShortcuts )
02790 return;
02791 if( pending_dfc && data )
02792 {
02793 global_shortcuts_disabled_for_client = true;
02794 pending_dfc = false;
02795 }
02796 else
02797 {
02798 global_shortcuts_disabled = data;
02799 global_shortcuts_disabled_for_client = false;
02800 }
02801
02802 for( ClientList::ConstIterator it = clients.begin();
02803 it != clients.end();
02804 ++it )
02805 (*it)->updateMouseGrab();
02806 }
02807
02808 }
02809
02810 #include "workspace.moc"