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