From f4ce449632eeb85aaeae63f32a7165d71047cde0 Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Mon, 14 Apr 2003 12:13:36 +0000
Subject: merged with embedded-tab-branch

---
 src/Ewmh.cc          |  30 +++--
 src/FbTk/FbWindow.cc |  29 +++--
 src/FbTk/Font.hh     |   9 +-
 src/Gnome.cc         |  12 +-
 src/Keys.cc          |   4 +-
 src/Keys.hh          |   5 +-
 src/Screen.hh        |  22 +---
 src/TextButton.cc    |  81 +++++++++++++
 src/TextButton.hh    |  59 ++++++++++
 src/WinClient.cc     | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/WinClient.hh     | 112 ++++++++++++++++++
 11 files changed, 632 insertions(+), 49 deletions(-)
 create mode 100644 src/TextButton.cc
 create mode 100644 src/TextButton.hh
 create mode 100644 src/WinClient.cc
 create mode 100644 src/WinClient.hh

diff --git a/src/Ewmh.cc b/src/Ewmh.cc
index f077932..c17bd92 100644
--- a/src/Ewmh.cc
+++ b/src/Ewmh.cc
@@ -19,15 +19,17 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Ewmh.cc,v 1.14 2003/04/09 17:20:00 rathnor Exp $
+// $Id: Ewmh.cc,v 1.15 2003/04/14 12:11:21 fluxgen Exp $
 
 #include "Ewmh.hh" 
 
 #include "Screen.hh"
 #include "Window.hh"
 #include "fluxbox.hh"
+#include "WinClient.hh"
 
 #include <iostream>
+#include <algorithm>
 #include <new>
 using namespace std;
 
@@ -116,8 +118,8 @@ void Ewmh::setupWindow(FluxboxWindow &win) {
         unsigned int desktop = static_cast<unsigned int>(*data);
         if (desktop == 0xFFFFFFFF && !win.isStuck())
             win.stick();
-        else if (win.getScreen())
-            win.getScreen()->sendToWorkspace(desktop, &win, false);
+        else
+            win.getScreen().sendToWorkspace(desktop, &win, false);
 
         XFree(data);
     }
@@ -147,7 +149,15 @@ void Ewmh::updateClientList(BScreen &screen) {
         Workspace::Windows::const_iterator it = (*workspace_it)->getWindowList().begin();
         Workspace::Windows::const_iterator it_end = (*workspace_it)->getWindowList().end();		
         for (; it != it_end; ++it) {
-            wl[win++] = (*it)->getClientWindow();
+            if ((*it)->numClients() == 1)
+                wl[win++] = (*it)->getClientWindow();
+            else {
+                // add every client in fluxboxwindow to list window list
+                std::list<WinClient *>::iterator client_it = (*it)->clientList().begin();
+                std::list<WinClient *>::iterator client_it_end = (*it)->clientList().end();
+                for (; client_it != client_it_end; ++client_it)
+                    wl[win++] = (*client_it)->window();
+            }
         }
     }
 
