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