]> Dogcows Code - chaz/openbox/blobdiff - src/screen.cc
Add the "obsetroot" tool. Use it to set the root background.
[chaz/openbox] / src / screen.cc
index 2c49c6cc5c16684cbfaae773af7b9271a5156a2d..6eaa5cc577190461a0ca2fd6022b5705ddfe758e 100644 (file)
@@ -2,6 +2,16 @@
 
 #include "config.h"
 
+#include "screen.hh"
+#include "client.hh"
+#include "openbox.hh"
+#include "frame.hh"
+#include "bindings.hh"
+#include "python.hh"
+#include "otk/display.hh"
+#include "otk/property.hh"
+#include "otk/util.hh"
+
 extern "C" {
 #ifdef    HAVE_UNISTD_H
 #  include <sys/types.h>
@@ -12,15 +22,6 @@ extern "C" {
 #define _(str) gettext(str)
 }
 
-#include "screen.hh"
-#include "client.hh"
-#include "openbox.hh"
-#include "frame.hh"
-#include "bindings.hh"
-#include "python.hh"
-#include "otk/display.hh"
-#include "otk/property.hh"
-
 #include <vector>
 #include <algorithm>
 #include <cstdio>
@@ -66,23 +67,11 @@ Screen::Screen(int screen)
   XDefineCursor(**otk::display, _info->rootWindow(),
                 openbox->cursors().session);
 
-  // XXX: initialize the screen's style
-  /*
-  otk::ustring stylepath;
-  python_get_string("THEME", &stylepath);
-  otk::Configuration sconfig(false);
-  sconfig.setFile(otk::expandTilde(stylepath.c_str()));
-  if (!sconfig.load()) {
-    sconfig.setFile(otk::expandTilde(DEFAULTSTYLE));
-    if (!sconfig.load()) {
-      printf(_("Unable to load default style: %s. Aborting.\n"), DEFAULTSTYLE);
-      ::exit(1);
-    }
-  }
-  _style.load(sconfig);
-  */
-  otk::display->renderControl(_number)->
-    drawRoot(*otk::RenderStyle::style(_number)->rootColor());
+  // initialize the screen's style
+  otk::RenderStyle::setStyle(_number, _config.theme);
+  // draw the root window
+  otk::bexec("obsetroot " + otk::RenderStyle::style(_number)->rootArgs(),
+             _info->displayString());
 
   // set up notification of netwm support
   changeSupportedAtoms();
@@ -95,22 +84,24 @@ Screen::Screen(int screen)
                      otk::Property::atoms.cardinal, geometry, 2);
 
   // Set the net_desktop_names property
-  std::vector<otk::ustring> names;
-  python_get_stringlist("DESKTOP_NAMES", &names);
   otk::Property::set(_info->rootWindow(),
                      otk::Property::atoms.net_desktop_names,
-                     otk::Property::utf8, names);
+                     otk::Property::utf8, _config.desktop_names);
   // the above set() will cause the updateDesktopNames to fire right away so
   // we have a list of desktop names
 
   _desktop = 0;
-  
-  if (!python_get_long("NUMBER_OF_DESKTOPS", &_num_desktops))
-    _num_desktops = 1;
-  changeNumDesktops(_num_desktops); // set the hint
+
+  changeNumDesktops(_config.num_desktops); // set the hint
 
   changeDesktop(0); // set the hint
 
+  // don't start in showing-desktop mode
+  _showing_desktop = false;
+  otk::Property::set(_info->rootWindow(),
+                     otk::Property::atoms.net_showing_desktop,
+                     otk::Property::atoms.cardinal, 0);
+
   // create the window which gets focus when no clients get it
   XSetWindowAttributes attr;
   attr.override_redirect = true;
@@ -122,7 +113,8 @@ Screen::Screen(int screen)
   // these may be further updated if any pre-existing windows are found in
   // the manageExising() function
   changeClientList();  // initialize the client lists, which will be empty
-  calcArea();          // initialize the available working area
+
+  updateDesktopLayout();
 
   // register this class as the event handler for the root window
   openbox->registerHandler(_info->rootWindow(), this);
@@ -199,27 +191,108 @@ void Screen::manageExisting()
   XFree(children);
 }
 