@@ -207,11 +217,11 @@ void Ewmh::updateWorkspaceCount(BScreen &screen) {
 }
 
 void Ewmh::updateState(FluxboxWindow &win) {
-
+    //!! TODO
 }
 
 void Ewmh::updateLayer(FluxboxWindow &win) {
-    //TODO _NET_WM_WINDOW_TYPE
+    //!! TODO _NET_WM_WINDOW_TYPE
 }
 
 void Ewmh::updateHints(FluxboxWindow &win) {
@@ -223,9 +233,11 @@ void Ewmh::updateWorkspace(FluxboxWindow &win) {
     if (win.isStuck())
         workspace = 0xFFFFFFFF; // appear on all desktops/workspaces
 
-    XChangeProperty(FbTk::App::instance()->display(), win.getClientWindow(),
-                    m_net_wm_desktop, XA_CARDINAL, 32, PropModeReplace,
-                    (unsigned char *)&workspace, 1);
+    for_each(win.clientList().begin(),
+             win.clientList().end(),
+             FbTk::ChangeProperty(FbTk::App::instance()->display(),
+                    m_net_wm_desktop, PropModeReplace,
+                    (unsigned char *)&workspace, 1));
 }
 
 // return true if we did handle the atom here
diff --git a/src/FbTk/FbWindow.cc b/src/FbTk/FbWindow.cc
index 5c0b2d2..e92c3d2 100644
--- a/src/FbTk/FbWindow.cc
+++ b/src/FbTk/FbWindow.cc
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: FbWindow.cc,v 1.7 2003/02/23 16:52:16 fluxgen Exp $
+// $Id: FbWindow.cc,v 1.8 2003/04/14 12:06:25 fluxgen Exp $
 
 #include "FbWindow.hh"
 
@@ -33,7 +33,7 @@ namespace FbTk {
 Display *FbWindow::s_display = 0;
 
 FbWindow::FbWindow():m_parent(0), m_screen_num(0), m_window(0), m_x(0), m_y(0), 
-                     m_width(0), m_height(0), m_border_width(0) {
+                     m_width(0), m_height(0), m_border_width(0), m_destroy(true) {
 
     if (s_display == 0)
         s_display = App::instance()->display();
@@ -45,7 +45,7 @@ FbWindow::FbWindow(int screen_num,
                    int depth,
                    int class_type):
     m_screen_num(screen_num),
-    m_parent(0) {
+    m_parent(0), m_destroy(true) {
 	
     create(RootWindow(FbTk::App::instance()->display(), screen_num), 
            x, y, width, height, eventmask,
@@ -53,11 +53,12 @@ FbWindow::FbWindow(int screen_num,
 };
 
 FbWindow::FbWindow(const FbWindow &parent,
-                   int x, int y, size_t width, size_t height, long eventmask,
+                   int x, int y, unsigned int width, unsigned int height, 
+                   long eventmask,
                    bool override_redirect, 
                    int depth, int class_type):
    m_parent(&parent),
-   m_screen_num(parent.screenNumber()) { 
+   m_screen_num(parent.screenNumber()), m_destroy(true) { 
 
     create(parent.window(), x, y, width, height, eventmask, 
            override_redirect, depth, class_type);
@@ -65,8 +66,13 @@ FbWindow::FbWindow(const FbWindow &parent,
 	
 };
 
+FbWindow::FbWindow(Window client):m_parent(0), m_window(client),
+                                  m_destroy(false) { // don't destroy this window
+    updateGeometry();
+}
+
 FbWindow::~FbWindow() {
-    if (m_window != 0)
+    if (m_window != 0 && m_destroy)
         XDestroyWindow(s_display, m_window);
 }
 
@@ -82,7 +88,7 @@ void FbWindow::setBackgroundPixmap(Pixmap bg_pixmap) {
 void FbWindow::setBorderColor(const FbTk::Color &border_color) {
     XSetWindowBorder(s_display, m_window, border_color.pixel());
 }
-void FbWindow::setBorderWidth(size_t size) {	
+void FbWindow::setBorderWidth(unsigned int size) {	
     XSetWindowBorderWidth(s_display, m_window, size);
     m_border_width = size;
 }
@@ -100,7 +106,7 @@ void FbWindow::clear() {
 }
 
 FbWindow &FbWindow::operator = (Window win) {
-    if (m_window != 0)
+    if (m_window != 0 && m_destroy)
         XDestroyWindow(s_display, m_window);
     m_window = win;
     if (m_window != 0)
@@ -127,13 +133,13 @@ void FbWindow::move(int x, int y) {
     m_y = y;
 }
 
-void FbWindow::resize(size_t width, size_t height) {
+void FbWindow::resize(unsigned int width, unsigned int height) {
     XResizeWindow(s_display, m_window, width, height);
     m_width = width;
     m_height = height;
 }
 
-void FbWindow::moveResize(int x, int y, size_t width, size_t height) {
+void FbWindow::moveResize(int x, int y, unsigned int width, unsigned int height) {
     XMoveResizeWindow(s_display, m_window, x, y, width, height);
     m_x = x;
     m_y = y;
@@ -152,6 +158,7 @@ void FbWindow::raise() {
 int FbWindow::screenNumber() const {
     return m_screen_num;
 }
+
 void FbWindow::updateGeometry() {
     if (m_window == 0)
         return;
@@ -164,7 +171,7 @@ void FbWindow::updateGeometry() {
 }
 
 void FbWindow::create(Window parent, int x, int y,
-                      size_t width, size_t height, 
+                      unsigned int width, unsigned int height, 
                       long eventmask, bool override_redirect,
                       int depth, int class_type) {
                      
diff --git a/src/FbTk/Font.hh b/src/FbTk/Font.hh
index a120539..8ecb5ce 100644
--- a/src/FbTk/Font.hh
+++ b/src/FbTk/Font.hh
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-//$Id: Font.hh,v 1.3 2002/12/08 18:37:08 fluxgen Exp $
+//$Id: Font.hh,v 1.4 2003/04/14 12:07:03 fluxgen Exp $
 
 #ifndef FBTK_FONT_HH
 #define FBTK_FONT_HH
@@ -64,7 +64,8 @@ public:
     int ascent() const;
     int descent() const;
     /**
-       Rotate font in any angle (currently only 90 degrees supported and just XFont implementation)
+       Rotate font in any angle 
+       (currently only 90 degrees supported and just XFont implementation)
     */
     void rotate(float angle);
 
@@ -79,7 +80,9 @@ public:
        @param y position
        @param rotate if the text should be drawn rotated (if it's rotated before)
     */	
-    void drawText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y, bool rotate=true) const;
+    void drawText(Drawable w, int screen, GC gc, 
+                  const char *text, size_t len, 
+                  int x, int y, bool rotate=true) const;
     bool isAntialias() const { return m_antialias; }
     /// @return true if the font is rotated, else false
     bool isRotated() const { return m_rotated; }
diff --git a/src/Gnome.cc b/src/Gnome.cc
index 13484c4..c35c6b8 100644
--- a/src/Gnome.cc
+++ b/src/Gnome.cc
@@ -1,5 +1,5 @@
 // Gnome.cc for fluxbox
-// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
+// Copyright (c) 2002 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and associated documentation files (the "Software"),
@@ -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.14 2003/04/09 17:20:01 rathnor Exp $
+// $Id: Gnome.cc,v 1.15 2003/04/14 12:11:59 fluxgen Exp $
 
 #include "Gnome.hh"
 
@@ -116,7 +116,7 @@ void Gnome::setupWindow(FluxboxWindow &win) {
                            (unsigned char **) &data) ==  Success && data) {
         unsigned int workspace_num = *data;
         if (win.getWorkspaceNumber() != workspace_num) 
-            win.getScreen()->reassociateWindow(&win, workspace_num, false);
+            win.getScreen().reassociateWindow(&win, workspace_num, false);
         XFree (data);
     }
 
@@ -250,9 +250,9 @@ bool Gnome::checkClientMessage(const XClientMessageEvent &ce, BScreen * screen,
         cerr<<__FILE__<<"("<<__LINE__<<"): Got workspace atom="<<ce.data.l[0]<<endl;
 #endif//!DEBUG
         if ( win !=0 && // the message sent to client window?
-             win->getScreen() && ce.data.l[0] >= 0 &&
-             ce.data.l[0] < (signed)win->getScreen()->getCount()) {
-            win->getScreen()->changeWorkspaceID(ce.data.l[0]);
+             ce.data.l[0] >= 0 &&
+             ce.data.l[0] < (signed)win->getScreen().getCount()) {
+            win->getScreen().changeWorkspaceID(ce.data.l[0]);
 					
         } else if (screen!=0 && //the message sent to root window?
                    ce.data.l[0] >= 0 &&
diff --git a/src/Keys.cc b/src/Keys.cc
index 20677cd..8d705c1 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-//$Id: Keys.cc,v 1.23 2003/02/28 23:55:37 fluxgen Exp $
+//$Id: Keys.cc,v 1.24 2003/04/14 12:10:16 fluxgen Exp $
 
 
 #include "Keys.hh"
@@ -108,6 +108,8 @@ Keys::t_actionstr Keys::m_actionlist[] = {
     {"LastTab", LASTTAB},
     {"MoveTabPrev", MOVETABPREV},
     {"MoveTabNext", MOVETABNEXT},
+    {"AttachLast", ATTACHLAST},
+    {"DetachClient", DETACHCLIENT},
     {"ShadeWindow", SHADE},
     {"MaximizeWindow", MAXIMIZE},
     {"StickWindow", STICK},
diff --git a/src/Keys.hh b/src/Keys.hh
index bfe3222..c0a6d6c 100644
--- a/src/Keys.hh
+++ b/src/Keys.hh
@@ -1,5 +1,5 @@
 // Keys.hh for Fluxbox - an X11 Window manager
-// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
+// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at linuxmail.org)
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and associated documentation files (the "Software"),
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Keys.hh,v 1.20 2003/02/28 23:37:41 fluxgen Exp $
+// $Id: Keys.hh,v 1.21 2003/04/14 12:10:14 fluxgen Exp $
 
 #ifndef KEYS_HH
 #define KEYS_HH
@@ -51,6 +51,7 @@ public:
         LEFTWORKSPACE, RIGHTWORKSPACE,
         KILLWINDOW, NEXTWINDOW,	PREVWINDOW,
         NEXTTAB, PREVTAB, FIRSTTAB, LASTTAB, MOVETABPREV, MOVETABNEXT,
+        ATTACHLAST, DETACHCLIENT,
         SHADE, MAXIMIZE, 
         STICK,       // Make Sticky
         EXECUTE,	// Run command
diff --git a/src/Screen.hh b/src/Screen.hh
index af60665..b4adcbf 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.73 2003/03/03 21:51:06 rathnor Exp $
+// $Id: Screen.hh,v 1.74 2003/04/14 12:13:36 fluxgen Exp $
 
 #ifndef	 SCREEN_HH
 #define	 SCREEN_HH
@@ -30,7 +30,6 @@
 #include "Theme.hh"
 #include "BaseDisplay.hh"
 #include "Workspace.hh"
-#include "Tab.hh"
 #include "Resource.hh"
 #include "Subject.hh"
 #include "FbWinFrameTheme.hh"
@@ -58,6 +57,7 @@ class Slit;
 class Toolbar;
 class FbWinFrameTheme;
 class RootTheme;
+class WinClient;
 
 namespace FbTk {
 class MenuTheme;
@@ -85,7 +85,6 @@ public:
     inline bool isSemiSloppyFocus() const { return (*resource.focus_model == Fluxbox::SEMISLOPPYFOCUS); }
     inline bool isRootColormapInstalled() const { return root_colormap_installed; }
     inline bool isScreenManaged() const { return managed; }
-    inline bool isTabRotateVertical() const { return *resource.tab_rotate_vertical; }
     inline bool isSloppyWindowGrouping() const { return *resource.sloppy_window_grouping; }
     inline bool isWorkspaceWarping() const { return *resource.workspace_warping; }
     inline bool isDesktopWheeling() const { return *resource.desktop_wheeling; }
@@ -188,14 +187,10 @@ public:
     inline int getEdgeSnapThreshold() const { return *resource.edge_snap_threshold; }
     inline int getRowPlacementDirection() const { return resource.row_direction; }
     inline int getColPlacementDirection() const { return resource.col_direction; }
-    inline unsigned int getTabWidth() const { return *resource.tab_width; }
-    inline unsigned int getTabHeight() const { return *resource.tab_height; }
 
     inline int getSlitLayerNum() const { return (*resource.slit_layernum).getNum(); }
     inline int getToolbarLayerNum() const { return (*resource.toolbar_layernum).getNum(); }
 
-    inline Tab::Placement getTabPlacement() const { return *resource.tab_placement; }
-    inline Tab::Alignment getTabAlignment() const { return *resource.tab_alignment; }
 
     inline void setRootColormapInstalled(Bool r) { root_colormap_installed = r;  }
     inline void saveRootCommand(std::string rootcmd) { *resource.rootcommand = rootcmd;  }
@@ -218,11 +213,6 @@ public:
     inline void saveFullMax(bool f) { resource.full_max = f;  }
     inline void saveFocusNew(bool f) { resource.focus_new = f;  }
     inline void saveFocusLast(bool f) { resource.focus_last = f;  }
-    inline void saveTabWidth(unsigned int w) { resource.tab_width = w;  }
-    inline void saveTabHeight(unsigned int h) { resource.tab_height = h;  }
-    inline void saveTabPlacement(Tab::Placement p) { *resource.tab_placement = p;  }
-    inline void saveTabAlignment(Tab::Alignment a) { *resource.tab_alignment = a;  }
-    inline void saveTabRotateVertical(bool r) { resource.tab_rotate_vertical = r;   }
     inline void saveSloppyWindowGrouping(bool s) { resource.sloppy_window_grouping = s;  }
     inline void saveWorkspaceWarping(bool s) { resource.workspace_warping = s; }
     inline void saveDesktopWheeling(bool s) { resource.desktop_wheeling = s; }
@@ -301,6 +291,7 @@ public:
     void updateNetizenWindowLower(Window);
     /// create window frame for client window and attach it
     FluxboxWindow *createWindow(Window clientwin);
+    FluxboxWindow *createWindow(WinClient &client);
     void setupWindowActions(FluxboxWindow &win);
 
     enum { ROWSMARTPLACEMENT = 1, COLSMARTPLACEMENT, CASCADEPLACEMENT, LEFTRIGHT,
@@ -386,7 +377,7 @@ private:
 
         Resource<bool> toolbar_auto_hide,
             image_dither, opaque_move, full_max,
-            max_over_slit, tab_rotate_vertical,
+            max_over_slit,
             sloppy_window_grouping, workspace_warping,
             desktop_wheeling, show_window_pos,
             focus_last, focus_new,
@@ -394,13 +385,10 @@ private:
         Resource<std::string> rootcommand;		
         Resource<Fluxbox::FocusModel> focus_model;
         bool ordered_dither;
-        Resource<int> workspaces, toolbar_width_percent, edge_snap_threshold,
-            tab_width, tab_height;
+        Resource<int> workspaces, toolbar_width_percent, edge_snap_threshold;            
         Resource<Fluxbox::Layer> slit_layernum, toolbar_layernum;
         int placement_policy, row_direction, col_direction;
 
-        Resource<Tab::Placement> tab_placement;
-        Resource<Tab::Alignment> tab_alignment;
         Resource<ToolbarHandler::ToolbarMode> toolbar_mode;
         Resource<int> toolbar_on_head;
         Resource<Toolbar::Placement> toolbar_placement;
diff --git a/src/TextButton.cc b/src/TextButton.cc
new file mode 100644
index 0000000..c977a53
--- /dev/null
+++ b/src/TextButton.cc
@@ -0,0 +1,81 @@
+// TextButton.cc for Fluxbox Window Manager
+// Copyright (c) 2003 Henrik Kinnunen (fluxgen[at]fluxbox.org)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// 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: TextButton.cc,v 1.2 2003/04/14 12:08:50 fluxgen Exp $
+
+#include "TextButton.hh"
+#include "Font.hh"
+
+#include <iostream>
+using namespace std;
+
+TextButton::TextButton(const FbTk::FbWindow &parent, 
+                       const FbTk::Font &font, 
+                       const std::string &text):FbTk::Button(parent, 0, 0, 10, 10),
+                                                m_font(&font),
+                                                m_text(text),
+                                                m_justify(FbTk::LEFT), m_bevel(1) {
+
+}
+
+void TextButton::setJustify(FbTk::Justify just) {
+    m_justify = just;
+}
+
+void TextButton::setText(const std::string &text) {
+    m_text = text;
+}
+
+void TextButton::setFont(const FbTk::Font &font) {
+    // no need to set new font if it's the same
+    if (&font == m_font)
+        return;
+    m_font = &font;
+    clear(); // redraw text with new font
+}
+
+/// set bevel and redraw text
+void TextButton::setBevel(int bevel) {
+    if (m_bevel == bevel)
+        return;
+    m_bevel = bevel;
+}
+
+/// clear window and redraw text 
+void TextButton::clear() {
+    FbTk::Button::clear(); // clear window and draw background
+    unsigned int textlen = text().size();
+    // do text alignment
+    int align_x = FbTk::doAlignment(width(),
+                                    bevel(),
+                                    justify(),
+                                    font(),
+                                    text().c_str(), text().size(),
+                                    textlen // return new text len
+                                    );
+
+    font().drawText(window().window(), // drawable
+                    window().screenNumber(),
+                    gc(), // graphic context
+                    text().c_str(), textlen, // string and string size
+                    align_x, font().ascent());// position
+}
+
diff --git a/src/TextButton.hh b/src/TextButton.hh
new file mode 100644
index 0000000..77615aa
--- /dev/null
+++ b/src/TextButton.hh
@@ -0,0 +1,59 @@
+// TextButton.hh for Fluxbox Window Manager
+// Copyright (c) 2003 Henrik Kinnunen (fluxgen[at]fluxbox.org)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// 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: TextButton.hh,v 1.2 2003/04/14 12:08:50 fluxgen Exp $
+
+#ifndef TEXTBUTTON_HH
+#define TEXTBUTTON_HH
+
+#include "Button.hh"
+#include "Text.hh"
+#include <string>
+
+namespace FbTk {
+class Font;
+};
+
+/// Displays a text on a button
+class TextButton: public FbTk::Button {
+public:
+    TextButton(const FbTk::FbWindow &parent, 
+               const FbTk::Font &font, const std::string &text);
+
+    void setJustify(FbTk::Justify just);
+    void setText(const std::string &text);
+    void setFont(const FbTk::Font &font);
+    void setBevel(int bevel);
+    /// clears window and redraw text
+    void clear();
+
+    inline FbTk::Justify justify() const { return m_justify; }
+    inline const std::string &text() const { return m_text; }
+    inline const FbTk::Font &font() const { return *m_font; }
+    int bevel() const { return m_bevel; }
+private:
+    const FbTk::Font *m_font;
+    std::string m_text;
+    FbTk::Justify m_justify;
+    int m_bevel;
+};
+
+#endif // TEXTBUTTON_HH
diff --git a/src/WinClient.cc b/src/WinClient.cc
new file mode 100644
index 0000000..467b2b5
--- /dev/null
+++ b/src/WinClient.cc
@@ -0,0 +1,318 @@
+// WinClient.cc for Fluxbox - an X11 Window manager
+// Copyright (c) 2003 Henrik Kinnunen (fluxgen(at)users.sourceforge.net)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// 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.2 2003/04/14 12:08:21 fluxgen Exp $
+
+#include "WinClient.hh"
+
+#include "Window.hh"
+#include "fluxbox.hh"
+#include "Screen.hh"
+#include "i18n.hh"
+
+#include <iostream>
+#include <algorithm>
+#include <iterator>
+using namespace std;
+
+WinClient::WinClient(Window win, FluxboxWindow &fbwin):FbTk::FbWindow(win),
+                     transient_for(0),
+                     window_group(0),
+                     x(0), y(0), old_bw(0),
+                     min_width(1), min_height(1),
+                     max_width(1), max_height(1),
+                     width_inc(1), height_inc(1),
+                     min_aspect_x(1), min_aspect_y(1),
+                     max_aspect_x(1), max_aspect_y(1),
+                     base_width(1), base_height(1),
+                     win_gravity(0),
+                     initial_state(0),
+                     normal_hint_flags(0),
+                     wm_hint_flags(0),
+                     mwm_hint(0),
+                     blackbox_hint(0),
+                     m_win(&fbwin),
+                     m_title(""), m_icon_title(""),
+                     m_diesig(*this) { }
+
+WinClient::~WinClient() {
+#ifdef DEBUG
+    cerr<<__FILE__<<"(~"<<__FUNCTION__<<")[this="<<this<<"]"<<endl;
+#endif // DEBUG
+
+    m_diesig.notify();
+
+    Fluxbox *fluxbox = Fluxbox::instance();
+
+    if (transient_for != 0) {
+        if (transientFor() == m_win) {
+            transient_for = 0;
+        }
+
+        fluxbox->setFocusedWindow(transient_for);
+
+        if (transient_for != 0) {
+            FluxboxWindow::ClientList::iterator client_it = 
+                transientFor()->clientList().begin();
+            FluxboxWindow::ClientList::iterator client_it_end = 
+                transientFor()->clientList().end();
+            for (; client_it != client_it_end; ++client_it) {
+                (*client_it)->transientList().remove(m_win);
+            }
+
+            transient_for->setInputFocus();
+            transient_for = 0;
+        }
+    }
+	
+    while (!transients.empty()) {
+        FluxboxWindow::ClientList::iterator it = 
+            transients.back()->clientList().begin();
+        FluxboxWindow::ClientList::iterator it_end = 
+            transients.back()->clientList().end();
+        for (; it != it_end; ++it) {
+            if ((*it)->transientFor() == m_win)
+                (*it)->transient_for = 0;
+        }
+
+        transients.pop_back();
+    }
+	
+    if (window_group != 0) {
+        fluxbox->removeGroupSearch(window_group);
+        window_group = 0;
+    }
+
+    if (mwm_hint != 0)
+        XFree(mwm_hint);
+
+    if (blackbox_hint != 0)
+        XFree(blackbox_hint);
+
+    if (window())
+        fluxbox->removeWindowSearch(window());
+
+    if (m_win != 0)
+        m_win->removeClient(*this);
+    m_win = 0;
+
+}
+
+void WinClient::updateRect(int x, int y, 
+                        unsigned int width, unsigned int height) {
+    Display *disp = FbTk::App::instance()->display();
+    XEvent event;
+    event.type = ConfigureNotify;
+
+    event.xconfigure.display = disp;
+    event.xconfigure.event = window();
+    event.xconfigure.window = window();
+    event.xconfigure.x = x;
+    event.xconfigure.y = y;
+    event.xconfigure.width = width;
+    event.xconfigure.height = height;
+    //!! TODO
+    event.xconfigure.border_width = 1;//client.old_bw;
+    //!! TODO
+    event.xconfigure.above = None; //m_frame.window().window();
+    event.xconfigure.override_redirect = false;
+
+    XSendEvent(disp, window(), False, StructureNotifyMask, &event);
+
+}
+
+void WinClient::sendFocus() {
+    Display *disp = FbTk::App::instance()->display();
+    // setup focus msg
+    XEvent ce;
+    ce.xclient.type = ClientMessage;
+    ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
+    ce.xclient.display = disp;
+    ce.xclient.window = window();
+    ce.xclient.format = 32;
+    ce.xclient.data.l[0] = FbAtoms::instance()->getWMTakeFocusAtom();
+    ce.xclient.data.l[1] = Fluxbox::instance()->getLastTime();
+    ce.xclient.data.l[2] = 0l;
+    ce.xclient.data.l[3] = 0l;
+    ce.xclient.data.l[4] = 0l;
+    // send focus msg
+    XSendEvent(disp, window(), false, NoEventMask, &ce);
+}
+
+void WinClient::sendClose() {
+    Display *disp = FbTk::App::instance()->display();
+    // fill in XClientMessage structure for delete message
+    XEvent ce;
+    ce.xclient.type = ClientMessage;
+    ce.xclient.message_type = FbAtoms::instance()->getWMProtocolsAtom();
+    ce.xclient.display = disp;
+    ce.xclient.window = window();
+    ce.xclient.format = 32;
+    ce.xclient.data.l[0] = FbAtoms::instance()->getWMDeleteAtom();
+    ce.xclient.data.l[1] = CurrentTime;
+    ce.xclient.data.l[2] = 0l;
+    ce.xclient.data.l[3] = 0l;
+    ce.xclient.data.l[4] = 0l;
+    // send event delete message to client window
+    XSendEvent(disp, window(), false, NoEventMask, &ce);
+}
+
+void WinClient::reparent(Window win, int x, int y) {
+    XReparentWindow(FbTk::App::instance()->display(), window(), win, x, y);
+}
+
+bool WinClient::getAttrib(XWindowAttributes &attr) const {
+    return XGetWindowAttributes(FbTk::App::instance()->display(), window(), &attr);
+}
+
+bool WinClient::getWMName(XTextProperty &textprop) const {
+    return XGetWMName(FbTk::App::instance()->display(), window(), &textprop);
+}
+
+bool WinClient::getWMIconName(XTextProperty &textprop) const {
+    return XGetWMName(FbTk::App::instance()->display(), window(), &textprop);
+}
+
+void WinClient::updateTransientInfo() {
+    if (m_win == 0)
+        return;
+    // remove us from parent
+    if (transientFor() != 0) {
+        //!! TODO
+        // since we don't know which client in transientFor()
+        // that we're transient for then we just remove us 
+        // from every client in transientFor() clientlist
+        FluxboxWindow::ClientList::iterator client_it = 
+            transientFor()->clientList().begin();
+        FluxboxWindow::ClientList::iterator client_it_end = 
+            transientFor()->clientList().end();
+        for (; client_it != client_it_end; ++client_it) {
+            (*client_it)->transientList().remove(m_win);
+        }
+    }
+    
+    transient_for = 0;
+    Display *disp = FbTk::App::instance()->display();
+    // determine if this is a transient window
+    Window win;
+    if (!XGetTransientForHint(disp, window(), &win))
+        return;
+
+    // we can't be transient to ourself
+    if (win == window())
+        return;
+	
+    if (win != 0 && m_win->getScreen().getRootWindow() == win) {
+        m_win->modal = true;
+        return;
+    }
+
+    transient_for = Fluxbox::instance()->searchWindow(win);
+    if (transient_for != 0 &&
+        window_group != None && win == window_group) {
+        transient_for = Fluxbox::instance()->searchGroup(win, m_win);
+    }
+	
+    // make sure we don't have deadlock loop in transient chain
+    for (FluxboxWindow *w = m_win; w != 0; w = w->m_client->transient_for) {
+        if (w == w->m_client->transient_for) {
+            w->m_client->transient_for = 0;
+            break;
+        }
+    }
+
+    if (transientFor() != 0) {
+        // we need to add ourself to the right client in
+        // the transientFor() window so we search client
+        WinClient *client = transientFor()->findClient(win);
+        assert(client != 0);
+        client->transientList().push_back(m_win);
+        // make sure we only have on instance of this
+        client->transientList().unique(); 
+        if (transientFor()->isStuck())
+            m_win->stick();       
+    }
+}
+
+
+void WinClient::updateTitle() {
+    XTextProperty text_prop;
+    char **list = 0;
+    int num = 0;
+    I18n *i18n = I18n::instance();
+
+    if (getWMName(text_prop)) {
+        if (text_prop.value && text_prop.nitems > 0) {
+            if (text_prop.encoding != XA_STRING) {
+				
+                text_prop.nitems = strlen((char *) text_prop.value);
+				
+                if (XmbTextPropertyToTextList(FbTk::App::instance()->display(), &text_prop,
+                                              &list, &num) == Success &&
+                    num > 0 && *list) {
+                    m_title = static_cast<char *>(*list);
+                    XFreeStringList(list);
+                } else
+                    m_title = (char *)text_prop.value;
+					
+            } else
+                m_title = (char *)text_prop.value;
+            XFree((char *) text_prop.value);
+        } else { // ok, we don't have a name, set default name
+            m_title = i18n->getMessage(
+                                       FBNLS::WindowSet, FBNLS::WindowUnnamed,
+                                       "Unnamed");
+        }
+    } else {
+        m_title = i18n->getMessage(
+                                   FBNLS::WindowSet, FBNLS::WindowUnnamed,
+                                   "Unnamed");
+    }
+
+}
+
+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) {
+                text_prop.nitems = strlen((char *) text_prop.value);
+
+                if (XmbTextPropertyToTextList(FbTk::App::instance()->display(), &text_prop,
+                                               &list, &num) == Success &&
+                    num > 0 && *list) {
+                    m_icon_title = (char *)*list;
+                    XFreeStringList(list);
+                } else
+                    m_icon_title = (char *)text_prop.value;
+            } else
+                m_icon_title = (char *)text_prop.value;
+
+            XFree((char *) text_prop.value);
+        } else
+            m_icon_title = title();
+    } else
+        m_icon_title = title();
+
+}
diff --git a/src/WinClient.hh b/src/WinClient.hh
new file mode 100644
index 0000000..6cd14dd
--- /dev/null
+++ b/src/WinClient.hh
@@ -0,0 +1,112 @@
+// WinClient.hh for Fluxbox - an X11 Window manager
+// Copyright (c) 2003 Henrik Kinnunen (fluxgen(at)users.sourceforge.net)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// 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.2 2003/04/14 12:08:21 fluxgen Exp $
+
+#ifndef WINCLIENT_HH
+#define WINCLIENT_HH
+
+#include "BaseDisplay.hh"
+#include "Subject.hh"
+#include "FbWindow.hh"
+
+#include <X11/Xutil.h>
+#include <string>
+
+class FluxboxWindow;
+
+/// Holds client window info 
+class WinClient:public FbTk::FbWindow {
+public:
+    typedef std::list<FluxboxWindow *> TransientList;
+
+    WinClient(Window win, FluxboxWindow &fbwin);
+
+    ~WinClient();
+    void updateRect(int x, int y, unsigned int width, unsigned int height);
+    void sendFocus();
+    void sendClose();
+    void reparent(Window win, int x, int y);
+    bool getAttrib(XWindowAttributes &attr) const;
+    bool getWMName(XTextProperty &textprop) const;
+    bool getWMIconName(XTextProperty &textprop) const;
+    void updateTitle();
+    void updateIconTitle();
+
+    /// notifies when this client dies
+    FbTk::Subject &dieSig() { return m_diesig; }
+
+    /// updates transient window information
+    void updateTransientInfo();
+    FluxboxWindow *transientFor() { return transient_for; }
+    const FluxboxWindow *transientFor() const { return transient_for; }
+    TransientList &transientList() { return transients; }
+    const TransientList &transientList() const { return transients; }
+    bool operator == (const FluxboxWindow &win) const {
+        return (m_win == &win);
+    }
+
+    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; }
+    /**
+       !! TODO !!
+       remove or move these to private
+     */
+
+    FluxboxWindow *transient_for; // which window are we a transient for?
+    std::list<FluxboxWindow *> transients;  // which windows are our transients?
+    Window window_group;
+
+ 
+    int x, y, old_bw;
+    unsigned int
+        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;
+
+    // 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
+    typedef struct MwmHints {
+        unsigned long flags;       // Motif wm flags
+        unsigned long functions;   // Motif wm functions
+        unsigned long decorations; // Motif wm decorations
+    } MwmHints;
+
+    MwmHints *mwm_hint;
+    BaseDisplay::BlackboxHints *blackbox_hint;
+    FluxboxWindow *m_win;
+    class WinClientSubj: public FbTk::Subject {
+    public:
+        explicit WinClientSubj(WinClient &client):m_winclient(client) { }
+        WinClient &winClient() { return m_winclient; }
+    private:
+        WinClient &m_winclient;
+    };
+
+private:
+    std::string m_title, m_icon_title;
+    WinClientSubj m_diesig;
+};
+
+#endif // WINCLIENT_HH
-- 
cgit v0.11.2