added support for _NET_WM_ALLOWED_ACTIONS and all the _NET_WM_ACTION_*. Added _NET_WM_STATE_MODAL and _NET_WM_WINDOW_TYPE_SPLASH
@@ -28,6 +28,8 @@ #include "Window.hh"
#include "WinClient.hh" #include "Workspace.hh" #include "Layer.hh" +#include "WinClientUtil.hh" + #include "FbTk/App.hh" #include "FbTk/FbWindow.hh" #include "FbTk/I18n.hh"@@ -109,11 +111,28 @@ m_net_wm_state_maximized_vert,
m_net_wm_state_fullscreen, m_net_wm_state_hidden, m_net_wm_state_skip_taskbar, - + m_net_wm_state_modal, + m_net_wm_state_below, + m_net_wm_state_above, + // window type m_net_wm_window_type, m_net_wm_window_type_dock, m_net_wm_window_type_desktop, + m_net_wm_window_type_splash, + + // window actions + m_net_wm_allowed_actions, + m_net_wm_action_move, + m_net_wm_action_resize, + m_net_wm_action_minimize, + m_net_wm_action_shade, + m_net_wm_action_stick, + m_net_wm_action_maximize_horz, + m_net_wm_action_maximize_vert, + m_net_wm_action_fullscreen, + m_net_wm_action_change_desktop, + m_net_wm_action_close, // root properties m_net_client_list,@@ -223,6 +242,15 @@ win.setTabable(false);
win.setMovable(false); win.setResizable(false); win.stick(); + + } else if (atoms[l] == m_net_wm_window_type_splash) { + /* + * _NET_WM_WINDOW_TYPE_SPLASH indicates that the + * window is a splash screen displayed as an application + * is starting up. + */ + win.setDecoration(FluxboxWindow::DECOR_NONE); + win.setMovable(false); } }@@ -297,7 +325,8 @@
Window *wl = FB_new_nothrow Window[num]; if (wl == 0) { _FB_USES_NLS; - cerr<<_FBTEXT(Ewmh, OutOfMemoryClientList, "Fatal: Out of memory, can't allocate for EWMH client list", "")<<endl; + cerr<<_FBTEXT(Ewmh, OutOfMemoryClientList, + "Fatal: Out of memory, can't allocate for EWMH client list", "")<<endl; return; }@@ -523,8 +552,8 @@ }
void Ewmh::updateState(FluxboxWindow &win) { - // TODO: should we update the _NET_WM_ALLOWED_ACTIONS - // here too? + + updateActions(win); typedef std::vector<unsigned int> StateVec;@@ -542,14 +571,13 @@ if (win.isIconic())
state.push_back(m_net_wm_state_hidden); if (win.isIconHidden()) state.push_back(m_net_wm_state_skip_taskbar); - if (win.isFullscreen()) { + if (win.isFullscreen()) state.push_back(m_net_wm_state_fullscreen); - } + if (win.winClient().isModal()) + state.push_back(m_net_wm_state_modal); FluxboxWindow::ClientList::iterator it = win.clientList().begin(); FluxboxWindow::ClientList::iterator it_end = win.clientList().end(); - - it = win.clientList().begin(); for (; it != it_end; ++it) { // search the old states for _NET_WM_STATE_SKIP_PAGER and append it@@ -565,18 +593,19 @@ &ret_type, &fmt, &nitems, &bytes_after,
&data); if (data) { Atom *old_states = (Atom *)data; - for (unsigned long i=0; i < nitems; ++i) + for (unsigned long i=0; i < nitems; ++i) { if (old_states[i] == m_net_wm_state_skip_pager) { client_state.push_back(m_net_wm_state_skip_pager); } + } XFree(data); } - if (!client_state.empty()) + if (!client_state.empty()) { (*it)->changeProperty(m_net_wm_state, XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&client_state.front()), client_state.size()); - else + } else (*it)->deleteProperty(m_net_wm_state); } }@@ -750,9 +779,6 @@
bool Ewmh::propertyNotify(WinClient &winclient, Atom the_property) { if (the_property == m_net_wm_strut) { -#ifdef DEBUG - cerr<<"_NET_WM_STRUT"<<endl; -#endif // DEBUG updateStrut(winclient); return true; }@@ -791,6 +817,7 @@ // type atoms
m_net_wm_window_type = XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False); m_net_wm_window_type_dock = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False); m_net_wm_window_type_desktop = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DESKTOP", False); + m_net_wm_window_type_splash = XInternAtom(disp, "_NET_WM_WINDOW_TYPE_SPLASH", False); // state atom and the supported state atoms m_net_wm_state = XInternAtom(disp, "_NET_WM_STATE", False);@@ -804,19 +831,20 @@ m_net_wm_state_skip_taskbar = XInternAtom(disp, "_NET_WM_STATE_SKIP_TASKBAR", False);
m_net_wm_state_skip_pager = XInternAtom(disp, "_NET_WM_STATE_SKIP_PAGER", False); m_net_wm_state_above = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False); m_net_wm_state_below = XInternAtom(disp, "_NET_WM_STATE_BELOW", False); + m_net_wm_state_modal = XInternAtom(disp, "_NET_WM_STATE_MODAL", False); // allowed actions m_net_wm_allowed_actions = XInternAtom(disp, "_NET_WM_ALLOWED_ACTIONS", False); - m_net_wm_action_move = XInternAtom(disp, "_NET_WM_ACTIONS_MOVE", False); - m_net_wm_action_resize = XInternAtom(disp, "_NET_WM_ACTIONS_RESIZE", False); - m_net_wm_action_minimize = XInternAtom(disp, "_NET_WM_ACTIONS_MINIMIZE", False); - m_net_wm_action_shade = XInternAtom(disp, "_NET_WM_ACTIONS_SHADE", False); - m_net_wm_action_stick = XInternAtom(disp, "_NET_WM_ACTIONS_STICK", False); - m_net_wm_action_maximize_horz = XInternAtom(disp, "_NET_WM_ACTIONS_MAXIMIZE_HORZ", False); - m_net_wm_action_maximize_vert = XInternAtom(disp, "_NET_WM_ACTIONS_MAXIMIZE_VERT", False); - m_net_wm_action_fullscreen = XInternAtom(disp, "_NET_WM_ACTIONS_FULLSCREEN", False); - m_net_wm_action_change_desktop = XInternAtom(disp, "_NET_WM_ACTIONS_CHANGE_DESKTOP", False); - m_net_wm_action_close = XInternAtom(disp, "_NET_WM_ACTIONS_CLOSE", False); + m_net_wm_action_move = XInternAtom(disp, "_NET_WM_ACTION_MOVE", False); + m_net_wm_action_resize = XInternAtom(disp, "_NET_WM_ACTION_RESIZE", False); + m_net_wm_action_minimize = XInternAtom(disp, "_NET_WM_ACTION_MINIMIZE", False); + m_net_wm_action_shade = XInternAtom(disp, "_NET_WM_ACTION_SHADE", False); + m_net_wm_action_stick = XInternAtom(disp, "_NET_WM_ACTION_STICK", False); + m_net_wm_action_maximize_horz = XInternAtom(disp, "_NET_WM_ACTION_MAXIMIZE_HORZ", False); + m_net_wm_action_maximize_vert = XInternAtom(disp, "_NET_WM_ACTION_MAXIMIZE_VERT", False); + m_net_wm_action_fullscreen = XInternAtom(disp, "_NET_WM_ACTION_FULLSCREEN", False); + m_net_wm_action_change_desktop = XInternAtom(disp, "_NET_WM_ACTION_CHANGE_DESKTOP", False); + m_net_wm_action_close = XInternAtom(disp, "_NET_WM_ACTION_CLOSE", False); m_net_wm_strut = XInternAtom(disp, "_NET_WM_STRUT", False); m_net_wm_icon_geometry = XInternAtom(disp, "_NET_WM_ICON_GEOMETRY", False);@@ -890,7 +918,7 @@ if (value && !win.isIconic())
win.iconify(); else if (!value && win.isIconic()) win.deiconify(); - } else if (state == m_net_wm_state_skip_taskbar) { + } else if (state == m_net_wm_state_skip_taskbar) { // skip taskbar win.setIconHidden(value); } else if (state == m_net_wm_state_below) { // bottom layer if (value)@@ -904,13 +932,14 @@ win.moveToLayer(Layer::ABOVE_DOCK);
else win.moveToLayer(Layer::NORMAL); } + // Note: state == net_wm_state_modal, We should not change it } // toggle window state void Ewmh::toggleState(FluxboxWindow &win, Atom state) { - if (state == m_net_wm_state_sticky) { + if (state == m_net_wm_state_sticky) { // sticky win.stick(); - } else if (state == m_net_wm_state_shaded){ + } else if (state == m_net_wm_state_shaded){ // shaded win.shade(); } else if (state == m_net_wm_state_maximized_horz ) { // maximized Horizontal win.maximizeHorizontal();@@ -923,7 +952,7 @@ if(win.isIconic())
win.deiconify(); else win.iconify(); - } else if (state == m_net_wm_state_skip_taskbar) { + } else if (state == m_net_wm_state_skip_taskbar) { // taskbar win.setIconHidden(!win.isIconHidden()); } else if (state == m_net_wm_state_below) { // bottom layer if (win.layerNum() == Layer::BOTTOM)@@ -956,6 +985,70 @@ data[0], data[1],
data[2], data[3])); winclient.screen().updateAvailableWorkspaceArea(); } +} + +void Ewmh::updateActions(FluxboxWindow &win) { + + /* From Extended Window Manager Hints, draft 1.3: + * + * _NET_WM_ALLOWED_ACTIONS, ATOM[] + * + * A list of atoms indicating user operations that the + * Window Manager supports for this window. Atoms present in the + * list indicate allowed actions, atoms not present in the list + * indicate actions that are not supported for this window. The + * Window Manager MUST keep this property updated to reflect the + * actions which are currently "active" or "sensitive" for a window. + * Taskbars, Pagers, and other tools use _NET_WM_ALLOWED_ACTIONS to + * decide which actions should be made available to the user. + */ + + typedef std::vector<Atom> ActionsVector; + ActionsVector actions; + actions.reserve(10); + // all windows can change desktop, + // be shaded or be sticky + actions.push_back(m_net_wm_action_change_desktop); + actions.push_back(m_net_wm_action_shade); + actions.push_back(m_net_wm_action_stick); + + if (win.isResizable()) + actions.push_back(m_net_wm_action_resize); + if (win.isMoveable()) + actions.push_back(m_net_wm_action_move); + if (win.isClosable()) + actions.push_back(m_net_wm_action_close); + if (win.isIconifiable()) + actions.push_back(m_net_wm_action_minimize); + + unsigned int max_width, max_height; + WinClientUtil::maxSize(win.clientList(), max_width, max_height); + + // if unlimited max width we can maximize horizontal + if (max_width == 0) { + actions.push_back(m_net_wm_action_maximize_horz); + } + // if unlimited max height we can maxmize vert + if (max_height == 0) { + actions.push_back(m_net_wm_action_maximize_vert); + } + + // if we have unlimited size in all directions we can have this window + // in fullscreen mode + if (max_height == 0 && max_width == 0) { + actions.push_back(m_net_wm_action_fullscreen); + } + + + + FluxboxWindow::ClientList::iterator it = win.clientList().begin(); + FluxboxWindow::ClientList::iterator it_end = win.clientList().end(); + for (; it != it_end; ++it) { + (*it)->changeProperty(m_net_wm_allowed_actions, XA_ATOM, 32, PropModeReplace, + reinterpret_cast<unsigned char*>(&actions.front()), + actions.size()); + } + } void Ewmh::setupState(FluxboxWindow &win) {
@@ -77,6 +77,8 @@ void setState(FluxboxWindow &win, Atom state, bool value);
void toggleState(FluxboxWindow &win, Atom state); void createAtoms(); void updateStrut(WinClient &winclient); + void updateActions(FluxboxWindow &win); + void setupState(FluxboxWindow &win); // root window properties@@ -94,6 +96,7 @@ // types
m_net_wm_window_type, m_net_wm_window_type_dock, m_net_wm_window_type_desktop, + m_net_wm_window_type_splash, // states m_net_wm_state, m_net_wm_state_sticky, m_net_wm_state_shaded,@@ -104,6 +107,7 @@ m_net_wm_state_skip_taskbar,
m_net_wm_state_skip_pager, m_net_wm_state_below, m_net_wm_state_above, + m_net_wm_state_modal, // allowed actions m_net_wm_allowed_actions,
@@ -135,6 +135,7 @@ ColSmartPlacement.hh ColSmartPlacement.cc \
RowSmartPlacement.hh RowSmartPlacement.cc \ ScreenPlacement.hh ScreenPlacement.cc \ UnderMousePlacement.hh UnderMousePlacement.cc \ + WinClientUtil.hh WinClientUtil.cc \ ${newwmspec_SOURCE} ${gnome_SOURCE} \ ${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}
@@ -0,0 +1,32 @@
+#include "WinClientUtil.hh" +#include "WinClient.hh" + +#include <algorithm> + +namespace WinClientUtil { + +void maxSize(const FluxboxWindow::ClientList &clients, + unsigned int &max_width, unsigned int &max_height) { + FluxboxWindow::ClientList::const_iterator it = clients.begin(); + FluxboxWindow::ClientList::const_iterator it_end = clients.end(); + max_width = ~0; // unlimited + max_height = ~0; // unlimited + for (; it != it_end; ++it) { + // special case for max height/width == 0 + // 0 indicates unlimited size, so we skip them + // and set max size to 0 if max size == ~0 after the loop + if ((*it)->maxHeight() != 0) + max_height = std::min( (*it)->maxHeight(), max_height ); + if ((*it)->maxWidth() != 0) + max_width = std::min( (*it)->maxWidth(), max_width ); + } + + if (max_width == ~0) + max_width = 0; + if (max_height == ~0) + max_height = 0; +} + +} + +
@@ -0,0 +1,19 @@
+#ifndef WINCLIENTUTIL_H +#define WINCLIENTUTIL_H + +#include "Window.hh" + +/// window client utilities +namespace WinClientUtil { + +/** + * Calculates the min of all maximum width/heights of all clients + * @param clients the client list + * @param width the return value of minimum of all max width of all clients + * @param height the return value of mimimum of all max heights of all clients + */ +void maxSize(const FluxboxWindow::ClientList &clients, + unsigned int &width, unsigned int &height); +} + +#endif // WINCLIENTUTIL_H
@@ -302,6 +302,7 @@ inline bool isIconifiable() const { return functions.iconify; }
inline bool isMaximizable() const { return functions.maximize; } inline bool isResizable() const { return functions.resize; } inline bool isClosable() const { return functions.close; } + inline bool isMoveable() const { return functions.move; } inline bool isStuck() const { return stuck; } inline bool hasTitlebar() const { return decorations.titlebar; } inline bool isMoving() const { return moving; }