Use the new windowmanager interaction API

svn path=/trunk/kdebase/kwin/; revision=52623
This commit is contained in:
Matthias Ettrich 2000-06-08 17:05:51 +00:00
parent 9b9570699b
commit 900e2e6c0b
10 changed files with 332 additions and 411 deletions

View file

@ -8,10 +8,10 @@ class KWinInterface : virtual public DCOPObject
K_DCOP
k_dcop:
virtual ASYNC cascadeDesktop() = 0;
virtual ASYNC unclutterDesktop() = 0;
virtual void updateClientArea() = 0;
virtual QRect clientArea() = 0;
virtual QRect edgeClientArea() = 0;
};
#endif

View file

@ -6,7 +6,7 @@ SUBDIRS = . pics clients
bin_PROGRAMS = kwin
lib_LTLIBRARIES = kwin.la
kwin_la_SOURCES = atoms.cpp client.cpp main.cpp stdclient.cpp workspace.cpp tabbox.cpp options.cpp plugins.cpp events.cpp KWinInterface.skel
kwin_la_SOURCES = atoms.cpp client.cpp main.cpp stdclient.cpp workspace.cpp tabbox.cpp options.cpp plugins.cpp events.cpp killwindow.cpp KWinInterface.skel
kwin_la_LIBADD = $(LIB_KDEUI)
kwin_la_LDFLAGS = $(all_libraries) -module -avoid-version

View file

@ -15,6 +15,9 @@ Atoms::Atoms()
Atom atoms_return[max];
int n = 0;
atoms[n] = &kwin_running;
names[n++] = (char *) "KWIN_RUNNING";
atoms[n] = &wm_protocols;
names[n++] = (char *) "WM_PROTOCOLS";
@ -27,49 +30,12 @@ Atoms::Atoms()
atoms[n] = &wm_change_state;
names[n++] = (char *) "WM_CHANGE_STATE";
// compatibility
atoms[n] = &kwm_win_icon;
names[n++] = (char *) "KWM_WIN_ICON";
// compatibility
atoms[n] = &kwm_running;
names[n++] = (char *) "KWM_RUNNING";
atoms[n] = &kwm_command;
names[n++] = (char *) "KWM_COMMAND";
atoms[n] = &motif_wm_hints;
names[n++] = (char *) "_MOTIF_WM_HINTS";
atoms[n] = &net_number_of_desktops;
names[n++] = (char *) "_NET_NUMBER_OF_DESKTOPS";
atoms[n] = &net_current_desktop;
names[n++] = (char *) "_NET_CURRENT_DESKTOP";
atoms[n] = &net_active_window;
names[n++] = (char *) "_NET_ACTIVE_WINDOW";
atoms[n] = &net_wm_context_help;
names[n++] = (char *) "_NET_WM_CONTEXT_HELP";
atoms[n] = &net_client_list;
names[n++] = (char *) "_NET_CLIENT_LIST";
atoms[n] = &net_client_list_stacking;
names[n++] = (char *) "_NET_CLIENT_LIST_STACKING";
atoms[n] = &net_kde_docking_windows;
names[n++] = (char *) "_NET_KDE_DOCKING_WINDOWS";
atoms[n] = &net_avoid_spec;
names[n++] = (char *) "_NET_AVOID_SPEC";
// FIXME: standardize? KWIN_ prefix is deliberate so this isn't missed
// set by kdelibs/kio/kmapnotify.c
atoms[n] = &kwin_initial_desktop;
names[n++] = (char *) "KWIN_INITIAL_DESKTOP"; // _NET_INITIAL_DESKTOP?
XInternAtoms( qt_xdisplay(), names, n, FALSE, atoms_return );
for (int i = 0; i < n; i++ )
*atoms[i] = atoms_return[i];

16
atoms.h
View file

@ -11,28 +11,16 @@ class Atoms {
public:
Atoms();
Atom kwin_running;
Atom wm_protocols;
Atom wm_delete_window;
Atom wm_take_focus;
Atom wm_change_state;
Atom kwm_win_icon; // compatibility
Atom kwm_command; // compatibility
Atom kwm_running;
Atom motif_wm_hints;
Atom net_number_of_desktops;
Atom net_current_desktop;
Atom net_active_window;
Atom net_client_list;
Atom net_client_list_stacking;
Atom net_wm_context_help;
Atom net_kde_docking_windows;
Atom net_avoid_spec;
Atom kwin_initial_desktop;
};

View file

