]> Dogcows Code - chaz/openbox/blobdiff - src/client.cc
support net_wm_strut's! nothing to do with them yet however
[chaz/openbox] / src / client.cc
index aef3dcbafe59287545e44203ee20cc35cf502285..a2106d867749f901fa0d78d85b3cea03af65b64c 100644 (file)
@@ -7,7 +7,6 @@
 #include "client.hh"
 #include "frame.hh"
 #include "screen.hh"
-#include "bbscreen.hh"
 #include "openbox.hh"
 #include "otk/display.hh"
 #include "otk/property.hh"
@@ -26,7 +25,8 @@ namespace ob {
 
 OBClient::OBClient(int screen, Window window)
   : otk::OtkEventHandler(),
-    _screen(screen), _window(window)
+    OBWidget(OBWidget::Type_Client),
+    frame(0), _screen(screen), _window(window)
 {
   assert(screen >= 0);
   assert(window);
@@ -36,22 +36,25 @@ OBClient::OBClient(int screen, Window window)
   // update EVERYTHING the first time!!
 
   // the state is kinda assumed to be normal. is this right? XXX
-  _wmstate = NormalState;
+  _wmstate = NormalState; _iconic = false;
   // no default decors or functions, each has to be enabled
   _decorations = _functions = 0;
+  // start unfocused
+  _focused = false;
   
   getArea();
   getDesktop();
+  // XXX: updateTransientFor();
   getType();
 
   // set the decorations and functions
+  _decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
+    Decor_Iconify | Decor_Maximize;
+  _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
   switch (_type) {
   case Type_Normal:
     // normal windows retain all of the possible decorations and
     // functionality
-    _decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
-                   Decor_Iconify | Decor_Maximize;
-    _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
 
   case Type_Dialog:
     // dialogs cannot be maximized
@@ -83,58 +86,13 @@ OBClient::OBClient(int screen, Window window)
   updateProtocols();
   updateNormalHints();
   updateWMHints();
-  // XXX: updateTransientFor();
   updateTitle();
   updateIconTitle();
   updateClass();
+  updateStrut();
 
-/*
-#ifdef DEBUG
-  printf("Mapped window: 0x%lx\n"
-         "  title:         \t%s\t  icon title:    \t%s\n"
-         "  app name:      \t%s\t\t  class:         \t%s\n"
-         "  position:      \t%d, %d\t\t  size:          \t%d, %d\n"
-         "  desktop:       \t%lu\t\t  group:         \t0x%lx\n"
-         "  type:          \t%d\t\t  min size       \t%d, %d\n"
-         "  base size      \t%d, %d\t\t  max size       \t%d, %d\n"
-         "  size incr      \t%d, %d\t\t  gravity        \t%d\n"
-         "  wm state       \t%ld\t\t  can be focused:\t%s\n"
-         "  notify focus:  \t%s\t\t  urgent:        \t%s\n"
-         "  shaped:        \t%s\t\t  modal:         \t%s\n"
-         "  shaded:        \t%s\t\t  iconic:        \t%s\n"
-         "  vert maximized:\t%s\t\t  horz maximized:\t%s\n"
-         "  fullscreen:    \t%s\t\t  floating:      \t%s\n"
-         "  requested pos: \t%s\n",
-         _window,
-         _title.c_str(),
-         _icon_title.c_str(),
-         _app_name.c_str(),
-         _app_class.c_str(),
-         _area.x(), _area.y(),
-         _area.width(), _area.height(),
-         _desktop,
-         _group,
-         _type,
-         _min_x, _min_y,
-         _base_x, _base_y,
-         _max_x, _max_y,
-         _inc_x, _inc_y,
-         _gravity,
-         _wmstate,
-         _can_focus ? "yes" : "no",
-         _focus_notify ? "yes" : "no",
-         _urgent ? "yes" : "no",
-         _shaped ? "yes" : "no",
-         _modal ? "yes" : "no",
-         _shaded ? "yes" : "no",
-         _iconic ? "yes" : "no",
-         _max_vert ? "yes" : "no",
-         _max_horz ? "yes" : "no",
-         _fullscreen ? "yes" : "no",
-         _floating ? "yes" : "no",
-         _positioned ? "yes" : "no");
-#endif
-*/
+  calcLayer();
+  changeState();
 }
 
 
@@ -142,9 +100,11 @@ OBClient::~OBClient()
 {
   const otk::OBProperty *property = Openbox::instance->property();
 
-  // these values should not be persisted across a window unmapping/mapping
-  property->erase(_window, otk::OBProperty::net_wm_desktop);
-  property->erase(_window, otk::OBProperty::net_wm_state);
+  if (Openbox::instance->state() != Openbox::State_Exiting) {
+    // these values should not be persisted across a window unmapping/mapping
+    property->erase(_window, otk::OBProperty::net_wm_desktop);
+    property->erase(_window, otk::OBProperty::net_wm_state);
+  }
 }
 
 
@@ -292,7 +252,8 @@ void OBClient::getState()
 {
   const otk::OBProperty *property = Openbox::instance->property();
 
-  _modal = _shaded = _max_horz = _max_vert = _fullscreen = _floating = false;
+  _modal = _shaded = _max_horz = _max_vert = _fullscreen = _above = _below =
+    _skip_taskbar = _skip_pager = false;
   
   unsigned long *state;
   unsigned long num = (unsigned) -1;
@@ -305,6 +266,12 @@ void OBClient::getState()
       else if (state[i] ==
                property->atom(otk::OBProperty::net_wm_state_shaded))
         _shaded = true;
+      else if (state[i] ==
+               property->atom(otk::OBProperty::net_wm_state_skip_taskbar))
+        _skip_taskbar = true;
+      else if (state[i] ==
+               property->atom(otk::OBProperty::net_wm_state_skip_pager))
+        _skip_pager = true;
       else if (state[i] ==
                property->atom(otk::OBProperty::net_wm_state_fullscreen))
         _fullscreen = true;
@@ -314,6 +281,12 @@ void OBClient::getState()
       else if (state[i] ==
                property->atom(otk::OBProperty::net_wm_state_maximized_horz))
         _max_horz = true;
+      else if (state[i] ==
+               property->atom(otk::OBProperty::net_wm_state_above))
+        _above = true;
+      else if (state[i] ==
+               property->atom(otk::OBProperty::net_wm_state_below))
+        _below = true;
     }
 
     delete [] state;
@@ -340,6 +313,17 @@ void OBClient::getShaped()
 }
 
 
+void OBClient::calcLayer() {
+  if (_iconic) _layer = OBScreen::Layer_Icon;
+  else if (_type == Type_Desktop) _layer = OBScreen::Layer_Desktop;
+  else if (_type == Type_Dock) _layer = OBScreen::Layer_Top;
+  else if (_fullscreen) _layer = OBScreen::Layer_Fullscreen;
+  else if (_above) _layer = OBScreen::Layer_Above;
+  else if (_below) _layer = OBScreen::Layer_Below;
+  else _layer = OBScreen::Layer_Normal;
+}
+
+
 void OBClient::updateProtocols()
 {
   const otk::OBProperty *property = Openbox::instance->property();
@@ -356,7 +340,8 @@ void OBClient::updateProtocols()
       if (proto[i] == property->atom(otk::OBProperty::wm_delete_window)) {
         _decorations |= Decor_Close;
         _functions |= Func_Close;
-        // XXX: update the decor?
+        if (frame)
+          frame->adjustSize(); // update the decorations
       } else if (proto[i] == property->atom(otk::OBProperty::wm_take_focus))
         // if this protocol is requested, then the window will be notified
         // by the window manager whenever it receives focus
@@ -371,6 +356,7 @@ void OBClient::updateNormalHints()
 {
   XSizeHints size;
   long ret;
+  int oldgravity = _gravity;
 
   // defaults
   _gravity = NorthWestGravity;
@@ -388,7 +374,7 @@ void OBClient::updateNormalHints()
 
     if (size.flags & PWinGravity)
       _gravity = size.win_gravity;
-    
+
     if (size.flags & PMinSize)
       _min_size.setPoint(size.min_width, size.min_height);
     
@@ -401,6 +387,15 @@ void OBClient::updateNormalHints()
     if (size.flags & PResizeInc)
       _size_inc.setPoint(size.width_inc, size.height_inc);
   }
+
+  // if the client has a frame, i.e. has already been mapped and is
+  // changing its gravity
+  if (frame && _gravity != oldgravity) {
+    // move our idea of the client's position based on its new gravity
+    int x, y;
+    frame->frameGravity(x, y);
+    _area.setPos(x, y);
+  }
 }
 
 
@@ -449,6 +444,9 @@ void OBClient::updateTitle()
 
   if (_title.empty())
     _title = _("Unnamed Window");
+
+  if (frame)
+    frame->setTitle(_title);
 }
 
 
