From cc9c7960c1c5413002c3a6c456650e59ee1ff501 Mon Sep 17 00:00:00 2001
From: rathnor <rathnor>
Date: Mon, 19 May 2003 14:26:30 +0000
Subject: add back some xinerama support (toolbar, slit (+menu), screen)

---
 ChangeLog       |   2 +
 RoadMap         |   2 +-
 src/Screen.cc   | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/Screen.hh   |  48 ++++++++++++++++++---
 src/Slit.cc     |  34 +++++++++++++--
 src/Toolbar.cc  |  35 +++++++++++++--
 src/Xinerama.hh | 105 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 336 insertions(+), 22 deletions(-)
 create mode 100644 src/Xinerama.hh

diff --git a/ChangeLog b/ChangeLog
index 6efe266..9475497 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,8 @@
 (Format: Year/Month/Day)
 Changes for 0.9.3:
 *03/05/19:
+   * Add back some Xinerama support (still need placement + maximise) (Simon)
+     Screen.hh/cc Toolbar.cc Slit.cc Xinerama.hh
    * Fix bsetroot segfault (Simon)
      FbWindow.cc
 *03/05/18:
diff --git a/RoadMap b/RoadMap
index e4199e9..cf1457b 100644
--- a/RoadMap
+++ b/RoadMap
@@ -117,7 +117,7 @@ Bugfixes/lower priority:
 Release:      0.9.3
 Approx Date:  26 May, 2003
 Major Features:
- - Xinerama                             (Simon)
+ = Xinerama                             (Simon)
  * XRandr                               (Henrik)
 Minor Features:
  - Add some sort of program launch function (Simon)
diff --git a/src/Screen.cc b/src/Screen.cc
index d3eb39e..aaa2209 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Screen.cc,v 1.171 2003/05/18 22:01:14 fluxgen Exp $
+// $Id: Screen.cc,v 1.172 2003/05/19 14:26:29 rathnor Exp $
 
 
 #include "Screen.hh"
@@ -114,6 +114,12 @@
 #include <X11/Xatom.h>
 #include <X11/keysym.h>
 
+#ifdef XINERAMA
+extern  "C" {
+#include <X11/extensions/Xinerama.h>
+}
+#endif // XINERAMA
+
 #include <iostream>
 #include <memory>
 #include <algorithm>
@@ -480,13 +486,14 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm,
     toolbar_on_head(rm, 0, scrname+".toolbar.onhead", altscrname+".Toolbar.onHead"),
     toolbar_placement(rm, Toolbar::BOTTOMCENTER, 
                       scrname+".toolbar.placement", altscrname+".Toolbar.Placement"),