@ -3,6 +3,7 @@ kwin - the KDE window manager
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
******************************************************************/
#define QT_CLEAN_NAMESPACE
#include <klocale.h>
#include <kapp.h>
#include <kdebug.h>
@ -16,6 +17,8 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include <qpainter.h>
#include <qwhatsthis.h>
#include <qtimer.h>
#include <kwin.h>
#include <netwm.h>
#include "workspace.h"
#include "client.h"
#include "events.h"
@ -35,6 +38,20 @@ static bool resizeVerticalDirectionFixed = FALSE;
static QRect* visible_bound = 0;
// NET WM Protocol handler class
class WinInfo : public NETWinInfo {
public:
WinInfo(Display * display, Window window,
Window rwin, unsigned long pr )
: NETWinInfo( display, window, rwin, pr, NET::WindowManager ) {
}
void changeDesktop(CARD32 /* desktop */) { }
void changeState(CARD32 /* state */, CARD32 /* mask */) { }
};
void Client::drawbound( const QRect& geom )
{
if ( visible_bound )
@ -326,11 +343,19 @@ bool WindowWrapper::x11Event( XEvent * e)
Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags f )
: QWidget( parent, name, f | WStyle_Customize | WStyle_NoBorder )
{
avoid = false;
anchor = AnchorNorth;
wspace = ws;
win = w;
unsigned long properties =
NET::WMDesktop |
NET::WMState |
NET::WMWindowType |
NET::WMStrut |
NET::WMName
;
info = new WinInfo( qt_xdisplay(), win, qt_xrootwin(), properties );
XWindowAttributes attr;
if (XGetWindowAttributes(qt_xdisplay(), win, &attr)){
original_geometry.setRect(attr.x, attr.y, attr.width, attr.height );
@ -367,33 +392,19 @@ Client::Client( Workspace *ws, WId w, QWidget *parent, const char *name, WFlags
if ( mainClient()->isSticky() )
setSticky( TRUE );
updateAvoidPolicy();
// should we open this window on a certain desktop?
Atom type;
int format;
unsigned long nitems, bytes;
long *data = 0L;
int status=XGetWindowProperty(qt_xdisplay(), w, atoms->kwin_initial_desktop, 0, 1L,
False, atoms->kwin_initial_desktop, &type, &format, &nitems, &bytes,
(unsigned char **)&data);
if ( info->desktop() )
desk= info->desktop(); // window had the initial desktop property!
if (status==Success) {
if (nitems>0)
desk=data[0]; // window had the initial desktop property!
XFree((char *)data);
}
// if this window is transient, ensure that it is opened on the
// same window as its parent. this is necessary when an application
// starts up on a different desktop than is currently displayed
//
// are there any other cases we need to check?
//
if (transient_for != None)
desk=KWM::desktop(transient_for);
if ( isTransient() )
desk = mainClient()->desktop();
}
@ -405,6 +416,8 @@ Client::~Client()
releaseWindow();
if (workspace()->activeClient() == this)
workspace()->setEnableFocusChange(true); // Safety
delete info;
}
@ -420,12 +433,12 @@ void Client::manage( bool isMapped )
QRect geom( original_geometry );
bool placementDone = FALSE;
SessionInfo* info = workspace()->takeSessionInfo( this );
if ( info )
geom.setRect( info->x, info->y, info->width, info->height );
SessionInfo* session = workspace()->takeSessionInfo( this );
if ( session )
geom.setRect( session->x, session->y, session->width, session->height );
if ( isMapped || info )
if ( isMapped || session )
placementDone = TRUE;
else {
if ( (xSizeHint.flags & PPosition) || (xSizeHint.flags & USPosition) ) {
@ -465,8 +478,8 @@ void Client::manage( bool isMapped )
// initial state
int state = NormalState;
if ( info ) {
if ( info->iconified )
if ( session ) {
if ( session->iconified )
state = IconicState;
} else {
// find out the initial state. Several possibilities exist
@ -480,19 +493,15 @@ void Client::manage( bool isMapped )
// initial desktop placement - note we don't clobber desk if it is
// set to some value, in case the initial desktop code in the
// constructor has already set a value for us
if ( info ) {
desk = info->desktop;
} else if (desk<=0) {
if ( session ) {
desk = session->desktop;
} else if ( desk <= 0 ) {
// assume window wants to be visible on the current desktop
desk = workspace()->currentDesktop();
// KDE 1.x compatibility
desk = KWM::desktop( win );
}
info->setDesktop( desk );
// initial desktop code needs this now
KWM::moveToDesktop( win, desk ); // KDE 1.x compatibility
setMappingState( state );
if ( state == NormalState && isOnDesktop( workspace()->currentDesktop() ) ) {
@ -503,11 +512,11 @@ void Client::manage( bool isMapped )
}
// other settings from the previous session
if ( info ) {
setSticky( info->sticky );
if ( session ) {
setSticky( session->sticky );
}
delete info;
delete session;
workspace()->updateClientArea();
}
@ -530,7 +539,14 @@ void Client::getWmNormalHints()
*/
void Client::fetchName()
{
QString s = KWM::title( win );
//#### QString s = KWM::title( win );
QString s;
char* c = 0;
if ( XFetchName( qt_xdisplay(), win, &c ) != 0 ) {
s = QString::fromLocal8Bit( c );
XFree( c );
}
if ( s != caption() ) {
setCaption( "" );
@ -544,6 +560,8 @@ void Client::fetchName()
s = s2;
}
setCaption( s );
info->setVisibleName( s.utf8() );
if ( !isWithdrawn() )
captionChange( caption() );
@ -572,6 +590,11 @@ void Client::setMappingState(int s){
*/
bool Client::windowEvent( XEvent * e)
{
unsigned int dirty = info->event( e ); // pass through the NET stuff
dirty = 0; // shut up, compiler
switch (e->type) {
case UnmapNotify:
if ( e->xunmap.window == winId() ) {
@ -636,8 +659,8 @@ bool Client::mapRequest( XMapRequestEvent& /* e */ )
break;
case NormalState:
// only show window if we're on current desktop
if (desk == KWM::currentDesktop())
show(); // for safety
if ( isOnDesktop( workspace()->currentDesktop() ) )
show(); // for safety
break;
}
@ -686,7 +709,7 @@ void Client::withdraw()
{
Events::raise( isTransient() ? Events::TransDelete : Events::Delete );
setMappingState( WithdrawnState );
KWM::moveToDesktop( win, -1 ); // compatibility
//### KWM::moveToDesktop( win, -1 ); // compatibility
releaseWindow();
workspace()->destroyClient( this );
}
@ -791,9 +814,6 @@ bool Client::propertyNotify( XPropertyEvent& e )
default:
if ( e.atom == atoms->wm_protocols )
getWindowProtocols();
else if ( e.atom == atoms->kwm_win_icon ) {
getWMHints(); // for the icons
}
break;
}
@ -810,9 +830,6 @@ bool Client::clientMessage( XClientMessageEvent& e )
if ( e.data.l[0] == IconicState && isNormal() )
iconify();
return TRUE;
} else if ( e.message_type == atoms->net_active_window ) {
workspace()->activateClient( this );
return TRUE;
}
return FALSE;
@ -836,6 +853,16 @@ void Client::sendSynteticConfigureNotify()
c.height = windowWrapper()->height();
c.border_width = 0;
XSendEvent( qt_xdisplay(), c.event, TRUE, NoEventMask, (XEvent*)&c );
// inform clients about the frame geometry
NETStrut strut;
QRect wr = windowWrapper()->geometry();
QRect mr = rect();
strut.left = wr.left();
strut.right = mr.right() - wr.right();
strut.top = wr.top();
strut.bottom = mr.bottom() - wr.bottom();
info->setKDEFrameStrut( strut );
}
@ -1066,7 +1093,7 @@ void Client::mouseMoveEvent( QMouseEvent * e)
geom.moveTopLeft( pp );
break;
default:
//fprintf(stderr, "KWin::mouseMoveEvent with mode = %d\n", mode);
//fprintf(stderr, "KWin::mouseMoveEvent with mode = %d\n", mode);
break;
}
@ -1654,6 +1681,8 @@ void Client::setSticky( bool b )
Events::raise( Events::UnSticky );
if ( !is_sticky )
setDesktop( workspace()->currentDesktop() );
else
info->setDesktop( NETWinInfo::OnAllDesktops );
workspace()->setStickyTransientsOf( this, b );
stickyChange( is_sticky );
}
@ -1661,16 +1690,15 @@ void Client::setSticky( bool b )
void Client::setDesktop( int desktop)
{
if ( isOnDesktop( desktop ) )
return;
desk = desktop;
KWM::moveToDesktop( win, desk );//##### compatibility
info->setDesktop( desktop );
}
void Client::getWMHints()
{
icon_pix = KWM::icon( win, 32, 32 ); // TODO sizes from workspace
miniicon_pix = KWM::miniIcon( win, 16, 16 );
// get the icons, allow scaling
icon_pix = KWin::icon( win, 32, 32, TRUE );
miniicon_pix = KWin::icon( win, 16, 16, TRUE );
if ( !isWithdrawn() )
iconChange();
@ -2016,58 +2044,22 @@ void Client::activateLayout()
layout()->activate();
}
void Client::updateAvoidPolicy()
QRect Client::adjustedClientArea( const QRect& area ) const
{
avoid = false;
// Find out if we should be avoided.
XTextProperty avoidProp;
if ( XGetTextProperty(
qt_xdisplay(),
win,
&avoidProp,
atoms->net_avoid_spec
) == 0 )
return;
char ** avoidList;
int avoidListCount;
if ( XTextPropertyToStringList(
&avoidProp, &avoidList, &avoidListCount) == 0 ) {
kdDebug() << "kwin: Client::updateAvoidPolicy: " << endl;
return;
}
// Must be one value only in string list.
if (avoidListCount != 1) {
kdDebug() << "kwin: Client::updateAvoidPolicy(): " << endl;
return;
}
// Which border is the client anchored to ?
avoid = true;
switch (avoidList[0][0]) {
case 'N':
anchor = AnchorNorth;
break;
case 'S':
anchor = AnchorSouth;
break;
case 'E':
anchor = AnchorEast;
break;
case 'W':
anchor = AnchorWest;
break;
default:
avoid = false;
break;
}
XFreeStringList(avoidList);
QRect r = area;
NETStrut strut = info->strut();
if ( strut.left > 0 )
r.setLeft( r.left() + (int) strut.left );
if ( strut.top > 0 )
r.setTop( r.top() + (int) strut.top );
if ( strut.right > 0 )
r.setRight( r.right() - (int) strut.right );
if ( strut.bottom > 0 )
r.setBottom( r.bottom() - (int) strut.bottom );
return r;
}
NoBorderClient::NoBorderClient( Workspace *ws, WId w, QWidget *parent, const char *name )
: Client( ws, w, parent, name )
{
@ -2079,3 +2071,4 @@ NoBorderClient::~NoBorderClient()
{
}

View file

@ -7,7 +7,6 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#define CLIENT_H
#include "options.h"
#include <kwm.h>
#include <qframe.h>
#include <qvbox.h>
#include <qpixmap.h>
@ -18,6 +17,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
class Workspace;
class Client;
class WinInfo;
class WindowWrapper : public QWidget
{
@ -70,10 +70,6 @@ public:
bool isTransient() const;
Client* mainClient();
void updateAvoidPolicy();
bool isAvoid() const { return avoid; }
int anchorEdge() const { return anchor; }
virtual bool windowEvent( XEvent * );
void manage( bool isMapped = FALSE );
@ -159,6 +155,8 @@ public:
QCString windowRole();
QCString sessionId();
QRect adjustedClientArea( const QRect& area ) const;
public slots:
void iconify();
@ -257,9 +255,8 @@ private:
QPixmap miniicon_pix;
QRect geom_restore;
QRegion mask;
WinInfo* info;
bool avoid;
int anchor;
};
inline WId Client::window() const

View file

@ -7,6 +7,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
// X11/Qt conflict
#undef Bool
#define QT_CLEAN_NAMESPACE
#include <kconfig.h>
#include "main.h"
#include "options.h"
@ -22,11 +23,11 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#define INT8 _X11INT8
#define INT32 _X11INT32
// #define INT8 _X11INT8
// #define INT32 _X11INT32
#include <X11/Xproto.h>
#undef INT8
#undef INT32
// #undef INT8
// #undef INT32
#include <kcmdlineargs.h>
#include <kaboutdata.h>

View file

@ -1,8 +1,9 @@
/*****************************************************************
kwin - the KDE window manager
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
******************************************************************/
#define QT_CLEAN_NAMESPACE
#include "tabbox.h"
#include "workspace.h"
#include "client.h"
@ -103,7 +104,7 @@ void TabBox::nextPrev( bool next)
else
client = workspace()->previousClient(client);
if (!firstClient) {
// When we see our first client for the second time,
// When we see our first client for the second time,
// it's time to stop.
firstClient = client;
}
@ -210,7 +211,7 @@ void TabBox::paintContents()
if ( currentClient() ) {
QString s;
if (!client->isOnDesktop(workspace()->currentDesktop())){
s = KWM::desktopName(client->desktop());
//### s = KWM::desktopName(client->desktop());
s.append(": ");
}

View file

@ -3,6 +3,7 @@ kwin - the KDE window manager
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
******************************************************************/
#define QT_CLEAN_NAMESPACE
#include <kconfig.h>
#include <kglobal.h>
#include <kglobalsettings.h>
@ -15,6 +16,8 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include <dcopclient.h>
#include <kdebug.h>
#include <netwm.h>
#include "workspace.h"
#include "client.h"
#include "stdclient.h"
@ -22,6 +25,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include "atoms.h"
#include "plugins.h"
#include "events.h"
#include "killwindow.h"
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
@ -38,6 +42,41 @@ const int XIconicState = IconicState;
#include <kwin.h>
#include <kapp.h>
// 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() {}
void changeNumberOfDesktops(CARD32 n) { workspace->setNumberOfDesktops( n ); }
void changeCurrentDesktop(CARD32 d) { workspace->setCurrentDesktop( d ); }
void changeActiveWindow(Window w) {
::Client* c = workspace->findClient( (WId) w );
if ( c )
workspace->activateClient( c );
}
void closeWindow(Window w) {
::Client* c = workspace->findClient( (WId) w );
if ( c ) {
c->closeWindow();
}
}
void moveResize(Window, int, int, unsigned long) { }
private:
Workspace* workspace;
};
extern Time kwin_time;
// used to store the return values of
@ -48,15 +87,15 @@ static int kwin_shape_event = 0;
static bool block_focus = FALSE;
// does the window w need a shape combine mask around it?
bool Shape::hasShape( WId w){
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;
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;
}
int Shape::shapeEvent()
@ -106,7 +145,7 @@ static void updateTime()
if ( !w )
w = new QWidget;
long data = 1;
XChangeProperty(qt_xdisplay(), w->winId(), atoms->kwm_running, atoms->kwm_running, 32,
XChangeProperty(qt_xdisplay(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
PropModeAppend, (unsigned char*) &data, 1);
XEvent ev;
XWindowEvent( qt_xdisplay(), w->winId(), PropertyChangeMask, &ev );
@ -118,36 +157,43 @@ Client* Workspace::clientFactory( Workspace *ws, WId w )
if ( Motif::noBorder( w ) )
return new NoBorderClient( ws, w );
NETWinInfo ni( qt_xdisplay(), w, root, NET::WMWindowType );
// hack TODO hints
QString s = KWM::title( w );
if ( s == "THE DESKTOP" ) {
switch ( ni.windowType() ) {
case NET::Desktop: {
XLowerWindow( qt_xdisplay(), w );
Client * c = new NoBorderClient( ws, w);
c->setSticky( TRUE );
c->setMayMove( FALSE );
ws->setDesktopClient( c );
c->setPassiveFocus( TRUE );
c->setPassiveFocus( TRUE );
return c;
}
if ( s.lower().right(6) == "kicker" ) {
case NET::Dock: {
Client * c = new NoBorderClient( ws, w);
c->setSticky( TRUE );
c->setMayMove( FALSE );
c->setPassiveFocus( TRUE );
c->setPassiveFocus( TRUE );
return c;
}
if ( s == "MAC MENU [menu]" ) {
case NET::Menu: {
Client * c = new NoBorderClient( ws, w);
c->setSticky( TRUE );
c->setMayMove( FALSE );
c->setPassiveFocus( TRUE );
c->setPassiveFocus( TRUE );
return c;
}
if ( ( s.right(6) == "[menu]" ) || ( s.right(7) == "[tools]" ) ) {
case NET::Toolbar: {
Client * c = new NoBorderClient( ws, w);
return c;
}
default:
break;
}
if ( Shape::hasShape( w ) ){
return new NoBorderClient( ws, w );
@ -179,8 +225,7 @@ Workspace::Workspace( bool restore )
root = qt_xrootwin();
session.setAutoDelete( TRUE );
clientArea_ = QApplication::desktop()->geometry();
edgeClientArea_ = QApplication::desktop()->geometry();
area = QApplication::desktop()->geometry();
if ( restore )
loadSessionInfo();
@ -213,8 +258,8 @@ Workspace::Workspace( bool restore )
XChangeProperty(
qt_xdisplay(),
qt_xrootwin(),
atoms->kwm_running,
atoms->kwm_running,
atoms->kwin_running,
atoms->kwin_running,
32,
PropModeAppend,
(unsigned char*) &data,
@ -234,6 +279,32 @@ Workspace::Workspace( bool restore )
void Workspace::init()
{
supportWindow = new QWidget;
unsigned long protocols =
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 |
NET::WMKDEDockWinFor
;
rootInfo = new RootInfo( this, qt_xdisplay(), supportWindow->winId(), "KWin", protocols, qt_xscreen() );
KConfig* config = KGlobal::config();
config->setGroup("Desktops");
if (!config->hasKey("NumberOfDesktops"))
@ -308,8 +379,11 @@ Workspace::~Workspace()
delete popup;
delete keys;
if ( root == qt_xrootwin() )
XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwm_running);
XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwin_running);
KGlobal::config()->sync();
delete rootInfo;
delete supportWindow;
}
@ -342,8 +416,8 @@ bool Workspace::workspaceEvent( XEvent * e )
return c->windowEvent( e );
// check for dock windows
if ( removeDockwin( e->xunmap.window ) )
return TRUE;
if ( removeDockwin( e->xunmap.window ) )
return TRUE;
if ( e->xunmap.event == root ) {
// keep track of map/unmap for own own windows to avoid
@ -365,8 +439,9 @@ bool Workspace::workspaceEvent( XEvent * e )
}
case ReparentNotify:
c = findClient( e->xreparent.window );
if ( c )
if ( c )
(void) c->windowEvent( e );
//do not confuse Qt with these events. After all, _we_ are the
//window manager who does the reparenting.
return TRUE;
@ -459,8 +534,9 @@ bool Workspace::workspaceEvent( XEvent * e )
break;
case FocusOut:
break;
case PropertyNotify:
case ClientMessage:
return clientMessage(e->xclient);
return netCheck( e );
break;
default:
if ( e->type == Shape::shapeEvent() ) {
@ -847,11 +923,8 @@ void Workspace::setActiveClient( Client* c )
if ( c->wantsTabFocus() )
focus_chain.append( c );
}
WId w = active_client? active_client->window() : 0;
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_active_window, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)&w, 1);
rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
}
@ -1340,7 +1413,7 @@ void Workspace::cascadePlacement (Client* c, bool re_init) {
cci[d].pos = QPoint( xp + delta_x, yp + delta_y );
}
void Workspace::deskCleanup(CleanupType ct)
void Workspace::cascadeDesktop()
{
ClientList::Iterator it(clients.fromLast());
for (; it != clients.end(); --it) {
@ -1349,14 +1422,25 @@ void Workspace::deskCleanup(CleanupType ct)
((*it)->isSticky()) ||
(!(*it)->mayMove()) )
continue;
if (ct == Cascade)
cascadePlacement(*it);
else if (ct == Unclutter)
smartPlacement(*it);
cascadePlacement(*it);
}
}
void Workspace::unclutterDesktop()
{
ClientList::Iterator it(clients.fromLast());
for (; it != clients.end(); --it) {
if((!(*it)->isOnDesktop(currentDesktop())) ||
((*it)->isIconified()) ||
((*it)->isSticky()) ||
(!(*it)->mayMove()) )
continue;
smartPlacement(*it);
}
}
/*!
Lowers the client \a c taking layers, transient windows and window
groups into account.
@ -1545,63 +1629,59 @@ void Workspace::setCurrentDesktop( int new_desktop ){
block_focus = TRUE;
if (new_desktop != current_desktop) {
/*
/*
optimized Desktop switching: unmapping done from back to front
mapping done from front to back => less exposure events
*/
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
if ( (*it)->isVisible() && !(*it)->isOnDesktop( new_desktop ) ) {
(*it)->hide();
}
}
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
if ( (*it)->isOnDesktop( new_desktop ) && !(*it)->isIconified() ) {
(*it)->show();
}
}
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
if ( (*it)->isVisible() && !(*it)->isOnDesktop( new_desktop ) ) {
(*it)->hide();
}
}
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
if ( (*it)->isOnDesktop( new_desktop ) && !(*it)->isIconified() ) {
(*it)->show();
}
}
}
current_desktop = new_desktop;
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_current_desktop, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&current_desktop, 1);
rootInfo->setCurrentDesktop( current_desktop );
// restore the focus on this desktop
block_focus = FALSE;
Client* c = 0;
if ( options->focusPolicyIsReasonable()) {
if (options->focusPolicy == Options::FocusFollowsMouse) {
// Search in focus chain
for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it) {
if ( (*it)->isVisible() && !(*it)->passiveFocus() ) {
c = *it;
break;
}
}
}
if (options->focusPolicy == Options::FocusFollowsMouse) {
// Search in focus chain
for( ClientList::ConstIterator it = focus_chain.fromLast(); it != focus_chain.end(); --it) {
if ( (*it)->isVisible() && !(*it)->passiveFocus() ) {
c = *it;
break;
}
}
}
if (!c) {
// Search top-most visible window
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
if ( (*it)->isVisible() && !(*it)->passiveFocus() ) {
c = *it;
break;
}
}
}
if (!c) {
// Search top-most visible window
for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
if ( (*it)->isVisible() && !(*it)->passiveFocus() ) {
c = *it;
break;
}
}
}
}
if ( c )
requestFocus( c );
requestFocus( c );
else
focusToNull();
focusToNull();
QApplication::syncX();
KWM::switchToDesktop( current_desktop ); // ### compatibility
}
@ -1619,36 +1699,18 @@ void Workspace::setNumberOfDesktops( int n )
if ( n == number_of_desktops )
return;
number_of_desktops = n;
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_number_of_desktops, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&number_of_desktops, 1);
rootInfo->setNumberOfDesktops( number_of_desktops );
}
/*!
Handles client messages sent to the workspace
*/
bool Workspace::clientMessage( XClientMessageEvent msg )
bool Workspace::netCheck( XEvent* e )
{
if ( msg.message_type == atoms->net_current_desktop ) {
setCurrentDesktop( msg.data.l[0] );
return TRUE;
}
if (msg.message_type == atoms->kwm_command) {
char c[21];
int i;
for (i=0;i<20;i++)
c[i] = msg.data.b[i];
c[i] = '\0';
QString com = c;
if (com == "deskUnclutter") {
deskCleanup(Unclutter);
} else if (com == "deskCascade") {
deskCleanup(Cascade);
}
return TRUE;
}
unsigned int dirty = rootInfo->event( e );
dirty = 0; // shut up, compiler
return FALSE;
}
@ -1665,9 +1727,7 @@ void Workspace::propagateClients( bool onlyStacking )
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it ) {
cl[i++] = (*it)->window();
}
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_client_list, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)cl, clients.count());
rootInfo->setClientList( (Window*) cl, i );
delete [] cl;
}
@ -1676,9 +1736,7 @@ void Workspace::propagateClients( bool onlyStacking )
for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) {
cl[i++] = (*it)->window();
}
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_client_list_stacking, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)cl, stacking_order.count());
rootInfo->setClientListStacking( (Window*) cl, i );
delete [] cl;
}
@ -1690,13 +1748,18 @@ void Workspace::propagateClients( bool onlyStacking )
*/
bool Workspace::addDockwin( WId w )
{
WId dockFor = 0;
if ( !KWin::isDockWindow( w, &dockFor ) )
return FALSE;
if ( dockwins.contains( w ) )
return TRUE;
NETWinInfo ni( qt_xdisplay(), w, root, NET::WMKDEDockWinFor );
WId dockFor = ni.kdeDockWinFor();
if ( !dockFor )
return FALSE;
dockwins.append( DockWindow( w, dockFor ) );
XSelectInput( qt_xdisplay(), w,
StructureNotifyMask
);
XAddToSaveSet( qt_xdisplay(), w );
propagateDockwins();
return TRUE;
}
@ -1739,9 +1802,8 @@ void Workspace::propagateDockwins()
for ( DockWindowList::ConstIterator it = dockwins.begin(); it != dockwins.end(); ++it ) {
cl[i++] = (*it).dockWin;
}
XChangeProperty(qt_xdisplay(), qt_xrootwin(),
atoms->net_kde_docking_windows, XA_WINDOW, 32,
PropModeReplace, (unsigned char *)cl, dockwins.count());
rootInfo->setKDEDockingWindows( (Window*) cl, i );
delete [] cl;
}
@ -1871,70 +1933,20 @@ void Workspace::slotLogout()
kapp->requestShutDown();
}
/*!
Kill Window feature, similar to xkill
*/
void Workspace::slotKillWindow()
{
static Cursor kill_cursor = 0;
if (!kill_cursor)
kill_cursor = XCreateFontCursor(qt_xdisplay(), XC_pirate);
if (XGrabPointer(qt_xdisplay(), qt_xrootwin(), False,
ButtonPressMask | ButtonReleaseMask |
PointerMotionMask |
EnterWindowMask | LeaveWindowMask,
GrabModeAsync, GrabModeAsync, None,
kill_cursor, CurrentTime) == GrabSuccess)
{
XGrabKeyboard(qt_xdisplay(), qt_xrootwin(), False,
GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent ev;
int return_pressed = 0;
int escape_pressed = 0;
int button_released = 0;
XGrabServer(qt_xdisplay());
while (!return_pressed && !escape_pressed && !button_released)
{
XMaskEvent(qt_xdisplay(), KeyPressMask | ButtonPressMask |
ButtonReleaseMask | PointerMotionMask, &ev);
if (ev.type == KeyPress)
{
int kc = XKeycodeToKeysym(qt_xdisplay(), ev.xkey.keycode, 0);
int mx = 0;
int my = 0;
return_pressed = (kc == XK_Return) || (kc == XK_space);
escape_pressed = (kc == XK_Escape);
if (kc == XK_Left) mx = -10;
if (kc == XK_Right) mx = 10;
if (kc == XK_Up) my = -10;
if (kc == XK_Down) my = 10;
if (ev.xkey.state & ControlMask)
{
mx /= 10;
my /= 10;
}
QCursor::setPos(QCursor::pos()+QPoint(mx, my));
}
if (ev.type == ButtonRelease)
{
button_released = (ev.xbutton.button == Button1);
killWindowAtPosition(ev.xbutton.x_root, ev.xbutton.y_root);
}
continue;
}
if (return_pressed)
killWindowAtPosition(QCursor::pos().x(), QCursor::pos().y());
XUngrabServer(qt_xdisplay());
XUngrabKeyboard(qt_xdisplay(), CurrentTime);
XUngrabPointer(qt_xdisplay(), CurrentTime);
}
KillWindow kill( this );
kill.start();
}
/*!
Kills the window at position \a x, \a y
*/
void Workspace::killWindowAtPosition(int x, int y)
{
ClientList::ConstIterator it(stacking_order.fromLast());
@ -2346,61 +2358,27 @@ SessionInfo* Workspace::takeSessionInfo( Client* c )
void Workspace::updateClientArea()
{
QRect area = QApplication::desktop()->geometry();
QRect edgeArea = QApplication::desktop()->geometry();
for (ClientList::ConstIterator it(clients.begin()); it != clients.end(); ++it) {
(*it)->updateAvoidPolicy();
if ((*it)->isAvoid() ) {
switch (AnchorEdge((*it)->anchorEdge())) {
case AnchorNorth:
area.setTop(QMAX(area.top(), (*it)->geometry().bottom()));
break;
case AnchorSouth:
area.setBottom(QMIN(area.bottom(), (*it)->geometry().top() - 1));
break;
case AnchorEast:
area.setRight(QMIN(area.right(), (*it)->geometry().left() - 1));
break;
case AnchorWest:
area.setLeft(QMAX(area.left(), (*it)->geometry().right()));
break;
default:
break;
}
}
// FIXME: Using the hackish method...
if (KWM::title((*it)->winId()) == "MAC MENU [menu]")
edgeArea.setTop((*it)->geometry().bottom());
QRect all = QApplication::desktop()->geometry();
QRect a = all;
for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it) {
a = a.intersect( (*it)->adjustedClientArea( all ) );
}
edgeClientArea_ = edgeArea;
if ( clientArea_ != area ) {
// something changed, remember it and notify kdesktop
clientArea_ = area;
QByteArray data;
QDataStream arg( data, IO_WriteOnly );
arg << clientArea_;
kapp->dcopClient()->send("kdesktop", "KDesktopIface", "clientAreaUpdated(QRect)", data);
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 );
}
}
}
QRect Workspace::clientArea()
{
return clientArea_;
}
QRect Workspace::edgeClientArea()
{
return edgeClientArea_;
return area;
}

