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