all repos — openbox @ f4c0547b7a90c9647a2c39c3d1a737142eab088e

openbox fork - make it a bit more like ryudo

merge from netwm-merge2 to netwm-merge3. Basically, all of netwm that we intend to support is 'supported'. Just need to squash bugs now.
Dana Jansens danakj@orodu.net
commit

f4c0547b7a90c9647a2c39c3d1a737142eab088e

parent

1766453ca2ce30adf84798cb504e8b4d258bd08f

M src/Makefile.amsrc/Makefile.am

@@ -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
M src/Netizen.ccsrc/Netizen.cc

@@ -27,19 +27,21 @@ #endif // HAVE_CONFIG_H

#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 @@

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::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::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::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::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::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::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);
M src/Netizen.hhsrc/Netizen.hh

@@ -32,11 +32,13 @@ // forward declaration

class Blackbox; class BScreen; class Netizen; +class XAtom; class Netizen { private: Blackbox *blackbox; BScreen *screen; + XAtom *xatom; Window window; XEvent event;
M src/Screen.ccsrc/Screen.cc

@@ -143,6 +143,14 @@ #ifdef HAVE_GETPID

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 @@ workspacemenu->insert(wkspc->getName(), wkspc->getMenu());

} saveWorkspaceNames(); + updateDesktopNames(); updateNetizenWorkspaceCount(); workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu);

@@ -253,9 +262,10 @@ slit = new Slit(this);

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::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 @@ workspacemenu->update();

toolbar->reconfigure(); + updateDesktopNames(); updateNetizenWorkspaceCount(); return workspacesList.size();

@@ -1048,6 +1060,7 @@ delete wkspc;

saveWorkspaces(getWorkspaceCount()); saveWorkspaceNames(); + updateDesktopNames(); toolbar->reconfigure();

@@ -1083,7 +1096,6 @@ current_workspace = getWorkspace(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 @@ updateNetizenCurrentWorkspace();

} +/* + * 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 @@ else if (w->isIconic())

removeIcon(w); windowList.remove(w); + updateClientList(); if (blackbox->getFocusedWindow() == w) blackbox->setFocusedWindow((BlackboxWindow *) 0);

@@ -1172,6 +1295,25 @@ }

} +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::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 @@

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 @@ end = windowList.end();

for (; it != end; ++it) if ((*it)->isMaximized()) (*it)->remaximize(); } + + updateWorkArea(); }
M src/Screen.hhsrc/Screen.hh

@@ -129,6 +129,9 @@ typedef std::list<Netizen*> NetizenList;

NetizenList netizenList; BlackboxWindowList iconList, windowList; + typedef std::vector<Window> WindowList; + WindowList desktopWindowList, systrayWindowList; + Slit *slit; Toolbar *toolbar; Workspace *current_workspace;

@@ -190,7 +193,7 @@

void InitMenu(void); void LoadStyle(void); - + void updateWorkArea(void); public: enum { RowSmartPlacement = 1, ColSmartPlacement, CascadePlacement, UnderMousePlacement, LeftRight, RightLeft, TopBottom, BottomTop };

@@ -310,16 +313,26 @@ void addWorkspaceName(const std::string& name);

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);
M src/Toolbar.ccsrc/Toolbar.cc

@@ -979,6 +979,7 @@ }

Workspace *wkspc = screen->getCurrentWorkspace(); wkspc->setName(new_workspace_name); + screen->updateDesktopNames(); wkspc->getMenu()->hide(); screen->getWorkspacemenu()->changeItemLabel(wkspc->getID() + 2,
M src/Window.ccsrc/Window.cc

@@ -110,7 +110,8 @@ }

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 @@

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

@@ -166,6 +169,12 @@ getWMNormalHints();

if (client.initial_state == WithdrawnState) { screen->getSlit()->addClient(client.window); + delete this; + return; + } + + if (isKDESystrayWindow()) { + screen->addSystrayWindow(client.window); delete this; return; }

@@ -178,15 +187,56 @@ blackbox->saveWindowSearch(frame.window, this);

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 &&

@@ -195,6 +245,8 @@ decorations &= ~(Decor_Maximize | Decor_Handle);

functions &= ~(Func_Resize | Func_Maximize); } upsize(); + + setAllowedActions(); bool place_window = True; if (blackbox->isStartup() || isTransient() ||

@@ -222,19 +274,22 @@

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 @@ else

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 @@

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 @@ unsigned int x = bsep;

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::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 @@

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)); }

@@ -1034,6 +1163,56 @@ }

/* + * 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 * thereafter.

@@ -1041,19 +1220,14 @@ * Returns: true if the MWM hints are successfully retreived and applied;

* false if they are not. */ void BlackboxWindow::getMWMHints(void) { - int format; - Atom atom_return; - unsigned long num, len; - MwmHints *mwm_hint = 0; + unsigned long num; + MwmHints *mwm_hint; - 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) + 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 @@ if (mwm_hint->functions & MwmFuncClose)

