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