]> Dogcows Code - chaz/openbox/commitdiff
merge from netwm-merge2 to netwm-merge3. Basically, all of netwm that we intend to...
authorDana Jansens <danakj@orodu.net>
Fri, 21 Jun 2002 20:40:14 +0000 (20:40 +0000)
committerDana Jansens <danakj@orodu.net>
Fri, 21 Jun 2002 20:40:14 +0000 (20:40 +0000)
14 files changed:
src/Makefile.am
src/Netizen.cc
src/Netizen.hh
src/Screen.cc
src/Screen.hh
src/Toolbar.cc
src/Window.cc
src/Window.hh
src/Workspace.cc
src/Workspace.hh
src/XAtom.cc
src/XAtom.hh
src/blackbox.cc
src/blackbox.hh

index b17abdc68d749c8edd6524ab6fcc37a68281d7a8..07e9287e5577c8bf6b10ee07ec69826319dbc744 100644 (file)
@@ -37,87 +37,98 @@ distclean-local:
        rm -f *\~ *.orig *.rej .\#*
 
 # local dependencies
-
 BaseDisplay.o: BaseDisplay.cc i18n.hh ../nls/blackbox-nls.hh \
 BaseDisplay.hh Timer.hh Util.hh GCCache.hh Color.hh
+ BaseDisplay.hh Timer.hh Util.hh GCCache.hh Color.hh
 Basemenu.o: Basemenu.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh Basemenu.hh GCCache.hh \
 Color.hh Image.hh Screen.hh Texture.hh Configmenu.hh Iconmenu.hh \
-  Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh Basemenu.hh \
GCCache.hh Color.hh Image.hh Screen.hh Texture.hh Configmenu.hh \
Iconmenu.hh Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh
 Clientmenu.o: Clientmenu.cc blackbox.hh i18n.hh ../nls/blackbox-nls.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh Clientmenu.hh \
 Basemenu.hh Screen.hh Color.hh Texture.hh Image.hh Configmenu.hh \
 Iconmenu.hh Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh \
-  Window.hh Windowmenu.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh \
Clientmenu.hh Basemenu.hh Screen.hh Color.hh Texture.hh Image.hh \
Configmenu.hh Iconmenu.hh Netizen.hh Rootmenu.hh Workspace.hh \
Workspacemenu.hh Window.hh Windowmenu.hh
 Color.o: Color.cc Color.hh BaseDisplay.hh Timer.hh Util.hh
-Configmenu.o: Configmenu.cc i18n.hh ../nls/blackbox-nls.hh Configmenu.hh \
 Basemenu.hh Image.hh Timer.hh BaseDisplay.hh Util.hh Color.hh \
 Toolbar.hh Screen.hh Texture.hh Iconmenu.hh Netizen.hh Rootmenu.hh \
 Workspace.hh Workspacemenu.hh blackbox.hh Configuration.hh Window.hh \
-  Windowmenu.hh
+Configmenu.o: Configmenu.cc i18n.hh ../nls/blackbox-nls.hh \
Configmenu.hh Basemenu.hh Image.hh Timer.hh BaseDisplay.hh Util.hh \
Color.hh Toolbar.hh Screen.hh Texture.hh Iconmenu.hh Netizen.hh \
Rootmenu.hh Workspace.hh Workspacemenu.hh blackbox.hh \
Configuration.hh XAtom.hh Window.hh Windowmenu.hh
 Configuration.o: Configuration.cc ../config.h Configuration.hh Util.hh
-GCCache.o: GCCache.cc GCCache.hh BaseDisplay.hh Timer.hh Util.hh Color.hh
+GCCache.o: GCCache.cc GCCache.hh BaseDisplay.hh Timer.hh Util.hh \
+ Color.hh
 Iconmenu.o: Iconmenu.cc i18n.hh ../nls/blackbox-nls.hh Iconmenu.hh \
-  Basemenu.hh Screen.hh Color.hh Texture.hh Util.hh Image.hh Timer.hh \
-  BaseDisplay.hh Configmenu.hh Netizen.hh Rootmenu.hh Workspace.hh \
-  Workspacemenu.hh blackbox.hh Configuration.hh Window.hh Windowmenu.hh
+ Basemenu.hh Screen.hh Color.hh Texture.hh Util.hh Image.hh Timer.hh \
+ BaseDisplay.hh Configmenu.hh Netizen.hh Rootmenu.hh Workspace.hh \
+ Workspacemenu.hh blackbox.hh Configuration.hh XAtom.hh Window.hh \
+ Windowmenu.hh
 Image.o: Image.cc blackbox.hh i18n.hh ../nls/blackbox-nls.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh GCCache.hh Color.hh \
-  Image.hh Texture.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh GCCache.hh \
Color.hh Image.hh Texture.hh
 ImageControl.o: ImageControl.cc blackbox.hh i18n.hh \
 ../nls/blackbox-nls.hh BaseDisplay.hh Timer.hh Util.hh Configuration.hh \
-  Color.hh Image.hh Texture.hh
../nls/blackbox-nls.hh BaseDisplay.hh Timer.hh Util.hh \
Configuration.hh XAtom.hh Color.hh Image.hh Texture.hh
 Netizen.o: Netizen.cc Netizen.hh Screen.hh Color.hh Texture.hh Util.hh \
 Image.hh Timer.hh BaseDisplay.hh Configmenu.hh Basemenu.hh Iconmenu.hh \
 Rootmenu.hh Workspace.hh Workspacemenu.hh blackbox.hh i18n.hh \
 ../nls/blackbox-nls.hh Configuration.hh
Image.hh Timer.hh BaseDisplay.hh Configmenu.hh Basemenu.hh \
Iconmenu.hh Rootmenu.hh Workspace.hh Workspacemenu.hh blackbox.hh \
i18n.hh ../nls/blackbox-nls.hh Configuration.hh XAtom.hh
 Rootmenu.o: Rootmenu.cc blackbox.hh i18n.hh ../nls/blackbox-nls.hh \
-  BaseDisplay.hh Timer.hh Util.hh Configuration.hh Rootmenu.hh \
-  Basemenu.hh Screen.hh Color.hh Texture.hh Image.hh Configmenu.hh \
-  Iconmenu.hh Netizen.hh Workspace.hh Workspacemenu.hh
-Screen.o: Screen.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
-  BaseDisplay.hh Timer.hh Util.hh Configuration.hh Clientmenu.hh \
-  Basemenu.hh GCCache.hh Color.hh Iconmenu.hh Image.hh Screen.hh \
-  Texture.hh Configmenu.hh Netizen.hh Rootmenu.hh Workspace.hh \
-  Workspacemenu.hh Slit.hh Toolbar.hh Window.hh Windowmenu.hh
-Slit.o: Slit.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh BaseDisplay.hh \
-  Timer.hh Util.hh Configuration.hh Image.hh Color.hh Screen.hh \
-  Texture.hh Configmenu.hh Basemenu.hh Iconmenu.hh Netizen.hh Rootmenu.hh \
-  Workspace.hh Workspacemenu.hh Slit.hh Toolbar.hh
-Texture.o: Texture.cc Texture.hh Color.hh Util.hh BaseDisplay.hh Timer.hh \
-  Image.hh Screen.hh Configmenu.hh Basemenu.hh Iconmenu.hh Netizen.hh \
-  Rootmenu.hh Workspace.hh Workspacemenu.hh blackbox.hh i18n.hh \
-  ../nls/blackbox-nls.hh Configuration.hh
+ BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh Rootmenu.hh \
+ Basemenu.hh Screen.hh Color.hh Texture.hh Image.hh Configmenu.hh \
+ Iconmenu.hh Netizen.hh Workspace.hh Workspacemenu.hh
+Screen.o: Screen.cc ../config.h i18n.hh ../nls/blackbox-nls.hh \
+ blackbox.hh BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh \
+ Clientmenu.hh Basemenu.hh GCCache.hh Color.hh Iconmenu.hh Image.hh \
+ Screen.hh Texture.hh Configmenu.hh Netizen.hh Rootmenu.hh \
+ Workspace.hh Workspacemenu.hh Slit.hh Toolbar.hh Window.hh \
+ Windowmenu.hh
+Slit.o: Slit.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
+ BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh Image.hh \
+ Color.hh Screen.hh Texture.hh Configmenu.hh Basemenu.hh Iconmenu.hh \
+ Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh Slit.hh \
+ Toolbar.hh
+Texture.o: Texture.cc Texture.hh Color.hh Util.hh BaseDisplay.hh \
+ Timer.hh Image.hh Screen.hh Configmenu.hh Basemenu.hh Iconmenu.hh \
+ Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh blackbox.hh \
+ i18n.hh ../nls/blackbox-nls.hh Configuration.hh XAtom.hh
 Timer.o: Timer.cc BaseDisplay.hh Timer.hh Util.hh
 Toolbar.o: Toolbar.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
-  BaseDisplay.hh Timer.hh Util.hh Configuration.hh Clientmenu.hh \
-  Basemenu.hh GCCache.hh Color.hh Iconmenu.hh Image.hh Rootmenu.hh \
-  Screen.hh Texture.hh Configmenu.hh Netizen.hh Workspace.hh \
-  Workspacemenu.hh Toolbar.hh Window.hh Windowmenu.hh Slit.hh
+ BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh \
+ Clientmenu.hh Basemenu.hh GCCache.hh Color.hh Iconmenu.hh Image.hh \
+ Rootmenu.hh Screen.hh Texture.hh Configmenu.hh Netizen.hh \
+ Workspace.hh Workspacemenu.hh Toolbar.hh Window.hh Windowmenu.hh \
+ Slit.hh
 Util.o: Util.cc Util.hh
 Window.o: Window.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh GCCache.hh Color.hh \
 Iconmenu.hh Basemenu.hh Image.hh Screen.hh Texture.hh Configmenu.hh \
 Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh Toolbar.hh \
-  Window.hh Windowmenu.hh Slit.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh GCCache.hh \
Color.hh Iconmenu.hh Basemenu.hh Image.hh Screen.hh Texture.hh \
Configmenu.hh Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh \
Toolbar.hh Window.hh Windowmenu.hh Slit.hh
 Windowmenu.o: Windowmenu.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
-  BaseDisplay.hh Timer.hh Util.hh Configuration.hh Screen.hh Color.hh \
-  Texture.hh Image.hh Configmenu.hh Basemenu.hh Iconmenu.hh Netizen.hh \
-  Rootmenu.hh Workspace.hh Workspacemenu.hh Window.hh Windowmenu.hh
+ BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh Screen.hh \
+ Color.hh Texture.hh Image.hh Configmenu.hh Basemenu.hh Iconmenu.hh \
+ Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh Window.hh \
+ Windowmenu.hh
 Workspace.o: Workspace.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh Clientmenu.hh \
 Basemenu.hh Netizen.hh Screen.hh Color.hh Texture.hh Image.hh \
 Configmenu.hh Iconmenu.hh Rootmenu.hh Workspace.hh Workspacemenu.hh \
-  Toolbar.hh Window.hh Windowmenu.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh \
Clientmenu.hh Basemenu.hh Netizen.hh Screen.hh Color.hh Texture.hh \
Image.hh Configmenu.hh Iconmenu.hh Rootmenu.hh Workspace.hh \
Workspacemenu.hh Toolbar.hh Window.hh Windowmenu.hh
 Workspacemenu.o: Workspacemenu.cc i18n.hh ../nls/blackbox-nls.hh \
-  blackbox.hh BaseDisplay.hh Timer.hh Util.hh Configuration.hh Screen.hh \
-  Color.hh Texture.hh Image.hh Configmenu.hh Basemenu.hh Iconmenu.hh \
-  Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh Toolbar.hh
+ blackbox.hh BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh \
+ Screen.hh Color.hh Texture.hh Image.hh Configmenu.hh Basemenu.hh \
+ Iconmenu.hh Netizen.hh Rootmenu.hh Workspace.hh Workspacemenu.hh \
+ Toolbar.hh
+XAtom.o: XAtom.cc ../config.h XAtom.hh blackbox.hh i18n.hh \
+ ../nls/blackbox-nls.hh BaseDisplay.hh Timer.hh Util.hh \
+ Configuration.hh Screen.hh Color.hh Texture.hh Image.hh Configmenu.hh \
+ Basemenu.hh Iconmenu.hh Netizen.hh Rootmenu.hh Workspace.hh \
+ Workspacemenu.hh
 blackbox.o: blackbox.cc i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh Basemenu.hh \
 Clientmenu.hh GCCache.hh Color.hh Image.hh Rootmenu.hh Screen.hh \
 Texture.hh Configmenu.hh Iconmenu.hh Netizen.hh Workspace.hh \
 Workspacemenu.hh Slit.hh Toolbar.hh Window.hh Windowmenu.hh
BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh Basemenu.hh \
+ Clientmenu.hh GCCache.hh Color.hh Image.hh Rootmenu.hh Screen.hh \
+ Texture.hh Configmenu.hh Iconmenu.hh Netizen.hh Workspace.hh \
+ Workspacemenu.hh Slit.hh Toolbar.hh Window.hh Windowmenu.hh
 i18n.o: i18n.cc i18n.hh ../nls/blackbox-nls.hh
-main.o: main.cc ../version.h i18n.hh ../nls/blackbox-nls.hh blackbox.hh \
 BaseDisplay.hh Timer.hh Util.hh Configuration.hh
+main.o: main.cc ../version.h i18n.hh ../nls/blackbox-nls.hh \
blackbox.hh BaseDisplay.hh Timer.hh Util.hh Configuration.hh XAtom.hh
index 6d73be95e8cd269dfe762ef895a17d9b0a83e404..a50f5e0b82b831ad2ddcebf6f25356685a146521 100644 (file)
 
 #include "Netizen.hh"
 #include "Screen.hh"
+#include "XAtom.hh"
 
 Netizen::Netizen(BScreen *scr, Window win) {
   screen = scr;
   blackbox = scr->getBlackbox();
+  xatom = blackbox->getXAtom();
   window = win;
 
   event.type = ClientMessage;
   event.xclient.message_type =
-    blackbox->getBlackboxStructureMessagesAtom();
+    xatom->getAtom(XAtom::blackbox_structure_messages);
   event.xclient.display = blackbox->getXDisplay();
   event.xclient.window = window;
   event.xclient.format = 32;
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyStartupAtom();
+  event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_startup);
   event.xclient.data.l[1] = event.xclient.data.l[2] =
     event.xclient.data.l[3] = event.xclient.data.l[4] = 0l;
 
