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"