+void Screen::updateDesktopLayout()
+{
+  //const unsigned long _NET_WM_ORIENTATION_HORZ = 0;
+  const unsigned long _NET_WM_ORIENTATION_VERT = 1;
+  //const unsigned long _NET_WM_TOPLEFT = 0;
+  const unsigned long _NET_WM_TOPRIGHT = 1;
+  const unsigned long _NET_WM_BOTTOMRIGHT = 2;
+  const unsigned long _NET_WM_BOTTOMLEFT = 3;
+  
+  // defaults
+  _layout.orientation = DesktopLayout::Horizontal;
+  _layout.start_corner = DesktopLayout::TopLeft;
+  _layout.rows = 1;
+  _layout.columns = _num_desktops;
+
+  unsigned long *data, num = 4;
+  if (otk::Property::get(_info->rootWindow(),
+                         otk::Property::atoms.net_desktop_layout,
+                         otk::Property::atoms.cardinal,
+                         &num, &data)) {
+    if (num >= 4) {
+      if (data[0] == _NET_WM_ORIENTATION_VERT)
+        _layout.orientation = DesktopLayout::Vertical;
+      if (data[3] == _NET_WM_TOPRIGHT)
+        _layout.start_corner = DesktopLayout::TopRight;
+      else if (data[3] == _NET_WM_BOTTOMRIGHT)
+        _layout.start_corner = DesktopLayout::BottomRight;
+      else if (data[3] == _NET_WM_BOTTOMLEFT)
+        _layout.start_corner = DesktopLayout::BottomLeft;
+
+      // fill in a zero rows/columns
+      if (!(data[1] == 0 && data[2] == 0)) { // both 0's is bad data..
+        if (data[1] == 0) {
+          data[1] = (_num_desktops + _num_desktops % data[2]) / data[2];
+        } else if (data[2] == 0) {
+          data[2] = (_num_desktops + _num_desktops % data[1]) / data[1];
+        }
+        _layout.columns = data[1];
+        _layout.rows = data[2];
+      }
+
+      // bounds checking
+      if (_layout.orientation == DesktopLayout::Horizontal) {
+        if (_layout.rows > _num_desktops) _layout.rows = _num_desktops;
+        if (_layout.columns > (_num_desktops + _num_desktops % _layout.rows) /
+            _layout.rows)
+          _layout.columns = (_num_desktops + _num_desktops % _layout.rows) /
+            _layout.rows;
+      } else {
+        if (_layout.columns > _num_desktops) _layout.columns = _num_desktops;
+        if (_layout.rows > (_num_desktops + _num_desktops % _layout.columns) /
+            _layout.columns)
+          _layout.rows = (_num_desktops + _num_desktops % _layout.columns) /
+            _layout.columns;
+      }
+    }
+    delete [] data;
+  }
+}
 
-void Screen::updateStrut()
+void Screen::updateStruts()
 {
-  _strut.left = _strut.right = _strut.top = _strut.bottom = 0;
+  struct ApplyStrut {
+    void operator()(otk::Strut &self, const otk::Strut &other) {
+      self.left = std::max(self.left, other.left);
+      self.right = std::max(self.right, other.right);
+      self.top = std::max(self.top, other.top);
+      self.bottom = std::max(self.bottom, other.bottom);
+    }
+  } apply;
 
-  ClientList::iterator it, end = clients.end();
+  StrutList::iterator sit, send = _struts.end();
+  // reset them all
+  for (sit = _struts.begin(); sit != send; ++sit)
+    sit->left = sit->right = sit->top = sit->bottom = 0;
+
+  ClientList::const_iterator it, end = clients.end();
   for (it = clients.begin(); it != end; ++it) {
+    if ((*it)->iconic()) continue; // these dont count in the strut
+    
+    unsigned int desk = (*it)->desktop();
     const otk::Strut &s = (*it)->strut();
-    _strut.left = std::max(_strut.left, s.left);
-    _strut.right = std::max(_strut.right, s.right);
-    _strut.top = std::max(_strut.top, s.top);
-    _strut.bottom = std::max(_strut.bottom, s.bottom);
+
+    if (desk == 0xffffffff)
+      for (unsigned int i = 0, e = _struts.size(); i < e; ++i)
+        apply(_struts[i], s);
+    else if (desk < _struts.size())
+      apply(_struts[desk], s);
+    else
+      assert(false); // invalid desktop otherwise..
+    // apply to the 'all desktops' strut
+    apply(_struts.back(), s);
   }
-  calcArea();
+  changeWorkArea();
 }
 
 
