From 900e2e6c0b86ac0ccebf5a31be8d2bc615e084c7 Mon Sep 17 00:00:00 2001 From: Matthias Ettrich Date: Thu, 8 Jun 2000 17:05:51 +0000 Subject: [PATCH] Use the new windowmanager interaction API svn path=/trunk/kdebase/kwin/; revision=52623 --- KWinInterface.h | 6 +- Makefile.am | 2 +- atoms.cpp | 40 +---- atoms.h | 16 +- client.cpp | 201 +++++++++++------------ client.h | 11 +- main.cpp | 9 +- tabbox.cpp | 7 +- workspace.cpp | 420 +++++++++++++++++++++++------------------------- workspace.h | 31 ++-- 10 files changed, 332 insertions(+), 411 deletions(-) diff --git a/KWinInterface.h b/KWinInterface.h index f98cffa5e2..1ab49d32f3 100644 --- a/KWinInterface.h +++ b/KWinInterface.h @@ -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 diff --git a/Makefile.am b/Makefile.am index 145951f47d..4bbff4f8f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/atoms.cpp b/atoms.cpp index 7978bc2210..565d979d3f 100644 --- a/atoms.cpp +++ b/atoms.cpp @@ -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]; diff --git a/atoms.h b/atoms.h index 4a4415c5cb..eb87dc0118 100644 --- a/atoms.h +++ b/atoms.h @@ -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; - }; diff --git a/client.cpp b/client.cpp index 2ec44d0379..1af7399d31 100644 --- a/client.cpp +++ b/client.cpp @@ -3,6 +3,7 @@ kwin - the KDE window manager Copyright (C) 1999, 2000 Matthias Ettrich ******************************************************************/ +#define QT_CLEAN_NAMESPACE #include #include #include @@ -16,6 +17,8 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include #include #include +#include +#include #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() { } + diff --git a/client.h b/client.h index bc1786acf6..65468167ae 100644 --- a/client.h +++ b/client.h @@ -7,7 +7,6 @@ Copyright (C) 1999, 2000 Matthias Ettrich #define CLIENT_H #include "options.h" -#include #include #include #include @@ -18,6 +17,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich 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 diff --git a/main.cpp b/main.cpp index 4063750e2b..d0f346d855 100644 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich // X11/Qt conflict #undef Bool +#define QT_CLEAN_NAMESPACE #include #include "main.h" #include "options.h" @@ -22,11 +23,11 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include #include #include -#define INT8 _X11INT8 -#define INT32 _X11INT32 +// #define INT8 _X11INT8 +// #define INT32 _X11INT32 #include -#undef INT8 -#undef INT32 +// #undef INT8 +// #undef INT32 #include #include diff --git a/tabbox.cpp b/tabbox.cpp index 407df3789e..02ddfd9119 100644 --- a/tabbox.cpp +++ b/tabbox.cpp @@ -1,8 +1,9 @@ /***************************************************************** kwin - the KDE window manager - + Copyright (C) 1999, 2000 Matthias Ettrich ******************************************************************/ +#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(": "); } diff --git a/workspace.cpp b/workspace.cpp index 8b3b3c8e9b..fc6ec9867a 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -3,6 +3,7 @@ kwin - the KDE window manager Copyright (C) 1999, 2000 Matthias Ettrich ******************************************************************/ +#define QT_CLEAN_NAMESPACE #include #include #include @@ -15,6 +16,8 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include #include +#include + #include "workspace.h" #include "client.h" #include "stdclient.h" @@ -22,6 +25,7 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include "atoms.h" #include "plugins.h" #include "events.h" +#include "killwindow.h" #include #include #include @@ -38,6 +42,41 @@ const int XIconicState = IconicState; #include #include + + + + +// 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 *)¤t_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; } diff --git a/workspace.h b/workspace.h index 2888c710ed..75af4d561f 100644 --- a/workspace.h +++ b/workspace.h @@ -12,21 +12,22 @@ Copyright (C) 1999, 2000 Matthias Ettrich #include #include #include -#include #include "options.h" #include "plugins.h" #include "KWinInterface.h" +#include + + class Client; class TabBox; class KConfig; class KGlobalAccel; +class RootInfo; typedef QValueList 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