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