-     slit_auto_hide(rm, false, 
-                     scrname+".slit.autoHide", altscrname+".Slit.AutoHide"),
-     slit_placement(rm, Slit::BOTTOMRIGHT,
-                    scrname+".slit.placement", altscrname+".Slit.Placement"),
-     slit_direction(rm, Slit::VERTICAL, 
-                    scrname+".slit.direction", altscrname+".Slit.Direction"),
-     slit_alpha(rm, 255, scrname+".slit.alpha", altscrname+".Slit.Alpha") {
+    slit_auto_hide(rm, false, 
+                   scrname+".slit.autoHide", altscrname+".Slit.AutoHide"),
+    slit_placement(rm, Slit::BOTTOMRIGHT,
+                   scrname+".slit.placement", altscrname+".Slit.Placement"),
+    slit_direction(rm, Slit::VERTICAL, 
+                   scrname+".slit.direction", altscrname+".Slit.Direction"),
+    slit_alpha(rm, 255, scrname+".slit.alpha", altscrname+".Slit.Alpha"),
+    slit_on_head(rm, 0, scrname+".slit.onhead", altscrname+".Slit.onHead") {
 
 };
 
@@ -516,6 +523,10 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
 
     Display *disp = FbTk::App::instance()->display();
 
+#ifdef XINERAMA
+    initXinerama(disp);
+#endif // XINERAMA
+
     event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
         SubstructureRedirectMask | KeyPressMask | KeyReleaseMask |
         ButtonPressMask | ButtonReleaseMask| SubstructureNotifyMask;
@@ -761,6 +772,12 @@ BScreen::~BScreen() {
     }
 
     netizenList.clear();
+
+#ifdef XINERAMA
+    if (hasXinerama() && m_xinerama_headinfo) {
+        delete [] m_xinerama_headinfo;
+    }
+#endif // XINERAMA
 }
 
 const FbTk::Menu &BScreen::toolbarModemenu() const {
@@ -2524,3 +2541,102 @@ void BScreen::updateSize() {
     //!! TODO: should we re-maximize the maximized windows?
     
 }
+
+#ifdef XINERAMA
+
+void BScreen::initXinerama(Display *display) {
+    if (!XineramaIsActive(display)) {
+        m_xinerama_avail = false;
+        m_xinerama_headinfo = 0;
+        return;
+    }
+    m_xinerama_avail = true;
+
+    XineramaScreenInfo *screen_info;
+    int number;
+    screen_info = XineramaQueryScreens(display, &number);
+    m_xinerama_headinfo = new XineramaHeadInfo[number];
+    m_xinerama_num_heads = number;
+    for (int i=0; i < number; i++) {
+        m_xinerama_headinfo[i].x = screen_info[i].x_org;
+        m_xinerama_headinfo[i].y = screen_info[i].y_org;
+        m_xinerama_headinfo[i].width = screen_info[i].width;
+        m_xinerama_headinfo[i].height = screen_info[i].height;
+    }
+
+}
+
+int BScreen::getHead(int x, int y) const {
+    if (!hasXinerama()) return 0;
+
+    for (int i=0; i < m_xinerama_num_heads; i++) {
+        if (x >= m_xinerama_headinfo[i].x &&
+            x < (m_xinerama_headinfo[i].x + m_xinerama_headinfo[i].width) &&
+            y >= m_xinerama_headinfo[i].y &&
+            y < (m_xinerama_headinfo[i].y + m_xinerama_headinfo[i].height)) {
+            return i+1;
+        }
+    }
+
+    return 0;
+}
+
+int BScreen::getCurrHead() const {
+    if (!hasXinerama()) return 0;
+    int root_x, root_y, ignore_i;
+
+    unsigned int ignore_ui;
+
+    Window ignore_w;
+
+    XQueryPointer(FbTk::App::instance()->display(),
+                  rootWindow().window(), &ignore_w, 
+                  &ignore_w, &root_x, &root_y,
+                  &ignore_i, &ignore_i, &ignore_ui);
+    return getHead(root_x, root_y);
+
+}
+
+int BScreen::getHeadX(int head) const {
+    if (head == 0 || head > m_xinerama_num_heads) return 0;
+    return m_xinerama_headinfo[head-1].x;
+}
+
+int BScreen::getHeadY(int head) const {
+    if (head == 0 || head > m_xinerama_num_heads) return 0;
+    return m_xinerama_headinfo[head-1].y;
+}
+
+int BScreen::getHeadWidth(int head) const {
+    if (head == 0 || head > m_xinerama_num_heads) return width();
+    return m_xinerama_headinfo[head-1].width;
+}
+
+int BScreen::getHeadHeight(int head) const {
+    if (head == 0 || head > m_xinerama_num_heads) return height();
+    return m_xinerama_headinfo[head-1].height;
+}
+
+template <>
+int BScreen::getOnHead<Toolbar>(Toolbar &tbar) {
+    return getToolbarOnHead();
+}
+
+template <>
+void BScreen::setOnHead<Toolbar>(Toolbar &tbar, int head) {
+    saveToolbarOnHead(head);
+    tbar.reconfigure();
+}
+
+template <>
+int BScreen::getOnHead<Slit>(Slit &tbar) {
+    return getSlitOnHead();
+}
+
+template <>
+void BScreen::setOnHead<Slit>(Slit &slit, int head) {
+    saveSlitOnHead(head);
+    slit.reconfigure();
+}
+
+#endif // XINERAMA
diff --git a/src/Screen.hh b/src/Screen.hh
index d06937b..f5585c7 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.99 2003/05/18 22:00:04 fluxgen Exp $
+// $Id: Screen.hh,v 1.100 2003/05/19 14:26:30 rathnor Exp $
 
 #ifndef	 SCREEN_HH
 #define	 SCREEN_HH
@@ -116,8 +116,8 @@ public:
     inline void saveSlitDirection(Slit::Direction d) { resource.slit_direction = d;  }
     inline void saveSlitAutoHide(bool t) { resource.slit_auto_hide = t;  }
     
-    inline unsigned int getSlitOnHead() const { return resource.slit_on_head; }
-    inline void saveSlitOnHead(unsigned int h) { resource.slit_on_head = h;  }
+    inline int getSlitOnHead() const { return *resource.slit_on_head; }
+    inline void saveSlitOnHead(int h) { *resource.slit_on_head = h;  }
 
     inline const Toolbar *toolbar() const { return m_toolbarhandler->getToolbar(); }
     inline Toolbar *toolbar() { return m_toolbarhandler->getToolbar(); }
@@ -296,6 +296,29 @@ public:
     /// (and maximized windows?)
     void updateSize();
 
+#ifdef XINERAMA
+    // Xinerama-related functions
+    inline bool hasXinerama() const { return m_xinerama_avail; }
+    inline int numHeads() const { return m_xinerama_num_heads; }
+
+    void initXinerama(Display *display);
+
+    int getHead(int x, int y) const;
+    int getCurrHead() const;
+    int getHeadX(int head) const;
+    int getHeadY(int head) const;
+    int getHeadWidth(int head) const;
+    int getHeadHeight(int head) const;
+
+    // magic to allow us to have "on head" placement without
+    // the object really knowing about it.
+    template <typename OnHeadObject>
+    int getOnHead(OnHeadObject &obj);
+
+    template <typename OnHeadObject>
+    void setOnHead(OnHeadObject &obj, int head);
+#endif // XINERAMA
+
     // notify netizens
     void updateNetizenCurrentWorkspace();
     void updateNetizenWorkspaceCount();
@@ -412,9 +435,7 @@ private:
         FbTk::Resource<bool> slit_auto_hide;
         FbTk::Resource<Slit::Placement> slit_placement;
         FbTk::Resource<Slit::Direction> slit_direction;
-        FbTk::Resource<int> slit_alpha;
-
-        unsigned int slit_on_head;
+        FbTk::Resource<int> slit_alpha, slit_on_head;
 
         std::string strftime_format;
 
@@ -425,6 +446,21 @@ private:
     } resource;
 
     std::auto_ptr<ToolbarHandler> m_toolbarhandler;
