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