@@ -49,7 +51,7 @@ Netizen::Netizen(BScreen *scr, Window win) {
 
 void Netizen::sendWorkspaceCount(void) {
   event.xclient.data.l[0] =
-    blackbox->getBlackboxNotifyWorkspaceCountAtom();
+    xatom->getAtom(XAtom::blackbox_notify_workspace_count);
   event.xclient.data.l[1] = screen->getWorkspaceCount();
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
@@ -58,7 +60,7 @@ void Netizen::sendWorkspaceCount(void) {
 
 void Netizen::sendCurrentWorkspace(void) {
   event.xclient.data.l[0] =
-    blackbox->getBlackboxNotifyCurrentWorkspaceAtom();
+    xatom->getAtom(XAtom::blackbox_notify_current_workspace);
   event.xclient.data.l[1] = screen->getCurrentWorkspaceID();
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
@@ -66,7 +68,7 @@ void Netizen::sendCurrentWorkspace(void) {
 
 
 void Netizen::sendWindowFocus(Window w) {
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyWindowFocusAtom();
+  event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_focus);
   event.xclient.data.l[1] = w;
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
@@ -74,7 +76,7 @@ void Netizen::sendWindowFocus(Window w) {
 
 
 void Netizen::sendWindowAdd(Window w, unsigned long p) {
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyWindowAddAtom();
+  event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_add);
   event.xclient.data.l[1] = w;
   event.xclient.data.l[2] = p;
 
@@ -85,7 +87,7 @@ void Netizen::sendWindowAdd(Window w, unsigned long p) {
 
 
 void Netizen::sendWindowDel(Window w) {
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyWindowDelAtom();
+  event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_del);
   event.xclient.data.l[1] = w;
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
@@ -93,7 +95,7 @@ void Netizen::sendWindowDel(Window w) {
 
 
 void Netizen::sendWindowRaise(Window w) {
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyWindowRaiseAtom();
+  event.xclient.data.l[0] = xatom->getAtom(XAtom::blackbox_notify_window_raise);
   event.xclient.data.l[1] = w;
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
@@ -101,7 +103,8 @@ void Netizen::sendWindowRaise(Window w) {
 
 
 void Netizen::sendWindowLower(Window w) {
-  event.xclient.data.l[0] = blackbox->getBlackboxNotifyWindowLowerAtom();
+  event.xclient.data.l[0] =
+    xatom->getAtom(XAtom::blackbox_notify_window_lower);
   event.xclient.data.l[1] = w;
 
   XSendEvent(blackbox->getXDisplay(), window, False, NoEventMask, &event);
index 2f7cbda2bfaea56d3a7433a5ff078ae47a1f2ac7..aebd20e1fabe0677ee2fac2c06792ef02461763e 100644 (file)
@@ -32,11 +32,13 @@ extern "C" {
 class Blackbox;
 class BScreen;
 class Netizen;
+class XAtom;
 
 class Netizen {
 private:
   Blackbox *blackbox;
   BScreen *screen;
+  XAtom *xatom;
   Window window;
   XEvent event;
 
index 5f69d82af15025eaf2d54d5e8265c501a9c78c82..1bea9bae9999b4ebd3edd6c3b32723dcc850c89b 100644 (file)
@@ -143,6 +143,14 @@ BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
   xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal,
                   (unsigned long) getpid());
 #endif // HAVE_GETPID
+  unsigned long geometry[] = { getWidth(),
+                               getHeight()};
+  xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry,
+                  XAtom::cardinal, geometry, 2);
+  unsigned long viewport[] = {0,0};
+  xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport,
+                  XAtom::cardinal, viewport, 2);
+                  
 
   XDefineCursor(blackbox->getXDisplay(), getRootWindow(),
                 blackbox->getSessionCursor());
@@ -233,6 +241,7 @@ BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
   }
   saveWorkspaceNames();
 
+  updateDesktopNames();
   updateNetizenWorkspaceCount();
 
   workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu);
@@ -253,9 +262,10 @@ BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
 
   InitMenu();
 
-  raiseWindows(0, 0);
+  raiseWindows(0, 0);     // this also initializes the empty stacking list
   rootmenu->update();
 
+  updateClientList();     // initialize the client list, which will be empty
   updateAvailableArea();
 
   changeWorkspaceID(0);
@@ -506,9 +516,10 @@ void BScreen::saveClock24Hour(Bool c) {
 
 void BScreen::saveWorkspaceNames() {
   string names;
-  WorkspaceList::iterator it;
-  WorkspaceList::iterator last = workspacesList.end() - 1;
-  for (it = workspacesList.begin(); it != workspacesList.end(); ++it) {
+  WorkspaceList::iterator it = workspacesList.begin();
+  const WorkspaceList::iterator last = workspacesList.end() - 1;
+  const WorkspaceList::iterator end = workspacesList.end();
+  for (; it != end; ++it) {
     names += (*it)->getName();
     if (it != last)
       names += ',';
@@ -1023,6 +1034,7 @@ unsigned int BScreen::addWorkspace(void) {
 
   toolbar->reconfigure();
 
+  updateDesktopNames();
   updateNetizenWorkspaceCount();
 
   return workspacesList.size();
@@ -1048,6 +1060,7 @@ unsigned int BScreen::removeLastWorkspace(void) {
 
   saveWorkspaces(getWorkspaceCount());
   saveWorkspaceNames();
+  updateDesktopNames();
 
   toolbar->reconfigure();
 
@@ -1083,7 +1096,6 @@ void BScreen::changeWorkspaceID(unsigned int id) {
 
     xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
                     XAtom::cardinal, id);
-    printf("%d\n", id);
 
     workspacemenu->setItemSelected(current_workspace->getID() + 2, True);
     toolbar->redrawWorkspaceLabel(True);
@@ -1100,14 +1112,124 @@ void BScreen::changeWorkspaceID(unsigned int id) {
 }
 
 
+/*
+ * Set the _NET_CLIENT_LIST root window property.
+ */
+void BScreen::updateClientList(void) {
+  if (windowList.size() > 0) {
+    Window *windows = new Window[windowList.size()];
+    Window *win_it = windows;
+    BlackboxWindowList::iterator it = windowList.begin();
+    const BlackboxWindowList::iterator end = windowList.end();
+    for (; it != end; ++it, ++win_it)
+      *win_it = (*it)->getClientWindow();
+    xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
+                    windows, windowList.size());
+    delete [] windows;
+  } else
+    xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
+                    0, 0);
+}
+
+
+/*
+ * Set the _NET_CLIENT_LIST_STACKING root window property.
+ */
+void BScreen::updateStackingList(void) {
+
+  BlackboxWindowList stack_order;
+
+  /*
+   * Get the atacking order from all of the workspaces.
+   * We start with the current workspace so that the sticky windows will be
+   * in the right order on the current workspace.
+   * XXX: Do we need to have sticky windows in the list once for each workspace?
+   */
+  getCurrentWorkspace()->appendStackOrder(stack_order);
+  for (unsigned int i = 0; i < getWorkspaceCount(); ++i)
+    if (i != getCurrentWorkspaceID())
+      getWorkspace(i)->appendStackOrder(stack_order);
+  if (stack_order.size() > 0) {
+    // set the client list atoms
+    Window *windows = new Window[stack_order.size()];
+    Window *win_it = windows;
+    BlackboxWindowList::iterator it = stack_order.begin();
+    const BlackboxWindowList::iterator end = stack_order.end();
+    for (; it != end; ++it, ++win_it)
+      *win_it = (*it)->getClientWindow();
+    xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
+                    XAtom::window, windows, stack_order.size());
+    delete [] windows;
+  } else
+    xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
+                    XAtom::window, 0, 0);
+}
+
+
+void BScreen::addSystrayWindow(Window window) {
+  systrayWindowList.push_back(window);
+  xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
+                  XAtom::window,
+                  &systrayWindowList[0], systrayWindowList.size());
+  blackbox->saveSystrayWindowSearch(window, this);
+}
+
+
+void BScreen::removeSystrayWindow(Window window) {
+  WindowList::iterator it = systrayWindowList.begin();
+  const WindowList::iterator end = systrayWindowList.end();
+  for (; it != end; ++it)
+    if (*it == window) {
+      systrayWindowList.erase(it);
+      xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
+                      XAtom::window,
+                      &systrayWindowList[0], systrayWindowList.size());
+      blackbox->removeSystrayWindowSearch(window);
+      break;
+    }
+}
+
+
+void BScreen::addDesktopWindow(Window window) {
+  desktopWindowList.push_back(window);
+  XLowerWindow(blackbox->getXDisplay(), window);
+  XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask);
+  blackbox->saveDesktopWindowSearch(window, this);
+}
+
+
+void BScreen::removeDesktopWindow(Window window) {
+  WindowList::iterator it = desktopWindowList.begin();
+  const WindowList::iterator end = desktopWindowList.end();
+  for (; it != end; ++it)
+    if (*it == window) {
+      desktopWindowList.erase(it);
+      XSelectInput(blackbox->getXDisplay(), window, None);
+      blackbox->removeDesktopWindowSearch(window);
+      break;
+    }
+}
+
+
 void BScreen::manageWindow(Window w) {
   new BlackboxWindow(blackbox, w, this);
 
   BlackboxWindow *win = blackbox->searchWindow(w);
   if (! win)
     return;
+  if (win->isDesktop()) {
+    // desktop windows cant do anything, so we remove all the normal window
+    // stuff from them, they are only kept around so that we can keep them on
+    // the bottom of the z-order
+    addDesktopWindow(win->getClientWindow());
+    win->restore(True);
+    delete win;
+    return;
+  }
 
   windowList.push_back(win);
+  updateClientList();
 
   XMapRequestEvent mre;
   mre.window = w;
@@ -1126,6 +1248,7 @@ void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) {
     removeIcon(w);
 
   windowList.remove(w);
+  updateClientList();
 
   if (blackbox->getFocusedWindow() == w)
     blackbox->setFocusedWindow((BlackboxWindow *) 0);
@@ -1172,6 +1295,25 @@ void BScreen::removeNetizen(Window w) {
 }
 
 
+void BScreen::updateWorkArea(void) {
+  if (workspacesList.size() > 0) {
+    unsigned long *dims = new unsigned long[4 * workspacesList.size()];
+    for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
+      // XXX: this could be different for each workspace
+      const Rect &area = availableArea();
+      dims[(i * 4) + 0] = area.x();
+      dims[(i * 4) + 1] = area.y();
+      dims[(i * 4) + 2] = area.width();
+      dims[(i * 4) + 3] = area.height();
+    }
+    xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
+                    dims, 4 * workspacesList.size());
+  } else
+    xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
+                    0, 0);
+}
+
+
 void BScreen::updateNetizenCurrentWorkspace(void) {
   std::for_each(netizenList.begin(), netizenList.end(),
                 std::mem_fun(&Netizen::sendCurrentWorkspace));
@@ -1182,6 +1324,8 @@ void BScreen::updateNetizenWorkspaceCount(void) {
   xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops,
                   XAtom::cardinal, workspacesList.size());
 
+  updateWorkArea();
+  
   std::for_each(netizenList.begin(), netizenList.end(),
                 std::mem_fun(&Netizen::sendWorkspaceCount));
 }
@@ -1190,6 +1334,10 @@ void BScreen::updateNetizenWorkspaceCount(void) {
 void BScreen::updateNetizenWindowFocus(void) {
   Window f = ((blackbox->getFocusedWindow()) ?
               blackbox->getFocusedWindow()->getClientWindow() : None);
+
+  xatom->setValue(getRootWindow(), XAtom::net_active_window,
+                  XAtom::window, f);
+
   NetizenList::iterator it = netizenList.begin();
   for (; it != netizenList.end(); ++it)
     (*it)->sendWindowFocus(f);
@@ -1277,11 +1425,35 @@ void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
   XRestackWindows(blackbox->getXDisplay(), session_stack, i);
 
   delete [] session_stack;
+
+  updateStackingList();
+}
+
+
+void BScreen::lowerDesktops(void) {
+  XLowerWindow(blackbox->getXDisplay(), desktopWindowList[0]);
+  if (desktopWindowList.size() > 1)
+    XRestackWindows(blackbox->getXDisplay(), &desktopWindowList[0],
+                    desktopWindowList.size());
 }
 
 
 void BScreen::addWorkspaceName(const string& name) {
   workspaceNames.push_back(name);
+  updateDesktopNames();
+}
+
+
+void BScreen::updateDesktopNames(){
+  XAtom::StringVect names;
+
+  WorkspaceList::iterator it = workspacesList.begin();
+  const WorkspaceList::iterator end = workspacesList.end();
+  for (; it != end; ++it)
+    names.push_back((*it)->getName());
+
+  xatom->setValue(getRootWindow(), XAtom::net_desktop_names,
+                  XAtom::utf8, names);
 }
 
 
@@ -1956,6 +2128,8 @@ void BScreen::updateAvailableArea(void) {
     for (; it != end; ++it)
       if ((*it)->isMaximized()) (*it)->remaximize();
   }
+
+  updateWorkArea();  
 }
 
 
index 44199b3437c5881f5238616f792222c387408f0b..e8c8cd7a743e9ebf0055e56239ada058b9cd5265 100644 (file)
@@ -129,6 +129,9 @@ private:
   NetizenList netizenList;
   BlackboxWindowList iconList, windowList;
 
+  typedef std::vector<Window> WindowList;
+  WindowList desktopWindowList, systrayWindowList;
+
   Slit *slit;
   Toolbar *toolbar;
   Workspace *current_workspace;
@@ -190,7 +193,7 @@ private:
   void InitMenu(void);
   void LoadStyle(void);
 
-
+  void updateWorkArea(void);
 public:
   enum { RowSmartPlacement = 1, ColSmartPlacement, CascadePlacement,
          UnderMousePlacement, LeftRight, RightLeft, TopBottom, BottomTop };
@@ -310,16 +313,26 @@ public:
   const std::string getNameOfWorkspace(unsigned int id);
   void changeWorkspaceID(unsigned int id);
   void saveWorkspaceNames(void);
+  void updateDesktopNames(void);
 
   void addNetizen(Netizen *n);
   void removeNetizen(Window w);
 
+  void addDesktopWindow(Window window);
+  void removeDesktopWindow(Window window);
+
+  void addSystrayWindow(Window window);
+  void removeSystrayWindow(Window window);
+
   void addIcon(BlackboxWindow *w);
   void removeIcon(BlackboxWindow *w);
 
+  void updateClientList(void);
+  void updateStackingList(void);
   void manageWindow(Window w);
   void unmanageWindow(BlackboxWindow *w, bool remap);
   void raiseWindows(Window *workspace_stack, unsigned int num);
+  void lowerDesktops(void);
   void reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id,
                          bool ignore_sticky);
   void propagateWindowName(const BlackboxWindow *bw);
index 55beb59de8898204a18aea5194ea5e90a227ff5d..9c7c2fafbbce319de7ee4099302446c87145f688 100644 (file)
@@ -979,6 +979,7 @@ void Toolbar::keyPressEvent(XKeyEvent *ke) {
 
       Workspace *wkspc = screen->getCurrentWorkspace();
       wkspc->setName(new_workspace_name);
+      screen->updateDesktopNames();
       wkspc->getMenu()->hide();
 
       screen->getWorkspacemenu()->changeItemLabel(wkspc->getID() + 2,
index 9e3d9f5eabd8a78dd4e183744c186e1794f16903..7df3d64a6c4e4bd2fe034782a83295cf4ba006fc 100644 (file)
@@ -110,7 +110,8 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
 
   flags.moving = flags.resizing = flags.shaded = flags.visible =
     flags.iconic = flags.focused = flags.stuck = flags.modal =
-    flags.send_focus_message = flags.shaped = False;
+    flags.send_focus_message = flags.shaped = flags.skip_taskbar =
+    flags.skip_pager = flags.fullscreen = False;
   flags.maximized = 0;
 
   blackbox_attrib.workspace = window_number = BSENTINEL;
@@ -155,8 +156,10 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
   timer = new BTimer(blackbox, this);
   timer->setTimeout(blackbox->getAutoRaiseDelay());
 
-  if (! getBlackboxHints())
+  if (! getBlackboxHints()) {
     getMWMHints();
+    getNetWMHints();
+  }
 
   // get size, aspect, minimum/maximum size and other hints set by the
   // client
@@ -170,6 +173,12 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
     return;
   }
 
+  if (isKDESystrayWindow()) {
+    screen->addSystrayWindow(client.window);
+    delete this;
+    return;
+  }
+
   frame.window = createToplevelWindow();
   frame.plate = createChildWindow(frame.window);
   associateClientWindow();
@@ -178,15 +187,56 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
   blackbox->saveWindowSearch(frame.plate, this);
   blackbox->saveWindowSearch(client.window, this);
 
+  screen->addStrut(&client.strut);
+  updateStrut();
+  
   // determine if this is a transient window
   getTransientInfo();
 
-  // adjust the window decorations based on transience and window sizes
-  if (isTransient()) {
+  // determine the window's type, so we can decide its decorations and
+  // functionality, or if we should not manage it at all
+  getWindowType();
+
+  // adjust the window decorations/behavior based on the window type
+  switch (window_type) {
+  case Type_Desktop:
+    // desktop windows are not managed by us, we just make sure they stay on the
+    // bottom.
+    return;
+
+  case Type_Dock:
+    // docks (such as kicker) cannot be moved, and appear on all workspaces
+    functions &= ~(Func_Move);
+    flags.stuck = True;
+  case Type_Toolbar:
+  case Type_Menu:
+  case Type_Utility:
+    // these windows have minimal decorations, only a titlebar, and cannot
+    // be resized or iconified
+    decorations &= ~(Decor_Maximize | Decor_Handle | Decor_Border |
+                     Decor_Iconify);
+    functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
+    break;
+
+  case Type_Splash:
+    // splash screens have no functionality or decorations, they are left up
+    // to the application which created them
+    decorations = 0;
+    functions = 0;
+    break;
+
+  case Type_Dialog:
+    // dialogs cannot be maximized, and don't display a handle
     decorations &= ~(Decor_Maximize | Decor_Handle);
     functions &= ~Func_Maximize;
+    break;
+
+  case Type_Normal:
+    // normal windows retain all of the possible decorations and functionality
+    break;
   }
 
+  // further adjeust the window's decorations/behavior based on window sizes
   if ((client.normal_hint_flags & PMinSize) &&
       (client.normal_hint_flags & PMaxSize) &&
       client.max_width <= client.min_width &&
@@ -196,6 +246,8 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
   }
   upsize();
 
+  setAllowedActions();
+
   bool place_window = True;
   if (blackbox->isStartup() || isTransient() ||
       client.normal_hint_flags & (PPosition|USPosition)) {
@@ -222,19 +274,22 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
   if ((! screen->isSloppyFocus()) || screen->doClickRaise()) {
     // grab button 1 for changing focus/raising
     blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
-                         GrabModeSync, GrabModeSync, frame.plate, None);
+                         GrabModeSync, GrabModeSync, None, None);
   }
 
-  blackbox->grabButton(Button1, Mod1Mask, frame.window, True,
-                       ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
-                       GrabModeAsync, frame.window, blackbox->getMoveCursor());
+  if (functions & Func_Move)
+    blackbox->grabButton(Button1, Mod1Mask, frame.window, True,
+                         ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+                         GrabModeAsync, frame.window,
+                         blackbox->getMoveCursor());
   blackbox->grabButton(Button2, Mod1Mask, frame.window, True,
                        ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
-                       frame.window, None);
-  blackbox->grabButton(Button3, Mod1Mask, frame.window, True,
-                       ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
-                       GrabModeAsync, frame.window,
-                       blackbox->getLowerRightAngleCursor());
+                       None, None);
+  if (functions & Func_Resize)
+    blackbox->grabButton(Button3, Mod1Mask, frame.window, True,
+                         ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
+                         GrabModeAsync, None,
+                         blackbox->getLowerRightAngleCursor());
 
   positionWindows();
   decorate();
@@ -267,6 +322,11 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
       current_state = NormalState;
   }
 
+  // get sticky state from our parent window if we've got one
+  if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
+      client.transient_for->isStuck() != flags.stuck)
+    stick();
+
   if (flags.shaded) {
     flags.shaded = False;
     shade();
@@ -313,10 +373,13 @@ BlackboxWindow::~BlackboxWindow(void) {
   if (! timer) // window not managed...
     return;
 
-  if (flags.moving || flags.resizing) {
-    screen->hideGeometry();
-    XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
-  }
+  screen->removeStrut(&client.strut);
+  screen->updateAvailableArea();
+
+  // We don't need to worry about resizing because resizing always grabs the X
+  // server. This should only ever happen if using opaque moving.
+  if (flags.moving)
+    endMove();
 
   delete timer;
 
@@ -741,19 +804,19 @@ void BlackboxWindow::positionButtons(bool redecorate_label) {
   for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
     switch(*it) {
     case 'C':
-      if (!frame.close_button) createCloseButton();
+      if (! frame.close_button) createCloseButton();
       XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
                         frame.button_w, frame.button_w);
       x += frame.button_w + bsep;
       break;
     case 'I':
-      if (!frame.iconify_button) createIconifyButton();
+      if (! frame.iconify_button) createIconifyButton();
       XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
                         frame.button_w, frame.button_w);
       x += frame.button_w + bsep;
       break;
     case 'M':
-      if (!frame.maximize_button) createMaximizeButton();
+      if (! frame.maximize_button) createMaximizeButton();
       XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
                         frame.button_w, frame.button_w);
       x += frame.button_w + bsep;
@@ -863,32 +926,98 @@ void BlackboxWindow::positionWindows(void) {
 }
 
 
-void BlackboxWindow::getWMName(void) {
-  XTextProperty text_prop;
+void BlackboxWindow::updateStrut(void) {
+  unsigned long num = 4;
+  unsigned long *data;
+  if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
+                        num, &data))
+    return;
+  if (num == 4) {
+    client.strut.left = data[0];
+    client.strut.right = data[1];
+    client.strut.top = data[2];
+    client.strut.bottom = data[3];
+
+    screen->updateAvailableArea();
+  }
+
+  delete [] data;
+}
+
+
+void BlackboxWindow::getWindowType(void) {
+  unsigned long val;
+  if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
+                      val)) {
+    if (val == xatom->getAtom(XAtom::net_wm_window_type_desktop))
+      window_type = Type_Desktop;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_dock))
+      window_type = Type_Dock;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
+      window_type = Type_Toolbar;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_menu))
+      window_type = Type_Menu;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_utility))
+      window_type = Type_Utility;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_splash))
+      window_type = Type_Splash;
+    else if (val == xatom->getAtom(XAtom::net_wm_window_type_dialog))
+      window_type = Type_Dialog;
+    else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
+      window_type = Type_Normal;
+    return;
+  }
 