functions |= Func_Close; } } - XFree(mwm_hint); + delete mwm_hint; }

@@ -1107,18 +1281,14 @@ * Returns: true if the hints are successfully retreived and applied; false if

* they are not. */ bool BlackboxWindow::getBlackboxHints(void) { - int format; - Atom atom_return; - unsigned long num, len; - BlackboxHints *blackbox_hint = 0; + unsigned long num; + BlackboxHints *blackbox_hint; - 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) + 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 @@ }

reconfigure(); } - XFree(blackbox_hint); + + delete blackbox_hint; + return True; }

@@ -1237,6 +1409,15 @@

// register ourselves with our new transient_for client.transient_for->client.transientList.push_back(this); flags.stuck = client.transient_for->flags.stuck; +} + + +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; }

@@ -1388,11 +1569,11 @@

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 @@

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.

@@ -1429,6 +1613,8 @@

XUnmapWindow(blackbox->getXDisplay(), frame.window); flags.visible = False; flags.iconic = True; + + setState(IconicState); screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);

@@ -1453,15 +1639,15 @@ }

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::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::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::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 @@ blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);

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::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 @@ }

} +/* + * (Un)Sticks a window and its relatives. + */ void BlackboxWindow::stick(void) { if (flags.stuck) { blackbox_attrib.flags ^= AttribOmnipresent;

@@ -1667,6 +1867,11 @@ flags.stuck = False;

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 @@

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::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 @@

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 @@ current_state = NormalState;

} 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 @@

// 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 @@ // adjust the window decorations based on transience

if (isTransient()) { decorations &= ~(Decor_Maximize | Decor_Handle); functions &= ~Func_Maximize; + setAllowedActions(); } reconfigure();

@@ -2246,6 +2499,7 @@ getWMIconName();

if (flags.iconic) screen->propagateWindowName(this); break; + case XAtom::net_wm_name: case XA_WM_NAME: getWMName();

@@ -2268,6 +2522,7 @@ } else {

decorations |= Decor_Maximize | Decor_Handle; functions |= Func_Resize | Func_Maximize; } + setAllowedActions(); } Rect old_rect = frame.rect;

@@ -2281,7 +2536,7 @@ break;

} default: - if (atom == blackbox->getWMProtocolsAtom()) { + if (atom == xatom->getAtom(XAtom::wm_protocols)) { getWMProtocols(); if ((decorations & Decor_Close) && (! frame.close_button)) {

@@ -2292,6 +2547,8 @@ XMapSubwindows(blackbox->getXDisplay(), frame.title);

} if (windowmenu) windowmenu->reconfigure(); } + } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) { + updateStrut(); } break;

@@ -2382,9 +2639,6 @@ lastButtonPressTime = be->time;

} } - 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 @@ (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))

