From ad10a3543e278aea0dd8e1fb83fa79b93025d14b Mon Sep 17 00:00:00 2001 From: mathias <mathias> Date: Tue, 21 Dec 2004 16:17:14 +0000 Subject: fix a problem with enabling/disabling fullscreen-mode in gtk2-apps * synchronize _NET_WM_STATE in Ewmh.cc * added FluxboxWindow::setFullscreen(bool) to Window.cc furthermore, if a window is in fullscreenmode any existing shape is disabled (looks pretty annoying in mplayer for example) --- src/Ewmh.cc | 107 ++++++++++++++++++++++++++++++++++++++++++++++------------ src/Ewmh.hh | 27 +++++++++++---- src/Window.cc | 65 ++++++++++++++++++++++++++++++++++- src/Window.hh | 46 ++++++++++++++----------- 4 files changed, 196 insertions(+), 49 deletions(-) diff --git a/src/Ewmh.cc b/src/Ewmh.cc index b6c5b24..78ea63e 100644 --- a/src/Ewmh.cc +++ b/src/Ewmh.cc @@ -60,10 +60,28 @@ Ewmh::~Ewmh() { void Ewmh::initForScreen(BScreen &screen) { Display *disp = FbTk::App::instance()->display(); + /* From Extended Window Manager Hints, draft 1.3: + * + * _NET_SUPPORTING_WM_CHECK + * + * The Window Manager MUST set this property on the root window + * to be the ID of a child window created by himself, to indicate + * that a compliant window manager is active. The child window + * MUST also have the _NET_SUPPORTING_WM_CHECK property set to + * the ID of the child window. The child window MUST also have + * the _NET_WM_NAME property set to the name of the Window Manager. + * + * Rationale: The child window is used to distinguish an active + * Window Manager from a stale _NET_SUPPORTING_WM_CHECK property + * that happens to point to another window. If the + * _NET_SUPPORTING_WM_CHECK window on the client window is missing + * or not properly set, clients SHOULD assume that no conforming + * Window Manager is present. + */ Window wincheck = XCreateSimpleWindow(disp, screen.rootWindow().window(), - 0, 0, 5, 5, 0, 0, 0); + -10, -10, 5, 5, 0, 0, 0); if (wincheck != None) { // store the window so we can delete it later @@ -72,10 +90,10 @@ void Ewmh::initForScreen(BScreen &screen) { screen.rootWindow().changeProperty(m_net_supporting_wm_check, XA_WINDOW, 32, PropModeReplace, (unsigned char *) &wincheck, 1); XChangeProperty(disp, wincheck, m_net_supporting_wm_check, XA_WINDOW, 32, - PropModeReplace, (unsigned char *) &wincheck, 1); + PropModeReplace, (unsigned char *) &wincheck, 1); XChangeProperty(disp, wincheck, m_net_wm_name, XA_STRING, 8, - PropModeReplace, (unsigned char *) "Fluxbox", strlen("Fluxbox")); + PropModeReplace, (unsigned char *) "Fluxbox", strlen("Fluxbox")); } //set supported atoms @@ -86,9 +104,9 @@ void Ewmh::initForScreen(BScreen &screen) { // states that we support: m_net_wm_state_sticky, m_net_wm_state_shaded, - m_net_wm_state_maximized_horz, - m_net_wm_state_maximized_vert, - m_net_wm_state_fullscreen, + m_net_wm_state_maximized_horz, + m_net_wm_state_maximized_vert, + m_net_wm_state_fullscreen, m_net_wm_state_hidden, m_net_wm_state_skip_taskbar, @@ -170,6 +188,7 @@ void Ewmh::setupFrame(FluxboxWindow &win) { * Managers that do not recognize the extensions. * */ + win.winClient().property(m_net_wm_window_type, 0, 0x7fffffff, False, XA_ATOM, &ret_type, &fmt, &nitems, &bytes_after, &data); @@ -501,7 +520,39 @@ void Ewmh::updateWorkarea(BScreen &screen) { } void Ewmh::updateState(FluxboxWindow &win) { - //!! TODO + + // TODO: should we update the _NET_WM_ALLOWED_ACTIONS + // here too? + + std::vector<unsigned int> state; + + if (win.isStuck()) + state.push_back(m_net_wm_state_sticky); + if (win.isShaded()) + state.push_back(m_net_wm_state_shaded); + if (win.layerNum() == Fluxbox::instance()->getBottomLayer()) + state.push_back(m_net_wm_state_below); + if (win.layerNum() == Fluxbox::instance()->getAboveDockLayer()) + state.push_back(m_net_wm_state_above); + if (win.isFocusHidden()) { + state.push_back(m_net_wm_state_hidden); + state.push_back(m_net_wm_state_skip_taskbar); + } + if (win.isFullscreen()) { + state.push_back(m_net_wm_state_fullscreen); + } + + FluxboxWindow::ClientList::iterator it = win.clientList().begin(); + FluxboxWindow::ClientList::iterator it_end = win.clientList().end(); + + it = win.clientList().begin(); + for (; it != it_end; ++it) { + if (!state.empty()) + (*it)->changeProperty(m_net_wm_state, XA_ATOM, 32, PropModeReplace, + reinterpret_cast<unsigned char*>(&state.front()), state.size()); + else + (*it)->deleteProperty(m_net_wm_state); + } } void Ewmh::updateLayer(FluxboxWindow &win) { @@ -537,6 +588,7 @@ void Ewmh::updateWorkspace(FluxboxWindow &win) { // return true if we did handle the atom here bool Ewmh::checkClientMessage(const XClientMessageEvent &ce, BScreen * screen, WinClient * const winclient) { + if (ce.message_type == m_net_wm_desktop) { // ce.data.l[0] = workspace number // valid window @@ -581,7 +633,6 @@ bool Ewmh::checkClientMessage(const XClientMessageEvent &ce, toggleState(win, ce.data.l[1]); toggleState(win, ce.data.l[2]); } - return true; } else if (ce.message_type == m_net_number_of_desktops) { if (screen == 0) @@ -676,7 +727,7 @@ bool Ewmh::propertyNotify(WinClient &winclient, Atom the_property) { #endif // DEBUG updateStrut(winclient); return true; - } + } return false; } @@ -725,6 +776,18 @@ void Ewmh::createAtoms() { m_net_wm_state_above = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False); m_net_wm_state_below = XInternAtom(disp, "_NET_WM_STATE_BELOW", 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_strut = XInternAtom(disp, "_NET_WM_STRUT", False); m_net_wm_icon_geometry = XInternAtom(disp, "_NET_WM_ICON_GEOMETRY", False); @@ -739,6 +802,12 @@ void Ewmh::createAtoms() { void Ewmh::setFullscreen(FluxboxWindow &win, bool value) { // fullscreen implies maximised, above dock layer, // and no decorations (or decorations offscreen) + // + // TODO: do we need the WindowState etc here anymore? + // FluxboxWindow::setFullscreen() remembering old values + // already and set them... + // only reason i can see is that the user manually + // moved the (fullscreened) window WindowState *saved_state = getState(win); if (value) { // fullscreen on @@ -746,25 +815,17 @@ void Ewmh::setFullscreen(FluxboxWindow &win, bool value) { saved_state = new WindowState(win.x(), win.y(), win.width(), win.height(), win.layerNum(), win.decorationMask()); saveState(win, saved_state); - - // actually make it fullscreen - - // clear decorations - win.setDecorationMask(0); - - // be xinerama aware - BScreen &screen = win.screen(); - int head = screen.getHead(win.fbWindow()); - win.moveResize(screen.getHeadX(head), screen.getHeadY(head), - screen.getHeadWidth(head), screen.getHeadHeight(head)); - win.moveToLayer(Fluxbox::instance()->getAboveDockLayer()); + win.setFullscreen(true); } } else { // turn off fullscreen if (saved_state) { // no saved state, can't restore it + win.setFullscreen(false); + /* win.setDecorationMask(saved_state->decor); win.moveResize(saved_state->x, saved_state->y, saved_state->width, saved_state->height); win.moveToLayer(saved_state->layer); + */ clearState(win); saved_state = 0; } @@ -791,11 +852,13 @@ void Ewmh::setState(FluxboxWindow &win, Atom state, bool value) { (!value && win.isMaximized())) win.maximizeVertical(); } else if (state == m_net_wm_state_fullscreen) { // fullscreen + if ((value && !win.isFullscreen()) || + (!value && win.isFullscreen())) setFullscreen(win, value); } else if (state == m_net_wm_state_hidden || state == m_net_wm_state_skip_taskbar) { win.setFocusHidden(value); - win.setIconHidden(win.isFocusHidden()); + win.setIconHidden(value); } else if (state == m_net_wm_state_below) { // bottom layer if (value) win.moveToLayer(Fluxbox::instance()->getBottomLayer()); diff --git a/src/Ewmh.hh b/src/Ewmh.hh index b3f1593..ebd6350 100644 --- a/src/Ewmh.hh +++ b/src/Ewmh.hh @@ -36,7 +36,7 @@ public: void initForScreen(BScreen &screen); void setupFrame(FluxboxWindow &win); void setupClient(WinClient &winclient); - + void updateFocusedWindow(BScreen &screen, Window win); void updateClientList(BScreen &screen); void updateWorkspaceNames(BScreen &screen); @@ -51,7 +51,7 @@ public: void updateHints(FluxboxWindow &win); void updateWorkspace(FluxboxWindow &win); - bool checkClientMessage(const XClientMessageEvent &ce, + bool checkClientMessage(const XClientMessageEvent &ce, BScreen * screen, WinClient * const winclient); bool propertyNotify(WinClient &winclient, Atom the_property); @@ -63,9 +63,10 @@ public: void setFullscreen(FluxboxWindow &win, bool value); private: - + typedef struct WindowState { - WindowState(int x, int y, unsigned int width, unsigned int height, int layer, unsigned int decor); + WindowState(int x, int y, unsigned int width, unsigned int height, + int layer, unsigned int decor); int x, y, layer; unsigned int width, height, decor; } WindowState; @@ -88,7 +89,7 @@ private: Atom m_net_close_window, m_net_wm_moveresize; // application window properties - Atom m_net_properties, m_net_wm_name, m_net_wm_desktop, + Atom m_net_properties, m_net_wm_name, m_net_wm_desktop, // types m_net_wm_window_type, m_net_wm_window_type_dock, @@ -96,16 +97,28 @@ private: // states m_net_wm_state, m_net_wm_state_sticky, m_net_wm_state_shaded, - m_net_wm_state_maximized_horz, m_net_wm_state_maximized_vert, + m_net_wm_state_maximized_horz, 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_below, m_net_wm_state_above, + // allowed 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, + m_net_wm_strut, m_net_wm_icon_geometry, m_net_wm_icon, m_net_wm_pid, m_net_wm_handled_icons; - + // application protocols Atom m_net_wm_ping; diff --git a/src/Window.cc b/src/Window.cc index 83f8771..f1cef6d 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -280,7 +280,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, m_themelistener(*this), moving(false), resizing(false), shaded(false), iconic(false), focused(false), - stuck(false), m_managed(false), + stuck(false), m_managed(false), fullscreen(false), maximized(MAX_NONE), m_attaching_tab(0), m_screen(client.screen()), @@ -292,6 +292,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, m_workspace_number(0), m_current_state(0), m_old_decoration(DECOR_NORMAL), + m_old_decoration_mask(0), m_client(&client), m_toggled_decos(false), m_shaped(false), @@ -302,6 +303,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, m_frame(tm, client.screen().imageControl(), 0, 0, 100, 100), m_layeritem(m_frame.window(), layer), m_layernum(layer.getLayerNum()), + m_old_layernum(0), m_parent(client.screen().rootWindow()), m_resize_corner(RIGHTBOTTOM) { @@ -603,6 +605,7 @@ void FluxboxWindow::init() { void FluxboxWindow::shape() { #ifdef SHAPE if (m_shaped) { + if (isFullscreen()) XShapeCombineShape(display, frame().window().window(), ShapeBounding, 0, frame().clientArea().y(), // xOff, yOff @@ -1579,10 +1582,70 @@ void FluxboxWindow::withdraw(bool interrupt_moving) { hide(interrupt_moving); } +/** setFullscreen mode: + + - maximize as big as the screen is, dont care about slit / toolbar + - raise to toplayer +*/ +void FluxboxWindow::setFullscreen(bool flag) { + + const int head = screen().getHead(fbWindow()); + Fluxbox* fb = Fluxbox::instance(); + + if (flag && !isFullscreen()) { + + if (isIconic()) + deiconify(); + + if (isShaded()) + shade(); + + frame().setUseShape(false); + + m_old_decoration_mask = decorationMask(); + m_old_layernum =layerNum(); + m_old_pos_x = frame().x(); + m_old_pos_y = frame().y(); + m_old_width = frame().width(); + m_old_height = frame().height(); + + // clear decorations + setDecorationMask(0); + + // be xinerama aware + moveResize(screen().getHeadX(head), screen().getHeadY(head), + screen().getHeadWidth(head), screen().getHeadHeight(head)); + moveToLayer(Fluxbox::instance()->getAboveDockLayer()); + + fullscreen = true; + + stateSig().notify(); + + } else if (!flag && isFullscreen()) { + + fullscreen = false; + + setDecorationMask(m_old_decoration_mask); + frame().setUseShape(!m_shaped); + + moveResize(m_old_pos_x, m_old_pos_y, m_old_width, m_old_height); + moveToLayer(m_old_layernum); + + m_old_decoration_mask = 0; + m_old_layernum = Fluxbox::instance()->getNormalLayer(); + + stateSig().notify(); + } +} + /** Maximize window both horizontal and vertical */ void FluxboxWindow::maximize(int type) { + + if (isFullscreen()) + return; + if (isIconic()) deiconify(); diff --git a/src/Window.hh b/src/Window.hh index c20f8a9..aa6de85 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -71,12 +71,12 @@ public: MwmHintsFunctions = (1l << 0), ///< use motif wm functions MwmHintsDecorations = (1l << 1) ///< use motif wm decorations }; - + /// Motif wm functions enum MwmFunc{ MwmFuncAll = (1l << 0), ///< all motif wm functions - MwmFuncResize = (1l << 1), ///< resize - MwmFuncMove = (1l << 2), ///< move + MwmFuncResize = (1l << 1), ///< resize + MwmFuncMove = (1l << 2), ///< move MwmFuncIconify = (1l << 3), ///< iconify MwmFuncMaximize = (1l << 4), ///< maximize MwmFuncClose = (1l << 5) ///< close @@ -100,10 +100,10 @@ public: ATTRIB_MAXVERT = 0x04, ATTRIB_OMNIPRESENT = 0x08, ATTRIB_WORKSPACE = 0x10, - ATTRIB_STACK = 0x20, + ATTRIB_STACK = 0x20, ATTRIB_DECORATION = 0x40, ATTRIB_HIDDEN = 0x80, - }; + }; /** * Types of maximization @@ -114,8 +114,8 @@ public: MAX_VERT = 2, ///< maximize vertical MAX_FULL = 3 ///< maximize full }; - /** - This enumeration represents individual decoration + /** + This enumeration represents individual decoration attributes, they can be OR-d together to get a mask. Useful for saving. */ @@ -165,7 +165,7 @@ public: /// attach client to our client list and remove it from old window void attachClient(WinClient &client, int x=-1, int y=-1); - /// detach client (remove it from list) and create a new window for it + /// detach client (remove it from list) and create a new window for it bool detachClient(WinClient &client); /// detach current working client if we have more than one void detachCurrentClient(); @@ -199,6 +199,8 @@ public: void kill(); /// set the window in withdrawn state void withdraw(bool interrupt_moving); + /// set fullscreen + void setFullscreen(bool flag); /// toggle maximize void maximize(int type = MAX_FULL); /// maximizes the window horizontal @@ -210,7 +212,7 @@ public: /// toggles shade void shade(); /// toggles sticky - void stick(); + void stick(); void raise(); void lower(); void tempRaise(); @@ -269,10 +271,13 @@ public: void setDecorationMask(unsigned int mask); /** - @name accessors + @name accessors */ //@{ - // whether this window can be tabbed with other windows, + + // @return NormalState | IconicState | WithdrawnState + unsigned int getWmState() const { return m_current_state; } + // whether this window can be tabbed with other windows, // and others tabbed with it inline void setTabable(bool tabable) { functions.tabable = tabable; } inline bool isTabable() { return functions.tabable; } @@ -280,12 +285,13 @@ public: inline void setResizable(bool resizable) { functions.resize = resizable; } inline bool isFocusHidden() const { return (m_blackbox_attrib.flags & ATTRIB_HIDDEN); } - inline bool isIconHidden() const { return m_icon_hidden; } + inline bool isIconHidden() const { return m_icon_hidden; } inline bool isManaged() const { return m_managed; } inline bool isFocused() const { return focused; } bool isVisible() const; inline bool isIconic() const { return iconic; } inline bool isShaded() const { return shaded; } + inline bool isFullscreen() const { return fullscreen; } inline bool isMaximized() const { return maximized == MAX_FULL; } inline bool isIconifiable() const { return functions.iconify; } inline bool isMaximizable() const { return functions.maximize; } @@ -318,8 +324,8 @@ public: const FbTk::Menu &menu() const { return *m_windowmenu.get(); } - // for extras to add menus. - // These menus will be marked internal, + // for extras to add menus. + // These menus will be marked internal, // and deleted when the window dies (as opposed to Screen void addExtraMenu(const char *label, FbTk::Menu *menu); void removeExtraMenu(FbTk::Menu *menu); @@ -341,7 +347,7 @@ public: int layerNum() const { return m_layernum; } void setLayerNum(int layernum); - + unsigned int titlebarHeight() const; @@ -453,7 +459,7 @@ private: // Window states bool moving, resizing, shaded, iconic, - focused, stuck, m_managed; + focused, stuck, m_managed, fullscreen; int maximized; @@ -474,9 +480,10 @@ private: unsigned int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" unsigned int m_workspace_number; - unsigned long m_current_state; + unsigned long m_current_state; // NormalState | IconicState | Withdrawn Decoration m_old_decoration; + unsigned int m_old_decoration_mask; ClientList m_clientlist; WinClient *m_client; ///< current client @@ -491,14 +498,14 @@ private: maximize, close, menu, sticky, shade, tab, enabled; } decorations; - bool m_toggled_decos; + bool m_toggled_decos; struct _functions { bool resize, move, iconify, maximize, close, tabable; } functions; bool m_shaped; ///< if the window is shaped with a mask - bool m_icon_hidden; ///< if the window is in the iconbar + bool m_icon_hidden; ///< if the window is in the iconbar int m_old_pos_x, m_old_pos_y; ///< old position so we can restore from maximized unsigned int m_old_width, m_old_height; ///< old size so we can restore from maximized state int m_last_button_x, ///< last known x position of the mouse button @@ -507,6 +514,7 @@ private: FbTk::XLayerItem m_layeritem; int m_layernum; + int m_old_layernum; FbTk::FbWindow &m_parent; ///< window on which we draw move/resize rectangle (the "root window") -- cgit v0.11.2