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