close(); redrawCloseButton(False); } else if (flags.moving) { - flags.moving = False; + endMove(); + } else if (flags.resizing) { + endResize(); + } else if (re->window == frame.window) { + if (re->button == 2 && re->state == Mod1Mask) + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + } +} - 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); - } else if (flags.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()); +void BlackboxWindow::beginMove(int x_root, int y_root) { + assert(! (flags.resizing || flags.moving)); - screen->hideGeometry(); + /* + 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); - constrain((re->window == frame.left_grip) ? TopRight : TopLeft); + if (windowmenu && windowmenu->isVisible()) + windowmenu->hide(); + + flags.moving = True; + blackbox->setChangingWindow(this); - // 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()); + if (! screen->doOpaqueMove()) { + XGrabServer(blackbox->getXDisplay()); - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - } else if (re->window == frame.window) { - if (re->button == 2 && re->state == Mod1Mask) - XUngrabPointer(blackbox->getXDisplay(), CurrentTime); + 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; -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); + 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; - if (windowmenu && windowmenu->isVisible()) - windowmenu->hide(); + // 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; - flags.moving = True; + srect = screen->getRect(); // now get the full screen - if (! screen->doOpaqueMove()) { - XGrabServer(blackbox->getXDisplay()); + dleft = std::abs(wleft - srect.left()), + dright = std::abs(wright - srect.right()), + dtop = std::abs(wtop - srect.top()), + dbottom = std::abs(wbottom - srect.bottom()); - frame.changing = frame.rect; - screen->showPosition(frame.changing.x(), frame.changing.y()); + // 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; - 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; + // 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); - const int snap_distance = screen->getEdgeSnapThreshold(); + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), + frame.changing.x(), + frame.changing.y(), + frame.changing.width() - 1, + frame.changing.height() - 1); + } - if (snap_distance) { - // window corners - const int wleft = dx, - wright = dx + frame.rect.width() - 1, - wtop = dy, - wbottom = dy + frame.rect.height() - 1; + screen->showPosition(dx, dy); +} - // 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 +void BlackboxWindow::endMove(void) { + assert(flags.moving); + assert(blackbox->getChangingWindow() == this); - 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()); + flags.moving = False; + blackbox->setChangingWindow(0); - // snap top of other window? - if (dtop < snap_distance && dtop <= dbottom) { - dy = winrect.top() - frame.rect.height(); + 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(); - 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; - } + XUngrabPointer(blackbox->getXDisplay(), CurrentTime); - continue; - } - // snap bottom of other window? - else if (dbottom < snap_distance) { - dy = winrect.bottom() + 1; + // 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)); +} - 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; - } +void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) { + assert(! (flags.resizing || flags.moving)); - // snap left of other window? - if (dleft < snap_distance && dleft <= dright) { - dx = winrect.left() - frame.rect.width(); + /* + 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(); + } - 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; - } + resize_dir = dir; - continue; - } - // snap right of other window? - else if (dright < snap_distance) { - dx = winrect.right() + 1; + Cursor cursor; + Corner anchor; + + switch (resize_dir) { + case BottomLeft: + anchor = TopRight; + cursor = blackbox->getLowerLeftAngleCursor(); + break; - 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; - } + case BottomRight: + anchor = TopLeft; + cursor = blackbox->getLowerRightAngleCursor(); + break; - continue; - } - } - } - - // try snap to the screen's available area - Rect srect = screen->availableArea(); + case TopLeft: + anchor = BottomRight; + cursor = blackbox->getUpperLeftAngleCursor(); + break; - 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()); + case TopRight: + anchor = BottomLeft; + cursor = blackbox->getUpperRightAngleCursor(); + break; - // 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; + default: + assert(false); // unhandled Corner + } + + XGrabServer(blackbox->getXDisplay()); + XGrabPointer(blackbox->getXDisplay(), frame.window, False, + PointerMotionMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); - // 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; + flags.resizing = True; + blackbox->setChangingWindow(this); - if (! screen->doFullMax()) { - srect = screen->getRect(); // now get the full screen + int gw, gh; + frame.changing = frame.rect; - dleft = std::abs(wleft - srect.left()), - dright = std::abs(wright - srect.right()), - dtop = std::abs(wtop - srect.top()), - dbottom = std::abs(wbottom - srect.bottom()); + constrain(anchor, &gw, &gh); - // 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; + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 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; - } - } + screen->showGeometry(gw, gh); + + frame.grab_x = x_root; + frame.grab_y = y_root; +} - 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); +void BlackboxWindow::doResize(int x_root, int y_root) { + assert(flags.resizing); + assert(blackbox->getChangingWindow() == this); - 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); + int gw, gh; + Corner anchor; - if (! flags.resizing) { - XGrabServer(blackbox->getXDisplay()); - XGrabPointer(blackbox->getXDisplay(), me->window, False, - ButtonMotionMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, - ((left) ? blackbox->getLowerLeftAngleCursor() : - blackbox->getLowerRightAngleCursor()), - CurrentTime); + 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; - flags.resizing = True; + default: + assert(false); // unhandled Corner + } + + constrain(anchor, &gw, &gh); - int gw, gh; - frame.grab_x = me->x; - frame.grab_y = me->y; - frame.changing = frame.rect; + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); - constrain((left) ? TopRight : TopLeft, &gw, &gh); + screen->showGeometry(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); +void BlackboxWindow::endResize(void) { + assert(flags.resizing); + assert(blackbox->getChangingWindow() == this); - int gw, gh; + XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(), + screen->getOpGC(), frame.changing.x(), frame.changing.y(), + frame.changing.width() - 1, frame.changing.height() - 1); + XUngrabServer(blackbox->getXDisplay()); - Corner anchor; + // unset maximized state after resized when fully maximized + if (flags.maximized == 1) + maximize(0); + + flags.resizing = False; + blackbox->setChangingWindow(0); - 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)); - } + configure(frame.changing.x(), frame.changing.y(), + frame.changing.width(), frame.changing.height()); + screen->hideGeometry(); - constrain(anchor, &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)); +} - 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); +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 @@ frame.changing.right() + frame.margin.right,

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); }
M src/Window.hhsrc/Window.hh

@@ -108,6 +108,20 @@ Decor_Maximize = (1l << 4),

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 @@ shaded, // is shaded?

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 @@

std::string title, icon_title; Rect rect; + Strut strut; int old_bw; // client's borderwidth

@@ -173,6 +191,8 @@ * this is based on the type of the client window as well as user input

* 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 @@ bool getState(void);

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 @@ void redrawIconifyButton(bool pressed);

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 @@ inline bool isVisible(void) const { return flags.visible; }

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 @@

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 @@ void maximize(unsigned int button);

void remaximize(void); void shade(void); void stick(void); - void unstick(void); void reconfigure(void); void updateFocusModel(void); void installColormap(bool install);
M src/Workspace.ccsrc/Workspace.cc

@@ -307,6 +307,7 @@

XLowerWindow(screen->getBaseDisplay()->getXDisplay(), stack_vector.front()); XRestackWindows(screen->getBaseDisplay()->getXDisplay(), &stack_vector[0], stack_vector.size()); + screen->lowerDesktops(); }

@@ -376,6 +377,14 @@ unsigned int Workspace::getCount(void) const {

return windowList.size(); } + +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());
M src/Workspace.hhsrc/Workspace.hh

@@ -93,6 +93,7 @@

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);
M src/XAtom.ccsrc/XAtom.cc

@@ -21,16 +21,17 @@ // DEALINGS IN THE SOFTWARE.

#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 @@ _atoms[wm_state] = create("WM_STATE");

_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 @@ _atoms[net_desktop_names] = create("_NET_DESKTOP_NAMES");

_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_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_ping] = create("_NET_WM_PING"); + _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 @@ // yes we do!

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 +} - 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; + +/* + * 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); + + 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]); + + std::string value; + + StringVect::const_iterator it = strings.begin(); + const StringVect::const_iterator end = strings.end(); + for (; it != end; ++it) + value += *it + '\0'; - XFree(textprop.value); + setValue(win, _atoms[atom], t, + reinterpret_cast<unsigned char *>(const_cast<char *>(value.c_str())), + 8, value.size(), false); }

@@ -238,23 +352,25 @@ unsigned long &nelements, unsigned char **value,

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 @@ XFree(c_val);

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);

@@ -290,44 +408,76 @@ }

/* + * 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])) + Atom t; + switch (type) { + case ansi: t = _atoms[string]; break; + case utf8: t = _atoms[utf8_string]; break; + default: assert(false); // unhandled StringType + } + + unsigned char *value; + unsigned long elements = (unsigned) -1; + if (!getValue(win, _atoms[atom], t, elements, &value, 8) || elements < 1) 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 - } - - if (ret != Success || count < 1) { - XFree(textprop.value); - 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; } - - /*
M src/XAtom.hhsrc/XAtom.hh

@@ -24,6 +24,9 @@ #define __XAtom_h

#include <X11/Xlib.h> #include <X11/Xatom.h> + +#include <assert.h> + #include <vector> #include <string>

@@ -52,6 +55,8 @@ wm_state,

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 @@ net_desktop_names,

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 @@ XAtom(const XAtom &);

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 @@ void setValue(Window win, Atoms atom, Atoms type,

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
M src/blackbox.ccsrc/blackbox.cc

@@ -156,17 +156,19 @@

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 @@

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 @@

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 @@ } else if ((slit = searchSlit(e->xdestroywindow.window))) {

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 @@

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 @@ if (e->xclient.data.l[0] == IconicState)

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 @@ screen->prevFocus();

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 @@ net.decoration = e->xclient.data.l[4];

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 @@ return (BScreen *) 0;

} +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 @@ return (Slit*) 0;

} +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)); }

@@ -840,6 +1101,16 @@

void Blackbox::saveSlitSearch(Window window, Slit *data) { slitSearchList.insert(SlitLookupPair(window, data)); +} + + +void Blackbox::removeDesktopWindowSearch(Window window) { + desktopSearchList.erase(window); +} + + +void Blackbox::removeSystrayWindowSearch(Window window) { + systraySearchList.erase(window); }

@@ -1057,6 +1328,13 @@ if (reread_menu_wait)

real_rereadMenu(); reconfigure_wait = reread_menu_wait = False; +} + + +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; }
M src/blackbox.hhsrc/blackbox.hh

@@ -98,7 +98,7 @@

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 @@ typedef std::map<Window, BlackboxWindow*> WindowLookup;

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 @@ typedef std::list<BScreen*> ScreenList;

ScreenList screenList; BScreen *active_screen; - BlackboxWindow *focused_window; + BlackboxWindow *focused_window, *changing_window; BTimer *timer; Configuration config; XAtom *xatom;

@@ -171,17 +175,23 @@ virtual ~Blackbox(void);

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 @@

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 @@ inline Cursor getLowerLeftAngleCursor(void) const

{ 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 @@

#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); } };