all repos — fluxbox @ 09a5c23c5b099af531842ae7868e98bc8d717dac

custom fork of the fluxbox windowmanager

fix grouping to persist over restart, plus various related bugs.
Also move a large proportion of window initialisation from FluxboxWindow to
WinClient
rathnor rathnor
commit

09a5c23c5b099af531842ae7868e98bc8d717dac

parent

2e6baffb9bf988901f9fa02f651efc9b2528d7b5

M ChangeLogChangeLog

@@ -1,5 +1,10 @@

(Format: Year/Month/Day) Changes for 0.9.4: +*03/06/23: + * Add group persistence over a restart, + Move most winclient initialisation from FluxboxWindow to WinClient, + And fix a few bugs (Simon) + Screen.hh/cc WinClient.hh/cc Window.hh/cc Gnome.cc Slit.hh *03/06/20: * Moved SlitTheme and SlitClient out from Slit.cc into new files (Henrik) SlitClient.hh/cc, SlitTheme.hh
M RoadMapRoadMap

@@ -132,17 +132,17 @@ Approx Date: 23 June, 2003

Key Features: * Regular expression support in remember on several attributes (Simon) - - Save grouping so it persists over restart (Simon) + * Save grouping so it persists over restart (Simon) - Autogrouping functionality into remember (Simon) (this will thus get regexp matching etc) + Shaped menu/slit/toolbar (Henrik) - - Improved screen object placement (?) + * Improved screen object placement (Henrik) (will fix Maximize over slit/toolbar) Other Minor Features: - Add some sort of program launch function (Simon) - nls code - layers, remember, new stuff... (Both) Bugfixes/lower priority: - - Titlebar sometimes doesn't redraw properly + * Titlebar sometimes doesn't redraw properly - Fixes for 0.9.3 and previous (Both) ----------------------------------------------------------

@@ -187,4 +187,4 @@ Approx Date: 31 July, 2003

- Obviously any remaining bug-fixes and small tweaks. - Translations. - - Documentation.+ - Documentation.
M src/Gnome.ccsrc/Gnome.cc

@@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Gnome.cc,v 1.26 2003/06/12 14:28:00 fluxgen Exp $ +// $Id: Gnome.cc,v 1.27 2003/06/23 14:16:04 rathnor Exp $ #include "Gnome.hh"

@@ -223,9 +223,13 @@ #ifdef DEBUG

cerr<<__FILE__<<"("<<__LINE__<<"): setting workspace("<<val<< ") for window("<<&win<<")"<<endl; #endif // DEBUG - win.winClient().changeProperty(m_gnome_wm_win_workspace, - XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)&val, 1); + + FluxboxWindow::ClientList::iterator client_it = win.clientList().begin(); + FluxboxWindow::ClientList::iterator client_it_end = win.clientList().end(); + for (; client_it != client_it_end; ++client_it) + (*client_it)->changeProperty(m_gnome_wm_win_workspace, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&val, 1); } void Gnome::updateState(FluxboxWindow &win) {

@@ -238,18 +242,25 @@ state |= WIN_STATE_MINIMIZED;