@@ -490,6 +488,29 @@ void OBClient::updateClass()
 }
 
 
+void OBClient::updateStrut()
+{
+  unsigned long num = 4;
+  unsigned long *data;
+  if (!Openbox::instance->property()->get(_window,
+                                          otk::OBProperty::net_wm_strut,
+                                          otk::OBProperty::Atom_Cardinal,
+                                          &num, &data))
+    return;
+
+  if (num == 4) {
+    _strut.left = data[0];
+    _strut.right = data[1];
+    _strut.top = data[2];
+    _strut.bottom = data[3];
+    
+    Openbox::instance->screen(_screen)->updateStrut();
+  }
+
+  delete [] data;
+}
+
+
 void OBClient::propertyHandler(const XPropertyEvent &e)
 {
   otk::OtkEventHandler::propertyHandler(e);
@@ -522,6 +543,8 @@ void OBClient::propertyHandler(const XPropertyEvent &e)
   else if (e.atom == property->atom(otk::OBProperty::wm_protocols))
     updateProtocols();
   // XXX: transient for hint
+  else if (e.atom == property->atom(otk::OBProperty::net_wm_strut))
+    updateStrut();
   // XXX: strut hint
 }
 
@@ -544,10 +567,11 @@ void OBClient::setWMState(long state)
 
 void OBClient::setDesktop(long target)
 {
-  assert(target >= 0);
+  printf("Setting desktop %ld\n", target);
+  assert(target >= 0 || target == (signed)0xffffffff);
   //assert(target == 0xffffffff || target < MAX);
-  
-  // XXX: move the window to the new desktop
+
+  // XXX: move the window to the new desktop (and set root property)
   _desktop = target;
 }
 