-void Screen::calcArea()
+void Screen::changeWorkArea()
 {
-  otk::Rect old_area = _area;
-
+  unsigned long *dims = new unsigned long[4 * _num_desktops];
+  for (unsigned int i = 0; i < _num_desktops + 1; ++i) {
+    otk::Rect old_area = _area[i];
 /*
 #ifdef    XINERAMA
   // reset to the full areas
@@ -228,10 +301,12 @@ void Screen::calcArea()
 #endif // XINERAMA
 */
   
-  _area = otk::Rect(_strut.left, _strut.top,
-                    _info->size().width() - (_strut.left + _strut.right),
-                    _info->size().height() - (_strut.top + _strut.bottom));
-
+    _area[i] = otk::Rect(_struts[i].left, _struts[i].top,
+                         _info->size().width() - (_struts[i].left +
+                                                  _struts[i].right),
+                         _info->size().height() - (_struts[i].top +
+                                                   _struts[i].bottom));
+    
 /*
 #ifdef    XINERAMA
   if (isXineramaActive()) {
@@ -254,15 +329,31 @@ void Screen::calcArea()
   }
 #endif // XINERAMA
 */
-  if (old_area != _area) {
-    // the area has changed, adjust all the maximized windows
-    ClientList::iterator it, end = clients.end();
-    for (it = clients.begin(); it != end; ++it)
-      (*it)->remaximize();
-  }
+    if (old_area != _area[i]) {
+      // the area has changed, adjust all the maximized windows
+      ClientList::iterator it, end = clients.end();
+      for (it = clients.begin(); it != end; ++it)
+        if (i < _num_desktops) {
+          if ((*it)->desktop() == i)
+            (*it)->remaximize();
+        } else {
+          // the 'all desktops' size
+          if ((*it)->desktop() == 0xffffffff)
+            (*it)->remaximize();
+        }
+    }
 
-  changeWorkArea();
+    // don't set these for the 'all desktops' area
+    if (i < _num_desktops) {
+      dims[(i * 4) + 0] = _area[i].x();
+      dims[(i * 4) + 1] = _area[i].y();
+      dims[(i * 4) + 2] = _area[i].width();
+      dims[(i * 4) + 3] = _area[i].height();
+    }
+  }
+  otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_workarea,
+                     otk::Property::atoms.cardinal, dims, 4 * _num_desktops);
+  delete [] dims;
 }
 
 
@@ -297,13 +388,13 @@ void Screen::changeSupportedAtoms()
     otk::Property::atoms.net_client_list_stacking,
     otk::Property::atoms.net_desktop_names,
     otk::Property::atoms.net_close_window,
+    otk::Property::atoms.net_desktop_layout,
+    otk::Property::atoms.net_showing_desktop,
     otk::Property::atoms.net_wm_name,
     otk::Property::atoms.net_wm_visible_name,
     otk::Property::atoms.net_wm_icon_name,
     otk::Property::atoms.net_wm_visible_icon_name,
-/*
     otk::Property::atoms.net_wm_desktop,
-*/
     otk::Property::atoms.net_wm_strut,
     otk::Property::atoms.net_wm_window_type,
     otk::Property::atoms.net_wm_window_type_desktop,
@@ -411,20 +502,6 @@ void Screen::changeStackingList()
 }
 
 
