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