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