]> Dogcows Code - chaz/openbox/blobdiff - src/client.cc
dont show a handle if it cant be resized at all
[chaz/openbox] / src / client.cc
index 91d61f4bd20392904744e19f06e675ebfde4b4c9..e55f681f58a7edaba152905dd4f23d8908f3fe30 100644 (file)
@@ -8,6 +8,7 @@
 #include "frame.hh"
 #include "screen.hh"
 #include "openbox.hh"
+#include "bindings.hh"
 #include "otk/display.hh"
 #include "otk/property.hh"
 
@@ -22,6 +23,8 @@ extern "C" {
 #define _(str) gettext(str)
 }
 
+#include <algorithm>
+
 namespace ob {
 
 Client::Client(int screen, Window window)
@@ -44,6 +47,12 @@ Client::Client(int screen, Window window)
   _transient_for = 0;
   // pick a layer to start from
   _layer = Layer_Normal;
+  // default to not urgent
+  _urgent = false;
+  // not positioned unless specified
+  _positioned = false;
+  // nothing is disabled unless specified
+  _disabled_decorations = 0;
   
   getArea();
   getDesktop();
@@ -73,7 +82,7 @@ Client::Client(int screen, Window window)
   updateStrut();
 
   // this makes sure that these windows appear on all desktops
-  if (_type == Type_Dock || _type == Type_Desktop)
+  if (/*_type == Type_Dock ||*/ _type == Type_Desktop)
     _desktop = 0xffffffff;
   
   // set the desktop hint, to make sure that it always exists, and to reflect
@@ -110,6 +119,21 @@ Client::~Client()
 }
 
 
+bool Client::validate() const
+{
+  XSync(**otk::display, false); // get all events on the server
+
+  XEvent e;
+  if (XCheckTypedWindowEvent(**otk::display, _window, DestroyNotify, &e) ||
+      XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &e)) {
+    XPutBackEvent(**otk::display, &e);
+    return false;
+  }
+
+  return true;
+}
+
+
 void Client::getGravity()
 {
   XWindowAttributes wattrib;
@@ -126,9 +150,13 @@ void Client::getDesktop()
   // defaults to the current desktop
   _desktop = openbox->screen(_screen)->desktop();
 
-  otk::Property::get(_window, otk::Property::atoms.net_wm_desktop,
-                     otk::Property::atoms.cardinal,
-                     (long unsigned*)&_desktop);
+  if (otk::Property::get(_window, otk::Property::atoms.net_wm_desktop,
+                         otk::Property::atoms.cardinal,
+                         (long unsigned*)&_desktop)) {
+#ifdef DEBUG
+//    printf("Window requested desktop: %ld\n", _desktop);
+#endif
+  }
 }
 
 
@@ -191,6 +219,11 @@ void Client::setupDecorAndFunctions()
     _decorations |= Decor_Close;
     _functions |= Func_Close;
   }
+
+  if (!(_min_size.x() < _max_size.x() || _min_size.y() < _max_size.y())) {
+    _decorations &= ~(Decor_Maximize | Decor_Handle);
+    _functions &= ~(Func_Resize | Func_Maximize);
+  }
   
   switch (_type) {
   case Type_Normal:
@@ -257,7 +290,30 @@ void Client::setupDecorAndFunctions()
     }
   }
 
+  // finally, user specified disabled decorations are applied to subtract
+  // decorations
+  if (_disabled_decorations & Decor_Titlebar)
+    _decorations &= ~Decor_Titlebar;
+  if (_disabled_decorations & Decor_Handle)
+    _decorations &= ~Decor_Handle;
+  if (_disabled_decorations & Decor_Border)
+    _decorations &= ~Decor_Border;
+  if (_disabled_decorations & Decor_Iconify)
+    _decorations &= ~Decor_Iconify;
+  if (_disabled_decorations & Decor_Maximize)
+    _decorations &= ~Decor_Maximize;
+  if (_disabled_decorations & Decor_AllDesktops)
+    _decorations &= ~Decor_AllDesktops;
+  if (_disabled_decorations & Decor_Close)
+    _decorations &= ~Decor_Close;
+
   changeAllowedActions();
+
+  if (frame) {
+    frame->adjustSize(); // change the decors on the frame
+    frame->adjustPosition(); // with more/less decorations, we may need to be
+                             // moved
+  }
 }
 
 