-  if (XGetWMName(blackbox->getXDisplay(), client.window, &text_prop)) {
-    client.title = textPropertyToString(blackbox->getXDisplay(), text_prop);
-    if (client.title.empty())
-      client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
-    XFree((char *) text_prop.value);
-  } else {
-    client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
+  /*
+   * the window type hint was not set, which means we either classify ourself
+   * as a normal window or a dialog, depending on if we are a transient.
+   */
+  if (isTransient())
+    window_type = Type_Dialog;
+
+  window_type = Type_Normal;
+}
+
+
+void BlackboxWindow::getWMName(void) {
+  if (xatom->getValue(client.window, XAtom::net_wm_name,
+                      XAtom::utf8, client.title) &&
+      !client.title.empty()) {
+    xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
+    return;
   }
+  //fall through to using WM_NAME
+  if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
+      && !client.title.empty()) {
+    xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
+    return;
+  }
+  // fall back to an internal default
+  client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
+  xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
+                  client.title);
 }
 
 
 void BlackboxWindow::getWMIconName(void) {
-  XTextProperty text_prop;
-
-  if (XGetWMIconName(blackbox->getXDisplay(), client.window, &text_prop)) {
-    client.icon_title =
-      textPropertyToString(blackbox->getXDisplay(), text_prop);
-    if (client.icon_title.empty())
-      client.icon_title = client.title;
-    XFree((char *) text_prop.value);
-  } else {
-    client.icon_title = client.title;
+  if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
+                      XAtom::utf8, client.icon_title) && 
+      !client.icon_title.empty()) {
+    xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
+    return;
   }
+  //fall through to using WM_ICON_NAME
+  if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
+                      client.icon_title) && 
+      !client.icon_title.empty()) {
+    xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
+    return;
+  }
+  // fall back to using the main name
+  client.icon_title = client.title;
+  xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
+                  client.icon_title);
 }
 
 
@@ -906,12 +1035,12 @@ void BlackboxWindow::getWMProtocols(void) {
   if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
                       &proto, &num_return)) {
     for (int i = 0; i < num_return; ++i) {
-      if (proto[i] == blackbox->getWMDeleteAtom()) {
+      if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
         decorations |= Decor_Close;
         functions |= Func_Close;
-      } else if (proto[i] == blackbox->getWMTakeFocusAtom())
+      } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
         flags.send_focus_message = True;
-      else if (proto[i] == blackbox->getBlackboxStructureMessagesAtom())
+      else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages))
         screen->addNetizen(new Netizen(screen, client.window));
     }
 
@@ -1033,6 +1162,56 @@ void BlackboxWindow::getWMNormalHints(void) {
 }
 
 
+/*
+ * Gets the NETWM hints for the class' contained window.
+ */
+void BlackboxWindow::getNetWMHints(void) {
+  unsigned long workspace;
+
+  if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
+                      workspace)) {
+    if (workspace == 0xffffffff)
+      flags.stuck = True;
+    else
+      blackbox_attrib.workspace = workspace;
+  }
+
+  unsigned long *state;
+  unsigned long num = (unsigned) -1;
+  if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
+                      num, &state)) {
+    bool vert = False,
+         horz = False;
+    for (unsigned long i = 0; i < num; ++i) {
+      if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
+        flags.modal = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
+        flags.shaded = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
+        flags.skip_taskbar = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
+        flags.skip_pager = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
+        flags.fullscreen = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
+        setState(IconicState);
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
+        vert = True;
+      else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
+        horz = True;
+    }
+    if (vert && horz)
+      flags.maximized = 1;
+    else if (vert)
+      flags.maximized = 2;
+    else if (horz)
+      flags.maximized = 3;
+
+    delete [] state;
+  }
+}
+
+
 /*
  * Gets the MWM hints for the class' contained window.
  * This is used while initializing the window to its first state, and not
@@ -1041,19 +1220,14 @@ void BlackboxWindow::getWMNormalHints(void) {
  * false if they are not.
  */
 void BlackboxWindow::getMWMHints(void) {
-  int format;
-  Atom atom_return;
-  unsigned long num, len;
-  MwmHints *mwm_hint = 0;
-
-  int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
-                               blackbox->getMotifWMHintsAtom(), 0,
-                               PropMwmHintsElements, False,
-                               blackbox->getMotifWMHintsAtom(), &atom_return,
-                               &format, &num, &len,
-                               (unsigned char **) &mwm_hint);
-
-  if (ret != Success || ! mwm_hint || num != PropMwmHintsElements)
+  unsigned long num;
+  MwmHints *mwm_hint;
+
+  num = PropMwmHintsElements;
+  if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
+                        XAtom::motif_wm_hints, num,
+                        (unsigned long **)&mwm_hint) ||
+      num < PropMwmHintsElements)
     return;
 
   if (mwm_hint->flags & MwmHintsDecorations) {
@@ -1095,7 +1269,7 @@ void BlackboxWindow::getMWMHints(void) {
         functions |= Func_Close;
     }
   }
-  XFree(mwm_hint);
+  delete mwm_hint;
 }
 
 
@@ -1107,18 +1281,14 @@ void BlackboxWindow::getMWMHints(void) {
  * they are not.
  */
 bool BlackboxWindow::getBlackboxHints(void) {
-  int format;
-  Atom atom_return;
-  unsigned long num, len;
-  BlackboxHints *blackbox_hint = 0;
-
-  int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
-                               blackbox->getBlackboxHintsAtom(), 0,
-                               PropBlackboxHintsElements, False,
-                               blackbox->getBlackboxHintsAtom(), &atom_return,
-                               &format, &num, &len,
-                               (unsigned char **) &blackbox_hint);
-  if (ret != Success || ! blackbox_hint || num != PropBlackboxHintsElements)
+  unsigned long num;
+  BlackboxHints *blackbox_hint;
+
+  num = PropBlackboxHintsElements;
+  if (! xatom->getValue(client.window, XAtom::blackbox_hints,
+                        XAtom::blackbox_hints, num,
+                        (unsigned long **)&blackbox_hint) ||
+      num < PropBlackboxHintsElements)
     return False;
 
   if (blackbox_hint->flags & AttribShaded)
@@ -1180,7 +1350,9 @@ bool BlackboxWindow::getBlackboxHints(void) {
 
     reconfigure();
   }
-  XFree(blackbox_hint);
+  
+  delete blackbox_hint;
+
   return True;
 }
 
@@ -1240,6 +1412,15 @@ void BlackboxWindow::getTransientInfo(void) {
 }
 
 
+bool BlackboxWindow::isKDESystrayWindow(void) {
+  Window systray;
+  if (xatom->getValue(client.window, XAtom::kde_net_wm_system_tray_window_for,
+                      XAtom::window, systray) && systray)
+    return True;
+  return False;
+}
+
+
 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
   if (client.transient_for &&
       client.transient_for != (BlackboxWindow*) ~0ul)
