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