]> Dogcows Code - chaz/openbox/blobdiff - src/client.cc
supply the same interface with optional arguments as before. increment callback funct...
[chaz/openbox] / src / client.cc
index e0d68db406749b245a435439429a3e25e40ffd7d..83fd110721ce13350ef8241859f07a5b35ba93d7 100644 (file)
@@ -39,30 +39,26 @@ Client::Client(int screen, Window window)
   
   // update EVERYTHING the first time!!
 
-  // we default to NormalState, visible
+  // defaults
   _wmstate = NormalState;
-  // start unfocused
   _focused = false;
-  // not a transient by default of course
   _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;
+  _modal_child = 0;
+  _group = None;
+  _desktop = 0;
   
   getArea();
   getDesktop();
+  getState();  // do this before updateTransientFor! (for _modal)
+  getShaped();
 
   updateTransientFor();
-  getType();
   getMwmHints();
-
-  getState();
-  getShaped();
+  getType(); // this can change the mwmhints for special cases
 
   updateProtocols();
 
@@ -103,7 +99,7 @@ Client::~Client()
     _transients.front()->_transient_for = 0;
     _transients.pop_front();
   }
-  
+
   // clean up parents reference to this
   if (_transient_for)
     _transient_for->_transients.remove(this); // remove from old parent
@@ -188,9 +184,12 @@ void Client::getType()
         _type = Type_Dialog;
       else if (val[i] == otk::Property::atoms.net_wm_window_type_normal)
         _type = Type_Normal;
-//    XXX: make this work again
-//    else if (val[i] == otk::Property::atoms.kde_net_wm_window_type_override)
-//      mwm_decorations = 0; // prevent this window from getting any decor
+      else if (val[i] == otk::Property::atoms.kde_net_wm_window_type_override){
+        // prevent this window from getting any decor or functionality
+        _mwmhints.flags &= MwmFlag_Functions | MwmFlag_Decorations;
+        _mwmhints.decorations = 0;
+        _mwmhints.functions = 0;
+      }
       if (_type != (WindowType) -1)
         break; // grab the first known type
     }
@@ -265,11 +264,8 @@ void Client::setupDecorAndFunctions()
         _decorations &= ~Decor_Border;
       if (! (_mwmhints.decorations & MwmDecor_Handle))
         _decorations &= ~Decor_Handle;
-      if (! (_mwmhints.decorations & MwmDecor_Title)) {
+      if (! (_mwmhints.decorations & MwmDecor_Title))
         _decorations &= ~Decor_Titlebar;
-        // if we don't have a titlebar, then we cannot shade!
-        _functions &= ~Func_Shade;
-      }
       if (! (_mwmhints.decorations & MwmDecor_Iconify))
         _decorations &= ~Decor_Iconify;
       if (! (_mwmhints.decorations & MwmDecor_Maximize))
@@ -293,6 +289,10 @@ void Client::setupDecorAndFunctions()
     }
   }
 
+  // can't maximize without moving/resizing
+  if (!((_functions & Func_Move) && (_functions & Func_Resize)))
+    _functions &= ~Func_Maximize;
+
   // finally, user specified disabled decorations are applied to subtract
   // decorations
   if (_disabled_decorations & Decor_Titlebar)
@@ -310,16 +310,17 @@ void Client::setupDecorAndFunctions()
   if (_disabled_decorations & Decor_Close)
     _decorations &= ~Decor_Close;
 
-  // You can't shade without a titlebar
+  // if we don't have a titlebar, then we cannot shade!
   if (!(_decorations & Decor_Titlebar))
     _functions &= ~Func_Shade;
-  
+
   changeAllowedActions();
 
   if (frame) {
     frame->adjustSize(); // change the decors on the frame
     frame->adjustPosition(); // with more/less decorations, we may need to be
                              // moved
+    remaximize(); // with new decor, the window's maximized size may change
   }
 }
 
@@ -481,9 +482,6 @@ void Client::updateNormalHints()
   _min_size.setPoint(0, 0);
   _max_size.setPoint(INT_MAX, INT_MAX);
 
