]> Dogcows Code - chaz/openbox/blobdiff - src/client.cc
reorder how theyre destroyed, probably doesnt matter anyways.
[chaz/openbox] / src / client.cc
index f564786f24cc0d26b8a1c530151e7ac5d92c8065..b36ba9aff2a6fe9bdf701b5f1de4f848b7396f56 100644 (file)
@@ -60,7 +60,8 @@ Client::Client(int screen, Window window)
   getShaped();
 
   updateProtocols();
-  updateNormalHints();
+  getGravity(); // get the attribute gravity
+  updateNormalHints(); // this may override the attribute gravity
   updateWMHints();
   updateTitle();
   updateIconTitle();
@@ -91,6 +92,17 @@ Client::~Client()
 }
 
 
+void Client::getGravity()
+{
+  XWindowAttributes wattrib;
+  Status ret;
+
+  ret = XGetWindowAttributes(**otk::display, _window, &wattrib);
+  assert(ret != BadWindow);
+  _gravity = wattrib.win_gravity;
+}
+
+
 void Client::getDesktop()
 {
   // defaults to the current desktop
@@ -156,15 +168,17 @@ void Client::getType()
 
 void Client::setupDecorAndFunctions()
 {
-  // start with everything
+  // start with everything (cept fullscreen)
   _decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
     Decor_Iconify | Decor_Maximize;
-  _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
+  _functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
+    Func_Shade;
   
   switch (_type) {
   case Type_Normal:
     // normal windows retain all of the possible decorations and
-    // functionality
+    // functionality, and are the only windows that you can fullscreen
+    _functions |= Func_Fullscreen;
 
   case Type_Dialog:
     // dialogs cannot be maximized
@@ -197,8 +211,11 @@ 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))
@@ -222,7 +239,7 @@ void Client::setupDecorAndFunctions()
     }
   }
 
-  // XXX: changeAllowedActions();
+  changeAllowedActions();
 }
 
 
@@ -275,10 +292,9 @@ void Client::getState()
     for (unsigned long i = 0; i < num; ++i) {
       if (state[i] == otk::Property::atoms.net_wm_state_modal)
         _modal = true;
-      else if (state[i] == otk::Property::atoms.net_wm_state_shaded) {
+      else if (state[i] == otk::Property::atoms.net_wm_state_shaded)
         _shaded = true;
-        _wmstate = IconicState;
-      } else if (state[i] == otk::Property::atoms.net_wm_state_skip_taskbar)
+      else if (state[i] == otk::Property::atoms.net_wm_state_skip_taskbar)
         _skip_taskbar = true;
       else if (state[i] == otk::Property::atoms.net_wm_state_skip_pager)
         _skip_pager = true;
@@ -339,7 +355,7 @@ void Client::calcLayer() {
         if we don't have a frame, then we aren't mapped yet (and this would
         SIGSEGV :)
       */
-      openbox->screen(_screen)->restack(true, this); // raise
+      openbox->screen(_screen)->raiseWindow(this);
     }
   }
 }
@@ -378,7 +394,6 @@ void Client::updateNormalHints()
   int oldgravity = _gravity;
 
   // defaults
-  _gravity = NorthWestGravity;
   _size_inc.setPoint(1, 1);
   _base_size.setPoint(0, 0);
   _min_size.setPoint(0, 0);
@@ -391,8 +406,18 @@ void Client::updateNormalHints()
   if (XGetWMNormalHints(**otk::display, _window, &size, &ret)) {
     _positioned = (size.flags & (PPosition|USPosition));
 
-    if (size.flags & PWinGravity)
+    if (size.flags & PWinGravity) {
       _gravity = size.win_gravity;
+      
+      // 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);
+      }
+    }
 
     if (size.flags & PMinSize)
       _min_size.setPoint(size.min_width, size.min_height);
@@ -406,15 +431,6 @@ void Client::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);
-  }
 }
 
 
@@ -645,6 +661,7 @@ void Client::setDesktop(long target)
 void Client::setState(StateAction action, long data1, long data2)
 {
   bool shadestate = _shaded;
+  bool fsstate = _fullscreen;
 
   if (!(action == State_Add || action == State_Remove ||
         action == State_Toggle))
@@ -691,16 +708,13 @@ void Client::setState(StateAction action, long data1, long data2)
         _max_horz = true;
         // XXX: resize the window etc
       } else if (state == otk::Property::atoms.net_wm_state_shaded) {
-        if (_shaded) continue;
-        // shade when we're all thru here
         shadestate = true;
       } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
         _skip_taskbar = true;
       } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
         _skip_pager = true;
       } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
