From 09a5c23c5b099af531842ae7868e98bc8d717dac Mon Sep 17 00:00:00 2001 From: rathnor Date: Mon, 23 Jun 2003 14:16:05 +0000 Subject: fix grouping to persist over restart, plus various related bugs. Also move a large proportion of window initialisation from FluxboxWindow to WinClient --- ChangeLog | 5 + RoadMap | 8 +- src/Gnome.cc | 31 +++-- src/Screen.cc | 112 +++++++++++++++--- src/Screen.hh | 13 ++- src/Slit.hh | 4 +- src/WinClient.cc | 242 +++++++++++++++++++++++++++++++++++++-- src/WinClient.hh | 39 ++++++- src/Window.cc | 338 +++++++++++++++++-------------------------------------- src/Window.hh | 35 ++---- 10 files changed, 526 insertions(+), 301 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b01866..9309e59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/RoadMap b/RoadMap index 08c1c7e..5cc34c4 100644 --- a/RoadMap +++ b/RoadMap @@ -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. \ No newline at end of file + - Documentation. diff --git a/src/Gnome.cc b/src/Gnome.cc index 6eef315..2b12b7f 100644 --- a/src/Gnome.cc +++ b/src/Gnome.cc @@ -19,7 +19,7 @@ // 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 @@ void Gnome::updateWorkspace(FluxboxWindow &win) { cerr<<__FILE__<<"("<<__LINE__<<"): setting workspace("<changeProperty(m_gnome_wm_win_workspace, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&val, 1); } void Gnome::updateState(FluxboxWindow &win) { @@ -238,18 +242,25 @@ void Gnome::updateState(FluxboxWindow &win) { 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); } diff --git a/src/Screen.cc b/src/Screen.cc index 7337b9f..c8a2344 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -22,7 +22,7 @@ // 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 @@ void BScreen::removeClient(WinClient &client) { 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 @@ void BScreen::updateNetizenConfigNotify(XEvent *e) { } 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 @@ FluxboxWindow *BScreen::createWindow(Window client) { 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 @@ void BScreen::notifyReleasedKeys(XKeyEvent &ke) { 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 @@ void BScreen::updateSize() { } +/** + * 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 @@ void BScreen::setOnHead(Toolbar &tbar, int 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) { + return slit.getOnHead(); +} + +template <> +void BScreen::setOnHead(Slit &slit, int head) { + slit.saveOnHead(head); + slit.reconfigure(); +} + diff --git a/src/Screen.hh b/src/Screen.hh index 920347b..78a0215 100644 --- a/src/Screen.hh +++ b/src/Screen.hh @@ -22,7 +22,7 @@ // 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 @@ public: template 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(); @@ -419,6 +425,11 @@ private: } 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 Groupables; + Groupables m_expecting_groups; + const std::string m_name, m_altname; FbTk::ResourceManager &m_resource_manager; diff --git a/src/Slit.hh b/src/Slit.hh index c83a50f..642e50f 100644 --- a/src/Slit.hh +++ b/src/Slit.hh @@ -22,7 +22,7 @@ // 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 @@ public: 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; } diff --git a/src/WinClient.cc b/src/WinClient.cc index 88be980..c0079e4 100644 --- a/src/WinClient.cc +++ b/src/WinClient.cc @@ -19,7 +19,7 @@ // 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 @@ 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 @@ WinClient::WinClient(Window win, FluxboxWindow &fbwin):FbTk::FbWindow(win), 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 @@ WinClient::~WinClient() { 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::updateRect(int x, int y, } 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 @@ void WinClient::updateIconTitle() { 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(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; +} diff --git a/src/WinClient.hh b/src/WinClient.hh index 30d6ff5..c72208f 100644 --- a/src/WinClient.hh +++ b/src/WinClient.hh @@ -19,7 +19,7 @@ // 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 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 diff --git a/src/Window.cc b/src/Window.cc index 2affa8e..be5d81f 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -22,7 +22,7 @@ // 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 #include #include +#include +#include using namespace std; @@ -232,7 +234,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, BScreen &scr, FbWinFrameTheme &t 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 @@ FluxboxWindow::FluxboxWindow(WinClient &client, BScreen &scr, FbWinFrameTheme &t } -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(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("<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 @@ void FluxboxWindow::init() { 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 @@ void FluxboxWindow::attachClient(WinClient &client) { 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 @@ void FluxboxWindow::attachClient(WinClient &client) { 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,8 +641,16 @@ void FluxboxWindow::attachClient(WinClient &client) { 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(); // keep the current window on top @@ -889,7 +879,7 @@ void FluxboxWindow::getWMProtocols() { 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::getWMProtocols() { } -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; - - 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 (sizehint.flags & PWinGravity) - m_client->win_gravity = sizehint.win_gravity; - else - m_client->win_gravity = NorthWestGravity; - } -} +void FluxboxWindow::getMWMHints() { + const WinClient::MwmHints *hint = m_client->getMwmHint(); + if (!hint) return; -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(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 @@ void FluxboxWindow::getMWMHints() { 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::getMWMHints() { 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) { - - if (num == (unsigned)PropBlackboxHintsElements) { - if (m_client->blackbox_hint->flags & ATTRIB_SHADED) - shaded = (m_client->blackbox_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 (m_client->blackbox_hint->flags & ATTRIB_OMNIPRESENT) - stuck = (m_client->blackbox_hint->attrib & - ATTRIB_OMNIPRESENT); - - if (m_client->blackbox_hint->flags & ATTRIB_WORKSPACE) - m_workspace_number = m_client->blackbox_hint->workspace; - - if (m_client->blackbox_hint->flags & ATTRIB_STACK) - m_workspace_number = m_client->blackbox_hint->stack; - - if (m_client->blackbox_hint->flags & ATTRIB_DECORATION) { - m_old_decoration = static_cast(m_client->blackbox_hint->decoration); - setDecoration(m_old_decoration); - } - } + const FluxboxWindow::BlackboxHints *hint = m_client->getBlackboxHint(); + if (!hint) return; + + if (hint->flags & ATTRIB_SHADED) + shaded = (hint->attrib & ATTRIB_SHADED); + + 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 (hint->flags & ATTRIB_OMNIPRESENT) + stuck = (hint->attrib & + ATTRIB_OMNIPRESENT); + + if (hint->flags & ATTRIB_WORKSPACE) + m_workspace_number = hint->workspace; + + if (hint->flags & ATTRIB_STACK) + m_workspace_number = hint->stack; + + if (hint->flags & ATTRIB_DECORATION) { + m_old_decoration = static_cast(hint->decoration); + setDecoration(m_old_decoration); } } @@ -1201,7 +1066,7 @@ bool FluxboxWindow::setInputFocus() { 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 @@ bool FluxboxWindow::setInputFocus() { frame().setFocus(true); - if (send_focus_message) - m_client->sendFocus(); + m_client->sendFocus(); if ((screen().isSloppyFocus() || screen().isSemiSloppyFocus()) && screen().doAutoRaise()) @@ -1428,7 +1292,7 @@ void FluxboxWindow::setLayerNum(int layernum) { m_blackbox_attrib.flags |= ATTRIB_STACK; m_blackbox_attrib.stack = layernum; - saveBlackboxHints(); + saveBlackboxAttribs(); #ifdef DEBUG cerr<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 @@ void FluxboxWindow::setState(unsigned long new_state) { PropModeReplace, (unsigned char *)state, 2)); - saveBlackboxHints(); + saveBlackboxAttribs(); //notify state changed m_statesig.notify(); } @@ -1833,7 +1701,11 @@ void FluxboxWindow::restoreAttributes() { 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 @@ void FluxboxWindow::propertyNotifyEvent(Atom atom) { } break; case XA_WM_HINTS: - getWMHints(); + m_client->updateWMHints(); break; case XA_WM_ICON_NAME: @@ -2199,7 +2071,7 @@ void FluxboxWindow::propertyNotifyEvent(Atom atom) { break; case XA_WM_NORMAL_HINTS: { - getWMNormalHints(); + m_client->updateWMNormalHints(); if ((m_client->normal_hint_flags & PMinSize) && (m_client->normal_hint_flags & PMaxSize)) { diff --git a/src/Window.hh b/src/Window.hh index 59a9084..1ffdb82 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -22,7 +22,7 @@ // 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 @@ public: 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 @@ public: 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 @@ public: void prevClient(); void setWindowNumber(int n) { m_window_number = n; } - + bool validateClient(); bool setInputFocus(); void raiseAndFocus() { raise(); setInputFocus(); } @@ -222,7 +213,7 @@ public: 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 @@ public: 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 @@ public: // 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 @@ private: 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 @@ private: // 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 @@ private: std::auto_ptr 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; @@ -452,8 +443,6 @@ private: 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 }; - }; -- cgit v0.11.2