-  // XXX: might want to cancel any interactive resizing of the window at this
-  // point..
-
   // get the hints from the window
   if (XGetWMNormalHints(**otk::display, _window, &size, &ret)) {
     _positioned = (size.flags & (PPosition|USPosition));
@@ -495,7 +493,7 @@ void Client::updateNormalHints()
       // changing its gravity
       if (frame && _gravity != oldgravity) {
         // move our idea of the client's position based on its new gravity
-        int x, y;
+        int x = frame->rect().x(), y = frame->rect().y();
         frame->frameGravity(x, y);
         _area.setPos(x, y);
       }
@@ -674,13 +672,18 @@ void Client::updateTransientFor()
 
   // if anything has changed...
   if (c != _transient_for) {
+    bool m = _modal;
+    if (_modal)
+      setModal(false);
+    
     if (_transient_for)
       _transient_for->_transients.remove(this); // remove from old parent
     _transient_for = c;
     if (_transient_for)
       _transient_for->_transients.push_back(this); // add to new parent
 
-    // XXX: change decor status?
+    if (m)
+      setModal(true);
   }
 }
 
@@ -793,12 +796,61 @@ void Client::setDesktop(long target)
 }
 
 
+Client *Client::findModalChild(Client *skip) const
+{
+  Client *ret = 0;
+  
+  // find a modal child recursively and try focus it
+  List::const_iterator it, end = _transients.end();
+  for (it = _transients.begin(); it != end; ++it)
+    if ((*it)->_modal && *it != skip)
+      return *it; // got one
+  // none of our direct children are modal, let them try check
+  for (it = _transients.begin(); it != end; ++it)
+    if ((ret = (*it)->findModalChild()))
+      return ret; // got one
+  return ret;
+}
+
+
+void Client::setModal(bool modal)
+{
+  if (modal == _modal) return;
+  
+  if (modal) {
+    Client *c = this;
+    while (c->_transient_for) {
+      c = c->_transient_for;
+      if (c->_modal_child) break; // already has a modal child
+      c->_modal_child = this;
+    }
+  } else {
+    // try find a replacement modal dialog
+    Client *replacement = 0;
+    
+    Client *c = this;
+    while (c->_transient_for) // go up the tree
+      c = c->_transient_for;
+    replacement = c->findModalChild(this); // find a modal child, skipping this
+
+    c = this;
+    while (c->_transient_for) {
+      c = c->_transient_for;
+      if (c->_modal_child != this) break; // has a different modal child
+      c->_modal_child = replacement;
+    }
+  }
+  _modal = modal;
+}
+
+
 void Client::setState(StateAction action, long data1, long data2)
 {
   bool shadestate = _shaded;
   bool fsstate = _fullscreen;
   bool maxh = _max_horz;
   bool maxv = _max_vert;
+  bool modal = _modal;
 
   if (!(action == State_Add || action == State_Remove ||
         action == State_Toggle))
@@ -834,14 +886,12 @@ void Client::setState(StateAction action, long data1, long data2)
     if (action == State_Add) {
       if (state == otk::Property::atoms.net_wm_state_modal) {
         if (_modal) continue;
-        _modal = true;
-        // XXX: give it focus if another window has focus that shouldnt now
+        modal = true;
       } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
         maxv = true;
       } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
         if (_max_horz) continue;
         maxh = true;
-        // XXX: resize the window etc
       } else if (state == otk::Property::atoms.net_wm_state_shaded) {
         shadestate = true;
       } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
@@ -861,7 +911,7 @@ void Client::setState(StateAction action, long data1, long data2)
     } else { // action == State_Remove
       if (state == otk::Property::atoms.net_wm_state_modal) {
         if (!_modal) continue;
-        _modal = false;
+        modal = false;
       } else if (state == otk::Property::atoms.net_wm_state_maximized_vert) {
         maxv = false;
       } else if (state == otk::Property::atoms.net_wm_state_maximized_horz) {
@@ -898,6 +948,8 @@ void Client::setState(StateAction action, long data1, long data2)
         maximize(maxv, 2, true);
     }
   }
+  if (modal != _modal)
+    setModal(modal);
   // change fullscreen state before shading, as it will affect if the window
   // can shade or not
   if (fsstate != _fullscreen)
@@ -1038,9 +1090,16 @@ void Client::clientMessageHandler(const XClientMessageEvent &e)
       setDesktop(openbox->screen(_screen)->desktop());
     if (_shaded)
       shade(false);
-    // XXX: deiconify
     focus();
     openbox->screen(_screen)->raiseWindow(this);
+  } else if (e.message_type == otk::Property::atoms.openbox_active_window) {
+    if (_iconic)
+      setDesktop(openbox->screen(_screen)->desktop());
+    if (e.data.l[0] && _shaded)
+      shade(false);
+    focus();
+    if (e.data.l[1])
+      openbox->screen(_screen)->raiseWindow(this);
   }
 }
 
