From fcf431100c1729c8301aa48a884c3b0feef495cb Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Sun, 12 Jan 2003 17:56:15 +0000
Subject: major update, moved SlitClient to Slit.cc, changed frame.window to
 FbWindow type, changed menus to FbTk Menu type, fixed clientlist menu with
 cycle up/down functions, changed Slit to an EventHandler

---
 src/Slit.cc | 1015 ++++++++++++++++++++++++++++++-----------------------------
 src/Slit.hh |  162 +++-------
 2 files changed, 573 insertions(+), 604 deletions(-)

diff --git a/src/Slit.cc b/src/Slit.cc
index 38fd773..1b099e7 100644
--- a/src/Slit.cc
+++ b/src/Slit.cc
@@ -1,8 +1,8 @@
 // Slit.cc for fluxbox
-// Copyright (c) 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
+// Copyright (c) 2002 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
 //
 // Slit.cc for Blackbox - an X11 Window manager
-// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
+// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and associated documentation files (the "Software"),
@@ -16,13 +16,15 @@
 //
 // 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
+// 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: Slit.cc,v 1.31 2003/01/09 22:07:49 fluxgen Exp $
+// $Id: Slit.cc,v 1.32 2003/01/12 17:56:15 fluxgen Exp $
+
+#include "Slit.hh"
 
 //use GNU extensions
 #ifndef	 _GNU_SOURCE
@@ -33,27 +35,29 @@
 #include "../config.h"
 #endif // HAVE_CONFIG_H
 
-#ifdef	SLIT
-
 #include "i18n.hh"
-#include "fluxbox.hh"
 #include "Screen.hh"
-#include "Slit.hh"
-#include "Toolbar.hh"
 #include "ImageControl.hh"
+#include "RefCount.hh"
+#include "SimpleCommand.hh"
+#include "BoolMenuItem.hh"
+#include "EventManager.hh"
+#include "MacroCommand.hh"
 
 #include <algorithm>
 #include <iostream>
 #include <cassert>
 
 #ifdef HAVE_SYS_STAT_H
-#	include <sys/types.h>
-#	include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #endif // HAVE_SYS_STAT_H
 
-#include <X11/keysym.h>
+#include <X11/Xatom.h>
 
-// Utility method for extracting name from window
+#include <iostream>
+#include <algorithm>
+using namespace std;
 namespace {
 
 void getWMName(BScreen *screen, Window window, std::string& name) {
@@ -62,7 +66,7 @@ void getWMName(BScreen *screen, Window window, std::string& name) {
     if (screen == 0 || window == None)
         return;
 
-    Display *display = BaseDisplay::getXDisplay();
+    Display *display = FbTk::App::instance()->display();
 
     XTextProperty text_prop;
     char **list;
@@ -87,33 +91,162 @@ void getWMName(BScreen *screen, Window window, std::string& name) {
                 name = (char *)text_prop.value;
         } else { // default name
             name = i18n->getMessage(
-                FBNLS::WindowSet, FBNLS::WindowUnnamed,
-                "Unnamed");
+                                    FBNLS::WindowSet, FBNLS::WindowUnnamed,
+                                    "Unnamed");
         }
     } else {
         // default name
         name = i18n->getMessage(
-            FBNLS::WindowSet, FBNLS::WindowUnnamed,
-            "Unnamed");
+                                FBNLS::WindowSet, FBNLS::WindowUnnamed,
+                                "Unnamed");
     }
 
 }
 
+};
+/// holds slit client info
+class SlitClient {
+public:
+    /// For adding an actual window
+    SlitClient(BScreen *screen, Window win) {
+        initialize(screen, win);
+    }
+    /// For adding a placeholder
+    explicit SlitClient(const char *name) { 
+        initialize();
+        match_name = (name == 0 ? "" : name);
+
+    }
+
+    // Now we pre-initialize a list of slit clients with names for
+    // comparison with incoming client windows.  This allows the slit
+    // to maintain a sorted order based on a saved window name list.
+    // Incoming windows not found in the list are appended.  Matching
+    // duplicates are inserted after the last found instance of the
+    // matching name.
+    std::string match_name;
+
+    Window window, client_window, icon_window;
+
+    int x, y;
+    unsigned int width, height;
+    bool visible; ///< wheter the client should be visible or not
+
+    void initialize(BScreen *screen = 0, Window win= None) {
+        client_window = win;
+        window = icon_window = None;
+        x = y = 0;
+        width = height = 0;
+        if (match_name.size() == 0)
+            getWMName(screen, client_window, match_name);
+        visible = true;        
+    }
+    void disableEvents() {
+        Display *disp = FbTk::App::instance()->display();
+        XSelectInput(disp, window, NoEventMask);
+    }
+    void enableEvents() {
+        Display *disp = FbTk::App::instance()->display();
+        XSelectInput(disp, window, StructureNotifyMask |
+                 SubstructureNotifyMask | EnterWindowMask);
+    }
+};
+
+namespace { 
+
+class SlitClientMenuItem: public FbTk::MenuItem {
+public:
+    explicit SlitClientMenuItem(SlitClient &client, FbTk::RefCount<FbTk::Command> &cmd):
+        FbTk::MenuItem(client.match_name.c_str(), cmd), m_client(client) {
+        FbTk::MenuItem::setSelected(client.visible);
+    }
+    const std::string &label() const {
+        return m_client.match_name;
+    }
+    bool isSelected() const {
+        return m_client.visible;
+    }
+    void click(int button, int time) { 
+        m_client.visible = !m_client.visible;
+        FbTk::MenuItem::click(button, time);
+    }
+private:
+    SlitClient &m_client;
+};
+
+class SlitDirMenuItem: public FbTk::MenuItem {
+public:
+    SlitDirMenuItem(const char *label, Slit &slit):FbTk::MenuItem(label), 
+                                                   m_slit(slit), 
+                                                   m_label(label ? label : "") { 
+        setLabel(m_label.c_str()); // update label
+    }
+    void click(int button, int time) {
+        // toggle direction
+        if (m_slit.direction() == Slit::HORIZONTAL)
+            m_slit.setDirection(Slit::VERTICAL);
+        else
+            m_slit.setDirection(Slit::HORIZONTAL);
+        setLabel(m_label.c_str());
+    }
+
+    void setLabel(const char *label) {
+        I18n *i18n = I18n::instance();
+        m_label = (label ? label : "");
+        std::string reallabel = m_label + " " + 
+            ( m_slit.direction() == Slit::HORIZONTAL ? 
+              i18n->getMessage(
+                               FBNLS::CommonSet, FBNLS::CommonDirectionHoriz,
+                               "Horizontal") :
+              i18n->getMessage(
+                               FBNLS::CommonSet, FBNLS::CommonDirectionVert,
+                               "Vertical") );
+        FbTk::MenuItem::setLabel(reallabel.c_str());
+    }
+private:
+    Slit &m_slit;
+    std::string m_label;
+};
+
+class PlaceSlitMenuItem: public FbTk::MenuItem {
+public:
+    PlaceSlitMenuItem(const char *label, Slit &slit, Slit::Placement place):
+        FbTk::MenuItem(label), m_slit(slit), m_place(place) {
+     
+    }
+    bool isEnabled() const { return m_slit.placement() != m_place; }
+    void click(int button, int time) {
+        m_slit.setPlacement(m_place);
+    }
+private:
+    Slit &m_slit;
+    Slit::Placement m_place;
+};
+
+
 }; // End anonymous namespace
 
