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