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 rules_updates_disabled( false ),
00079 active_client (0),
00080 last_active_client (0),
00081 most_recently_raised (0),
00082 movingClient(0),
00083 pending_take_activity ( NULL ),
00084 delayfocus_client (0),
00085 showing_desktop( false ),
00086 block_showing_desktop( 0 ),
00087 was_user_interaction (false),
00088 session_saving (false),
00089 control_grab (false),
00090 tab_grab (false),
00091 mouse_emulation (false),
00092 block_focus (0),
00093 tab_box (0),
00094 popupinfo (0),
00095 popup (0),
00096 advanced_popup (0),
00097 desk_popup (0),
00098 desk_popup_index (0),
00099 keys (0),
00100 client_keys ( NULL ),
00101 client_keys_dialog ( NULL ),
00102 client_keys_client ( NULL ),
00103 disable_shortcuts_keys ( NULL ),
00104 global_shortcuts_disabled( false ),
00105 global_shortcuts_disabled_for_client( false ),
00106 root (0),
00107 workspaceInit (true),
00108 startup(0), electric_have_borders(false),
00109 electric_current_border(0),
00110 electric_top_border(None),
00111 electric_bottom_border(None),
00112 electric_left_border(None),
00113 electric_right_border(None),
00114 layoutOrientation(Qt::Vertical),
00115 layoutX(-1),
00116 layoutY(2),
00117 workarea(NULL),
00118 screenarea(NULL),
00119 managing_topmenus( false ),
00120 topmenu_selection( NULL ),
00121 topmenu_watcher( NULL ),
00122 topmenu_height( 0 ),
00123 topmenu_space( NULL ),
00124 set_active_client_recursion( 0 ),
00125 block_stacking_updates( 0 ),
00126 forced_global_mouse_grab( false )
00127 {
00128 _self = this;
00129 mgr = new PluginMgr;
00130 root = qt_xrootwin();
00131 default_colormap = DefaultColormap(qt_xdisplay(), qt_xscreen() );
00132 installed_colormap = default_colormap;
00133 session.setAutoDelete( TRUE );
00134
00135 connect( &temporaryRulesMessages, SIGNAL( gotMessage( const QString& )),
00136 this, SLOT( gotTemporaryRulesMessage( const QString& )));
00137 connect( &rulesUpdatedTimer, SIGNAL( timeout()), this, SLOT( writeWindowRules()));
00138
00139 updateXTime();
00140
00141 delayFocusTimer = 0;
00142
00143 electric_time_first = qt_x_time;
00144 electric_time_last = qt_x_time;
00145
00146 if ( restore )
00147 loadSessionInfo();
00148
00149 loadWindowRules();
00150
00151 (void) QApplication::desktop();
00152
00153 desktop_widget =
00154 new QWidget(
00155 0,
00156 "desktop_widget",
00157 Qt::WType_Desktop | Qt::WPaintUnclipped
00158 );
00159
00160 kapp->setGlobalMouseTracking( true );
00161
00162 startup = new KStartupInfo(
00163 KStartupInfo::DisableKWinModule | KStartupInfo::AnnounceSilenceChanges, this );
00164
00165
00166 XSelectInput(qt_xdisplay(), root,
00167 KeyPressMask |
00168 PropertyChangeMask |
00169 ColormapChangeMask |
00170 SubstructureRedirectMask |
00171 SubstructureNotifyMask |
00172 FocusChangeMask
00173 );
00174
00175 Shape::init();
00176
00177
00178 long data = 1;
00179
00180 XChangeProperty(
00181 qt_xdisplay(),
00182 qt_xrootwin(),
00183 atoms->kwin_running,
00184 atoms->kwin_running,
00185 32,
00186 PropModeAppend,
00187 (unsigned char*) &data,
00188 1
00189 );
00190
00191 client_keys = new KGlobalAccel( this );
00192 initShortcuts();
00193 tab_box = new TabBox( this );
00194 popupinfo = new PopupInfo( );
00195
00196 init();
00197
00198 #if (QT_VERSION-0 >= 0x030200) // XRANDR support
00199 connect( kapp->desktop(), SIGNAL( resized( int )), SLOT( desktopResized()));
00200 #endif
00201
00202
00203 if (options->useTranslucency)
00204 {
00205 kompmgr = new KProcess;
00206 connect(kompmgr, SIGNAL(receivedStderr(KProcess*, char*, int)), SLOT(handleKompmgrOutput(KProcess*, char*, int)));
00207 *kompmgr << "kompmgr";
00208 startKompmgr();
00209 }
00210 }
00211
00212
00213 void Workspace::init()
00214 {
00215 checkElectricBorders();
00216
00217
00218
00219
00220
00221 supportWindow = new QWidget;
00222 XLowerWindow( qt_xdisplay(), supportWindow->winId());
00223
00224 XSetWindowAttributes attr;
00225 attr.override_redirect = 1;
00226 null_focus_window = XCreateWindow( qt_xdisplay(), qt_xrootwin(), -1,-1, 1, 1, 0, CopyFromParent,
00227 InputOnly, CopyFromParent, CWOverrideRedirect, &attr );
00228 XMapWindow(qt_xdisplay(), null_focus_window);
00229
00230 unsigned long protocols[ 5 ] =
00231 {
00232 NET::Supported |
00233 NET::SupportingWMCheck |
00234 NET::ClientList |
00235 NET::ClientListStacking |
00236 NET::DesktopGeometry |
00237 NET::NumberOfDesktops |
00238 NET::CurrentDesktop |
00239 NET::ActiveWindow |
00240 NET::WorkArea |
00241 NET::CloseWindow |
00242 NET::DesktopNames |
00243 NET::KDESystemTrayWindows |
00244 NET::WMName |
00245 NET::WMVisibleName |
00246 NET::WMDesktop |
00247 NET::WMWindowType |
00248 NET::WMState |
00249 NET::WMStrut |
00250 NET::WMIconGeometry |
00251 NET::WMIcon |
00252 NET::WMPid |
00253 NET::WMMoveResize |
00254 NET::WMKDESystemTrayWinFor |
00255 NET::WMFrameExtents |
00256 NET::WMPing
00257 ,
00258 NET::NormalMask |
00259 NET::DesktopMask |
00260 NET::DockMask |
00261 NET::ToolbarMask |
00262 NET::MenuMask |
00263 NET::DialogMask |
00264 NET::OverrideMask |
00265 NET::TopMenuMask |
00266 NET::UtilityMask |
00267 NET::SplashMask |
00268 0
00269 ,
00270 NET::Modal |
00271
00272 NET::MaxVert |
00273 NET::MaxHoriz |
00274 NET::Shaded |
00275 NET::SkipTaskbar |
00276 NET::KeepAbove |
00277
00278 NET::SkipPager |
00279 NET::Hidden |
00280 NET::FullScreen |
00281 NET::KeepBelow |
00282 NET::DemandsAttention |
00283 0
00284 ,
00285 NET::WM2UserTime |
00286 NET::WM2StartupId |
00287 NET::WM2AllowedActions |
00288 NET::WM2RestackWindow |
00289 NET::WM2MoveResizeWindow |
00290 NET::WM2ExtendedStrut |
00291 NET::WM2KDETemporaryRules |
00292 NET::WM2ShowingDesktop |
00293 NET::WM2DesktopLayout |
00294 0
00295 ,
00296 NET::ActionMove |
00297 NET::ActionResize |
00298 NET::ActionMinimize |
00299 NET::ActionShade |
00300
00301 NET::ActionMaxVert |
00302 NET::ActionMaxHoriz |
00303 NET::ActionFullScreen |
00304 NET::ActionChangeDesktop |
00305 NET::ActionClose |
00306 0
00307 ,
00308 };
00309
00310 rootInfo = new RootInfo( this, qt_xdisplay(), supportWindow->winId(), "KWin",
00311 protocols, 5, qt_xscreen() );
00312
00313 loadDesktopSettings();
00314 updateDesktopLayout();
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 // This actually seems to make things worse now
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 void Workspace::setDesktopLayout( int, int, int )
01527 {
01528 }
01529
01530 void Workspace::updateDesktopLayout()
01531 {
01532
01533 layoutOrientation = ( rootInfo->desktopLayoutOrientation() == NET::OrientationHorizontal
01534 ? Qt::Horizontal : Qt::Vertical );
01535 layoutX = rootInfo->desktopLayoutColumnsRows().width();
01536 layoutY = rootInfo->desktopLayoutColumnsRows().height();
01537 if( layoutX == 0 && layoutY == 0 )
01538 layoutY = 2;
01539 }
01540
01541 void Workspace::calcDesktopLayout(int &x, int &y) const
01542 {
01543 x = layoutX;
01544 y = layoutY;
01545 if((x <= 0) && (y > 0))
01546 x = (numberOfDesktops()+y-1) / y;
01547 else if((y <=0) && (x > 0))
01548 y = (numberOfDesktops()+x-1) / x;
01549
01550 if(x <=0)
01551 x = 1;
01552 if (y <= 0)
01553 y = 1;
01554 }
01555
01560 bool Workspace::addSystemTrayWin( WId w )
01561 {
01562 if ( systemTrayWins.contains( w ) )
01563 return TRUE;
01564
01565 NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
01566 WId trayWinFor = ni.kdeSystemTrayWinFor();
01567 if ( !trayWinFor )
01568 return FALSE;
01569 systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
01570 XSelectInput( qt_xdisplay(), w,
01571 StructureNotifyMask
01572 );
01573 XAddToSaveSet( qt_xdisplay(), w );
01574 propagateSystemTrayWins();
01575 return TRUE;
01576 }
01577
01582 bool Workspace::removeSystemTrayWin( WId w, bool check )
01583 {
01584 if ( !systemTrayWins.contains( w ) )
01585 return FALSE;
01586 if( check )
01587 {
01588
01589
01590
01591
01592
01593
01594
01595 int num_props;
01596 Atom* props = XListProperties( qt_xdisplay(), w, &num_props );
01597 if( props != NULL )
01598 {
01599 for( int i = 0;
01600 i < num_props;
01601 ++i )
01602 if( props[ i ] == atoms->kde_system_tray_embedding )
01603 {
01604 XFree( props );
01605 return false;
01606 }
01607 XFree( props );
01608 }
01609 }
01610 systemTrayWins.remove( w );
01611 propagateSystemTrayWins();
01612 return TRUE;
01613 }
01614
01615
01619 void Workspace::propagateSystemTrayWins()
01620 {
01621 Window *cl = new Window[ systemTrayWins.count()];
01622
01623 int i = 0;
01624 for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it )
01625 {
01626 cl[i++] = (*it).win;
01627 }
01628
01629 rootInfo->setKDESystemTrayWindows( cl, i );
01630 delete [] cl;
01631 }
01632
01633
01634 void Workspace::killWindowId( Window window_to_kill )
01635 {
01636 if( window_to_kill == None )
01637 return;
01638 Window window = window_to_kill;
01639 Client* client = NULL;
01640 for(;;)
01641 {
01642 client = findClient( FrameIdMatchPredicate( window ));
01643 if( client != NULL )
01644 break;
01645 Window parent, root;
01646 Window* children;
01647 unsigned int children_count;
01648 XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
01649 if( children != NULL )
01650 XFree( children );
01651 if( window == root )
01652 break;
01653 window = parent;
01654 }
01655 if( client != NULL )
01656 client->killWindow();
01657 else
01658 XKillClient( qt_xdisplay(), window_to_kill );
01659 }
01660
01661
01662 void Workspace::sendPingToWindow( Window window, Time timestamp )
01663 {
01664 rootInfo->sendPing( window, timestamp );
01665 }
01666
01667 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
01668 {
01669 rootInfo->takeActivity( c->window(), timestamp, flags );
01670 pending_take_activity = c;
01671 }
01672
01673
01677 void Workspace::slotGrabWindow()
01678 {
01679 if ( active_client )
01680 {
01681 QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
01682
01683
01684 if( Shape::available())
01685 {
01686
01687 int count, order;
01688 XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), active_client->frameId(),
01689 ShapeBounding, &count, &order);
01690
01691
01692
01693
01694 if (rects)
01695 {
01696
01697 QRegion contents;
01698 for (int pos = 0; pos < count; pos++)
01699 contents += QRegion(rects[pos].x, rects[pos].y,
01700 rects[pos].width, rects[pos].height);
01701 XFree(rects);
01702
01703
01704 QRegion bbox(0, 0, snapshot.width(), snapshot.height());
01705
01706
01707 QRegion maskedAway = bbox - contents;
01708 QMemArray<QRect> maskedAwayRects = maskedAway.rects();
01709
01710
01711 QBitmap mask( snapshot.width(), snapshot.height());
01712 QPainter p(&mask);
01713 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
01714 for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
01715 p.fillRect(maskedAwayRects[pos], Qt::color0);
01716 p.end();
01717 snapshot.setMask(mask);
01718 }
01719 }
01720
01721 QClipboard *cb = QApplication::clipboard();
01722 cb->setPixmap( snapshot );
01723 }
01724 else
01725 slotGrabDesktop();
01726 }
01727
01731 void Workspace::slotGrabDesktop()
01732 {
01733 QPixmap p = QPixmap::grabWindow( qt_xrootwin() );
01734 QClipboard *cb = QApplication::clipboard();
01735 cb->setPixmap( p );
01736 }
01737
01738
01742 void Workspace::slotMouseEmulation()
01743 {
01744
01745 if ( mouse_emulation )
01746 {
01747 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01748 mouse_emulation = FALSE;
01749 return;
01750 }
01751
01752 if ( XGrabKeyboard(qt_xdisplay(),
01753 root, FALSE,
01754 GrabModeAsync, GrabModeAsync,
01755 qt_x_time) == GrabSuccess )
01756 {
01757 mouse_emulation = TRUE;
01758 mouse_emulation_state = 0;
01759 mouse_emulation_window = 0;
01760 }
01761 }
01762
01769 WId Workspace::getMouseEmulationWindow()
01770 {
01771 Window root;
01772 Window child = qt_xrootwin();
01773 int root_x, root_y, lx, ly;
01774 uint state;
01775 Window w;
01776 Client * c = 0;
01777 do
01778 {
01779 w = child;
01780 if (!c)
01781 c = findClient( FrameIdMatchPredicate( w ));
01782 XQueryPointer( qt_xdisplay(), w, &root, &child,
01783 &root_x, &root_y, &lx, &ly, &state );
01784 } while ( child != None && child != w );
01785
01786 if ( c && !c->isActive() )
01787 activateClient( c );
01788 return (WId) w;
01789 }
01790
01794 unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
01795 {
01796 if ( !w )
01797 return state;
01798 QWidget* widget = QWidget::find( w );
01799 if ( (!widget || widget->inherits("QToolButton") ) && !findClient( WindowMatchPredicate( w )) )
01800 {
01801 int x, y;
01802 Window xw;
01803 XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
01804 if ( type == EmuMove )
01805 {
01806 XEvent e;
01807 e.type = MotionNotify;
01808 e.xmotion.window = w;
01809 e.xmotion.root = qt_xrootwin();
01810 e.xmotion.subwindow = w;
01811 e.xmotion.time = qt_x_time;
01812 e.xmotion.x = x;
01813 e.xmotion.y = y;
01814 e.xmotion.x_root = pos.x();
01815 e.xmotion.y_root = pos.y();
01816 e.xmotion.state = state;
01817 e.xmotion.is_hint = NotifyNormal;
01818 XSendEvent( qt_xdisplay(), w, TRUE, ButtonMotionMask, &e );
01819 }
01820 else
01821 {
01822 XEvent e;
01823 e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
01824 e.xbutton.window = w;
01825 e.xbutton.root = qt_xrootwin();
01826 e.xbutton.subwindow = w;
01827 e.xbutton.time = qt_x_time;
01828 e.xbutton.x = x;
01829 e.xbutton.y = y;
01830 e.xbutton.x_root = pos.x();
01831 e.xbutton.y_root = pos.y();
01832 e.xbutton.state = state;
01833 e.xbutton.button = button;
01834 XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, &e );
01835
01836 if ( type == EmuPress )
01837 {
01838 switch ( button )
01839 {
01840 case 2:
01841 state |= Button2Mask;
01842 break;
01843 case 3:
01844 state |= Button3Mask;
01845 break;
01846 default:
01847 state |= Button1Mask;
01848 break;
01849 }
01850 }
01851 else
01852 {
01853 switch ( button )
01854 {
01855 case 2:
01856 state &= ~Button2Mask;
01857 break;
01858 case 3:
01859 state &= ~Button3Mask;
01860 break;
01861 default:
01862 state &= ~Button1Mask;
01863 break;
01864 }
01865 }
01866 }
01867 }
01868 return state;
01869 }
01870
01874 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
01875 {
01876 if ( root != qt_xrootwin() )
01877 return FALSE;
01878 int kc = XKeycodeToKeysym(qt_xdisplay(), ev.keycode, 0);
01879 int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
01880
01881 bool is_control = km & ControlMask;
01882 bool is_alt = km & Mod1Mask;
01883 bool is_shift = km & ShiftMask;
01884 int delta = is_control?1:is_alt?32:8;
01885 QPoint pos = QCursor::pos();
01886
01887 switch ( kc )
01888 {
01889 case XK_Left:
01890 case XK_KP_Left:
01891 pos.rx() -= delta;
01892 break;
01893 case XK_Right:
01894 case XK_KP_Right:
01895 pos.rx() += delta;
01896 break;
01897 case XK_Up:
01898 case XK_KP_Up:
01899 pos.ry() -= delta;
01900 break;
01901 case XK_Down:
01902 case XK_KP_Down:
01903 pos.ry() += delta;
01904 break;
01905 case XK_F1:
01906 if ( !mouse_emulation_state )
01907 mouse_emulation_window = getMouseEmulationWindow();
01908 if ( (mouse_emulation_state & Button1Mask) == 0 )
01909 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01910 if ( !is_shift )
01911 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01912 break;
01913 case XK_F2:
01914 if ( !mouse_emulation_state )
01915 mouse_emulation_window = getMouseEmulationWindow();
01916 if ( (mouse_emulation_state & Button2Mask) == 0 )
01917 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
01918 if ( !is_shift )
01919 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01920 break;
01921 case XK_F3:
01922 if ( !mouse_emulation_state )
01923 mouse_emulation_window = getMouseEmulationWindow();
01924 if ( (mouse_emulation_state & Button3Mask) == 0 )
01925 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
01926 if ( !is_shift )
01927 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01928 break;
01929 case XK_Return:
01930 case XK_space:
01931 case XK_KP_Enter:
01932 case XK_KP_Space:
01933 {
01934 if ( !mouse_emulation_state )
01935 {
01936
01937 mouse_emulation_window = getMouseEmulationWindow();
01938 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01939 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01940 }
01941 else
01942 {
01943 if ( mouse_emulation_state & Button1Mask )
01944 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01945 if ( mouse_emulation_state & Button2Mask )
01946 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01947 if ( mouse_emulation_state & Button3Mask )
01948 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01949 }
01950 }
01951
01952 case XK_Escape:
01953 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01954 mouse_emulation = FALSE;
01955 return TRUE;
01956 default:
01957 return FALSE;
01958 }
01959
01960 QCursor::setPos( pos );
01961 if ( mouse_emulation_state )
01962 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
01963 return TRUE;
01964
01965 }
01966
01972 QWidget* Workspace::desktopWidget()
01973 {
01974 return desktop_widget;
01975 }
01976
01977
01978 void Workspace::delayFocus()
01979 {
01980 requestFocus( delayfocus_client );
01981 cancelDelayFocus();
01982 }
01983
01984 void Workspace::requestDelayFocus( Client* c )
01985 {
01986 delayfocus_client = c;
01987 delete delayFocusTimer;
01988 delayFocusTimer = new QTimer( this );
01989 connect( delayFocusTimer, SIGNAL( timeout() ), this, SLOT( delayFocus() ) );
01990 delayFocusTimer->start( options->delayFocusInterval, TRUE );
01991 }
01992
01993 void Workspace::cancelDelayFocus()
01994 {
01995 delete delayFocusTimer;
01996 delayFocusTimer = 0;
01997 }
01998
01999
02000
02001
02002
02003
02004
02005
02006 void Workspace::checkElectricBorders( bool force )
02007 {
02008 if( force )
02009 destroyBorderWindows();
02010
02011 electric_current_border = 0;
02012
02013 QRect r = QApplication::desktop()->geometry();
02014 electricTop = r.top();
02015 electricBottom = r.bottom();
02016 electricLeft = r.left();
02017 electricRight = r.right();
02018
02019 if (options->electricBorders() == Options::ElectricAlways)
02020 createBorderWindows();
02021 else
02022 destroyBorderWindows();
02023 }
02024
02025 void Workspace::createBorderWindows()
02026 {
02027 if ( electric_have_borders )
02028 return;
02029
02030 electric_have_borders = true;
02031
02032 QRect r = QApplication::desktop()->geometry();
02033 XSetWindowAttributes attributes;
02034 unsigned long valuemask;
02035 attributes.override_redirect = True;
02036 attributes.event_mask = ( EnterWindowMask | LeaveWindowMask );
02037 valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
02038 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02039 XC_sb_up_arrow);
02040 electric_top_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02041 0,0,
02042 r.width(),1,
02043 0,
02044 CopyFromParent, InputOnly,
02045 CopyFromParent,
02046 valuemask, &attributes);
02047 XMapWindow(qt_xdisplay(), electric_top_border);
02048
02049 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02050 XC_sb_down_arrow);
02051 electric_bottom_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02052 0,r.height()-1,
02053 r.width(),1,
02054 0,
02055 CopyFromParent, InputOnly,
02056 CopyFromParent,
02057 valuemask, &attributes);
02058 XMapWindow(qt_xdisplay(), electric_bottom_border);
02059
02060 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02061 XC_sb_left_arrow);
02062 electric_left_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02063 0,0,
02064 1,r.height(),
02065 0,
02066 CopyFromParent, InputOnly,
02067 CopyFromParent,
02068 valuemask, &attributes);
02069 XMapWindow(qt_xdisplay(), electric_left_border);
02070
02071 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
02072 XC_sb_right_arrow);
02073 electric_right_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
02074 r.width()-1,0,
02075 1,r.height(),
02076 0,
02077 CopyFromParent, InputOnly,
02078 CopyFromParent,
02079 valuemask, &attributes);
02080 XMapWindow(qt_xdisplay(), electric_right_border);
02081
02082 Atom version = 4;
02083 XChangeProperty( qt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
02084 32, PropModeReplace, ( unsigned char* )&version, 1 );
02085 XChangeProperty( qt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
02086 32, PropModeReplace, ( unsigned char* )&version, 1 );
02087 XChangeProperty( qt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
02088 32, PropModeReplace, ( unsigned char* )&version, 1 );
02089 XChangeProperty( qt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
02090 32, PropModeReplace, ( unsigned char* )&version, 1 );
02091 }
02092
02093
02094
02095
02096
02097
02098
02099 void Workspace::destroyBorderWindows()
02100 {
02101 if( !electric_have_borders)
02102 return;
02103
02104 electric_have_borders = false;
02105
02106 if(electric_top_border)
02107 XDestroyWindow(qt_xdisplay(),electric_top_border);
02108 if(electric_bottom_border)
02109 XDestroyWindow(qt_xdisplay(),electric_bottom_border);
02110 if(electric_left_border)
02111 XDestroyWindow(qt_xdisplay(),electric_left_border);
02112 if(electric_right_border)
02113 XDestroyWindow(qt_xdisplay(),electric_right_border);
02114
02115 electric_top_border = None;
02116 electric_bottom_border = None;
02117 electric_left_border = None;
02118 electric_right_border = None;
02119 }
02120
02121 void Workspace::clientMoved(const QPoint &pos, Time now)
02122 {
02123 if (options->electricBorders() == Options::ElectricDisabled)
02124 return;
02125
02126 if ((pos.x() != electricLeft) &&
02127 (pos.x() != electricRight) &&
02128 (pos.y() != electricTop) &&
02129 (pos.y() != electricBottom))
02130 return;
02131
02132 Time treshold_set = options->electricBorderDelay();
02133 Time treshold_reset = 250;
02134 int distance_reset = 30;
02135
02136 int border = 0;
02137 if (pos.x() == electricLeft)
02138 border = 1;
02139 else if (pos.x() == electricRight)
02140 border = 2;
02141 else if (pos.y() == electricTop)
02142 border = 3;
02143 else if (pos.y() == electricBottom)
02144 border = 4;
02145
02146 if ((electric_current_border == border) &&
02147 (timestampDiff(electric_time_last, now) < treshold_reset) &&
02148 ((pos-electric_push_point).manhattanLength() < distance_reset))
02149 {
02150 electric_time_last = now;
02151
02152 if (timestampDiff(electric_time_first, now) > treshold_set)
02153 {
02154 electric_current_border = 0;
02155
02156 QRect r = QApplication::desktop()->geometry();
02157 int offset;
02158
02159 int desk_before = currentDesktop();
02160 switch(border)
02161 {
02162 case 1:
02163 slotSwitchDesktopLeft();
02164 if (currentDesktop() != desk_before)
02165 {
02166 offset = r.width() / 5;
02167 QCursor::setPos(r.width() - offset, pos.y());
02168 }
02169 break;
02170
02171 case 2:
02172 slotSwitchDesktopRight();
02173 if (currentDesktop() != desk_before)
02174 {
02175 offset = r.width() / 5;
02176 QCursor::setPos(offset, pos.y());
02177 }
02178 break;
02179
02180 case 3:
02181 slotSwitchDesktopUp();
02182 if (currentDesktop() != desk_before)
02183 {
02184 offset = r.height() / 5;
02185 QCursor::setPos(pos.x(), r.height() - offset);
02186 }
02187 break;
02188
02189 case 4:
02190 slotSwitchDesktopDown();
02191 if (currentDesktop() != desk_before)
02192 {
02193 offset = r.height() / 5;
02194 QCursor::setPos(pos.x(), offset);
02195 }
02196 break;
02197 }
02198 return;
02199 }
02200 }
02201 else
02202 {
02203 electric_current_border = border;
02204 electric_time_first = now;
02205 electric_time_last = now;
02206 electric_push_point = pos;
02207 }
02208
02209 int mouse_warp = 1;
02210
02211
02212 switch( border)
02213 {
02214 case 1: QCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
02215 case 2: QCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
02216 case 3: QCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
02217 case 4: QCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
02218 }
02219 }
02220
02221
02222
02223 bool Workspace::electricBorder(XEvent *e)
02224 {
02225 if( !electric_have_borders )
02226 return false;
02227 if( e->type == EnterNotify )
02228 {
02229 if( e->xcrossing.window == electric_top_border ||
02230 e->xcrossing.window == electric_left_border ||
02231 e->xcrossing.window == electric_bottom_border ||
02232 e->xcrossing.window == electric_right_border)
02233
02234 {
02235 clientMoved( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
02236 return true;
02237 }
02238 }
02239 if( e->type == ClientMessage )
02240 {
02241 if( e->xclient.message_type == atoms->xdnd_position
02242 && ( e->xclient.window == electric_top_border
02243 || e->xclient.window == electric_bottom_border
02244 || e->xclient.window == electric_left_border
02245 || e->xclient.window == electric_right_border ))
02246 {
02247 updateXTime();
02248 clientMoved( QPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), qt_x_time );
02249 return true;
02250 }
02251 }
02252 return false;
02253 }
02254
02255
02256
02257
02258 void Workspace::raiseElectricBorders()
02259 {
02260
02261 if(electric_have_borders)
02262 {
02263 XRaiseWindow(qt_xdisplay(), electric_top_border);
02264 XRaiseWindow(qt_xdisplay(), electric_left_border);
02265 XRaiseWindow(qt_xdisplay(), electric_bottom_border);
02266 XRaiseWindow(qt_xdisplay(), electric_right_border);
02267 }
02268 }
02269
02270 void Workspace::addTopMenu( Client* c )
02271 {
02272 assert( c->isTopMenu());
02273 assert( !topmenus.contains( c ));
02274 topmenus.append( c );
02275 if( managingTopMenus())
02276 {
02277 int minsize = c->minSize().height();
02278 if( minsize > topMenuHeight())
02279 {
02280 topmenu_height = minsize;
02281 updateTopMenuGeometry();
02282 }
02283 updateTopMenuGeometry( c );
02284 updateCurrentTopMenu();
02285 }
02286
02287 }
02288
02289 void Workspace::removeTopMenu( Client* c )
02290 {
02291
02292
02293 assert( c->isTopMenu());
02294 assert( topmenus.contains( c ));
02295 topmenus.remove( c );
02296 updateCurrentTopMenu();
02297
02298 }
02299
02300 void Workspace::lostTopMenuSelection()
02301 {
02302
02303
02304 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02305 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02306 if( !managing_topmenus )
02307 return;
02308 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02309 disconnect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02310 managing_topmenus = false;
02311 delete topmenu_space;
02312 topmenu_space = NULL;
02313 updateClientArea();
02314 for( ClientList::ConstIterator it = topmenus.begin();
02315 it != topmenus.end();
02316 ++it )
02317 (*it)->checkWorkspacePosition();
02318 }
02319
02320 void Workspace::lostTopMenuOwner()
02321 {
02322 if( !options->topMenuEnabled())
02323 return;
02324
02325 if( !topmenu_selection->claim( false ))
02326 {
02327
02328 return;
02329 }
02330
02331 setupTopMenuHandling();
02332 }
02333
02334 void Workspace::setupTopMenuHandling()
02335 {
02336 if( managing_topmenus )
02337 return;
02338 connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02339 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02340 managing_topmenus = true;
02341 topmenu_space = new QWidget;
02342 Window stack[ 2 ];
02343 stack[ 0 ] = supportWindow->winId();
02344 stack[ 1 ] = topmenu_space->winId();
02345 XRestackWindows(qt_xdisplay(), stack, 2);
02346 updateTopMenuGeometry();
02347 topmenu_space->show();
02348 updateClientArea();
02349 updateCurrentTopMenu();
02350 }
02351
02352 int Workspace::topMenuHeight() const
02353 {
02354 if( topmenu_height == 0 )
02355 {
02356 KMenuBar tmpmenu;
02357 tmpmenu.insertItem( "dummy" );
02358 topmenu_height = tmpmenu.sizeHint().height();
02359 }
02360 return topmenu_height;
02361 }
02362
02363 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
02364 {
02365 return mgr->createDecoration( bridge );
02366 }
02367
02368 QString Workspace::desktopName( int desk ) const
02369 {
02370 return QString::fromUtf8( rootInfo->desktopName( desk ) );
02371 }
02372
02373 bool Workspace::checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data )
02374 {
02375 return startup->checkStartup( w, id, data ) == KStartupInfo::Match;
02376 }
02377
02382 void Workspace::focusToNull()
02383 {
02384 XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, qt_x_time );
02385 }
02386
02387 void Workspace::helperDialog( const QString& message, const Client* c )
02388 {
02389 QStringList args;
02390 QString type;
02391 if( message == "noborderaltf3" )
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 without its border.\n"
02397 "Without the border, you will not be able to enable the border "
02398 "again using the mouse: use the window operations menu instead, "
02399 "activated using the %1 keyboard shortcut." )
02400 .arg( shortcut );
02401 type = "altf3warning";
02402 }
02403 else if( message == "fullscreenaltf3" )
02404 {
02405 QString shortcut = QString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02406 .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02407 args << "--msgbox" <<
02408 i18n( "You have selected to show a window in fullscreen mode.\n"
02409 "If the application itself does not have an option to turn the fullscreen "
02410 "mode off you will not be able to disable it "
02411 "again using the mouse: use the window operations menu instead, "
02412 "activated using the %1 keyboard shortcut." )
02413 .arg( shortcut );
02414 type = "altf3warning";
02415 }
02416 else
02417 assert( false );
02418 KProcess proc;
02419 proc << "kdialog" << args;
02420 if( !type.isEmpty())
02421 {
02422 KConfig cfg( "kwin_dialogsrc" );
02423 cfg.setGroup( "Notification Messages" );
02424 if( !cfg.readBoolEntry( type, true ))
02425 return;
02426 proc << "--dontagain" << "kwin_dialogsrc:" + type;
02427 }
02428 if( c != NULL )
02429 proc << "--embed" << QString::number( c->window());
02430 proc.start( KProcess::DontCare );
02431 }
02432
02433
02434
02435
02436 void Workspace::startKompmgr()
02437 {
02438 if (!kompmgr || kompmgr->isRunning())
02439 return;
02440 if (!kompmgr->start(KProcess::OwnGroup, KProcess::Stderr))
02441 {
02442 options->useTranslucency = FALSE;
02443 KProcess proc;
02444 proc << "kdialog" << "--error"
02445 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02446 << "--title" << "Composite Manager Failure";
02447 proc.start(KProcess::DontCare);
02448 }
02449 else
02450 {
02451 delete kompmgr_selection;
02452 char selection_name[ 100 ];
02453 sprintf( selection_name, "_NET_WM_CM_S%d", DefaultScreen( qt_xdisplay()));
02454 kompmgr_selection = new KSelectionOwner( selection_name );
02455 connect( kompmgr_selection, SIGNAL( lostOwnership()), SLOT( stopKompmgr()));
02456 kompmgr_selection->claim( true );
02457 connect(kompmgr, SIGNAL(processExited(KProcess*)), SLOT(restartKompmgr()));
02458 options->useTranslucency = TRUE;
02459 allowKompmgrRestart = FALSE;
02460 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02461 QByteArray ba;
02462 QDataStream arg(ba, IO_WriteOnly);
02463 arg << "";
02464 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStarted()", ba);
02465 }
02466 if (popup){ delete popup; popup = 0L; }
02467 }
02468
02469 void Workspace::stopKompmgr()
02470 {
02471 if (!kompmgr || !kompmgr->isRunning())
02472 return;
02473 delete kompmgr_selection;
02474 kompmgr_selection = NULL;
02475 kompmgr->disconnect(this, SLOT(restartKompmgr()));
02476 options->useTranslucency = FALSE;
02477 if (popup){ delete popup; popup = 0L; }
02478 kompmgr->kill();
02479 QByteArray ba;
02480 QDataStream arg(ba, IO_WriteOnly);
02481 arg << "";
02482 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStopped()", ba);
02483 }
02484
02485 bool Workspace::kompmgrIsRunning()
02486 {
02487 return kompmgr && kompmgr->isRunning();
02488 }
02489
02490 void Workspace::unblockKompmgrRestart()
02491 {
02492 allowKompmgrRestart = TRUE;
02493 }
02494
02495 void Workspace::restartKompmgr()
02496
02497 {
02498 if (!allowKompmgrRestart)
02499 {
02500 delete kompmgr_selection;
02501 kompmgr_selection = NULL;
02502 options->useTranslucency = FALSE;
02503 KProcess proc;
02504 proc << "kdialog" << "--error"
02505 << i18n( "The Composite Manager crashed twice within a minute and is therefore disabled for this session.")
02506 << "--title" << i18n("Composite Manager Failure");
02507 proc.start(KProcess::DontCare);
02508 return;
02509 }
02510 if (!kompmgr)
02511 return;
02512
02513
02514
02515
02516
02517
02518
02519
02520 if (!kompmgr->start(KProcess::NotifyOnExit, KProcess::Stderr))
02521 {
02522 delete kompmgr_selection;
02523 kompmgr_selection = NULL;
02524 options->useTranslucency = FALSE;
02525 KProcess proc;
02526 proc << "kdialog" << "--error"
02527 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02528 << "--title" << i18n("Composite Manager Failure");
02529 proc.start(KProcess::DontCare);
02530 }
02531 else
02532 {
02533 allowKompmgrRestart = FALSE;
02534 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02535 }
02536 }
02537
02538 void Workspace::handleKompmgrOutput( KProcess* , char *buffer, int buflen)
02539 {
02540 QString message;
02541 QString output = QString::fromLocal8Bit( buffer, buflen );
02542 if (output.contains("Started",false))
02543 ;
02544 else if (output.contains("Can't open display",false))
02545 message = i18n("<qt><b>kompmgr failed to open the display</b><br>There is probably an invalid display entry in your ~/.xcompmgrrc.</qt>");
02546 else if (output.contains("No render extension",false))
02547 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>");
02548 else if (output.contains("No composite extension",false))
02549 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>"
02550 "<i>Section \"Extensions\"<br>"
02551 "Option \"Composite\" \"Enable\"<br>"
02552 "EndSection</i></qt>");
02553 else if (output.contains("No damage extension",false))
02554 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>");
02555 else if (output.contains("No XFixes extension",false))
02556 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>");
02557 else return;
02558
02559 kompmgr->closeStderr();
02560 disconnect(kompmgr, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(handleKompmgrOutput(KProcess*, char*, int)));
02561 if( !message.isEmpty())
02562 {
02563 KProcess proc;
02564 proc << "kdialog" << "--error"
02565 << message
02566 << "--title" << i18n("Composite Manager Failure");
02567 proc.start(KProcess::DontCare);
02568 }
02569 }
02570
02571
02572 void Workspace::setOpacity(unsigned long winId, unsigned int opacityPercent)
02573 {
02574 if (opacityPercent > 100) opacityPercent = 100;
02575 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02576 if (winId == (*it)->window())
02577 {
02578 (*it)->setOpacity(opacityPercent < 100, (unsigned int)((opacityPercent/100.0)*0xFFFFFFFF));
02579 return;
02580 }
02581 }
02582
02583 void Workspace::setShadowSize(unsigned long winId, unsigned int shadowSizePercent)
02584 {
02585
02586 if (shadowSizePercent > 400) shadowSizePercent = 400;
02587 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02588 if (winId == (*it)->window())
02589 {
02590 (*it)->setShadowSize(shadowSizePercent);
02591 return;
02592 }
02593 }
02594
02595 void Workspace::setUnshadowed(unsigned long winId)
02596 {
02597 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02598 if (winId == (*it)->window())
02599 {
02600 (*it)->setShadowSize(0);
02601 return;
02602 }
02603 }
02604
02605 void Workspace::setShowingDesktop( bool showing )
02606 {
02607 rootInfo->setShowingDesktop( showing );
02608 showing_desktop = showing;
02609 ++block_showing_desktop;
02610 if( showing_desktop )
02611 {
02612 showing_desktop_clients.clear();
02613 ++block_focus;
02614 ClientList cls = stackingOrder();
02615
02616
02617 for( ClientList::ConstIterator it = cls.begin();
02618 it != cls.end();
02619 ++it )
02620 {
02621 if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
02622 showing_desktop_clients.prepend( *it );
02623 }
02624 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02625 it != showing_desktop_clients.end();
02626 ++it )
02627 (*it)->minimize(true);
02628 --block_focus;
02629 if( Client* desk = findDesktop( true, currentDesktop()))
02630 requestFocus( desk );
02631 }
02632 else
02633 {
02634 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02635 it != showing_desktop_clients.end();
02636 ++it )
02637 (*it)->unminimize(true);
02638 if( showing_desktop_clients.count() > 0 )
02639 requestFocus( showing_desktop_clients.first());
02640 showing_desktop_clients.clear();
02641 }
02642 --block_showing_desktop;
02643 }
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654 void Workspace::resetShowingDesktop( bool keep_hidden )
02655 {
02656 if( block_showing_desktop > 0 )
02657 return;
02658 rootInfo->setShowingDesktop( false );
02659 showing_desktop = false;
02660 ++block_showing_desktop;
02661 if( !keep_hidden )
02662 {
02663 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02664 it != showing_desktop_clients.end();
02665 ++it )
02666 (*it)->unminimize(true);
02667 }
02668 showing_desktop_clients.clear();
02669 --block_showing_desktop;
02670 }
02671
02672
02673
02674
02675
02676
02677
02678
02679 void Workspace::slotDisableGlobalShortcuts()
02680 {
02681 if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
02682 disableGlobalShortcuts( false );
02683 else
02684 disableGlobalShortcuts( true );
02685 }
02686
02687 static bool pending_dfc = false;
02688
02689 void Workspace::disableGlobalShortcutsForClient( bool disable )
02690 {
02691 if( global_shortcuts_disabled_for_client == disable )
02692 return;
02693 if( !global_shortcuts_disabled )
02694 {
02695 if( disable )
02696 pending_dfc = true;
02697 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02698
02699 }
02700 }
02701
02702 void Workspace::disableGlobalShortcuts( bool disable )
02703 {
02704 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02705
02706 }
02707
02708 void Workspace::kipcMessage( int id, int data )
02709 {
02710 if( id != KIPC::BlockShortcuts )
02711 return;
02712 if( pending_dfc && data )
02713 {
02714 global_shortcuts_disabled_for_client = true;
02715 pending_dfc = false;
02716 }
02717 else
02718 {
02719 global_shortcuts_disabled = data;
02720 global_shortcuts_disabled_for_client = false;
02721 }
02722
02723 for( ClientList::ConstIterator it = clients.begin();
02724 it != clients.end();
02725 ++it )
02726 (*it)->updateMouseGrab();
02727 }
02728
02729 }
02730
02731 #include "workspace.moc"