-        if (_fullscreen) continue;
-        _fullscreen = true;
+        fsstate = true;
       } else if (state == otk::Property::atoms.net_wm_state_above) {
         if (_above) continue;
         _above = true;
@@ -722,16 +736,13 @@ void Client::setState(StateAction action, long data1, long data2)
         _max_horz = false;
         // XXX: resize the window etc
       } else if (state == otk::Property::atoms.net_wm_state_shaded) {
-        if (!_shaded) continue;
-        // unshade when we're all thru here
         shadestate = false;
       } else if (state == otk::Property::atoms.net_wm_state_skip_taskbar) {
         _skip_taskbar = false;
       } else if (state == otk::Property::atoms.net_wm_state_skip_pager) {
         _skip_pager = false;
       } else if (state == otk::Property::atoms.net_wm_state_fullscreen) {
-        if (!_fullscreen) continue;
-        _fullscreen = false;
+        fsstate = false;
       } else if (state == otk::Property::atoms.net_wm_state_above) {
         if (!_above) continue;
         _above = false;
@@ -741,6 +752,10 @@ void Client::setState(StateAction action, long data1, long data2)
       }
     }
   }
+  // change fullscreen state before shading, as it will affect if the window
+  // can shade or not
+  if (fsstate != _fullscreen)
+    fullscreen(fsstate);
   if (shadestate != _shaded)
     shade(shadestate);
   calcLayer();
@@ -756,6 +771,7 @@ void Client::toggleClientBorder(bool addborder)
   // reversed.
   int x = _area.x(), y = _area.y();
   switch(_gravity) {
+  default:
   case NorthWestGravity:
   case WestGravity:
   case SouthWestGravity:
@@ -766,8 +782,17 @@ void Client::toggleClientBorder(bool addborder)
     if (addborder) x -= _border_width * 2;
     else           x += _border_width * 2;
     break;
+  case NorthGravity:
+  case SouthGravity:
+  case CenterGravity:
+  case ForgetGravity:
+  case StaticGravity:
+    if (addborder) x -= _border_width;
+    else           x += _border_width;
+    break;
   }
   switch(_gravity) {
+  default:
   case NorthWestGravity:
   case NorthGravity:
   case NorthEastGravity:
@@ -778,8 +803,13 @@ void Client::toggleClientBorder(bool addborder)
     if (addborder) y -= _border_width * 2;
     else           y += _border_width * 2;
     break;
-  default:
-    // no change for StaticGravity etc.
+  case WestGravity:
+  case EastGravity:
+  case CenterGravity:
+  case ForgetGravity:
+  case StaticGravity:
+    if (addborder) y -= _border_width;
+    else           y += _border_width;
     break;
   }
   _area.setPos(x, y);
@@ -856,7 +886,7 @@ void Client::clientMessageHandler(const XClientMessageEvent &e)
       shade(false);
     // XXX: deiconify
     focus();
-    openbox->screen(_screen)->restack(true, this); // raise
+    openbox->screen(_screen)->raiseWindow(this);
   }
 }
 
@@ -874,7 +904,14 @@ void Client::shapeHandler(const XShapeEvent &e)
 #endif
 
 
-void Client::resize(Corner anchor, int w, int h, int x, int y)
+void Client::resize(Corner anchor, int w, int h)
+{
+  if (!(_functions & Func_Resize)) return;
+  internal_resize(anchor, w, h);
+}
+
+
+void Client::internal_resize(Corner anchor, int w, int h, int x, int y)
 {
   w -= _base_size.x(); 
   h -= _base_size.y();
@@ -936,11 +973,18 @@ void Client::resize(Corner anchor, int w, int h, int x, int y)
 
   // resize the frame to match the request
   frame->adjustSize();
-  move(x, y);
+  internal_move(x, y);
 }
 
 
 void Client::move(int x, int y)
+{
+  if (!(_functions & Func_Move)) return;
+  internal_move(x, y);
+}
+
+
+void Client::internal_move(int x, int y)
 {
   _area.setPos(x, y);
 
@@ -1031,9 +1075,63 @@ void Client::changeState()
 }
 
 
