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