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