@@ -1149,6 +1208,8 @@ void Client::internal_resize(Corner anchor, int w, int h, bool user,
 void Client::move(int x, int y)
 {
   if (!(_functions & Func_Move)) return;
+  frame->frameGravity(x, y); // get the client's position based on x,y for the
+                             // frame
   internal_move(x, y);
 }
 
@@ -1281,6 +1342,37 @@ void Client::changeAllowedActions(void)
 
   otk::Property::set(_window, otk::Property::atoms.net_wm_allowed_actions,
                      otk::Property::atoms.atom, actions, num);
+
+  // make sure the window isn't breaking any rules now
+  
+  if (!(_functions & Func_Shade) && _shaded)
+    if (frame) shade(false);
+    else _shaded = false;
+  if (!(_functions & Func_Iconify) && _iconic)
+    if (frame) setDesktop(openbox->screen(_screen)->desktop());
+    else _iconic = false;
+  if (!(_functions & Func_Fullscreen) && _fullscreen)
+    if (frame) fullscreen(false);
+    else _fullscreen = false;
+  if (!(_functions & Func_Maximize) && (_max_horz || _max_vert))
+    if (frame) maximize(false, 0);
+    else _max_vert = _max_horz = false;
+}
+
+
+void Client::remaximize()
+{
+  int dir;
+  if (_max_horz && _max_vert)
+    dir = 0;
+  else if (_max_horz)
+    dir = 1;
+  else if (_max_vert)
+    dir = 2;
+  else
+    return; // not maximized
+  _max_horz = _max_vert = false;
+  maximize(true, dir, false);
 }
 
 
@@ -1288,6 +1380,11 @@ void Client::applyStartupState()
 {
   // these are in a carefully crafted order..
 
+  if (_modal) {
+    _modal = false;
+    setModal(true);
+  }
+  
   if (_iconic) {
     _iconic = false;
     setDesktop(ICONIC_DESKTOP);
@@ -1360,18 +1457,11 @@ void Client::maximize(bool max, int dir, bool savearea)
     if (dir == 2 && !_max_vert) return;
   }
 
-  int g = _gravity;
-  
   const otk::Rect &a = openbox->screen(_screen)->area();
-  int x = _area.x(), y = _area.y(), w = _area.width(), h = _area.height();
+  int x = frame->rect().x(), y = frame->rect().y(),
+    w = _area.width(), h = _area.height();
   
   if (max) {
-    // when maximizing, put the client where we want, NOT the frame!
-    _gravity = StaticGravity;
-    // adjust our idea of position based on StaticGravity, so we stay put
-    // unless asked
-    frame->frameGravity(x, y);
-
     if (savearea) {
       long dimensions[4];
       long *readdim;
@@ -1409,7 +1499,7 @@ void Client::maximize(bool max, int dir, bool savearea)
       w = a.width();
     }
     if (dir == 0 || dir == 2) { // vert
-      y = a.y() + frame->size().top;
+      y = a.y();
       h = a.height() - frame->size().top - frame->size().bottom;
     }
   } else {
@@ -1441,24 +1531,20 @@ void Client::maximize(bool max, int dir, bool savearea)
         h = a.height() / 2;
       }
     }
-    otk::Property::erase(_window, otk::Property::atoms.openbox_premax);
   }
 
   if (dir == 0 || dir == 1) // horz
     _max_horz = max;
   if (dir == 0 || dir == 2) // vert
     _max_vert = max;
+
+  if (!_max_horz && !_max_vert)
+    otk::Property::erase(_window, otk::Property::atoms.openbox_premax);
+
   changeState(); // change the state hints on the client
 
+  frame->frameGravity(x, y); // figure out where the client should be going
   internal_resize(TopLeft, w, h, true, x, y);
-  _gravity = g;
-  if (max) {
-    // because of my little gravity trick in here, we have to set the position
-    // of the client to what it really is
-    int x, y;
-    frame->frameGravity(x, y);
-    _area.setPos(x, y);
-  }
 }
 
 
@@ -1544,8 +1630,24 @@ void Client::disableDecorations(DecorationFlags flags)
 }
 
 
+void Client::installColormap(bool install) const
+{
+  XWindowAttributes wa;
+  if (XGetWindowAttributes(**otk::display, _window, &wa)) {
+    if (install)
+      XInstallColormap(**otk::display, wa.colormap);
+    else
+      XUninstallColormap(**otk::display, wa.colormap);
+  }
+}
+
+
 bool Client::focus()
 {
+  // if we have a modal child, then focus it, not us
+  if (_modal_child)
+    return _modal_child->focus();
+
   // won't try focus if the client doesn't want it, or if the window isn't
   // visible on the screen
   if (!(frame->isVisible() && (_can_focus || _focus_notify))) return false;
This page took 0.033267 seconds and 4 git commands to generate.