@@ -411,6 +467,8 @@ void Client::updateNormalHints()
   int oldgravity = _gravity;
 
   // defaults
+  _min_ratio = 0.0;
+  _max_ratio = 0.0;
   _size_inc.setPoint(1, 1);
   _base_size.setPoint(0, 0);
   _min_size.setPoint(0, 0);
@@ -436,6 +494,11 @@ void Client::updateNormalHints()
       }
     }
 
+    if (size.flags & PAspect) {
+      if (size.min_aspect.y) _min_ratio = size.min_aspect.x/size.min_aspect.y;
+      if (size.max_aspect.y) _max_ratio = size.max_aspect.x/size.max_aspect.y;
+    }
+
     if (size.flags & PMinSize)
       _min_size.setPoint(size.min_width, size.min_height);
     
@@ -457,7 +520,7 @@ void Client::updateWMHints(bool initstate)
 
   // assume a window takes input if it doesnt specify
   _can_focus = true;
-  _urgent = false;
+  bool ur = false;
   
   if ((hints = XGetWMHints(**otk::display, _window)) != NULL) {
     if (hints->flags & InputHint)
@@ -468,7 +531,7 @@ void Client::updateWMHints(bool initstate)
       _iconic = hints->initial_state == IconicState;
 
     if (hints->flags & XUrgencyHint)
-      _urgent = true;
+      ur = true;
 
     if (hints->flags & WindowGroupHint) {
       if (hints->window_group != _group) {
@@ -481,6 +544,18 @@ void Client::updateWMHints(bool initstate)
 
     XFree(hints);
   }
+
+  if (ur != _urgent) {
+    _urgent = ur;
+#ifdef DEBUG
+    printf("DEBUG: Urgent Hint for 0x%lx: %s\n",
+           (long)_window, _urgent ? "ON" : "OFF");
+#endif
+    // fire the urgent callback if we're mapped, otherwise, wait until after
+    // we're mapped
+    if (frame)
+      fireUrgent();
+  }
 }
 
 
@@ -556,9 +631,12 @@ void Client::updateStrut()
     _strut.left = data[0];
     _strut.right = data[1];
     _strut.top = data[2];
-    _strut.bottom = data[3];
-    
-    openbox->screen(_screen)->updateStrut();
+    _strut.bottom = data[3]; 
+
+    // updating here is pointless while we're being mapped cuz we're not in
+    // the screen's client list yet
+    if (frame)
+      openbox->screen(_screen)->updateStrut();
   }
 
   delete [] data;
@@ -603,6 +681,9 @@ void Client::updateTransientFor()
 void Client::propertyHandler(const XPropertyEvent &e)
 {
   otk::EventHandler::propertyHandler(e);
+
+  // validate cuz we query stuff off the client here
+  if (!validate()) return;
   
   // compress changes to a single property into a single change
   XEvent ce;
@@ -615,16 +696,16 @@ void Client::propertyHandler(const XPropertyEvent &e)
     }
   }
 
-  if (e.atom == XA_WM_NORMAL_HINTS)
+  if (e.atom == XA_WM_NORMAL_HINTS) {
     updateNormalHints();
-  else if (e.atom == XA_WM_HINTS)
+    setupDecorAndFunctions(); // normal hints can make a window non-resizable
+  } else if (e.atom == XA_WM_HINTS)
     updateWMHints();
   else if (e.atom == XA_WM_TRANSIENT_FOR) {
     updateTransientFor();
     getType();
     calcLayer(); // type may have changed, so update the layer
     setupDecorAndFunctions();
-    frame->adjustSize(); // this updates the frame for any new decor settings
   }
   else if (e.atom == otk::Property::atoms.net_wm_name ||
            e.atom == otk::Property::atoms.wm_name)
@@ -637,7 +718,6 @@ void Client::propertyHandler(const XPropertyEvent &e)
   else if (e.atom == otk::Property::atoms.wm_protocols) {
     updateProtocols();
     setupDecorAndFunctions();
-    frame->adjustSize(); // update the decorations
   }
   else if (e.atom == otk::Property::atoms.net_wm_strut)
     updateStrut();