if (win.isShaded()) state |= WIN_STATE_SHADED; - win.winClient().changeProperty(m_gnome_wm_win_state, - XA_CARDINAL, 32, - PropModeReplace, (unsigned char *)&state, 1); + FluxboxWindow::ClientList::iterator client_it = win.clientList().begin(); + FluxboxWindow::ClientList::iterator client_it_end = win.clientList().end(); + for (; client_it != client_it_end; ++client_it) + (*client_it)->changeProperty(m_gnome_wm_win_state, + XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&state, 1); } void Gnome::updateLayer(FluxboxWindow &win) { //TODO - map from flux layers to gnome ones // our layers are in the opposite direction to GNOME int layernum = Fluxbox::instance()->getDesktopLayer() - win.layerNum(); - win.winClient().changeProperty(m_gnome_wm_win_layer, - XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)&layernum, 1); + + FluxboxWindow::ClientList::iterator client_it = win.clientList().begin(); + FluxboxWindow::ClientList::iterator client_it_end = win.clientList().end(); + for (; client_it != client_it_end; ++client_it) + (*client_it)->changeProperty(m_gnome_wm_win_layer, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&layernum, 1); }
M src/Screen.ccsrc/Screen.cc

@@ -22,7 +22,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Screen.cc,v 1.189 2003/06/23 13:31:47 fluxgen Exp $ +// $Id: Screen.cc,v 1.190 2003/06/23 14:16:04 rathnor Exp $ #include "Screen.hh"

@@ -835,6 +835,16 @@ // update client lists

for_each(getWorkspacesList().begin(), getWorkspacesList().end(), mem_fun(&Workspace::updateClientmenu)); + // remove any grouping this is expecting + Groupables::iterator it = m_expecting_groups.begin(); + Groupables::iterator it_end = m_expecting_groups.end(); + for (; it != it_end; ++it) { + if (it->second == &client) { + m_expecting_groups.erase(it); + // it should only be in there a maximum of once + break; + } + } } FluxboxWindow *BScreen::getIcon(unsigned int index) {

@@ -1106,23 +1116,31 @@ }

} FluxboxWindow *BScreen::createWindow(Window client) { - FluxboxWindow *win = new FluxboxWindow(client, *this, - winFrameTheme(), *menuTheme(), - *layerManager().getLayer(Fluxbox::instance()->getNormalLayer())); - + WinClient *winclient = new WinClient(client, *this); + #ifdef SLIT - if (win->initialState() == WithdrawnState) { - delete win; - win = 0; + if (winclient->initial_state == WithdrawnState) { + delete winclient; slit()->addClient(client); return 0; } #endif // SLIT + // check if it should be grouped with something else + FluxboxWindow *win; + if ((win = findGroupLeft(*winclient)) != 0) { + win->attachClient(*winclient); + } else { + win = new FluxboxWindow(*winclient, *this, + winFrameTheme(), *menuTheme(), + *layerManager().getLayer(Fluxbox::instance()->getNormalLayer())); + } + if (!win->isManaged()) { delete win; return 0; } else { + // always put on end of focused list, if it gets focused it'll get pushed up // there is only the one win client at this stage if (doFocusNew())

@@ -1135,9 +1153,18 @@ Fluxbox::instance()->saveWindowSearch(client, win);

setupWindowActions(*win); Fluxbox::instance()->attachSignals(*win); } - if (win->workspaceNumber() == currentWorkspaceID() || win->isStuck()) { + + // we also need to check if another window expects this window to the left + // and if so, then join it. + FluxboxWindow *otherwin = 0; + // TODO: does this do the right stuff focus-wise? + if ((otherwin = findGroupRight(*winclient)) && otherwin != win) + win->attachClient(otherwin->winClient()); + + if (!win->isIconic() && (win->workspaceNumber() == currentWorkspaceID() || win->isStuck())) { win->show(); } + XSync(FbTk::App::instance()->display(), False); return win; }

@@ -2349,10 +2376,16 @@ if (cycling_focus) {

cycling_focus = false; cycling_last = 0; // put currently focused window to top - WinClient *client = *cycling_window; - focused_list.erase(cycling_window); - focused_list.push_front(client); - client->fbwindow()->raise(); + // the iterator may be invalid if the window died + // in which case we'll do a proper revert focus + if (cycling_window != focused_list.end()) { + WinClient *client = *cycling_window; + focused_list.erase(cycling_window); + focused_list.push_front(client); + client->fbwindow()->raise(); + } else { + Fluxbox::instance()->revertFocus(*this); + } } }

@@ -2407,6 +2440,45 @@

} +/** + * Find the group of windows to this window's left + * So, we check the leftgroup hint, and see if we know any windows + */ +FluxboxWindow *BScreen::findGroupLeft(WinClient &winclient) { + Window w = winclient.getGroupLeftWindow(); + if (w == None) + return 0; + + FluxboxWindow *fbwin = Fluxbox::instance()->searchWindow(w); + + if (!fbwin) { + // not found, add it to expecting + m_expecting_groups[w] = &winclient; + } else if (&fbwin->screen() != &winclient.screen()) + // something is not consistent + return 0; + + return fbwin; +} + +FluxboxWindow *BScreen::findGroupRight(WinClient &winclient) { + Groupables::iterator it = m_expecting_groups.find(winclient.window()); + if (it == m_expecting_groups.end()) + return 0; + + // yay, this'll do. + WinClient *other = it->second; + m_expecting_groups.erase(it); // don't expect it anymore + + // forget about it if it isn't the left-most client in the group, plus + // it must have the atom set on it (i.e. previously encountered by fluxbox) + // for us to check our expecting + if (!winclient.hasGroupLeftWindow() || + other->getGroupLeftWindow() != None) + return 0; + + return other->m_win; +} void BScreen::initXinerama() { #ifdef XINERAMA Display *display = FbTk::App::instance()->display();

@@ -2544,3 +2616,17 @@ // saveToolbarOnHead(head);

tbar.reconfigure(); } +// TODO: when toolbar gets its resources moved into Toolbar.hh/cc, then +// this can be gone and a consistent interface for the two used +// on the actual objects +template <> +int BScreen::getOnHead<Slit>(Slit &slit) { + return slit.getOnHead(); +} + +template <> +void BScreen::setOnHead<Slit>(Slit &slit, int head) { + slit.saveOnHead(head); + slit.reconfigure(); +} +
M src/Screen.hhsrc/Screen.hh

@@ -22,7 +22,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Screen.hh,v 1.108 2003/06/23 12:57:36 fluxgen Exp $ +// $Id: Screen.hh,v 1.109 2003/06/23 14:16:04 rathnor Exp $ #ifndef SCREEN_HH #define SCREEN_HH

@@ -295,6 +295,12 @@

template <typename OnHeadObject> void setOnHead(OnHeadObject &obj, int head); + // grouping - we want ordering, so we can either search for a + // group to the left, or to the right (they'll be different if + // they exist). + FluxboxWindow *findGroupLeft(WinClient &winclient); + FluxboxWindow *findGroupRight(WinClient &winclient); + // notify netizens void updateNetizenCurrentWorkspace(); void updateNetizenWorkspaceCount();

@@ -418,6 +424,11 @@ int date_format;

} resource; + + // This is a map of windows to clients for clients that had a left + // window set, but that window wasn't present at the time + typedef std::map<Window, WinClient *> Groupables; + Groupables m_expecting_groups; const std::string m_name, m_altname; FbTk::ResourceManager &m_resource_manager;
M src/Slit.hhsrc/Slit.hh

@@ -22,7 +22,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -/// $Id: Slit.hh,v 1.33 2003/06/22 12:32:08 fluxgen Exp $ +/// $Id: Slit.hh,v 1.34 2003/06/23 14:16:04 rathnor Exp $ #ifndef SLIT_HH #define SLIT_HH

@@ -67,6 +67,8 @@ inline bool isHidden() const { return m_hidden; }

inline bool doAutoHide() const { return *m_rc_auto_hide; } inline Direction direction() const { return *m_rc_direction; } inline Placement placement() const { return *m_rc_placement; } + inline int getOnHead() const { return *m_rc_on_head; } + inline void saveOnHead(int head) { m_rc_on_head = head; } FbTk::Menu &menu() { return m_slitmenu; } inline const FbTk::FbWindow &window() const { return frame.window; }
M src/WinClient.ccsrc/WinClient.cc

@@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: WinClient.cc,v 1.13 2003/06/22 12:35:03 fluxgen Exp $ +// $Id: WinClient.cc,v 1.14 2003/06/23 14:16:05 rathnor Exp $ #include "WinClient.hh"

@@ -38,7 +38,7 @@ #include <cassert>

using namespace std; -WinClient::WinClient(Window win, FluxboxWindow &fbwin):FbTk::FbWindow(win), +WinClient::WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin):FbTk::FbWindow(win), transient_for(0), window_group(0), x(0), y(0), old_bw(0),