@@ -555,6 +579,7 @@ void OBClient::setDesktop(long target)
 void OBClient::setState(StateAction action, long data1, long data2)
 {
   const otk::OBProperty *property = Openbox::instance->property();
+  bool restack = false, shadestate = _shaded;
 
   if (!(action == State_Add || action == State_Remove ||
         action == State_Toggle))
@@ -577,11 +602,19 @@ void OBClient::setState(StateAction action, long data1, long data2)
         action = _max_horz ? State_Remove : State_Add;
       else if (state == property->atom(otk::OBProperty::net_wm_state_shaded))
         action = _shaded ? State_Remove : State_Add;
+      else if (state ==
+               property->atom(otk::OBProperty::net_wm_state_skip_taskbar))
+        action = _skip_taskbar ? State_Remove : State_Add;
+      else if (state ==
+               property->atom(otk::OBProperty::net_wm_state_skip_pager))
+        action = _skip_pager ? State_Remove : State_Add;
       else if (state ==
                property->atom(otk::OBProperty::net_wm_state_fullscreen))
         action = _fullscreen ? State_Remove : State_Add;
-      else if (state == property->atom(otk::OBProperty::net_wm_state_floating))
-        action = _floating ? State_Remove : State_Add;
+      else if (state == property->atom(otk::OBProperty::net_wm_state_above))
+        action = _above ? State_Remove : State_Add;
+      else if (state == property->atom(otk::OBProperty::net_wm_state_below))
+        action = _below ? State_Remove : State_Add;
     }
     
     if (action == State_Add) {
@@ -602,18 +635,29 @@ void OBClient::setState(StateAction action, long data1, long data2)
       } else if (state ==
                  property->atom(otk::OBProperty::net_wm_state_shaded)) {
         if (_shaded) continue;
-        _shaded = true;
-        // XXX: hide the client window
+        // shade when we're all thru here
+        shadestate = true;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_skip_taskbar)) {
+        _skip_taskbar = true;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_skip_pager)) {
+        _skip_pager = true;
       } else if (state ==
                  property->atom(otk::OBProperty::net_wm_state_fullscreen)) {
         if (_fullscreen) continue;
         _fullscreen = true;
-        // XXX: raise the window n shit
+        restack = false;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_above)) {
+        if (_above) continue;
+        _above = true;
+        restack = true;
       } else if (state ==
-                 property->atom(otk::OBProperty::net_wm_state_floating)) {
-        if (_floating) continue;
-        _floating = true;
-        // XXX: raise the window n shit
+                 property->atom(otk::OBProperty::net_wm_state_below)) {
+        if (_below) continue;
+        _below = true;
+        restack = true;
       }
 
     } else { // action == State_Remove
@@ -633,21 +677,85 @@ void OBClient::setState(StateAction action, long data1, long data2)
       } else if (state ==
                  property->atom(otk::OBProperty::net_wm_state_shaded)) {
         if (!_shaded) continue;
-        _shaded = false;
-        // XXX: show the client window
+        // unshade when we're all thru here
+        shadestate = false;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_skip_taskbar)) {
+        _skip_taskbar = false;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_skip_pager)) {
+        _skip_pager = false;
       } else if (state ==
                  property->atom(otk::OBProperty::net_wm_state_fullscreen)) {
         if (!_fullscreen) continue;
         _fullscreen = false;
-        // XXX: lower the window to its proper layer
+        restack = true;
       } else if (state ==
-                 property->atom(otk::OBProperty::net_wm_state_floating)) {
-        if (!_floating) continue;
-        _floating = false;
-        // XXX: lower the window to its proper layer
+                 property->atom(otk::OBProperty::net_wm_state_above)) {
+        if (!_above) continue;
+        _above = false;
+        restack = true;
+      } else if (state ==
+                 property->atom(otk::OBProperty::net_wm_state_below)) {
+        if (!_below) continue;
+        _below = false;
+        restack = true;
       }
     }
   }
