]> 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 eeb09a374981a4fe5cfe9dc30d3f6386c6faa980..e55f681f58a7edaba152905dd4f23d8908f3fe30 100644 (file)
@@ -23,6 +23,8 @@ extern "C" {
 #define _(str) gettext(str)
 }
 
+#include <algorithm>
+
 namespace ob {
 
 Client::Client(int screen, Window window)
@@ -47,6 +49,10 @@ Client::Client(int screen, Window window)
   _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();
@@ -113,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;
@@ -198,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:
@@ -264,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
+  }
 }
 
 
@@ -418,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);
@@ -443,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);
     
@@ -497,7 +553,7 @@ void Client::updateWMHints(bool initstate)
 #endif
     // fire the urgent callback if we're mapped, otherwise, wait until after
     // we're mapped
-    if (_urgent && frame)
+    if (frame)
       fireUrgent();
   }
 }
@@ -576,8 +632,11 @@ void Client::updateStrut()
     _strut.right = data[1];
     _strut.top = data[2];
     _strut.bottom = data[3]; 
-   
-    openbox->screen(_screen)->updateStrut();
+
+    // 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;
@@ -622,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;
@@ -634,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)
@@ -656,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();
@@ -895,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) {
@@ -980,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();
@@ -990,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
@@ -1276,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
@@ -1320,6 +1399,7 @@ bool Client::focus()
     XSendEvent(**otk::display, _window, False, NoEventMask, &ce);
   }
 
+  XSync(**otk::display, False);
   return true;
 }
 
@@ -1404,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.028265 seconds and 4 git commands to generate.