@@ -52,12 +52,20 @@ win_gravity(0),

initial_state(0), normal_hint_flags(0), wm_hint_flags(0), - mwm_hint(0), - blackbox_hint(0), - m_win(&fbwin), + send_focus_message(false), + m_win(fbwin), modal(false), m_title(""), m_icon_title(""), - m_diesig(*this), m_screen(fbwin.screen()) { } + m_class_name(""), m_instance_name(""), + m_blackbox_hint(0), + m_mwm_hint(0), + m_focus_mode(F_PASSIVE), + m_diesig(*this), m_screen(screen) { + updateBlackboxHints(); + updateMWMHints(); + updateWMHints(); + updateWMNormalHints(); +} WinClient::~WinClient() { #ifdef DEBUG

@@ -90,11 +98,11 @@ fluxbox->removeGroupSearch(window_group);

window_group = 0; } - if (mwm_hint != 0) - XFree(mwm_hint); + if (m_mwm_hint != 0) + XFree(m_mwm_hint); - if (blackbox_hint != 0) - XFree(blackbox_hint); + if (m_blackbox_hint != 0) + XFree(m_blackbox_hint); if (window()) fluxbox->removeWindowSearch(window());

@@ -126,6 +134,9 @@

} void WinClient::sendFocus() { + if (!send_focus_message) + return; + Display *disp = FbTk::App::instance()->display(); // setup focus msg XEvent ce;

@@ -264,7 +275,7 @@ void WinClient::updateIconTitle() {

XTextProperty text_prop; char **list = 0; int num = 0; - + if (getWMIconName(text_prop)) { if (text_prop.value && text_prop.nitems > 0) { if (text_prop.encoding != XA_STRING) {

@@ -288,3 +299,212 @@ } else

m_icon_title = title(); } + +void WinClient::saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs) { + changeProperty(FbAtoms::instance()->getFluxboxAttributesAtom(), + PropModeReplace, XA_CARDINAL, 32, + (unsigned char *)&blackbox_attribs, + FluxboxWindow::PropBlackboxAttributesElements + ); +} + +void WinClient::updateBlackboxHints() { + int format; + Atom atom_return; + unsigned long num, len; + FbAtoms *atoms = FbAtoms::instance(); + + if (m_blackbox_hint) { + XFree(m_blackbox_hint); + m_blackbox_hint = 0; + } + + if (property(atoms->getFluxboxHintsAtom(), 0, + PropBlackboxHintsElements, False, + atoms->getFluxboxHintsAtom(), &atom_return, + &format, &num, &len, + (unsigned char **) &m_blackbox_hint) && + m_blackbox_hint) { + if (num != (unsigned)PropBlackboxHintsElements) { + XFree(m_blackbox_hint); + m_blackbox_hint = 0; + } + } +} + +void WinClient::updateMWMHints() { + int format; + Atom atom_return; + unsigned long num = 0, len = 0; + Atom motif_wm_hints = XInternAtom(FbTk::App::instance()->display(), "_MOTIF_WM_HINTS", False); + + if (m_mwm_hint) { + XFree(m_mwm_hint); + m_mwm_hint = 0; + } + + if (!(property(motif_wm_hints, 0, + PropMwmHintsElements, false, + motif_wm_hints, &atom_return, + &format, &num, &len, + (unsigned char **) &m_mwm_hint) && + m_mwm_hint)) { + if (num != static_cast<unsigned int>(PropMwmHintsElements)) { + XFree(m_mwm_hint); + m_mwm_hint = 0; + return; + } + } +} + +void WinClient::updateWMHints() { + XWMHints *wmhint = XGetWMHints(FbTk::App::instance()->display(), window()); + if (! wmhint) { + m_focus_mode = F_PASSIVE; + window_group = None; + initial_state = NormalState; + } else { + wm_hint_flags = wmhint->flags; + if (wmhint->flags & InputHint) { + if (wmhint->input) { + if (send_focus_message) + m_focus_mode = F_LOCALLYACTIVE; + else + m_focus_mode = F_PASSIVE; + } else { + if (send_focus_message) + m_focus_mode = F_GLOBALLYACTIVE; + else + m_focus_mode = F_NOINPUT; + } + } else + m_focus_mode = F_PASSIVE; + + if (wmhint->flags & StateHint) + initial_state = wmhint->initial_state; + else + initial_state = NormalState; + + if (wmhint->flags & WindowGroupHint) { + if (! window_group) + window_group = wmhint->window_group; + } else + window_group = None; + + XFree(wmhint); + } +} + + +void WinClient::updateWMNormalHints() { + long icccm_mask; + XSizeHints sizehint; + if (! XGetWMNormalHints(FbTk::App::instance()->display(), window(), &sizehint, &icccm_mask)) { + min_width = min_height = + base_width = base_height = + width_inc = height_inc = 1; + max_width = 0; // unbounded + max_height = 0; + min_aspect_x = min_aspect_y = + max_aspect_x = max_aspect_y = 1; + win_gravity = NorthWestGravity; + } else { + normal_hint_flags = sizehint.flags; + + if (sizehint.flags & PMinSize) { + min_width = sizehint.min_width; + min_height = sizehint.min_height; + } else + min_width = min_height = 1; + + if (sizehint.flags & PMaxSize) { + max_width = sizehint.max_width; + max_height = sizehint.max_height; + } else { + max_width = 0; // unbounded + max_height = 0; + } + + if (sizehint.flags & PResizeInc) { + width_inc = sizehint.width_inc; + height_inc = sizehint.height_inc; + } else + width_inc = height_inc = 1; + + if (sizehint.flags & PAspect) { + min_aspect_x = sizehint.min_aspect.x; + min_aspect_y = sizehint.min_aspect.y; + max_aspect_x = sizehint.max_aspect.x; + max_aspect_y = sizehint.max_aspect.y; + } else + min_aspect_x = min_aspect_y = + max_aspect_x = max_aspect_y = 1; + + if (sizehint.flags & PBaseSize) { + base_width = sizehint.base_width; + base_height = sizehint.base_height; + } else + base_width = base_height = 0; + + if (sizehint.flags & PWinGravity) + win_gravity = sizehint.win_gravity; + else + win_gravity = NorthWestGravity; + } +} + +Window WinClient::getGroupLeftWindow() const { + int format; + Atom atom_return; + unsigned long num = 0, len = 0; + Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + + Window *data = 0; + if (property(group_left_hint, 0, + 1, false, + XA_WINDOW, &atom_return, + &format, &num, &len, + (unsigned char **) &data) && + data) { + if (num != 1) { + XFree(data); + return None; + } else { + Window ret = *data; + XFree(data); + return ret; + } + } + return None; +} + + +void WinClient::setGroupLeftWindow(Window win) { + Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + changeProperty(group_left_hint, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &win, 1); +} + +bool WinClient::hasGroupLeftWindow() const { + int format; + Atom atom_return; + unsigned long num = 0, len = 0; + Atom group_left_hint = XInternAtom(FbTk::App::instance()->display(), "_FLUXBOX_GROUP_LEFT", False); + + Window *data = 0; + if (property(group_left_hint, 0, + 1, false, + XA_WINDOW, &atom_return, + &format, &num, &len, + (unsigned char **) &data) && + data) { + if (num != 1) { + XFree(data); + return false; + } else { + XFree(data); + return true; + } + } + return false; +}
M src/WinClient.hhsrc/WinClient.hh

@@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: WinClient.hh,v 1.7 2003/06/15 18:36:40 fluxgen Exp $ +// $Id: WinClient.hh,v 1.8 2003/06/23 14:16:05 rathnor Exp $ #ifndef WINCLIENT_HH #define WINCLIENT_HH

@@ -38,7 +38,7 @@ class WinClient:public FbTk::FbWindow {

public: typedef std::list<WinClient *> TransientList; - WinClient(Window win, FluxboxWindow &fbwin); + WinClient(Window win, BScreen &screen, FluxboxWindow *fbwin = 0); ~WinClient(); void updateRect(int x, int y, unsigned int width, unsigned int height);

@@ -80,6 +80,20 @@ const std::string &title() const { return m_title; }

const std::string &iconTitle() const { return m_icon_title; } const FluxboxWindow *fbwindow() const { return m_win; } FluxboxWindow *fbwindow() { return m_win; } + + static const int PropBlackboxHintsElements = 5; + static const int PropMwmHintsElements = 3; + + void updateBlackboxHints(); + void updateMWMHints(); + void updateWMHints(); + void updateWMNormalHints(); + + // grouping is tracked by remembering the window to the left in the group + Window getGroupLeftWindow() const; + void setGroupLeftWindow(Window win); + bool hasGroupLeftWindow() const; + /** !! TODO !! remove or move these to private

@@ -96,6 +110,7 @@ min_width, min_height, max_width, max_height, width_inc, height_inc,

min_aspect_x, min_aspect_y, max_aspect_x, max_aspect_y, base_width, base_height, win_gravity; unsigned long initial_state, normal_hint_flags, wm_hint_flags; + bool send_focus_message; // this structure only contains 3 elements... the Motif 2.0 structure contains // 5... we only need the first 3... so that is all we will define

@@ -105,8 +120,6 @@ unsigned long functions; // Motif wm functions

unsigned long decorations; // Motif wm decorations } MwmHints; - MwmHints *mwm_hint; - FluxboxWindow::BlackboxHints *blackbox_hint; FluxboxWindow *m_win; class WinClientSubj: public FbTk::Subject { public:

@@ -116,12 +129,28 @@ private:

WinClient &m_winclient; }; + inline int getFocusMode() const { return m_focus_mode; } + inline const FluxboxWindow::BlackboxHints *getBlackboxHint() const { + return m_blackbox_hint; } + void saveBlackboxAttribs(FluxboxWindow::BlackboxAttributes &blackbox_attribs); + inline const MwmHints *getMwmHint() const { return m_mwm_hint; } + + enum { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE }; + private: bool modal; + std::string m_title, m_icon_title; + std::string m_class_name, m_instance_name; + + FluxboxWindow::BlackboxHints *m_blackbox_hint; + MwmHints *m_mwm_hint; + + int m_focus_mode; + WinClientSubj m_diesig; BScreen &m_screen; - std::string m_class_name, m_instance_name; + }; #endif // WINCLIENT_HH
M src/Window.ccsrc/Window.cc

@@ -22,7 +22,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Window.cc,v 1.194 2003/06/22 21:29:32 fluxgen Exp $ +// $Id: Window.cc,v 1.195 2003/06/23 14:16:05 rathnor Exp $ #include "Window.hh"

@@ -61,6 +61,8 @@ #include <cstring>

#include <cstdio> #include <iostream> #include <cassert> +#include <functional> +#include <algorithm> using namespace std;

@@ -232,7 +234,7 @@ m_workspacesig(*this),

m_diesig(*this), moving(false), resizing(false), shaded(false), maximized(false), iconic(false), focused(false), - stuck(false), send_focus_message(false), m_managed(false), + stuck(false), m_managed(false), m_screen(scr), m_timer(this), display(0),

@@ -255,42 +257,6 @@ init();

} -FluxboxWindow::FluxboxWindow(Window w, BScreen &scr, FbWinFrameTheme &tm, - FbTk::MenuTheme &menutheme, - FbTk::XLayer &layer): - oplock(false), - m_hintsig(*this), - m_statesig(*this), - m_layersig(*this), - m_workspacesig(*this), - m_diesig(*this), - moving(false), resizing(false), shaded(false), maximized(false), - iconic(false), focused(false), - stuck(false), send_focus_message(false), m_managed(false), - m_screen(scr), - m_timer(this), - display(0), - m_layermenu(new LayerMenu<FluxboxWindow>(menutheme, - scr.screenNumber(), - scr.imageControl(), - *scr.layerManager().getLayer(Fluxbox::instance()->getMenuLayer()), - this, - false)), - m_windowmenu(menutheme, scr.screenNumber(), scr.imageControl()), - m_old_decoration(DECOR_NORMAL), - m_client(new WinClient(w, *this)), - m_frame(new FbWinFrame(tm, scr.imageControl(), scr.screenNumber(), 0, 0, 100, 100)), - m_strut(0), - m_layeritem(m_frame->window(), layer), - m_layernum(layer.getLayerNum()), - m_parent(scr.rootWindow()) { - assert(w != 0); - init(); - -} - - - FluxboxWindow::~FluxboxWindow() { #ifdef DEBUG cerr<<__FILE__<<"("<<__LINE__<<"): starting ~FluxboxWindow("<<this<<")"<<endl;

@@ -344,7 +310,10 @@ // so parent menu don't kill us

m_layermenu->setInternalMenu(); m_attaching_tab = 0; + assert(m_client); + m_client->m_win = this; + m_client->setGroupLeftWindow(None); // nothing to the left. // check for shape extension and whether the window is shaped m_shaped = false;

@@ -433,16 +402,17 @@

functions.resize = functions.move = functions.iconify = functions.maximize = true; functions.close = decorations.close = false; - getBlackboxHints(); - if (! m_client->blackbox_hint) + if (m_client->getBlackboxHint() != 0) + getBlackboxHints(); + else getMWMHints(); // get size, aspect, minimum/maximum size and other hints set // by the client getWMProtocols(); - getWMHints(); - getWMNormalHints(); + if (m_client->window_group != None) + Fluxbox::instance()->saveGroupSearch(m_client->window_group, this); //!! // fetch client size and placement

@@ -589,13 +559,23 @@ // reparent client win to this frame

frame().setClientWindow(client); FbTk::EventManager &evm = *FbTk::EventManager::instance(); + // get the current window on the end of our client list + Window leftwin = None; + ClientList::iterator client_it = clientList().end(); + ClientList::iterator client_it_end = clientList().end(); + --client_it; + if (client_it != client_it_end) + leftwin = (*client_it)->window(); + + client.setGroupLeftWindow(leftwin); + if (client.fbwindow() != 0) { FluxboxWindow *old_win = client.fbwindow(); // store old window Fluxbox *fb = Fluxbox::instance(); // make sure we set new window search for each client - ClientList::iterator client_it = old_win->clientList().begin(); - ClientList::iterator client_it_end = old_win->clientList().end(); + client_it = old_win->clientList().begin(); + client_it_end = old_win->clientList().end(); for (; client_it != client_it_end; ++client_it) { // setup eventhandlers for client fb->saveWindowSearch((*client_it)->window(), this);

@@ -628,10 +608,12 @@ set_client_cmd(new SetClientCmd(*(*client_it)));

btn->setOnClick(set_client_cmd); evm.add(*this, btn->window()); // we take care of button events for this + (*client_it)->saveBlackboxAttribs(m_blackbox_attrib); } // add client and move over all attached clients // from the old window to this list + // all the "left window"s will remain the same, except for the first. m_clientlist.splice(m_clientlist.end(), old_win->m_clientlist); old_win->m_client = 0;

@@ -659,7 +641,15 @@

client.m_win = this; Fluxbox::instance()->saveWindowSearch(client.window(), this); + client.saveBlackboxAttribs(m_blackbox_attrib); } + + // make sure that the state etc etc is updated for the new client + // TODO: one day these should probably be neatened to only act on the + // affected clients if possible + m_statesig.notify(); + m_workspacesig.notify(); + m_layersig.notify(); frame().reconfigure();

@@ -889,7 +879,7 @@ for (int i = 0; i < num_return; ++i) {

if (proto[i] == fbatoms->getWMDeleteAtom()) functions.close = true; else if (proto[i] == fbatoms->getWMTakeFocusAtom()) - send_focus_message = true; + m_client->send_focus_message = true; else if (proto[i] == fbatoms->getFluxboxStructureMessagesAtom()) screen().addNetizen(m_client->window()); }

@@ -902,125 +892,13 @@

} -void FluxboxWindow::getWMHints() { - //!! - XWMHints *wmhint = XGetWMHints(display, m_client->window()); - if (! wmhint) { - iconic = false; - m_focus_mode = F_PASSIVE; - m_client->window_group = None; - m_client->initial_state = NormalState; - } else { - m_client->wm_hint_flags = wmhint->flags; - if (wmhint->flags & InputHint) { - if (wmhint->input) { - if (send_focus_message) - m_focus_mode = F_LOCALLYACTIVE; - else - m_focus_mode = F_PASSIVE; - } else { - if (send_focus_message) - m_focus_mode = F_GLOBALLYACTIVE; - else - m_focus_mode = F_NOINPUT; - } - } else - m_focus_mode = F_PASSIVE; - - if (wmhint->flags & StateHint) - m_client->initial_state = wmhint->initial_state; - else - m_client->initial_state = NormalState; - - if (wmhint->flags & WindowGroupHint) { - if (! m_client->window_group) { - m_client->window_group = wmhint->window_group; - Fluxbox::instance()->saveGroupSearch(m_client->window_group, this); - } - } else - m_client->window_group = None; - - XFree(wmhint); - } -} - - -void FluxboxWindow::getWMNormalHints() { - long icccm_mask; - XSizeHints sizehint; - if (! XGetWMNormalHints(display, m_client->window(), &sizehint, &icccm_mask)) { - m_client->min_width = m_client->min_height = - m_client->base_width = m_client->base_height = - m_client->width_inc = m_client->height_inc = 1; - m_client->max_width = 0; // unbounded - m_client->max_height = 0; - m_client->min_aspect_x = m_client->min_aspect_y = - m_client->max_aspect_x = m_client->max_aspect_y = 1; - m_client->win_gravity = NorthWestGravity; - } else { - m_client->normal_hint_flags = sizehint.flags; - - if (sizehint.flags & PMinSize) { - m_client->min_width = sizehint.min_width; - m_client->min_height = sizehint.min_height; - } else - m_client->min_width = m_client->min_height = 1; - - if (sizehint.flags & PMaxSize) { - m_client->max_width = sizehint.max_width; - m_client->max_height = sizehint.max_height; - } else { - m_client->max_width = 0; // unbounded - m_client->max_height = 0; - } - - if (sizehint.flags & PResizeInc) { - m_client->width_inc = sizehint.width_inc; - m_client->height_inc = sizehint.height_inc; - } else - m_client->width_inc = m_client->height_inc = 1; - - if (sizehint.flags & PAspect) { - m_client->min_aspect_x = sizehint.min_aspect.x; - m_client->min_aspect_y = sizehint.min_aspect.y; - m_client->max_aspect_x = sizehint.max_aspect.x; - m_client->max_aspect_y = sizehint.max_aspect.y; - } else - m_client->min_aspect_x = m_client->min_aspect_y = - m_client->max_aspect_x = m_client->max_aspect_y = 1; +void FluxboxWindow::getMWMHints() { + const WinClient::MwmHints *hint = m_client->getMwmHint(); - if (sizehint.flags & PBaseSize) { - m_client->base_width = sizehint.base_width; - m_client->base_height = sizehint.base_height; - } else - m_client->base_width = m_client->base_height = 0; + if (!hint) return; - if (sizehint.flags & PWinGravity) - m_client->win_gravity = sizehint.win_gravity; - else - m_client->win_gravity = NorthWestGravity; - } -} - - -void FluxboxWindow::getMWMHints() { - int format; - Atom atom_return; - unsigned long num, len; - Atom motif_wm_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False); - if (!(m_client->property(motif_wm_hints, 0, - PropMwmHintsElements, false, - motif_wm_hints, &atom_return, - &format, &num, &len, - (unsigned char **) &m_client->mwm_hint) && - m_client->mwm_hint)) { - return; - } - if (num != static_cast<unsigned int>(PropMwmHintsElements)) - return; - - if (m_client->mwm_hint->flags & MwmHintsDecorations) { - if (m_client->mwm_hint->decorations & MwmDecorAll) { + if (hint->flags & MwmHintsDecorations) { + if (hint->decorations & MwmDecorAll) { decorations.titlebar = decorations.handle = decorations.border = decorations.iconify = decorations.maximize = decorations.close = decorations.menu = true;

@@ -1029,41 +907,41 @@ decorations.titlebar = decorations.handle = decorations.border =

decorations.iconify = decorations.maximize = decorations.close = decorations.tab = false; decorations.menu = true; - if (m_client->mwm_hint->decorations & MwmDecorBorder) + if (hint->decorations & MwmDecorBorder) decorations.border = true; - if (m_client->mwm_hint->decorations & MwmDecorHandle) + if (hint->decorations & MwmDecorHandle) decorations.handle = true; - if (m_client->mwm_hint->decorations & MwmDecorTitle) { + if (hint->decorations & MwmDecorTitle) { //only tab on windows with titlebar decorations.titlebar = decorations.tab = true; } - if (m_client->mwm_hint->decorations & MwmDecorMenu) + if (hint->decorations & MwmDecorMenu) decorations.menu = true; - if (m_client->mwm_hint->decorations & MwmDecorIconify) + if (hint->decorations & MwmDecorIconify) decorations.iconify = true; - if (m_client->mwm_hint->decorations & MwmDecorMaximize) + if (hint->decorations & MwmDecorMaximize) decorations.maximize = true; } } - if (m_client->mwm_hint->flags & MwmHintsFunctions) { - if (m_client->mwm_hint->functions & MwmFuncAll) { + if (hint->flags & MwmHintsFunctions) { + if (hint->functions & MwmFuncAll) { functions.resize = functions.move = functions.iconify = functions.maximize = functions.close = true; } else { functions.resize = functions.move = functions.iconify = functions.maximize = functions.close = false; - if (m_client->mwm_hint->functions & MwmFuncResize) + if (hint->functions & MwmFuncResize) functions.resize = true; - if (m_client->mwm_hint->functions & MwmFuncMove) + if (hint->functions & MwmFuncMove) functions.move = true; - if (m_client->mwm_hint->functions & MwmFuncIconify) + if (hint->functions & MwmFuncIconify) functions.iconify = true; - if (m_client->mwm_hint->functions & MwmFuncMaximize) + if (hint->functions & MwmFuncMaximize) functions.maximize = true; - if (m_client->mwm_hint->functions & MwmFuncClose) + if (hint->functions & MwmFuncClose) functions.close = true; } }

@@ -1073,50 +951,37 @@ }

void FluxboxWindow::getBlackboxHints() { - int format; - Atom atom_return; - unsigned long num, len; - FbAtoms *atoms = FbAtoms::instance(); - - if (XGetWindowProperty(display, m_client->window(), - atoms->getFluxboxHintsAtom(), 0, - PropBlackboxHintsElements, False, - atoms->getFluxboxHintsAtom(), &atom_return, - &format, &num, &len, - (unsigned char **) &m_client->blackbox_hint) == Success && - m_client->blackbox_hint) { + const FluxboxWindow::BlackboxHints *hint = m_client->getBlackboxHint(); + if (!hint) return; - if (num == (unsigned)PropBlackboxHintsElements) { - if (m_client->blackbox_hint->flags & ATTRIB_SHADED) - shaded = (m_client->blackbox_hint->attrib & ATTRIB_SHADED); + if (hint->flags & ATTRIB_SHADED) + shaded = (hint->attrib & ATTRIB_SHADED); - if ((m_client->blackbox_hint->flags & ATTRIB_MAXHORIZ) && - (m_client->blackbox_hint->flags & ATTRIB_MAXVERT)) - maximized = ((m_client->blackbox_hint->attrib & - (ATTRIB_MAXHORIZ | - ATTRIB_MAXVERT)) ? 1 : 0); - else if (m_client->blackbox_hint->flags & ATTRIB_MAXVERT) - maximized = ((m_client->blackbox_hint->attrib & - ATTRIB_MAXVERT) ? 2 : 0); - else if (m_client->blackbox_hint->flags & ATTRIB_MAXHORIZ) - maximized = ((m_client->blackbox_hint->attrib & - ATTRIB_MAXHORIZ) ? 3 : 0); + if ((hint->flags & ATTRIB_MAXHORIZ) && + (hint->flags & ATTRIB_MAXVERT)) + maximized = ((hint->attrib & + (ATTRIB_MAXHORIZ | + ATTRIB_MAXVERT)) ? 1 : 0); + else if (hint->flags & ATTRIB_MAXVERT) + maximized = ((hint->attrib & + ATTRIB_MAXVERT) ? 2 : 0); + else if (hint->flags & ATTRIB_MAXHORIZ) + maximized = ((hint->attrib & + ATTRIB_MAXHORIZ) ? 3 : 0); - if (m_client->blackbox_hint->flags & ATTRIB_OMNIPRESENT) - stuck = (m_client->blackbox_hint->attrib & - ATTRIB_OMNIPRESENT); + if (hint->flags & ATTRIB_OMNIPRESENT) + stuck = (hint->attrib & + ATTRIB_OMNIPRESENT); - if (m_client->blackbox_hint->flags & ATTRIB_WORKSPACE) - m_workspace_number = m_client->blackbox_hint->workspace; + if (hint->flags & ATTRIB_WORKSPACE) + m_workspace_number = hint->workspace; - if (m_client->blackbox_hint->flags & ATTRIB_STACK) - m_workspace_number = m_client->blackbox_hint->stack; + if (hint->flags & ATTRIB_STACK) + m_workspace_number = hint->stack; - if (m_client->blackbox_hint->flags & ATTRIB_DECORATION) { - m_old_decoration = static_cast<Decoration>(m_client->blackbox_hint->decoration); - setDecoration(m_old_decoration); - } - } + if (hint->flags & ATTRIB_DECORATION) { + m_old_decoration = static_cast<Decoration>(hint->decoration); + setDecoration(m_old_decoration); } }

@@ -1201,7 +1066,7 @@ if ((*it)->isModal())

return (*it)->fbwindow()->setCurrentClient(**it, true); } } else { - if (m_focus_mode == F_LOCALLYACTIVE || m_focus_mode == F_PASSIVE) { + if (m_client->getFocusMode() == WinClient::F_LOCALLYACTIVE || m_client->getFocusMode() == WinClient::F_PASSIVE) { XSetInputFocus(display, m_client->window(), RevertToPointerRoot, CurrentTime); } else {

@@ -1214,8 +1079,7 @@ Fluxbox::instance()->setFocusedWindow(this);

frame().setFocus(true); - if (send_focus_message) - m_client->sendFocus(); + m_client->sendFocus(); if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus()) && screen().doAutoRaise())

@@ -1428,7 +1292,7 @@ m_layernum = layernum;

m_blackbox_attrib.flags |= ATTRIB_STACK; m_blackbox_attrib.stack = layernum; - saveBlackboxHints(); + saveBlackboxAttribs(); #ifdef DEBUG cerr<<this<<" notify layer signal"<<endl;

@@ -1688,14 +1552,18 @@ fluxbox->ungrab();

} /** - Saves blackbox hints for every client in our list + Saves blackbox attributes for every client in our list */ -void FluxboxWindow::saveBlackboxHints() { +void FluxboxWindow::saveBlackboxAttribs() { for_each(m_clientlist.begin(), m_clientlist.end(), - FbTk::ChangeProperty(display, FbAtoms::instance()->getFluxboxAttributesAtom(), - PropModeReplace, - (unsigned char *)&m_blackbox_attrib, - PropBlackboxAttributesElements)); + FbTk::ChangeProperty( + display, + FbAtoms::instance()->getFluxboxAttributesAtom(), + PropModeReplace, + (unsigned char *)&m_blackbox_attrib, + PropBlackboxAttributesElements + ) + ); } /**

@@ -1715,7 +1583,7 @@ FbTk::ChangeProperty(display, FbAtoms::instance()->getWMStateAtom(),

PropModeReplace, (unsigned char *)state, 2)); - saveBlackboxHints(); + saveBlackboxAttribs(); //notify state changed m_statesig.notify(); }

@@ -1833,7 +1701,11 @@ if (m_client->property(fbatoms->getFluxboxAttributesAtom(), 0l,

PropBlackboxAttributesElements, false, fbatoms->getFluxboxAttributesAtom(), &atom_return, &foo, &nitems, &ulfoo, (unsigned char **) &net) && - net && nitems == (unsigned)PropBlackboxAttributesElements) { + net) { + if (nitems != (unsigned)PropBlackboxAttributesElements) { + XFree(net); + return; + } m_blackbox_attrib.flags = net->flags; m_blackbox_attrib.attrib = net->attrib; m_blackbox_attrib.workspace = net->workspace;

@@ -2179,7 +2051,7 @@

} break; case XA_WM_HINTS: - getWMHints(); + m_client->updateWMHints(); break; case XA_WM_ICON_NAME:

@@ -2199,7 +2071,7 @@

break; case XA_WM_NORMAL_HINTS: { - getWMNormalHints(); + m_client->updateWMNormalHints(); if ((m_client->normal_hint_flags & PMinSize) && (m_client->normal_hint_flags & PMaxSize)) {
M src/Window.hhsrc/Window.hh

@@ -22,7 +22,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// $Id: Window.hh,v 1.79 2003/06/18 13:55:16 fluxgen Exp $ +// $Id: Window.hh,v 1.80 2003/06/23 14:16:05 rathnor Exp $ #ifndef WINDOW_HH #define WINDOW_HH

@@ -103,10 +103,6 @@ ATTRIB_STACK = 0x20,

ATTRIB_DECORATION = 0x40 }; - static const int PropBlackboxHintsElements = 5; - static const int PropBlackboxAttributesElements = 8; - static const int PropMwmHintsElements = 3; - typedef struct _blackbox_hints { unsigned long flags, attrib, workspace, stack; int decoration;

@@ -126,11 +122,6 @@ FbWinFrameTheme &tm,

FbTk::MenuTheme &menutheme, FbTk::XLayer &layer); - /// create fluxbox window with parent win and screen connection - FluxboxWindow(Window win, BScreen &scr, - FbWinFrameTheme &tm, - FbTk::MenuTheme &menutheme, - FbTk::XLayer &layer); virtual ~FluxboxWindow(); /// attach client to our client list and remove it from old window

@@ -148,7 +139,7 @@ void nextClient();

void prevClient(); void setWindowNumber(int n) { m_window_number = n; } - + bool validateClient(); bool setInputFocus(); void raiseAndFocus() { raise(); setInputFocus(); }

@@ -222,7 +213,7 @@

void setDecoration(Decoration decoration); void applyDecorations(); void toggleDecoration(); - + /** This enumeration represents individual decoration attributes, they can be OR-d together to get a mask.

@@ -334,7 +325,7 @@

const timeval &lastFocusTime() const { return m_last_focus_time;} //@} - + class WinSubject: public FbTk::Subject { public: WinSubject(FluxboxWindow &w):m_win(w) { }

@@ -348,6 +339,8 @@ bool oplock; // Used to help stop transient loops occurring by locking a window

// during certain operations private: + static const int PropBlackboxAttributesElements = 8; + void init(); /// applies a shape mask to the window if it has one void shape();

@@ -367,15 +360,13 @@ /// gets title string from client window and updates frame's title

void updateTitleFromClient(); /// gets icon name from client window void updateIconNameFromClient(); - void getWMNormalHints(); void getWMProtocols(); - void getWMHints(); void getMWMHints(); void getBlackboxHints(); - void saveBlackboxHints(); + void saveBlackboxAttribs(); void setNetWMAttributes(); void associateClientWindow(); - + void restoreGravity(); void setGravityOffsets(); void setState(unsigned long stateval);

@@ -394,7 +385,7 @@ WinSubject m_hintsig, m_statesig, m_layersig, m_workspacesig, m_diesig;

// Window states bool moving, resizing, shaded, maximized, iconic, - focused, stuck, send_focus_message, m_managed; + focused, stuck, m_managed; WinClient *m_attaching_tab;

@@ -406,15 +397,15 @@

std::auto_ptr<FbTk::Menu> m_layermenu; FbTk::Menu m_windowmenu; - + timeval m_last_focus_time; - + int m_button_grab_x, m_button_grab_y; // handles last button press event for move int m_last_resize_x, m_last_resize_y; // handles last button press event for resize int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving unsigned int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" - int m_focus_mode, m_window_number; + int m_window_number; unsigned int m_workspace_number; unsigned long m_current_state;

@@ -451,8 +442,6 @@ FbTk::XLayerItem m_layeritem;

int m_layernum; FbTk::FbWindow &m_parent; ///< window on which we draw move/resize rectangle (the "root window") - - enum { F_NOINPUT = 0, F_PASSIVE, F_LOCALLYACTIVE, F_GLOBALLYACTIVE }; };