@@ -1388,11 +1569,11 @@ bool BlackboxWindow::setInputFocus(void) {
   if (flags.send_focus_message) {
     XEvent ce;
     ce.xclient.type = ClientMessage;
-    ce.xclient.message_type = blackbox->getWMProtocolsAtom();
+    ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
     ce.xclient.display = blackbox->getXDisplay();
     ce.xclient.window = client.window;
     ce.xclient.format = 32;
-    ce.xclient.data.l[0] = blackbox->getWMTakeFocusAtom();
+    ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
     ce.xclient.data.l[1] = blackbox->getLastTime();
     ce.xclient.data.l[2] = 0l;
     ce.xclient.data.l[3] = 0l;
@@ -1408,10 +1589,13 @@ bool BlackboxWindow::setInputFocus(void) {
 void BlackboxWindow::iconify(void) {
   if (flags.iconic) return;
 
+  // We don't need to worry about resizing because resizing always grabs the X
+  // server. This should only ever happen if using opaque moving.
+  if (flags.moving)
+    endMove();
+    
   if (windowmenu) windowmenu->hide();
 
-  setState(IconicState);
-
   /*
    * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
    * we need to clear the event mask on client.window for a split second.
@@ -1430,6 +1614,8 @@ void BlackboxWindow::iconify(void) {
   flags.visible = False;
   flags.iconic = True;
 
+  setState(IconicState);
+
   screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
 
   if (isTransient()) {
@@ -1453,15 +1639,15 @@ void BlackboxWindow::iconify(void) {
 
 
 void BlackboxWindow::show(void) {
+  flags.visible = True;
+  flags.iconic = False;
+
   current_state = (flags.shaded) ? IconicState : NormalState;
   setState(current_state);
 
   XMapWindow(blackbox->getXDisplay(), client.window);
   XMapSubwindows(blackbox->getXDisplay(), frame.window);
   XMapWindow(blackbox->getXDisplay(), frame.window);
-
-  flags.visible = True;
-  flags.iconic = False;
 }
 
 
@@ -1489,11 +1675,11 @@ void BlackboxWindow::deiconify(bool reassoc, bool raise) {
 void BlackboxWindow::close(void) {
   XEvent ce;
   ce.xclient.type = ClientMessage;
-  ce.xclient.message_type = blackbox->getWMProtocolsAtom();
+  ce.xclient.message_type =  xatom->getAtom(XAtom::wm_protocols);
   ce.xclient.display = blackbox->getXDisplay();
   ce.xclient.window = client.window;
   ce.xclient.format = 32;
-  ce.xclient.data.l[0] = blackbox->getWMDeleteAtom();
+  ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
   ce.xclient.data.l[1] = CurrentTime;
   ce.xclient.data.l[2] = 0l;
   ce.xclient.data.l[3] = 0l;
@@ -1503,11 +1689,16 @@ void BlackboxWindow::close(void) {
 
 
 void BlackboxWindow::withdraw(void) {
-  setState(current_state);
-
+  // We don't need to worry about resizing because resizing always grabs the X
+  // server. This should only ever happen if using opaque moving.
+  if (flags.moving)
+    endMove();
+    
   flags.visible = False;
   flags.iconic = False;
 
+  setState(current_state);
+
   XUnmapWindow(blackbox->getXDisplay(), frame.window);
 
   XGrabServer(blackbox->getXDisplay());
@@ -1524,6 +1715,11 @@ void BlackboxWindow::withdraw(void) {
 
 
 void BlackboxWindow::maximize(unsigned int button) {
+  // We don't need to worry about resizing because resizing always grabs the X
+  // server. This should only ever happen if using opaque moving.
+  if (flags.moving)
+    endMove();
+
   // handle case where menu is open then the max button is used instead
   if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
 
@@ -1534,7 +1730,7 @@ void BlackboxWindow::maximize(unsigned int button) {
     blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
 
     /*
-      when a resize is begun, maximize(0) is called to clear any maximization
+      when a resize finishes, maximize(0) is called to clear any maximization
       flags currently set.  Otherwise it still thinks it is maximized.
       so we do not need to call configure() because resizing will handle it
     */
@@ -1624,6 +1820,7 @@ void BlackboxWindow::remaximize(void) {
 void BlackboxWindow::setWorkspace(unsigned int n) {
   blackbox_attrib.flags |= AttribWorkspace;
   blackbox_attrib.workspace = n;
+  xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
 }
 
 
@@ -1658,6 +1855,9 @@ void BlackboxWindow::shade(void) {
 }
 
 
+/*
+ * (Un)Sticks a window and its relatives.
+ */
 void BlackboxWindow::stick(void) {
   if (flags.stuck) {
     blackbox_attrib.flags ^= AttribOmnipresent;
@@ -1667,6 +1867,11 @@ void BlackboxWindow::stick(void) {
 
     if (! flags.iconic)
       screen->reassociateWindow(this, BSENTINEL, True);
+    else
+      // temporary fix since sticky windows suck. set the hint to what we
+      // actually hold in our data.
+      xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
+                      blackbox_attrib.workspace);
 
     setState(current_state);
   } else {
@@ -1675,8 +1880,23 @@ void BlackboxWindow::stick(void) {
     blackbox_attrib.flags |= AttribOmnipresent;
     blackbox_attrib.attrib |= AttribOmnipresent;
 
+    // temporary fix since sticky windows suck. set the hint to a different
+    // value than that contained in the class' data.
+    xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
+                    0xffffffff);
+
     setState(current_state);
   }
+  // go up the chain
+  if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
+      client.transient_for->isStuck() != flags.stuck)
+    client.transient_for->stick();
+  // go down the chain
+  BlackboxWindowList::iterator it;
+  const BlackboxWindowList::iterator end = client.transientList.end();
+  for (it = client.transientList.begin(); it != end; ++it)
+    if ((*it)->isStuck() != flags.stuck)
+      (*it)->stick();
 }
 
 
@@ -1806,6 +2026,28 @@ void BlackboxWindow::installColormap(bool install) {
 }
 
 
+void BlackboxWindow::setAllowedActions(void) {
+  Atom actions[7];
+  int num = 0;
+  
+  actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
+  actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
+  actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
+
+  if (functions & Func_Move)
+    actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
+  if (functions & Func_Resize)
+    actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
+  if (functions & Func_Maximize) {
+    actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
+    actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
+  }
+
+  xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
+                  actions, num);
+}
+
+
 void BlackboxWindow::setState(unsigned long new_state) {
   current_state = new_state;
 
@@ -1817,41 +2059,49 @@ void BlackboxWindow::setState(unsigned long new_state) {
   xatom->setValue(client.window, XAtom::blackbox_attributes,
                   XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
                   PropBlackboxAttributesElements);
+
+  Atom netstate[8];
+  int num = 0;
+  if (flags.modal)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
+  if (flags.shaded)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
+  if (flags.iconic)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
+  if (flags.skip_taskbar)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
+  if (flags.skip_pager)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
+  if (flags.fullscreen)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
+  if (flags.maximized == 1 || flags.maximized == 2)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
+  if (flags.maximized == 1 || flags.maximized == 3)
+    netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
+  xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
+                  netstate, num);
 }
 
 
 bool BlackboxWindow::getState(void) {
-  current_state = 0;
-
-  Atom atom_return;
-  bool ret = False;
-  unsigned long *state, nitems;
-
-  if (! xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state, nitems,
-                        &state))
-    return False;
-
-  current_state = static_cast<unsigned long>(state[0]);
-  delete state;
-
-  return True;
+  bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
+                             current_state);
+  if (! ret) current_state = 0;
+  return ret;
 }
 
 
 void BlackboxWindow::restoreAttributes(void) {
-  Atom atom_return;
-  int foo;
-  unsigned long ulfoo, nitems;
-
+  unsigned long num = PropBlackboxAttributesElements;
   BlackboxAttributes *net;
-  int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
-                               blackbox->getBlackboxAttributesAtom(), 0l,
-                               PropBlackboxAttributesElements, False,
-                               blackbox->getBlackboxAttributesAtom(),
-                               &atom_return, &foo, &nitems, &ulfoo,
-                               (unsigned char **) &net);
-  if (ret != Success || ! net || nitems != PropBlackboxAttributesElements)
+  if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
+                        XAtom::blackbox_attributes, num,
+                        (unsigned long **)&net))
+    return;
+  if (num < PropBlackboxAttributesElements) {
+    delete net;
     return;
+  }
 
   if (net->flags & AttribShaded && net->attrib & AttribShaded) {
     flags.shaded = False;
@@ -1868,9 +2118,11 @@ void BlackboxWindow::restoreAttributes(void) {
  }
 
   if ((net->workspace != screen->getCurrentWorkspaceID()) &&
-      (net->workspace < screen->getWorkspaceCount())) {
+      (net->workspace < screen->getWorkspaceCount()))
     screen->reassociateWindow(this, net->workspace, True);
 
+  if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
+      (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
     // set to WithdrawnState so it will be mapped on the new workspace
     if (current_state == NormalState) current_state = WithdrawnState;
   } else if (current_state == WithdrawnState) {
@@ -1913,7 +2165,7 @@ void BlackboxWindow::restoreAttributes(void) {
   // with the state set it will then be the map events job to read the window's
   // state and behave accordingly
 
-  XFree((void *) net);
+  delete net;
 }
 
 
@@ -2231,6 +2483,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
     if (isTransient()) {
       decorations &= ~(Decor_Maximize | Decor_Handle);
       functions &= ~Func_Maximize;
+      setAllowedActions();
     }
 
     reconfigure();
@@ -2246,6 +2499,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
     if (flags.iconic) screen->propagateWindowName(this);
     break;
 
+  case XAtom::net_wm_name:
   case XA_WM_NAME:
     getWMName();
 
@@ -2268,6 +2522,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
         decorations |= Decor_Maximize | Decor_Handle;
         functions |= Func_Resize | Func_Maximize;
       }
+      setAllowedActions();
     }
 
     Rect old_rect = frame.rect;
@@ -2281,7 +2536,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
   }
 
   default:
-    if (atom == blackbox->getWMProtocolsAtom()) {
+    if (atom == xatom->getAtom(XAtom::wm_protocols)) {
       getWMProtocols();
 
       if ((decorations & Decor_Close) && (! frame.close_button)) {
@@ -2292,6 +2547,8 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
         }
         if (windowmenu) windowmenu->reconfigure();
       }
+    } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) {
+      updateStrut();
     }
 
     break;
@@ -2382,9 +2639,6 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) {
         }
       }
 
-      frame.grab_x = be->x_root - frame.rect.x() - frame.border_w;
-      frame.grab_y = be->y_root - frame.rect.y() - frame.border_w;
-
       if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
 
       screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
@@ -2478,307 +2732,344 @@ void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) {
       close();
     redrawCloseButton(False);
   } else if (flags.moving) {
-    flags.moving = False;
-
-    if (! screen->doOpaqueMove()) {
-      /* when drawing the rubber band, we need to make sure we only draw inside
-       * the frame... frame.changing_* contain the new coords for the window,
-       * so we need to subtract 1 from changing_w/changing_h every where we
-       * draw the rubber band (for both moving and resizing)
-       */
-      XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                     screen->getOpGC(), frame.changing.x(), frame.changing.y(),
-                     frame.changing.width() - 1, frame.changing.height() - 1);
-      XUngrabServer(blackbox->getXDisplay());
-
-      configure(frame.changing.x(), frame.changing.y(),
-                frame.changing.width(), frame.changing.height());
-    } else {
-      configure(frame.rect.x(), frame.rect.y(),
-                frame.rect.width(), frame.rect.height());
-    }
-    screen->hideGeometry();
-    XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
+    endMove();
   } else if (flags.resizing) {
+    endResize();
+  } else if (re->window == frame.window) {
+    if (re->button == 2 && re->state == Mod1Mask)
+      XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
+  }
+}
+
+
+void BlackboxWindow::beginMove(int x_root, int y_root) {
+  assert(! (flags.resizing || flags.moving));
+
+  /*
+    Only one window can be moved/resized at a time. If another window is already
+    being moved or resized, then stop it before whating to work with this one.
+  */
+  BlackboxWindow *changing = blackbox->getChangingWindow();
+  if (changing && changing != this) {
+    if (changing->flags.moving)
+      changing->endMove();
+    else // if (changing->flags.resizing)
+      changing->endResize();
+  }
+  
+  XGrabPointer(blackbox->getXDisplay(), frame.window, False,
+               PointerMotionMask | ButtonReleaseMask,
+               GrabModeAsync, GrabModeAsync,
+               None, blackbox->getMoveCursor(), CurrentTime);
+
+  if (windowmenu && windowmenu->isVisible())
+    windowmenu->hide();
+
+  flags.moving = True;
+  blackbox->setChangingWindow(this);
+
+  if (! screen->doOpaqueMove()) {
+    XGrabServer(blackbox->getXDisplay());
+
+    frame.changing = frame.rect;
+    screen->showPosition(frame.changing.x(), frame.changing.y());
+
+    XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                   screen->getOpGC(),
+                   frame.changing.x(),
+                   frame.changing.y(),
+                   frame.changing.width() - 1,
+                   frame.changing.height() - 1);
+  }
+
+  frame.grab_x = x_root - frame.rect.x() - frame.border_w;
+  frame.grab_y = y_root - frame.rect.y() - frame.border_w;
+}
+
+void BlackboxWindow::doMove(int x_root, int y_root) {
+  assert(flags.moving);
+  assert(blackbox->getChangingWindow() == this);
+
+  int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
+  dx -= frame.border_w;
+  dy -= frame.border_w;
+
+  const int snap_distance = screen->getEdgeSnapThreshold();
+
+  if (snap_distance) {
+    Rect srect = screen->availableArea();
+    // window corners
+    const int wleft = dx,
+      wright = dx + frame.rect.width() - 1,
+      wtop = dy,
+      wbottom = dy + frame.rect.height() - 1;
+
+    int dleft = std::abs(wleft - srect.left()),
+      dright = std::abs(wright - srect.right()),
+      dtop = std::abs(wtop - srect.top()),
+      dbottom = std::abs(wbottom - srect.bottom());
+
+    // snap left?
+    if (dleft < snap_distance && dleft < dright)
+      dx = srect.left();
+    // snap right?
+    else if (dright < snap_distance && dright < dleft)
+      dx = srect.right() - frame.rect.width() + 1;
+
+    // snap top?
+    if (dtop < snap_distance && dtop < dbottom)
+      dy = srect.top();
+    // snap bottom?
+    else if (dbottom < snap_distance && dbottom < dtop)
+      dy = srect.bottom() - frame.rect.height() + 1;
+
+    srect = screen->getRect(); // now get the full screen
+
+    dleft = std::abs(wleft - srect.left()),
+      dright = std::abs(wright - srect.right()),
+      dtop = std::abs(wtop - srect.top()),
+      dbottom = std::abs(wbottom - srect.bottom());
+
+    // snap left?
+    if (dleft < snap_distance && dleft < dright)
+      dx = srect.left();
+    // snap right?
+    else if (dright < snap_distance && dright < dleft)
+      dx = srect.right() - frame.rect.width() + 1;
+
+    // snap top?
+    if (dtop < snap_distance && dtop < dbottom)
+      dy = srect.top();
+    // snap bottom?
+    else if (dbottom < snap_distance && dbottom < dtop)
+      dy = srect.bottom() - frame.rect.height() + 1;
+  }
+
+  if (screen->doOpaqueMove()) {
+    configure(dx, dy, frame.rect.width(), frame.rect.height());
+  } else {
+    XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                   screen->getOpGC(),
+                   frame.changing.x(),
+                   frame.changing.y(),
+                   frame.changing.width() - 1,
+                   frame.changing.height() - 1);
+
+    frame.changing.setPos(dx, dy);
+
+    XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                   screen->getOpGC(),
+                   frame.changing.x(),
+                   frame.changing.y(),
+                   frame.changing.width() - 1,
+                   frame.changing.height() - 1);
+  }
+
+  screen->showPosition(dx, dy);
+}
+
+
+void BlackboxWindow::endMove(void) {
+  assert(flags.moving);
+  assert(blackbox->getChangingWindow() == this);
+
+  flags.moving = False;
+  blackbox->setChangingWindow(0);
+
+  if (! screen->doOpaqueMove()) {
+    /* when drawing the rubber band, we need to make sure we only draw inside
+     * the frame... frame.changing_* contain the new coords for the window,
+     * so we need to subtract 1 from changing_w/changing_h every where we
+     * draw the rubber band (for both moving and resizing)
+     */
     XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
                    screen->getOpGC(), frame.changing.x(), frame.changing.y(),
                    frame.changing.width() - 1, frame.changing.height() - 1);
-    XUngrabServer(blackbox->getXDisplay());
+      XUngrabServer(blackbox->getXDisplay());
+  
+      configure(frame.changing.x(), frame.changing.y(),
+                frame.changing.width(), frame.changing.height());
+  } else {
+    configure(frame.rect.x(), frame.rect.y(),
+              frame.rect.width(), frame.rect.height());
+  }
+  screen->hideGeometry();
 
-    screen->hideGeometry();
+  XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
 
-    constrain((re->window == frame.left_grip) ? TopRight : TopLeft);
+  // if there are any left over motions from the move, drop them now
+  XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
+  XEvent e;
+  while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
+                                MotionNotify, &e));
+}
 
-    // unset maximized state when resized after fully maximized
-    if (flags.maximized == 1)
-      maximize(0);
-    flags.resizing = False;
-    configure(frame.changing.x(), frame.changing.y(),
-              frame.changing.width(), frame.changing.height());
 
-    XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
-  } else if (re->window == frame.window) {
-    if (re->button == 2 && re->state == Mod1Mask)
-      XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
+void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
+  assert(! (flags.resizing || flags.moving));
+
+  /*
+    Only one window can be moved/resized at a time. If another window is already
+    being moved or resized, then stop it before whating to work with this one.
+  */
+  BlackboxWindow *changing = blackbox->getChangingWindow();
+  if (changing && changing != this) {
+    if (changing->flags.moving)
+      changing->endMove();
+    else // if (changing->flags.resizing)
+      changing->endResize();
   }
+
+  resize_dir = dir;
+
+  Cursor cursor;
+  Corner anchor;
+  
+  switch (resize_dir) {
+  case BottomLeft:
+    anchor = TopRight;
+    cursor = blackbox->getLowerLeftAngleCursor();
+    break;
+
+  case BottomRight:
+    anchor = TopLeft;
+    cursor = blackbox->getLowerRightAngleCursor();
+    break;
+
+  case TopLeft:
+    anchor = BottomRight;
+    cursor = blackbox->getUpperLeftAngleCursor();
+    break;
+
+  case TopRight:
+    anchor = BottomLeft;
+    cursor = blackbox->getUpperRightAngleCursor();
+    break;
+
+  default:
+    assert(false); // unhandled Corner
+  }
+  
+  XGrabServer(blackbox->getXDisplay());
+  XGrabPointer(blackbox->getXDisplay(), frame.window, False,
+               PointerMotionMask | ButtonReleaseMask,
+               GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
+
+  flags.resizing = True;
+  blackbox->setChangingWindow(this);
+
+  int gw, gh;
+  frame.changing = frame.rect;
+
+  constrain(anchor,  &gw, &gh);
+
+  XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
+                 frame.changing.width() - 1, frame.changing.height() - 1);
+
+  screen->showGeometry(gw, gh);
+  
+  frame.grab_x = x_root;
+  frame.grab_y = y_root;
 }
 
 