-Slit::Slit(BScreen *scr):m_screen(scr), timer(this), slitmenu(*this) {
-    assert(scr);
-    Fluxbox * const fluxbox = Fluxbox::instance();
+Slit::Slit(BScreen &scr, const char *filename):m_screen(&scr), timer(this), 
+                         slitmenu(*scr.menuTheme(), 
+                                  scr.getScreenNumber(), 
+                                  *scr.getImageControl()),
+                         placement_menu(*scr.menuTheme(),
+                         scr.getScreenNumber(),
+                         *scr.getImageControl()),
+                         clientlist_menu(*scr.menuTheme(),
+                         scr.getScreenNumber(),
+                         *scr.getImageControl())  {
 
-    on_top = screen()->isSlitOnTop();
-    hidden = do_auto_hide = screen()->doSlitAutoHide();
+    // default placement and direction
+    m_direction = HORIZONTAL;
+    m_placement = TOPLEFT;
+    on_top = false;
+    hidden = do_auto_hide = false;
 
-	
-    frame.window = frame.pixmap = None;
+    frame.pixmap = None;
 
-	
-    timer.setTimeout(fluxbox->getAutoRaiseDelay());
-    timer.fireOnce(True);
+    timer.setTimeout(200); // default timeout
+    timer.fireOnce(true);
 
     XSetWindowAttributes attrib;
     unsigned long create_mask = CWBackPixmap | CWBackPixel | CWBorderPixel |
@@ -128,39 +261,42 @@ Slit::Slit(BScreen *scr):m_screen(scr), timer(this), slitmenu(*this) {
 
     frame.x = frame.y = 0;
     frame.width = frame.height = 1;
-
+    Display *disp = FbTk::App::instance()->display();
     frame.window =
-        XCreateWindow(BaseDisplay::getXDisplay(), screen()->getRootWindow(), frame.x, frame.y,
+        XCreateWindow(disp, screen()->getRootWindow(), frame.x, frame.y,
                       frame.width, frame.height, screen()->getBorderWidth(),
                       screen()->getDepth(), InputOutput, screen()->getVisual(),
                       create_mask, &attrib);
-    fluxbox->saveSlitSearch(frame.window, this);
 
+    FbTk::EventManager::instance()->add(*this, frame.window);
+
+    //For KDE dock applets
+    kwm1_dockwindow = XInternAtom(disp, "KWM_DOCKWINDOW", False); //KDE v1.x
+    kwm2_dockwindow = XInternAtom(disp, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); //KDE v2.x
+    
     // Get client list for sorting purposes
-    loadClientList();
+    loadClientList(filename);
+
+    setupMenu();
 
     reconfigure();
 }
 
 
 Slit::~Slit() {
-    screen()->getImageControl()->removeImage(frame.pixmap);
-
-    Fluxbox::instance()->removeSlitSearch(frame.window);
-
-    XDestroyWindow(BaseDisplay::getXDisplay(), frame.window);
+    if (frame.pixmap != 0)
+        screen()->getImageControl()->removeImage(frame.pixmap);
 }
 
 
 void Slit::addClient(Window w) {
-
+#ifdef DEBUG
+    cerr<<"Slit::addClient()"<<endl;
+#endif // DEBUG
     //Can't add non existent window
     if (w == None)
         return;
 
-    if (!Fluxbox::instance()->validateWindow(w)) 
-        return;
-
     // Look for slot in client list by name
     SlitClient *client = 0;
     std::string match_name;
@@ -192,10 +328,11 @@ void Slit::addClient(Window w) {
         client = new SlitClient(screen(), w);
         clientList.push_back(client);
     }
-    Display *disp = BaseDisplay::getXDisplay();
+
+    Display *disp = FbTk::App::instance()->display();
     XWMHints *wmhints = XGetWMHints(disp, w);
 
-    if (wmhints) {
+    if (wmhints != 0) {
         if ((wmhints->flags & IconWindowHint) &&
             (wmhints->icon_window != None)) {
             XMoveWindow(disp, client->client_window, screen()->getWidth() + 10,
@@ -213,9 +350,11 @@ void Slit::addClient(Window w) {
         client->icon_window = None;
         client->window = client->client_window;
     }
+
     XWindowAttributes attrib;
+    
 #ifdef KDE
-    Fluxbox *fluxbox = Fluxbox::instance();
+
     //Check and see if new client is a KDE dock applet
     //If so force reasonable size
     bool iskdedockapp=false;
@@ -225,8 +364,8 @@ void Slit::addClient(Window w) {
 
     // Check if KDE v2.x dock applet
     if (XGetWindowProperty(disp, w,
-                           fluxbox->getKWM2DockwindowAtom(), 0l, 1l, False,
-                           fluxbox->getKWM2DockwindowAtom(),
+                           kwm2_dockwindow, 0l, 1l, False,
+                           kwm2_dockwindow,
                            &ajunk, &ijunk, &uljunk, &uljunk,
                            (unsigned char **) &data) == Success) {
         iskdedockapp = (data && data[0] != 0);
@@ -236,8 +375,8 @@ void Slit::addClient(Window w) {
     // Check if KDE v1.x dock applet
     if (!iskdedockapp) {
         if (XGetWindowProperty(disp, w,
-                               fluxbox->getKWM1DockwindowAtom(), 0l, 1l, False,
-                               fluxbox->getKWM1DockwindowAtom(),
+                               kwm1_dockwindow, 0l, 1l, False,
+                               kwm1_dockwindow,
                                &ajunk, &ijunk, &uljunk, &uljunk,
                                (unsigned char **) &data) == Success) {
             iskdedockapp = (data && data[0] != 0);
@@ -249,42 +388,64 @@ void Slit::addClient(Window w) {
         client->width = client->height = 24;
     else
 #endif // KDE
-	{
+    
+        {
             if (XGetWindowAttributes(disp, client->window, &attrib)) {
                 client->width = attrib.width;
                 client->height = attrib.height;
-            } else {
+            } else { // set default size if we failed to get window attributes
                 client->width = client->height = 64;
             }
-	}
+        }
 
+    // disable border for client window
     XSetWindowBorderWidth(disp, client->window, 0);
 
-    XSelectInput(disp, frame.window, NoEventMask);
-    XSelectInput(disp, client->window, NoEventMask);
+    // disable events to frame.window
+    frame.window.setEventMask(NoEventMask);
+    client->disableEvents();
 
-    XReparentWindow(disp, client->window, frame.window, 0, 0);
+    XReparentWindow(disp, client->window, frame.window.window(), 0, 0);
     XMapRaised(disp, client->window);
     XChangeSaveSet(disp, client->window, SetModeInsert);
-
-    XSelectInput(disp, frame.window, SubstructureRedirectMask |
-                 ButtonPressMask | EnterWindowMask | LeaveWindowMask);
-    XSelectInput(disp, client->window, StructureNotifyMask |
-                 SubstructureNotifyMask | EnterWindowMask);
+    // reactivate events for frame.window
+    frame.window.setEventMask(SubstructureRedirectMask |
+                              ButtonPressMask | EnterWindowMask | LeaveWindowMask);
+    // setup event for slit client window
+    client->enableEvents();
+    // flush events
     XFlush(disp);
+    // add slit client to eventmanager
+    FbTk::EventManager::instance()->add(*this, client->client_window);
+    FbTk::EventManager::instance()->add(*this, client->icon_window);
 
-    Fluxbox::instance()->saveSlitSearch(client->client_window, this);
-    Fluxbox::instance()->saveSlitSearch(client->icon_window, this);
+    frame.window.show();
+    frame.window.clear();
     reconfigure();
 
+    updateClientmenu();
+
     saveClientList();
 
 }
 
+void Slit::setDirection(Direction dir) {
+    m_direction = dir;
+    reconfigure();
+}
+
+void Slit::setPlacement(Placement place) {
+    m_placement = place;
+    reconfigure();
+}
 
 void Slit::removeClient(SlitClient *client, bool remap, bool destroy) {
-    Fluxbox::instance()->removeSlitSearch(client->client_window);
-    Fluxbox::instance()->removeSlitSearch(client->icon_window);
+#ifdef DEBUG
+    cerr<<"Slit::removeClient()"<<endl;
+#endif // DEBUG
+    // remove from event manager
+    FbTk::EventManager::instance()->remove(client->client_window);
+    FbTk::EventManager::instance()->remove(client->icon_window);
 
     // Destructive removal?
     if (destroy)
@@ -294,21 +455,26 @@ void Slit::removeClient(SlitClient *client, bool remap, bool destroy) {
 
     screen()->removeNetizen(client->window);
 
-    if (remap && Fluxbox::instance()->validateWindow(client->window)) {
-        Display *disp = BaseDisplay::getXDisplay();
-        XSelectInput(disp, frame.window, NoEventMask);
-        XSelectInput(disp, client->window, NoEventMask);
+    if (remap) {
+        Display *disp = FbTk::App::instance()->display();
+        if (!client->visible)
+            XMapWindow(disp, client->window);
+        client->disableEvents();
+        // stop events to frame.window temporarly
+        frame.window.setEventMask(NoEventMask);
         XReparentWindow(disp, client->window, screen()->getRootWindow(),
 			client->x, client->y);
         XChangeSaveSet(disp, client->window, SetModeDelete);
-        XSelectInput(disp, frame.window, SubstructureRedirectMask |
-                     ButtonPressMask | EnterWindowMask | LeaveWindowMask);
+        // reactivate events to frame.window
+        frame.window.setEventMask(SubstructureRedirectMask | ButtonPressMask |
+                                  EnterWindowMask | LeaveWindowMask);
         XFlush(disp);
     }
 
     // Destructive removal?
     if (destroy)
         delete client;
+    updateClientmenu();
 }
 
 
@@ -340,97 +506,96 @@ void Slit::reconfigure() {
     // actually correspond to mapped windows.
     int num_windows = 0;
 
-    switch (screen()->getSlitDirection()) {
+    switch (direction()) {
     case VERTICAL: 
-    {
-        SlitClients::iterator it = clientList.begin();
-        SlitClients::iterator it_end = clientList.end();
-        for (; it != it_end; ++it) {
-				//client created window?
-            if ((*it)->window != None) {
-                num_windows++;
-                frame.height += (*it)->height + screen()->getBevelWidth();
+        {
+            SlitClients::iterator it = clientList.begin();
+            SlitClients::iterator it_end = clientList.end();
+            for (; it != it_end; ++it) {
+                //client created window?
+                if ((*it)->window != None && (*it)->visible) {
+                    num_windows++;
+                    frame.height += (*it)->height + screen()->getBevelWidth();
 					
-                //frame width < client window?
-                if (frame.width < (*it)->width) 
-                    frame.width = (*it)->width;
+                    //frame width < client window?
+                    if (frame.width < (*it)->width) 
+                        frame.width = (*it)->width;
+                }
             }
         }
-    }
 
-    if (frame.width < 1)
-        frame.width = 1;
-    else
-        frame.width += (screen()->getBevelWidth() * 2);
+        if (frame.width < 1)
+            frame.width = 1;
+        else
+            frame.width += (screen()->getBevelWidth() * 2);
 
-    if (frame.height < 1)
-        frame.height = 1;
-    else
-        frame.height += screen()->getBevelWidth();
+        if (frame.height < 1)
+            frame.height = 1;
+        else
+            frame.height += screen()->getBevelWidth();
 
-    break;
+        break;
 
     case HORIZONTAL: 
-    {
-        SlitClients::iterator it = clientList.begin();
-        SlitClients::iterator it_end = clientList.end();
-        for (; it != it_end; ++it) {
-				//client created window?
-            if ((*it)->window != None) {
-                num_windows++;
-                frame.width += (*it)->width + screen()->getBevelWidth();
-                //frame height < client height?
-                if (frame.height < (*it)->height)
-                    frame.height = (*it)->height;
+        {
+            SlitClients::iterator it = clientList.begin();
+            SlitClients::iterator it_end = clientList.end();
+            for (; it != it_end; ++it) {
+                //client created window?
+                if ((*it)->window != None && (*it)->visible) {
+                    num_windows++;
+                    frame.width += (*it)->width + screen()->getBevelWidth();
+                    //frame height < client height?
+                    if (frame.height < (*it)->height)
+                        frame.height = (*it)->height;
+                }
             }
         }
-    }
 
-    if (frame.width < 1)
-        frame.width = 1;
-    else
-        frame.width += screen()->getBevelWidth();
+        if (frame.width < 1)
+            frame.width = 1;
+        else
+            frame.width += screen()->getBevelWidth();
 
-    if (frame.height < 1)
-        frame.height = 1;
-    else
-        frame.height += (screen()->getBevelWidth() * 2);
+        if (frame.height < 1)
+            frame.height = 1;
+        else
+            frame.height += (screen()->getBevelWidth() * 2);
 
-    break;
+        break;
     }
 
     reposition();
-    Display *disp = BaseDisplay::getXDisplay();
-
-    XSetWindowBorderWidth(disp, frame.window, screen()->getBorderWidth());
-    XSetWindowBorder(disp, frame.window,
-                     screen()->getBorderColor()->pixel());
+    Display *disp = FbTk::App::instance()->display();
 
+    frame.window.setBorderWidth(screen()->getBorderWidth());
+    frame.window.setBorderColor(*screen()->getBorderColor());
     //did we actually use slit slots
     if (num_windows == 0)
-        XUnmapWindow(disp, frame.window);
+        frame.window.hide();
     else
-        XMapWindow(disp, frame.window);
+        frame.window.show();
 
     Pixmap tmp = frame.pixmap;
     FbTk::ImageControl *image_ctrl = screen()->getImageControl();
     const FbTk::Texture &texture = screen()->getTheme()->getSlitTexture();
     if (texture.type() == (FbTk::Texture::FLAT | FbTk::Texture::SOLID)) {
         frame.pixmap = None;
-        XSetWindowBackground(disp, frame.window, texture.color().pixel());
+        frame.window.setBackgroundColor(texture.color());
     } else {
         frame.pixmap = image_ctrl->renderImage(frame.width, frame.height,
                                                texture);
-        XSetWindowBackgroundPixmap(disp, frame.window, frame.pixmap);
+        frame.window.setBackgroundPixmap(frame.pixmap);
     }
 
     if (tmp) 
         image_ctrl->removeImage(tmp);
-    XClearWindow(disp, frame.window);
+
+    frame.window.clear();
 
     int x, y;
 
-    switch (screen()->getSlitDirection()) {
+    switch (direction()) {
     case VERTICAL:
         x = 0;
         y = screen()->getBevelWidth();
@@ -439,17 +604,25 @@ void Slit::reconfigure() {
             SlitClients::iterator it = clientList.begin();
             SlitClients::iterator it_end = clientList.end();
             for (; it != it_end; ++it) {
-				//client created window?
                 if ((*it)->window == None)
                     continue;
 
-                x = (frame.width - (*it)->width) / 2;
-                Display *disp = BaseDisplay::getXDisplay();
+                //client created window?
+                if ((*it)->visible) 
+                    XMapWindow(disp, (*it)->window);
+                else {
+                    (*it)->disableEvents();
+                    XUnmapWindow(disp, (*it)->window);
+                    (*it)->enableEvents();
+                    continue;
+                }
+
+                x = (frame.width - (*it)->width) / 2;                
+
                 XMoveResizeWindow(disp, (*it)->window, x, y,
                                   (*it)->width, (*it)->height);
-                XMapWindow(disp, (*it)->window);
 
-				// for ICCCM compliance
+                // for ICCCM compliance
                 (*it)->x = x;
                 (*it)->y = y;
 
@@ -464,7 +637,7 @@ void Slit::reconfigure() {
                 event.xconfigure.width = (*it)->width;
                 event.xconfigure.height = (*it)->height;
                 event.xconfigure.border_width = 0;
-                event.xconfigure.above = frame.window;
+                event.xconfigure.above = frame.window.window();
                 event.xconfigure.override_redirect = False;
 
                 XSendEvent(disp, (*it)->window, False, StructureNotifyMask,
@@ -481,20 +654,33 @@ void Slit::reconfigure() {
         y = 0;
 
         {
+            cerr<<"Clients: "<<clientList.size()<<endl;
             SlitClients::iterator it = clientList.begin();
             SlitClients::iterator it_end = clientList.end();
             for (; it != it_end; ++it) {
-				//client created window?
+                //client created window?
                 if ((*it)->window == None)
                     continue;
 
+                if ((*it)->visible) { 
+                    XMapWindow(disp, (*it)->window);
+                } else {
+                    (*it)->disableEvents();
+                    XUnmapWindow(disp, (*it)->window);
+                    (*it)->enableEvents();
+                    continue;
+                }
+
                 y = (frame.height - (*it)->height) / 2;
 
                 XMoveResizeWindow(disp, (*it)->window, x, y,
                                   (*it)->width, (*it)->height);
-                XMapWindow(disp, (*it)->window);
 
-				// for ICCCM compliance
+
+
+
+
+                // for ICCCM compliance
                 (*it)->x = x;
                 (*it)->y = y;
 
@@ -509,7 +695,7 @@ void Slit::reconfigure() {
                 event.xconfigure.width = (*it)->width;
                 event.xconfigure.height = (*it)->height;
                 event.xconfigure.border_width = 0;
-                event.xconfigure.above = frame.window;
+                event.xconfigure.above = frame.window.window();
                 event.xconfigure.override_redirect = False;
 
                 XSendEvent(disp, (*it)->window, False, StructureNotifyMask,
@@ -523,6 +709,7 @@ void Slit::reconfigure() {
     }
 
     slitmenu.reconfigure();
+    updateClientmenu();
 }
 
 
@@ -531,29 +718,16 @@ void Slit::reposition() {
         head_y = 0,
         head_w,
         head_h;
-#ifdef XINERAMA
-    if (screen()->hasXinerama()) {
-        unsigned int head = screen()->getSlitOnHead();
-
-        head_x = screen()->getHeadX(head);
-        head_y = screen()->getHeadY(head);
-        head_w = screen()->getHeadWidth(head);
-        head_h = screen()->getHeadHeight(head);
-    } else {
-        head_w = screen()->getWidth();
-        head_h = screen()->getHeight();
-    }
-#else // !XINERAMA
+
     head_w = screen()->getWidth();
     head_h = screen()->getHeight();
-#endif // XINERAMA
 
     // place the slit in the appropriate place
-    switch (screen()->getSlitPlacement()) {
+    switch (placement()) {
     case TOPLEFT:
         frame.x = head_x;
         frame.y = head_y;
-        if (screen()->getSlitDirection() == VERTICAL) {
+        if (direction() == VERTICAL) {
             frame.x_hidden = screen()->getBevelWidth() -
                 screen()->getBorderWidth() - frame.width;
             frame.y_hidden = head_y;
@@ -575,7 +749,7 @@ void Slit::reposition() {
     case BOTTOMLEFT:
         frame.x = head_x;
         frame.y = head_h - frame.height - screen()->getBorderWidth2x();
-        if (screen()->getSlitDirection() == VERTICAL) {
+        if (direction() == VERTICAL) {
             frame.x_hidden = head_x + screen()->getBevelWidth() -
                 screen()->getBorderWidth() - frame.width;
             frame.y_hidden = frame.y;
@@ -605,7 +779,7 @@ void Slit::reposition() {
     case TOPRIGHT:
         frame.x = head_x + head_w - frame.width - screen()->getBorderWidth2x();
         frame.y = head_y;
-        if (screen()->getSlitDirection() == VERTICAL) {
+        if (direction() == VERTICAL) {
             frame.x_hidden = head_x + head_w -
                 screen()->getBevelWidth() - screen()->getBorderWidth();
             frame.y_hidden = head_y;
@@ -628,7 +802,7 @@ void Slit::reposition() {
     case BOTTOMRIGHT:
         frame.x = head_x + head_w - frame.width - screen()->getBorderWidth2x();
         frame.y = head_y + head_h - frame.height - screen()->getBorderWidth2x();
-        if (screen()->getSlitDirection() == VERTICAL) {
+        if (direction() == VERTICAL) {
             frame.x_hidden = head_x + head_w - 
                 screen()->getBevelWidth() - screen()->getBorderWidth();
             frame.y_hidden = frame.y;
@@ -640,62 +814,99 @@ void Slit::reposition() {
         break;
     }
 
-    const Toolbar * const tbar = screen()->getToolbar();
-    int sw = frame.width + screen()->getBorderWidth2x(),
-        sh = frame.height + screen()->getBorderWidth2x(),
-        tw = tbar->width() + screen()->getBorderWidth(),
-        th = tbar->height() + screen()->getBorderWidth();
-
-    if (tbar->x() < frame.x + sw && tbar->x() + tw > frame.x &&
-        tbar->y() < frame.y + sh && tbar->y() + th > frame.y) {
-        if (frame.y < th) {
-            frame.y += tbar->exposedHeight();
-            if (screen()->getSlitDirection() == VERTICAL)
-                frame.y_hidden += tbar->exposedHeight();
-            else
-                frame.y_hidden = frame.y;
-        } else {
-            frame.y -= tbar->exposedHeight();
-            if (screen()->getSlitDirection() == VERTICAL)
-                frame.y_hidden -= tbar->exposedHeight();
-            else
-                frame.y_hidden = frame.y;
-        }
-    }
-
-    Display *disp = BaseDisplay::getXDisplay();
-
     if (hidden) {
-        XMoveResizeWindow(disp, frame.window, frame.x_hidden,
-                          frame.y_hidden, frame.width, frame.height);
+        frame.window.moveResize(frame.x_hidden,
+                                frame.y_hidden, frame.width, frame.height);
     } else {
-        XMoveResizeWindow(disp, frame.window, frame.x,
-                          frame.y, frame.width, frame.height);
+        frame.window.moveResize(frame.x,
+                                frame.y, frame.width, frame.height);
     }
 }
 
 
 void Slit::shutdown() {
     saveClientList();
-    while (clientList.size() != 0)
+    while (!clientList.empty())
         removeClient(clientList.front(), true, true);
 }
 
+void Slit::cycleClientsUp() {
+    // rotate client list up, ie the first goes last
+    SlitClients::iterator it = clientList.begin();
+    SlitClient *client = *it;
+    clientList.erase(it);
+    clientList.push_back(client);
+    reconfigure();
+}
+
+void Slit::cycleClientsDown() {
+    // rotate client list down, ie the last goes first
+    SlitClient *client = clientList.back();
+    clientList.remove(client);
+    clientList.push_front(client);
+    reconfigure();
+}
+
+void Slit::handleEvent(XEvent &event) {
+    if (event.type == DestroyNotify) {
+        removeClient(event.xdestroywindow.window, false);
+    } else if (event.type == UnmapNotify) {        
+        removeClient(event.xany.window);
+    } else if (event.type == MapRequest) {
+#ifdef KDE
+        //Check and see if client is KDE dock applet.
+        //If so add to Slit
+        bool iskdedockapp = false;
+        Atom ajunk;
+        int ijunk;
+        unsigned long *data = (unsigned long *) 0, uljunk;
+        Display *disp = FbTk::App::instance()->display();
+        // Check if KDE v2.x dock applet
+        if (XGetWindowProperty(disp, event.xmaprequest.window,
+                               kwm2_dockwindow, 0l, 1l, False,
+                               XA_WINDOW, &ajunk, &ijunk, &uljunk,
+                               &uljunk, (unsigned char **) &data) == Success) {
+					
+            if (data)
+                iskdedockapp = True;
+            XFree((char *) data);
+	
+        }
+
+        // Check if KDE v1.x dock applet
+        if (!iskdedockapp) {
+            if (XGetWindowProperty(disp, event.xmaprequest.window,
+                                   kwm1_dockwindow, 0l, 1l, False,
+                                   kwm1_dockwindow, &ajunk, &ijunk, &uljunk,
+                                   &uljunk, (unsigned char **) &data) == Success) {
+                iskdedockapp = (data && data[0] != 0);
+                XFree((char *) data);
+            }
+        }
 
-void Slit::buttonPressEvent(XButtonEvent *e) {
-    if (e->window != frame.window) 
+        if (iskdedockapp) {
+            XSelectInput(disp, event.xmaprequest.window, StructureNotifyMask);
+            addClient(event.xmaprequest.window);
+        }
+#endif //KDE
+        
+    }
+}
+
+void Slit::buttonPressEvent(XButtonEvent &e) {
+    if (e.window != frame.window.window()) 
         return;
 
-    if (e->button == Button1 && (! on_top)) {
+    if (e.button == Button1 && (! on_top)) {
         Workspace::Stack st;
-        st.push_back(frame.window);
+        st.push_back(frame.window.window());
         screen()->raiseWindows(st);
-    } else if (e->button == Button2 && (! on_top)) {
-        XLowerWindow(BaseDisplay::getXDisplay(), frame.window);
-    } else if (e->button == Button3) {
+    } else if (e.button == Button2 && (! on_top)) {
+        frame.window.lower();
+    } else if (e.button == Button3) {
         if (! slitmenu.isVisible()) {
-            int x = e->x_root - (slitmenu.width() / 2),
-                y = e->y_root - (slitmenu.height() / 2); 
+            int x = e.x_root - (slitmenu.width() / 2),
+                y = e.y_root - (slitmenu.height() / 2); 
 
             if (x < 0)
                 x = 0;
@@ -711,11 +922,15 @@ void Slit::buttonPressEvent(XButtonEvent *e) {
             slitmenu.show();
         } else
             slitmenu.hide();
+    } else if (e.button == 4) {
+        cycleClientsUp();
+    } else if (e.button == 5) {
+        cycleClientsDown();
     }
 }
 
 
-void Slit::enterNotifyEvent(XCrossingEvent *) {
+void Slit::enterNotifyEvent(XCrossingEvent &) {
     if (! do_auto_hide)
         return;
 
@@ -729,7 +944,7 @@ void Slit::enterNotifyEvent(XCrossingEvent *) {
 }
 
 
-void Slit::leaveNotifyEvent(XCrossingEvent *) {
+void Slit::leaveNotifyEvent(XCrossingEvent &ev) {
     if (! do_auto_hide)
         return;
 
@@ -740,35 +955,33 @@ void Slit::leaveNotifyEvent(XCrossingEvent *) {
         if (! timer.isTiming()) 
             timer.start();
     }
-}
-
 
-void Slit::configureRequestEvent(XConfigureRequestEvent *e) {
+}
 
-    if (!Fluxbox::instance()->validateWindow(e->window))
-        return;
 
+void Slit::configureRequestEvent(XConfigureRequestEvent &event) {
     bool reconf = false;
     XWindowChanges xwc;
 
-    xwc.x = e->x;
-    xwc.y = e->y;
-    xwc.width = e->width;
-    xwc.height = e->height;
+    xwc.x = event.x;
+    xwc.y = event.y;
+    xwc.width = event.width;
+    xwc.height = event.height;
     xwc.border_width = 0;
-    xwc.sibling = e->above;
-    xwc.stack_mode = e->detail;
+    xwc.sibling = event.above;
+    xwc.stack_mode = event.detail;
 
-    XConfigureWindow(BaseDisplay::getXDisplay(), e->window, e->value_mask, &xwc);
+    XConfigureWindow(FbTk::App::instance()->display(), 
+                     event.window, event.value_mask, &xwc);
 
     SlitClients::iterator it = clientList.begin();
     SlitClients::iterator it_end = clientList.end();
     for (; it != it_end; ++it) {
-        if ((*it)->window == e->window) {
-            if ((*it)->width != ((unsigned) e->width) ||
-                (*it)->height != ((unsigned) e->height)) {
-                (*it)->width = (unsigned) e->width;
-                (*it)->height = (unsigned) e->height;
+        if ((*it)->window == event.window) {
+            if ((*it)->width != ((unsigned) event.width) ||
+                (*it)->height != ((unsigned) event.height)) {
+                (*it)->width = (unsigned) event.width;
+                (*it)->height = (unsigned) event.height;
 
                 reconf = true; //requires reconfiguration
 
@@ -783,24 +996,27 @@ void Slit::configureRequestEvent(XConfigureRequestEvent *e) {
 
 
 void Slit::timeout() {
-    hidden = ! hidden;
-    Display *disp = BaseDisplay::getXDisplay();
+    hidden = ! hidden; // toggle hidden state
     if (hidden)
-        XMoveWindow(disp, frame.window, frame.x_hidden, frame.y_hidden);
+        frame.window.move(frame.x_hidden, frame.y_hidden);
     else
-        XMoveWindow(disp, frame.window, frame.x, frame.y);
+        frame.window.move(frame.x, frame.y);
 }
 
-void Slit::loadClientList() {
-    const std::string &filename = Fluxbox::instance()->getSlitlistFilename();
+void Slit::loadClientList(const char *filename) {
+    if (filename == 0)
+        return;
+
+    m_filename = filename; // save filename so we can save client list later
+
     struct stat buf;
-    if (!stat(filename.c_str(), &buf)) {
-        std::ifstream file(Fluxbox::instance()->getSlitlistFilename().c_str());
+    if (!stat(filename, &buf)) {
+        std::ifstream file(filename);
         std::string name;
         while (! file.eof()) {
             name = "";
             std::getline(file, name); // get the entire line
-            if (name.size() > 0) {
+            if (name.size() > 0) { // don't add client unless we have a valid line
                 SlitClient *client = new SlitClient(name.c_str());
                 clientList.push_back(client);
             }
@@ -808,9 +1024,30 @@ void Slit::loadClientList() {
     }
 }
 
+void Slit::updateClientmenu() {
+    // clear old items
+    clientlist_menu.removeAll();
+    clientlist_menu.setLabel("Clients");
+    FbTk::RefCount<FbTk::Command> cycle_up(new FbTk::SimpleCommand<Slit>(*this, &Slit::cycleClientsUp));
+    FbTk::RefCount<FbTk::Command> cycle_down(new FbTk::SimpleCommand<Slit>(*this, &Slit::cycleClientsDown));
+    clientlist_menu.insert("Cycle Up", cycle_up);
+    clientlist_menu.insert("Cycle Down", cycle_down);
+    FbTk::MenuItem *separator = new FbTk::MenuItem("-------");
+    separator->setEnabled(false);
+    clientlist_menu.insert(separator);
+    FbTk::RefCount<FbTk::Command> reconfig(new FbTk::SimpleCommand<Slit>(*this, &Slit::reconfigure));
+    SlitClients::iterator it = clientList.begin();
+    for (; it != clientList.end(); ++it) {
+        if ((*it) != 0)
+            clientlist_menu.insert(new SlitClientMenuItem(*(*it), reconfig));
+    }
+
+    clientlist_menu.update();
+}
+
 void Slit::saveClientList() {
-    const std::string &filename = Fluxbox::instance()->getSlitlistFilename();
-    std::ofstream file(filename.c_str());
+
+    std::ofstream file(m_filename.c_str());
     SlitClients::iterator it = clientList.begin();
     SlitClients::iterator it_end = clientList.end();
     std::string prevName;
@@ -823,10 +1060,8 @@ void Slit::saveClientList() {
         prevName = name;
     }
 }
+
 void Slit::setOnTop(bool val) {
-    on_top = val;
-    screen()->saveSlitOnTop(val);
-			
     if (isOnTop())
         screen()->raiseWindows(Workspace::Stack());
 
@@ -835,277 +1070,77 @@ void Slit::setOnTop(bool val) {
 
 void Slit::setAutoHide(bool val) {
     do_auto_hide = val;
-    screen()->saveSlitAutoHide(val);
 }
 
-Slitmenu::Slitmenu(Slit &sl) : Basemenu(sl.screen()),
-                               slit(sl),
-#ifdef XINERAMA
-                               m_headmenu(0),
-#endif // XINERAMA 
-                               m_placementmenu(*this),
-                               m_directionmenu(*this) {
-
+void Slit::setupMenu() {
     I18n *i18n = I18n::instance();
     using namespace FBNLS;
-    setLabel(i18n->getMessage(
-        SlitSet, SlitSlitTitle,
-        "Slit"));
-    setInternalMenu();
-
-
-#ifdef XINERAMA
-    if (screen()->hasXinerama()) { // only create if we need
-        m_headmenu.reset(new Headmenu(*this));
-    }
-#endif // XINERAMA
-
-    insert(i18n->getMessage(
-        CommonSet, CommonDirectionTitle,
-        "Direction"),
-           &m_directionmenu);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementTitle,
-        "Placement"),
-           &m_placementmenu);
-
-#ifdef XINERAMA
-    if (screen()->hasXinerama()) {
-        insert(i18n->getMessage(0, 0, "Place on Head"), m_headmenu.get());
-    }
-#endif // XINERAMA
-
-    insert(i18n->getMessage(
-        CommonSet, CommonAlwaysOnTop,
-        "Always on top"), 1);
-    insert(i18n->getMessage(
-        CommonSet, CommonAutoHide,
-        "Auto hide"), 2);
-
-    setItemSelected(2, slit.isOnTop());
-    setItemSelected(3, slit.doAutoHide());
-	
-    update();
-
-}
-
-
-Slitmenu::~Slitmenu() {
-
-}
-
-
-void Slitmenu::itemSelected(int button, unsigned int index) {
-    if (button == 1) {
-        BasemenuItem *item = find(index);
-        if (! item) return;
-
-        switch (item->function()) {
-        case 1:
-            // toggle on top
-            slit.setOnTop(slit.isOnTop() ? false : true);
-            setItemSelected(2, slit.isOnTop());
-            break;
-        case 2: // auto hide
-            slit.setAutoHide(slit.doAutoHide() ? false : true);
-            setItemSelected(3, slit.doAutoHide());
-            break;
-        }
-		
-        //save the new configuration
-        Fluxbox::instance()->save_rc();
-        update();
-    }
-}
-
-
-void Slitmenu::internal_hide() {
-    Basemenu::internal_hide();
-    if (slit.doAutoHide())
-        slit.timeout();
-}
-
-
-void Slitmenu::reconfigure() {
-    m_directionmenu.reconfigure();
-    m_placementmenu.reconfigure();
-#ifdef XINERAMA
-    if (m_headmenu.get() != 0) {
-        m_headmenu->reconfigure();
-    }
-#endif // XINERAMA
-    setItemSelected(2, slit.isOnTop());
-    setItemSelected(3, slit.doAutoHide());
-
-    Basemenu::reconfigure();
-}
-
-
-Slitmenu::Directionmenu::Directionmenu(Slitmenu &sm) : Basemenu(sm.screen()),
-                                                       slitmenu(sm) {
-
-    I18n *i18n = I18n::instance();
-    using namespace FBNLS;	
-    setLabel(i18n->getMessage(
-        SlitSet, SlitSlitDirection,
-        "Slit Direction"));
-    setInternalMenu();
-
-    insert(i18n->getMessage(
-        CommonSet, CommonDirectionHoriz,
-        "Horizontal"),
-           Slit::HORIZONTAL);
-    insert(i18n->getMessage(
-        CommonSet, CommonDirectionVert,
-        "Vertical"),
-           Slit::VERTICAL);
-
-    update();
-
-    if (screen()->getSlitDirection() == Slit::HORIZONTAL)
-        setItemSelected(0, true);
-    else
-        setItemSelected(1, true);
-}
-
-
-void Slitmenu::Directionmenu::itemSelected(int button, unsigned int index) {
-    if (button == 1) {
-        BasemenuItem *item = find(index);
-        if (item == 0)
-            return;
-
-        screen()->saveSlitDirection(item->function());
-
-        if (item->function() == Slit::HORIZONTAL) {
-            setItemSelected(0, true);
-            setItemSelected(1, false);
+    using namespace FbTk;
+
+    RefCount<Command> menu_cmd(new SimpleCommand<Slit>(*this, &Slit::reconfigure));
+    // setup base menu
+    slitmenu.setLabel("Slit");
+    slitmenu.insert(i18n->getMessage(
+                                     CommonSet, CommonPlacementTitle,
+                                     "Placement"),
+                    &placement_menu);
+    slitmenu.insert(new BoolMenuItem(i18n->getMessage(
+                                                      CommonSet, CommonAlwaysOnTop,
+                                                      "Always on top"),
+                                     on_top,
+                                     menu_cmd));
+
+    slitmenu.insert(new BoolMenuItem(i18n->getMessage(
+                                                      CommonSet, CommonAutoHide,
+                                                      "Auto hide"),
+                                     do_auto_hide,
+                                     menu_cmd));
+
+    slitmenu.insert(new SlitDirMenuItem(i18n->getMessage(
+                                                         SlitSet, SlitSlitDirection,
+                                                         "Slit Direction"), *this));
+    slitmenu.insert("Clients", &clientlist_menu);
+    slitmenu.update();
+
+    // setup sub menu
+
+    
+    placement_menu.setLabel(i18n->getMessage(
+                                             SlitSet, SlitSlitPlacement,
+                                             "Slit Placement"));
+    placement_menu.setMinimumSublevels(3);
+    placement_menu.setInternalMenu();
+   
+
+    // setup items in sub menu
+    struct {
+        int set;
+        int base;
+        const char *default_str;
+        Placement slit_placement;
+    } place_menu[]  = {
+        {CommonSet, CommonPlacementTopLeft, "Top Left", Slit::TOPLEFT},
+        {CommonSet, CommonPlacementCenterLeft, "Center Left", Slit::CENTERLEFT},
+        {CommonSet, CommonPlacementBottomLeft, "Bottom Left", Slit::BOTTOMLEFT},
+        {CommonSet, CommonPlacementTopCenter, "Top Center", Slit::TOPCENTER},
+        {0, 0, 0, Slit::TOPLEFT}, // middle item, empty
+        {CommonSet, CommonPlacementBottomCenter, "Bottom Center", Slit::BOTTOMCENTER},
+        {CommonSet, CommonPlacementTopRight, "Top Right", Slit::TOPRIGHT},
+        {CommonSet, CommonPlacementCenterRight, "Center Right", Slit::CENTERRIGHT},
+        {CommonSet, CommonPlacementBottomRight, "Bottom Right", Slit::BOTTOMRIGHT}
+    };
+    // create items in sub menu
+    for (size_t i=0; i<9; ++i) {
+        if (place_menu[i].default_str == 0) {
+            placement_menu.insert("");
         } else {
-            setItemSelected(0, false);
-            setItemSelected(1, true);
+            const char *i18n_str = i18n->getMessage(place_menu[i].set, 
+                                                    place_menu[i].base,
+                                                    place_menu[i].default_str);
+            placement_menu.insert(new PlaceSlitMenuItem(i18n_str, *this,
+                                                        place_menu[i].slit_placement));
         }
-        Fluxbox::instance()->save_rc();
-        hide();		
-        slitmenu.slit.reconfigure();
     }
+    // finaly update sub menu
+    placement_menu.update();
 }
-
-
-Slitmenu::Placementmenu::Placementmenu(Slitmenu &sm) : Basemenu(sm.screen()),
-                                                       slitmenu(sm) {
-
-    I18n *i18n = I18n::instance();
-    using namespace FBNLS;	
-    setLabel(i18n->getMessage(
-        SlitSet, SlitSlitPlacement,
-        "Slit Placement"));
-    setMinimumSublevels(3);
-    setInternalMenu();
-
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementTopLeft,
-        "Top Left"),
-           Slit::TOPLEFT);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementCenterLeft,
-        "Center Left"),
-           Slit::CENTERLEFT);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementBottomLeft,
-        "Bottom Left"),
-           Slit::BOTTOMLEFT);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementTopCenter,
-        "Top Center"),
-           Slit::TOPCENTER);
-    insert("");
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementBottomCenter,
-        "Bottom Center"),
-           Slit::BOTTOMCENTER);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementTopRight,
-        "Top Right"),
-           Slit::TOPRIGHT);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementCenterRight,
-        "Center Right"),
-           Slit::CENTERRIGHT);
-    insert(i18n->getMessage(
-        CommonSet, CommonPlacementBottomRight,
-        "Bottom Right"),
-           Slit::BOTTOMRIGHT);
-
-    update();
-}
-
-
-void Slitmenu::Placementmenu::itemSelected(int button, unsigned int index) {
-    if (button == 1) {
-        BasemenuItem *item = find(index);
-        if (! item) return;
-
-        if (item->function()) {
-            screen()->saveSlitPlacement(item->function());
-            hide();
-            slitmenu.slit.reconfigure();
-            Fluxbox::instance()->save_rc();
-        }
-    }
-}
-
-#ifdef XINERAMA
-
-Slitmenu::Headmenu::Headmenu(Slitmenu &sm): Basemenu(sm.screen()),
-                                            slitmenu(sm) {
-
-    I18n *i18n = I18n::instance();
-
-    setLabel(i18n->getMessage(0, 0, "Place on Head")); //TODO: NLS
-    setInternalMenu();
-
-    int numHeads = screen()->getNumHeads();
-    // fill menu with head entries
-    for (int i = 0; i < numHeads; i++) {
-        char headName[32];
-        sprintf(headName, "Head %i", i+1); //TODO: NLS
-        insert(i18n->getMessage(0, 0, headName), i);
-    }
-
-    update();
-}
-
-void Slitmenu::Headmenu::itemSelected(int button, unsigned int index) {
-    if (button == 1) {
-        BasemenuItem *item = find(index);
-        if (! item)
-            return;
-
-        screen()->saveSlitOnHead(item->function());
-        hide();
-        slitmenu.slit.reconfigure();
-        Fluxbox::instance()->save_rc();
-    }
-}
-
-#endif // XINERAMA
-
-Slit::SlitClient::SlitClient(const char *name) {
-    initialize();
-    match_name = (name == 0 ? "" : name);
-}
-
-Slit::SlitClient::SlitClient(BScreen *screen, Window w) {
-    initialize(screen, w);
-}
-
-void Slit::SlitClient::initialize(BScreen *screen, Window w) {
-    client_window = w;
-    window = icon_window = None;
-    x = y = 0;
-    width = height = 0;
-    if (match_name.size() == 0)
-        getWMName(screen, client_window, match_name);
-}
-
-#endif // SLIT
diff --git a/src/Slit.hh b/src/Slit.hh
index e2542f7..3a7c437 100644
--- a/src/Slit.hh
+++ b/src/Slit.hh
@@ -22,12 +22,14 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 // DEALINGS IN THE SOFTWARE.
 	
-/// $Id: Slit.hh,v 1.17 2003/01/09 22:06:49 fluxgen Exp $
+/// $Id: Slit.hh,v 1.18 2003/01/12 17:53:10 fluxgen Exp $
 
 #ifndef	 SLIT_HH
 #define	 SLIT_HH
 
-#include "Basemenu.hh"
+#include "Menu.hh"
+#include "FbWindow.hh"
+#include "Timer.hh"
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
@@ -35,95 +37,43 @@
 #include <list>
 #include <string>
 #include <memory>
-
-// forward declaration
-class Slit;
-
-/// menu in slit
-class Slitmenu : public Basemenu {
-public:
-    explicit Slitmenu(Slit &theslist);
-    virtual ~Slitmenu();
-
-    const Basemenu &getDirectionmenu() const { return m_directionmenu; }
-    const Basemenu &getPlacementmenu() const { return m_placementmenu; }
-
-#ifdef XINERAMA
-    const Basemenu *getHeadmenu() const { return m_headmenu.get(); }
-#endif // XINERAMA
-
-    void reconfigure();
-
-protected:
-    virtual void itemSelected(int button, unsigned int index);
-    virtual void internal_hide();
-
-private: 
-    class Directionmenu : public Basemenu {
-    public:
-        Directionmenu(Slitmenu &sm);
-
-    protected:
-        virtual void itemSelected(int button, unsigned int index);
-
-    private:
-        Slitmenu &slitmenu;
-    };
-
-    class Placementmenu : public Basemenu {
-    public:
-        Placementmenu(Slitmenu &sm);
-
-    protected: 
-        virtual void itemSelected(int button, unsigned int index);
-
-    private:
-        Slitmenu &slitmenu;
-    };
-
-    Slit &slit;
-
-#ifdef XINERAMA
-    class Headmenu : public Basemenu {
-    public:
-        Headmenu(Slitmenu &sm);
-    protected: 
-        virtual void itemSelected(int button, unsigned int index);
-    private:
-        Slitmenu &slitmenu;
-    };
-    friend class Headmenu;
-    std::auto_ptr<Headmenu> m_headmenu;
-#endif // XINERAMA
-
-    Placementmenu m_placementmenu;
-    Directionmenu m_directionmenu;
-
-
-
-    friend class Directionmenu;
-    friend class Placementmenu;
-};
+class BScreen;
+class SlitClient;
 
 /// Handles dock apps
-class Slit : public FbTk::TimeoutHandler {
+class Slit : public FbTk::TimeoutHandler, public FbTk::EventHandler {
 public:
-    explicit Slit(BScreen *screen);
+    
+    /**
+       Client alignment
+    */
+    enum Direction { VERTICAL = 1, HORIZONTAL };
+    /**
+       Screen placement
+    */
+    enum Placement { TOPLEFT = 1, CENTERLEFT, BOTTOMLEFT, TOPCENTER, BOTTOMCENTER,
+           TOPRIGHT, CENTERRIGHT, BOTTOMRIGHT };
+
+    explicit Slit(BScreen &screen, const char *filename = 0);
     virtual ~Slit();
 
     inline bool isOnTop() const { return on_top; }
     inline bool isHidden() const { return hidden; }
     inline bool doAutoHide() const { return do_auto_hide; }
+    inline Direction direction() const { return m_direction; }
+    inline Placement placement() const { return m_placement; }
+    FbTk::Menu &menu() { return slitmenu; }
 
-    Slitmenu &menu() { return slitmenu; }
-
-    inline const Window &getWindowID() const { return frame.window; }
+    inline Window getWindowID() const { return frame.window.window(); }
 
     inline int x() const { return ((hidden) ? frame.x_hidden : frame.x); }
     inline int y() const { return ((hidden) ? frame.y_hidden : frame.y); }
 
     inline unsigned int width() const { return frame.width; }
     inline unsigned int height() const { return frame.height; }
+
+    void setDirection(Direction dir);
+    void setPlacement(Placement place);
     void setOnTop(bool val);
     void setAutoHide(bool val);
     void addClient(Window clientwin);
@@ -131,57 +81,39 @@ public:
     void reconfigure();
     void reposition();
     void shutdown();
+    /// save clients name in a file
     void saveClientList();
+    /// cycle slit clients up one step
+    void cycleClientsUp();
+    /// cycle slit clients down one step
+    void cycleClientsDown();
+
     BScreen *screen() { return m_screen; }
     const BScreen *screen() const { return m_screen; }
     /**
        @name eventhandlers
     */
     //@{
-    void buttonPressEvent(XButtonEvent *bp);
-    void enterNotifyEvent(XCrossingEvent *en);
-    void leaveNotifyEvent(XCrossingEvent *ln);
-    void configureRequestEvent(XConfigureRequestEvent *cr);
+    void handleEvent(XEvent &event);
+    void buttonPressEvent(XButtonEvent &event);
+    void enterNotifyEvent(XCrossingEvent &event);
+    void leaveNotifyEvent(XCrossingEvent &event);
+    void configureRequestEvent(XConfigureRequestEvent &event);
     //@}
 	
     virtual void timeout();
 
-    /**
-       Client alignment
-    */
-    enum { VERTICAL = 1, HORIZONTAL };
-    /**
-       Screen placement
-    */
-    enum { TOPLEFT = 1, CENTERLEFT, BOTTOMLEFT, TOPCENTER, BOTTOMCENTER,
-           TOPRIGHT, CENTERRIGHT, BOTTOMRIGHT };
 
 private:
-    class SlitClient {
-    public:
-        SlitClient(BScreen *screen, Window client_window);	// For adding an actual window
-        SlitClient(const char *name);		// For adding a placeholder
-
-        // Now we pre-initialize a list of slit clients with names for
-        // comparison with incoming client windows.  This allows the slit
-        // to maintain a sorted order based on a saved window name list.
-        // Incoming windows not found in the list are appended.  Matching
-        // duplicates are inserted after the last found instance of the
-        // matching name.
-        std::string match_name;
-
-        Window window, client_window, icon_window;
-
-        int x, y;
-        unsigned int width, height;
-
-        void initialize(BScreen *screen = 0, Window client_window= None);
-    };
+    void setupMenu();
 	
     void removeClient(SlitClient *client, bool remap, bool destroy);
-    void loadClientList();
-	
+    void loadClientList(const char *filename);
+    void updateClientmenu();
+
     bool on_top, hidden, do_auto_hide;
+    Direction m_direction;
+    Placement m_placement;
 
     BScreen *m_screen;
     FbTk::Timer timer;
@@ -189,17 +121,19 @@ private:
     typedef std::list<SlitClient *> SlitClients;
 
     SlitClients clientList;
-    Slitmenu slitmenu;
+    FbTk::Menu slitmenu, placement_menu, clientlist_menu;
     std::string clientListPath;
+    std::string m_filename;
 
     struct frame {
         Pixmap pixmap;
-        Window window;
+        FbTk::FbWindow window;
 
         int x, y, x_hidden, y_hidden;
         unsigned int width, height;
     } frame;
-
+    // for KDE
+    Atom kwm1_dockwindow, kwm2_dockwindow;
 };
 
 
-- 
cgit v0.11.2