2000-03-24 22:23:02 +00:00
|
|
|
|
/*****************************************************************
|
|
|
|
|
kwin - the KDE window manager
|
|
|
|
|
|
|
|
|
|
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
|
|
|
|
|
******************************************************************/
|
2000-06-08 17:05:51 +00:00
|
|
|
|
#define QT_CLEAN_NAMESPACE
|
1999-11-11 01:27:37 +00:00
|
|
|
|
#include <kconfig.h>
|
|
|
|
|
#include <kglobal.h>
|
2000-06-03 01:19:08 +00:00
|
|
|
|
#include <kglobalsettings.h>
|
1999-11-13 01:51:22 +00:00
|
|
|
|
#include <kglobalaccel.h>
|
|
|
|
|
#include <klocale.h>
|
1999-12-22 17:16:23 +00:00
|
|
|
|
#include <stdlib.h>
|
1999-12-01 22:09:32 +00:00
|
|
|
|
#include <qwhatsthis.h>
|
2000-05-04 23:12:29 +00:00
|
|
|
|
#include <qdatastream.h>
|
|
|
|
|
#include <kapp.h>
|
|
|
|
|
#include <dcopclient.h>
|
2000-05-24 20:57:42 +00:00
|
|
|
|
#include <kdebug.h>
|
1999-11-11 01:27:37 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
#include <netwm.h>
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
#include "workspace.h"
|
|
|
|
|
#include "client.h"
|
|
|
|
|
#include "stdclient.h"
|
|
|
|
|
#include "tabbox.h"
|
|
|
|
|
#include "atoms.h"
|
1999-12-24 01:36:47 +00:00
|
|
|
|
#include "plugins.h"
|
2000-05-07 20:38:11 +00:00
|
|
|
|
#include "events.h"
|
2000-06-19 10:45:45 +00:00
|
|
|
|
#include "killwindow.h"
|
1999-08-19 23:26:42 +00:00
|
|
|
|
#include <X11/X.h>
|
|
|
|
|
#include <X11/Xos.h>
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
|
#include <X11/keysym.h>
|
1999-12-06 00:43:55 +00:00
|
|
|
|
#include <X11/keysymdef.h>
|
1999-11-12 03:11:19 +00:00
|
|
|
|
#include <X11/extensions/shape.h>
|
2000-05-17 23:02:42 +00:00
|
|
|
|
#include <X11/cursorfont.h>
|
1999-11-12 03:11:19 +00:00
|
|
|
|
|
2000-05-07 20:17:33 +00:00
|
|
|
|
const int XIconicState = IconicState;
|
|
|
|
|
#undef IconicState
|
|
|
|
|
|
|
|
|
|
#include <kwin.h>
|
2000-03-24 22:23:02 +00:00
|
|
|
|
#include <kapp.h>
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NET WM Protocol handler class
|
|
|
|
|
class RootInfo : public NETRootInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr, int scr= -1)
|
|
|
|
|
: NETRootInfo( dpy, w, name, pr, scr ) {
|
|
|
|
|
workspace = ws;
|
|
|
|
|
}
|
|
|
|
|
~RootInfo() {}
|
|
|
|
|
|
2000-06-24 19:09:50 +00:00
|
|
|
|
void changeNumberOfDesktops(int n) { workspace->setNumberOfDesktops( n ); }
|
|
|
|
|
void changeCurrentDesktop(int d) { workspace->setCurrentDesktop( d ); }
|
2000-06-21 17:43:44 +00:00
|
|
|
|
void changeActiveWindow(Window w) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
::Client* c = workspace->findClient( (WId) w );
|
|
|
|
|
if ( c )
|
|
|
|
|
workspace->activateClient( c );
|
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
void closeWindow(Window w) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
::Client* c = workspace->findClient( (WId) w );
|
|
|
|
|
if ( c ) {
|
|
|
|
|
c->closeWindow();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void moveResize(Window, int, int, unsigned long) { }
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
private:
|
|
|
|
|
Workspace* workspace;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-11-28 21:41:15 +00:00
|
|
|
|
extern Time kwin_time;
|
2000-06-23 16:26:44 +00:00
|
|
|
|
extern void kwin_updateTime();
|
1999-11-28 21:41:15 +00:00
|
|
|
|
|
1999-11-12 03:11:19 +00:00
|
|
|
|
// used to store the return values of
|
|
|
|
|
// XShapeQueryExtension.
|
|
|
|
|
// Necessary since shaped window are an extension to X
|
|
|
|
|
static int kwin_has_shape = 0;
|
|
|
|
|
static int kwin_shape_event = 0;
|
1999-11-29 02:49:20 +00:00
|
|
|
|
static bool block_focus = FALSE;
|
1999-11-12 03:11:19 +00:00
|
|
|
|
// does the window w need a shape combine mask around it?
|
|
|
|
|
bool Shape::hasShape( WId w){
|
2000-06-08 17:05:51 +00:00
|
|
|
|
int xws, yws, xbs, ybs;
|
|
|
|
|
unsigned wws, hws, wbs, hbs;
|
|
|
|
|
int boundingShaped, clipShaped;
|
|
|
|
|
if (!kwin_has_shape)
|
|
|
|
|
return FALSE;
|
|
|
|
|
XShapeQueryExtents(qt_xdisplay(), w,
|
|
|
|
|
&boundingShaped, &xws, &yws, &wws, &hws,
|
|
|
|
|
&clipShaped, &xbs, &ybs, &wbs, &hbs);
|
|
|
|
|
return boundingShaped != 0;
|
1999-11-12 03:11:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Shape::shapeEvent()
|
|
|
|
|
{
|
|
|
|
|
return kwin_shape_event;
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
2000-04-06 18:29:04 +00:00
|
|
|
|
bool Motif::noBorder( WId w )
|
|
|
|
|
{
|
|
|
|
|
struct MwmHints {
|
|
|
|
|
ulong flags;
|
|
|
|
|
ulong functions;
|
|
|
|
|
ulong decorations;
|
|
|
|
|
long input_mode;
|
|
|
|
|
ulong status;
|
|
|
|
|
};
|
|
|
|
|
Atom type;
|
|
|
|
|
int format;
|
|
|
|
|
unsigned long length, after;
|
|
|
|
|
unsigned char* data;
|
|
|
|
|
MwmHints* hints = 0;
|
|
|
|
|
if ( XGetWindowProperty( qt_xdisplay(), w, atoms->motif_wm_hints, 0, 5,
|
|
|
|
|
FALSE, atoms->motif_wm_hints, &type, &format,
|
|
|
|
|
&length, &after, &data ) == Success ) {
|
|
|
|
|
if ( data )
|
|
|
|
|
hints = (MwmHints*) data;
|
|
|
|
|
}
|
|
|
|
|
bool result = FALSE;
|
|
|
|
|
if ( hints ) {
|
|
|
|
|
if ( hints->flags & (1L << 1 ) ) { // // MWM_HINTS_DECORATIONS;
|
|
|
|
|
if ( hints->decorations == 0 )
|
|
|
|
|
result = TRUE;
|
|
|
|
|
}
|
|
|
|
|
XFree( data );
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
2000-05-07 20:17:33 +00:00
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Creates a new client for window \a w, depending on certain hints
|
|
|
|
|
(like Motif hints and the NET_WM_TYPE.
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
|
|
|
|
Shaped windows always get a NoBorderClient.
|
2000-06-22 14:12:13 +00:00
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::clientFactory( WId w )
|
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
NETWinInfo ni( qt_xdisplay(), w, root, NET::WMWindowType );
|
2000-05-07 20:17:33 +00:00
|
|
|
|
|
2000-07-08 12:08:41 +00:00
|
|
|
|
if ( (ni.windowType() == NET::Normal || ni.windowType() == NET::Unknown)
|
|
|
|
|
&& Motif::noBorder( w ) )
|
2000-06-22 14:12:13 +00:00
|
|
|
|
return new NoBorderClient( this, w );
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
switch ( ni.windowType() ) {
|
|
|
|
|
case NET::Desktop: {
|
1999-11-07 02:07:03 +00:00
|
|
|
|
XLowerWindow( qt_xdisplay(), w );
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Client * c = new NoBorderClient( this, w);
|
1999-11-07 02:07:03 +00:00
|
|
|
|
c->setSticky( TRUE );
|
2000-06-22 14:12:13 +00:00
|
|
|
|
setDesktopClient( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return c;
|
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-22 18:08:35 +00:00
|
|
|
|
case NET::Menu:
|
2000-06-08 17:05:51 +00:00
|
|
|
|
case NET::Dock: {
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Client * c = new NoBorderClient( this, w);
|
1999-11-07 01:43:06 +00:00
|
|
|
|
c->setSticky( TRUE );
|
2000-04-08 18:45:20 +00:00
|
|
|
|
return c;
|
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
case NET::Toolbar: {
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Client * c = new NoBorderClient( this, w);
|
1999-12-07 02:18:27 +00:00
|
|
|
|
return c;
|
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-11-12 03:11:19 +00:00
|
|
|
|
if ( Shape::hasShape( w ) ){
|
2000-06-22 14:12:13 +00:00
|
|
|
|
return new NoBorderClient( this, w );
|
1999-11-12 03:11:19 +00:00
|
|
|
|
}
|
2000-06-22 14:12:13 +00:00
|
|
|
|
return(mgr.allocateClient(this, w));
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-05-04 23:12:29 +00:00
|
|
|
|
// Rikkus: This class is too complex. It needs splitting further.
|
|
|
|
|
// It's a nightmare to understand, especially with so few comments :(
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
|
|
|
|
// Matthias: Feel free to ask me questions about it. Feel free to add
|
|
|
|
|
// comments. I dissagree that further splittings makes it easier. 2500
|
|
|
|
|
// lines are not too much. It's the task that is complex, not the
|
|
|
|
|
// code.
|
2000-03-24 22:23:02 +00:00
|
|
|
|
Workspace::Workspace( bool restore )
|
2000-05-04 23:12:29 +00:00
|
|
|
|
: QObject (0, "workspace"),
|
|
|
|
|
DCOPObject ("KWinInterface"),
|
|
|
|
|
current_desktop (0),
|
|
|
|
|
number_of_desktops(0),
|
|
|
|
|
desktop_widget (0),
|
|
|
|
|
desktop_client (0),
|
|
|
|
|
active_client (0),
|
|
|
|
|
should_get_focus (0),
|
|
|
|
|
control_grab (false),
|
|
|
|
|
tab_grab (false),
|
|
|
|
|
mouse_emulation (false),
|
2000-06-02 00:20:41 +00:00
|
|
|
|
focus_change (true),
|
2000-05-04 23:12:29 +00:00
|
|
|
|
tab_box (0),
|
|
|
|
|
popup (0),
|
|
|
|
|
desk_popup (0),
|
|
|
|
|
keys (0),
|
|
|
|
|
root (0)
|
1999-08-19 23:26:42 +00:00
|
|
|
|
{
|
2000-03-22 12:36:07 +00:00
|
|
|
|
root = qt_xrootwin();
|
2000-03-24 22:23:02 +00:00
|
|
|
|
session.setAutoDelete( TRUE );
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
area = QApplication::desktop()->geometry();
|
2000-05-07 20:40:16 +00:00
|
|
|
|
|
2000-03-24 22:23:02 +00:00
|
|
|
|
if ( restore )
|
2000-05-04 23:12:29 +00:00
|
|
|
|
loadSessionInfo();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
(void) QApplication::desktop(); // trigger creation of desktop widget
|
2000-05-04 23:12:29 +00:00
|
|
|
|
|
|
|
|
|
desktop_widget =
|
|
|
|
|
new QWidget(
|
|
|
|
|
0,
|
|
|
|
|
"desktop_widget",
|
|
|
|
|
Qt::WType_Desktop | Qt::WPaintUnclipped
|
|
|
|
|
);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
// select windowmanager privileges
|
|
|
|
|
XSelectInput(qt_xdisplay(), root,
|
|
|
|
|
KeyPressMask |
|
|
|
|
|
PropertyChangeMask |
|
|
|
|
|
ColormapChangeMask |
|
|
|
|
|
SubstructureRedirectMask |
|
|
|
|
|
SubstructureNotifyMask
|
|
|
|
|
);
|
|
|
|
|
|
1999-11-12 03:11:19 +00:00
|
|
|
|
int dummy;
|
2000-05-04 23:12:29 +00:00
|
|
|
|
kwin_has_shape =
|
|
|
|
|
XShapeQueryExtension(qt_xdisplay(), &kwin_shape_event, &dummy);
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-11-13 03:44:09 +00:00
|
|
|
|
// compatibility
|
|
|
|
|
long data = 1;
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
2000-05-04 23:12:29 +00:00
|
|
|
|
XChangeProperty(
|
|
|
|
|
qt_xdisplay(),
|
|
|
|
|
qt_xrootwin(),
|
2000-06-08 17:05:51 +00:00
|
|
|
|
atoms->kwin_running,
|
|
|
|
|
atoms->kwin_running,
|
2000-05-04 23:12:29 +00:00
|
|
|
|
32,
|
|
|
|
|
PropModeAppend,
|
|
|
|
|
(unsigned char*) &data,
|
|
|
|
|
1
|
|
|
|
|
);
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
grabKey(XK_Tab, Mod1Mask);
|
|
|
|
|
grabKey(XK_Tab, Mod1Mask | ShiftMask);
|
|
|
|
|
grabKey(XK_Tab, ControlMask);
|
|
|
|
|
grabKey(XK_Tab, ControlMask | ShiftMask);
|
1999-11-13 01:51:22 +00:00
|
|
|
|
createKeybindings();
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
init();
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
tab_box = new TabBox( this );
|
1999-11-07 08:46:36 +00:00
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
void Workspace::init()
|
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
supportWindow = new QWidget;
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
|
|
|
|
unsigned long protocols =
|
2000-06-08 17:05:51 +00:00
|
|
|
|
NET::Supported |
|
|
|
|
|
NET::SupportingWMCheck |
|
|
|
|
|
NET::ClientList |
|
|
|
|
|
NET::ClientListStacking |
|
|
|
|
|
NET::NumberOfDesktops |
|
|
|
|
|
NET::CurrentDesktop |
|
|
|
|
|
NET::ActiveWindow |
|
|
|
|
|
NET::WorkArea |
|
|
|
|
|
NET::CloseWindow |
|
|
|
|
|
|
|
|
|
|
NET::WMName |
|
|
|
|
|
NET::WMDesktop |
|
|
|
|
|
NET::WMWindowType |
|
|
|
|
|
NET::WMState |
|
|
|
|
|
NET::WMStrut |
|
|
|
|
|
NET::WMIconGeometry |
|
|
|
|
|
NET::WMIcon |
|
|
|
|
|
NET::WMPid |
|
2000-06-28 07:51:45 +00:00
|
|
|
|
NET::WMKDESystemTrayWinFor
|
2000-06-08 17:05:51 +00:00
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
rootInfo = new RootInfo( this, qt_xdisplay(), supportWindow->winId(), "KWin", protocols, qt_xscreen() );
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
1999-12-03 18:51:22 +00:00
|
|
|
|
KConfig* config = KGlobal::config();
|
1999-12-03 19:04:03 +00:00
|
|
|
|
config->setGroup("Desktops");
|
1999-12-03 18:51:22 +00:00
|
|
|
|
if (!config->hasKey("NumberOfDesktops"))
|
1999-12-03 19:04:03 +00:00
|
|
|
|
config->writeEntry("NumberOfDesktops", 4);
|
1999-12-06 20:54:30 +00:00
|
|
|
|
int n = config->readNumEntry("NumberOfDesktops");
|
|
|
|
|
setNumberOfDesktops( n );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
setCurrentDesktop( 1 );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
unsigned int i, nwins;
|
|
|
|
|
Window dw1, dw2, *wins;
|
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
|
1999-12-24 01:36:47 +00:00
|
|
|
|
connect(&mgr, SIGNAL(resetAllClients()), this,
|
|
|
|
|
SLOT(slotResetAllClients()));
|
2000-06-24 06:48:53 +00:00
|
|
|
|
connect(kapp, SIGNAL(appearanceChanged()), this,
|
|
|
|
|
SLOT(slotResetAllClients()));
|
1999-12-24 01:36:47 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabServer( qt_xdisplay() );
|
|
|
|
|
XQueryTree(qt_xdisplay(), root, &dw1, &dw2, &wins, &nwins);
|
|
|
|
|
for (i = 0; i < nwins; i++) {
|
|
|
|
|
XGetWindowAttributes(qt_xdisplay(), wins[i], &attr);
|
|
|
|
|
if (attr.override_redirect )
|
|
|
|
|
continue;
|
|
|
|
|
if (attr.map_state != IsUnmapped) {
|
2000-06-28 07:51:45 +00:00
|
|
|
|
if ( addSystemTrayWin( wins[i] ) )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
continue;
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Client* c = clientFactory( wins[i] );
|
1999-11-07 02:07:03 +00:00
|
|
|
|
if ( c != desktop_client ) {
|
|
|
|
|
clients.append( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
stacking_order.append( c );
|
1999-11-07 02:07:03 +00:00
|
|
|
|
}
|
1999-11-17 17:25:26 +00:00
|
|
|
|
if ( c->wantsTabFocus() )
|
|
|
|
|
focus_chain.append( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
c->manage( TRUE );
|
|
|
|
|
if ( c == desktop_client )
|
|
|
|
|
setDesktopClient( c );
|
|
|
|
|
if ( root != qt_xrootwin() ) {
|
|
|
|
|
// TODO may use QWidget:.create
|
|
|
|
|
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
|
|
|
|
|
c->move(0,0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
XFree((void *) wins);
|
|
|
|
|
XUngrabServer( qt_xdisplay() );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
propagateClients();
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
|
|
|
|
//CT initialize the cascading info
|
|
|
|
|
for( int i = 0; i < numberOfDesktops(); i++) {
|
|
|
|
|
CascadingInfo inf;
|
|
|
|
|
inf.pos = QPoint(0,0);
|
|
|
|
|
inf.col = 0;
|
|
|
|
|
inf.row = 0;
|
|
|
|
|
cci.append(inf);
|
|
|
|
|
}
|
2000-04-28 02:52:09 +00:00
|
|
|
|
|
|
|
|
|
updateClientArea();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Workspace::~Workspace()
|
|
|
|
|
{
|
1999-11-07 02:07:03 +00:00
|
|
|
|
if ( desktop_client ) {
|
|
|
|
|
WId win = desktop_client->window();
|
|
|
|
|
delete desktop_client;
|
|
|
|
|
XMapWindow( qt_xdisplay(), win );
|
|
|
|
|
XLowerWindow( qt_xdisplay(), win );
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
1999-11-02 15:17:15 +00:00
|
|
|
|
WId win = (*it)->window();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
delete (*it);
|
1999-11-02 15:17:15 +00:00
|
|
|
|
XMapWindow( qt_xdisplay(), win );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
delete tab_box;
|
|
|
|
|
delete popup;
|
1999-11-13 01:51:22 +00:00
|
|
|
|
delete keys;
|
1999-11-13 03:44:09 +00:00
|
|
|
|
if ( root == qt_xrootwin() )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwin_running);
|
1999-12-03 19:04:03 +00:00
|
|
|
|
KGlobal::config()->sync();
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
delete rootInfo;
|
|
|
|
|
delete supportWindow;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-11-17 17:25:26 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
/*!
|
|
|
|
|
Handles workspace specific XEvents
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::workspaceEvent( XEvent * e )
|
|
|
|
|
{
|
1999-12-06 00:43:55 +00:00
|
|
|
|
if ( mouse_emulation && e->type == ButtonPress || e->type == ButtonRelease ) {
|
|
|
|
|
mouse_emulation = FALSE;
|
|
|
|
|
XUngrabKeyboard( qt_xdisplay(), kwin_time );
|
|
|
|
|
}
|
1999-12-07 21:54:52 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
Client * c = findClient( e->xany.window );
|
|
|
|
|
if ( c )
|
|
|
|
|
return c->windowEvent( e );
|
|
|
|
|
|
|
|
|
|
switch (e->type) {
|
|
|
|
|
case ButtonPress:
|
|
|
|
|
case ButtonRelease:
|
2000-04-26 01:45:10 +00:00
|
|
|
|
case MotionNotify:
|
1999-08-19 23:26:42 +00:00
|
|
|
|
break;
|
|
|
|
|
case UnmapNotify:
|
|
|
|
|
// this is special due to
|
1999-11-15 00:52:05 +00:00
|
|
|
|
// SubstructureNotifyMask. e->xany.window is the window the
|
1999-08-19 23:26:42 +00:00
|
|
|
|
// event is reported to. Take care not to confuse Qt.
|
|
|
|
|
c = findClient( e->xunmap.window );
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( c )
|
|
|
|
|
return c->windowEvent( e );
|
1999-11-11 01:22:41 +00:00
|
|
|
|
|
2000-06-28 07:51:45 +00:00
|
|
|
|
// check for system tray windows
|
|
|
|
|
if ( removeSystemTrayWin( e->xunmap.window ) )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
return TRUE;
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-20 13:51:29 +00:00
|
|
|
|
if ( e->xunmap.event == root ) {
|
1999-11-15 00:52:05 +00:00
|
|
|
|
// keep track of map/unmap for own own windows to avoid
|
|
|
|
|
// race conditions
|
|
|
|
|
c = findClientWidthId( e->xunmap.window );
|
|
|
|
|
if ( c )
|
|
|
|
|
return c->windowEvent( e );
|
|
|
|
|
}
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( e->xunmap.event != e->xunmap.window ) // hide wm typical event from Qt
|
|
|
|
|
return TRUE;
|
1999-11-15 00:52:05 +00:00
|
|
|
|
case MapNotify:
|
1999-11-20 13:51:29 +00:00
|
|
|
|
if ( e->xunmap.event == root ) {
|
1999-11-15 00:52:05 +00:00
|
|
|
|
// keep track of map/unmap for own own windows to avoid
|
|
|
|
|
// race conditions
|
|
|
|
|
c = findClientWidthId( e->xmap.window );
|
|
|
|
|
if ( c )
|
|
|
|
|
return c->windowEvent( e );
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
case ReparentNotify:
|
1999-11-02 00:32:31 +00:00
|
|
|
|
c = findClient( e->xreparent.window );
|
2000-06-21 17:43:44 +00:00
|
|
|
|
if ( c )
|
1999-11-02 00:32:31 +00:00
|
|
|
|
(void) c->windowEvent( e );
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
//do not confuse Qt with these events. After all, _we_ are the
|
|
|
|
|
//window manager who does the reparenting.
|
1999-11-02 00:32:31 +00:00
|
|
|
|
return TRUE;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
case DestroyNotify:
|
2000-06-28 07:51:45 +00:00
|
|
|
|
if ( removeSystemTrayWin( e->xdestroywindow.window ) )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
return TRUE;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return destroyClient( findClient( e->xdestroywindow.window ) );
|
|
|
|
|
case MapRequest:
|
2000-06-23 16:26:44 +00:00
|
|
|
|
kwin_updateTime();
|
1999-11-16 01:25:42 +00:00
|
|
|
|
c = findClient( e->xmaprequest.window );
|
|
|
|
|
if ( !c ) {
|
|
|
|
|
if ( e->xmaprequest.parent == root ) {
|
2000-06-28 07:51:45 +00:00
|
|
|
|
if ( addSystemTrayWin( e->xmaprequest.window ) )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
return TRUE;
|
2000-06-22 14:12:13 +00:00
|
|
|
|
c = clientFactory( e->xmaprequest.window );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( root != qt_xrootwin() ) {
|
|
|
|
|
// TODO may use QWidget:.create
|
|
|
|
|
XReparentWindow( qt_xdisplay(), c->winId(), root, 0, 0 );
|
|
|
|
|
}
|
1999-11-07 02:07:03 +00:00
|
|
|
|
if ( c != desktop_client ) {
|
1999-11-17 17:25:26 +00:00
|
|
|
|
if ( c->wantsTabFocus() )
|
|
|
|
|
focus_chain.prepend( c );
|
1999-11-07 02:07:03 +00:00
|
|
|
|
clients.append( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
stacking_order.append( c );
|
1999-11-07 02:07:03 +00:00
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
1999-11-16 01:25:42 +00:00
|
|
|
|
}
|
|
|
|
|
if ( c ) {
|
1999-08-19 23:26:42 +00:00
|
|
|
|
bool result = c->windowEvent( e );
|
2000-06-22 14:12:13 +00:00
|
|
|
|
propagateClients();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( c == desktop_client )
|
|
|
|
|
setDesktopClient( c );
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
break;
|
1999-12-01 22:09:32 +00:00
|
|
|
|
case EnterNotify:
|
|
|
|
|
if ( !QWhatsThis::inWhatsThisMode() )
|
|
|
|
|
break;
|
|
|
|
|
{
|
|
|
|
|
QWidget* w = QWidget::find( e->xcrossing.window );
|
|
|
|
|
if ( w && w->inherits("WindowWrapper" ) )
|
|
|
|
|
QWhatsThis::leaveWhatsThisMode();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case LeaveNotify:
|
|
|
|
|
if ( !QWhatsThis::inWhatsThisMode() )
|
|
|
|
|
break;
|
|
|
|
|
c = findClientWidthId( e->xcrossing.window );
|
|
|
|
|
if ( c && e->xcrossing.detail != NotifyInferior )
|
|
|
|
|
QWhatsThis::leaveWhatsThisMode();
|
|
|
|
|
break;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
case ConfigureRequest:
|
1999-11-12 03:11:19 +00:00
|
|
|
|
c = findClient( e->xconfigurerequest.window );
|
|
|
|
|
if ( c )
|
|
|
|
|
return c->windowEvent( e );
|
|
|
|
|
else if ( e->xconfigurerequest.parent == root ) {
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XWindowChanges wc;
|
|
|
|
|
unsigned int value_mask = 0;
|
|
|
|
|
wc.border_width = 0;
|
|
|
|
|
wc.x = e->xconfigurerequest.x;
|
|
|
|
|
wc.y = e->xconfigurerequest.y;
|
|
|
|
|
wc.width = e->xconfigurerequest.width;
|
|
|
|
|
wc.height = e->xconfigurerequest.height;
|
|
|
|
|
wc.sibling = None;
|
|
|
|
|
wc.stack_mode = Above;
|
|
|
|
|
value_mask = e->xconfigurerequest.value_mask | CWBorderWidth;
|
|
|
|
|
XConfigureWindow( qt_xdisplay(), e->xconfigurerequest.window, value_mask, & wc );
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case KeyPress:
|
1999-12-06 00:43:55 +00:00
|
|
|
|
if ( QWidget::keyboardGrabber() ) {
|
|
|
|
|
freeKeyboard( FALSE );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ( mouse_emulation )
|
|
|
|
|
return keyPressMouseEmulation( e->xkey );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return keyPress(e->xkey);
|
2000-03-21 20:02:27 +00:00
|
|
|
|
case KeyRelease:
|
1999-12-06 00:43:55 +00:00
|
|
|
|
if ( QWidget::keyboardGrabber() ) {
|
|
|
|
|
freeKeyboard( FALSE );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ( mouse_emulation )
|
|
|
|
|
return FALSE;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return keyRelease(e->xkey);
|
|
|
|
|
break;
|
|
|
|
|
case FocusIn:
|
|
|
|
|
break;
|
|
|
|
|
case FocusOut:
|
|
|
|
|
break;
|
2000-06-08 17:05:51 +00:00
|
|
|
|
case PropertyNotify:
|
1999-11-07 01:43:06 +00:00
|
|
|
|
case ClientMessage:
|
2000-06-08 17:05:51 +00:00
|
|
|
|
return netCheck( e );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
break;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
default:
|
1999-11-12 03:11:19 +00:00
|
|
|
|
if ( e->type == Shape::shapeEvent() ) {
|
|
|
|
|
c = findClient( ((XShapeEvent *)e)->window );
|
|
|
|
|
if ( c )
|
|
|
|
|
c->updateShape();
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-07 08:46:36 +00:00
|
|
|
|
bool Workspace::hasClient(Client* c)
|
|
|
|
|
{
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it) == c )
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
/*!
|
|
|
|
|
Finds the client that embedds the window \a w
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::findClient( WId w ) const
|
|
|
|
|
{
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->window() == w )
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
1999-11-07 02:07:03 +00:00
|
|
|
|
if ( desktop_client && w == desktop_client->window() )
|
|
|
|
|
return desktop_client;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-15 00:52:05 +00:00
|
|
|
|
/*!
|
|
|
|
|
Finds the client with window id \a w
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::findClientWidthId( WId w ) const
|
|
|
|
|
{
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->winId() == w )
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
/*!
|
|
|
|
|
Returns the workspace's geometry
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-11-13 01:51:22 +00:00
|
|
|
|
\sa clientArea()
|
1999-08-19 23:26:42 +00:00
|
|
|
|
*/
|
|
|
|
|
QRect Workspace::geometry() const
|
|
|
|
|
{
|
|
|
|
|
if ( root == qt_xrootwin() )
|
|
|
|
|
return QRect( QPoint(0, 0), QApplication::desktop()->size() );
|
|
|
|
|
else {
|
|
|
|
|
// todo caching, keep track of configure notify etc.
|
|
|
|
|
QRect r;
|
|
|
|
|
XWindowAttributes attr;
|
|
|
|
|
if (XGetWindowAttributes(qt_xdisplay(), root, &attr)){
|
|
|
|
|
r.setRect(0, 0, attr.width, attr.height );
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Destroys the client \a c
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::destroyClient( Client* c)
|
|
|
|
|
{
|
|
|
|
|
if ( !c )
|
|
|
|
|
return FALSE;
|
|
|
|
|
clients.remove( c );
|
|
|
|
|
stacking_order.remove( c );
|
|
|
|
|
focus_chain.remove( c );
|
|
|
|
|
c->invalidateWindow();
|
|
|
|
|
clientHidden( c );
|
1999-11-07 20:29:26 +00:00
|
|
|
|
if ( c == desktop_client )
|
|
|
|
|
desktop_client = 0;
|
2000-05-06 18:59:43 +00:00
|
|
|
|
delete c;
|
|
|
|
|
c = 0;
|
1999-11-07 01:43:06 +00:00
|
|
|
|
propagateClients();
|
2000-04-26 21:28:51 +00:00
|
|
|
|
updateClientArea();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Auxiliary function to release a passive keyboard grab
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::freeKeyboard(bool pass){
|
|
|
|
|
if (!pass)
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XAllowEvents(qt_xdisplay(), AsyncKeyboard, kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
else
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XAllowEvents(qt_xdisplay(), ReplayKeyboard, kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
QApplication::syncX();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Handles alt-tab / control-tab
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::keyPress(XKeyEvent key)
|
|
|
|
|
{
|
|
|
|
|
if ( root != qt_xrootwin() )
|
|
|
|
|
return FALSE;
|
|
|
|
|
int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0);
|
|
|
|
|
int km = key.state & (ControlMask | Mod1Mask | ShiftMask);
|
|
|
|
|
|
|
|
|
|
if (!control_grab){
|
|
|
|
|
|
|
|
|
|
if( (kc == XK_Tab) &&
|
|
|
|
|
( km == (Mod1Mask | ShiftMask)
|
|
|
|
|
|| km == (Mod1Mask)
|
|
|
|
|
)){
|
|
|
|
|
if (!tab_grab){
|
2000-06-22 18:08:35 +00:00
|
|
|
|
if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ){
|
1999-08-19 23:26:42 +00:00
|
|
|
|
// CDE style raise / lower
|
|
|
|
|
Client* c = topClientOnDesktop();
|
|
|
|
|
Client* nc = c;
|
|
|
|
|
if (km & ShiftMask){
|
|
|
|
|
do {
|
|
|
|
|
nc = previousStaticClient(nc);
|
|
|
|
|
} while (nc && nc != c &&
|
|
|
|
|
(!nc->isOnDesktop(currentDesktop()) ||
|
2000-06-22 18:08:35 +00:00
|
|
|
|
nc->isIconified() || !nc->wantsTabFocus() ) );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
do {
|
|
|
|
|
nc = nextStaticClient(nc);
|
|
|
|
|
} while (nc && nc != c &&
|
|
|
|
|
(!nc->isOnDesktop(currentDesktop()) ||
|
2000-06-22 18:08:35 +00:00
|
|
|
|
nc->isIconified() || !nc->wantsTabFocus() ) );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if (c && c != nc)
|
2000-06-22 18:08:35 +00:00
|
|
|
|
lowerClient( c, false );
|
|
|
|
|
if (nc) {
|
|
|
|
|
if ( options->focusPolicyIsReasonable() )
|
|
|
|
|
activateClient( nc );
|
|
|
|
|
else
|
|
|
|
|
raiseClient( nc );
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
freeKeyboard(FALSE);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2000-04-26 01:45:10 +00:00
|
|
|
|
XGrabPointer( qt_xdisplay(), root, TRUE,
|
|
|
|
|
(uint)(ButtonPressMask | ButtonReleaseMask |
|
|
|
|
|
ButtonMotionMask | EnterWindowMask |
|
|
|
|
|
LeaveWindowMask | PointerMotionMask),
|
|
|
|
|
GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, None, kwin_time );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabKeyboard(qt_xdisplay(),
|
|
|
|
|
root, FALSE,
|
|
|
|
|
GrabModeAsync, GrabModeAsync,
|
1999-11-28 21:41:15 +00:00
|
|
|
|
kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
tab_grab = TRUE;
|
|
|
|
|
tab_box->setMode( TabBox::WindowsMode );
|
|
|
|
|
tab_box->reset();
|
|
|
|
|
}
|
|
|
|
|
tab_box->nextPrev( (km & ShiftMask) == 0 );
|
2000-05-14 01:58:13 +00:00
|
|
|
|
tab_box->delayedShow();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!tab_grab){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( (kc == XK_Tab) &&
|
|
|
|
|
( km == (ControlMask | ShiftMask)
|
|
|
|
|
|| km == (ControlMask)
|
|
|
|
|
)){
|
|
|
|
|
if (!control_grab){
|
2000-04-26 01:45:10 +00:00
|
|
|
|
XGrabPointer( qt_xdisplay(), root, TRUE,
|
|
|
|
|
(uint)(ButtonPressMask | ButtonReleaseMask |
|
|
|
|
|
ButtonMotionMask | EnterWindowMask |
|
|
|
|
|
LeaveWindowMask | PointerMotionMask),
|
|
|
|
|
GrabModeSync, GrabModeAsync,
|
|
|
|
|
None, None, kwin_time );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabKeyboard(qt_xdisplay(),
|
|
|
|
|
root, FALSE,
|
|
|
|
|
GrabModeAsync, GrabModeAsync,
|
1999-11-28 21:41:15 +00:00
|
|
|
|
kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
control_grab = TRUE;
|
|
|
|
|
tab_box->setMode( TabBox::DesktopMode );
|
|
|
|
|
tab_box->reset();
|
|
|
|
|
}
|
|
|
|
|
tab_box->nextPrev( (km & ShiftMask) == 0 );
|
2000-05-14 01:58:13 +00:00
|
|
|
|
tab_box->delayedShow();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (control_grab || tab_grab){
|
|
|
|
|
if (kc == XK_Escape){
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XUngrabKeyboard(qt_xdisplay(), kwin_time);
|
2000-04-26 01:45:10 +00:00
|
|
|
|
XUngrabPointer( qt_xdisplay(), kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
tab_box->hide();
|
|
|
|
|
tab_grab = FALSE;
|
|
|
|
|
control_grab = FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
freeKeyboard(FALSE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Handles alt-tab / control-tab
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::keyRelease(XKeyEvent key)
|
|
|
|
|
{
|
|
|
|
|
if ( root != qt_xrootwin() )
|
|
|
|
|
return FALSE;
|
|
|
|
|
int i;
|
|
|
|
|
if (tab_grab){
|
|
|
|
|
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
|
|
|
|
for (i=0; i<xmk->max_keypermod; i++)
|
|
|
|
|
if (xmk->modifiermap[xmk->max_keypermod * Mod1MapIndex + i]
|
|
|
|
|
== key.keycode){
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XUngrabKeyboard(qt_xdisplay(), kwin_time);
|
2000-04-26 01:45:10 +00:00
|
|
|
|
XUngrabPointer( qt_xdisplay(), kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
tab_box->hide();
|
|
|
|
|
tab_grab = false;
|
|
|
|
|
if ( tab_box->currentClient() ){
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
activateClient( tab_box->currentClient() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (control_grab){
|
|
|
|
|
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
|
|
|
|
for (i=0; i<xmk->max_keypermod; i++)
|
|
|
|
|
if (xmk->modifiermap[xmk->max_keypermod * ControlMapIndex + i]
|
|
|
|
|
== key.keycode){
|
2000-04-26 01:45:10 +00:00
|
|
|
|
XUngrabPointer( qt_xdisplay(), kwin_time);
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XUngrabKeyboard(qt_xdisplay(), kwin_time);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
tab_box->hide();
|
|
|
|
|
control_grab = False;
|
|
|
|
|
if ( tab_box->currentDesktop() != -1 )
|
1999-11-07 01:43:06 +00:00
|
|
|
|
setCurrentDesktop( tab_box->currentDesktop() );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
auxiliary functions to travers all clients according the focus
|
|
|
|
|
order. Useful for kwm<EFBFBD>s Alt-tab feature.
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::nextClient( Client* c ) const
|
|
|
|
|
{
|
|
|
|
|
if ( focus_chain.isEmpty() )
|
|
|
|
|
return 0;
|
|
|
|
|
ClientList::ConstIterator it = focus_chain.find( c );
|
|
|
|
|
if ( it == focus_chain.end() )
|
|
|
|
|
return focus_chain.last();
|
|
|
|
|
if ( it == focus_chain.begin() )
|
|
|
|
|
return focus_chain.last();
|
|
|
|
|
--it;
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
auxiliary functions to travers all clients according the focus
|
|
|
|
|
order. Useful for kwm<EFBFBD>s Alt-tab feature.
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::previousClient( Client* c ) const
|
|
|
|
|
{
|
|
|
|
|
if ( focus_chain.isEmpty() )
|
|
|
|
|
return 0;
|
|
|
|
|
ClientList::ConstIterator it = focus_chain.find( c );
|
|
|
|
|
if ( it == focus_chain.end() )
|
|
|
|
|
return focus_chain.first();
|
|
|
|
|
++it;
|
|
|
|
|
if ( it == focus_chain.end() )
|
|
|
|
|
return focus_chain.first();
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
auxiliary functions to travers all clients according the static
|
|
|
|
|
order. Useful for the CDE-style Alt-tab feature.
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::nextStaticClient( Client* c ) const
|
|
|
|
|
{
|
|
|
|
|
if ( clients.isEmpty() )
|
|
|
|
|
return 0;
|
|
|
|
|
ClientList::ConstIterator it = clients.find( c );
|
|
|
|
|
if ( it == clients.end() )
|
|
|
|
|
return clients.first();
|
|
|
|
|
++it;
|
|
|
|
|
if ( it == clients.end() )
|
|
|
|
|
return clients.first();
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
auxiliary functions to travers all clients according the static
|
|
|
|
|
order. Useful for the CDE-style Alt-tab feature.
|
|
|
|
|
*/
|
|
|
|
|
Client* Workspace::previousStaticClient( Client* c ) const
|
|
|
|
|
{
|
|
|
|
|
if ( clients.isEmpty() )
|
|
|
|
|
return 0;
|
|
|
|
|
ClientList::ConstIterator it = clients.find( c );
|
|
|
|
|
if ( it == clients.end() )
|
|
|
|
|
return clients.last();
|
|
|
|
|
if ( it == clients.begin() )
|
|
|
|
|
return clients.last();
|
|
|
|
|
--it;
|
|
|
|
|
return *it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 18:08:35 +00:00
|
|
|
|
Returns topmost visible client. Windows on the dock and the
|
|
|
|
|
desktop are excluded.
|
1999-08-19 23:26:42 +00:00
|
|
|
|
*/
|
2000-06-22 18:08:35 +00:00
|
|
|
|
Client* Workspace::topClientOnDesktop() const
|
1999-08-19 23:26:42 +00:00
|
|
|
|
{
|
2000-06-22 18:08:35 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
|
2000-07-10 15:54:17 +00:00
|
|
|
|
if ( !(*it)->isDesktop() && !(*it)->isDock() && !(*it)->isDock() )
|
2000-06-22 18:08:35 +00:00
|
|
|
|
return *it;
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Grabs the keysymbol \a keysym with the given modifiers \a mod
|
|
|
|
|
plus all possibile combinations of Lock and NumLock
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::grabKey(KeySym keysym, unsigned int mod){
|
|
|
|
|
static int NumLockMask = 0;
|
|
|
|
|
if (!keysym||!XKeysymToKeycode(qt_xdisplay(), keysym)) return;
|
|
|
|
|
if (!NumLockMask){
|
|
|
|
|
XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay());
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0; i<8; i++){
|
|
|
|
|
if (xmk->modifiermap[xmk->max_keypermod * i] ==
|
|
|
|
|
XKeysymToKeycode(qt_xdisplay(), XK_Num_Lock))
|
|
|
|
|
NumLockMask = (1<<i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
XGrabKey(qt_xdisplay(),
|
|
|
|
|
XKeysymToKeycode(qt_xdisplay(), keysym), mod,
|
1999-11-15 15:57:48 +00:00
|
|
|
|
qt_xrootwin(), FALSE,
|
1999-11-29 14:19:32 +00:00
|
|
|
|
GrabModeAsync, GrabModeSync);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabKey(qt_xdisplay(),
|
|
|
|
|
XKeysymToKeycode(qt_xdisplay(), keysym), mod | LockMask,
|
1999-11-15 15:57:48 +00:00
|
|
|
|
qt_xrootwin(), FALSE,
|
1999-11-29 14:19:32 +00:00
|
|
|
|
GrabModeAsync, GrabModeSync);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabKey(qt_xdisplay(),
|
|
|
|
|
XKeysymToKeycode(qt_xdisplay(), keysym), mod | NumLockMask,
|
1999-11-15 15:57:48 +00:00
|
|
|
|
qt_xrootwin(), FALSE,
|
1999-11-29 14:19:32 +00:00
|
|
|
|
GrabModeAsync, GrabModeSync);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
XGrabKey(qt_xdisplay(),
|
|
|
|
|
XKeysymToKeycode(qt_xdisplay(), keysym), mod | LockMask | NumLockMask,
|
1999-11-15 15:57:48 +00:00
|
|
|
|
qt_xrootwin(), FALSE,
|
1999-11-29 14:19:32 +00:00
|
|
|
|
GrabModeAsync, GrabModeSync);
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Informs the workspace about the active client, i.e. the client that
|
|
|
|
|
has the focus (or None if no client has the focus). This functions
|
|
|
|
|
is called by the client itself that gets focus. It has no other
|
1999-11-07 01:43:06 +00:00
|
|
|
|
effect than fixing the focus chain and the return value of
|
|
|
|
|
activeClient(). And of course, to propagate the active client to the
|
|
|
|
|
world.
|
1999-08-19 23:26:42 +00:00
|
|
|
|
*/
|
|
|
|
|
void Workspace::setActiveClient( Client* c )
|
|
|
|
|
{
|
|
|
|
|
if ( active_client == c )
|
|
|
|
|
return;
|
|
|
|
|
if ( active_client )
|
|
|
|
|
active_client->setActive( FALSE );
|
|
|
|
|
active_client = c;
|
|
|
|
|
if ( active_client ) {
|
|
|
|
|
focus_chain.remove( c );
|
1999-11-17 17:25:26 +00:00
|
|
|
|
if ( c->wantsTabFocus() )
|
|
|
|
|
focus_chain.append( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
2000-07-10 15:54:17 +00:00
|
|
|
|
|
|
|
|
|
// toplevel menubar handling
|
|
|
|
|
Client* main = 0;
|
|
|
|
|
if ( active_client )
|
|
|
|
|
main = active_client->mainClient();
|
|
|
|
|
|
|
|
|
|
// show the new menu bar first...
|
|
|
|
|
Client* menubar = 0;
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->isMenu() && (*it)->mainClient() == main ) {
|
|
|
|
|
menubar = *it;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( !menubar && desktop_client ) {
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->isMenu() && (*it)->mainClient() == desktop_client ) {
|
|
|
|
|
menubar = *it;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( menubar ) {
|
|
|
|
|
menubar->show();
|
|
|
|
|
menubar->raise();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ... then hide the other ones. Avoids flickers.
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->isMenu() && (*it) != menubar )
|
|
|
|
|
(*it)->hide();
|
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Tries to activate the client \a c. This function performs what you
|
|
|
|
|
expect when clicking the respective entry in a taskbar: showing and
|
|
|
|
|
raising the client (this may imply switching to the another virtual
|
|
|
|
|
desktop) and putting the focus onto it. Once X really gave focus to
|
|
|
|
|
the client window as requested, the client itself will call
|
|
|
|
|
setActiveClient() and the operation is complete. This may not happen
|
|
|
|
|
with certain focus policies, though.
|
|
|
|
|
|
|
|
|
|
\sa setActiveClient(), requestFocus()
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::activateClient( Client* c)
|
|
|
|
|
{
|
|
|
|
|
if (!c->isOnDesktop(currentDesktop()) ) {
|
1999-11-15 22:37:12 +00:00
|
|
|
|
setCurrentDesktop( c->desktop() );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
raiseClient( c );
|
2000-05-07 20:38:11 +00:00
|
|
|
|
if ( c->isIconified() )
|
|
|
|
|
Events::raise( Events::DeIconify );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
c->show();
|
1999-11-28 20:10:58 +00:00
|
|
|
|
iconifyOrDeiconifyTransientsOf( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( options->focusPolicyIsReasonable() )
|
|
|
|
|
requestFocus( c );
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-28 20:10:58 +00:00
|
|
|
|
void Workspace::iconifyOrDeiconifyTransientsOf( Client* c )
|
|
|
|
|
{
|
1999-11-28 20:17:57 +00:00
|
|
|
|
if ( c->isIconified() || c->isShade() ) {
|
1999-11-28 20:10:58 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
1999-11-29 14:19:32 +00:00
|
|
|
|
if ( (*it)->transientFor() == c->window()
|
|
|
|
|
&& !(*it)->isIconified()
|
1999-11-28 20:17:57 +00:00
|
|
|
|
&& !(*it)->isShade() ) {
|
2000-05-07 20:17:33 +00:00
|
|
|
|
(*it)->setMappingState( XIconicState );
|
1999-11-28 20:10:58 +00:00
|
|
|
|
(*it)->hide();
|
|
|
|
|
iconifyOrDeiconifyTransientsOf( (*it) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->transientFor() == c->window() && !(*it)->isVisible() ) {
|
|
|
|
|
(*it)->show();
|
|
|
|
|
iconifyOrDeiconifyTransientsOf( (*it) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
2000-01-10 03:47:30 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sets the client \a c's transient windows' sticky property to \a sticky.
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::setStickyTransientsOf( Client* c, bool sticky )
|
|
|
|
|
{
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->transientFor() == c->window() && (*it)->isSticky() != sticky )
|
|
|
|
|
(*it)->setSticky( sticky );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-28 20:55:52 +00:00
|
|
|
|
/*!
|
|
|
|
|
Returns whether a client with the specified \a caption exists, or not.
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::hasCaption( const QString& caption )
|
|
|
|
|
{
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->caption() == caption )
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
/*!
|
|
|
|
|
Tries to activate the client by asking X for the input focus. This
|
|
|
|
|
function does not perform any show, raise or desktop switching. See
|
|
|
|
|
Workspace::activateClient() instead.
|
|
|
|
|
|
|
|
|
|
\sa Workspace::activateClient()
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::requestFocus( Client* c)
|
|
|
|
|
{
|
2000-06-02 00:20:41 +00:00
|
|
|
|
if (!focusChangeEnabled())
|
|
|
|
|
return;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
//TODO will be different for non-root clients. (subclassing?)
|
|
|
|
|
if ( !c ) {
|
|
|
|
|
focusToNull();
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-11-29 14:19:32 +00:00
|
|
|
|
|
1999-11-29 02:06:41 +00:00
|
|
|
|
if ( !popup || !popup->isVisible() )
|
|
|
|
|
popup_client = c;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
if ( c->isVisible() && !c->isShade() ) {
|
|
|
|
|
c->takeFocus();
|
|
|
|
|
should_get_focus = c;
|
1999-12-07 22:04:07 +00:00
|
|
|
|
focus_chain.remove( c );
|
|
|
|
|
if ( c->wantsTabFocus() )
|
|
|
|
|
focus_chain.append( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
} else if ( c->isShade() ) {
|
|
|
|
|
// client cannot accept focus, but at least the window should be active (window menu, et. al. )
|
|
|
|
|
focusToNull();
|
|
|
|
|
c->setActive( TRUE );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Informs the workspace that the client \a c has been hidden. If it
|
|
|
|
|
was the active client, the workspace activates another one.
|
|
|
|
|
|
|
|
|
|
\a c may already be destroyed
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::clientHidden( Client* c )
|
|
|
|
|
{
|
2000-07-08 13:35:59 +00:00
|
|
|
|
if ( c != active_client && ( active_client || c != should_get_focus ) )
|
|
|
|
|
return;
|
2000-07-09 20:29:53 +00:00
|
|
|
|
|
2000-07-08 13:35:59 +00:00
|
|
|
|
active_client = 0;
|
|
|
|
|
should_get_focus = 0;
|
|
|
|
|
if (!block_focus &&
|
|
|
|
|
options->focusPolicyIsReasonable() &&
|
|
|
|
|
!focus_chain.isEmpty()
|
|
|
|
|
) {
|
|
|
|
|
for (ClientList::ConstIterator it = focus_chain.fromLast();
|
|
|
|
|
it != focus_chain.end();
|
|
|
|
|
--it) {
|
|
|
|
|
if ((*it)->isVisible()) {
|
|
|
|
|
requestFocus(*it);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-06-27 14:43:12 +00:00
|
|
|
|
if ( desktop_client )
|
|
|
|
|
requestFocus( desktop_client );
|
|
|
|
|
else
|
|
|
|
|
focusToNull();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-11-25 16:38:11 +00:00
|
|
|
|
QPopupMenu* Workspace::clientPopup( Client* c )
|
1999-08-19 23:26:42 +00:00
|
|
|
|
{
|
1999-11-22 01:57:51 +00:00
|
|
|
|
popup_client = c;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
if ( !popup ) {
|
|
|
|
|
popup = new QPopupMenu;
|
1999-11-22 01:57:51 +00:00
|
|
|
|
popup->setCheckable( TRUE );
|
2000-06-03 01:19:08 +00:00
|
|
|
|
popup->setFont(KGlobalSettings::menuFont());
|
1999-11-22 01:57:51 +00:00
|
|
|
|
connect( popup, SIGNAL( aboutToShow() ), this, SLOT( clientPopupAboutToShow() ) );
|
|
|
|
|
connect( popup, SIGNAL( activated(int) ), this, SLOT( clientPopupActivated(int) ) );
|
2000-03-24 22:23:02 +00:00
|
|
|
|
|
2000-03-24 09:42:23 +00:00
|
|
|
|
PluginMenu *deco = new PluginMenu(&mgr, popup);
|
2000-06-03 01:19:08 +00:00
|
|
|
|
deco->setFont(KGlobalSettings::menuFont());
|
1999-09-27 16:02:44 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
desk_popup = new QPopupMenu( popup );
|
|
|
|
|
desk_popup->setCheckable( TRUE );
|
2000-06-03 01:19:08 +00:00
|
|
|
|
desk_popup->setFont(KGlobalSettings::menuFont());
|
1999-11-22 01:57:51 +00:00
|
|
|
|
connect( desk_popup, SIGNAL( activated(int) ), this, SLOT( sendToDesktop(int) ) );
|
|
|
|
|
connect( desk_popup, SIGNAL( aboutToShow() ), this, SLOT( desktopPopupAboutToShow() ) );
|
|
|
|
|
|
1999-11-29 02:06:41 +00:00
|
|
|
|
popup->insertItem( i18n("&Move"), Options::MoveOp );
|
|
|
|
|
popup->insertItem( i18n("&Size"), Options::ResizeOp );
|
1999-12-30 22:46:45 +00:00
|
|
|
|
popup->insertItem( i18n("Mi&nimize"), Options::IconifyOp );
|
1999-11-29 02:06:41 +00:00
|
|
|
|
popup->insertItem( i18n("Ma&ximize"), Options::MaximizeOp );
|
|
|
|
|
popup->insertItem( i18n("Sh&ade"), Options::ShadeOp );
|
2000-06-28 13:20:42 +00:00
|
|
|
|
popup->insertItem( i18n("Always &On Top"), Options::StaysOnTopOp );
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
popup->insertSeparator();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
popup->insertItem(i18n("&Decoration"), deco );
|
|
|
|
|
popup->insertItem(i18n("&To desktop"), desk_popup );
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
popup->insertSeparator();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
QString k = KAccel::keyToString( keys->currentKey( "Window close" ), true );
|
1999-11-29 02:06:41 +00:00
|
|
|
|
popup->insertItem(i18n("&Close")+'\t'+k, Options::CloseOp );
|
1999-11-22 01:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
return popup;
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-11-29 02:06:41 +00:00
|
|
|
|
void Workspace::performWindowOperation( Client* c, Options::WindowOperation op ) {
|
|
|
|
|
if ( !c )
|
1999-11-22 01:57:51 +00:00
|
|
|
|
return;
|
1999-11-29 14:19:32 +00:00
|
|
|
|
|
1999-11-29 02:06:41 +00:00
|
|
|
|
switch ( op ) {
|
1999-12-06 00:43:55 +00:00
|
|
|
|
case Options::MoveOp:
|
|
|
|
|
c->performMouseCommand( Options::MouseMove, QCursor::pos() );
|
|
|
|
|
break;
|
|
|
|
|
case Options::ResizeOp:
|
|
|
|
|
c->performMouseCommand( Options::MouseResize, QCursor::pos() );
|
|
|
|
|
break;
|
1999-11-29 02:06:41 +00:00
|
|
|
|
case Options::CloseOp:
|
|
|
|
|
c->closeWindow();
|
|
|
|
|
break;
|
|
|
|
|
case Options::MaximizeOp:
|
|
|
|
|
c->maximize();
|
|
|
|
|
break;
|
|
|
|
|
case Options::IconifyOp:
|
|
|
|
|
c->iconify();
|
|
|
|
|
break;
|
|
|
|
|
case Options::ShadeOp:
|
|
|
|
|
c->setShade( !c->isShade() );
|
|
|
|
|
break;
|
2000-06-28 13:20:42 +00:00
|
|
|
|
case Options::StaysOnTopOp:
|
|
|
|
|
c->setStaysOnTop( !c->staysOnTop() );
|
|
|
|
|
raiseClient( c );
|
|
|
|
|
break;
|
1999-11-29 02:06:41 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-29 14:19:32 +00:00
|
|
|
|
void Workspace::clientPopupActivated( int id )
|
1999-11-29 02:06:41 +00:00
|
|
|
|
{
|
1999-12-06 00:43:55 +00:00
|
|
|
|
performWindowOperation( popup_client, (Options::WindowOperation) id );
|
1999-11-22 01:57:51 +00:00
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Places the client \a c according to the workspace's layout policy
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::doPlacement( Client* c )
|
|
|
|
|
{
|
1999-11-16 08:53:02 +00:00
|
|
|
|
if (options->placement == Options::Random)
|
1999-08-19 23:26:42 +00:00
|
|
|
|
randomPlacement( c );
|
1999-11-16 08:53:02 +00:00
|
|
|
|
else if (options->placement == Options::Smart)
|
|
|
|
|
smartPlacement( c );
|
1999-11-20 06:27:07 +00:00
|
|
|
|
else if (options->placement == Options::Cascade)
|
|
|
|
|
cascadePlacement( c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Place the client \a c according to a simply "random" placement algorithm.
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::randomPlacement(Client* c){
|
|
|
|
|
const int step = 24;
|
|
|
|
|
static int px = step;
|
|
|
|
|
static int py = 2 * step;
|
|
|
|
|
int tx,ty;
|
|
|
|
|
|
1999-11-13 01:51:22 +00:00
|
|
|
|
QRect maxRect = clientArea();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
if (px < maxRect.x())
|
|
|
|
|
px = maxRect.x();
|
|
|
|
|
if (py < maxRect.y())
|
|
|
|
|
py = maxRect.y();
|
|
|
|
|
|
|
|
|
|
px += step;
|
|
|
|
|
py += 2*step;
|
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if (px > maxRect.width()/2)
|
|
|
|
|
px = maxRect.x() + step;
|
|
|
|
|
if (py > maxRect.height()/2)
|
|
|
|
|
py = maxRect.y() + step;
|
|
|
|
|
tx = px;
|
|
|
|
|
ty = py;
|
|
|
|
|
if (tx + c->width() > maxRect.right()){
|
|
|
|
|
tx = maxRect.right() - c->width();
|
|
|
|
|
if (tx < 0)
|
|
|
|
|
tx = 0;
|
|
|
|
|
px = maxRect.x();
|
|
|
|
|
}
|
|
|
|
|
if (ty + c->height() > maxRect.bottom()){
|
|
|
|
|
ty = maxRect.bottom() - c->height();
|
|
|
|
|
if (ty < 0)
|
|
|
|
|
ty = 0;
|
|
|
|
|
py = maxRect.y();
|
|
|
|
|
}
|
|
|
|
|
c->move( tx, ty );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-11-16 08:53:02 +00:00
|
|
|
|
/*!
|
|
|
|
|
Place the client \a c according to a really smart placement algorithm :-)
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::smartPlacement(Client* c){
|
1999-11-22 01:57:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* SmartPlacement by Cristian Tibirna (tibirna@kde.org)
|
|
|
|
|
* adapted for kwm (16-19jan98) and for kwin (16Nov1999) using (with
|
|
|
|
|
* permission) ideas from fvwm, authored by
|
|
|
|
|
* Anthony Martin (amartin@engr.csulb.edu).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const int none = 0, h_wrong = -1, w_wrong = -2; // overlap types
|
2000-03-21 20:02:27 +00:00
|
|
|
|
long int overlap, min_overlap = 0;
|
1999-11-22 01:57:51 +00:00
|
|
|
|
int x_optimal, y_optimal;
|
|
|
|
|
int possible;
|
|
|
|
|
|
|
|
|
|
int cxl, cxr, cyt, cyb; //temp coords
|
|
|
|
|
int xl, xr, yt, yb; //temp coords
|
|
|
|
|
|
|
|
|
|
// get the maximum allowed windows space
|
|
|
|
|
QRect maxRect = clientArea();
|
|
|
|
|
int x = maxRect.left(), y = maxRect.top();
|
|
|
|
|
x_optimal = x; y_optimal = y;
|
|
|
|
|
|
|
|
|
|
//client gabarit
|
|
|
|
|
int ch = c->height(), cw = c->width();
|
|
|
|
|
|
|
|
|
|
bool first_pass = true; //CT lame flag. Don't like it. What else would do?
|
|
|
|
|
|
|
|
|
|
//loop over possible positions
|
|
|
|
|
do {
|
|
|
|
|
//test if enough room in x and y directions
|
|
|
|
|
if ( y + ch > maxRect.bottom() )
|
|
|
|
|
overlap = h_wrong; // this throws the algorithm to an exit
|
|
|
|
|
else if( x + cw > maxRect.right() )
|
|
|
|
|
overlap = w_wrong;
|
|
|
|
|
else {
|
|
|
|
|
overlap = none; //initialize
|
|
|
|
|
|
|
|
|
|
cxl = x; cxr = x + cw;
|
|
|
|
|
cyt = y; cyb = y + ch;
|
|
|
|
|
QValueList<Client*>::ConstIterator l;
|
|
|
|
|
for(l = clients.begin(); l != clients.end() ; ++l ) {
|
|
|
|
|
if((*l)->isOnDesktop(currentDesktop()) && (*l) != desktop_client &&
|
|
|
|
|
!(*l)->isIconified() && (*l) != c ) {
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-12-19 03:04:39 +00:00
|
|
|
|
xl = (*l)->x(); yt = (*l)->y();
|
|
|
|
|
xr = xl + (*l)->width(); yb = yt + (*l)->height();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
//if windows overlap, calc the overall overlapping
|
|
|
|
|
if((cxl < xr) && (cxr > xl) &&
|
|
|
|
|
(cyt < yb) && (cyb > yt)) {
|
|
|
|
|
xl = QMAX(cxl, xl); xr = QMIN(cxr, xr);
|
|
|
|
|
yt = QMAX(cyt, yt); yb = QMIN(cyb, yb);
|
|
|
|
|
overlap += (xr - xl) * (yb - yt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-11-16 08:53:02 +00:00
|
|
|
|
}
|
1999-11-17 06:11:39 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
//CT first time we get no overlap we stop.
|
|
|
|
|
if (overlap == none) {
|
|
|
|
|
x_optimal = x;
|
|
|
|
|
y_optimal = y;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if (first_pass) {
|
|
|
|
|
first_pass = false;
|
|
|
|
|
min_overlap = overlap;
|
|
|
|
|
}
|
|
|
|
|
//CT save the best position and the minimum overlap up to now
|
|
|
|
|
else if ( overlap >= none && overlap < min_overlap) {
|
|
|
|
|
min_overlap = overlap;
|
|
|
|
|
x_optimal = x;
|
|
|
|
|
y_optimal = y;
|
|
|
|
|
}
|
1999-11-17 06:11:39 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// really need to loop? test if there's any overlap
|
|
|
|
|
if ( overlap > none ) {
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
possible = maxRect.right();
|
|
|
|
|
if ( possible - cw > x) possible -= cw;
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// compare to the position of each client on the current desk
|
|
|
|
|
QValueList<Client*>::ConstIterator l;
|
|
|
|
|
for(l = clients.begin(); l != clients.end() ; ++l) {
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if ( (*l)->isOnDesktop(currentDesktop()) && (*l) != desktop_client &&
|
|
|
|
|
!(*l)->isIconified() && (*l) != c ) {
|
1999-11-16 08:53:02 +00:00
|
|
|
|
|
1999-12-19 03:04:39 +00:00
|
|
|
|
xl = (*l)->x(); yt = (*l)->y();
|
|
|
|
|
xr = xl + (*l)->width(); yb = yt + (*l)->height();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// if not enough room above or under the current tested client
|
|
|
|
|
// determine the first non-overlapped x position
|
1999-12-19 03:04:39 +00:00
|
|
|
|
if( ( y < yb ) && ( yt < ch + y ) ) {
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-12-19 03:04:39 +00:00
|
|
|
|
if( xr > x )
|
|
|
|
|
possible = possible < xr ? possible : xr;
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if( xl - cw > x )
|
|
|
|
|
possible = possible < xl - cw ? possible : xl - cw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-12-19 03:04:39 +00:00
|
|
|
|
x = possible;
|
1999-11-16 08:53:02 +00:00
|
|
|
|
}
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// ... else ==> not enough x dimension (overlap was wrong on horizontal)
|
|
|
|
|
else if ( overlap == w_wrong ) {
|
|
|
|
|
x = maxRect.left();
|
|
|
|
|
possible = maxRect.bottom();
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if ( possible - ch > y ) possible -= ch;
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
//test the position of each window on current desk
|
|
|
|
|
QValueList<Client*>::ConstIterator l;
|
|
|
|
|
for( l = clients.begin(); l != clients.end() ; ++l ) {
|
|
|
|
|
if( (*l)->isOnDesktop( currentDesktop() ) && (*l) != desktop_client &&
|
|
|
|
|
(*l) != c && !c->isIconified() ) {
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-12-19 03:04:39 +00:00
|
|
|
|
xl = (*l)->x(); yt = (*l)->y();
|
|
|
|
|
xr = xl + (*l)->width(); yb = yt + (*l)->height();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if( yb > y)
|
|
|
|
|
possible = possible < yb ? possible : yb;
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if( yt - ch > y )
|
|
|
|
|
possible = possible < yt - ch ? possible : yt - ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-12-19 03:04:39 +00:00
|
|
|
|
y = possible;
|
1999-11-16 08:53:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-11-22 01:57:51 +00:00
|
|
|
|
while( overlap != none && overlap != h_wrong );
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// place the window
|
2000-03-21 20:02:27 +00:00
|
|
|
|
c->move( x_optimal, y_optimal );
|
1999-11-16 08:53:02 +00:00
|
|
|
|
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
1999-11-20 06:27:07 +00:00
|
|
|
|
/*!
|
|
|
|
|
Place windows in a cascading order, remembering positions for each desktop
|
1999-11-20 13:51:29 +00:00
|
|
|
|
*/
|
1999-11-20 06:27:07 +00:00
|
|
|
|
void Workspace::cascadePlacement (Client* c, bool re_init) {
|
1999-11-22 01:57:51 +00:00
|
|
|
|
/* cascadePlacement by Cristian Tibirna (tibirna@kde.org) (30Jan98)
|
1999-11-20 06:27:07 +00:00
|
|
|
|
*/
|
|
|
|
|
// work coords
|
1999-11-22 01:57:51 +00:00
|
|
|
|
int xp, yp;
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
//CT how do I get from the 'Client' class the size that NW squarish "handle"
|
|
|
|
|
int delta_x = 24;
|
|
|
|
|
int delta_y = 24;
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
int d = currentDesktop() - 1;
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// get the maximum allowed windows space and desk's origin
|
|
|
|
|
// (CT 20Nov1999 - is this common to all desktops?)
|
|
|
|
|
QRect maxRect = clientArea();
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
|
|
|
|
// initialize often used vars: width and height of c; we gain speed
|
1999-11-22 01:57:51 +00:00
|
|
|
|
int ch = c->height();
|
|
|
|
|
int cw = c->width();
|
|
|
|
|
int H = maxRect.bottom();
|
|
|
|
|
int W = maxRect.right();
|
|
|
|
|
int X = maxRect.left();
|
|
|
|
|
int Y = maxRect.top();
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
|
|
|
|
//initialize if needed
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if (re_init) {
|
|
|
|
|
cci[d].pos = QPoint(X, Y);
|
|
|
|
|
cci[d].col = cci[d].row = 0;
|
|
|
|
|
}
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
xp = cci[d].pos.x();
|
|
|
|
|
yp = cci[d].pos.y();
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
//here to touch in case people vote for resize on placement
|
|
|
|
|
if ((yp + ch ) > H) yp = Y;
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if ((xp + cw ) > W)
|
|
|
|
|
if (!yp) {
|
|
|
|
|
smartPlacement(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else xp = X;
|
1999-11-20 06:27:07 +00:00
|
|
|
|
|
|
|
|
|
//if this isn't the first window
|
1999-11-22 01:57:51 +00:00
|
|
|
|
if ( cci[d].pos.x() != X && cci[d].pos.y() != Y ) {
|
1999-12-22 09:46:21 +00:00
|
|
|
|
/* The following statements cause an internal compiler error with
|
|
|
|
|
* egcs-2.91.66 on SuSE Linux 6.3. The equivalent forms compile fine.
|
|
|
|
|
* 22-Dec-1999 CS
|
|
|
|
|
*
|
|
|
|
|
* if ( xp != X && yp == Y ) xp = delta_x * (++(cci[d].col));
|
|
|
|
|
* if ( yp != Y && xp == X ) yp = delta_y * (++(cci[d].row));
|
|
|
|
|
*/
|
|
|
|
|
if ( xp != X && yp == Y )
|
|
|
|
|
{
|
|
|
|
|
++(cci[d].col);
|
|
|
|
|
xp = delta_x * cci[d].col;
|
|
|
|
|
}
|
|
|
|
|
if ( yp != Y && xp == X )
|
|
|
|
|
{
|
|
|
|
|
++(cci[d].row);
|
|
|
|
|
yp = delta_y * cci[d].row;
|
|
|
|
|
}
|
1999-11-22 01:57:51 +00:00
|
|
|
|
|
|
|
|
|
// last resort: if still doesn't fit, smart place it
|
|
|
|
|
if ( ((xp + cw) > W - X) || ((yp + ch) > H - Y) ) {
|
|
|
|
|
smartPlacement(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-11-20 06:27:07 +00:00
|
|
|
|
}
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// place the window
|
|
|
|
|
c->move( QPoint( xp, yp ) );
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
// new position
|
|
|
|
|
cci[d].pos = QPoint( xp + delta_x, yp + delta_y );
|
1999-11-20 06:27:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Cascades all clients on the current desktop
|
|
|
|
|
*/
|
2000-06-08 17:05:51 +00:00
|
|
|
|
void Workspace::cascadeDesktop()
|
1999-12-03 21:08:07 +00:00
|
|
|
|
{
|
2000-05-03 12:57:37 +00:00
|
|
|
|
ClientList::Iterator it(clients.fromLast());
|
|
|
|
|
for (; it != clients.end(); --it) {
|
1999-12-03 21:08:07 +00:00
|
|
|
|
if((!(*it)->isOnDesktop(currentDesktop())) ||
|
|
|
|
|
((*it)->isIconified()) ||
|
2000-04-19 04:36:47 +00:00
|
|
|
|
((*it)->isSticky()) ||
|
2000-06-22 18:08:35 +00:00
|
|
|
|
(!(*it)->isMovable()) )
|
1999-12-03 21:08:07 +00:00
|
|
|
|
continue;
|
2000-06-08 17:05:51 +00:00
|
|
|
|
cascadePlacement(*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-12-03 21:08:07 +00:00
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Unclutters the current desktop by smart-placing all clients
|
|
|
|
|
again.
|
|
|
|
|
*/
|
2000-06-08 17:05:51 +00:00
|
|
|
|
void Workspace::unclutterDesktop()
|
|
|
|
|
{
|
|
|
|
|
ClientList::Iterator it(clients.fromLast());
|
|
|
|
|
for (; it != clients.end(); --it) {
|
|
|
|
|
if((!(*it)->isOnDesktop(currentDesktop())) ||
|
|
|
|
|
((*it)->isIconified()) ||
|
|
|
|
|
((*it)->isSticky()) ||
|
2000-06-22 18:08:35 +00:00
|
|
|
|
(!(*it)->isMovable()) )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
continue;
|
|
|
|
|
smartPlacement(*it);
|
1999-12-03 21:08:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
2000-06-22 21:57:39 +00:00
|
|
|
|
/*!
|
|
|
|
|
Reread settings
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::reconfigure()
|
|
|
|
|
{
|
|
|
|
|
KGlobal::config()->reparseConfiguration();
|
|
|
|
|
options->reload();
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
2000-07-08 12:08:41 +00:00
|
|
|
|
/*!
|
2000-06-28 13:20:42 +00:00
|
|
|
|
Lowers the client \a c taking stays-on-top flags, layers,
|
|
|
|
|
transient windows and window groups into account.
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
*/
|
2000-05-03 12:57:37 +00:00
|
|
|
|
void Workspace::lowerClient( Client* c, bool dropFocus )
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
{
|
2000-05-03 06:30:37 +00:00
|
|
|
|
if ( !c )
|
|
|
|
|
return;
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
if ( c == desktop_client )
|
|
|
|
|
return; // deny
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
ClientList saveset;
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
if ( c->transientFor() ) {
|
|
|
|
|
/* search for a non-transient managed window, which this client
|
|
|
|
|
is transient to (possibly over many ways) */
|
|
|
|
|
saveset.append( c );
|
|
|
|
|
Client* t = findClient( c->transientFor() );
|
|
|
|
|
Client* tmp;
|
|
|
|
|
while ( t && !saveset.contains( t ) && t->transientFor() ) {
|
|
|
|
|
tmp = findClient( t->transientFor() );
|
|
|
|
|
if ( !tmp )
|
|
|
|
|
break;
|
|
|
|
|
saveset.append( t );
|
|
|
|
|
t = tmp;
|
|
|
|
|
}
|
|
|
|
|
if ( t && !saveset.contains( t ) && t != desktop_client ) {
|
|
|
|
|
lowerClient( t );
|
|
|
|
|
return;
|
|
|
|
|
}
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
saveset.clear();
|
|
|
|
|
saveset.append( c );
|
|
|
|
|
lowerTransientsOf(saveset, c );
|
|
|
|
|
stacking_order.remove(c);
|
|
|
|
|
stacking_order.prepend(c);
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
ClientList list = constrainedStackingOrder( stacking_order );
|
|
|
|
|
Window* new_stack = new Window[ list.count() + 1 ];
|
2000-05-03 06:30:37 +00:00
|
|
|
|
int i = 0;
|
2000-05-03 12:57:37 +00:00
|
|
|
|
Client *new_top = 0;
|
2000-06-28 13:20:42 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it) {
|
2000-05-03 06:30:37 +00:00
|
|
|
|
new_stack[i++] = (*it)->winId();
|
2000-05-03 12:57:37 +00:00
|
|
|
|
if (!new_top && (*it)->isVisible()) new_top = (*it);
|
2000-05-03 06:30:37 +00:00
|
|
|
|
}
|
|
|
|
|
XRaiseWindow(qt_xdisplay(), new_stack[0]);
|
|
|
|
|
XRestackWindows(qt_xdisplay(), new_stack, i);
|
|
|
|
|
delete [] new_stack;
|
2000-06-28 13:20:42 +00:00
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
propagateClients( TRUE );
|
2000-05-03 12:57:37 +00:00
|
|
|
|
if (dropFocus && new_top) {
|
|
|
|
|
requestFocus(new_top);
|
|
|
|
|
}
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-07-08 12:08:41 +00:00
|
|
|
|
/*!
|
2000-06-28 13:20:42 +00:00
|
|
|
|
Raises the client \a c taking layers, stays-on-top flags,
|
|
|
|
|
transient windows and window groups into account.
|
1999-08-19 23:26:42 +00:00
|
|
|
|
*/
|
|
|
|
|
void Workspace::raiseClient( Client* c )
|
|
|
|
|
{
|
|
|
|
|
if ( !c )
|
|
|
|
|
return;
|
2000-07-10 11:15:48 +00:00
|
|
|
|
|
|
|
|
|
if ( tab_box->isVisible() )
|
|
|
|
|
return;
|
|
|
|
|
|
2000-05-08 19:37:54 +00:00
|
|
|
|
ClientList saveset;
|
2000-05-26 13:54:50 +00:00
|
|
|
|
|
2000-05-08 19:37:54 +00:00
|
|
|
|
if ( c == desktop_client ) {
|
|
|
|
|
saveset.clear();
|
|
|
|
|
saveset.append( c );
|
|
|
|
|
raiseTransientsOf(saveset, c );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return; // deny
|
2000-05-08 19:37:54 +00:00
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
|
|
|
|
|
stacking_order.remove( c );
|
|
|
|
|
stacking_order.append( c );
|
|
|
|
|
|
1999-11-13 02:35:15 +00:00
|
|
|
|
if ( c->transientFor() ) {
|
|
|
|
|
saveset.append( c );
|
|
|
|
|
Client* t = findClient( c->transientFor() );
|
|
|
|
|
Client* tmp;
|
|
|
|
|
while ( t && !saveset.contains( t ) && t->transientFor() ) {
|
|
|
|
|
tmp = findClient( t->transientFor() );
|
|
|
|
|
if ( !tmp )
|
|
|
|
|
break;
|
|
|
|
|
saveset.append( t );
|
|
|
|
|
t = tmp;
|
|
|
|
|
}
|
|
|
|
|
if ( t && !saveset.contains( t ) && t != desktop_client ) {
|
|
|
|
|
raiseClient( t );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveset.clear();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
saveset.append( c );
|
|
|
|
|
raiseTransientsOf(saveset, c );
|
2000-07-08 12:08:41 +00:00
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
ClientList list = constrainedStackingOrder( stacking_order );
|
|
|
|
|
Window* new_stack = new Window[ list.count() + 1 ];
|
1999-08-19 23:26:42 +00:00
|
|
|
|
int i = 0;
|
2000-06-28 13:20:42 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = list.fromLast(); it != list.end(); --it) {
|
1999-08-19 23:26:42 +00:00
|
|
|
|
new_stack[i++] = (*it)->winId();
|
|
|
|
|
}
|
|
|
|
|
XRaiseWindow(qt_xdisplay(), new_stack[0]);
|
|
|
|
|
XRestackWindows(qt_xdisplay(), new_stack, i);
|
|
|
|
|
delete [] new_stack;
|
|
|
|
|
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-11-07 01:43:06 +00:00
|
|
|
|
propagateClients( TRUE );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Private auxiliary function used in raiseClient()
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::raiseTransientsOf( ClientList& safeset, Client* c )
|
|
|
|
|
{
|
|
|
|
|
ClientList local = stacking_order;
|
|
|
|
|
for ( ClientList::ConstIterator it = local.begin(); it != local.end(); ++it) {
|
|
|
|
|
if ( (*it)->transientFor() == c->window() && !safeset.contains( *it ) ) {
|
|
|
|
|
safeset.append( *it );
|
|
|
|
|
stacking_order.remove( *it );
|
|
|
|
|
stacking_order.append( *it );
|
|
|
|
|
raiseTransientsOf( safeset, *it );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-03 06:30:37 +00:00
|
|
|
|
/*!
|
|
|
|
|
Private auxiliary function used in lowerClient()
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::lowerTransientsOf( ClientList& safeset, Client* c )
|
|
|
|
|
{
|
|
|
|
|
ClientList local = stacking_order;
|
2000-06-28 13:20:42 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = local.fromLast(); it!=local.end(); --it) {
|
2000-05-03 12:57:37 +00:00
|
|
|
|
if ((*it)->transientFor() == c->window() && !safeset.contains(*it)) {
|
2000-05-03 06:30:37 +00:00
|
|
|
|
safeset.append( *it );
|
|
|
|
|
lowerTransientsOf( safeset, *it );
|
|
|
|
|
stacking_order.remove( *it );
|
|
|
|
|
stacking_order.prepend( *it );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Returns a stacking order based upon \a list that fulfills certain contained.
|
2000-07-08 12:08:41 +00:00
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
Currently it obeyes the staysOnTop flag only.
|
2000-07-08 12:08:41 +00:00
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
\sa Client::staysOnTop()
|
|
|
|
|
*/
|
|
|
|
|
ClientList Workspace::constrainedStackingOrder( const ClientList& list )
|
|
|
|
|
{
|
|
|
|
|
ClientList result;
|
|
|
|
|
ClientList::ConstIterator it;
|
|
|
|
|
for ( it = list.begin(); it!=list.end(); ++it) {
|
2000-06-28 13:24:04 +00:00
|
|
|
|
if ( !(*it)->staysOnTop() && !(*it)->mainClient()->staysOnTop())
|
2000-06-28 13:20:42 +00:00
|
|
|
|
result.append( *it );
|
|
|
|
|
}
|
|
|
|
|
for ( it = list.begin(); it!=list.end(); ++it) {
|
2000-06-28 13:24:04 +00:00
|
|
|
|
if ( (*it)->staysOnTop() || (*it)->mainClient()->staysOnTop() )
|
2000-06-28 13:20:42 +00:00
|
|
|
|
result.append( *it );
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-19 23:26:42 +00:00
|
|
|
|
/*!
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Puts the focus on a dummy window
|
1999-08-19 23:26:42 +00:00
|
|
|
|
*/
|
|
|
|
|
void Workspace::focusToNull(){
|
|
|
|
|
static Window w = 0;
|
|
|
|
|
int mask;
|
|
|
|
|
XSetWindowAttributes attr;
|
|
|
|
|
if (w == 0) {
|
|
|
|
|
mask = CWOverrideRedirect;
|
|
|
|
|
attr.override_redirect = 1;
|
|
|
|
|
w = XCreateWindow(qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0, CopyFromParent,
|
|
|
|
|
InputOnly, CopyFromParent, mask, &attr);
|
|
|
|
|
XMapWindow(qt_xdisplay(), w);
|
|
|
|
|
}
|
1999-11-28 21:41:15 +00:00
|
|
|
|
XSetInputFocus(qt_xdisplay(), w, RevertToPointerRoot, kwin_time );
|
1999-08-19 23:26:42 +00:00
|
|
|
|
//colormapFocus(0); TODO
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Declares client \a c to be the desktop.
|
|
|
|
|
*/
|
1999-08-19 23:26:42 +00:00
|
|
|
|
void Workspace::setDesktopClient( Client* c)
|
|
|
|
|
{
|
|
|
|
|
desktop_client = c;
|
|
|
|
|
if ( desktop_client ) {
|
|
|
|
|
desktop_client->lower();
|
|
|
|
|
desktop_client->setGeometry( geometry() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-07 01:43:06 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sets the current desktop to \a new_desktop
|
|
|
|
|
|
|
|
|
|
Shows/Hides windows according to the stacking order and finally
|
|
|
|
|
propages the new desktop to the world
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::setCurrentDesktop( int new_desktop ){
|
2000-05-30 05:52:11 +00:00
|
|
|
|
if (new_desktop < 1 || new_desktop > number_of_desktops )
|
1999-08-19 23:26:42 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2000-06-01 05:32:06 +00:00
|
|
|
|
active_client = 0;
|
1999-11-29 02:49:20 +00:00
|
|
|
|
block_focus = TRUE;
|
1999-11-29 14:19:32 +00:00
|
|
|
|
|
2000-05-30 05:52:11 +00:00
|
|
|
|
if (new_desktop != current_desktop) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
/*
|
2000-06-01 05:32:06 +00:00
|
|
|
|
optimized Desktop switching: unmapping done from back to front
|
|
|
|
|
mapping done from front to back => less exposure events
|
|
|
|
|
*/
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
|
|
|
|
|
if ( (*it)->isVisible() && !(*it)->isOnDesktop( new_desktop ) ) {
|
|
|
|
|
(*it)->hide();
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-06-24 17:58:10 +00:00
|
|
|
|
current_desktop = new_desktop;
|
|
|
|
|
rootInfo->setCurrentDesktop( current_desktop ); // propagate befor the shows below
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
|
|
|
|
|
if ( (*it)->isOnDesktop( new_desktop ) && !(*it)->isIconified() ) {
|
|
|
|
|
(*it)->show();
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
2000-06-24 19:09:50 +00:00
|
|
|
|
current_desktop = new_desktop;
|
|
|
|
|
|
|
|
|
|
rootInfo->setCurrentDesktop( current_desktop );
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
1999-11-29 02:49:20 +00:00
|
|
|
|
// restore the focus on this desktop
|
|
|
|
|
block_focus = FALSE;
|
2000-06-01 05:32:06 +00:00
|
|
|
|
Client* c = 0;
|
|
|
|
|
|
|
|
|
|
if ( options->focusPolicyIsReasonable()) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
if (options->focusPolicy == Options::FocusFollowsMouse) {
|
|
|
|
|
// Search in focus chain
|
|
|
|
|
for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it) {
|
2000-06-22 18:08:35 +00:00
|
|
|
|
if ( (*it)->isVisible() ) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
c = *it;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!c) {
|
|
|
|
|
// Search top-most visible window
|
|
|
|
|
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
|
2000-06-22 18:08:35 +00:00
|
|
|
|
if ( (*it)->isVisible() ) {
|
2000-06-08 17:05:51 +00:00
|
|
|
|
c = *it;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-11-20 13:51:29 +00:00
|
|
|
|
}
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
2000-06-01 05:32:06 +00:00
|
|
|
|
if ( c )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
requestFocus( c );
|
2000-05-30 05:52:11 +00:00
|
|
|
|
else
|
2000-06-08 17:05:51 +00:00
|
|
|
|
focusToNull();
|
1999-11-20 13:51:29 +00:00
|
|
|
|
|
1999-11-15 00:52:05 +00:00
|
|
|
|
QApplication::syncX();
|
1999-08-19 23:26:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Returns the workspace's desktop widget. The desktop widget is
|
|
|
|
|
sometimes required by clients to draw on it, for example outlines on
|
|
|
|
|
moving or resizing.
|
|
|
|
|
*/
|
1999-09-27 16:02:44 +00:00
|
|
|
|
QWidget* Workspace::desktopWidget()
|
|
|
|
|
{
|
|
|
|
|
return desktop_widget;
|
|
|
|
|
}
|
1999-11-07 01:43:06 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sets the number of virtual desktops to \a n
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::setNumberOfDesktops( int n )
|
|
|
|
|
{
|
|
|
|
|
if ( n == number_of_desktops )
|
|
|
|
|
return;
|
|
|
|
|
number_of_desktops = n;
|
2000-06-08 17:05:51 +00:00
|
|
|
|
rootInfo->setNumberOfDesktops( number_of_desktops );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Handles client messages sent to the workspace
|
|
|
|
|
*/
|
2000-06-08 17:05:51 +00:00
|
|
|
|
bool Workspace::netCheck( XEvent* e )
|
1999-11-07 01:43:06 +00:00
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
unsigned int dirty = rootInfo->event( e );
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
dirty = 0; // shut up, compiler
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
1999-11-07 01:43:06 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Propagates the managed clients to the world
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::propagateClients( bool onlyStacking )
|
|
|
|
|
{
|
|
|
|
|
WId* cl;
|
|
|
|
|
int i;
|
|
|
|
|
if ( !onlyStacking ) {
|
1999-11-11 01:22:41 +00:00
|
|
|
|
cl = new WId[ clients.count()];
|
1999-11-07 01:43:06 +00:00
|
|
|
|
i = 0;
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it ) {
|
|
|
|
|
cl[i++] = (*it)->window();
|
|
|
|
|
}
|
2000-06-08 17:05:51 +00:00
|
|
|
|
rootInfo->setClientList( (Window*) cl, i );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
delete [] cl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cl = new WId[ stacking_order.count()];
|
|
|
|
|
i = 0;
|
|
|
|
|
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
|
|
|
|
|
cl[i++] = (*it)->window();
|
|
|
|
|
}
|
2000-06-08 17:05:51 +00:00
|
|
|
|
rootInfo->setClientListStacking( (Window*) cl, i );
|
1999-11-07 01:43:06 +00:00
|
|
|
|
delete [] cl;
|
|
|
|
|
}
|
1999-11-11 01:22:41 +00:00
|
|
|
|
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
2000-06-28 07:51:45 +00:00
|
|
|
|
Check whether \a w is a system tray window. If so, add it to the respective
|
1999-12-06 00:43:55 +00:00
|
|
|
|
datastructures and propagate it to the world.
|
|
|
|
|
*/
|
2000-06-28 07:51:45 +00:00
|
|
|
|
bool Workspace::addSystemTrayWin( WId w )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
{
|
2000-06-28 07:51:45 +00:00
|
|
|
|
if ( systemTrayWins.contains( w ) )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
return TRUE;
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-28 07:51:45 +00:00
|
|
|
|
NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDESystemTrayWinFor );
|
|
|
|
|
WId trayWinFor = ni.kdeSystemTrayWinFor();
|
|
|
|
|
if ( !trayWinFor )
|
2000-06-08 17:05:51 +00:00
|
|
|
|
return FALSE;
|
2000-06-28 07:51:45 +00:00
|
|
|
|
systemTrayWins.append( SystemTrayWindow( w, trayWinFor ) );
|
1999-11-11 01:22:41 +00:00
|
|
|
|
XSelectInput( qt_xdisplay(), w,
|
|
|
|
|
StructureNotifyMask
|
|
|
|
|
);
|
2000-06-08 17:05:51 +00:00
|
|
|
|
XAddToSaveSet( qt_xdisplay(), w );
|
2000-06-28 07:51:45 +00:00
|
|
|
|
propagateSystemTrayWins();
|
1999-11-11 01:22:41 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
/*!
|
2000-06-28 07:51:45 +00:00
|
|
|
|
Check whether \a w is a system tray window. If so, remove it from
|
|
|
|
|
the respective datastructures and propagate this to the world.
|
1999-12-06 00:43:55 +00:00
|
|
|
|
*/
|
2000-06-28 07:51:45 +00:00
|
|
|
|
bool Workspace::removeSystemTrayWin( WId w )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
{
|
2000-06-28 07:51:45 +00:00
|
|
|
|
if ( !systemTrayWins.contains( w ) )
|
1999-11-11 01:22:41 +00:00
|
|
|
|
return FALSE;
|
2000-06-28 07:51:45 +00:00
|
|
|
|
systemTrayWins.remove( w );
|
|
|
|
|
propagateSystemTrayWins();
|
1999-11-11 01:22:41 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Returns whether iconify means actually withdraw for client \a. This
|
|
|
|
|
is TRUE for clients that have a docking window. In that case the
|
|
|
|
|
docking window will serve as icon replacement.
|
|
|
|
|
*/
|
1999-11-14 06:34:28 +00:00
|
|
|
|
bool Workspace::iconifyMeansWithdraw( Client* c)
|
|
|
|
|
{
|
2000-06-28 07:51:45 +00:00
|
|
|
|
for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it ) {
|
|
|
|
|
if ( (*it).winFor == c->window() )
|
1999-11-14 06:34:28 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-11 01:22:41 +00:00
|
|
|
|
/*!
|
2000-06-28 07:51:45 +00:00
|
|
|
|
Propagates the systemTrayWins to the world
|
1999-11-11 01:22:41 +00:00
|
|
|
|
*/
|
2000-06-28 07:51:45 +00:00
|
|
|
|
void Workspace::propagateSystemTrayWins()
|
1999-11-11 01:22:41 +00:00
|
|
|
|
{
|
2000-06-28 07:51:45 +00:00
|
|
|
|
WId* cl = new WId[ systemTrayWins.count()];
|
1999-11-11 01:22:41 +00:00
|
|
|
|
int i = 0;
|
2000-06-28 07:51:45 +00:00
|
|
|
|
for ( SystemTrayWindowList::ConstIterator it = systemTrayWins.begin(); it != systemTrayWins.end(); ++it ) {
|
|
|
|
|
cl[i++] = (*it).win;
|
1999-11-11 01:22:41 +00:00
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-28 07:51:45 +00:00
|
|
|
|
rootInfo->setKDESystemTrayWindows( (Window*) cl, i );
|
1999-11-11 01:22:41 +00:00
|
|
|
|
delete [] cl;
|
|
|
|
|
}
|
1999-11-13 01:51:22 +00:00
|
|
|
|
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
/*!
|
|
|
|
|
Create the global accel object \c keys.
|
|
|
|
|
*/
|
1999-11-13 01:51:22 +00:00
|
|
|
|
void Workspace::createKeybindings(){
|
|
|
|
|
keys = new KGlobalAccel();
|
1999-11-14 06:34:28 +00:00
|
|
|
|
|
1999-11-13 01:51:22 +00:00
|
|
|
|
#include "kwinbindings.cpp"
|
|
|
|
|
|
|
|
|
|
keys->connectItem( "Switch to desktop 1", this, SLOT( slotSwitchDesktop1() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 2", this, SLOT( slotSwitchDesktop2() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 3", this, SLOT( slotSwitchDesktop3() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 4", this, SLOT( slotSwitchDesktop4() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 5", this, SLOT( slotSwitchDesktop5() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 6", this, SLOT( slotSwitchDesktop6() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 7", this, SLOT( slotSwitchDesktop7() ));
|
|
|
|
|
keys->connectItem( "Switch to desktop 8", this, SLOT( slotSwitchDesktop8() ));
|
2000-07-04 17:07:58 +00:00
|
|
|
|
keys->connectItem( "Switch desktop left", this, SLOT( slotSwitchDesktopLeft() ));
|
|
|
|
|
keys->connectItem( "Switch desktop right", this, SLOT( slotSwitchDesktopRight() ));
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
keys->connectItem( "Pop-up window operations menu", this, SLOT( slotWindowOperations() ) );
|
|
|
|
|
keys->connectItem( "Window close", this, SLOT( slotWindowClose() ) );
|
1999-11-29 02:18:29 +00:00
|
|
|
|
keys->connectItem( "Window maximize", this, SLOT( slotWindowMaximize() ) );
|
|
|
|
|
keys->connectItem( "Window maximize horizontal", this, SLOT( slotWindowMaximizeHorizontal() ) );
|
|
|
|
|
keys->connectItem( "Window maximize vertical", this, SLOT( slotWindowMaximizeVertical() ) );
|
|
|
|
|
keys->connectItem( "Window iconify", this, SLOT( slotWindowIconify() ) );
|
1999-11-29 02:49:20 +00:00
|
|
|
|
keys->connectItem( "Window shade", this, SLOT( slotWindowShade() ) );
|
1999-12-06 00:43:55 +00:00
|
|
|
|
keys->connectItem( "Window move", this, SLOT( slotWindowMove() ) );
|
|
|
|
|
keys->connectItem( "Window resize", this, SLOT( slotWindowResize() ) );
|
1999-11-13 01:51:22 +00:00
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
keys->connectItem( "Mouse emulation", this, SLOT( slotMouseEmulation() ) );
|
2000-05-17 20:15:17 +00:00
|
|
|
|
|
|
|
|
|
keys->connectItem( "Logout", this, SLOT( slotLogout() ) );
|
2000-05-17 23:02:42 +00:00
|
|
|
|
|
|
|
|
|
keys->connectItem( "Kill Window", this, SLOT( slotKillWindow() ) );
|
1999-11-13 01:51:22 +00:00
|
|
|
|
keys->readSettings();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Workspace::slotSwitchDesktop1(){
|
|
|
|
|
setCurrentDesktop(1);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop2(){
|
|
|
|
|
setCurrentDesktop(2);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop3(){
|
|
|
|
|
setCurrentDesktop(3);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop4(){
|
|
|
|
|
setCurrentDesktop(4);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop5(){
|
|
|
|
|
setCurrentDesktop(5);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop6(){
|
|
|
|
|
setCurrentDesktop(6);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop7(){
|
|
|
|
|
setCurrentDesktop(7);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktop8(){
|
|
|
|
|
setCurrentDesktop(8);
|
|
|
|
|
}
|
2000-07-04 17:07:58 +00:00
|
|
|
|
void Workspace::slotSwitchDesktopRight(){
|
|
|
|
|
int d = currentDesktop() + 1;
|
|
|
|
|
if ( d > number_of_desktops )
|
|
|
|
|
d = 1;
|
|
|
|
|
setCurrentDesktop(d);
|
|
|
|
|
}
|
|
|
|
|
void Workspace::slotSwitchDesktopLeft(){
|
|
|
|
|
int d = currentDesktop() - 1;
|
|
|
|
|
if ( d <= 0 )
|
|
|
|
|
d = number_of_desktops;
|
|
|
|
|
setCurrentDesktop(d);
|
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Maximizes the popup client
|
|
|
|
|
*/
|
1999-11-29 02:18:29 +00:00
|
|
|
|
void Workspace::slotWindowMaximize()
|
|
|
|
|
{
|
|
|
|
|
if ( popup_client )
|
|
|
|
|
popup_client->maximize( Client::MaximizeFull );
|
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Maximizes the popup client vertically
|
|
|
|
|
*/
|
1999-11-29 02:18:29 +00:00
|
|
|
|
void Workspace::slotWindowMaximizeVertical()
|
|
|
|
|
{
|
|
|
|
|
if ( popup_client )
|
|
|
|
|
popup_client->maximize( Client::MaximizeVertical );
|
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Maximizes the popup client horiozontally
|
|
|
|
|
*/
|
1999-11-29 02:18:29 +00:00
|
|
|
|
void Workspace::slotWindowMaximizeHorizontal()
|
|
|
|
|
{
|
|
|
|
|
if ( popup_client )
|
|
|
|
|
popup_client->maximize( Client::MaximizeHorizontal );
|
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Iconifies the popup client
|
|
|
|
|
*/
|
1999-11-29 02:18:29 +00:00
|
|
|
|
void Workspace::slotWindowIconify()
|
|
|
|
|
{
|
1999-12-06 00:43:55 +00:00
|
|
|
|
performWindowOperation( popup_client, Options::IconifyOp );
|
1999-11-29 02:18:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
/*!
|
|
|
|
|
Shades/unshades the popup client respectively
|
|
|
|
|
*/
|
1999-11-29 02:49:20 +00:00
|
|
|
|
void Workspace::slotWindowShade()
|
|
|
|
|
{
|
1999-12-06 00:43:55 +00:00
|
|
|
|
performWindowOperation( popup_client, Options::ShadeOp );
|
1999-11-29 02:49:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Invokes keyboard mouse emulation
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::slotMouseEmulation()
|
|
|
|
|
{
|
|
|
|
|
if ( XGrabKeyboard(qt_xdisplay(),
|
|
|
|
|
root, FALSE,
|
|
|
|
|
GrabModeAsync, GrabModeAsync,
|
|
|
|
|
kwin_time) == GrabSuccess ) {
|
|
|
|
|
mouse_emulation = TRUE;
|
2000-06-21 17:43:44 +00:00
|
|
|
|
mouse_emulation_state = 0;
|
|
|
|
|
mouse_emulation_window = 0;
|
1999-12-06 00:43:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-17 20:15:17 +00:00
|
|
|
|
void Workspace::slotLogout()
|
|
|
|
|
{
|
|
|
|
|
kapp->requestShutDown();
|
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Kill Window feature, similar to xkill
|
|
|
|
|
*/
|
2000-05-17 23:02:42 +00:00
|
|
|
|
void Workspace::slotKillWindow()
|
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
KillWindow kill( this );
|
|
|
|
|
kill.start();
|
2000-05-17 23:02:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Kills the window at position \a x, \a y
|
|
|
|
|
*/
|
2000-05-17 23:02:42 +00:00
|
|
|
|
void Workspace::killWindowAtPosition(int x, int y)
|
|
|
|
|
{
|
2000-05-29 22:38:43 +00:00
|
|
|
|
ClientList::ConstIterator it(stacking_order.fromLast());
|
|
|
|
|
for ( ; it != stacking_order.end(); --it)
|
2000-05-17 23:02:42 +00:00
|
|
|
|
{
|
|
|
|
|
Client *client = (*it);
|
2000-05-29 22:38:43 +00:00
|
|
|
|
if ( client->frameGeometry().contains(QPoint(x, y)) &&
|
2000-05-26 13:54:50 +00:00
|
|
|
|
client->isOnDesktop( currentDesktop() ) &&
|
2000-05-17 23:02:42 +00:00
|
|
|
|
!client->isIconified() )
|
|
|
|
|
{
|
|
|
|
|
client->killWindow();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
/*!
|
|
|
|
|
Adjusts the desktop popup to the current values and the location of
|
|
|
|
|
the popup client.
|
|
|
|
|
*/
|
1999-11-22 01:57:51 +00:00
|
|
|
|
void Workspace::desktopPopupAboutToShow()
|
|
|
|
|
{
|
1999-11-25 16:38:11 +00:00
|
|
|
|
if ( !desk_popup )
|
1999-11-22 01:57:51 +00:00
|
|
|
|
return;
|
|
|
|
|
desk_popup->clear();
|
1999-11-22 18:34:46 +00:00
|
|
|
|
desk_popup->insertItem( i18n("&All desktops"), 0 );
|
|
|
|
|
if ( popup_client->isSticky() )
|
|
|
|
|
desk_popup->setItemChecked( 0, TRUE );
|
2000-03-12 06:18:14 +00:00
|
|
|
|
desk_popup->insertSeparator( -1 );
|
1999-11-22 01:57:51 +00:00
|
|
|
|
int id;
|
|
|
|
|
for ( int i = 1; i <= numberOfDesktops(); i++ ) {
|
|
|
|
|
id = desk_popup->insertItem( QString("&")+QString::number(i ), i );
|
1999-11-22 18:34:46 +00:00
|
|
|
|
if ( popup_client && !popup_client->isSticky() && popup_client->desktop() == i )
|
1999-11-22 01:57:51 +00:00
|
|
|
|
desk_popup->setItemChecked( id, TRUE );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
The client popup menu will become visible soon.
|
1999-12-07 21:54:52 +00:00
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
Adjust the items according to the respective popup client.
|
|
|
|
|
*/
|
1999-11-22 01:57:51 +00:00
|
|
|
|
void Workspace::clientPopupAboutToShow()
|
|
|
|
|
{
|
|
|
|
|
if ( !popup_client || !popup )
|
|
|
|
|
return;
|
1999-11-29 02:06:41 +00:00
|
|
|
|
popup->setItemChecked( Options::MaximizeOp, popup_client->isMaximized() );
|
|
|
|
|
popup->setItemChecked( Options::ShadeOp, popup_client->isShade() );
|
2000-06-28 13:20:42 +00:00
|
|
|
|
popup->setItemChecked( Options::StaysOnTopOp, popup_client->staysOnTop() );
|
1999-11-22 01:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
2000-06-23 18:56:59 +00:00
|
|
|
|
Sends client \a c to desktop \a desk.
|
2000-06-24 17:58:10 +00:00
|
|
|
|
|
2000-06-23 18:56:59 +00:00
|
|
|
|
Takes care of transients as well.
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::sendClientToDesktop( Client* c, int desk )
|
|
|
|
|
{
|
|
|
|
|
if ( c->isSticky() )
|
|
|
|
|
c->setSticky( FALSE );
|
|
|
|
|
|
|
|
|
|
if ( c->isOnDesktop( desk ) )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
c->setDesktop( desk );
|
|
|
|
|
c->hide();
|
|
|
|
|
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
if ( (*it)->transientFor() == c->window() ) {
|
|
|
|
|
sendClientToDesktop( *it, desk );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sends the popup client to desktop \a desk
|
2000-06-24 17:58:10 +00:00
|
|
|
|
|
2000-06-23 18:56:59 +00:00
|
|
|
|
Internal slot for the window operation menu
|
1999-12-06 00:43:55 +00:00
|
|
|
|
*/
|
1999-11-22 01:57:51 +00:00
|
|
|
|
void Workspace::sendToDesktop( int desk )
|
|
|
|
|
{
|
|
|
|
|
if ( !popup_client )
|
|
|
|
|
return;
|
1999-11-22 18:34:46 +00:00
|
|
|
|
if ( desk == 0 ) {
|
|
|
|
|
popup_client->setSticky( !popup_client->isSticky() );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-06-24 17:58:10 +00:00
|
|
|
|
|
2000-06-23 18:56:59 +00:00
|
|
|
|
sendClientToDesktop( popup_client, desk );
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Shows the window operations popup menu for the activeClient()
|
|
|
|
|
*/
|
1999-11-22 01:57:51 +00:00
|
|
|
|
void Workspace::slotWindowOperations()
|
|
|
|
|
{
|
|
|
|
|
if ( !active_client )
|
|
|
|
|
return;
|
2000-06-22 18:08:35 +00:00
|
|
|
|
if ( !active_client->isMovable())
|
2000-05-20 07:54:11 +00:00
|
|
|
|
return;
|
|
|
|
|
|
1999-11-22 01:57:51 +00:00
|
|
|
|
QPopupMenu* p = clientPopup( active_client );
|
|
|
|
|
p->popup( active_client->mapToGlobal( active_client->windowWrapper()->geometry().topLeft() ) );
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Closes the popup client
|
|
|
|
|
*/
|
1999-11-22 01:57:51 +00:00
|
|
|
|
void Workspace::slotWindowClose()
|
|
|
|
|
{
|
1999-12-06 00:43:55 +00:00
|
|
|
|
performWindowOperation( popup_client, Options::CloseOp );
|
1999-11-22 01:57:51 +00:00
|
|
|
|
}
|
1999-11-25 16:38:11 +00:00
|
|
|
|
|
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
/*!
|
|
|
|
|
Starts keyboard move mode for the popup client
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::slotWindowMove()
|
|
|
|
|
{
|
|
|
|
|
performWindowOperation( popup_client, Options::MoveOp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Starts keyboard resize mode for the popup client
|
|
|
|
|
*/
|
|
|
|
|
void Workspace::slotWindowResize()
|
|
|
|
|
{
|
|
|
|
|
performWindowOperation( popup_client, Options::ResizeOp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
1999-11-25 16:38:11 +00:00
|
|
|
|
Client \a c is moved around to position \a pos. This gives the
|
|
|
|
|
workspace the opportunity to interveniate and to implement
|
|
|
|
|
snap-to-windows functionality.
|
|
|
|
|
*/
|
|
|
|
|
QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
|
|
|
|
|
{
|
1999-11-25 23:12:32 +00:00
|
|
|
|
//CT 16mar98, 27May98 - magics: BorderSnapZone, WindowSnapZone
|
|
|
|
|
//CT adapted for kwin on 25Nov1999
|
2000-07-09 20:29:53 +00:00
|
|
|
|
if (options->windowSnapZone || options->borderSnapZone ) {
|
1999-11-25 23:12:32 +00:00
|
|
|
|
|
|
|
|
|
int snap; //snap trigger
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
QRect maxRect = clientArea();
|
|
|
|
|
int xmin = maxRect.left();
|
2000-05-10 04:36:50 +00:00
|
|
|
|
int xmax = maxRect.right()+1; //desk size
|
1999-11-25 23:12:32 +00:00
|
|
|
|
int ymin = maxRect.top();
|
2000-05-10 04:36:50 +00:00
|
|
|
|
int ymax = maxRect.bottom()+1;
|
1999-11-25 23:12:32 +00:00
|
|
|
|
int cx, cy, rx, ry, cw, ch; //these don't change
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
int nx, ny; //buffers
|
|
|
|
|
int deltaX = xmax, deltaY = ymax; //minimum distance to other clients
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
int lx, ly, lrx, lry; //coords and size for the comparison client, l
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
nx = cx = pos.x();
|
|
|
|
|
ny = cy = pos.y();
|
|
|
|
|
rx = cx + (cw = c->width());
|
|
|
|
|
ry = cy + (ch = c->height());
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
// border snap
|
2000-07-09 20:29:53 +00:00
|
|
|
|
snap = options->borderSnapZone;
|
1999-11-25 23:12:32 +00:00
|
|
|
|
if (snap) {
|
|
|
|
|
if ( QABS(cx-xmin) < snap ){
|
|
|
|
|
deltaX = QABS(cx - xmin);
|
|
|
|
|
nx = xmin;
|
|
|
|
|
}
|
|
|
|
|
if ((QABS(xmax-rx) < snap) && (QABS(xmax-rx) < deltaX)) {
|
2000-05-10 04:36:50 +00:00
|
|
|
|
deltaX = QABS(xmax-rx);
|
1999-11-25 23:12:32 +00:00
|
|
|
|
nx = xmax - cw;
|
|
|
|
|
}
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
if ( QABS(cy-ymin) < snap ){
|
|
|
|
|
deltaY = QABS(cy-ymin);
|
|
|
|
|
ny = ymin;
|
|
|
|
|
}
|
|
|
|
|
if ((QABS(ymax-ry) < snap) && (QABS(ymax-ry) < deltaY)) {
|
|
|
|
|
deltaY = QABS(ymax-ry);
|
|
|
|
|
ny = ymax - ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-11-28 20:10:58 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
// windows snap
|
2000-07-09 20:29:53 +00:00
|
|
|
|
snap = options->windowSnapZone;
|
1999-11-25 23:12:32 +00:00
|
|
|
|
if (snap) {
|
|
|
|
|
QValueList<Client *>::ConstIterator l;
|
|
|
|
|
for (l = clients.begin();l != clients.end();++l ) {
|
|
|
|
|
if((*l)->isOnDesktop(currentDesktop()) && (*l) != desktop_client &&
|
|
|
|
|
!(*l)->isIconified() && (*l)->transientFor() == None &&
|
|
|
|
|
(*l) != c ) {
|
|
|
|
|
lx = (*l)->x();
|
|
|
|
|
ly = (*l)->y();
|
|
|
|
|
lrx = lx + (*l)->width();
|
|
|
|
|
lry = ly + (*l)->height();
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
if( ( ( cy <= lry ) && ( cy >= ly ) ) ||
|
|
|
|
|
( ( ry >= ly ) && ( ry <= lry ) ) ||
|
|
|
|
|
( ( ly >= cy ) && ( lry <= ry ) ) ) {
|
|
|
|
|
if ( ( QABS( lrx - cx ) < snap ) &&
|
|
|
|
|
( QABS( lrx -cx ) < deltaX ) ) {
|
|
|
|
|
deltaX = QABS( lrx - cx );
|
|
|
|
|
nx = lrx;
|
|
|
|
|
}
|
|
|
|
|
if ( ( QABS( rx - lx ) < snap ) &&
|
|
|
|
|
( QABS( rx - lx ) < deltaX ) ) {
|
2000-05-10 04:36:50 +00:00
|
|
|
|
deltaX = QABS(rx - lx);
|
1999-11-25 23:12:32 +00:00
|
|
|
|
nx = lx - cw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-03-21 20:02:27 +00:00
|
|
|
|
|
1999-11-25 23:12:32 +00:00
|
|
|
|
if( ( ( cx <= lrx ) && ( cx >= lx ) ) ||
|
|
|
|
|
( ( rx >= lx ) && ( rx <= lrx ) ) ||
|
|
|
|
|
( ( lx >= cx ) && ( lrx <= rx ) ) ) {
|
|
|
|
|
if ( ( QABS( lry - cy ) < snap ) &&
|
|
|
|
|
( QABS( lry -cy ) < deltaY ) ) {
|
|
|
|
|
deltaY = QABS( lry - cy );
|
|
|
|
|
ny = lry;
|
|
|
|
|
}
|
|
|
|
|
if ( ( QABS( ry-ly ) < snap ) &&
|
|
|
|
|
( QABS( ry - ly ) < deltaY ) ) {
|
|
|
|
|
deltaY = QABS( ry - ly );
|
|
|
|
|
ny = ly - ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pos = QPoint(nx, ny);
|
|
|
|
|
}
|
|
|
|
|
return pos;
|
1999-11-25 16:38:11 +00:00
|
|
|
|
}
|
1999-12-06 00:43:55 +00:00
|
|
|
|
|
|
|
|
|
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Returns the child window under the mouse and activates the
|
|
|
|
|
respective client if necessary.
|
|
|
|
|
|
|
|
|
|
Auxiliary function for the mouse emulation system.
|
|
|
|
|
*/
|
|
|
|
|
WId Workspace::getMouseEmulationWindow()
|
|
|
|
|
{
|
|
|
|
|
Window root;
|
|
|
|
|
Window child = qt_xrootwin();
|
|
|
|
|
int root_x, root_y, lx, ly;
|
|
|
|
|
uint state;
|
|
|
|
|
Window w;
|
|
|
|
|
Client * c = 0;
|
|
|
|
|
do {
|
|
|
|
|
w = child;
|
|
|
|
|
if (!c)
|
|
|
|
|
c = findClientWidthId( w );
|
|
|
|
|
XQueryPointer( qt_xdisplay(), w, &root, &child,
|
|
|
|
|
&root_x, &root_y, &lx, &ly, &state );
|
|
|
|
|
} while ( child != None && child != w );
|
|
|
|
|
|
|
|
|
|
if ( c && !c->isActive() )
|
|
|
|
|
activateClient( c );
|
|
|
|
|
return (WId) w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Sends a faked mouse event to the specified window. Returns the new button state.
|
|
|
|
|
*/
|
|
|
|
|
unsigned int Workspace::sendFakedMouseEvent( QPoint pos, WId w, MouseEmulation type, int button, unsigned int state )
|
|
|
|
|
{
|
|
|
|
|
if ( !w )
|
|
|
|
|
return state;
|
|
|
|
|
QWidget* widget = QWidget::find( w );
|
|
|
|
|
if ( (!widget || widget->inherits("QToolButton") ) && !findClient( w ) ) {
|
|
|
|
|
int x, y;
|
|
|
|
|
Window xw;
|
|
|
|
|
XTranslateCoordinates( qt_xdisplay(), qt_xrootwin(), w, pos.x(), pos.y(), &x, &y, &xw );
|
|
|
|
|
if ( type == EmuMove ) { // motion notify events
|
|
|
|
|
XMotionEvent e;
|
|
|
|
|
e.type = MotionNotify;
|
|
|
|
|
e.window = w;
|
|
|
|
|
e.root = qt_xrootwin();
|
|
|
|
|
e.subwindow = w;
|
|
|
|
|
e.time = kwin_time;
|
|
|
|
|
e.x = x;
|
|
|
|
|
e.y = y;
|
|
|
|
|
e.x_root = pos.x();
|
|
|
|
|
e.y_root = pos.y();
|
|
|
|
|
e.state = state;
|
|
|
|
|
e.is_hint = NotifyNormal;
|
|
|
|
|
XSendEvent( qt_xdisplay(), w, TRUE, ButtonMotionMask, (XEvent*)&e );
|
|
|
|
|
} else {
|
|
|
|
|
XButtonEvent e;
|
|
|
|
|
e.type = type == EmuRelease ? ButtonRelease : ButtonPress;
|
|
|
|
|
e.window = w;
|
|
|
|
|
e.root = qt_xrootwin();
|
|
|
|
|
e.subwindow = w;
|
|
|
|
|
e.time = kwin_time;
|
|
|
|
|
e.x = x;
|
|
|
|
|
e.y = y;
|
|
|
|
|
e.x_root = pos.x();
|
|
|
|
|
e.y_root = pos.y();
|
|
|
|
|
e.state = state;
|
|
|
|
|
e.button = button;
|
|
|
|
|
XSendEvent( qt_xdisplay(), w, TRUE, ButtonPressMask, (XEvent*)&e );
|
|
|
|
|
|
|
|
|
|
if ( type == EmuPress ) {
|
|
|
|
|
switch ( button ) {
|
|
|
|
|
case 2:
|
|
|
|
|
state |= Button2Mask;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
state |= Button3Mask;
|
|
|
|
|
break;
|
|
|
|
|
default: // 1
|
|
|
|
|
state |= Button1Mask;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
switch ( button ) {
|
|
|
|
|
case 2:
|
|
|
|
|
state &= ~Button2Mask;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
state &= ~Button3Mask;
|
|
|
|
|
break;
|
|
|
|
|
default: // 1
|
|
|
|
|
state &= ~Button1Mask;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-07 21:54:52 +00:00
|
|
|
|
/*!
|
1999-12-06 00:43:55 +00:00
|
|
|
|
Handles keypress event during mouse emulation
|
|
|
|
|
*/
|
|
|
|
|
bool Workspace::keyPressMouseEmulation( XKeyEvent key )
|
|
|
|
|
{
|
|
|
|
|
if ( root != qt_xrootwin() )
|
|
|
|
|
return FALSE;
|
|
|
|
|
int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0);
|
|
|
|
|
int km = key.state & (ControlMask | Mod1Mask | ShiftMask);
|
1999-12-07 21:54:52 +00:00
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
bool is_control = km & ControlMask;
|
|
|
|
|
bool is_alt = km & Mod1Mask;
|
2000-06-21 17:43:44 +00:00
|
|
|
|
bool is_shift = km & ShiftMask;
|
1999-12-06 00:43:55 +00:00
|
|
|
|
int delta = is_control?1:is_alt?32:8;
|
|
|
|
|
QPoint pos = QCursor::pos();
|
1999-12-07 21:54:52 +00:00
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
switch ( kc ) {
|
|
|
|
|
case XK_Left:
|
|
|
|
|
case XK_KP_Left:
|
|
|
|
|
pos.rx() -= delta;
|
|
|
|
|
break;
|
|
|
|
|
case XK_Right:
|
|
|
|
|
case XK_KP_Right:
|
|
|
|
|
pos.rx() += delta;
|
|
|
|
|
break;
|
|
|
|
|
case XK_Up:
|
|
|
|
|
case XK_KP_Up:
|
|
|
|
|
pos.ry() -= delta;
|
|
|
|
|
break;
|
|
|
|
|
case XK_Down:
|
|
|
|
|
case XK_KP_Down:
|
|
|
|
|
pos.ry() += delta;
|
|
|
|
|
break;
|
2000-06-21 17:43:44 +00:00
|
|
|
|
case XK_F1:
|
|
|
|
|
if ( !mouse_emulation_state )
|
|
|
|
|
mouse_emulation_window = getMouseEmulationWindow();
|
|
|
|
|
if ( (mouse_emulation_state & Button1Mask) == 0 )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
|
|
|
|
|
if ( !is_shift )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
|
|
|
|
|
break;
|
|
|
|
|
case XK_F2:
|
|
|
|
|
if ( !mouse_emulation_state )
|
|
|
|
|
mouse_emulation_window = getMouseEmulationWindow();
|
|
|
|
|
if ( (mouse_emulation_state & Button2Mask) == 0 )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button2, mouse_emulation_state );
|
|
|
|
|
if ( !is_shift )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
|
|
|
|
|
break;
|
|
|
|
|
case XK_F3:
|
|
|
|
|
if ( !mouse_emulation_state )
|
|
|
|
|
mouse_emulation_window = getMouseEmulationWindow();
|
|
|
|
|
if ( (mouse_emulation_state & Button3Mask) == 0 )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button3, mouse_emulation_state );
|
|
|
|
|
if ( !is_shift )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
|
|
|
|
|
break;
|
1999-12-06 00:43:55 +00:00
|
|
|
|
case XK_Return:
|
|
|
|
|
case XK_space:
|
|
|
|
|
case XK_KP_Enter:
|
|
|
|
|
case XK_KP_Space:
|
|
|
|
|
{
|
2000-06-21 17:43:44 +00:00
|
|
|
|
if ( !mouse_emulation_state ) {
|
|
|
|
|
// nothing was pressed, fake a LMB click
|
|
|
|
|
mouse_emulation_window = getMouseEmulationWindow();
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuPress, Button1, mouse_emulation_state );
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
|
|
|
|
|
} else { // release all
|
|
|
|
|
if ( mouse_emulation_state & Button1Mask )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button1, mouse_emulation_state );
|
|
|
|
|
if ( mouse_emulation_state & Button2Mask )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button2, mouse_emulation_state );
|
|
|
|
|
if ( mouse_emulation_state & Button3Mask )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuRelease, Button3, mouse_emulation_state );
|
1999-12-06 00:43:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// fall through
|
|
|
|
|
case XK_Escape:
|
|
|
|
|
XUngrabKeyboard(qt_xdisplay(), kwin_time);
|
|
|
|
|
mouse_emulation = FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
1999-12-07 21:54:52 +00:00
|
|
|
|
|
1999-12-06 00:43:55 +00:00
|
|
|
|
QCursor::setPos( pos );
|
2000-06-21 17:43:44 +00:00
|
|
|
|
if ( mouse_emulation_state )
|
|
|
|
|
mouse_emulation_state = sendFakedMouseEvent( pos, mouse_emulation_window, EmuMove, 0, mouse_emulation_state );
|
1999-12-06 00:43:55 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-24 01:36:47 +00:00
|
|
|
|
|
2000-03-24 22:23:02 +00:00
|
|
|
|
/*!
|
|
|
|
|
Puts a new decoration frame around every client. Used to react on
|
|
|
|
|
style changes.
|
|
|
|
|
*/
|
1999-12-24 01:36:47 +00:00
|
|
|
|
void Workspace::slotResetAllClients()
|
|
|
|
|
{
|
|
|
|
|
for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
Client *oldClient = (*it);
|
|
|
|
|
WId w = oldClient->window();
|
|
|
|
|
oldClient->hide();
|
|
|
|
|
oldClient->releaseWindow();
|
|
|
|
|
// Replace oldClient with newClient in all lists
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Client *newClient = clientFactory (w);
|
1999-12-24 01:36:47 +00:00
|
|
|
|
(*it) = newClient;
|
|
|
|
|
ClientList::Iterator jt = stacking_order.find (oldClient);
|
|
|
|
|
(*jt) = newClient;
|
|
|
|
|
jt = focus_chain.find (oldClient);
|
|
|
|
|
(*jt) = newClient;
|
|
|
|
|
delete oldClient;
|
2000-03-24 09:42:23 +00:00
|
|
|
|
newClient->manage( TRUE );
|
1999-12-24 01:36:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-03-24 22:23:02 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Stores the current session in the config file
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
\sa loadSessionInfo()
|
2000-03-24 22:23:02 +00:00
|
|
|
|
*/
|
|
|
|
|
void Workspace::storeSession( KConfig* config )
|
|
|
|
|
{
|
|
|
|
|
config->setGroup("Session" );
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
Client* c = (*it);
|
|
|
|
|
QCString sessionId = c->sessionId();
|
|
|
|
|
QCString windowRole = c->windowRole();
|
|
|
|
|
if ( !sessionId.isEmpty() ) {
|
|
|
|
|
count++;
|
|
|
|
|
QString n = QString::number(count);
|
|
|
|
|
config->writeEntry( QString("sessionId")+n, c->sessionId().data() );
|
|
|
|
|
config->writeEntry( QString("windowRole")+n, c->windowRole().data() );
|
|
|
|
|
config->writeEntry( QString("x")+n, c->x() );
|
|
|
|
|
config->writeEntry( QString("y")+n, c->y() );
|
|
|
|
|
config->writeEntry( QString("width")+n, c->windowWrapper()->width() );
|
|
|
|
|
config->writeEntry( QString("height")+n, c->windowWrapper()->height() );
|
|
|
|
|
config->writeEntry( QString("desktop")+n, c->desktop() );
|
|
|
|
|
config->writeEntry( QString("iconified")+n, c->isIconified()?"true":"false" );
|
|
|
|
|
config->writeEntry( QString("sticky")+n, c->isSticky()?"true":"false" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
config->writeEntry( "count", count );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
/*!
|
|
|
|
|
Loads the session information from the config file.
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
\sa storeSession()
|
|
|
|
|
*/
|
2000-03-24 22:23:02 +00:00
|
|
|
|
void Workspace::loadSessionInfo()
|
|
|
|
|
{
|
|
|
|
|
session.clear();
|
|
|
|
|
KConfig* config = kapp->sessionConfig();
|
|
|
|
|
config->setGroup("Session" );
|
|
|
|
|
int count = config->readNumEntry( "count" );
|
|
|
|
|
for ( int i = 1; i <= count; i++ ) {
|
|
|
|
|
QString n = QString::number(i);
|
|
|
|
|
SessionInfo* info = new SessionInfo;
|
|
|
|
|
session.append( info );
|
|
|
|
|
info->sessionId = config->readEntry( QString("sessionId")+n ).latin1();
|
|
|
|
|
info->windowRole = config->readEntry( QString("windowRole")+n ).latin1();
|
|
|
|
|
info->x = config->readNumEntry( QString("x")+n );
|
|
|
|
|
info->y = config->readNumEntry( QString("y")+n );
|
|
|
|
|
info->width = config->readNumEntry( QString("width")+n );
|
|
|
|
|
info->height = config->readNumEntry( QString("height")+n );
|
|
|
|
|
info->desktop = config->readNumEntry( QString("desktop")+n );
|
|
|
|
|
info->iconified = config->readBoolEntry( QString("iconified")+n );
|
|
|
|
|
info->sticky = config->readBoolEntry( QString("sticky")+n );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 14:12:13 +00:00
|
|
|
|
Returns the SessionInfo for client \a c. The returned session
|
|
|
|
|
info is removed from the storage. It's up to the caller to delete it.
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
May return 0 if there's no session info for the client.
|
|
|
|
|
*/
|
2000-03-24 22:23:02 +00:00
|
|
|
|
SessionInfo* Workspace::takeSessionInfo( Client* c )
|
|
|
|
|
{
|
|
|
|
|
if ( session.isEmpty() )
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
QCString sessionId = c->sessionId();
|
|
|
|
|
QCString windowRole = c->windowRole();
|
|
|
|
|
|
|
|
|
|
for (SessionInfo* info = session.first(); info; info = session.next() ) {
|
2000-04-06 18:29:04 +00:00
|
|
|
|
if ( info->sessionId == sessionId &&
|
2000-03-24 22:23:02 +00:00
|
|
|
|
( ( info->windowRole.isEmpty() && windowRole.isEmpty() )
|
|
|
|
|
|| (info->windowRole == windowRole ) ) )
|
|
|
|
|
return session.take();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Updates the current client area according to the current clients.
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
If the area changes, the new area is propagate to the world.
|
2000-06-22 18:08:35 +00:00
|
|
|
|
|
|
|
|
|
The client area is the area that is available for clients (that
|
|
|
|
|
which is not taken by windows like panels, the top-of-screen menu
|
|
|
|
|
etc).
|
2000-06-23 16:26:44 +00:00
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
\sa clientArea()
|
|
|
|
|
*/
|
2000-05-26 13:54:50 +00:00
|
|
|
|
void Workspace::updateClientArea()
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
QRect all = QApplication::desktop()->geometry();
|
|
|
|
|
QRect a = all;
|
|
|
|
|
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
|
|
|
|
|
a = a.intersect( (*it)->adjustedClientArea( all ) );
|
2000-05-26 13:54:50 +00:00
|
|
|
|
}
|
2000-06-21 17:43:44 +00:00
|
|
|
|
|
2000-06-08 17:05:51 +00:00
|
|
|
|
if ( area != a ) {
|
|
|
|
|
area = a;
|
|
|
|
|
NETRect r;
|
|
|
|
|
r.pos.x = area.x();
|
|
|
|
|
r.pos.y = area.y();
|
|
|
|
|
r.size.width = area.width();
|
|
|
|
|
r.size.height = area.height();
|
|
|
|
|
for( int i = 0; i < numberOfDesktops(); i++) {
|
|
|
|
|
rootInfo->setWorkArea( i, r );
|
|
|
|
|
}
|
Preliminary support for avoiding covering clients such as kicker
which want to be permanently visible.
I've used an XAtom called '_NET_AVOID_SPEC'. This of course can change
if need be. I think it's correct according to the wm spec, but the
wm spec seems to be empty on gnome.org, so who knows.
Windows can choose to be avoided by setting an XTextProperty
with one value, which can be either 'N', 'S', 'E', or 'W', according
to which screen edge they are anchored to.
kwin then sets its 'clientArea' rect appropriately, so that (in
theory at least) clients will not enter this area in some circumstances,
such as when being mapped for the first time.
You can see that this actually works if you start lots of konsoles. They
don't appear over the panel. I don't know what happens if you move the
panel, but I presume things will be screwed up, because I haven't
looked at that yet.
If you maximise a window, it'll still fill the screen, because the
implementation of maximise in kwin/client.cpp doesn't take account
of the workspace's clientArea rect. This is easy to fix, but I've
been awake for too long, so I'll do it after 42 winks.
svn path=/trunk/kdebase/kwin/; revision=46772
2000-04-16 09:06:03 +00:00
|
|
|
|
}
|
2000-05-04 23:12:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-22 14:12:13 +00:00
|
|
|
|
|
2000-06-23 16:26:44 +00:00
|
|
|
|
/*!
|
2000-06-22 18:08:35 +00:00
|
|
|
|
returns the area available for clients. This is the desktop
|
|
|
|
|
geometry minus windows on the dock. Placement algorithms should
|
2000-06-23 16:26:44 +00:00
|
|
|
|
refer to this rather than geometry().
|
|
|
|
|
|
2000-06-22 18:08:35 +00:00
|
|
|
|
\sa geometry()
|
2000-06-22 14:12:13 +00:00
|
|
|
|
*/
|
2000-05-06 18:59:43 +00:00
|
|
|
|
QRect Workspace::clientArea()
|
|
|
|
|
{
|
2000-06-08 17:05:51 +00:00
|
|
|
|
return area;
|
2000-05-06 18:59:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-28 13:20:42 +00:00
|
|
|
|
|
2000-06-09 00:20:21 +00:00
|
|
|
|
#include "workspace.moc"
|