+  if (shadestate != _shaded)
+    shade(shadestate);
+  if (restack) {
+    calcLayer();
+    Openbox::instance->screen(_screen)->restack(true, this); // raise
+  }
+}
+
+
+void OBClient::toggleClientBorder(bool addborder)
+{
+  // adjust our idea of where the client is, based on its border. When the
+  // border is removed, the client should now be considered to be in a
+  // different position.
+  // when re-adding the border to the client, the same operation needs to be
+  // reversed.
+  int x = _area.x(), y = _area.y();
+  switch(_gravity) {
+  case NorthWestGravity:
+  case WestGravity:
+  case SouthWestGravity:
+    break;
+  case NorthEastGravity:
+  case EastGravity:
+  case SouthEastGravity:
+    if (addborder) x -= _border_width * 2;
+    else           x += _border_width * 2;
+    break;
+  }
+  switch(_gravity) {
+  case NorthWestGravity:
+  case NorthGravity:
+  case NorthEastGravity:
+    break;
+  case SouthWestGravity:
+  case SouthGravity:
+  case SouthEastGravity:
+    if (addborder) y -= _border_width * 2;
+    else           y += _border_width * 2;
+    break;
+  default:
+    // no change for StaticGravity etc.
+    break;
+  }
+  _area.setPos(x, y);
+
+  if (addborder) {
+    XSetWindowBorderWidth(otk::OBDisplay::display, _window, _border_width);
+
+    // move the client so it is back it the right spot _with_ its border!
+    XMoveWindow(otk::OBDisplay::display, _window, x, y);
+  } else
+    XSetWindowBorderWidth(otk::OBDisplay::display, _window, 0);
 }
 
 
@@ -694,28 +802,42 @@ void OBClient::clientMessageHandler(const XClientMessageEvent &e)
       setDesktop(e.data.l[0]); // use the found event
     else
       setDesktop(e.data.l[0]); // use the original event
-  }
-  else if (e.message_type == property->atom(otk::OBProperty::net_wm_state))
+  } else if (e.message_type == property->atom(otk::OBProperty::net_wm_state)) {
     // can't compress these
     setState((StateAction)e.data.l[0], e.data.l[1], e.data.l[2]);
+  } else if (e.message_type ==
+             property->atom(otk::OBProperty::net_close_window)) {
+    close();
+  } else if (e.message_type ==
+             property->atom(otk::OBProperty::net_active_window)) {
+    focus();
+    Openbox::instance->screen(_screen)->restack(true, this); // raise
+  } else {
+  }
 }
 
 
-#if defined(SHAPE) || defined(DOXYGEN_IGNORE)
+#if defined(SHAPE)
 void OBClient::shapeHandler(const XShapeEvent &e)
 {
   otk::OtkEventHandler::shapeHandler(e);
   
   _shaped = e.shaped;
+  frame->adjustShape();
 }
 #endif
 
 