-void Screen::changeWorkArea() {
-  unsigned long *dims = new unsigned long[4 * _num_desktops];
-  for (long i = 0; i < _num_desktops; ++i) {
-    dims[(i * 4) + 0] = _area.x();
-    dims[(i * 4) + 1] = _area.y();
-    dims[(i * 4) + 2] = _area.width();
-    dims[(i * 4) + 3] = _area.height();
-  }
-  otk::Property::set(_info->rootWindow(), otk::Property::atoms.net_workarea,
-                     otk::Property::atoms.cardinal, dims, 4 * _num_desktops);
-  delete [] dims;
-}
-
-
 void Screen::manageWindow(Window window)
 {
   Client *client = 0;
@@ -512,11 +589,7 @@ void Screen::manageWindow(Window window)
   EventData ddata(_number, client, EventAction::DisplayingWindow, 0);
   openbox->bindings()->fireEvent(&ddata);
 
-  // if on the current desktop.. (or all desktops)
-  if (client->desktop() == _desktop ||
-      client->desktop() == (signed)0xffffffff) {
-    client->frame->show();
-  }
+  client->showhide();
 
   client->applyStartupState();
 
@@ -526,7 +599,7 @@ void Screen::manageWindow(Window window)
   clients.push_back(client);
   // once the client is in the list, update our strut to include the new
   // client's (it is good that this happens after window placement!)
-  updateStrut();
+  updateStruts();
   // this puts into the stacking order, then raises it
   _stacking.push_back(client);
   raiseWindow(client);
@@ -592,13 +665,13 @@ void Screen::unmanageWindow(Client *client)
 
   // once the client is out of the list, update our strut to remove it's
   // influence
-  updateStrut();
+  updateStruts();
 
   // unset modal before dropping our focus
   client->_modal = false;
   
   // unfocus the client (calls the focus callbacks)
-  client->unfocus();
+  if (client->focused()) client->unfocus();
 
 #ifdef DEBUG
   printf("Unmanaged window 0x%lx frame 0x%lx\n", client->window(), framewin);
@@ -663,9 +736,6 @@ void Screen::raiseWindow(Client *client)
   const ClientList::iterator end = _stacking.end();
 
   // the stacking list is from highest to lowest
-//  for (;it != end, ++it) {
-//    if ((*it)->layer() <= client->layer() && m != *it) break;
-//  }
   for (; it != end && ((*it)->layer() > client->layer() || m == *it); ++it);
 
   /*
@@ -683,13 +753,13 @@ void Screen::raiseWindow(Client *client)
   changeStackingList(); 
 }
 
-void Screen::changeDesktop(long desktop)
+void Screen::changeDesktop(unsigned int desktop)
 {
-  if (!(desktop >= 0 && desktop < _num_desktops)) return;
+  if (desktop >= _num_desktops) return;
 
-  printf("Moving to desktop %ld\n", desktop);
+  printf("Moving to desktop %u\n", desktop);
   
-  long old = _desktop;
+  unsigned int old = _desktop;
   
   _desktop = desktop;
   otk::Property::set(_info->rootWindow(),
@@ -699,20 +769,15 @@ void Screen::changeDesktop(long desktop)
   if (old == _desktop) return;
 
   ClientList::iterator it, end = clients.end();
-  for (it = clients.begin(); it != end; ++it) {
-    if ((*it)->desktop() == old) {
-      (*it)->frame->hide();
-    } else if ((*it)->desktop() == _desktop) {
-      (*it)->frame->show();
-    }
-  }
+  for (it = clients.begin(); it != end; ++it)
+    (*it)->showhide();
 
   // force the callbacks to fire
   if (!openbox->focusedClient())
     openbox->setFocusedClient(0);
 }
 
-void Screen::changeNumDesktops(long num)
+void Screen::changeNumDesktops(unsigned int num)
 {
   assert(num > 0);
   
@@ -721,9 +786,8 @@ void Screen::changeNumDesktops(long num)
   // move windows on desktops that will no longer exist!
   ClientList::iterator it, end = clients.end();
   for (it = clients.begin(); it != end; ++it) {
-    int d = (*it)->desktop();
-    if (d >= num && !(d == (signed) 0xffffffff ||
-                      d == Client::ICONIC_DESKTOP)) {
+    unsigned int d = (*it)->desktop();
+    if (d >= num && d != 0xffffffff) {
       XEvent ce;
       ce.xclient.type = ClientMessage;
       ce.xclient.message_type = otk::Property::atoms.net_wm_desktop;
@@ -750,12 +814,17 @@ void Screen::changeNumDesktops(long num)
                      viewport, _num_desktops * 2);
   delete [] viewport;
 
-  // update the work area hint
-  changeWorkArea();
+  // change our struts/area to match
+  _area.resize(_num_desktops + 1);
+  _struts.resize(_num_desktops + 1);
+  updateStruts();
+
+  // the number of rows/columns will differ
+  updateDesktopLayout();
 
   // change our desktop if we're on one that no longer exists!
-  if (_desktop >= num)
-    changeDesktop(num - 1);
+  if (_desktop >= _num_desktops)
+    changeDesktop(_num_desktops - 1);
 }
 
 
@@ -767,15 +836,13 @@ void Screen::updateDesktopNames()
                           otk::Property::atoms.net_desktop_names,
                           otk::Property::utf8, &num, &_desktop_names))
     _desktop_names.clear();
-  while ((long)_desktop_names.size() < _num_desktops)
+  while (_desktop_names.size() < _num_desktops)
     _desktop_names.push_back("Unnamed");
 }
 
 
-void Screen::setDesktopName(long i, const otk::ustring &name)
+void Screen::setDesktopName(unsigned int i, const otk::ustring &name)
 {
-  assert(i >= 0);
-
   if (i >= _num_desktops) return;
 
   otk::Property::StringVect newnames = _desktop_names;
@@ -785,6 +852,19 @@ void Screen::setDesktopName(long i, const otk::ustring &name)
                      otk::Property::utf8, newnames);
 }
 
+otk::ustring Screen::desktopName(unsigned int i) const
+{
+  if (i >= _num_desktops) return "";
+  return _desktop_names[i];
+}
+
+const otk::Rect& Screen::area(unsigned int desktop) const {
+  assert(desktop < _num_desktops || desktop == 0xffffffff);
+  if (desktop < _num_desktops)
+    return _area[desktop];
+  else
+    return _area[_num_desktops];
+}
 
 void Screen::installColormap(bool install) const
 {
@@ -794,6 +874,41 @@ void Screen::installColormap(bool install) const
     XUninstallColormap(**otk::display, _info->colormap());
 }
 
+void Screen::showDesktop(bool show)
+{
+  if (show == _showing_desktop) return; // no change
+
+  // save the window focus, and restore it when leaving the show-desktop mode
+  static Window saved_focus = 0;
+  if (show) {
+    Client *c = openbox->focusedClient();
+    if (c) saved_focus = c->window();
+  }
+  
+  _showing_desktop = show;
+
+  ClientList::iterator it, end = clients.end();
+  for (it = clients.begin(); it != end; ++it) {
+    if ((*it)->type() == Client::Type_Desktop) {
+      if (show)
+        (*it)->focus();
+    } else
+      (*it)->showhide();
+  }
+
+  if (!show) {
+    Client *f = openbox->focusedClient();
+    if (!f || f->type() == Client::Type_Desktop) {
+      Client *c = openbox->findClient(saved_focus);
+      if (c) c->focus();
+    }
+  }
+
+  otk::Property::set(_info->rootWindow(),
+                     otk::Property::atoms.net_showing_desktop,
+                     otk::Property::atoms.cardinal,
+                     show ? 1 : 0);
+}
 
 void Screen::propertyHandler(const XPropertyEvent &e)
 {
@@ -813,6 +928,8 @@ void Screen::propertyHandler(const XPropertyEvent &e)
 
   if (e.atom == otk::Property::atoms.net_desktop_names)
     updateDesktopNames();
+  else if (e.atom == otk::Property::atoms.net_desktop_layout)
+    updateDesktopLayout();
 }
 
 
@@ -826,6 +943,8 @@ void Screen::clientMessageHandler(const XClientMessageEvent &e)
     changeDesktop(e.data.l[0]);
   } else if (e.message_type == otk::Property::atoms.net_number_of_desktops) {
     changeNumDesktops(e.data.l[0]);
+  } else if (e.message_type == otk::Property::atoms.net_showing_desktop) {
+    showDesktop(e.data.l[0] != 0);
   }
 }
 
@@ -843,8 +962,11 @@ void Screen::mapRequestHandler(const XMapRequestEvent &e)
 #ifdef DEBUG
     printf("DEBUG: MAP REQUEST CAUGHT IN SCREEN. IGNORED.\n");
 #endif
-  } else
+  } else {
+    if (_showing_desktop)
+      showDesktop(false); // leave showing-the-desktop mode
     manageWindow(e.window);
+  }
 }
 
 }
This page took 0.033245 seconds and 4 git commands to generate.