+
+#ifdef XINERAMA
+    // Xinerama related private data
+    bool m_xinerama_avail;
+    int m_xinerama_num_heads;
+    
+    int m_xinerama_center_x, m_xinerama_center_y;
+
+    struct XineramaHeadInfo {
+        int x, y, width, height;        
+    } *m_xinerama_headinfo;
+
+    
+
+#endif
 };
 
 
diff --git a/src/Slit.cc b/src/Slit.cc
index 6f1a7c4..b2dd383 100644
--- a/src/Slit.cc
+++ b/src/Slit.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Slit.cc,v 1.55 2003/05/17 11:00:50 fluxgen Exp $
+// $Id: Slit.cc,v 1.56 2003/05/19 14:26:30 rathnor Exp $
 
 #include "Slit.hh"
 
@@ -52,6 +52,10 @@
 #include "Transparent.hh"
 #include "IntResMenuItem.hh"
 
+#ifdef XINERAMA
+#include "Xinerama.hh"
+#endif // XINERAMA
+
 #include <algorithm>
 #include <iostream>
 #include <cassert>
@@ -790,8 +794,20 @@ void Slit::reposition() {
         head_w,
         head_h;
 
-    head_w = screen().width();
-    head_h = screen().height();
+#ifdef XINERAMA
+    if (screen().hasXinerama()) {
+        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 
+#endif // XINERAMA
+    {
+        head_w = screen().width();
+        head_h = screen().height();
+    }
+
     int border_width = screen().rootTheme().borderWidth();
     int bevel_width = screen().rootTheme().bevelWidth();
 
@@ -1206,6 +1222,18 @@ void Slit::setupMenu() {
 
     m_slitmenu.insert("Layer...", m_layermenu.get());
 
+#ifdef XINERAMA
+    if (screen().hasXinerama()) {
+        m_slitmenu.insert("On Head...", new XineramaHeadMenu<Slit>(
+                        *screen().menuTheme(),
+                        screen(),
+                        screen().imageControl(),
+                        *screen().layerManager().getLayer(Fluxbox::instance()->getMenuLayer()),
+                        this
+                        ));
+    }
+                    
+#endif //XINERAMA
     m_slitmenu.insert(new BoolMenuItem(i18n->getMessage(
                                                         CommonSet, CommonAutoHide,
                                                         "Auto hide"),
diff --git a/src/Toolbar.cc b/src/Toolbar.cc
index 2508ec9..9a29f79 100644
--- a/src/Toolbar.cc
+++ b/src/Toolbar.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Toolbar.cc,v 1.84 2003/05/17 11:30:59 fluxgen Exp $
+// $Id: Toolbar.cc,v 1.85 2003/05/19 14:26:30 rathnor Exp $
 
 #include "Toolbar.hh"
 
@@ -43,6 +43,10 @@
 #include "BoolMenuItem.hh"
 #include "FbWinFrameTheme.hh"
 
+#ifdef XINERAMA
+#include "Xinerama.hh"
+#endif XINERAMA
+
 // use GNU extensions
 #ifndef	 _GNU_SOURCE
 #define	 _GNU_SOURCE
@@ -134,6 +138,18 @@ void setupMenus(Toolbar &tbar) {
     menu.setInternalMenu();
 
     menu.insert("Layer...", &tbar.layermenu());
+#ifdef XINERAMA
+    if (tbar.screen().hasXinerama()) {
+        menu.insert("On Head...", new XineramaHeadMenu<Toolbar>(
+                        *tbar.screen().menuTheme(),
+                        tbar.screen(),
+                        tbar.screen().imageControl(),
+                        *tbar.screen().layerManager().getLayer(Fluxbox::instance()->getMenuLayer()),
+                        &tbar
+                        ));
+    }
+                    
+#endif //XINERAMA
 
     // setup items in placement menu
     struct {
@@ -1091,10 +1107,21 @@ void Toolbar::setPlacement(Toolbar::Placement where) {
         head_w,
         head_h;
 
-    m_place = where;
+#ifdef XINERAMA
+    if (screen().hasXinerama()) {
+        int head = screen().getToolbarOnHead();
+        head_x = screen().getHeadX(head);
+        head_y = screen().getHeadY(head);
+        head_w = screen().getHeadWidth(head);
+        head_h = screen().getHeadHeight(head);
+    } else 
+#endif // XINERAMA
+    {
+        head_w = screen().width();
+        head_h = screen().height();
+    }
 
-    head_w = screen().width();
-    head_h = screen().height();
+    m_place = where;
 
     frame.width = head_w * screen().getToolbarWidthPercent() / 100;
     frame.height = m_theme.font().height();
diff --git a/src/Xinerama.hh b/src/Xinerama.hh
new file mode 100644
index 0000000..eebd431
--- /dev/null
+++ b/src/Xinerama.hh
@@ -0,0 +1,105 @@
+// Xinerama.hh for Fluxbox - helpful tools for multiple heads
+// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
+//                and Simon Bowden    (rathnor 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: Xinerama.hh,v 1.1 2003/05/19 14:26:30 rathnor Exp $
+
+#ifndef XINERAMA_HH
+#define XINERAMA_HH
+
+#include "MenuItem.hh"
+#include "FbMenu.hh"
+#include "FbCommands.hh"
+#include "RefCount.hh"
+#include "SimpleCommand.hh"
+
+#include "fluxbox.hh"
+
+// provides a generic way for giving an object a xinerama head menu
+// The object must have two functions:
+// int getOnHead(), and
+// void setOnHead(int)
+
+/// this class holds the xinerama items
+template <typename ItemType> 
+class XineramaHeadMenuItem : public FbTk::MenuItem {
+public:
+    XineramaHeadMenuItem(const char *label, ItemType *object, int headnum,
+                  FbTk::RefCount<FbTk::Command> &cmd):
+        FbTk::MenuItem(label,cmd), m_object(object), m_headnum(headnum) {}
+    XineramaHeadMenuItem(const char *label, ItemType *object, int headnum):
+        FbTk::MenuItem(label), m_object(object), m_headnum(headnum) {}
+
+    bool isEnabled() const { return m_object->screen().getOnHead(*m_object) != m_headnum; } ;
+    void click(int button, int time) {
+        m_object->screen().setOnHead(*m_object, m_headnum);
+        FbTk::MenuItem::click(button, time);
+    }
+    
+private:
+    ItemType *m_object;
+    int m_headnum;
+};
+
+
+/// Create a xinerama menu
+template <typename ItemType>
+class XineramaHeadMenu : public FbMenu {
+public:
+    XineramaHeadMenu(FbTk::MenuTheme &tm, BScreen &screen, FbTk::ImageControl &imgctrl,
+                     FbTk::XLayer &layer, ItemType *item);
+
+private:
+    ItemType *m_object;
+};
+
+
+template <typename ItemType>
+XineramaHeadMenu<ItemType>::XineramaHeadMenu(FbTk::MenuTheme &tm, BScreen &screen, FbTk::ImageControl &imgctrl,
+                               FbTk::XLayer &layer, ItemType *item):
+    FbMenu(tm, screen.screenNumber(), imgctrl, layer), 
+    m_object(item) 
+{
+    
+    FbTk::RefCount<FbTk::Command> saverc_cmd(new FbTk::SimpleCommand<Fluxbox>(
+                                     *Fluxbox::instance(), 
+                                     &Fluxbox::save_rc));
+    char tname[128];
+    for (int i=1; i <= screen.numHeads(); ++i) {
+        // TODO: nls
+/*
+        sprintf(tname, I18n::instance()->
+                getMessage(
+                    FBNLS::ScreenSet, 
+                    FBNLS::XineramaDefaultHeadFormat,
+                    "Head %d"), i); //m_id starts at 0
+*/
+        sprintf(tname, "Head %d", i);
+        insert(new XineramaHeadMenuItem<ItemType>(
+                   tname, m_object, i, saverc_cmd));
+    }
+    // TODO: nls
+    insert(new XineramaHeadMenuItem<ItemType>(
+               "All Heads", m_object, 0, saverc_cmd));
+    update();
+}
+
+#endif // XINERAMA_HH
-- 
cgit v0.11.2