-void OBClient::resize(Corner anchor, int w, int h)
+void OBClient::resize(Corner anchor, int w, int h, int x, int y)
 {
   w -= _base_size.x(); 
   h -= _base_size.y();
 
+  // for interactive resizing. have to move half an increment in each
+  // direction.
+  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()) {
@@ -738,47 +860,207 @@ void OBClient::resize(Corner anchor, int w, int h)
 
   w += _base_size.x();
   h += _base_size.y();
-  
-  switch (anchor) {
-  case TopLeft:
-    break;
-  case TopRight:
-    _area.setX(_area.x() - _area.width() - w);
-    break;
-  case BottomLeft:
-    _area.setY(_area.y() - _area.height() - h);
-    break;
-  case BottomRight:
-    _area.setX(_area.x() - _area.width() - w);
-    _area.setY(_area.y() - _area.height() - h);
-    break;
+
+  if (x == INT_MIN || y == INT_MIN) {
+    x = _area.x();
+    y = _area.y();
+    switch (anchor) {
+    case TopLeft:
+      break;
+    case TopRight:
+      x -= w - _area.width();
+      break;
+    case BottomLeft:
+      y -= h - _area.height();
+      break;
+    case BottomRight:
+      x -= w - _area.width();
+      y -= h - _area.height();
+      break;
+    }
   }
 
   _area.setSize(w, h);
 
-  // resize the frame to match
-  frame->adjust();
+  XResizeWindow(otk::OBDisplay::display, _window, w, h);
+
+  // resize the frame to match the request
+  frame->adjustSize();
+  move(x, y);
 }
 
 
 void OBClient::move(int x, int y)
 {
   _area.setPos(x, y);
+
   // move the frame to be in the requested position
-  frame->applyGravity();
+  frame->adjustPosition();
+}
+
+
+void OBClient::close()
+{
+  XEvent ce;
+  const otk::OBProperty *property = Openbox::instance->property();
+
+  if (!(_functions & Func_Close)) return;
+
+  // XXX: itd be cool to do timeouts and shit here for killing the client's
+  //      process off
+  // like... if the window is around after 5 seconds, then the close button
+  // turns a nice red, and if this function is called again, the client is
+  // explicitly killed.
+
+  ce.xclient.type = ClientMessage;
+  ce.xclient.message_type =  property->atom(otk::OBProperty::wm_protocols);
+  ce.xclient.display = otk::OBDisplay::display;
+  ce.xclient.window = _window;
+  ce.xclient.format = 32;
+  ce.xclient.data.l[0] = property->atom(otk::OBProperty::wm_delete_window);
+  ce.xclient.data.l[1] = CurrentTime;
+  ce.xclient.data.l[2] = 0l;
+  ce.xclient.data.l[3] = 0l;
+  ce.xclient.data.l[4] = 0l;
+  XSendEvent(otk::OBDisplay::display, _window, False, NoEventMask, &ce);
+}
+
+
+void OBClient::changeState()
+{
+  const otk::OBProperty *property = Openbox::instance->property();
+
+  unsigned long state[2];
+  state[0] = _wmstate;
+  state[1] = None;
+  property->set(_window, otk::OBProperty::wm_state, otk::OBProperty::wm_state,
+                state, 2);
+  
+  Atom netstate[10];
+  int num = 0;
+  if (_modal)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_modal);
+  if (_shaded)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_shaded);
+  if (_iconic)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_hidden);
+  if (_skip_taskbar)
+    netstate[num++] =
+      property->atom(otk::OBProperty::net_wm_state_skip_taskbar);
+  if (_skip_pager)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_skip_pager);
+  if (_fullscreen)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_fullscreen);
+  if (_max_vert)
+    netstate[num++] =
+      property->atom(otk::OBProperty::net_wm_state_maximized_vert);
+  if (_max_horz)
+    netstate[num++] =
+      property->atom(otk::OBProperty::net_wm_state_maximized_horz);
+  if (_above)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_above);
+  if (_below)
+    netstate[num++] = property->atom(otk::OBProperty::net_wm_state_below);
+  property->set(_window, otk::OBProperty::net_wm_state,
+                otk::OBProperty::Atom_Atom, netstate, num);
+  
+}
+
+void OBClient::shade(bool shade)
+{
+  if (shade == _shaded) return; // already done
+
+  _wmstate = shade ? IconicState : NormalState;
+  _shaded = shade;
+  changeState();
+  frame->adjustSize();
+}
+
+
+bool OBClient::focus()
+{
+  if (!(_can_focus || _focus_notify) || _focused) return false;
+
+  if (_can_focus)
+    XSetInputFocus(otk::OBDisplay::display, _window, RevertToNone, CurrentTime);
+
+  if (_focus_notify) {
+    XEvent ce;
+    const otk::OBProperty *property = Openbox::instance->property();
+    
+    ce.xclient.type = ClientMessage;
+    ce.xclient.message_type =  property->atom(otk::OBProperty::wm_protocols);
+    ce.xclient.display = otk::OBDisplay::display;
+    ce.xclient.window = _window;
+    ce.xclient.format = 32;
+    ce.xclient.data.l[0] = property->atom(otk::OBProperty::wm_take_focus);
+    ce.xclient.data.l[1] = Openbox::instance->lastTime();
+    ce.xclient.data.l[2] = 0l;
+    ce.xclient.data.l[3] = 0l;
+    ce.xclient.data.l[4] = 0l;
+    XSendEvent(otk::OBDisplay::display, _window, False, NoEventMask, &ce);
+  }
+
+  return true;
+}
+
+
+void OBClient::unfocus()
+{
+  if (!_focused) return;
+
+  assert(Openbox::instance->focusedClient() == this);
+  Openbox::instance->setFocusedClient(0);
+}
+
+
+void OBClient::focusHandler(const XFocusChangeEvent &e)
+{
+#ifdef    DEBUG
+  printf("FocusIn for 0x%lx\n", e.window);
+#endif // DEBUG
+  
+  OtkEventHandler::focusHandler(e);
+
+  frame->focus();
+  _focused = true;
+
+  Openbox::instance->setFocusedClient(this);
+}
+
+
+void OBClient::unfocusHandler(const XFocusChangeEvent &e)
+{
+#ifdef    DEBUG
+  printf("FocusOut for 0x%lx\n", e.window);
+#endif // DEBUG
+  
+  OtkEventHandler::unfocusHandler(e);
+
+  frame->unfocus();
+  _focused = false;
+
+  if (Openbox::instance->focusedClient() == this) {
+    printf("UNFOCUSED!\n");
+    Openbox::instance->setFocusedClient(this);
+  }
 }
 
 
 void OBClient::configureRequestHandler(const XConfigureRequestEvent &e)
 {
-  OtkEventHandler::configureRequestHandler(e);
+#ifdef    DEBUG
+  printf("ConfigureRequest for 0x%lx\n", e.window);
+#endif // DEBUG
   
+  OtkEventHandler::configureRequestHandler(e);
+
   // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
 
   if (e.value_mask & CWBorderWidth)
     _border_width = e.border_width;
 
-    // resize, then move, as specified in the EWMH section 7.7
+  // resize, then move, as specified in the EWMH section 7.7
   if (e.value_mask & (CWWidth | CWHeight)) {
     int w = (e.value_mask & CWWidth) ? e.width : _area.width();
     int h = (e.value_mask & CWHeight) ? e.height : _area.height();
@@ -800,10 +1082,14 @@ void OBClient::configureRequestHandler(const XConfigureRequestEvent &e)
       corner = TopLeft;
     }
 
-    resize(corner, w, h);
-  }
-
-  if (e.value_mask & (CWX | CWY)) {
+    // if moving AND resizing ...
+    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();
+      resize(corner, w, h, x, y);
+    } else // if JUST resizing...
+      resize(corner, w, h);
+  } 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();
     move(x, y);
@@ -857,4 +1143,26 @@ void OBClient::destroyHandler(const XDestroyWindowEvent &e)
 }
 
 
+void OBClient::reparentHandler(const XReparentEvent &e)
+{
+  // this is when the client is first taken captive in the frame
+  if (e.parent == frame->plate()) return;
+
+#ifdef    DEBUG
+  printf("ReparentNotify for 0x%lx\n", e.window);
+#endif // DEBUG
+
+  OtkEventHandler::reparentHandler(e);
+
+  /*
+    This event is quite rare and is usually handled in unmapHandler.
+    However, if the window is unmapped when the reparent event occurs,
+    the window manager never sees it because an unmap event is not sent
+    to an already unmapped window.
+  */
+
+  // this deletes us etc
+  Openbox::instance->screen(_screen)->unmanageWindow(this);
+}
+
 }
This page took 0.036068 seconds and 4 git commands to generate.