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 if ( c->wantsTabFocus() && !focus_chain.contains( c ))
00516 focus_chain.append( c );
00517 clients.append( c );
00518 }
00519 if( !unconstrained_stacking_order.contains( c ))
00520 unconstrained_stacking_order.append( c );
00521 if( !stacking_order.contains( c ))
00522 stacking_order.append( c );
00523 if( c->isTopMenu())
00524 addTopMenu( c );
00525 updateClientArea();
00526 updateClientLayer( c );
00527 if( c->isDesktop())
00528 {
00529 raiseClient( c );
00530
00531 if( activeClient() == NULL && should_get_focus.count() == 0 )
00532 activateClient( findDesktop( true, currentDesktop()));
00533 }
00534 c->checkActiveModal();
00535 checkTransients( c->window());
00536 updateStackingOrder( true );
00537 if( c->isUtility() || c->isMenu() || c->isToolbar())
00538 updateToolWindows( true );
00539 }
00540
00541
00542
00543
00544 void Workspace::removeClient( Client* c, allowed_t )
00545 {
00546 if (c == active_popup_client)
00547 closeActivePopup();
00548
00549 if( client_keys_client == c )
00550 setupWindowShortcutDone( false );
00551 if( !c->shortcut().isNull())
00552 c->setShortcut( QString::null );
00553
00554 if( c->isDialog())
00555 Notify::raise( Notify::TransDelete );
00556 if( c->isNormalWindow())
00557 Notify::raise( Notify::Delete );
00558
00559 Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
00560 clients.remove( c );
00561 desktops.remove( c );
00562 unconstrained_stacking_order.remove( c );
00563 stacking_order.remove( c );
00564 focus_chain.remove( c );
00565 attention_chain.remove( c );
00566 if( c->isTopMenu())
00567 removeTopMenu( c );
00568 Group* group = findGroup( c->window());
00569 if( group != NULL )
00570 group->lostLeader();
00571
00572 if ( c == most_recently_raised )
00573 most_recently_raised = 0;
00574 should_get_focus.remove( c );
00575 Q_ASSERT( c != active_client );
00576 if ( c == last_active_client )
00577 last_active_client = 0;
00578 if( c == pending_take_activity )
00579 pending_take_activity = NULL;
00580 if( c == delayfocus_client )
00581 cancelDelayFocus();
00582
00583 updateStackingOrder( true );
00584
00585 if (tab_grab)
00586 tab_box->repaint();
00587
00588 updateClientArea();
00589 }
00590
00591 void Workspace::updateCurrentTopMenu()
00592 {
00593 if( !managingTopMenus())
00594 return;
00595
00596 Client* menubar = 0;
00597 bool block_desktop_menubar = false;
00598 if( active_client )
00599 {
00600
00601 Client* menu_client = active_client;
00602 for(;;)
00603 {
00604 if( menu_client->isFullScreen())
00605 block_desktop_menubar = true;
00606 for( ClientList::ConstIterator it = menu_client->transients().begin();
00607 it != menu_client->transients().end();
00608 ++it )
00609 if( (*it)->isTopMenu())
00610 {
00611 menubar = *it;
00612 break;
00613 }
00614 if( menubar != NULL || !menu_client->isTransient())
00615 break;
00616 if( menu_client->isModal() || menu_client->transientFor() == NULL )
00617 break;
00618 menu_client = menu_client->transientFor();
00619 }
00620 if( !menubar )
00621 {
00622 for( ClientList::ConstIterator it = active_client->group()->members().begin();
00623 it != active_client->group()->members().end();
00624 ++it )
00625 if( (*it)->isTopMenu())
00626 {
00627 menubar = *it;
00628 break;
00629 }
00630 }
00631 }
00632 if( !menubar && !block_desktop_menubar && options->desktopTopMenu())
00633 {
00634
00635 Client* desktop = findDesktop( true, currentDesktop());
00636 if( desktop != NULL )
00637 {
00638 for( ClientList::ConstIterator it = desktop->transients().begin();
00639 it != desktop->transients().end();
00640 ++it )
00641 if( (*it)->isTopMenu())
00642 {
00643 menubar = *it;
00644 break;
00645 }
00646 }
00647
00648
00649
00650 if( menubar == NULL )
00651 {
00652 for( ClientList::ConstIterator it = topmenus.begin();
00653 it != topmenus.end();
00654 ++it )
00655 if( (*it)->wasOriginallyGroupTransient())
00656 {
00657 menubar = *it;
00658 break;
00659 }
00660 }
00661 }
00662
00663
00664 if ( menubar )
00665 {
00666 if( active_client && !menubar->isOnDesktop( active_client->desktop()))
00667 menubar->setDesktop( active_client->desktop());
00668 menubar->hideClient( false );
00669 topmenu_space->hide();
00670
00671
00672
00673 unconstrained_stacking_order.remove( menubar );
00674 unconstrained_stacking_order.append( menubar );
00675 }
00676 else if( !block_desktop_menubar )
00677 {
00678 topmenu_space->show();
00679 }
00680
00681
00682 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00683 {
00684 if( (*it)->isTopMenu() && (*it) != menubar )
00685 (*it)->hideClient( true );
00686 }
00687 }
00688
00689
00690 void Workspace::updateToolWindows( bool also_hide )
00691 {
00692
00693 if( !options->hideUtilityWindowsForInactive )
00694 {
00695 for( ClientList::ConstIterator it = clients.begin();
00696 it != clients.end();
00697 ++it )
00698 (*it)->hideClient( false );
00699 return;
00700 }
00701 const Group* group = NULL;
00702 const Client* client = active_client;
00703
00704
00705 while( client != NULL )
00706 {
00707 if( !client->isTransient())
00708 break;
00709 if( client->groupTransient())
00710 {
00711 group = client->group();
00712 break;
00713 }
00714 client = client->transientFor();
00715 }
00716
00717
00718
00719
00720 ClientList to_show, to_hide;
00721 for( ClientList::ConstIterator it = stacking_order.begin();
00722 it != stacking_order.end();
00723 ++it )
00724 {
00725 if( (*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar())
00726 {
00727 bool show = true;
00728 if( !(*it)->isTransient())
00729 {
00730 if( (*it)->group()->members().count() == 1 )
00731 show = true;
00732 else if( client != NULL && (*it)->group() == client->group())
00733 show = true;
00734 else
00735 show = false;
00736 }
00737 else
00738 {
00739 if( group != NULL && (*it)->group() == group )
00740 show = true;
00741 else if( client != NULL && client->hasTransient( (*it), true ))
00742 show = true;
00743 else
00744 show = false;
00745 }
00746 if( !show && also_hide )
00747 {
00748 const ClientList mainclients = (*it)->mainClients();
00749
00750
00751 if( mainclients.isEmpty())
00752 show = true;
00753 for( ClientList::ConstIterator it2 = mainclients.begin();
00754 it2 != mainclients.end();
00755 ++it2 )
00756 {
00757 if( (*it2)->isSpecialWindow())
00758 show = true;
00759 }
00760 if( !show )
00761 to_hide.append( *it );
00762 }
00763 if( show )
00764 to_show.append( *it );
00765 }
00766 }
00767 for( ClientList::ConstIterator it = to_show.fromLast();
00768 it != to_show.end();
00769 --it )
00770
00771 (*it)->hideClient( false );
00772 if( also_hide )
00773 {
00774 for( ClientList::ConstIterator it = to_hide.begin();
00775 it != to_hide.end();
00776 ++it )
00777 (*it)->hideClient( true );
00778 updateToolWindowsTimer.stop();
00779 }
00780 else
00781 {
00782 updateToolWindowsTimer.start( 50, true );
00783 }
00784 }
00785
00786 void Workspace::slotUpdateToolWindows()
00787 {
00788 updateToolWindows( true );
00789 }
00790
00794 void Workspace::updateColormap()
00795 {
00796 Colormap cmap = default_colormap;
00797 if ( activeClient() && activeClient()->colormap() != None )
00798 cmap = activeClient()->colormap();
00799 if ( cmap != installed_colormap )
00800 {
00801 XInstallColormap(qt_xdisplay(), cmap );
00802 installed_colormap = cmap;
00803 }
00804 }
00805
00806 void Workspace::reconfigure()
00807 {
00808 reconfigureTimer.start(200, true);
00809 }
00810
00811
00812 void Workspace::slotSettingsChanged(int category)
00813 {
00814 kdDebug(1212) << "Workspace::slotSettingsChanged()" << endl;
00815 if( category == (int) KApplication::SETTINGS_SHORTCUTS )
00816 readShortcuts();
00817 }
00818
00822 KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
00823
00824 void Workspace::slotReconfigure()
00825 {
00826 kdDebug(1212) << "Workspace::slotReconfigure()" << endl;
00827 reconfigureTimer.stop();
00828
00829 KGlobal::config()->reparseConfiguration();
00830 unsigned long changed = options->updateSettings();
00831 tab_box->reconfigure();
00832 popupinfo->reconfigure();
00833 initPositioning->reinitCascading( 0 );
00834 readShortcuts();
00835 forEachClient( CheckIgnoreFocusStealingProcedure());
00836 updateToolWindows( true );
00837
00838 if( mgr->reset( changed ))
00839 {
00840 #if 0 // This actually seems to make things worse now
00841 QWidget curtain;
00842 curtain.setBackgroundMode( NoBackground );
00843 curtain.setGeometry( QApplication::desktop()->geometry() );
00844 curtain.show();
00845 #endif
00846 for( ClientList::ConstIterator it = clients.begin();
00847 it != clients.end();
00848 ++it )
00849 {
00850 (*it)->updateDecoration( true, true );
00851 }
00852 mgr->destroyPreviousPlugin();
00853 }
00854 else
00855 {
00856 forEachClient( CheckBorderSizesProcedure());
00857 }
00858
00859 checkElectricBorders();
00860
00861 if( options->topMenuEnabled() && !managingTopMenus())
00862 {
00863 if( topmenu_selection->claim( false ))
00864 setupTopMenuHandling();
00865 else
00866 lostTopMenuSelection();
00867 }
00868 else if( !options->topMenuEnabled() && managingTopMenus())
00869 {
00870 topmenu_selection->release();
00871 lostTopMenuSelection();
00872 }
00873 topmenu_height = 0;
00874 if( managingTopMenus())
00875 {
00876 updateTopMenuGeometry();
00877 updateCurrentTopMenu();
00878 }
00879
00880 loadWindowRules();
00881 for( ClientList::Iterator it = clients.begin();
00882 it != clients.end();
00883 ++it )
00884 {
00885 (*it)->setupWindowRules( true );
00886 (*it)->applyWindowRules();
00887 discardUsedWindowRules( *it, false );
00888 }
00889
00890 if (options->resetKompmgr)
00891 {
00892 bool tmp = options->useTranslucency;
00893 stopKompmgr();
00894 if (tmp)
00895 QTimer::singleShot( 200, this, SLOT(startKompmgr()) );
00896 }
00897 }
00898
00899 void Workspace::loadDesktopSettings()
00900 {
00901 KConfig* c = KGlobal::config();
00902 QCString groupname;
00903 if (screen_number == 0)
00904 groupname = "Desktops";
00905 else
00906 groupname.sprintf("Desktops-screen-%d", screen_number);
00907 KConfigGroupSaver saver(c,groupname);
00908
00909 int n = c->readNumEntry("Number", 4);
00910 number_of_desktops = n;
00911 delete workarea;
00912 workarea = new QRect[ n + 1 ];
00913 delete screenarea;
00914 screenarea = NULL;
00915 rootInfo->setNumberOfDesktops( number_of_desktops );
00916 desktop_focus_chain.resize( n );
00917 for(int i = 1; i <= n; i++)
00918 {
00919 QString s = c->readEntry(QString("Name_%1").arg(i),
00920 i18n("Desktop %1").arg(i));
00921 rootInfo->setDesktopName( i, s.utf8().data() );
00922 desktop_focus_chain[i-1] = i;
00923 }
00924 }
00925
00926 void Workspace::saveDesktopSettings()
00927 {
00928 KConfig* c = KGlobal::config();
00929 QCString groupname;
00930 if (screen_number == 0)
00931 groupname = "Desktops";
00932 else
00933 groupname.sprintf("Desktops-screen-%d", screen_number);
00934 KConfigGroupSaver saver(c,groupname);
00935
00936 c->writeEntry("Number", number_of_desktops );
00937 for(int i = 1; i <= number_of_desktops; i++)
00938 {
00939 QString s = desktopName( i );
00940 QString defaultvalue = i18n("Desktop %1").arg(i);
00941 if ( s.isEmpty() )
00942 {
00943 s = defaultvalue;
00944 rootInfo->setDesktopName( i, s.utf8().data() );
00945 }
00946
00947 if (s != defaultvalue)
00948 {
00949 c->writeEntry( QString("Name_%1").arg(i), s );
00950 }
00951 else
00952 {
00953 QString currentvalue = c->readEntry(QString("Name_%1").arg(i));
00954 if (currentvalue != defaultvalue)
00955 c->writeEntry( QString("Name_%1").arg(i), "" );
00956 }
00957 }
00958 }
00959
00960 QStringList Workspace::configModules(bool controlCenter)
00961 {
00962 QStringList args;
00963 args << "kde-kwindecoration.desktop";
00964 if (controlCenter)
00965 args << "kde-kwinoptions.desktop";
00966 else if (kapp->authorizeControlModule("kde-kwinoptions.desktop"))
00967 args << "kwinactions" << "kwinfocus" << "kwinmoving" << "kwinadvanced" << "kwinrules" << "kwintranslucency";
00968 return args;
00969 }
00970
00971 void Workspace::configureWM()
00972 {
00973 KApplication::kdeinitExec( "kcmshell", configModules(false) );
00974 }
00975
00979 void Workspace::doNotManage( QString title )
00980 {
00981 doNotManageList.append( title );
00982 }
00983
00987 bool Workspace::isNotManaged( const QString& title )
00988 {
00989 for ( QStringList::Iterator it = doNotManageList.begin(); it != doNotManageList.end(); ++it )
00990 {
00991 QRegExp r( (*it) );
00992 if (r.search(title) != -1)
00993 {
00994 doNotManageList.remove( it );
00995 return TRUE;
00996 }
00997 }
00998 return FALSE;
00999 }
01000
01004 void Workspace::refresh()
01005 {
01006 QWidget w;
01007 w.setGeometry( QApplication::desktop()->geometry() );
01008 w.show();
01009 w.hide();
01010 QApplication::flushX();
01011 }
01012
01020 class ObscuringWindows
01021 {
01022 public:
01023 ~ObscuringWindows();
01024 void create( Client* c );
01025 private:
01026 QValueList<Window> obscuring_windows;
01027 static QValueList<Window>* cached;
01028 static unsigned int max_cache_size;
01029 };
01030
01031 QValueList<Window>* ObscuringWindows::cached = 0;
01032 unsigned int ObscuringWindows::max_cache_size = 0;
01033
01034 void ObscuringWindows::create( Client* c )
01035 {
01036 if( cached == 0 )
01037 cached = new QValueList<Window>;
01038 Window obs_win;
01039 XWindowChanges chngs;
01040 int mask = CWSibling | CWStackMode;
01041 if( cached->count() > 0 )
01042 {
01043 cached->remove( obs_win = cached->first());
01044 chngs.x = c->x();
01045 chngs.y = c->y();
01046 chngs.width = c->width();
01047 chngs.height = c->height();
01048 mask |= CWX | CWY | CWWidth | CWHeight;
01049 }
01050 else
01051 {
01052 XSetWindowAttributes a;
01053 a.background_pixmap = None;
01054 a.override_redirect = True;
01055 obs_win = XCreateWindow( qt_xdisplay(), qt_xrootwin(), c->x(), c->y(),
01056 c->width(), c->height(), 0, CopyFromParent, InputOutput,
01057 CopyFromParent, CWBackPixmap | CWOverrideRedirect, &a );
01058 }
01059 chngs.sibling = c->frameId();
01060 chngs.stack_mode = Below;
01061 XConfigureWindow( qt_xdisplay(), obs_win, mask, &chngs );
01062 XMapWindow( qt_xdisplay(), obs_win );
01063 obscuring_windows.append( obs_win );
01064 }
01065
01066 ObscuringWindows::~ObscuringWindows()
01067 {
01068 max_cache_size = QMAX( max_cache_size, obscuring_windows.count() + 4 ) - 1;
01069 for( QValueList<Window>::ConstIterator it = obscuring_windows.begin();
01070 it != obscuring_windows.end();
01071 ++it )
01072 {
01073 XUnmapWindow( qt_xdisplay(), *it );
01074 if( cached->count() < max_cache_size )
01075 cached->prepend( *it );
01076 else
01077 XDestroyWindow( qt_xdisplay(), *it );
01078 }
01079 }
01080
01081
01088 bool Workspace::setCurrentDesktop( int new_desktop )
01089 {
01090 if (new_desktop < 1 || new_desktop > number_of_desktops )
01091 return false;
01092
01093 closeActivePopup();
01094 ++block_focus;
01095
01096 StackingUpdatesBlocker blocker( this );
01097
01098 int old_desktop = current_desktop;
01099 if (new_desktop != current_desktop)
01100 {
01101 ++block_showing_desktop;
01102
01103
01104
01105
01106 Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop));
01107
01108 ObscuringWindows obs_wins;
01109
01110 current_desktop = new_desktop;
01111
01112 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
01113 if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
01114 {
01115 if( (*it)->isShown( true ) && (*it)->isOnDesktop( old_desktop ))
01116 obs_wins.create( *it );
01117 (*it)->updateVisibility();
01118 }
01119
01120 rootInfo->setCurrentDesktop( current_desktop );
01121
01122 if( movingClient && !movingClient->isOnDesktop( new_desktop ))
01123 movingClient->setDesktop( new_desktop );
01124
01125 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
01126 if ( (*it)->isOnDesktop( new_desktop ) )
01127 (*it)->updateVisibility();
01128
01129 --block_showing_desktop;
01130 if( showingDesktop())
01131 resetShowingDesktop( false );
01132 }
01133
01134
01135 --block_focus;
01136 Client* c = 0;
01137
01138 if ( options->focusPolicyIsReasonable())
01139 {
01140
01141
01142 if ( focus_chain.contains( active_client ) && active_client->isShown( true )
01143 && active_client->isOnCurrentDesktop())
01144 {
01145 c = active_client;
01146 }
01147
01148 if ( !c )
01149 {
01150 for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it)
01151 {
01152 if ( (*it)->isShown( false ) && !(*it)->isOnAllDesktops() && (*it)->isOnCurrentDesktop())
01153 {
01154 c = *it;
01155 break;
01156 }
01157 }
01158 }
01159
01160 if ( !c )
01161 {
01162 for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it)
01163 {
01164 if ( (*it)->isShown( false ) && (*it)->isOnCurrentDesktop())
01165 {
01166 c = *it;
01167 break;
01168 }
01169 }
01170 }
01171 }
01172
01173
01174
01175
01176 else if( active_client && active_client->isShown( true ) && active_client->isOnCurrentDesktop())
01177 c= active_client;
01178
01179 if( c != active_client )
01180 setActiveClient( NULL, Allowed );
01181
01182 if ( c )
01183 requestFocus( c );
01184 else
01185 focusToNull();
01186
01187 if( !desktops.isEmpty() )
01188 {
01189 Window w_tmp;
01190 int i_tmp;
01191 XGetInputFocus( qt_xdisplay(), &w_tmp, &i_tmp );
01192 if( w_tmp == null_focus_window )
01193 requestFocus( findDesktop( true, currentDesktop()));
01194 }
01195
01196 updateCurrentTopMenu();
01197
01198
01199
01200
01201
01202
01203 for( int i = desktop_focus_chain.find( current_desktop ); i > 0; i-- )
01204 desktop_focus_chain[i] = desktop_focus_chain[i-1];
01205 desktop_focus_chain[0] = current_desktop;
01206
01207
01208
01209
01210
01211
01212 if( old_desktop != 0 )
01213 popupinfo->showInfo( desktopName(currentDesktop()) );
01214 return true;
01215 }
01216
01217
01218 void Workspace::nextDesktop()
01219 {
01220 int desktop = currentDesktop() + 1;
01221 setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
01222 }
01223
01224
01225 void Workspace::previousDesktop()
01226 {
01227 int desktop = currentDesktop() - 1;
01228 setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
01229 }
01230
01231 int Workspace::desktopToRight( int desktop ) const
01232 {
01233 int x,y;
01234 calcDesktopLayout(x,y);
01235 int dt = desktop-1;
01236 if (layoutOrientation == Qt::Vertical)
01237 {
01238 dt += y;
01239 if ( dt >= numberOfDesktops() )
01240 {
01241 if ( options->rollOverDesktops )
01242 dt -= numberOfDesktops();
01243 else
01244 return desktop;
01245 }
01246 }
01247 else
01248 {
01249 int d = (dt % x) + 1;
01250 if ( d >= x )
01251 {
01252 if ( options->rollOverDesktops )
01253 d -= x;
01254 else
01255 return desktop;
01256 }
01257 dt = dt - (dt % x) + d;
01258 }
01259 return dt+1;
01260 }
01261
01262 int Workspace::desktopToLeft( int desktop ) const
01263 {
01264 int x,y;
01265 calcDesktopLayout(x,y);
01266 int dt = desktop-1;
01267 if (layoutOrientation == Qt::Vertical)
01268 {
01269 dt -= y;
01270 if ( dt < 0 )
01271 {
01272 if ( options->rollOverDesktops )
01273 dt += numberOfDesktops();
01274 else
01275 return desktop;
01276 }
01277 }
01278 else
01279 {
01280 int d = (dt % x) - 1;
01281 if ( d < 0 )
01282 {
01283 if ( options->rollOverDesktops )
01284 d += x;
01285 else
01286 return desktop;
01287 }
01288 dt = dt - (dt % x) + d;
01289 }
01290 return dt+1;
01291 }
01292
01293 int Workspace::desktopUp( int desktop ) const
01294 {
01295 int x,y;
01296 calcDesktopLayout(x,y);
01297 int dt = desktop-1;
01298 if (layoutOrientation == Qt::Horizontal)
01299 {
01300 dt -= x;
01301 if ( dt < 0 )
01302 {
01303 if ( options->rollOverDesktops )
01304 dt += numberOfDesktops();
01305 else
01306 return desktop;
01307 }
01308 }
01309 else
01310 {
01311 int d = (dt % y) - 1;
01312 if ( d < 0 )
01313 {
01314 if ( options->rollOverDesktops )
01315 d += y;
01316 else
01317 return desktop;
01318 }
01319 dt = dt - (dt % y) + d;
01320 }
01321 return dt+1;
01322 }
01323
01324 int Workspace::desktopDown( int desktop ) const
01325 {
01326 int x,y;
01327 calcDesktopLayout(x,y);
01328 int dt = desktop-1;
01329 if (layoutOrientation == Qt::Horizontal)
01330 {
01331 dt += x;
01332 if ( dt >= numberOfDesktops() )
01333 {
01334 if ( options->rollOverDesktops )
01335 dt -= numberOfDesktops();
01336 else
01337 return desktop;
01338 }
01339 }
01340 else
01341 {
01342 int d = (dt % y) + 1;
01343 if ( d >= y )
01344 {
01345 if ( options->rollOverDesktops )
01346 d -= y;
01347 else
01348 return desktop;
01349 }
01350 dt = dt - (dt % y) + d;
01351 }
01352 return dt+1;
01353 }
01354
01355
01359 void Workspace::setNumberOfDesktops( int n )
01360 {
01361 if ( n == number_of_desktops )
01362 return;
01363 int old_number_of_desktops = number_of_desktops;
01364 number_of_desktops = n;
01365
01366 if( currentDesktop() > numberOfDesktops())
01367 setCurrentDesktop( numberOfDesktops());
01368
01369
01370
01371 if( old_number_of_desktops < number_of_desktops )
01372 {
01373 rootInfo->setNumberOfDesktops( number_of_desktops );
01374 NETPoint* viewports = new NETPoint[ number_of_desktops ];
01375 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01376 delete[] viewports;
01377 updateClientArea( true );
01378 }
01379
01380
01381
01382 if( old_number_of_desktops > number_of_desktops )
01383 {
01384 for( ClientList::ConstIterator it = clients.begin();
01385 it != clients.end();
01386 ++it)
01387 {
01388 if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
01389 sendClientToDesktop( *it, numberOfDesktops(), true );
01390 }
01391 }
01392 if( old_number_of_desktops > number_of_desktops )
01393 {
01394 rootInfo->setNumberOfDesktops( number_of_desktops );
01395 NETPoint* viewports = new NETPoint[ number_of_desktops ];
01396 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01397 delete[] viewports;
01398 updateClientArea( true );
01399 }
01400
01401 saveDesktopSettings();
01402
01403
01404 desktop_focus_chain.resize( n );
01405 for( int i = 0; i < (int)desktop_focus_chain.size(); i++ )
01406 desktop_focus_chain[i] = i+1;
01407 }
01408
01414 void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
01415 {
01416 bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
01417 c->setDesktop( desk );
01418 if ( c->desktop() != desk )
01419 return;
01420 desk = c->desktop();
01421
01422 if ( c->isOnDesktop( currentDesktop() ) )
01423 {
01424 if ( c->wantsTabFocus() && options->focusPolicyIsReasonable()
01425 && !was_on_desktop
01426 && !dont_activate )
01427 requestFocus( c );
01428 else
01429 restackClientUnderActive( c );
01430 }
01431 else
01432 {
01433 raiseClient( c );
01434 focus_chain.remove( c );
01435 if ( c->wantsTabFocus() )
01436 focus_chain.append( c );
01437 }
01438
01439 ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01440 for( ClientList::ConstIterator it = transients_stacking_order.begin();
01441 it != transients_stacking_order.end();
01442 ++it )
01443 sendClientToDesktop( *it, desk, dont_activate );
01444 updateClientArea();
01445 }
01446
01447 void Workspace::setDesktopLayout(int o, int x, int y)
01448 {
01449 layoutOrientation = (Qt::Orientation) o;
01450 layoutX = x;
01451 layoutY = y;
01452 }
01453
01454 void Workspace::calcDesktopLayout(int &x, int &y) const
01455 {
01456 x = layoutX;
01457 y = layoutY;
01458 if ((x == -1) && (y > 0))
01459 x = (numberOfDesktops()+y-1) / y;
01460 else if ((y == -1) && (x > 0))
01461 y = (numberOfDesktops()+x-1) / x;
01462
01463 if (x == -1)
01464 x = 1;
01465 if (y == -1)
01466 y = 1;
01467 }
01468
01473 bool Workspace::addSystemTrayWin( WId w )
01474 {
01475 if ( systemTrayWins.contains( w ) )
01476 return TRUE;
01477
01478 NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
01479 WId trayWinFor = ni.kdeSystemTrayWinFor();
01480 if ( !trayWinFor )
01481 return FALSE;
01482 systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
01483 XSelectInput( qt_xdisplay(), w,
01484 StructureNotifyMask
01485 );
01486 XAddToSaveSet( qt_xdisplay(), w );
01487 propagateSystemTrayWins();
01488 return TRUE;
01489 }
01490
01495 bool Workspace::removeSystemTrayWin( WId w, bool check )
01496 {
01497 if ( !systemTrayWins.contains( w ) )
01498 return FALSE;
01499 if( check )
01500 {
01501
01502
01503
01504
01505
01506
01507
01508 int num_props;
01509 Atom* props = XListProperties( qt_xdisplay(), w, &num_props );
01510 if( props != NULL )
01511 {
01512 for( int i = 0;
01513 i < num_props;
01514 ++i )
01515 if( props[ i ] == atoms->kde_system_tray_embedding )
01516 {
01517 XFree( props );
01518 return false;
01519 }
01520 XFree( props );
01521 }
01522 }
01523 systemTrayWins.remove( w );
01524 propagateSystemTrayWins();
01525 return TRUE;
01526 }
01527
01528
01532 void Workspace::propagateSystemTrayWins()
01533 {
01534 Window *cl = new Window[ systemTrayWins.count()];
01535
01536 int i = 0;
01537 for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it )
01538 {
01539 cl[i++] = (*it).win;
01540 }
01541
01542 rootInfo->setKDESystemTrayWindows( cl, i );
01543 delete [] cl;
01544 }
01545
01546
01547 void Workspace::killWindowId( Window window_to_kill )
01548 {
01549 if( window_to_kill == None )
01550 return;
01551 Window window = window_to_kill;
01552 Client* client = NULL;
01553 for(;;)
01554 {
01555 client = findClient( FrameIdMatchPredicate( window ));
01556 if( client != NULL )
01557 break;
01558 Window parent, root;
01559 Window* children;
01560 unsigned int children_count;
01561 XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
01562 if( children != NULL )
01563 XFree( children );
01564 if( window == root )
01565 break;
01566 window = parent;
01567 }
01568 if( client != NULL )
01569 client->killWindow();
01570 else
01571 XKillClient( qt_xdisplay(), window_to_kill );
01572 }
01573
01574
01575 void Workspace::sendPingToWindow( Window window, Time timestamp )
01576 {
01577 rootInfo->sendPing( window, timestamp );
01578 }
01579
01580 void Workspace::sendTakeActivity( Client* c, Time timestamp, long flags )
01581 {
01582 rootInfo->takeActivity( c->window(), timestamp, flags );
01583 pending_take_activity = c;
01584 }
01585
01586
01590 void Workspace::slotGrabWindow()
01591 {
01592 if ( active_client )
01593 {
01594 QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
01595
01596
01597 if( Shape::available())
01598 {
01599
01600 int count, order;
01601 XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), active_client->frameId(),
01602 ShapeBounding, &count, &order);
01603
01604
01605
01606
01607 if (rects)
01608 {
01609
01610 QRegion contents;
01611 for (int pos = 0; pos < count; pos++)
01612 contents += QRegion(rects[pos].x, rects[pos].y,
01613 rects[pos].width, rects[pos].height);
01614 XFree(rects);
01615
01616
01617 QRegion bbox(0, 0, snapshot.width(), snapshot.height());
01618
01619
01620 QRegion maskedAway = bbox - contents;
01621 QMemArray<QRect> maskedAwayRects = maskedAway.rects();
01622
01623
01624 QBitmap mask( snapshot.width(), snapshot.height());
01625 QPainter p(&mask);
01626 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
01627 for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
01628 p.fillRect(maskedAwayRects[pos], Qt::color0);
01629 p.end();
01630 snapshot.setMask(mask);
01631 }
01632 }
01633
01634 QClipboard *cb = QApplication::clipboard();
01635 cb->setPixmap( snapshot );
01636 }
01637 else
01638 slotGrabDesktop();
01639 }
01640
01644 void Workspace::slotGrabDesktop()
01645 {
01646 QPixmap p = QPixmap::grabWindow( qt_xrootwin() );
01647 QClipboard *cb = QApplication::clipboard();
01648 cb->setPixmap( p );
01649 }
01650
01651
01655 void Workspace::slotMouseEmulation()
01656 {
01657
01658 if ( mouse_emulation )
01659 {
01660 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01661 mouse_emulation = FALSE;
01662 return;
01663 }
01664
01665 if ( XGrabKeyboard(qt_xdisplay(),
01666 root, FALSE,
01667 GrabModeAsync, GrabModeAsync,
01668 qt_x_time) == GrabSuccess )
01669 {
01670 mouse_emulation = TRUE;
01671 mouse_emulation_state = 0;
01672 mouse_emulation_window = 0;
01673 }
01674 }
01675
01682 WId Workspace::getMouseEmulationWindow()
01683 {
01684 Window root;
01685 Window child = qt_xrootwin();
01686 int root_x, root_y, lx, ly;
01687 uint state;
01688 Window w;
01689 Client * c = 0;
01690 do
01691 {
01692 w = child;
01693 if (!c)
01694 c = findClient( FrameIdMatchPredicate( w ));
01695 XQueryPointer( qt_xdisplay(), w, &root, &child,
01696 &root_x, &root_y, &lx, &ly, &state );
01697 } while ( child != None && child != w );
01698
01699 if ( c && !c->isActive() )
01700 activateClient( c );
01701 return (WId) w;
01702 }
01703
01707 unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
01708 {
01709 if ( !w )
01710 return state;
01711 QWidget* widget = QWidget::find( w );
01712 if ( (!widget || widget->inherits("QToolButton") ) && !findClient( WindowMatchPredicate( w )) )
01713 {
01714 int x, y;
01715 Window xw;
01716 XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
01717 if ( type == EmuMove )
01718 {
01719 XMotionEvent e;
01720 e.type = MotionNotify;
01721 e.window = w;
01722 e.root = qt_xrootwin();
01723 e.subwindow = w;
01724 e.time = qt_x_time;
01725 e.x = x;
01726 e.y = y;
01727 e.x_root = pos.x();
01728 e.y_root = pos.y();
01729 e.state = state;
01730 e.is_hint = NotifyNormal;
01731 XSendEvent( qt_xdisplay(), w, TRUE, ButtonMotionMask, (XEvent*)&e );
01732 }
01733 else
01734 {
01735 XButtonEvent e;
01736 e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
01737 e.window = w;
01738 e.root = qt_xrootwin();
01739 e.subwindow = w;
01740 e.time = qt_x_time;
01741 e.x = x;
01742 e.y = y;
01743 e.x_root = pos.x();
01744 e.y_root = pos.y();
01745 e.state = state;
01746 e.button = button;
01747 XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, (XEvent*)&e );
01748
01749 if ( type == EmuPress )
01750 {
01751 switch ( button )
01752 {
01753 case 2:
01754 state |= Button2Mask;
01755 break;
01756 case 3:
01757 state |= Button3Mask;
01758 break;
01759 default:
01760 state |= Button1Mask;
01761 break;
01762 }
01763 }
01764 else
01765 {
01766 switch ( button )
01767 {
01768 case 2:
01769 state &= ~Button2Mask;
01770 break;
01771 case 3:
01772 state &= ~Button3Mask;
01773 break;
01774 default:
01775 state &= ~Button1Mask;
01776 break;
01777 }
01778 }
01779 }
01780 }
01781 return state;
01782 }
01783
01787 bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
01788 {
01789 if ( root != qt_xrootwin() )
01790 return FALSE;
01791 int kc = XKeycodeToKeysym(qt_xdisplay(), ev.keycode, 0);
01792 int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
01793
01794 bool is_control = km & ControlMask;
01795 bool is_alt = km & Mod1Mask;
01796 bool is_shift = km & ShiftMask;
01797 int delta = is_control?1:is_alt?32:8;
01798 QPoint pos = QCursor::pos();
01799
01800 switch ( kc )
01801 {
01802 case XK_Left:
01803 case XK_KP_Left:
01804 pos.rx() -= delta;
01805 break;
01806 case XK_Right:
01807 case XK_KP_Right:
01808 pos.rx() += delta;
01809 break;
01810 case XK_Up:
01811 case XK_KP_Up:
01812 pos.ry() -= delta;
01813 break;
01814 case XK_Down:
01815 case XK_KP_Down:
01816 pos.ry() += delta;
01817 break;
01818 case XK_F1:
01819 if ( !mouse_emulation_state )
01820 mouse_emulation_window = getMouseEmulationWindow();
01821 if ( (mouse_emulation_state & Button1Mask) == 0 )
01822 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01823 if ( !is_shift )
01824 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01825 break;
01826 case XK_F2:
01827 if ( !mouse_emulation_state )
01828 mouse_emulation_window = getMouseEmulationWindow();
01829 if ( (mouse_emulation_state & Button2Mask) == 0 )
01830 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
01831 if ( !is_shift )
01832 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01833 break;
01834 case XK_F3:
01835 if ( !mouse_emulation_state )
01836 mouse_emulation_window = getMouseEmulationWindow();
01837 if ( (mouse_emulation_state & Button3Mask) == 0 )
01838 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
01839 if ( !is_shift )
01840 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01841 break;
01842 case XK_Return:
01843 case XK_space:
01844 case XK_KP_Enter:
01845 case XK_KP_Space:
01846 {
01847 if ( !mouse_emulation_state )
01848 {
01849
01850 mouse_emulation_window = getMouseEmulationWindow();
01851 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01852 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01853 }
01854 else
01855 {
01856 if ( mouse_emulation_state & Button1Mask )
01857 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01858 if ( mouse_emulation_state & Button2Mask )
01859 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01860 if ( mouse_emulation_state & Button3Mask )
01861 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01862 }
01863 }
01864
01865 case XK_Escape:
01866 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01867 mouse_emulation = FALSE;
01868 return TRUE;
01869 default:
01870 return FALSE;
01871 }
01872
01873 QCursor::setPos( pos );
01874 if ( mouse_emulation_state )
01875 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
01876 return TRUE;
01877
01878 }
01879
01885 QWidget* Workspace::desktopWidget()
01886 {
01887 return desktop_widget;
01888 }
01889
01890
01891 void Workspace::delayFocus()
01892 {
01893 requestFocus( delayfocus_client );
01894 cancelDelayFocus();
01895 }
01896
01897 void Workspace::requestDelayFocus( Client* c )
01898 {
01899 delayfocus_client = c;
01900 delete delayFocusTimer;
01901 delayFocusTimer = new QTimer( this );
01902 connect( delayFocusTimer, SIGNAL( timeout() ), this, SLOT( delayFocus() ) );
01903 delayFocusTimer->start( options->delayFocusInterval, TRUE );
01904 }
01905
01906 void Workspace::cancelDelayFocus()
01907 {
01908 delete delayFocusTimer;
01909 delayFocusTimer = 0;
01910 }
01911
01912
01913
01914
01915
01916
01917
01918
01919 void Workspace::checkElectricBorders( bool force )
01920 {
01921 if( force )
01922 destroyBorderWindows();
01923
01924 electric_current_border = 0;
01925
01926 QRect r = QApplication::desktop()->geometry();
01927 electricTop = r.top();
01928 electricBottom = r.bottom();
01929 electricLeft = r.left();
01930 electricRight = r.right();
01931
01932 if (options->electricBorders() == Options::ElectricAlways)
01933 createBorderWindows();
01934 else
01935 destroyBorderWindows();
01936 }
01937
01938 void Workspace::createBorderWindows()
01939 {
01940 if ( electric_have_borders )
01941 return;
01942
01943 electric_have_borders = true;
01944
01945 QRect r = QApplication::desktop()->geometry();
01946 XSetWindowAttributes attributes;
01947 unsigned long valuemask;
01948 attributes.override_redirect = True;
01949 attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
01950 VisibilityChangeMask);
01951 valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
01952 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01953 XC_sb_up_arrow);
01954 electric_top_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01955 0,0,
01956 r.width(),1,
01957 0,
01958 CopyFromParent, InputOnly,
01959 CopyFromParent,
01960 valuemask, &attributes);
01961 XMapWindow(qt_xdisplay(), electric_top_border);
01962
01963 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01964 XC_sb_down_arrow);
01965 electric_bottom_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01966 0,r.height()-1,
01967 r.width(),1,
01968 0,
01969 CopyFromParent, InputOnly,
01970 CopyFromParent,
01971 valuemask, &attributes);
01972 XMapWindow(qt_xdisplay(), electric_bottom_border);
01973
01974 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01975 XC_sb_left_arrow);
01976 electric_left_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01977 0,0,
01978 1,r.height(),
01979 0,
01980 CopyFromParent, InputOnly,
01981 CopyFromParent,
01982 valuemask, &attributes);
01983 XMapWindow(qt_xdisplay(), electric_left_border);
01984
01985 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01986 XC_sb_right_arrow);
01987 electric_right_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01988 r.width()-1,0,
01989 1,r.height(),
01990 0,
01991 CopyFromParent, InputOnly,
01992 CopyFromParent,
01993 valuemask, &attributes);
01994 XMapWindow(qt_xdisplay(), electric_right_border);
01995
01996 Atom version = 4;
01997 XChangeProperty( qt_xdisplay(), electric_top_border, atoms->xdnd_aware, XA_ATOM,
01998 32, PropModeReplace, ( unsigned char* )&version, 1 );
01999 XChangeProperty( qt_xdisplay(), electric_bottom_border, atoms->xdnd_aware, XA_ATOM,
02000 32, PropModeReplace, ( unsigned char* )&version, 1 );
02001 XChangeProperty( qt_xdisplay(), electric_left_border, atoms->xdnd_aware, XA_ATOM,
02002 32, PropModeReplace, ( unsigned char* )&version, 1 );
02003 XChangeProperty( qt_xdisplay(), electric_right_border, atoms->xdnd_aware, XA_ATOM,
02004 32, PropModeReplace, ( unsigned char* )&version, 1 );
02005 }
02006
02007
02008
02009
02010
02011
02012
02013 void Workspace::destroyBorderWindows()
02014 {
02015 if( !electric_have_borders)
02016 return;
02017
02018 electric_have_borders = false;
02019
02020 if(electric_top_border)
02021 XDestroyWindow(qt_xdisplay(),electric_top_border);
02022 if(electric_bottom_border)
02023 XDestroyWindow(qt_xdisplay(),electric_bottom_border);
02024 if(electric_left_border)
02025 XDestroyWindow(qt_xdisplay(),electric_left_border);
02026 if(electric_right_border)
02027 XDestroyWindow(qt_xdisplay(),electric_right_border);
02028
02029 electric_top_border = None;
02030 electric_bottom_border = None;
02031 electric_left_border = None;
02032 electric_right_border = None;
02033 }
02034
02035 void Workspace::clientMoved(const QPoint &pos, Time now)
02036 {
02037 if (options->electricBorders() == Options::ElectricDisabled)
02038 return;
02039
02040 if ((pos.x() != electricLeft) &&
02041 (pos.x() != electricRight) &&
02042 (pos.y() != electricTop) &&
02043 (pos.y() != electricBottom))
02044 return;
02045
02046 Time treshold_set = options->electricBorderDelay();
02047 Time treshold_reset = 250;
02048 int distance_reset = 30;
02049
02050 int border = 0;
02051 if (pos.x() == electricLeft)
02052 border = 1;
02053 else if (pos.x() == electricRight)
02054 border = 2;
02055 else if (pos.y() == electricTop)
02056 border = 3;
02057 else if (pos.y() == electricBottom)
02058 border = 4;
02059
02060 if ((electric_current_border == border) &&
02061 (timestampDiff(electric_time_last, now) < treshold_reset) &&
02062 ((pos-electric_push_point).manhattanLength() < distance_reset))
02063 {
02064 electric_time_last = now;
02065
02066 if (timestampDiff(electric_time_first, now) > treshold_set)
02067 {
02068 electric_current_border = 0;
02069
02070 QRect r = QApplication::desktop()->geometry();
02071 int offset;
02072
02073 int desk_before = currentDesktop();
02074 switch(border)
02075 {
02076 case 1:
02077 slotSwitchDesktopLeft();
02078 if (currentDesktop() != desk_before)
02079 {
02080 offset = r.width() / 5;
02081 QCursor::setPos(r.width() - offset, pos.y());
02082 }
02083 break;
02084
02085 case 2:
02086 slotSwitchDesktopRight();
02087 if (currentDesktop() != desk_before)
02088 {
02089 offset = r.width() / 5;
02090 QCursor::setPos(offset, pos.y());
02091 }
02092 break;
02093
02094 case 3:
02095 slotSwitchDesktopUp();
02096 if (currentDesktop() != desk_before)
02097 {
02098 offset = r.height() / 5;
02099 QCursor::setPos(pos.x(), r.height() - offset);
02100 }
02101 break;
02102
02103 case 4:
02104 slotSwitchDesktopDown();
02105 if (currentDesktop() != desk_before)
02106 {
02107 offset = r.height() / 5;
02108 QCursor::setPos(pos.x(), offset);
02109 }
02110 break;
02111 }
02112 return;
02113 }
02114 }
02115 else
02116 {
02117 electric_current_border = border;
02118 electric_time_first = now;
02119 electric_time_last = now;
02120 electric_push_point = pos;
02121 }
02122
02123 int mouse_warp = 1;
02124
02125
02126 switch( border)
02127 {
02128 case 1: QCursor::setPos(pos.x()+mouse_warp, pos.y()); break;
02129 case 2: QCursor::setPos(pos.x()-mouse_warp, pos.y()); break;
02130 case 3: QCursor::setPos(pos.x(), pos.y()+mouse_warp); break;
02131 case 4: QCursor::setPos(pos.x(), pos.y()-mouse_warp); break;
02132 }
02133 }
02134
02135
02136
02137 bool Workspace::electricBorder(XEvent *e)
02138 {
02139 if( !electric_have_borders )
02140 return false;
02141 if( e->type == EnterNotify )
02142 {
02143 if( e->xcrossing.window == electric_top_border ||
02144 e->xcrossing.window == electric_left_border ||
02145 e->xcrossing.window == electric_bottom_border ||
02146 e->xcrossing.window == electric_right_border)
02147
02148 {
02149 clientMoved( QPoint( e->xcrossing.x_root, e->xcrossing.y_root ), e->xcrossing.time );
02150 return true;
02151 }
02152 }
02153 if( e->type == ClientMessage )
02154 {
02155 if( e->xclient.message_type == atoms->xdnd_position
02156 && ( e->xclient.window == electric_top_border
02157 || e->xclient.window == electric_bottom_border
02158 || e->xclient.window == electric_left_border
02159 || e->xclient.window == electric_right_border ))
02160 {
02161 updateXTime();
02162 clientMoved( QPoint( e->xclient.data.l[2]>>16, e->xclient.data.l[2]&0xffff), qt_x_time );
02163 return true;
02164 }
02165 }
02166 return false;
02167 }
02168
02169
02170
02171
02172 void Workspace::raiseElectricBorders()
02173 {
02174
02175 if(electric_have_borders)
02176 {
02177 XRaiseWindow(qt_xdisplay(), electric_top_border);
02178 XRaiseWindow(qt_xdisplay(), electric_left_border);
02179 XRaiseWindow(qt_xdisplay(), electric_bottom_border);
02180 XRaiseWindow(qt_xdisplay(), electric_right_border);
02181 }
02182 }
02183
02184 void Workspace::addTopMenu( Client* c )
02185 {
02186 assert( c->isTopMenu());
02187 assert( !topmenus.contains( c ));
02188 topmenus.append( c );
02189 if( managingTopMenus())
02190 {
02191 int minsize = c->minSize().height();
02192 if( minsize > topMenuHeight())
02193 {
02194 topmenu_height = minsize;
02195 updateTopMenuGeometry();
02196 }
02197 updateTopMenuGeometry( c );
02198 updateCurrentTopMenu();
02199 }
02200
02201 }
02202
02203 void Workspace::removeTopMenu( Client* c )
02204 {
02205
02206
02207 assert( c->isTopMenu());
02208 assert( topmenus.contains( c ));
02209 topmenus.remove( c );
02210 updateCurrentTopMenu();
02211
02212 }
02213
02214 void Workspace::lostTopMenuSelection()
02215 {
02216
02217
02218 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02219 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02220 if( !managing_topmenus )
02221 return;
02222 connect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02223 disconnect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02224 managing_topmenus = false;
02225 delete topmenu_space;
02226 topmenu_space = NULL;
02227 updateClientArea();
02228 for( ClientList::ConstIterator it = topmenus.begin();
02229 it != topmenus.end();
02230 ++it )
02231 (*it)->checkWorkspacePosition();
02232 }
02233
02234 void Workspace::lostTopMenuOwner()
02235 {
02236 if( !options->topMenuEnabled())
02237 return;
02238
02239 if( !topmenu_selection->claim( false ))
02240 {
02241
02242 return;
02243 }
02244
02245 setupTopMenuHandling();
02246 }
02247
02248 void Workspace::setupTopMenuHandling()
02249 {
02250 if( managing_topmenus )
02251 return;
02252 connect( topmenu_selection, SIGNAL( lostOwnership()), this, SLOT( lostTopMenuSelection()));
02253 disconnect( topmenu_watcher, SIGNAL( lostOwner()), this, SLOT( lostTopMenuOwner()));
02254 managing_topmenus = true;
02255 topmenu_space = new QWidget;
02256 Window stack[ 2 ];
02257 stack[ 0 ] = supportWindow->winId();
02258 stack[ 1 ] = topmenu_space->winId();
02259 XRestackWindows(qt_xdisplay(), stack, 2);
02260 updateTopMenuGeometry();
02261 topmenu_space->show();
02262 updateClientArea();
02263 updateCurrentTopMenu();
02264 }
02265
02266 int Workspace::topMenuHeight() const
02267 {
02268 if( topmenu_height == 0 )
02269 {
02270 KMenuBar tmpmenu;
02271 tmpmenu.insertItem( "dummy" );
02272 topmenu_height = tmpmenu.sizeHint().height();
02273 }
02274 return topmenu_height;
02275 }
02276
02277 KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
02278 {
02279 return mgr->createDecoration( bridge );
02280 }
02281
02282 QString Workspace::desktopName( int desk ) const
02283 {
02284 return QString::fromUtf8( rootInfo->desktopName( desk ) );
02285 }
02286
02287 bool Workspace::checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data )
02288 {
02289 return startup->checkStartup( w, id, data ) == KStartupInfo::Match;
02290 }
02291
02296 void Workspace::focusToNull()
02297 {
02298 XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, qt_x_time );
02299 }
02300
02301 void Workspace::helperDialog( const QString& message, const Client* c )
02302 {
02303 QStringList args;
02304 QString type;
02305 if( message == "noborderaltf3" )
02306 {
02307 QString shortcut = QString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02308 .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02309 args << "--msgbox" <<
02310 i18n( "You have selected to show a window without its border.\n"
02311 "Without the border, you will not be able to enable the border "
02312 "again using the mouse: use the window operations menu instead, "
02313 "activated using the %1 keyboard shortcut." )
02314 .arg( shortcut );
02315 type = "altf3warning";
02316 }
02317 else if( message == "fullscreenaltf3" )
02318 {
02319 QString shortcut = QString( "%1 (%2)" ).arg( keys->label( "Window Operations Menu" ))
02320 .arg( keys->shortcut( "Window Operations Menu" ).seq( 0 ).toString());
02321 args << "--msgbox" <<
02322 i18n( "You have selected to show a window in fullscreen mode.\n"
02323 "If the application itself does not have an option to turn the fullscreen "
02324 "mode off you will not be able to disable it "
02325 "again using the mouse: use the window operations menu instead, "
02326 "activated using the %1 keyboard shortcut." )
02327 .arg( shortcut );
02328 type = "altf3warning";
02329 }
02330 else
02331 assert( false );
02332 KProcess proc;
02333 proc << "kdialog" << args;
02334 if( !type.isEmpty())
02335 {
02336 KConfig cfg( "kwin_dialogsrc" );
02337 cfg.setGroup( "Notification Messages" );
02338 if( !cfg.readBoolEntry( type, true ))
02339 return;
02340 proc << "--dontagain" << "kwin_dialogsrc:" + type;
02341 }
02342 if( c != NULL )
02343 proc << "--embed" << QString::number( c->window());
02344 proc.start( KProcess::DontCare );
02345 }
02346
02347
02348
02349
02350 void Workspace::startKompmgr()
02351 {
02352 if (!kompmgr || kompmgr->isRunning())
02353 return;
02354 if (!kompmgr->start(KProcess::OwnGroup, KProcess::Stderr))
02355 {
02356 options->useTranslucency = FALSE;
02357 KProcess proc;
02358 proc << "kdialog" << "--error"
02359 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02360 << "--title" << "Composite Manager Failure";
02361 proc.start(KProcess::DontCare);
02362 }
02363 else
02364 {
02365 connect(kompmgr, SIGNAL(processExited(KProcess*)), SLOT(restartKompmgr()));
02366 options->useTranslucency = TRUE;
02367 allowKompmgrRestart = FALSE;
02368 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02369 QByteArray ba;
02370 QDataStream arg(ba, IO_WriteOnly);
02371 arg << "";
02372 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStarted()", ba);
02373 }
02374 if (popup){ delete popup; popup = 0L; }
02375 }
02376
02377 void Workspace::stopKompmgr()
02378 {
02379 if (!kompmgr || !kompmgr->isRunning())
02380 return;
02381 kompmgr->disconnect(this, SLOT(restartKompmgr()));
02382 options->useTranslucency = FALSE;
02383 if (popup){ delete popup; popup = 0L; }
02384 kompmgr->kill();
02385 QByteArray ba;
02386 QDataStream arg(ba, IO_WriteOnly);
02387 arg << "";
02388 kapp->dcopClient()->emitDCOPSignal("default", "kompmgrStopped()", ba);
02389 }
02390
02391 bool Workspace::kompmgrIsRunning()
02392 {
02393 return kompmgr && kompmgr->isRunning();
02394 }
02395
02396 void Workspace::unblockKompmgrRestart()
02397 {
02398 allowKompmgrRestart = TRUE;
02399 }
02400
02401 void Workspace::restartKompmgr()
02402
02403 {
02404 if (!allowKompmgrRestart)
02405 {
02406 options->useTranslucency = FALSE;
02407 KProcess proc;
02408 proc << "kdialog" << "--error"
02409 << i18n( "The Composite Manager crashed twice within a minute and is therefore disabled for this session.")
02410 << "--title" << i18n("Composite Manager Failure");
02411 proc.start(KProcess::DontCare);
02412 return;
02413 }
02414 if (!kompmgr)
02415 return;
02416
02417
02418
02419
02420
02421
02422
02423
02424 if (!kompmgr->start(KProcess::NotifyOnExit, KProcess::Stderr))
02425 {
02426 options->useTranslucency = FALSE;
02427 KProcess proc;
02428 proc << "kdialog" << "--error"
02429 << i18n("The Composite Manager could not be started.\\nMake sure you have \"kompmgr\" in a $PATH directory.")
02430 << "--title" << i18n("Composite Manager Failure");
02431 proc.start(KProcess::DontCare);
02432 }
02433 else
02434 {
02435 allowKompmgrRestart = FALSE;
02436 QTimer::singleShot( 60000, this, SLOT(unblockKompmgrRestart()) );
02437 }
02438 }
02439
02440 void Workspace::handleKompmgrOutput( KProcess* , char *buffer, int buflen)
02441 {
02442 QString message;
02443 QString output = QString::fromLocal8Bit( buffer, buflen );
02444 if (output.contains("Started",false))
02445 ;
02446 else if (output.contains("Can't open display",false))
02447 message = i18n("<qt><b>kompmgr failed to open the display</b><br>There is probably an invalid display entry in your ~/.xcompmgrrc.</qt>");
02448 else if (output.contains("No render extension",false))
02449 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>");
02450 else if (output.contains("No composite extension",false))
02451 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>"
02452 "<i>Section \"Extensions\"<br>"
02453 "Option \"Composite\" \"Enable\"<br>"
02454 "EndSection</i></qt>");
02455 else if (output.contains("No damage extension",false))
02456 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>");
02457 else if (output.contains("No XFixes extension",false))
02458 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>");
02459 else return;
02460
02461 kompmgr->closeStderr();
02462 disconnect(kompmgr, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(handleKompmgrOutput(KProcess*, char*, int)));
02463 if( !message.isEmpty())
02464 {
02465 KProcess proc;
02466 proc << "kdialog" << "--error"
02467 << message
02468 << "--title" << i18n("Composite Manager Failure");
02469 proc.start(KProcess::DontCare);
02470 }
02471 }
02472
02473
02474 void Workspace::setOpacity(unsigned long winId, unsigned int opacityPercent)
02475 {
02476 if (opacityPercent > 100) opacityPercent = 100;
02477 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02478 if (winId == (*it)->window())
02479 {
02480 (*it)->setOpacity(opacityPercent < 100, (unsigned int)((opacityPercent/100.0)*0xFFFFFFFF));
02481 return;
02482 }
02483 }
02484
02485 void Workspace::setShadowSize(unsigned long winId, unsigned int shadowSizePercent)
02486 {
02487
02488 if (shadowSizePercent > 400) shadowSizePercent = 400;
02489 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02490 if (winId == (*it)->window())
02491 {
02492 (*it)->setShadowSize(shadowSizePercent);
02493 return;
02494 }
02495 }
02496
02497 void Workspace::setUnshadowed(unsigned long winId)
02498 {
02499 for( ClientList::ConstIterator it = stackingOrder().begin(); it != stackingOrder().end(); it++ )
02500 if (winId == (*it)->window())
02501 {
02502 (*it)->setShadowSize(0);
02503 return;
02504 }
02505 }
02506
02507 void Workspace::setShowingDesktop( bool showing )
02508 {
02509 rootInfo->setShowingDesktop( showing );
02510 showing_desktop = showing;
02511 ++block_showing_desktop;
02512 if( showing_desktop )
02513 {
02514 showing_desktop_clients.clear();
02515 ++block_focus;
02516 ClientList cls = stackingOrder();
02517
02518
02519 for( ClientList::ConstIterator it = cls.begin();
02520 it != cls.end();
02521 ++it )
02522 {
02523 if( (*it)->isOnCurrentDesktop() && (*it)->isShown( true ) && !(*it)->isSpecialWindow())
02524 showing_desktop_clients.prepend( *it );
02525 }
02526 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02527 it != showing_desktop_clients.end();
02528 ++it )
02529 (*it)->minimize(true);
02530 --block_focus;
02531 if( Client* desk = findDesktop( true, currentDesktop()))
02532 requestFocus( desk );
02533 }
02534 else
02535 {
02536 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02537 it != showing_desktop_clients.end();
02538 ++it )
02539 (*it)->unminimize(true);
02540 if( showing_desktop_clients.count() > 0 )
02541 requestFocus( showing_desktop_clients.first());
02542 showing_desktop_clients.clear();
02543 }
02544 --block_showing_desktop;
02545 }
02546
02547
02548
02549
02550
02551
02552
02553 void Workspace::resetShowingDesktop( bool keep_hidden )
02554 {
02555 if( block_showing_desktop > 0 )
02556 return;
02557 rootInfo->setShowingDesktop( false );
02558 showing_desktop = false;
02559 ++block_showing_desktop;
02560 if( !keep_hidden )
02561 {
02562 for( ClientList::ConstIterator it = showing_desktop_clients.begin();
02563 it != showing_desktop_clients.end();
02564 ++it )
02565 (*it)->unminimize(true);
02566 }
02567 showing_desktop_clients.clear();
02568 --block_showing_desktop;
02569 }
02570
02571
02572
02573
02574
02575
02576
02577
02578 void Workspace::slotDisableGlobalShortcuts()
02579 {
02580 if( global_shortcuts_disabled || global_shortcuts_disabled_for_client )
02581 disableGlobalShortcuts( false );
02582 else
02583 disableGlobalShortcuts( true );
02584 }
02585
02586 static bool pending_dfc = false;
02587
02588 void Workspace::disableGlobalShortcutsForClient( bool disable )
02589 {
02590 if( global_shortcuts_disabled_for_client == disable )
02591 return;
02592 if( !global_shortcuts_disabled )
02593 {
02594 if( disable )
02595 pending_dfc = true;
02596 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02597
02598 }
02599 }
02600
02601 void Workspace::disableGlobalShortcuts( bool disable )
02602 {
02603 KIPC::sendMessageAll( KIPC::BlockShortcuts, disable );
02604
02605 }
02606
02607 void Workspace::kipcMessage( int id, int data )
02608 {
02609 if( id != KIPC::BlockShortcuts )
02610 return;
02611 if( pending_dfc && data )
02612 {
02613 global_shortcuts_disabled_for_client = true;
02614 pending_dfc = false;
02615 }
02616 else
02617 {
02618 global_shortcuts_disabled = data;
02619 global_shortcuts_disabled_for_client = false;
02620 }
02621
02622 for( ClientList::ConstIterator it = clients.begin();
02623 it != clients.end();
02624 ++it )
02625 (*it)->updateMouseGrab();
02626 }
02627
02628 }
02629
02630 #include "workspace.moc"