+void Client::changeAllowedActions(void)
+{
+  Atom actions[9];
+  int num = 0;
+
+  actions[num++] = otk::Property::atoms.net_wm_action_change_desktop;
+
+  if (_functions & Func_Shade)
+    actions[num++] = otk::Property::atoms.net_wm_action_shade;
+  if (_functions & Func_Close)
+    actions[num++] = otk::Property::atoms.net_wm_action_close;
+  if (_functions & Func_Move)
+    actions[num++] = otk::Property::atoms.net_wm_action_move;
+  if (_functions & Func_Iconify)
+    actions[num++] = otk::Property::atoms.net_wm_action_minimize;
+  if (_functions & Func_Resize)
+    actions[num++] = otk::Property::atoms.net_wm_action_resize;
+  if (_functions & Func_Fullscreen)
+    actions[num++] = otk::Property::atoms.net_wm_action_fullscreen;
+  if (_functions & Func_Maximize) {
+    actions[num++] = otk::Property::atoms.net_wm_action_maximize_horz;
+    actions[num++] = otk::Property::atoms.net_wm_action_maximize_vert;
+  }
+
+  otk::Property::set(_window, otk::Property::atoms.net_wm_allowed_actions,
+                     otk::Property::atoms.atom, actions, num);
+}
+
+
+void Client::applyStartupState()
+{
+  // these are in a carefully crafted order..
+  
+  if (_fullscreen) {
+    _fullscreen = false;
+    fullscreen(true);
+  }
+  if (_shaded) {
+    _shaded = false;
+    shade(true);
+  }
+  
+  if (_max_vert); // XXX: incomplete
+  if (_max_horz); // XXX: incomplete
+
+  if (_skip_taskbar); // nothing to do for this
+  if (_skip_pager);   // nothing to do for this
+  if (_modal);        // nothing to do for this
+  if (_above);        // nothing to do for this
+  if (_below);        // nothing to do for this
+}
+
+
 void Client::shade(bool shade)
 {
-  if (shade == _shaded) return; // already done
+  if (!(_functions & Func_Shade) || // can't
+      _shaded == shade) return;     // already done
 
   _wmstate = shade ? IconicState : NormalState;
   _shaded = shade;
@@ -1042,6 +1140,54 @@ void Client::shade(bool shade)
 }
 
 
+void Client::fullscreen(bool fs)
+{
+  static FunctionFlags saved_func;
+  static DecorationFlags saved_decor;
+  static otk::Rect saved_area;
+  static otk::Point saved_logical_size;
+
+  if (!(_functions & Func_Fullscreen) || // can't
+      _fullscreen == fs) return;         // already done
+
+  _fullscreen = fs;
+  changeState(); // change the state hints on the client
+
+  if (fs) {
+    // save the functions and remove them
+    saved_func = _functions;
+    _functions = _functions & (Func_Close | Func_Fullscreen | Func_Iconify);
+    // save the decorations and remove them
+    saved_decor = _decorations;
+    _decorations = 0;
+    // save the area and adjust it (we don't call internal resize here for
+    // constraints on the size, etc, we just make it fullscreen).
+    saved_area = _area;
+    const otk::ScreenInfo *info = otk::display->screenInfo(_screen);
+    _area.setRect(0, 0, info->width(), info->height());
+    saved_logical_size = _logical_size;
+    _logical_size.setPoint((info->width() - _base_size.x()) / _size_inc.x(),
+                           (info->height() - _base_size.y()) / _size_inc.y());
+  } else {
+    _functions = saved_func;
+    _decorations = saved_decor;
+    _area = saved_area;
+    _logical_size = saved_logical_size;
+  }
+  
+  changeAllowedActions();  // based on the new _functions
+  
+  frame->adjustSize();     // drop/replace the decor's and resize
+  frame->adjustPosition(); // get (back) in position!
+
+  // raise (back) into our stacking layer
+  openbox->screen(_screen)->raiseWindow(this);
+
+  // try focus us when we go into fullscreen mode
+  if (fs) focus();
+}
+
+
 bool Client::focus() const
 {
   // won't try focus if the client doesn't want it, or if the window isn't
@@ -1152,26 +1298,26 @@ 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();
-      resize(corner, w, h, x, y);
+      internal_resize(corner, w, h, x, y);
     } else // if JUST resizing...
-      resize(corner, w, h);
+      internal_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);
+    internal_move(x, y);
   }
 
   if (e.value_mask & CWStackMode) {
     switch (e.detail) {
     case Below:
     case BottomIf:
-      openbox->screen(_screen)->restack(false, this); // lower
+      openbox->screen(_screen)->lowerWindow(this);
       break;
 
     case Above:
     case TopIf:
     default:
-      openbox->screen(_screen)->restack(true, this); // raise
+      openbox->screen(_screen)->raiseWindow(this);
       break;
     }
   }
This page took 0.031455 seconds and 4 git commands to generate.