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