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 addTopMenu( c );
00448 updateClientArea();
00449 updateClientLayer( c );
00450
if( c->isDesktop())
00451 {
00452 raiseClient( c );
00453
00454
if( activeClient() == NULL && should_get_focus.count() == 0 )
00455 activateClient( findDesktop(
true, currentDesktop()));
00456 }
00457
if( c->isUtility() || c->isMenu() || c->isToolbar())
00458 updateToolWindows(
true );
00459 checkTransients( c->window());
00460 updateStackingOrder(
true );
00461 }
00462
00463
00464
00465
00466
void Workspace::removeClient( Client* c, allowed_t )
00467 {
00468
if (c == active_client && popup)
00469 popup->close();
00470
if( c == popup_client )
00471 popup_client = 0;
00472
00473
if( c->isDialog())
00474 Notify::raise( Notify::TransDelete );
00475
if( c->isNormalWindow())
00476 Notify::raise( Notify::Delete );
00477
00478 storeFakeSessionInfo( c );
00479
00480 Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
00481 clients.remove( c );
00482 desktops.remove( c );
00483 unconstrained_stacking_order.remove( c );
00484 stacking_order.remove( c );
00485 focus_chain.remove( c );
00486 attention_chain.remove( c );
00487
if( c->isTopMenu())
00488 removeTopMenu( c );
00489 Group* group = findGroup( c->window());
00490
if( group != NULL )
00491 group->lostLeader();
00492
00493
if ( c == most_recently_raised )
00494 most_recently_raised = 0;
00495 should_get_focus.remove( c );
00496 Q_ASSERT( c != active_client );
00497
if ( c == last_active_client )
00498 last_active_client = 0;
00499
00500 updateStackingOrder(
true );
00501
00502
if (tab_grab)
00503 tab_box->repaint();
00504
00505 updateClientArea();
00506 }
00507
00508
void Workspace::updateCurrentTopMenu()
00509 {
00510
if( !managingTopMenus())
00511
return;
00512
00513
Client* menubar = 0;
00514
bool block_desktop_menubar =
false;
00515
if( active_client )
00516 {
00517
00518
Client* menu_client = active_client;
00519
for(;;)
00520 {
00521
if( menu_client->isFullScreen())
00522 block_desktop_menubar =
true;
00523
for( ClientList::ConstIterator it = menu_client->transients().begin();
00524 it != menu_client->transients().end();
00525 ++it )
00526
if( (*it)->isTopMenu())
00527 {
00528 menubar = *it;
00529
break;
00530 }
00531
if( menubar != NULL || !menu_client->isTransient())
00532
break;
00533
if( menu_client->isModal() || menu_client->transientFor() == NULL )
00534
break;
00535 menu_client = menu_client->transientFor();
00536 }
00537
if( !menubar )
00538 {
00539
for( ClientList::ConstIterator it = active_client->group()->members().begin();
00540 it != active_client->group()->members().end();
00541 ++it )
00542
if( (*it)->isTopMenu())
00543 {
00544 menubar = *it;
00545
break;
00546 }
00547 }
00548 }
00549
if( !menubar && !block_desktop_menubar && options->desktopTopMenu())
00550 {
00551
00552
Client*
desktop = findDesktop(
true, currentDesktop());
00553
if( desktop != NULL )
00554 {
00555
for( ClientList::ConstIterator it = desktop->transients().begin();
00556 it != desktop->transients().end();
00557 ++it )
00558
if( (*it)->isTopMenu())
00559 {
00560 menubar = *it;
00561
break;
00562 }
00563 }
00564
00565
00566
00567
if( menubar == NULL )
00568 {
00569
for( ClientList::ConstIterator it = topmenus.begin();
00570 it != topmenus.end();
00571 ++it )
00572
if( (*it)->wasOriginallyGroupTransient())
00573 {
00574 menubar = *it;
00575
break;
00576 }
00577 }
00578 }
00579
00580
00581
if ( menubar )
00582 {
00583
if( active_client && !menubar->isOnDesktop( active_client->desktop()))
00584 menubar->setDesktop( active_client->desktop());
00585 menubar->hideClient(
false );
00586 topmenu_space->hide();
00587
00588
00589
00590 unconstrained_stacking_order.remove( menubar );
00591 unconstrained_stacking_order.append( menubar );
00592 }
00593
else if( !block_desktop_menubar )
00594 {
00595 topmenu_space->show();
00596 }
00597
00598
00599
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00600 {
00601
if( (*it)->isTopMenu() && (*it) != menubar )
00602 (*it)->hideClient(
true );
00603 }
00604 }
00605
00606
00607
void Workspace::updateToolWindows(
bool also_hide )
00608 {
00609
00610
const Group* group = NULL;
00611
const Client* client = active_client;
00612
00613
00614
while( client != NULL )
00615 {
00616
if( !client->isTransient())
00617
break;
00618
if( client->groupTransient())
00619 {
00620 group = client->group();
00621
break;
00622 }
00623 client = client->transientFor();
00624 }
00625
00626
00627
00628
00629 ClientList to_show, to_hide;
00630
for( ClientList::ConstIterator it = stacking_order.begin();
00631 it != stacking_order.end();
00632 ++it )
00633 {
00634
if( (*it)->isUtility() || (*it)->isMenu() || (*it)->isToolbar())
00635 {
00636
bool show =
true;
00637
if( !(*it)->isTransient())
00638 {
00639
if( (*it)->group()->members().count() == 1 )
00640 show =
true;
00641
else if( client != NULL && (*it)->group() == client->group())
00642 show =
true;
00643
else
00644 show =
false;
00645 }
00646
else
00647 {
00648
if( group != NULL && (*it)->group() == group )
00649 show =
true;
00650
else if( client != NULL && client->hasTransient( (*it),
true ))
00651 show =
true;
00652
else
00653 show =
false;
00654 }
00655
if( show )
00656 to_show.append( *it );
00657
else if( also_hide )
00658 to_hide.append( *it );
00659 }
00660 }
00661
for( ClientList::ConstIterator it = to_show.fromLast();
00662 it != to_show.end();
00663 --it )
00664
00665 (*it)->hideClient(
false );
00666
if( also_hide )
00667 {
00668
for( ClientList::ConstIterator it = to_hide.begin();
00669 it != to_hide.end();
00670 ++it )
00671 (*it)->hideClient(
true );
00672 updateToolWindowsTimer.stop();
00673 }
00674
else
00675 {
00676 updateToolWindowsTimer.start( 50,
true );
00677 }
00678 }
00679
00680
void Workspace::slotUpdateToolWindows()
00681 {
00682 updateToolWindows(
true );
00683 }
00684
00688
void Workspace::updateColormap()
00689 {
00690 Colormap cmap = default_colormap;
00691
if ( activeClient() && activeClient()->colormap() != None )
00692 cmap = activeClient()->colormap();
00693
if ( cmap != installed_colormap )
00694 {
00695 XInstallColormap(qt_xdisplay(), cmap );
00696 installed_colormap = cmap;
00697 }
00698 }
00699
00700
void Workspace::reconfigure()
00701 {
00702 reconfigureTimer.start(200,
true);
00703 }
00704
00705
00706
void Workspace::slotSettingsChanged(
int category)
00707 {
00708 kdDebug(1212) <<
"Workspace::slotSettingsChanged()" << endl;
00709
if( category == (
int) KApplication::SETTINGS_SHORTCUTS )
00710 readShortcuts();
00711 }
00712
00716 KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
00717
00718
void Workspace::slotReconfigure()
00719 {
00720 kdDebug(1212) <<
"Workspace::slotReconfigure()" << endl;
00721 reconfigureTimer.stop();
00722
00723 KGlobal::config()->reparseConfiguration();
00724
unsigned long changed = options->updateSettings();
00725 tab_box->reconfigure();
00726 popupinfo->reconfigure();
00727 readShortcuts();
00728 forEachClient( CheckIgnoreFocusStealingProcedure());
00729
00730
if( mgr->reset( changed ))
00731 {
00732
#if 0 // This actually seems to make things worse now
00733
QWidget curtain;
00734 curtain.setBackgroundMode( NoBackground );
00735 curtain.setGeometry( QApplication::desktop()->geometry() );
00736 curtain.show();
00737
#endif
00738
for( ClientList::ConstIterator it = clients.begin();
00739 it != clients.end();
00740 ++it )
00741 {
00742 (*it)->updateDecoration(
true,
true );
00743 }
00744 mgr->destroyPreviousPlugin();
00745 }
00746
else
00747 {
00748 forEachClient( CheckBorderSizesProcedure());
00749 }
00750
00751
if (options->electricBorders() == Options::ElectricAlways)
00752 createBorderWindows();
00753
else
00754 destroyBorderWindows();
00755
00756
if( options->topMenuEnabled() && !managingTopMenus())
00757 {
00758
if( topmenu_selection->claim(
false ))
00759 setupTopMenuHandling();
00760
else
00761 lostTopMenuSelection();
00762 }
00763
else if( !options->topMenuEnabled() && managingTopMenus())
00764 {
00765 topmenu_selection->release();
00766 lostTopMenuSelection();
00767 }
00768 topmenu_height = 0;
00769
if( managingTopMenus())
00770 {
00771 updateTopMenuGeometry();
00772 updateCurrentTopMenu();
00773 }
00774 }
00775
00776
void Workspace::loadDesktopSettings()
00777 {
00778 KConfig c(
"kwinrc");
00779
00780 QCString groupname;
00781
if (screen_number == 0)
00782 groupname =
"Desktops";
00783
else
00784 groupname.sprintf(
"Desktops-screen-%d", screen_number);
00785 c.setGroup(groupname);
00786
00787
int n = c.readNumEntry(
"Number", 4);
00788 number_of_desktops = n;
00789
delete workarea;
00790 workarea =
new QRect[ n + 1 ];
00791 rootInfo->setNumberOfDesktops( number_of_desktops );
00792 desktop_focus_chain.resize( n );
00793
for(
int i = 1; i <= n; i++)
00794 {
00795 QString s = c.readEntry(QString(
"Name_%1").arg(i),
00796 i18n(
"Desktop %1").arg(i));
00797 rootInfo->setDesktopName( i, s.utf8().data() );
00798 desktop_focus_chain[i-1] = i;
00799 }
00800 }
00801
00802
void Workspace::saveDesktopSettings()
00803 {
00804 KConfig c(
"kwinrc");
00805
00806 QCString groupname;
00807
if (screen_number == 0)
00808 groupname =
"Desktops";
00809
else
00810 groupname.sprintf(
"Desktops-screen-%d", screen_number);
00811 c.setGroup(groupname);
00812
00813 c.writeEntry(
"Number", number_of_desktops );
00814
for(
int i = 1; i <= number_of_desktops; i++)
00815 {
00816 QString s = desktopName( i );
00817 QString defaultvalue = i18n(
"Desktop %1").arg(i);
00818
if ( s.isEmpty() )
00819 {
00820 s = defaultvalue;
00821 rootInfo->setDesktopName( i, s.utf8().data() );
00822 }
00823
00824
if (s != defaultvalue)
00825 {
00826 c.writeEntry( QString(
"Name_%1").arg(i), s );
00827 }
00828
else
00829 {
00830 QString currentvalue = c.readEntry(QString(
"Name_%1").arg(i));
00831
if (currentvalue != defaultvalue)
00832 c.writeEntry( QString(
"Name_%1").arg(i),
"" );
00833 }
00834 }
00835 }
00836
00837 QStringList Workspace::configModules(
bool controlCenter)
00838 {
00839 QStringList args;
00840 args <<
"kde-kwindecoration.desktop";
00841
if (controlCenter)
00842 args <<
"kde-kwinoptions.desktop";
00843
else if (kapp->authorizeControlModule(
"kde-kwinoptions.desktop"))
00844 args <<
"kwinactions" <<
"kwinfocus" <<
"kwinmoving" <<
"kwinadvanced";
00845
return args;
00846 }
00847
00848
void Workspace::configureWM()
00849 {
00850 KApplication::kdeinitExec(
"kcmshell", configModules(
false) );
00851 }
00852
00856
void Workspace::doNotManage( QString title )
00857 {
00858 doNotManageList.append( title );
00859 }
00860
00864
bool Workspace::isNotManaged(
const QString& title )
00865 {
00866
for ( QStringList::Iterator it = doNotManageList.begin(); it != doNotManageList.end(); ++it )
00867 {
00868 QRegExp r( (*it) );
00869
if (r.search(title) != -1)
00870 {
00871 doNotManageList.remove( it );
00872
return TRUE;
00873 }
00874 }
00875
return FALSE;
00876 }
00877
00881
void Workspace::refresh()
00882 {
00883 QWidget w;
00884 w.setGeometry( QApplication::desktop()->geometry() );
00885 w.show();
00886 w.hide();
00887 QApplication::flushX();
00888 }
00889
00897
class ObscuringWindows
00898 {
00899
public:
00900 ~ObscuringWindows();
00901
void create( Client* c );
00902
private:
00903 QValueList<Window> obscuring_windows;
00904
static QValueList<Window>* cached;
00905
static unsigned int max_cache_size;
00906 };
00907
00908 QValueList<Window>* ObscuringWindows::cached = 0;
00909
unsigned int ObscuringWindows::max_cache_size = 0;
00910
00911
void ObscuringWindows::create( Client* c )
00912 {
00913
if( cached == 0 )
00914 cached =
new QValueList<Window>;
00915 Window obs_win;
00916 XWindowChanges chngs;
00917
int mask = CWSibling | CWStackMode;
00918
if( cached->count() > 0 )
00919 {
00920 cached->remove( obs_win = cached->first());
00921 chngs.x = c->x();
00922 chngs.y = c->y();
00923 chngs.width = c->width();
00924 chngs.height = c->height();
00925 mask |= CWX | CWY | CWWidth | CWHeight;
00926 }
00927
else
00928 {
00929 XSetWindowAttributes a;
00930 a.background_pixmap = None;
00931 a.override_redirect = True;
00932 obs_win = XCreateWindow( qt_xdisplay(), qt_xrootwin(), c->x(), c->y(),
00933 c->width(), c->height(), 0, CopyFromParent, InputOutput,
00934 CopyFromParent, CWBackPixmap | CWOverrideRedirect, &a );
00935 }
00936 chngs.sibling = c->frameId();
00937 chngs.stack_mode = Below;
00938 XConfigureWindow( qt_xdisplay(), obs_win, mask, &chngs );
00939 XMapWindow( qt_xdisplay(), obs_win );
00940 obscuring_windows.append( obs_win );
00941 }
00942
00943 ObscuringWindows::~ObscuringWindows()
00944 {
00945 max_cache_size = QMAX( max_cache_size, obscuring_windows.count() + 4 ) - 1;
00946
for( QValueList<Window>::ConstIterator it = obscuring_windows.begin();
00947 it != obscuring_windows.end();
00948 ++it )
00949 {
00950 XUnmapWindow( qt_xdisplay(), *it );
00951
if( cached->count() < max_cache_size )
00952 cached->prepend( *it );
00953
else
00954 XDestroyWindow( qt_xdisplay(), *it );
00955 }
00956 }
00957
00958
00965
bool Workspace::setCurrentDesktop(
int new_desktop )
00966 {
00967
if (new_desktop < 1 || new_desktop > number_of_desktops )
00968
return false;
00969
00970
if( popup )
00971 popup->close();
00972 ++block_focus;
00973
00974 StackingUpdatesBlocker blocker(
this );
00975
00976
if (new_desktop != current_desktop)
00977 {
00978
00979
00980
00981
00982 Notify::raise((Notify::Event) (Notify::DesktopChange+new_desktop));
00983
00984 ObscuringWindows obs_wins;
00985
00986
int old_desktop = current_desktop;
00987 current_desktop = new_desktop;
00988
00989
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00990
if ( !(*it)->isOnDesktop( new_desktop ) && (*it) != movingClient )
00991 {
00992
if( (*it)->isShown(
true ) && (*it)->isOnDesktop( old_desktop ))
00993 obs_wins.create( *it );
00994 (*it)->virtualDesktopChange();
00995 }
00996
00997 rootInfo->setCurrentDesktop( current_desktop );
00998
00999
if( movingClient && !movingClient->isOnDesktop( new_desktop ))
01000 movingClient->setDesktop( new_desktop );
01001
01002
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
01003
if ( (*it)->isOnDesktop( new_desktop ) )
01004 (*it)->virtualDesktopChange();
01005 }
01006
01007
01008 --block_focus;
01009
Client* c = 0;
01010
01011
if ( options->focusPolicyIsReasonable())
01012 {
01013
01014
01015
if ( focus_chain.contains( active_client ) && active_client->isShown(
true )
01016 && active_client->isOnCurrentDesktop())
01017 {
01018 c = active_client;
01019 }
01020
01021
if ( !c )
01022 {
01023
for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it)
01024 {
01025
if ( (*it)->isShown(
false ) && !(*it)->isOnAllDesktops() && (*it)->isOnCurrentDesktop())
01026 {
01027 c = *it;
01028
break;
01029 }
01030 }
01031 }
01032
01033
if ( !c )
01034 {
01035
for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it)
01036 {
01037
if ( (*it)->isShown(
false ) && (*it)->isOnCurrentDesktop())
01038 {
01039 c = *it;
01040
break;
01041 }
01042 }
01043 }
01044 }
01045
01046
01047
01048
01049
else if( active_client && active_client->isShown(
true ) && active_client->isOnCurrentDesktop())
01050 c= active_client;
01051
01052
if( c != active_client )
01053 setActiveClient( NULL, Allowed );
01054
01055
if ( c )
01056 requestFocus( c );
01057
else
01058 focusToNull();
01059
01060
if( !desktops.isEmpty() )
01061 {
01062 Window w_tmp;
01063
int i_tmp;
01064 XGetInputFocus( qt_xdisplay(), &w_tmp, &i_tmp );
01065
if( w_tmp == null_focus_window )
01066 requestFocus( findDesktop(
true, currentDesktop()));
01067 }
01068
01069
01070
01071
01072
01073
01074
for(
int i = desktop_focus_chain.find( current_desktop ); i > 0; i-- )
01075 desktop_focus_chain[i] = desktop_focus_chain[i-1];
01076 desktop_focus_chain[0] = current_desktop;
01077
01078
01079
01080
01081
01082
return true;
01083 }
01084
01085
void Workspace::nextDesktop()
01086 {
01087
int desktop = currentDesktop() + 1;
01088 setCurrentDesktop(desktop > numberOfDesktops() ? 1 : desktop);
01089 popupinfo->showInfo( desktopName(currentDesktop()) );
01090 }
01091
01092
void Workspace::previousDesktop()
01093 {
01094
int desktop = currentDesktop() - 1;
01095 setCurrentDesktop(desktop > 0 ? desktop : numberOfDesktops());
01096 popupinfo->showInfo( desktopName(currentDesktop()) );
01097 }
01098
01102
void Workspace::setNumberOfDesktops(
int n )
01103 {
01104
if ( n == number_of_desktops )
01105
return;
01106
int old_number_of_desktops = number_of_desktops;
01107 number_of_desktops = n;
01108
01109
if( currentDesktop() > numberOfDesktops())
01110 setCurrentDesktop( numberOfDesktops());
01111
01112
01113
01114
if( old_number_of_desktops < number_of_desktops )
01115 {
01116 rootInfo->setNumberOfDesktops( number_of_desktops );
01117 NETPoint* viewports =
new NETPoint[ number_of_desktops ];
01118 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01119
delete[] viewports;
01120 updateClientArea(
true );
01121 }
01122
01123
01124
01125
if( old_number_of_desktops > number_of_desktops )
01126 {
01127
for( ClientList::ConstIterator it = clients.begin();
01128 it != clients.end();
01129 ++it)
01130 {
01131
if( !(*it)->isOnAllDesktops() && (*it)->desktop() > numberOfDesktops())
01132 sendClientToDesktop( *it, numberOfDesktops(),
true );
01133 }
01134 }
01135
if( old_number_of_desktops > number_of_desktops )
01136 {
01137 rootInfo->setNumberOfDesktops( number_of_desktops );
01138 NETPoint* viewports =
new NETPoint[ number_of_desktops ];
01139 rootInfo->setDesktopViewport( number_of_desktops, *viewports );
01140
delete[] viewports;
01141 updateClientArea(
true );
01142 }
01143
01144 saveDesktopSettings();
01145
01146
01147 desktop_focus_chain.resize( n );
01148
for(
int i = 0; i < (
int)desktop_focus_chain.size(); i++ )
01149 desktop_focus_chain[i] = i+1;
01150 }
01151
01157
void Workspace::sendClientToDesktop( Client* c,
int desk,
bool dont_activate )
01158 {
01159
if ( c->desktop() == desk )
01160
return;
01161
01162
bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
01163 c->setDesktop( desk );
01164 desk = c->desktop();
01165
01166
if ( c->isOnDesktop( currentDesktop() ) )
01167 {
01168
if ( c->wantsTabFocus() && options->focusPolicyIsReasonable()
01169 && !was_on_desktop
01170 && !dont_activate )
01171 requestFocus( c );
01172
else
01173 restackClientUnderActive( c );
01174 }
01175
else
01176 {
01177 raiseClient( c );
01178 focus_chain.remove( c );
01179
if ( c->wantsTabFocus() )
01180 focus_chain.append( c );
01181 }
01182
01183 ClientList transients_stacking_order = ensureStackingOrder( c->transients());
01184
for( ClientList::ConstIterator it = transients_stacking_order.begin();
01185 it != transients_stacking_order.end();
01186 ++it )
01187 sendClientToDesktop( *it, desk, dont_activate );
01188 updateClientArea();
01189 }
01190
01191
void Workspace::setDesktopLayout(
int o,
int x,
int y)
01192 {
01193 layoutOrientation = (Qt::Orientation) o;
01194 layoutX = x;
01195 layoutY = y;
01196 }
01197
01198
void Workspace::calcDesktopLayout(
int &x,
int &y)
01199 {
01200 x = layoutX;
01201 y = layoutY;
01202
if ((x == -1) && (y > 0))
01203 x = (numberOfDesktops()+y-1) / y;
01204
else if ((y == -1) && (x > 0))
01205 y = (numberOfDesktops()+x-1) / x;
01206
01207
if (x == -1)
01208 x = 1;
01209
if (y == -1)
01210 y = 1;
01211 }
01212
01217
bool Workspace::addSystemTrayWin( WId w )
01218 {
01219
if ( systemTrayWins.contains( w ) )
01220
return TRUE;
01221
01222 NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
01223 WId trayWinFor = ni.kdeSystemTrayWinFor();
01224
if ( !trayWinFor )
01225
return FALSE;
01226 systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
01227 XSelectInput( qt_xdisplay(), w,
01228 StructureNotifyMask
01229 );
01230 XAddToSaveSet( qt_xdisplay(), w );
01231 propagateSystemTrayWins();
01232
return TRUE;
01233 }
01234
01239
bool Workspace::removeSystemTrayWin( WId w,
bool check )
01240 {
01241
if ( !systemTrayWins.contains( w ) )
01242
return FALSE;
01243
if( check )
01244 {
01245
01246
01247
01248
01249
01250
01251
01252
int num_props;
01253 Atom* props = XListProperties( qt_xdisplay(), w, &num_props );
01254
if( props != NULL )
01255 {
01256
for(
int i = 0;
01257 i < num_props;
01258 ++i )
01259
if( props[ i ] == atoms->kde_system_tray_embedding )
01260 {
01261 XFree( props );
01262
return false;
01263 }
01264 XFree( props );
01265 }
01266 }
01267 systemTrayWins.remove( w );
01268 propagateSystemTrayWins();
01269
return TRUE;
01270 }
01271
01272
01276
void Workspace::propagateSystemTrayWins()
01277 {
01278 Window *cl =
new Window[ systemTrayWins.count()];
01279
01280
int i = 0;
01281
for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it )
01282 {
01283 cl[i++] = (*it).win;
01284 }
01285
01286 rootInfo->setKDESystemTrayWindows( cl, i );
01287
delete [] cl;
01288 }
01289
01290
01291
void Workspace::killWindowId( Window window_to_kill )
01292 {
01293
if( window_to_kill == None )
01294
return;
01295 Window window = window_to_kill;
01296
Client* client = NULL;
01297
for(;;)
01298 {
01299 client = findClient( FrameIdMatchPredicate( window ));
01300
if( client != NULL )
01301
break;
01302 Window parent, root;
01303 Window* children;
01304
unsigned int children_count;
01305 XQueryTree( qt_xdisplay(), window, &root, &parent, &children, &children_count );
01306
if( children != NULL )
01307 XFree( children );
01308
if( window == root )
01309
break;
01310 window = parent;
01311 }
01312
if( client != NULL )
01313 client->killWindow();
01314
else
01315 XKillClient( qt_xdisplay(), window_to_kill );
01316 }
01317
01318
01319
void Workspace::sendPingToWindow( Window window, Time timestamp )
01320 {
01321 rootInfo->sendPing( window, timestamp );
01322 }
01323
01324
01328
void Workspace::slotGrabWindow()
01329 {
01330
if ( active_client )
01331 {
01332 QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
01333
01334
01335
if( Shape::available())
01336 {
01337
01338
int count, order;
01339 XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), active_client->frameId(),
01340 ShapeBounding, &count, &order);
01341
01342
01343
01344
01345
if (rects)
01346 {
01347
01348 QRegion contents;
01349
for (
int pos = 0; pos < count; pos++)
01350 contents += QRegion(rects[pos].x, rects[pos].y,
01351 rects[pos].width, rects[pos].height);
01352 XFree(rects);
01353
01354
01355 QRegion bbox(0, 0, snapshot.width(), snapshot.height());
01356
01357
01358 QRegion maskedAway = bbox - contents;
01359 QMemArray<QRect> maskedAwayRects = maskedAway.rects();
01360
01361
01362 QBitmap mask( snapshot.width(), snapshot.height());
01363 QPainter p(&mask);
01364 p.fillRect(0, 0, mask.width(), mask.height(), Qt::color1);
01365
for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
01366 p.fillRect(maskedAwayRects[pos], Qt::color0);
01367 p.end();
01368 snapshot.setMask(mask);
01369 }
01370 }
01371
01372 QClipboard *cb = QApplication::clipboard();
01373 cb->setPixmap( snapshot );
01374 }
01375
else
01376 slotGrabDesktop();
01377 }
01378
01382
void Workspace::slotGrabDesktop()
01383 {
01384 QPixmap p = QPixmap::grabWindow( qt_xrootwin() );
01385 QClipboard *cb = QApplication::clipboard();
01386 cb->setPixmap( p );
01387 }
01388
01389
01393
void Workspace::slotMouseEmulation()
01394 {
01395
01396
if ( mouse_emulation )
01397 {
01398 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01399 mouse_emulation = FALSE;
01400
return;
01401 }
01402
01403
if ( XGrabKeyboard(qt_xdisplay(),
01404 root, FALSE,
01405 GrabModeAsync, GrabModeAsync,
01406 qt_x_time) == GrabSuccess )
01407 {
01408 mouse_emulation = TRUE;
01409 mouse_emulation_state = 0;
01410 mouse_emulation_window = 0;
01411 }
01412 }
01413
01420 WId Workspace::getMouseEmulationWindow()
01421 {
01422 Window root;
01423 Window child = qt_xrootwin();
01424
int root_x, root_y, lx, ly;
01425 uint state;
01426 Window w;
01427
Client * c = 0;
01428
do
01429 {
01430 w = child;
01431
if (!c)
01432 c = findClient( FrameIdMatchPredicate( w ));
01433 XQueryPointer( qt_xdisplay(), w, &root, &child,
01434 &root_x, &root_y, &lx, &ly, &state );
01435 }
while ( child != None && child != w );
01436
01437
if ( c && !c->isActive() )
01438 activateClient( c );
01439
return (WId) w;
01440 }
01441
01445
unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation type,
int button,
unsigned int state )
01446 {
01447
if ( !w )
01448
return state;
01449 QWidget* widget = QWidget::find( w );
01450
if ( (!widget || widget->inherits(
"QToolButton") ) && !findClient( WindowMatchPredicate( w )) )
01451 {
01452
int x, y;
01453 Window xw;
01454 XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
01455
if ( type == EmuMove )
01456 {
01457 XMotionEvent e;
01458 e.type = MotionNotify;
01459 e.window = w;
01460 e.root = qt_xrootwin();
01461 e.subwindow = w;
01462 e.time = qt_x_time;
01463 e.x = x;
01464 e.y = y;
01465 e.x_root = pos.x();
01466 e.y_root = pos.y();
01467 e.state = state;
01468 e.is_hint = NotifyNormal;
01469 XSendEvent( qt_xdisplay(), w, TRUE, ButtonMotionMask, (XEvent*)&e );
01470 }
01471
else
01472 {
01473 XButtonEvent e;
01474 e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
01475 e.window = w;
01476 e.root = qt_xrootwin();
01477 e.subwindow = w;
01478 e.time = qt_x_time;
01479 e.x = x;
01480 e.y = y;
01481 e.x_root = pos.x();
01482 e.y_root = pos.y();
01483 e.state = state;
01484 e.button = button;
01485 XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, (XEvent*)&e );
01486
01487
if ( type == EmuPress )
01488 {
01489
switch ( button )
01490 {
01491
case 2:
01492 state |= Button2Mask;
01493
break;
01494
case 3:
01495 state |= Button3Mask;
01496
break;
01497
default:
01498 state |= Button1Mask;
01499
break;
01500 }
01501 }
01502
else
01503 {
01504
switch ( button )
01505 {
01506
case 2:
01507 state &= ~Button2Mask;
01508
break;
01509
case 3:
01510 state &= ~Button3Mask;
01511
break;
01512
default:
01513 state &= ~Button1Mask;
01514
break;
01515 }
01516 }
01517 }
01518 }
01519
return state;
01520 }
01521
01525
bool Workspace::keyPressMouseEmulation( XKeyEvent& ev )
01526 {
01527
if ( root != qt_xrootwin() )
01528
return FALSE;
01529
int kc = XKeycodeToKeysym(qt_xdisplay(), ev.keycode, 0);
01530
int km = ev.state & (ControlMask | Mod1Mask | ShiftMask);
01531
01532
bool is_control = km & ControlMask;
01533
bool is_alt = km & Mod1Mask;
01534
bool is_shift = km & ShiftMask;
01535
int delta = is_control?1:is_alt?32:8;
01536 QPoint pos = QCursor::pos();
01537
01538
switch ( kc )
01539 {
01540
case XK_Left:
01541
case XK_KP_Left:
01542 pos.rx() -= delta;
01543
break;
01544
case XK_Right:
01545
case XK_KP_Right:
01546 pos.rx() += delta;
01547
break;
01548
case XK_Up:
01549
case XK_KP_Up:
01550 pos.ry() -= delta;
01551
break;
01552
case XK_Down:
01553
case XK_KP_Down:
01554 pos.ry() += delta;
01555
break;
01556
case XK_F1:
01557
if ( !mouse_emulation_state )
01558 mouse_emulation_window = getMouseEmulationWindow();
01559
if ( (mouse_emulation_state & Button1Mask) == 0 )
01560 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01561
if ( !is_shift )
01562 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01563
break;
01564
case XK_F2:
01565
if ( !mouse_emulation_state )
01566 mouse_emulation_window = getMouseEmulationWindow();
01567
if ( (mouse_emulation_state & Button2Mask) == 0 )
01568 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
01569
if ( !is_shift )
01570 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01571
break;
01572
case XK_F3:
01573
if ( !mouse_emulation_state )
01574 mouse_emulation_window = getMouseEmulationWindow();
01575
if ( (mouse_emulation_state & Button3Mask) == 0 )
01576 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
01577
if ( !is_shift )
01578 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01579
break;
01580
case XK_Return:
01581
case XK_space:
01582
case XK_KP_Enter:
01583
case XK_KP_Space:
01584 {
01585
if ( !mouse_emulation_state )
01586 {
01587
01588 mouse_emulation_window = getMouseEmulationWindow();
01589 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
01590 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01591 }
01592
else
01593 {
01594
if ( mouse_emulation_state & Button1Mask )
01595 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
01596
if ( mouse_emulation_state & Button2Mask )
01597 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
01598
if ( mouse_emulation_state & Button3Mask )
01599 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
01600 }
01601 }
01602
01603
case XK_Escape:
01604 XUngrabKeyboard(qt_xdisplay(), qt_x_time);
01605 mouse_emulation = FALSE;
01606
return TRUE;
01607
default:
01608
return FALSE;
01609 }
01610
01611 QCursor::setPos( pos );
01612
if ( mouse_emulation_state )
01613 mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
01614
return TRUE;
01615
01616 }
01617
01623 QWidget* Workspace::desktopWidget()
01624 {
01625
return desktop_widget;
01626 }
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
void Workspace::createBorderWindows()
01638 {
01639
if ( electric_have_borders )
01640
return;
01641
01642 electric_have_borders =
true;
01643 electric_current_border = 0;
01644
01645 QRect r = QApplication::desktop()->geometry();
01646 electricTop = r.top();
01647 electricBottom = r.bottom();
01648 electricLeft = r.left();
01649 electricRight = r.right();
01650
01651 XSetWindowAttributes attributes;
01652
unsigned long valuemask;
01653 attributes.override_redirect = True;
01654 attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
01655 VisibilityChangeMask);
01656 valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
01657 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01658 XC_sb_up_arrow);
01659 electric_top_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01660 0,0,
01661 r.width(),1,
01662 0,
01663 CopyFromParent, InputOnly,
01664 CopyFromParent,
01665 valuemask, &attributes);
01666 XMapWindow(qt_xdisplay(), electric_top_border);
01667
01668 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01669 XC_sb_down_arrow);
01670 electric_bottom_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01671 0,r.height()-1,
01672 r.width(),1,
01673 0,
01674 CopyFromParent, InputOnly,
01675 CopyFromParent,
01676 valuemask, &attributes);
01677 XMapWindow(qt_xdisplay(), electric_bottom_border);
01678
01679 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01680 XC_sb_left_arrow);
01681 electric_left_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01682 0,0,
01683 1,r.height(),
01684 0,
01685 CopyFromParent, InputOnly,
01686 CopyFromParent,
01687 valuemask, &attributes);
01688 XMapWindow(qt_xdisplay(), electric_left_border);
01689
01690 attributes.cursor = XCreateFontCursor(qt_xdisplay(),
01691 XC_sb_right_arrow);
01692 electric_right_border = XCreateWindow (qt_xdisplay(), qt_xrootwin(),
01693 r.width()-1,0,
01694 1,r.height(),
01695 0,
01696 CopyFromParent, InputOnly,
01697 CopyFromParent,
01698 valuemask, &attributes);
01699 XMapWindow(qt_xdisplay(), electric_right_border);
01700 }
01701
01702
01703
01704
01705
01706
01707
01708
void Workspace::destroyBorderWindows()
01709 {
01710
if( !electric_have_borders)
01711
return;
01712
01713 electric_have_borders =
false;
01714
01715
if(electric_top_border)
01716 XDestroyWindow(qt_xdisplay(),electric_top_border);
01717
if(electric_bottom_border)
01718 XDestroyWindow(qt_xdisplay(),electric_bottom_border);
01719
if(electric_left_border)
01720 XDestroyWindow(qt_xdisplay(),electric_left_border);
01721
if(electric_right_border)
01722 XDestroyWindow(qt_xdisplay(),electric_right_border);
01723
01724 electric_top_border = None;
01725 electric_bottom_border = None;
01726 electric_left_border = None;
01727 electric_right_border = None;
01728 }
01729
01730
void Workspace::clientMoved(
const QPoint &pos, Time now)
01731 {
01732
if (options->electricBorders() == Options::ElectricDisabled)
01733
return;
01734
01735
if ((pos.x() != electricLeft) &&
01736 (pos.x() != electricRight) &&
01737 (pos.y() != electricTop) &&
01738 (pos.y() != electricBottom))
01739
return;
01740
01741 Time treshold_set = options->electricBorderDelay();
01742 Time treshold_reset = 250;
01743
int distance_reset = 10;
01744
01745
int border = 0;
01746
if (pos.x() == electricLeft)
01747 border = 1;
01748
else if (pos.x() == electricRight)
01749 border = 2;
01750
else if (pos.y() == electricTop)
01751 border = 3;
01752
else if (pos.y() == electricBottom)
01753 border = 4;
01754
01755
if ((electric_current_border == border) &&
01756 (timestampDiff(electric_time_last, now) < treshold_reset) &&
01757 ((pos-electric_push_point).manhattanLength() < distance_reset))
01758 {
01759 electric_time_last = now;
01760
01761
if (timestampDiff(electric_time_first, now) > treshold_set)
01762 {
01763 electric_current_border = 0;
01764
01765 QRect r = QApplication::desktop()->geometry();
01766
int offset;
01767
01768
int desk_before = currentDesktop();
01769
switch(border)
01770 {
01771
case 1:
01772 slotSwitchDesktopLeft();
01773
if (currentDesktop() != desk_before)
01774 {
01775 offset = r.width() / 5;
01776 QCursor::setPos(r.width() - offset, pos.y());
01777 }
01778
break;
01779
01780
case 2:
01781 slotSwitchDesktopRight();
01782
if (currentDesktop() != desk_before)
01783 {
01784 offset = r.width() / 5;
01785 QCursor::setPos(offset, pos.y());
01786 }
01787
break;
01788
01789
case 3:
01790 slotSwitchDesktopUp();
01791
if (currentDesktop() != desk_before)
01792 {
01793 offset = r.height() / 5;
01794 QCursor::setPos(pos.x(), r.height() - offset);
01795 }
01796
break;
01797
01798
case 4:
01799 slotSwitchDesktopDown();
01800
if (currentDesktop() != desk_before)
01801 {
01802 offset = r.height() / 5;
01803 QCursor::setPos(pos.x(), offset);
01804 }
01805
break;
01806 }
01807
return;
01808 }
01809 }
01810
else
01811 {
01812 electric_current_border = border;
01813 electric_time_first = now;
01814 electric_time_last = now;
01815 electric_push_point = pos;
01816 }
01817
01818
int mouse_warp = 1;
01819
01820
01821
switch( border)
01822 {
01823
case 1: QCursor::setPos(pos.x()+mouse_warp, pos.y());
break;
01824
case 2: QCursor::setPos(pos.x()-mouse_warp, pos.y());
break;
01825
case 3: QCursor::setPos(pos.x(), pos.y()+mouse_warp);
break;
01826
case 4: QCursor::setPos(pos.x(), pos.y()-mouse_warp);
break;
01827 }
01828 }
01829
01830
01831
01832
void Workspace::electricBorder(XEvent *e)
01833 {
01834 Time now = e->xcrossing.time;
01835 QPoint p(e->xcrossing.x_root, e->xcrossing.y_root);
01836
01837 clientMoved(p, now);
01838 }
01839
01840
01841
01842
01843
void Workspace::raiseElectricBorders()
01844 {
01845
01846
if(electric_have_borders)
01847 {
01848 XRaiseWindow(qt_xdisplay(), electric_top_border);
01849 XRaiseWindow(qt_xdisplay(), electric_left_border);
01850 XRaiseWindow(qt_xdisplay(), electric_bottom_border);
01851 XRaiseWindow(qt_xdisplay(), electric_right_border);
01852 }
01853 }
01854
01855
void Workspace::addTopMenu( Client* c )
01856 {
01857 assert( c->isTopMenu());
01858 assert( !topmenus.contains( c ));
01859 topmenus.append( c );
01860
if( managingTopMenus())
01861 {
01862
int minsize = c->minSize().height();
01863
if( minsize > topMenuHeight())
01864 {
01865 topmenu_height = minsize;
01866 updateTopMenuGeometry();
01867 }
01868 updateTopMenuGeometry( c );
01869 updateCurrentTopMenu();
01870 }
01871
01872 }
01873
01874
void Workspace::removeTopMenu( Client* c )
01875 {
01876
01877
01878 assert( c->isTopMenu());
01879 assert( topmenus.contains( c ));
01880 topmenus.remove( c );
01881 updateCurrentTopMenu();
01882
01883 }
01884
01885
void Workspace::lostTopMenuSelection()
01886 {
01887
01888
01889 disconnect( topmenu_watcher, SIGNAL( lostOwner()),
this, SLOT( lostTopMenuOwner()));
01890 connect( topmenu_watcher, SIGNAL( lostOwner()),
this, SLOT( lostTopMenuOwner()));
01891
if( !managing_topmenus )
01892
return;
01893 connect( topmenu_watcher, SIGNAL( lostOwner()),
this, SLOT( lostTopMenuOwner()));
01894 disconnect( topmenu_selection, SIGNAL( lostOwnership()),
this, SLOT( lostTopMenuSelection()));
01895 managing_topmenus =
false;
01896
delete topmenu_space;
01897 topmenu_space = NULL;
01898 updateClientArea();
01899
for( ClientList::ConstIterator it = topmenus.begin();
01900 it != topmenus.end();
01901 ++it )
01902 (*it)->checkWorkspacePosition();
01903 }
01904
01905
void Workspace::lostTopMenuOwner()
01906 {
01907
if( !options->topMenuEnabled())
01908
return;
01909
01910
if( !topmenu_selection->claim(
false ))
01911 {
01912
01913
return;
01914 }
01915
01916 setupTopMenuHandling();
01917 }
01918
01919
void Workspace::setupTopMenuHandling()
01920 {
01921
if( managing_topmenus )
01922
return;
01923 connect( topmenu_selection, SIGNAL( lostOwnership()),
this, SLOT( lostTopMenuSelection()));
01924 disconnect( topmenu_watcher, SIGNAL( lostOwner()),
this, SLOT( lostTopMenuOwner()));
01925 managing_topmenus =
true;
01926 topmenu_space =
new QWidget;
01927 updateTopMenuGeometry();
01928 topmenu_space->show();
01929 updateClientArea();
01930 updateCurrentTopMenu();
01931 }
01932
01933
int Workspace::topMenuHeight()
const
01934
{
01935
if( topmenu_height == 0 )
01936 {
01937 KMenuBar tmpmenu;
01938 tmpmenu.insertItem(
"dummy" );
01939 topmenu_height = tmpmenu.sizeHint().height();
01940 }
01941
return topmenu_height;
01942 }
01943
01944
KDecoration* Workspace::createDecoration( KDecorationBridge* bridge )
01945 {
01946
return mgr->createDecoration( bridge );
01947 }
01948
01949 QString Workspace::desktopName(
int desk )
const
01950
{
01951
return QString::fromUtf8( rootInfo->desktopName( desk ) );
01952 }
01953
01954
bool Workspace::checkStartupNotification( Window w, KStartupInfoData& data )
01955 {
01956
return startup->checkStartup( w, data ) == KStartupInfo::Match;
01957 }
01958
01963
void Workspace::focusToNull()
01964 {
01965
int mask;
01966 XSetWindowAttributes attr;
01967
if (null_focus_window == 0)
01968 {
01969 mask = CWOverrideRedirect;
01970 attr.override_redirect = 1;
01971 null_focus_window = XCreateWindow(qt_xdisplay(), qt_xrootwin(), -1,-1, 1, 1, 0, CopyFromParent,
01972 InputOnly, CopyFromParent, mask, &attr);
01973 XMapWindow(qt_xdisplay(), null_focus_window);
01974 }
01975 XSetInputFocus(qt_xdisplay(), null_focus_window, RevertToPointerRoot, qt_x_time );
01976 }
01977
01978
void Workspace::helperDialog(
const QString& message,
const Client* c )
01979 {
01980 QStringList args;
01981 QString type;
01982
if( message ==
"noborderaltf3" )
01983 {
01984 args <<
"--msgbox" <<
01985 i18n(
"You have selected to show a window without its border.\n"
01986
"Without the border, you won't be able to enable the border "
01987
"again using the mouse. Use the window operations menu instead, "
01988
"activated using the %1 keyboard shortcut." )
01989 .arg( keys->shortcut(
"Window Operations Menu" ).seq( 0 ).toString());
01990 type =
"altf3warning";
01991 }
01992
else if( message ==
"fullscreenaltf3" )
01993 {
01994 args <<
"--msgbox" <<
01995 i18n(
"You have selected to show a window in fullscreen mode.\n"
01996
"If the application itself doesn't have an option to turn the fullscreen "
01997
"mode off, you won't be able to disable it "
01998
"again using the mouse. Use the window operations menu instead, "
01999
"activated using the %1 keyboard shortcut." )
02000 .arg( keys->shortcut(
"Window Operations Menu" ).seq( 0 ).toString());
02001 type =
"altf3warning";
02002 }
02003
else
02004 assert(
false );
02005 KProcess proc;
02006 proc <<
"kdialog" << args;
02007
if( !type.isEmpty())
02008 {
02009 KConfig cfg(
"kwin_dialogsrc" );
02010 cfg.setGroup(
"Notification Messages" );
02011
if( !cfg.readBoolEntry( type,
true ))
02012
return;
02013 proc <<
"--dontagain" <<
"kwin_dialogsrc:" + type;
02014 }
02015
if( c != NULL )
02016 proc <<
"--embed" << QString::number( c->window());
02017 proc.start( KProcess::DontCare );
02018 }
02019
02020 }
02021
02022
#include "workspace.moc"