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