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