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