-void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) {
-  if (! flags.resizing && (me->state & Button1Mask) &&
-      (functions & Func_Move) &&
-      (frame.title == me->window || frame.label == me->window ||
-       frame.handle == me->window || frame.window == me->window)) {
-    if (! flags.moving) {
-      XGrabPointer(blackbox->getXDisplay(), me->window, False,
-                   Button1MotionMask | ButtonReleaseMask,
-                   GrabModeAsync, GrabModeAsync,
-                   None, blackbox->getMoveCursor(), CurrentTime);
-
-      if (windowmenu && windowmenu->isVisible())
-        windowmenu->hide();
+void BlackboxWindow::doResize(int x_root, int y_root) {
+  assert(flags.resizing);
+  assert(blackbox->getChangingWindow() == this);
 
-      flags.moving = True;
+  XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
+                 frame.changing.width() - 1, frame.changing.height() - 1);
 
-      if (! screen->doOpaqueMove()) {
-        XGrabServer(blackbox->getXDisplay());
+  int gw, gh;
+  Corner anchor;
 
-        frame.changing = frame.rect;
-        screen->showPosition(frame.changing.x(), frame.changing.y());
+  switch (resize_dir) {
+    case BottomLeft:
+      anchor = TopRight;
+      frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+                             frame.rect.height() + (y_root - frame.grab_y));
+      break;
+    case BottomRight:
+      anchor = TopLeft;
+      frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+                             frame.rect.height() + (y_root - frame.grab_y));
+      break;
+    case TopLeft:
+      anchor = BottomRight;
+      frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
+                             frame.rect.height() - (y_root - frame.grab_y));
+      break;
+    case TopRight:
+      anchor = BottomLeft;
+      frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
+                             frame.rect.height() - (y_root - frame.grab_y));
+      break;
 
-        XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                       screen->getOpGC(),
-                       frame.changing.x(),
-                       frame.changing.y(),
-                       frame.changing.width() - 1,
-                       frame.changing.height() - 1);
-      }
-    } else {
-      int dx = me->x_root - frame.grab_x, dy = me->y_root - frame.grab_y;
-      dx -= frame.border_w;
-      dy -= frame.border_w;
-
-      const int snap_distance = screen->getEdgeSnapThreshold();
-
-      if (snap_distance) {
-        // window corners
-        const int wleft = dx,
-                 wright = dx + frame.rect.width() - 1,
-                   wtop = dy,
-                wbottom = dy + frame.rect.height() - 1;
-
-        // Maybe this should be saved in the class, and set in the setWorkspace
-        // function!!
-        Workspace *w = screen->getWorkspace(getWorkspaceNumber());
-        assert(w);
-
-        if (screen->getWindowToWindowSnap()) {
-          // try snap to another window
-          for (unsigned int i = 0, c = w->getCount(); i < c; ++i) {
-            BlackboxWindow *snapwin = w->getWindow(i);
-            if (snapwin == this)
-              continue;   // don't snap to self
-
-            const Rect &winrect = snapwin->frameRect();
-            int dleft = std::abs(wright - winrect.left()),
-               dright = std::abs(wleft - winrect.right()),
-                 dtop = std::abs(wbottom - winrect.top()),
-              dbottom = std::abs(wtop - winrect.bottom());
-
-            // snap top of other window?
-            if (dtop < snap_distance && dtop <= dbottom) {
-              dy = winrect.top() - frame.rect.height();
-
-              if (screen->getWindowCornerSnap()) {
-                // try corner-snap to its other sides
-                dleft = std::abs(wleft - winrect.left());
-                dright = std::abs(wright - winrect.right());
-                if (dleft < snap_distance && dleft <= dright)
-                  dx = winrect.left();
-                else if (dright < snap_distance)
-                  dx = winrect.right() - frame.rect.width() + 1;
-              }
-
-              continue;
-            }
-            // snap bottom of other window?
-            else if (dbottom < snap_distance) {
-              dy = winrect.bottom() + 1;
-
-              if (screen->getWindowCornerSnap()) {
-                // try corner-snap to its other sides
-                dleft = std::abs(wleft - winrect.left());
-                dright = std::abs(wright - winrect.right());
-                if (dleft < snap_distance && dleft <= dright)
-                  dx = winrect.left();
-                else if (dright < snap_distance)
-                  dx = winrect.right() - frame.rect.width() + 1;
-              }
-
-              continue;
-            }
-
-            // snap left of other window?
-            if (dleft < snap_distance && dleft <= dright) {
-              dx = winrect.left() - frame.rect.width();
-
-              if (screen->getWindowCornerSnap()) {
-                // try corner-snap to its other sides
-                dtop = std::abs(wtop - winrect.top());
-                dbottom = std::abs(wbottom - winrect.bottom());
-                if (dtop < snap_distance && dtop <= dbottom)
-                  dy = winrect.top();
-                else if (dbottom < snap_distance)
-                  dy = winrect.bottom() - frame.rect.height() + 1;
-              }
-
-              continue;
-            }
-            // snap right of other window?
-            else if (dright < snap_distance) {
-              dx = winrect.right() + 1;
-
-              if (screen->getWindowCornerSnap()) {
-                // try corner-snap to its other sides
-                dtop = std::abs(wtop - winrect.top());
-                dbottom = std::abs(wbottom - winrect.bottom());
-                if (dtop < snap_distance && dtop <= dbottom)
-                  dy = winrect.top();
-                else if (dbottom < snap_distance)
-                  dy = winrect.bottom() - frame.rect.height() + 1;
-              }
-
-              continue;
-            }
-          }
-        }
-                
-        // try snap to the screen's available area
-        Rect srect = screen->availableArea();
-
-        int dleft = std::abs(wleft - srect.left()),
-           dright = std::abs(wright - srect.right()),
-             dtop = std::abs(wtop - srect.top()),
-          dbottom = std::abs(wbottom - srect.bottom());
-
-        // snap left?
-        if (dleft < snap_distance && dleft <= dright)
-          dx = srect.left();
-        // snap right?
-        else if (dright < snap_distance)
-          dx = srect.right() - frame.rect.width() + 1;
-
-        // snap top?
-        if (dtop < snap_distance && dtop <= dbottom)
-          dy = srect.top();
-        // snap bottom?
-        else if (dbottom < snap_distance)
-          dy = srect.bottom() - frame.rect.height() + 1;
-
-        if (! screen->doFullMax()) {
-          srect = screen->getRect(); // now get the full screen
-
-          dleft = std::abs(wleft - srect.left()),
-          dright = std::abs(wright - srect.right()),
-          dtop = std::abs(wtop - srect.top()),
-          dbottom = std::abs(wbottom - srect.bottom());
-
-          // snap left?
-          if (dleft < snap_distance && dleft <= dright)
-            dx = srect.left();
-          // snap right?
-          else if (dright < snap_distance)
-            dx = srect.right() - frame.rect.width() + 1;
-
-          // snap top?
-          if (dtop < snap_distance && dtop <= dbottom)
-            dy = srect.top();
-          // snap bottom?
-          else if (dbottom < snap_distance)
-            dy = srect.bottom() - frame.rect.height() + 1;
-        }
-      }
+    default:
+      assert(false); // unhandled Corner
+  }
+  
+  constrain(anchor, &gw, &gh);
 
-      if (screen->doOpaqueMove()) {
-        configure(dx, dy, frame.rect.width(), frame.rect.height());
-      } else {
-        XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                       screen->getOpGC(),
-                       frame.changing.x(),
-                       frame.changing.y(),
-                       frame.changing.width() - 1,
-                       frame.changing.height() - 1);
-
-        frame.changing.setPos(dx, dy);
-
-        XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                       screen->getOpGC(),
-                       frame.changing.x(),
-                       frame.changing.y(),
-                       frame.changing.width() - 1,
-                       frame.changing.height() - 1);
-      }
+  XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
+                 frame.changing.width() - 1, frame.changing.height() - 1);
 
-      screen->showPosition(dx, dy);
-    }
-  } else if ((functions & Func_Resize) &&
-             (((me->state & Button1Mask) &&
-               (me->window == frame.right_grip ||
-                me->window == frame.left_grip)) ||
-              (me->state & (Mod1Mask | Button3Mask) &&
-               me->window == frame.window))) {
-    bool left = (me->window == frame.left_grip);
-
-    if (! flags.resizing) {
-      XGrabServer(blackbox->getXDisplay());
-      XGrabPointer(blackbox->getXDisplay(), me->window, False,
-                   ButtonMotionMask | ButtonReleaseMask,
-                   GrabModeAsync, GrabModeAsync, None,
-                   ((left) ? blackbox->getLowerLeftAngleCursor() :
-                    blackbox->getLowerRightAngleCursor()),
-                   CurrentTime);
-
-      flags.resizing = True;
-
-      int gw, gh;
-      frame.grab_x = me->x;
-      frame.grab_y = me->y;
-      frame.changing = frame.rect;
-
-      constrain((left) ? TopRight : TopLeft, &gw, &gh);
-
-      XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                     screen->getOpGC(), frame.changing.x(), frame.changing.y(),
-                     frame.changing.width() - 1, frame.changing.height() - 1);
-
-      screen->showGeometry(gw, gh);
-    } else {
-      XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                     screen->getOpGC(), frame.changing.x(), frame.changing.y(),
-                     frame.changing.width() - 1, frame.changing.height() - 1);
+  screen->showGeometry(gw, gh);
+}
 
-      int gw, gh;
 
-      Corner anchor;
+void BlackboxWindow::endResize(void) {
+  assert(flags.resizing);
+  assert(blackbox->getChangingWindow() == this);
 
-      if (left) {
-        anchor = TopRight;
-        frame.changing.setCoords(me->x_root - frame.grab_x, frame.rect.top(),
-                                 frame.rect.right(), frame.rect.bottom());
-        frame.changing.setHeight(frame.rect.height() + (me->y - frame.grab_y));
-      } else {
-        anchor = TopLeft;
-        frame.changing.setSize(frame.rect.width() + (me->x - frame.grab_x),
-                               frame.rect.height() + (me->y - frame.grab_y));
-      }
+  XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
+                 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
+                 frame.changing.width() - 1, frame.changing.height() - 1);
+  XUngrabServer(blackbox->getXDisplay());
 
-      constrain(anchor, &gw, &gh);
+  // unset maximized state after resized when fully maximized
+  if (flags.maximized == 1)
+    maximize(0);
+  
+  flags.resizing = False;
+  blackbox->setChangingWindow(0);
 
-      XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
-                     screen->getOpGC(), frame.changing.x(), frame.changing.y(),
-                     frame.changing.width() - 1, frame.changing.height() - 1);
+  configure(frame.changing.x(), frame.changing.y(),
+            frame.changing.width(), frame.changing.height());
+  screen->hideGeometry();
 
-      screen->showGeometry(gw, gh);
+  XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
+  
+  // if there are any left over motions from the resize, drop them now
+  XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
+  XEvent e;
+  while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
+                                MotionNotify, &e));
+}
+
+
+void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) {
+  if (flags.moving) {
+    doMove(me->x_root, me->y_root);
+  } else if (flags.resizing) {
+    doResize(me->x_root, me->y_root);
+  } else {
+    if (! flags.resizing && (me->state & Button1Mask) &&
+        (functions & Func_Move) &&
+        (frame.title == me->window || frame.label == me->window ||
+         frame.handle == me->window || frame.window == me->window)) {
+      beginMove(me->x_root, me->y_root);
+    } else if ((functions & Func_Resize) &&
+               (((me->state & Button1Mask) &&
+                 (me->window == frame.right_grip ||
+                  me->window == frame.left_grip)) ||
+                (me->state & (Mod1Mask | Button3Mask) &&
+                 me->window == frame.window))) {
+      beginResize(me->x_root, me->y_root,
+                  (me->window == frame.left_grip) ? BottomLeft : BottomRight);
     }
   }
 }
@@ -3082,16 +3373,29 @@ void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) {
                            frame.changing.bottom() + frame.margin.bottom);
 
   // move frame.changing to the specified anchor
+  int dx = 0,
+      dy = 0;
   switch (anchor) {
   case TopLeft:
-    // nothing to do
     break;
 
   case TopRight:
-    int dx = frame.rect.right() - frame.changing.right();
-    frame.changing.setPos(frame.changing.x() + dx, frame.changing.y());
+    dx = frame.rect.right() - frame.changing.right();
     break;
+
+  case BottomLeft:
+    dy = frame.rect.bottom() - frame.changing.bottom();
+    break;
+
+  case BottomRight:
+    dx = frame.rect.right() - frame.changing.right();
+    dy = frame.rect.bottom() - frame.changing.bottom();
+    break;
+
+  default:
+    assert(false);  // unhandled corner
   }
+  frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
 }
 
 
index 038a58affc578613e8ab3cdfbe6c28d0942d70b2..aab1a412778d049e1ea9d7296316d6c42ff939ce 100644 (file)
@@ -108,6 +108,20 @@ public:
                     Decor_Close    = (1l << 5) };
   typedef unsigned char DecorationFlags;
 
+  enum WindowType { Type_Desktop,
+                    Type_Dock,
+                    Type_Toolbar,
+                    Type_Menu,
+                    Type_Utility,
+                    Type_Splash,
+                    Type_Dialog,
+                    Type_Normal };
+
+  enum Corner { TopLeft,
+                TopRight,
+                BottomLeft,
+                BottomRight };
+
 private:
   Blackbox *blackbox;
   BScreen *screen;
@@ -132,8 +146,11 @@ private:
       visible,               // is visible?
       iconic,                // is iconified?
       focused,               // has focus?
-      stuck,                 // is omnipresent
+      stuck,                 // is omnipresent?
       modal,                 // is modal? (must be dismissed to continue)
+      skip_taskbar,          // skipped by taskbars?
+      skip_pager,            // skipped by pagers?
+      fullscreen,            // a fullscreen window?
       send_focus_message,    // should we send focus messages to our client?
       shaped;                // does the frame use the shape extension?
     unsigned int maximized;  // maximize is special, the number corresponds
@@ -151,6 +168,7 @@ private:
     std::string title, icon_title;
 
     Rect rect;
+    Strut strut;
 
     int old_bw;                       // client's borderwidth
 
@@ -173,6 +191,8 @@ private:
    * the menu is not really decor, but it goes hand in hand with the decor
    */
   DecorationFlags decorations;
