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