View file

@ -12,21 +12,22 @@ Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
#include <qguardedptr.h>
#include <qvaluelist.h>
#include <qlist.h>
#include <X11/Xlib.h>
#include "options.h"
#include "plugins.h"
#include "KWinInterface.h"
#include <X11/Xlib.h>
class Client;
class TabBox;
class KConfig;
class KGlobalAccel;
class RootInfo;
typedef QValueList<Client*> ClientList;
enum AnchorEdge { AnchorNorth, AnchorSouth, AnchorEast, AnchorWest };
class DockWindow
{
public:
@ -180,12 +181,11 @@ public:
*/
virtual void updateClientArea();
/**
* @return the area available for edge-anchored windows. This
* is the desktop geometry adjusted for other edge-anchored
* windows that have priority.
*/
virtual QRect edgeClientArea();
// dcop interface
void cascadeDesktop();
void unclutterDesktop();
public slots:
void setCurrentDesktop( int new_desktop );
@ -228,7 +228,7 @@ protected:
bool keyPress( XKeyEvent key );
bool keyRelease( XKeyEvent key );
bool keyPressMouseEmulation( XKeyEvent key );
bool clientMessage( XClientMessageEvent msg );
bool netCheck( XEvent* e );
private:
void init();
@ -241,9 +241,6 @@ private:
void smartPlacement(Client* c);
void cascadePlacement(Client* c, bool re_init = false);
enum CleanupType { Cascade, Unclutter };
void deskCleanup(CleanupType);
void focusToNull();
Client* findClientWidthId( WId w ) const;
@ -299,12 +296,12 @@ private:
KGlobalAccel *keys;
WId root;
// -cascading
Atom kwm_command;
PluginMgr mgr;
RootInfo *rootInfo;
QWidget* supportWindow;
QRect clientArea_, edgeClientArea_;
QRect area;
};
inline WId Workspace::rootWin() const