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