@@ -876,6 +956,9 @@ void Client::clientMessageHandler(const XClientMessageEvent &e)
 {
   otk::EventHandler::clientMessageHandler(e);
   
+  // validate cuz we query stuff off the client here
+  if (!validate()) return;
+  
   if (e.format != 32) return;
 
   if (e.message_type == otk::Property::atoms.wm_change_state) {
@@ -961,7 +1044,8 @@ void Client::resize(Corner anchor, int w, int h)
 }
 
 
-void Client::internal_resize(Corner anchor, int w, int h, int x, int y)
+void Client::internal_resize(Corner anchor, int w, int h, bool user,
+                             int x, int y)
 {
   w -= _base_size.x(); 
   h -= _base_size.y();
@@ -971,14 +1055,21 @@ void Client::internal_resize(Corner anchor, int w, int h, int x, int y)
   w += _size_inc.x() / 2;
   h += _size_inc.y() / 2;
 
-  // is the window resizable? if it is not, then don't check its sizes, the
-  // client can do what it wants and the user can't change it anyhow
-  if (_min_size.x() <= _max_size.x() && _min_size.y() <= _max_size.y()) {
+  if (user) {
+    // if this is a user-requested resize, then check against min/max sizes
+    // and aspect ratios
+
     // smaller than min size or bigger than max size?
     if (w < _min_size.x()) w = _min_size.x();
     else if (w > _max_size.x()) w = _max_size.x();
     if (h < _min_size.y()) h = _min_size.y();
     else if (h > _max_size.y()) h = _max_size.y();
+
+    // adjust the height ot match the width for the aspect ratios
+    if (_min_ratio)
+      if (h * _min_ratio > w) h = static_cast<int>(w / _min_ratio);
+    if (_max_ratio)
+      if (h * _max_ratio < w) h = static_cast<int>(w / _max_ratio);
   }
 
   // keep to the increments
@@ -1162,7 +1253,6 @@ void Client::applyStartupState()
   // these are in a carefully crafted order..
 
   if (_iconic) {
-    printf("MAP ICONIC\n");
     _iconic = false;
     setDesktop(ICONIC_DESKTOP);
   }
@@ -1174,6 +1264,8 @@ void Client::applyStartupState()
     _shaded = false;
     shade(true);
   }
+  if (_urgent)
+    fireUrgent();
   
   if (_max_vert); // XXX: incomplete
   if (_max_horz); // XXX: incomplete
@@ -1186,6 +1278,14 @@ void Client::applyStartupState()
 }
 
 
+void Client::fireUrgent()
+{
+  // call the python UrgentWindow callbacks
+  EventData data(_screen, this, EventAction::UrgentWindow, 0);
+  openbox->bindings()->fireEvent(&data);
+}
+
+
 void Client::shade(bool shade)
 {
   if (!(_functions & Func_Shade) || // can't
@@ -1248,6 +1348,13 @@ void Client::fullscreen(bool fs)
 }
 
 
+void Client::disableDecorations(DecorationFlags flags)
+{
+  _disabled_decorations = flags;
+  setupDecorAndFunctions();
+}
+
+
 bool Client::focus()
 {
   // won't try focus if the client doesn't want it, or if the window isn't
@@ -1266,7 +1373,7 @@ bool Client::focus()
   }
   while (XCheckTypedWindowEvent(**otk::display, _window, UnmapNotify, &ev)) {
     if (ignore_unmaps) {
-      --ignore_unmaps;
+      unmapHandler(ev.xunmap);
     } else {
       XPutBackEvent(**otk::display, &ev);
       return false;
@@ -1292,6 +1399,7 @@ bool Client::focus()
     XSendEvent(**otk::display, _window, False, NoEventMask, &ce);
   }
 
+  XSync(**otk::display, False);
   return true;
 }
 
@@ -1376,9 +1484,9 @@ void Client::configureRequestHandler(const XConfigureRequestEvent &e)
     if (e.value_mask & (CWX | CWY)) {
       int x = (e.value_mask & CWX) ? e.x : _area.x();
       int y = (e.value_mask & CWY) ? e.y : _area.y();
-      internal_resize(corner, w, h, x, y);
+      internal_resize(corner, w, h, false, x, y);
     } else // if JUST resizing...
-      internal_resize(corner, w, h);
+      internal_resize(corner, w, h, false);
   } else if (e.value_mask & (CWX | CWY)) { // if JUST moving...
     int x = (e.value_mask & CWX) ? e.x : _area.x();
     int y = (e.value_mask & CWY) ? e.y : _area.y();
This page took 0.030726 seconds and 4 git commands to generate.