+  Corner resize_dir;
+  WindowType window_type;
 
   /*
    * client window = the application's window
@@ -234,14 +254,18 @@ private:
   Window createToplevelWindow();
   Window createChildWindow(Window parent, Cursor = None);
 
+  void getWindowType(void);
+  void updateStrut(void);
   void getWMName(void);
   void getWMIconName(void);
   void getWMNormalHints(void);
   void getWMProtocols(void);
   void getWMHints(void);
+  void getNetWMHints(void);
   void getMWMHints(void);
   bool getBlackboxHints(void);
   void getTransientInfo(void);
+  bool isKDESystrayWindow(void);
   void setNetWMAttributes(void);
   void associateClientWindow(void);
   void decorate(void);
@@ -265,10 +289,14 @@ private:
   void redrawMaximizeButton(bool pressed);
   void restoreGravity(void);
   void setGravityOffsets(void);
+  void setAllowedActions(void);
   void setState(unsigned long new_state);
   void upsize(void);
+  void doMove(int x_root, int y_root);
+  void endMove(void);
+  void doResize(int x_root, int y_root);
+  void endResize(void);
 
-  enum Corner { TopLeft, TopRight };
   void constrain(Corner anchor, int *pw = 0, int *ph = 0);
 
 public:
@@ -281,11 +309,16 @@ public:
   inline bool isIconic(void) const { return flags.iconic; }
   inline bool isShaded(void) const { return flags.shaded; }
   inline bool isMaximized(void) const { return flags.maximized; }
+  inline bool isMaximizedHoriz(void) const { return flags.maximized == 3; }
+  inline bool isMaximizedVert(void) const { return flags.maximized == 2; }
+  inline bool isMaximizedFull(void) const { return flags.maximized == 1; }
   inline bool isStuck(void) const { return flags.stuck; }
+  inline bool isModal(void) const { return flags.modal; }
   inline bool isIconifiable(void) const { return functions & Func_Iconify; }
   inline bool isMaximizable(void) const { return functions & Func_Maximize; }
   inline bool isResizable(void) const { return functions & Func_Resize; }
   inline bool isClosable(void) const { return functions & Func_Close; }
+  inline bool isDesktop(void) const { return window_type == Type_Desktop; }
 
   inline bool hasTitlebar(void) const { return decorations & Decor_Titlebar; }
 
@@ -321,6 +354,19 @@ public:
   bool validateClient(void) const;
   bool setInputFocus(void);
 
+  // none of these are used by the window manager, they are here to persist
+  // them properly in the window's netwm state property.
+  inline bool skipTaskbar(void) const { return flags.skip_taskbar; }
+  inline void setSkipTaskbar(const bool s) { flags.skip_taskbar = s; }
+  inline bool skipPager(void) const { return flags.skip_pager; }
+  inline void setSkipPager(const bool s) { flags.skip_pager = s; }
+  inline bool isFullscreen(void) const { return flags.fullscreen; }
+  inline void setFullscreen(const bool f) { flags.fullscreen = f; }
+
+  inline void setModal(const bool m) { flags.modal = m; }
+
+  void beginMove(int x_root, int y_root);
+  void beginResize(int x_root, int y_root, Corner dir);
   void setFocusFlag(bool focus);
   void iconify(void);
   void deiconify(bool reassoc = True, bool raise = True);
@@ -331,7 +377,6 @@ public:
   void remaximize(void);
   void shade(void);
   void stick(void);
-  void unstick(void);
   void reconfigure(void);
   void updateFocusModel(void);
   void installColormap(bool install);
index 1d07a5bea12daa5db632dc0b88df2d931f646ac3..50a9f4fbca28145bb46dd882c589d41989fd8543 100644 (file)
@@ -307,6 +307,7 @@ void Workspace::lowerWindow(BlackboxWindow *w) {
   XLowerWindow(screen->getBaseDisplay()->getXDisplay(), stack_vector.front());
   XRestackWindows(screen->getBaseDisplay()->getXDisplay(),
                   &stack_vector[0], stack_vector.size());
+  screen->lowerDesktops();
 }
 
 
@@ -377,6 +378,14 @@ unsigned int Workspace::getCount(void) const {
 }
 
 
+void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
+  BlackboxWindowList::const_iterator it = stackingList.begin();
+  const BlackboxWindowList::const_iterator end = stackingList.end();
+  for (; it != end; ++it)
+    stack_order.push_back(*it);
+}
+  
+
 bool Workspace::isCurrent(void) const {
   return (id == screen->getCurrentWorkspaceID());
 }
index dadb0dd0c50638c2dd26c467e67058a72184e5b5..33f17b3dec9b65a6ee9e040d2d6517d37fb2e6fc 100644 (file)
@@ -93,6 +93,7 @@ public:
   void addWindow(BlackboxWindow *w, bool place = False);
   unsigned int removeWindow(BlackboxWindow *w);
   unsigned int getCount(void) const;
+  void appendStackOrder(BlackboxWindowList &stack_order) const;
 
   void showAll(void);
   void hideAll(void);
index 649f118f7b7395a9fb7997210f2d63834e3d6100..545739ab0390f5cbb659180717ff2c7ebbe14ab9 100644 (file)
 
 #include "../config.h"
 
+#include <assert.h>
+
 #include "XAtom.hh"
-#include "blackbox.hh"
 #include "Screen.hh"
 #include "Util.hh"
 
-XAtom::XAtom(Blackbox *bb) {
-  _display = bb->getXDisplay();
+XAtom::XAtom(Display *d) {
+  _display = d;
 
   // make sure asserts fire if there is a problem
-  memset(_atoms, sizeof(_atoms), 0);
+  memset(_atoms, 0, sizeof(_atoms));
 
   _atoms[cardinal] = XA_CARDINAL;
   _atoms[window] = XA_WINDOW;
@@ -49,6 +50,8 @@ XAtom::XAtom(Blackbox *bb) {
   _atoms[wm_change_state] = create("WM_CHANGE_STATE");
   _atoms[wm_delete_window] = create("WM_DELETE_WINDOW");
   _atoms[wm_take_focus] = create("WM_TAKE_FOCUS");
+  _atoms[wm_name] = create("WM_NAME");
+  _atoms[wm_icon_name] = create("WM_ICON_NAME");
   _atoms[motif_wm_hints] = create("_MOTIF_WM_HINTS");
   _atoms[blackbox_hints] = create("_BLACKBOX_HINTS");
   _atoms[blackbox_attributes] = create("_BLACKBOX_ATTRIBUTES");
@@ -84,23 +87,69 @@ XAtom::XAtom(Blackbox *bb) {
   _atoms[net_active_window] = create("_NET_ACTIVE_WINDOW");
   _atoms[net_workarea] = create("_NET_WORKAREA");
   _atoms[net_supporting_wm_check] = create("_NET_SUPPORTING_WM_CHECK");
-  _atoms[net_virtual_roots] = create("_NET_VIRTUAL_ROOTS");
+//  _atoms[net_virtual_roots] = create("_NET_VIRTUAL_ROOTS");
 
   _atoms[net_close_window] = create("_NET_CLOSE_WINDOW");
   _atoms[net_wm_moveresize] = create("_NET_WM_MOVERESIZE");
 
-  _atoms[net_properties] = create("_NET_PROPERTIES");
+//  _atoms[net_properties] = create("_NET_PROPERTIES");
   _atoms[net_wm_name] = create("_NET_WM_NAME");
+  _atoms[net_wm_visible_name] = create("_NET_WM_VISIBLE_NAME");
+  _atoms[net_wm_icon_name] = create("_NET_WM_ICON_NAME");
+  _atoms[net_wm_visible_icon_name] = create("_NET_WM_VISIBLE_ICON_NAME");
   _atoms[net_wm_desktop] = create("_NET_WM_DESKTOP");
   _atoms[net_wm_window_type] = create("_NET_WM_WINDOW_TYPE");
   _atoms[net_wm_state] = create("_NET_WM_STATE");
   _atoms[net_wm_strut] = create("_NET_WM_STRUT");
-  _atoms[net_wm_icon_geometry] = create("_NET_WM_ICON_GEOMETRY");
-  _atoms[net_wm_icon] = create("_NET_WM_ICON");
-  _atoms[net_wm_pid] = create("_NET_WM_PID");
-  _atoms[net_wm_handled_icons] = create("_NET_WM_HANDLED_ICONS");
+//  _atoms[net_wm_icon_geometry] = create("_NET_WM_ICON_GEOMETRY");
+//  _atoms[net_wm_icon] = create("_NET_WM_ICON");
+//  _atoms[net_wm_pid] = create("_NET_WM_PID");
+//  _atoms[net_wm_handled_icons] = create("_NET_WM_HANDLED_ICONS");
+  _atoms[net_wm_allowed_actions] = create("_NET_WM_ALLOWED_ACTIONS");
 
-  _atoms[net_wm_ping] = create("_NET_WM_PING");
+//  _atoms[net_wm_ping] = create("_NET_WM_PING");
+  
+  _atoms[net_wm_window_type_desktop] = create("_NET_WM_WINDOW_TYPE_DESKTOP");
+  _atoms[net_wm_window_type_dock] = create("_NET_WM_WINDOW_TYPE_DOCK");
+  _atoms[net_wm_window_type_toolbar] = create("_NET_WM_WINDOW_TYPE_TOOLBAR");
+  _atoms[net_wm_window_type_menu] = create("_NET_WM_WINDOW_TYPE_MENU");
+  _atoms[net_wm_window_type_utility] = create("_NET_WM_WINDOW_TYPE_UTILITY");
+  _atoms[net_wm_window_type_splash] = create("_NET_WM_WINDOW_TYPE_SPLASH");
+  _atoms[net_wm_window_type_dialog] = create("_NET_WM_WINDOW_TYPE_DIALOG");
+  _atoms[net_wm_window_type_normal] = create("_NET_WM_WINDOW_TYPE_NORMAL");
+
+  _atoms[net_wm_moveresize_size_topleft] =
+    create("_NET_WM_MOVERESIZE_SIZE_TOPLEFT");
+  _atoms[net_wm_moveresize_size_topright] =
+    create("_NET_WM_MOVERESIZE_SIZE_TOPRIGHT");
+  _atoms[net_wm_moveresize_size_bottomleft] =
+    create("_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT");
+  _atoms[net_wm_moveresize_size_bottomright] =
+    create("_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT");
+  _atoms[net_wm_moveresize_move] =
+    create("_NET_WM_MOVERESIZE_MOVE");
+  _atoms[net_wm_action_move] = create("_NET_WM_ACTION_MOVE");
+  _atoms[net_wm_action_resize] = create("_NET_WM_ACTION_RESIZE");
+  _atoms[net_wm_action_shade] = create("_NET_WM_ACTION_SHADE");
+  _atoms[net_wm_action_maximize_horz] = create("_NET_WM_ACTION_MAXIMIZE_HORZ");
+  _atoms[net_wm_action_maximize_vert] = create("_NET_WM_ACTION_MAXIMIZE_VERT");
+  _atoms[net_wm_action_change_desktop] =
+    create("_NET_WM_ACTION_CHANGE_DESKTOP");
+  _atoms[net_wm_action_close] = create("_NET_WM_ACTION_CLOSE");
+    
+  _atoms[net_wm_state_modal] = create("_NET_WM_STATE_MODAL");
+  _atoms[net_wm_state_maximized_vert] = create("_NET_WM_STATE_MAXIMIZED_VERT");
+  _atoms[net_wm_state_maximized_horz] = create("_NET_WM_STATE_MAXIMIZED_HORZ");
+  _atoms[net_wm_state_shaded] = create("_NET_WM_STATE_SHADED");
+  _atoms[net_wm_state_skip_taskbar] = create("_NET_WM_STATE_SKIP_TASKBAR");
+  _atoms[net_wm_state_skip_pager] = create("_NET_WM_STATE_SKIP_PAGER");
+  _atoms[net_wm_state_hidden] = create("_NET_WM_STATE_HIDDEN");
+  _atoms[net_wm_state_fullscreen] = create("_NET_WM_STATE_FULLSCREEN");
+  
+  _atoms[kde_net_system_tray_windows] = create("_KDE_NET_SYSTEM_TRAY_WINDOWS");
+  _atoms[kde_net_wm_system_tray_window_for] =
+    create("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
 }
 
 
@@ -148,7 +197,53 @@ void XAtom::setSupported(const ScreenInfo *screen) {
 
   Atom supported[] = {
     _atoms[net_current_desktop],
-    _atoms[net_number_of_desktops]
+    _atoms[net_number_of_desktops],
+    _atoms[net_desktop_geometry],
+    _atoms[net_desktop_viewport],
+    _atoms[net_active_window],
+    _atoms[net_workarea],
+    _atoms[net_client_list],
+    _atoms[net_client_list_stacking],
+    _atoms[net_desktop_names],
+    _atoms[net_close_window],
+    _atoms[net_wm_name],
+    _atoms[net_wm_visible_name],
+    _atoms[net_wm_icon_name],
+    _atoms[net_wm_visible_icon_name],
+    _atoms[net_wm_desktop],
+    _atoms[net_wm_strut],
+    _atoms[net_wm_window_type],
+    _atoms[net_wm_window_type_desktop],
+    _atoms[net_wm_window_type_dock],
+    _atoms[net_wm_window_type_toolbar],
+    _atoms[net_wm_window_type_menu],
+    _atoms[net_wm_window_type_utility],
+    _atoms[net_wm_window_type_splash],
+    _atoms[net_wm_window_type_dialog],
+    _atoms[net_wm_window_type_normal],
+    _atoms[net_wm_moveresize],
+    _atoms[net_wm_moveresize_size_topleft],
+    _atoms[net_wm_moveresize_size_topright],
+    _atoms[net_wm_moveresize_size_bottomleft],
+    _atoms[net_wm_moveresize_size_bottomright],
+    _atoms[net_wm_moveresize_move],
+    _atoms[net_wm_allowed_actions],
+    _atoms[net_wm_action_move],
+    _atoms[net_wm_action_resize],
+    _atoms[net_wm_action_shade],
+    _atoms[net_wm_action_maximize_horz],
+    _atoms[net_wm_action_maximize_vert],
+    _atoms[net_wm_action_change_desktop],
+    _atoms[net_wm_action_close],
+    _atoms[net_wm_state],
+    _atoms[net_wm_state_modal],
+    _atoms[net_wm_state_maximized_vert],
+    _atoms[net_wm_state_maximized_horz],
+    _atoms[net_wm_state_shaded],
+    _atoms[net_wm_state_skip_taskbar],
+    _atoms[net_wm_state_skip_pager],
+    _atoms[net_wm_state_hidden],
+    _atoms[net_wm_state_fullscreen],
   };
   const int num_supported = sizeof(supported)/sizeof(Atom);
 
@@ -165,12 +260,11 @@ void XAtom::setValue(Window win, Atom atom, Atom type,
                      unsigned char* data, int size, int nelements,
                      bool append) const {
   assert(win != None); assert(atom != None); assert(type != None);
-  assert(data != (unsigned char *) 0);
+  assert(nelements == 0 || (nelements > 0 && data != (unsigned char *) 0));
   assert(size == 8 || size == 16 || size == 32);
-  assert(nelements > 0);
   XChangeProperty(_display, win, atom, type, size,
                   (append ? PropModeAppend : PropModeReplace),
-                  data, nelements);                  
+                  data, nelements);
 }
 
 
@@ -205,24 +299,44 @@ void XAtom::setValue(Window win, Atoms atom, StringType type,
                      const std::string &value) const {
   assert(atom >= 0 && atom < NUM_ATOMS);
   assert(type >= 0 && type < NUM_STRING_TYPE);
-  assert(win != None); assert(_atoms[atom] != None);
+  
+  Atom t;
+  switch (type) {
+  case ansi: t = _atoms[string]; break;
+  case utf8: t = _atoms[utf8_string]; break;
+  default: assert(false); // unhandled StringType
+  }
+  setValue(win, _atoms[atom], t,
+           reinterpret_cast<unsigned char *>(const_cast<char *>(value.c_str())),
+           8, value.size() + 1, false); // add 1 to the size to include the null
+}
+
+
+/*
+ * Set an array of string property values on a window.
+ */
+void XAtom::setValue(Window win, Atoms atom, StringType type,
+                     const StringVect &strings) const {
+  assert(atom >= 0 && atom < NUM_ATOMS);
+  assert(type >= 0 && type < NUM_STRING_TYPE);
 
-  const char *c = value.c_str();
-  XTextProperty textprop;
-  if (Success != XmbTextListToTextProperty(_display, const_cast<char**>(&c), 1,
-                                           type == ansi ? XStringStyle :
-#ifdef X_HAVE_UTF8_STRING
-                                           XUTF8StringStyle,
-#else
-                                           XCompoundTextStyle,
-#endif
-                                           &textprop)) {
-    return;
+  Atom t;
+  switch (type) {
+  case ansi: t = _atoms[string]; break;
+  case utf8: t = _atoms[utf8_string]; break;
+  default: assert(false); // unhandled StringType
   }
-  
-  XSetTextProperty(_display, win, &textprop, _atoms[atom]);
 
-  XFree(textprop.value);
+  std::string value;
+
+  StringVect::const_iterator it = strings.begin();
+  const StringVect::const_iterator end = strings.end();
+  for (; it != end; ++it)
+      value += *it + '\0';
+
+  setValue(win, _atoms[atom], t,
+           reinterpret_cast<unsigned char *>(const_cast<char *>(value.c_str())),
+           8, value.size(), false);
 }
 
 
@@ -238,23 +352,25 @@ bool XAtom::getValue(Window win, Atom atom, Atom type,
                      int size) const {
   assert(win != None); assert(atom != None); assert(type != None);
   assert(size == 8 || size == 16 || size == 32);
+  assert(nelements > 0);
   unsigned char *c_val;        // value alloc'd with c malloc
   Atom ret_type;
   int ret_size;
   unsigned long ret_bytes;
+  const unsigned long maxread = nelements;
   // try get the first element
   XGetWindowProperty(_display, win, atom, 0l, 1l, False, AnyPropertyType,
                      &ret_type, &ret_size, &nelements, &ret_bytes, &c_val);
-  if (ret_type == None)
-    // the property does not exist on the window
+  if (ret_type == None || nelements < 1)
+    // the property does not exist on the window or is empty
     return false;
   if (ret_type != type || ret_size != size) {
     // wrong data in property
     XFree(c_val);
     return false;
   }
-  // the data is correct, now, is there more than 1 element?
-  if (ret_bytes == 0) {
+  // the data is correct, now, is there more elements left?
+  if (ret_bytes == 0 || maxread <= nelements) {
     // we got the whole property's value
     *value = new unsigned char[nelements * size/8 + 1];
     memcpy(*value, c_val, nelements * size/8 + 1);
@@ -262,10 +378,12 @@ bool XAtom::getValue(Window win, Atom atom, Atom type,
     return true;    
   }
   // get the entire property since it is larger than one long
-  free(c_val);
+  XFree(c_val);
   // the number of longs that need to be retreived to get the property's entire
   // value. The last + 1 is the first long that we retrieved above.
-  const int remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
+  int remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
+  if (remain > size/8 * (signed)maxread) // dont get more than the max
+    remain = size/8 * (signed)maxread;
   XGetWindowProperty(_display, win, atom, 0l, remain, False, type, &ret_type,
                      &ret_size, &nelements, &ret_bytes, &c_val);
   assert(ret_bytes == 0);
@@ -289,47 +407,79 @@ bool XAtom::getValue(Window win, Atoms atom, Atoms type,
 }
 
 
+/*
+ * Gets a single 32-bit property's value from a window.
+ */
+bool XAtom::getValue(Window win, Atoms atom, Atoms type,
+                     unsigned long &value) const {
+  assert(atom >= 0 && atom < NUM_ATOMS);
+  assert(type >= 0 && type < NUM_ATOMS);
+  unsigned long *temp;
+  unsigned long num = 1;
+  if (! getValue(win, _atoms[atom], _atoms[type], num,
+                 reinterpret_cast<unsigned char **>(&temp), 32))
+    return false;
+  value = temp[0];
+  delete [] temp;
+  return true;
+}
+
+
 /*
  * Gets an string property's value from a window.
  */
 bool XAtom::getValue(Window win, Atoms atom, StringType type,
                      std::string &value) const {
+  int n = 1;
+  StringVect s;
+  if (getValue(win, atom, type, n, s)) {
+    value = s[0];
+    return true;
+  }
+  return false;
+}
+
+
+bool XAtom::getValue(Window win, Atoms atom, StringType type, int &nelements,
+                     StringVect &strings) const {
   assert(atom >= 0 && atom < NUM_ATOMS);
   assert(type >= 0 && type < NUM_STRING_TYPE);
   assert(win != None); assert(_atoms[atom] != None);
+  assert(nelements > 0);
 
-  XTextProperty textprop;
-  if (0 == XGetTextProperty(_display, win, &textprop, _atoms[atom]))
-    return false;
-
-  int ret;
-  int count;
-  char **list;
-  if (type == ansi) {
-      ret = XmbTextPropertyToTextList(_display, &textprop, &list, &count);
-  } else {
-#ifdef X_HAVE_UTF8_STRING
-    ret = Xutf8TextPropertyToTextList(_display, &textprop, &list, &count);
-#else
-    ret = XmbTextPropertyToTextList(_display, &textprop, &list, &count);
-#endif
+  Atom t;
+  switch (type) {
+  case ansi: t = _atoms[string]; break;
+  case utf8: t = _atoms[utf8_string]; break;
+  default: assert(false); // unhandled StringType
   }
-  if (ret != Success || count < 1) {
-    XFree(textprop.value);
+  
+  unsigned char *value;
+  unsigned long elements = (unsigned) -1;
+  if (!getValue(win, _atoms[atom], t, elements, &value, 8) || elements < 1)
     return false;
+
+  std::string s(reinterpret_cast<char *>(value));
+  delete [] value;
+
+  std::string::const_iterator it = s.begin(), end = s.end();
+  int num = 0;
+  while(num < nelements) {
+    std::string::const_iterator tmp = it; // current string.begin()
+    it = std::find(tmp, end, '\0');       // look for null between tmp and end
+    strings.push_back(std::string(tmp, it));   // s[tmp:it)
+    if (it == end)
+      break;
+    ++it;
+    ++num;
   }
 
-  value = list[0];
+  nelements = elements;
 
-  XFreeStringList(list);
-  XFree(textprop.value);
   return true;
 }
 
 
-
-
 /*
  * Removes a property entirely from a window.
  */
index 580b973c6e3f961e6eb3b81440c2ff48f8984008..839951a8796e088057c6380d59986116bb6cf454 100644 (file)
@@ -24,6 +24,9 @@
 
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
+
+#include <assert.h>
+
 #include <vector>
 #include <string>
 
@@ -52,6 +55,8 @@ public:
     wm_delete_window,
     wm_take_focus,
     wm_change_state,
+    wm_name,
+    wm_icon_name,
     motif_wm_hints,
     blackbox_attributes,
     blackbox_change_attributes,
@@ -85,24 +90,63 @@ public:
     net_active_window,
     net_workarea,
     net_supporting_wm_check,
-    net_virtual_roots,
+//    net_virtual_roots,
     // root window messages
     net_close_window,
     net_wm_moveresize,
     // application window properties
-    net_properties,
+//    net_properties,
     net_wm_name,
+    net_wm_visible_name,
+    net_wm_icon_name,
+    net_wm_visible_icon_name,
     net_wm_desktop,
     net_wm_window_type,
     net_wm_state,
     net_wm_strut,
-    net_wm_icon_geometry,
-    net_wm_icon,
-    net_wm_pid,
-    net_wm_handled_icons,
+//  net_wm_icon_geometry,
+//  net_wm_icon,
+//  net_wm_pid,
+//  net_wm_handled_icons,
+    net_wm_allowed_actions,
     // application protocols
-    net_wm_ping,
-
+//    net_wm_ping,
+
+    net_wm_window_type_desktop,
+    net_wm_window_type_dock,
+    net_wm_window_type_toolbar,
+    net_wm_window_type_menu,
+    net_wm_window_type_utility,
+    net_wm_window_type_splash,
+    net_wm_window_type_dialog,
+    net_wm_window_type_normal,
+
+    net_wm_moveresize_size_topleft,
+    net_wm_moveresize_size_topright,
+    net_wm_moveresize_size_bottomleft,
+    net_wm_moveresize_size_bottomright,
+    net_wm_moveresize_move,
+
+    net_wm_action_move,
+    net_wm_action_resize,
+    net_wm_action_shade,
+    net_wm_action_maximize_horz,
+    net_wm_action_maximize_vert,
+    net_wm_action_change_desktop,
+    net_wm_action_close,
+
+    net_wm_state_modal,
+    net_wm_state_maximized_vert,
+    net_wm_state_maximized_horz,
+    net_wm_state_shaded,
+    net_wm_state_skip_taskbar,
+    net_wm_state_skip_pager,
+    net_wm_state_hidden,
+    net_wm_state_fullscreen,
+
+    kde_net_system_tray_windows,
+    kde_net_wm_system_tray_window_for,
     // constant for how many atoms exist in the enumerator
     NUM_ATOMS
   };
@@ -134,7 +178,9 @@ private:
   XAtom& operator=(const XAtom&);
 
 public:
-  XAtom(Blackbox *bb);
+  typedef std::vector<std::string> StringVect;
+  
+  XAtom(Display *d);
   virtual ~XAtom();
 
   // setup support on a screen, each screen should call this once in its
@@ -146,21 +192,29 @@ public:
                 unsigned long value[], int elements) const;
   void setValue(Window win, Atoms atom, StringType type,
                 const std::string &value) const;
+  void setValue(Window win, Atoms atom, StringType type,
+                const StringVect &strings) const;
 
   // the 'value' is allocated inside the function and
   // delete [] value needs to be called when you are done with it.
   // the 'value' array returned is null terminated, and has 'nelements'
   // elements in it plus the null.
+  // nelements must be set to the maximum number of elements to read from
+  // the property.
   bool getValue(Window win, Atoms atom, Atoms type,
                 unsigned long &nelements, unsigned long **value) const;
+  bool getValue(Window win, Atoms atom, Atoms type, unsigned long &value) const;
   bool getValue(Window win, Atoms atom, StringType type,
                 std::string &value) const;
+  bool getValue(Window win, Atoms atom, StringType type,
+                int &nelements, StringVect &strings) const;
   
   void eraseValue(Window win, Atoms atom) const;
 
   // temporary function!! remove when not used in blackbox.hh anymore!!
   inline Atom getAtom(Atoms a)
-  { Atom ret = _atoms[a]; assert(ret != 0); return ret; }
+  { assert(a >= 0 && a < NUM_ATOMS); Atom ret = _atoms[a];
+    assert(ret != 0); return ret; }
 };
 
 #endif // __XAtom_h
index 56782248dddd5b9a3ef6802df26ef17e8f20cd0c..3cc12bc4523e65333d00e6ab719efd728d7b2114 100644 (file)
@@ -156,17 +156,19 @@ Blackbox::Blackbox(char **m_argv, char *dpy_name, char *rc, char *menu)
   resource.auto_raise_delay.tv_sec = resource.auto_raise_delay.tv_usec = 0;
 
   active_screen = 0;
-  focused_window = (BlackboxWindow *) 0;
+  focused_window = changing_window = (BlackboxWindow *) 0;
 
   XrmInitialize();
   load_rc();
 
-  xatom = new XAtom(this);
+  xatom = new XAtom(getXDisplay());
 
   cursor.session = XCreateFontCursor(getXDisplay(), XC_left_ptr);
   cursor.move = XCreateFontCursor(getXDisplay(), XC_fleur);
   cursor.ll_angle = XCreateFontCursor(getXDisplay(), XC_ll_angle);
   cursor.lr_angle = XCreateFontCursor(getXDisplay(), XC_lr_angle);
+  cursor.ul_angle = XCreateFontCursor(getXDisplay(), XC_ul_angle);
+  cursor.ur_angle = XCreateFontCursor(getXDisplay(), XC_ur_angle);
 
   for (unsigned int i = 0; i < getNumberOfScreens(); i++) {
     BScreen *screen = new BScreen(this, i);
@@ -356,11 +358,16 @@ void Blackbox::process_event(XEvent *e) {
   case UnmapNotify: {
     BlackboxWindow *win = (BlackboxWindow *) 0;
     Slit *slit = (Slit *) 0;
+    BScreen *screen = (BScreen *) 0;
 
     if ((win = searchWindow(e->xunmap.window))) {
       win->unmapNotifyEvent(&e->xunmap);
     } else if ((slit = searchSlit(e->xunmap.window))) {
       slit->unmapNotifyEvent(&e->xunmap);
+    } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
+      screen->removeSystrayWindow(e->xunmap.window);
+    } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
+      screen->removeDesktopWindow(e->xunmap.window);
     }
 
     break;
@@ -369,6 +376,7 @@ void Blackbox::process_event(XEvent *e) {
   case DestroyNotify: {
     BlackboxWindow *win = (BlackboxWindow *) 0;
     Slit *slit = (Slit *) 0;
+    BScreen *screen = (BScreen *) 0;
     BWindowGroup *group = (BWindowGroup *) 0;
 
     if ((win = searchWindow(e->xdestroywindow.window))) {
@@ -377,6 +385,10 @@ void Blackbox::process_event(XEvent *e) {
       slit->removeClient(e->xdestroywindow.window, False);
     } else if ((group = searchGroup(e->xdestroywindow.window))) {
       delete group;
+    } else if ((screen = searchSystrayWindow(e->xunmap.window))) {
+      screen->removeSystrayWindow(e->xunmap.window);
+    } else if ((screen = searchDesktopWindow(e->xunmap.window))) {
+      screen->removeDesktopWindow(e->xunmap.window);
     }
 
     break;
@@ -656,6 +668,7 @@ void Blackbox::process_event(XEvent *e) {
   case ClientMessage: {
     if (e->xclient.format == 32) {
       if (e->xclient.message_type == xatom->getAtom(XAtom::wm_change_state)) {
+        // WM_CHANGE_STATE message
         BlackboxWindow *win = searchWindow(e->xclient.window);
         if (! win || ! win->validateClient()) return;
 
@@ -663,18 +676,35 @@ void Blackbox::process_event(XEvent *e) {
           win->iconify();
         if (e->xclient.data.l[0] == NormalState)
           win->deiconify();
-      } else if(e->xclient.message_type == getBlackboxChangeWorkspaceAtom()) {
+      } else if (e->xclient.message_type == 
+                 xatom->getAtom(XAtom::blackbox_change_workspace) || 
+                 e->xclient.message_type == 
+                 xatom->getAtom(XAtom::net_current_desktop)) {
+        // NET_CURRENT_DESKTOP message
         BScreen *screen = searchScreen(e->xclient.window);
 
         unsigned int workspace = e->xclient.data.l[0];
         if (screen && workspace < screen->getWorkspaceCount())
           screen->changeWorkspaceID(workspace);
-      } else if (e->xclient.message_type == getBlackboxChangeWindowFocusAtom()) {
+      } else if (e->xclient.message_type == 
+                 xatom->getAtom(XAtom::blackbox_change_window_focus) ||
+                 e->xclient.message_type == 
+                 xatom->getAtom(XAtom::net_active_window)) {
+        // NET_ACTIVE_WINDOW
         BlackboxWindow *win = searchWindow(e->xclient.window);
 
-        if (win && win->isVisible() && win->setInputFocus())
-          win->installColormap(True);
-      } else if (e->xclient.message_type == getBlackboxCycleWindowFocusAtom()) {
+        if (win) {
+          if (win->isIconic())
+            win->deiconify(False, True);
+          if (win->isVisible() && win->setInputFocus()) {
+            //win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
+            //  raiseWindow(win);
+            win->installColormap(True);
+          }
+        }
+      } else if (e->xclient.message_type == 
+                 xatom->getAtom(XAtom::blackbox_cycle_window_focus)) {
+        // BLACKBOX_CYCLE_WINDOW_FOCUS
         BScreen *screen = searchScreen(e->xclient.window);
 
         if (screen) {
@@ -683,7 +713,31 @@ void Blackbox::process_event(XEvent *e) {
           else
             screen->nextFocus();
         }
-      } else if (e->xclient.message_type == getBlackboxChangeAttributesAtom()) {
+      } else if (e->xclient.message_type == 
+                 xatom->getAtom(XAtom::net_wm_desktop)) {
+        // NET_WM_DESKTOP
+        BlackboxWindow *win = searchWindow(e->xclient.window);
+
+        if (win) {
+          BScreen *screen = win->getScreen();
+          unsigned long wksp = (unsigned) e->xclient.data.l[0];
+          if (wksp < screen->getWorkspaceCount()) {
+            if (win->isIconic()) win->deiconify(False, True);
+            if (win->isStuck()) win->stick();
+            if (wksp != screen->getCurrentWorkspaceID())
+              win->withdraw();
+            else
+              win->show();
+            screen->reassociateWindow(win, wksp, True);
+          } else if (wksp == 0xfffffffe) { // XXX: BUG, BUT DOING THIS SO KDE WORKS FOR NOW!!
+            if (win->isIconic()) win->deiconify(False, True);
+            if (! win->isStuck()) win->stick();
+            if (! win->isVisible()) win->show();
+          }
+        }
+      } else if (e->xclient.message_type == 
+                 xatom->getAtom(XAtom::blackbox_change_attributes)) {
+        // BLACKBOX_CHANGE_ATTRIBUTES
         BlackboxWindow *win = searchWindow(e->xclient.window);
 
         if (win && win->validateClient()) {
@@ -696,6 +750,185 @@ void Blackbox::process_event(XEvent *e) {
 
           win->changeBlackboxHints(&net);
         }
+      } else if (e->xclient.message_type == 
+                xatom->getAtom(XAtom::net_number_of_desktops)) {
+        // NET_NUMBER_OF_DESKTOPS
+        BScreen *screen = searchScreen(e->xclient.window);
+        
+        if (e->xclient.data.l[0] > 0) {
+          if ((unsigned) e->xclient.data.l[0] < screen->getWorkspaceCount()) {
+            // shrink
+            for (int i = screen->getWorkspaceCount();
+                 i > e->xclient.data.l[0]; --i)
+              screen->removeLastWorkspace();
+            // removeLast already sets the current workspace to the 
+            // last available one.
+          } else if ((unsigned) e->xclient.data.l[0] >
+                     screen->getWorkspaceCount()) {
+            // grow
+            for(int i = screen->getWorkspaceCount(); 
+                i < e->xclient.data.l[0]; ++i)
+              screen->addWorkspace();
+          }
+        }
+      } else if (e->xclient.message_type ==
+                 xatom->getAtom(XAtom::net_close_window)) {
+        // NET_CLOSE_WINDOW
+        BlackboxWindow *win = searchWindow(e->xclient.window);
+        if (win && win->validateClient())
+          win->close(); // could this be smarter?
+      } else if (e->xclient.message_type ==
+                 xatom->getAtom(XAtom::net_wm_moveresize)) {
+        // NET_WM_MOVERESIZE
+        BlackboxWindow *win = searchWindow(e->xclient.window);
+        if (win && win->validateClient()) {
+          int x_root = e->xclient.data.l[0],
+              y_root = e->xclient.data.l[1];
+          if ((Atom) e->xclient.data.l[2] ==
+              xatom->getAtom(XAtom::net_wm_moveresize_move)) {
+            win->beginMove(x_root, y_root);
+          } else {
+            if ((Atom) e->xclient.data.l[2] ==
+                xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
+              win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
+            else if ((Atom) e->xclient.data.l[2] ==
+                     xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
+              win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
+            else if ((Atom) e->xclient.data.l[2] ==
+                     xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
+              win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
+            else if ((Atom) e->xclient.data.l[2] ==
+                xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
+              win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
+          }
+        }
+      } else if (e->xclient.message_type ==
+                 xatom->getAtom(XAtom::net_wm_state)) {
+        // NET_WM_STATE
+        BlackboxWindow *win = searchWindow(e->xclient.window);
+        if (win && win->validateClient()) {
+          const Atom action = (Atom) e->xclient.data.l[0];
+          const Atom state[] = { (Atom) e->xclient.data.l[1],
+                                 (Atom) e->xclient.data.l[2] };
+          
+          for (int i = 0; i < 2; ++i) {
+            if (! state[i])
+              continue;
+
+            if ((Atom) e->xclient.data.l[0] == 1) {
+              // ADD
+              if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
+                win->setModal(True);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
+                if (win->isMaximizedHoriz()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(1); // full
+                } else if (! win->isMaximized()) {
+                  win->maximize(2); // vert
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
+                if (win->isMaximizedVert()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(1); // full
+                } else if (! win->isMaximized()) {
+                  win->maximize(3); // horiz
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_shaded)) {
+                if (! win->isShaded())
+                  win->shade();
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
+                win->setSkipTaskbar(True);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
+                win->setSkipPager(True);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
+                win->setFullscreen(True);
+              }
+            } else if (action == 0) {
+              // REMOVE
+              if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
+                win->setModal(False);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
+                if (win->isMaximizedFull()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(3); // horiz
+                } else if (win->isMaximizedVert()) {
+                  win->maximize(0); // unmaximize
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
+                if (win->isMaximizedFull()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(2); // vert
+                } else if (win->isMaximizedHoriz()) {
+                  win->maximize(0); // unmaximize
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_shaded)) {
+                if (win->isShaded())
+                  win->shade();
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
+                win->setSkipTaskbar(False);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
+                win->setSkipPager(False);
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
+                win->setFullscreen(False);
+              }
+            } else if (action == 2) {
+              // TOGGLE
+              if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal)) {
+                win->setModal(! win->isModal());
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_vert)) {
+                if (win->isMaximizedFull()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(3); // horiz
+                } else if (win->isMaximizedVert()) {
+                  win->maximize(0); // unmaximize
+                } else if (win->isMaximizedHoriz()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(1); // full
+                } else {
+                  win->maximize(2); // vert
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_maximized_horz)) {
+                if (win->isMaximizedFull()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(2); // vert
+                } else if (win->isMaximizedHoriz()) {
+                  win->maximize(0); // unmaximize
+                } else if (win->isMaximizedVert()) {
+                  win->maximize(0); // unmaximize
+                  win->maximize(1); // full
+                } else {
+                  win->maximize(3); // horiz
+                }
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_shaded)) {
+                win->shade();
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_taskbar)) {
+                win->setSkipTaskbar(! win->skipTaskbar());
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_skip_pager)) {
+                win->setSkipPager(! win->skipPager());
+              } else if (state[i] ==
+                         xatom->getAtom(XAtom::net_wm_state_fullscreen)) {
+                win->setFullscreen(! win->isFullscreen());
+              }
+            }
+          }
+        }
       }
     }
 
@@ -773,6 +1006,24 @@ BScreen *Blackbox::searchScreen(Window window) {
 }
 
 
+BScreen *Blackbox::searchDesktopWindow(Window window) {
+  WindowScreenLookup::iterator it = desktopSearchList.find(window);
+  if (it != desktopSearchList.end())
+    return it->second;
+
+  return (BScreen*) 0;
+}
+
+
+BScreen *Blackbox::searchSystrayWindow(Window window) {
+  WindowScreenLookup::iterator it = systraySearchList.find(window);
+  if (it != systraySearchList.end())
+    return it->second;
+
+  return (BScreen*) 0;
+}
+
+
 BlackboxWindow *Blackbox::searchWindow(Window window) {
   WindowLookup::iterator it = windowSearchList.find(window);
   if (it != windowSearchList.end())
@@ -818,6 +1069,16 @@ Slit *Blackbox::searchSlit(Window window) {
 }
 
 
+void Blackbox::saveDesktopWindowSearch(Window window, BScreen *screen) {
+  desktopSearchList.insert(WindowScreenLookupPair(window, screen));
+}
+
+
+void Blackbox::saveSystrayWindowSearch(Window window, BScreen *screen) {
+  systraySearchList.insert(WindowScreenLookupPair(window, screen));
+}
+
+
 void Blackbox::saveWindowSearch(Window window, BlackboxWindow *data) {
   windowSearchList.insert(WindowLookupPair(window, data));
 }
@@ -843,6 +1104,16 @@ void Blackbox::saveSlitSearch(Window window, Slit *data) {
 }
 
 
+void Blackbox::removeDesktopWindowSearch(Window window) {
+  desktopSearchList.erase(window);
+}
+
+
+void Blackbox::removeSystrayWindowSearch(Window window) {
+  systraySearchList.erase(window);
+}
+
+
 void Blackbox::removeWindowSearch(Window window) {
   windowSearchList.erase(window);
 }
@@ -1060,6 +1331,13 @@ void Blackbox::timeout(void) {
 }
 
 
+void Blackbox::setChangingWindow(BlackboxWindow *win) {
+  // make sure one of the two is null and the other isn't
+  assert((! changing_window && win) || (! win && changing_window));
+  changing_window = win;
+}
+
+
 void Blackbox::setFocusedWindow(BlackboxWindow *win) {
   if (focused_window && focused_window == win) // nothing to do
     return;
index cb38dc3400ae019800703d1c19ce2f7e86bff84b..a5f5549153a2e084be618a9cbbd4c62572019baf 100644 (file)
@@ -98,7 +98,7 @@ extern I18n i18n;
 class Blackbox : public BaseDisplay, public TimeoutHandler {
 private:
   struct BCursor {
-    Cursor session, move, ll_angle, lr_angle;
+    Cursor session, move, ll_angle, lr_angle, ul_angle, ur_angle;
   };
   BCursor cursor;
 
@@ -121,6 +121,10 @@ private:
   typedef WindowLookup::value_type WindowLookupPair;
   WindowLookup windowSearchList;
 
+  typedef std::map<Window, BScreen*> WindowScreenLookup;
+  typedef WindowScreenLookup::value_type WindowScreenLookupPair;
+  WindowScreenLookup systraySearchList, desktopSearchList;
+
   typedef std::map<Window, BWindowGroup*> GroupLookup;
   typedef GroupLookup::value_type GroupLookupPair;
   GroupLookup groupSearchList;
@@ -144,7 +148,7 @@ private:
   ScreenList screenList;
 
   BScreen *active_screen;
-  BlackboxWindow *focused_window;
+  BlackboxWindow *focused_window, *changing_window;
   BTimer *timer;
   Configuration config;
   XAtom *xatom;
@@ -171,17 +175,23 @@ public:
 
   Basemenu *searchMenu(Window window);
   BWindowGroup *searchGroup(Window window);
+  BScreen *searchDesktopWindow(Window window);
+  BScreen *searchSystrayWindow(Window window);
   BlackboxWindow *searchWindow(Window window);
   BScreen *searchScreen(Window window);
   Toolbar *searchToolbar(Window);
   Slit *searchSlit(Window);
 
   void saveMenuSearch(Window window, Basemenu *data);
+  void saveDesktopWindowSearch(Window window, BScreen *screen);
+  void saveSystrayWindowSearch(Window window, BScreen *screen);
   void saveWindowSearch(Window window, BlackboxWindow *data);
   void saveGroupSearch(Window window, BWindowGroup *data);
   void saveToolbarSearch(Window window, Toolbar *data);
   void saveSlitSearch(Window window, Slit *data);
   void removeMenuSearch(Window window);
+  void removeDesktopWindowSearch(Window window);
+  void removeSystrayWindowSearch(Window window);
   void removeWindowSearch(Window window);
   void removeGroupSearch(Window window);
   void removeToolbarSearch(Window window);
@@ -190,6 +200,7 @@ public:
   inline XAtom *getXAtom(void) { return xatom; }
   
   inline BlackboxWindow *getFocusedWindow(void) { return focused_window; }
+  inline BlackboxWindow *getChangingWindow(void) { return changing_window; }
 
   inline Configuration *getConfig() { return &config; }
   inline const Time &getDoubleClickInterval(void) const
@@ -225,8 +236,13 @@ public:
     { return cursor.ll_angle; }
   inline Cursor getLowerRightAngleCursor(void) const
     { return cursor.lr_angle; }
+  inline Cursor getUpperLeftAngleCursor(void) const
+    { return cursor.ul_angle; }
+  inline Cursor getUpperRightAngleCursor(void) const
+    { return cursor.ur_angle; }
 
-  void setFocusedWindow(BlackboxWindow *w);
+  void setFocusedWindow(BlackboxWindow *win);
+  void setChangingWindow(BlackboxWindow *win);
   void shutdown(void);
   void saveStyleFilename(const std::string& filename);
   void addMenuTimestamp(const std::string& filename);
@@ -244,64 +260,6 @@ public:
 #ifndef   HAVE_STRFTIME
   enum { B_AmericanDate = 1, B_EuropeanDate };
 #endif // HAVE_STRFTIME
-
-  inline Atom getWMDeleteAtom(void) const
-    { return xatom->getAtom(XAtom::wm_delete_window); }
-  inline Atom getWMProtocolsAtom(void) const
-    { return xatom->getAtom(XAtom::wm_protocols); }
-  inline Atom getWMTakeFocusAtom(void) const
-    { return xatom->getAtom(XAtom::wm_take_focus); }
-  inline Atom getWMColormapAtom(void) const
-    { return xatom->getAtom(XAtom::wm_colormap_windows); }
-  inline Atom getMotifWMHintsAtom(void) const
-    { return xatom->getAtom(XAtom::motif_wm_hints); }
-
-  // this atom is for normal app->WM hints about decorations, stacking,
-  // starting workspace etc...
-  inline Atom getBlackboxHintsAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_hints); }
-
-  // these atoms are for normal app->WM interaction beyond the scope of the
-  // ICCCM...
-  inline Atom getBlackboxAttributesAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_attributes); }
-  inline Atom getBlackboxChangeAttributesAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_change_attributes); }
-
-  // these atoms are for window->WM interaction, with more control and
-  // information on window "structure"... common examples are
-  // notifying apps when windows are raised/lowered... when the user changes
-  // workspaces... i.e. "pager talk"
-  inline Atom getBlackboxStructureMessagesAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_structure_messages); }
-
-  // *Notify* portions of the NETStructureMessages protocol
-  inline Atom getBlackboxNotifyStartupAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_startup); }
-  inline Atom getBlackboxNotifyWindowAddAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_window_add); }
-  inline Atom getBlackboxNotifyWindowDelAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_window_del); }
-  inline Atom getBlackboxNotifyWindowFocusAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_window_focus); }
-  inline Atom getBlackboxNotifyCurrentWorkspaceAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_current_workspace); }
-  inline Atom getBlackboxNotifyWorkspaceCountAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_workspace_count); }
-  inline Atom getBlackboxNotifyWindowRaiseAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_window_raise); }
-  inline Atom getBlackboxNotifyWindowLowerAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_notify_window_lower); }
-
-  // atoms to change that request changes to the desktop environment during
-  // runtime... these messages can be sent by any client... as the sending
-  // client window id is not included in the ClientMessage event...
-  inline Atom getBlackboxChangeWorkspaceAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_change_workspace); }
-  inline Atom getBlackboxChangeWindowFocusAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_change_window_focus); }
-  inline Atom getBlackboxCycleWindowFocusAtom(void) const
-    { return xatom->getAtom(XAtom::blackbox_cycle_window_focus); }
 };
 
 
This page took 0.105409 seconds and 4 git commands to generate.