merge r6257-6267 from trunk
authorDana Jansens <danakj@orodu.net>
Thu, 10 May 2007 04:42:02 +0000 (04:42 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 10 May 2007 04:42:02 +0000 (04:42 +0000)
21 files changed:
COMPLIANCE
Makefile.am
data/menu.xml.in [deleted file]
data/rc.xml.in [deleted file]
data/xsession/openbox-gnome [deleted file]
data/xsession/openbox-gnome-session [deleted file]
data/xsession/openbox-kde [deleted file]
data/xsession/openbox-kde-session [deleted file]
openbox/client.c
openbox/client.h
openbox/event.c
openbox/mouse.c
openbox/openbox.c
openbox/prop.c
openbox/prop.h
openbox/resist.c
openbox/resist.h
openbox/screen.c
openbox/session.c
openbox/stacking.c
openbox/stacking.h

index 0235846..fdc40d1 100644 (file)
@@ -58,8 +58,7 @@ the version of the spec which Openbox is compliant up to for the hint.
        Openbox doesn't look for hung processes at this time.
 + _NET_FRAME_EXTENTS (1.3)
 + _NET_WM_STATE_DEMANDS_ATTENTION (1.3)
-- _NET_RESTACK_WINDOW (1.3)
-       Openbox doesn't support this at this time.
++ _NET_RESTACK_WINDOW (1.3)
 + _NET_WM_SYNC_REQUEST (1.3)
 + _NET_WM_FULL_PLACEMENT (1.4)
 + _NET_WM_MOVERESIZE_CANCEL (1.4)
index 84bf752..8e012f5 100644 (file)
@@ -32,9 +32,7 @@ bin_PROGRAMS = \
 
 bin_SCRIPTS = \
        data/xsession/openbox-gnome-session \
-       data/xsession/openbox-kde-session \
-       data/xsession/openbox-gnome \
-       data/xsession/openbox-kde
+       data/xsession/openbox-kde-session
 
 ## render ##
 
@@ -353,25 +351,29 @@ nodist_pkgconfig_DATA = \
 dist_pixmap_DATA = \
        data/openbox.png
 
-nodist_rc_DATA = \
+dist_rc_DATA = \
        data/rc.xml \
        data/menu.xml
 
 edit = $(SED) \
        -e 's!@version\@!$(VERSION)!' \
-       -e 's!@xsddir\@!$(xsddir)!'
+       -e 's!@bindir\@!$(bindir)!'
 
-data/rc.xml: Makefile $(srcdir)/data/rc.xml.in data
+data/xsession/openbox-gnome-session: Makefile data \
+               $(srcdir)/data/xsession/openbox-gnome-session.in
        @echo make: creating $@
        @rm -f $@
        @mkdir data 2>/dev/null || true
-       @$(edit) $(srcdir)/data/rc.xml.in >$@
+       @$(edit) $(srcdir)/data/xsession/openbox-gnome-session.in >$@
+       @chmod +x $@
 
-data/menu.xml: Makefile $(srcdir)/data/menu.xml.in data
+data/xsession/openbox-kde-session: Makefile data \
+               $(srcdir)/data/xsession/openbox-kde-session.in
        @echo make: creating $@
        @rm -f $@
        @mkdir data 2>/dev/null || true
-       @$(edit) $(srcdir)/data/menu.xml.in >$@
+       @$(edit) $(srcdir)/data/xsession/openbox-kde-session.in >$@
+       @chmod +x $@
 
 dist_gnomewmfiles_DATA = \
        data/gnome-wm-properties/openbox.desktop \
@@ -387,8 +389,8 @@ dist_noinst_DATA = \
        version.h.in \
        data/rc.xsd \
        data/menu.xsd \
-       data/rc.xml.in \
-       data/menu.xml.in \
+       data/xsession/openbox-gnome-session.in \
+       data/xsession/openbox-kde-session.in \
        render/obrender-3.0.pc.in \
        parser/obparser-3.0.pc.in \
        tools/themeupdate/themeupdate.py \
@@ -418,10 +420,6 @@ EXTRA_DIST = \
        COPYING \
        AUTHORS
 
-CLEANFILES = \
-       data/rc.xml \
-       data/menu.xml
-
 #doc:
 #       $(MAKE) -$(MAKEFLAGS) -C doc/doxygen doc
 
diff --git a/data/menu.xml.in b/data/menu.xml.in
deleted file mode 100644 (file)
index 9f86dd6..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<openbox_menu xmlns="http://openbox.org/"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://openbox.org/
-                file://@xsddir@/menu.xsd">
-
-<menu id="games-menu" label="Games">
-  <item label="Crack-Attack">
-    <action name="Execute"><execute>crack-attack</execute></action>
-  </item>
-  <item label="XFRisk">
-    <action name="Execute"><execute>xfrisk</execute></action>
-  </item>
-  <item label="Quake III">
-    <action name="Execute"><execute>quake3</execute></action>
-  </item>
-</menu>
-
-<menu id="apps-menu" label="Applications">
-  <item label="Xterm">
-    <action name="Execute"><execute>xterm</execute></action>
-  </item>
-  <item label="Mozilla">
-    <action name="Execute"><execute>mozilla</execute></action>
-  </item>
-  <item label="Gaim">
-    <action name="Execute"><execute>gaim</execute></action>
-  </item>
-  <item label="Quark">
-    <action name="Execute"><execute>strange-quark</execute></action>
-  </item>
-</menu>
-
-<menu id="root-menu" label="Openbox 3">
-  <separator label="Openbox" />
-  <menu id="apps-menu" />
-  <menu id="games-menu" />
-  <separator />
-  <menu id="client-list-menu" />
-  <separator />
-  <item label="ObConf">
-    <action name="Execute"><execute>obconf</execute></action>
-  </item>
-  <item label="Reconfigure">
-    <action name="Reconfigure" />
-  </item>
-  <separator />
-  <item label="Exit">
-    <action name="Exit" />
-  </item>
-</menu>
-
-</openbox_menu>
diff --git a/data/rc.xml.in b/data/rc.xml.in
deleted file mode 100644 (file)
index 8ccf1cf..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- Do not edit this file, it will be overwritten on install.
-        Copy the file to $HOME/.config/openbox/ instead. -->
-
-<openbox_config xmlns="http://openbox.org/"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://openbox.org/
-                file://@xsddir@/rc.xsd">
-
-<resistance>
-  <strength>10</strength>
-  <screen_edge_strength>20</screen_edge_strength>
-  <edges_hit_layers_below>no</edges_hit_layers_below>
-</resistance>
-
-<focus>
-  <focusNew>yes</focusNew>
-  <focusLast>no</focusLast>
-  <followMouse>no</followMouse>
-  <focusDelay>0</focusDelay>
-  <raiseOnFocus>no</raiseOnFocus>
-</focus>
-
-<placement>
-  <policy>Smart</policy>
-  <!-- 'Smart' or 'UnderMouse' -->
-</placement>
-
-<theme>
-  <name>Clearlooks</name>
-  <titleLayout>NLIMC</titleLayout>
-  <titleNumber>yes</titleNumber>
-  <!--
-      avaible characters are NDSLIMC, each can occur at most once.
-      N: client menu
-      L: window label (AKA title).
-      I: iconify
-      M: maximize
-      C: close
-      S: shade
-      D: omnipresent (on all desktops).
-  -->
-  <keepBorder>yes</keepBorder>
-  <animateIconify>yes</animateIconify>
-  <font place="ActiveWindow">
-    <name>sans</name>
-    <size>7</size>
-    <!-- font size in points -->
-    <weight>bold</weight>
-    <!-- 'bold' or 'normal' -->
-    <slant>normal</slant>
-    <!-- 'italic' or 'normal' -->
-  </font>
-  <font place="InactiveWindow">
-    <name>sans</name>
-    <size>7</size>
-    <!-- font size in points -->
-    <weight>bold</weight>
-    <!-- 'bold' or 'normal' -->
-    <slant>normal</slant>
-    <!-- 'italic' or 'normal' -->
-  </font>
-  <font place="MenuHeader">
-    <name>sans</name>
-    <size>8</size>
-    <!-- font size in points -->
-    <weight>bold</weight>
-    <!-- 'bold' or 'normal' -->
-    <slant>normal</slant>
-    <!-- 'italic' or 'normal' -->
-  </font>
-  <font place="MenuItem">
-    <name>sans</name>
-    <size>9</size>
-    <!-- font size in points -->
-    <weight>bold</weight>
-    <!-- 'bold' or 'normal' -->
-    <slant>normal</slant>
-    <!-- 'italic' or 'normal' -->
-  </font>
-  <font place="OnScreenDisplay">
-    <name>sans</name>
-    <size>9</size>
-    <!-- font size in points -->
-    <weight>bold</weight>
-    <!-- 'bold' or 'normal' -->
-    <slant>normal</slant>
-    <!-- 'italic' or 'normal' -->
-  </font>
-</theme>
-
-<desktops>
-  <!-- this stuff is only used at startup, pagers allow you to change them
-       during a session -->
-  <number>4</number>
-  <firstdesk>1</firstdesk>
-  <names>
-    <name>desktop one</name>
-    <name>desktop two</name>
-    <name>desktop three</name>
-    <name>desktop four</name>
-  </names>
-</desktops>
-
-<resize>
-  <drawContents>yes</drawContents>
-  <popupShow>Nonpixel</popupShow>
-  <!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
-  <popupPosition>Center</popupPosition>
-  <!-- 'Center' or 'Top' -->
-</resize>
-
-<dock>
-  <position>TopLeft</position>
-  <!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
-  <floatingX>0</floatingX>
-  <floatingY>0</floatingY>
-  <noStrut>no</noStrut>
-  <stacking>Above</stacking>
-  <!-- 'Above', 'Normal', or 'Below' -->
-  <direction>Vertical</direction>
-  <!-- 'Vertical' or 'Horizontal' -->
-  <autoHide>no</autoHide>
-  <hideDelay>300</hideDelay>
-  <showDelay>300</showDelay>
-  <moveButton>Middle</moveButton>
-</dock>
-
-<keyboard>
-  <chainQuitKey>C-g</chainQuitKey>
-
-  <keybind key="A-F10">
-    <action name="MaximizeFull"/>
-  </keybind>
-  <keybind key="A-F5">
-    <action name="UnmaximizeFull"/>
-  </keybind>
-  <keybind key="A-F12">
-    <action name="ToggleShade"/>
-  </keybind>
-  <keybind key="C-A-Left">
-    <action name="DesktopLeft"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="C-A-Right">
-    <action name="DesktopRight"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="C-A-Up">
-    <action name="DesktopUp"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="C-A-Down">
-    <action name="DesktopDown"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="S-A-Left">
-    <action name="SendToDesktopLeft"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="S-A-Right">
-    <action name="SendToDesktopRight"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="S-A-Up">
-    <action name="SendToDesktopUp"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="S-A-Down">
-    <action name="SendToDesktopDown"><wrap>no</wrap></action>
-  </keybind>
-  <keybind key="C-A-d">
-    <action name="ToggleShowDesktop"/>
-  </keybind>
-  <keybind key="A-F4">
-    <action name="Close"/>
-  </keybind>
-  <keybind key="A-Tab">
-    <action name="NextWindow"/>
-  </keybind>
-  <keybind key="A-S-Tab">
-    <action name="PreviousWindow"/>
-  </keybind>
-  <keybind key="C-A-Tab">
-    <action name="NextWindow"><panels>yes</panels></action>
-  </keybind>
-  <keybind key="C-A-S-Tab">
-    <action name="PreviousWindow"><panels>yes</panels></action>
-  </keybind>
-  <keybind key="A-F7">
-    <action name="Move"/>
-  </keybind>
-  <keybind key="A-F8">
-    <action name="Resize"/>
-  </keybind>
-  <keybind key="A-F9">
-    <action name="Iconify"/>
-  </keybind>
-  <keybind key="A-space">
-    <action name="ShowMenu"><menu>client-menu</menu></action>
-  </keybind>
-</keyboard>
-
-<mouse>
-  <dragThreshold>3</dragThreshold>
-  <doubleClickTime>200</doubleClickTime>
-
-  <context name="Frame">
-    <mousebind button="A-Left" action="Drag">
-      <action name="Move"/>
-    </mousebind>
-    <mousebind button="A-Left" action="Click">
-      <action name="Raise"/>
-    </mousebind>
-    <mousebind button="A-Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="A-Middle" action="Drag">
-      <action name="Resize"/>
-    </mousebind> 
-    <mousebind button="A-Middle" action="Click">
-      <action name="Lower"/>
-    </mousebind>
-    <mousebind button="A-Right" action="Press">
-      <action name="ShowMenu"><menu>client-menu</menu></action>
-    </mousebind>
-    <mousebind button="A-Up" action="Click">
-      <action name="DesktopPrevious"/>
-    </mousebind>
-    <mousebind button="A-Down" action="Click">
-      <action name="DesktopNext"/>
-    </mousebind>
-    <mousebind button="C-A-Up" action="Click">
-      <action name="SendToDesktopPrevious"/>
-    </mousebind>
-    <mousebind button="C-A-Down" action="Click">
-      <action name="SendToDesktopNext"/>
-    </mousebind>
-  </context>
-  <context name="Titlebar">
-    <mousebind button="Left" action="Drag">
-      <action name="Move"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="Raise"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="DoubleClick">
-      <action name="ToggleShade"/>
-    </mousebind>
-    <mousebind button="Middle" action="Press">
-      <action name="Lower"/>
-    </mousebind>
-    <mousebind button="Up" action="Click">
-      <action name="Shade"/>
-    </mousebind>
-    <mousebind button="Down" action="Click">
-      <action name="Unshade"/>
-    </mousebind>
-    <mousebind button="Right" action="Press">
-      <action name="ShowMenu"><menu>client-menu</menu></action>
-    </mousebind>
-  </context>
-  <context name="Handle">
-    <mousebind button="Left" action="Drag">
-      <action name="Move"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="Raise"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Middle" action="Press">
-      <action name="Lower"/>
-    </mousebind>
-  </context>
-  <context name="BLCorner">
-    <mousebind button="Left" action="Drag">
-      <action name="Resize"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-  </context>
-  <context name="BRCorner">
-    <mousebind button="Left" action="Drag">
-      <action name="Resize"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-  </context>
-  <context name="TLCorner">
-    <mousebind button="Left" action="Drag">
-      <action name="Resize"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-  </context>
-  <context name="TRCorner">
-    <mousebind button="Left" action="Drag">
-      <action name="Resize"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-  </context>
-  <context name="Client">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-      <action name="Raise"/>
-    </mousebind>
-    <mousebind button="Middle" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Right" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-  </context>
-  <context name="Icon">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Right" action="Press">
-      <action name="ShowMenu"><menu>client-menu</menu></action>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="ShowMenu"><menu>client-menu</menu></action>
-    </mousebind>
-  </context>
-  <context name="AllDesktops">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="ToggleOmnipresent"/>
-    </mousebind>
-  </context>
-  <context name="Shade">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="ToggleShade"/>
-    </mousebind>
-  </context>
-  <context name="Iconify">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="Iconify"/>
-    </mousebind>
-  </context>
-  <context name="Maximize">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Middle" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Right" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="ToggleMaximizeFull"/>
-    </mousebind>
-    <mousebind button="Middle" action="Click">
-      <action name="ToggleMaximizeVert"/>
-    </mousebind>
-    <mousebind button="Right" action="Click">
-      <action name="ToggleMaximizeHorz"/>
-    </mousebind>
-  </context>
-  <context name="Close">
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-    </mousebind>
-    <mousebind button="Left" action="Click">
-      <action name="Close"/>
-    </mousebind>
-  </context>
-  <context name="Desktop">
-    <mousebind button="Up" action="Press">
-      <action name="DesktopPrevious"/>
-    </mousebind>
-    <mousebind button="Down" action="Press">
-      <action name="DesktopNext"/>
-    </mousebind>
-    <mousebind button="A-Up" action="Press">
-      <action name="DesktopPrevious"/>
-    </mousebind>
-    <mousebind button="A-Down" action="Press">
-      <action name="DesktopNext"/>
-    </mousebind>
-    <mousebind button="Left" action="Press">
-      <action name="Focus"/>
-      <action name="Raise"/>
-    </mousebind> 
-    <mousebind button="Middle" action="Press">
-      <action name="ShowMenu"><menu>client-list-menu</menu></action>
-    </mousebind> 
-    <mousebind button="Right" action="Press">
-      <action name="ShowMenu"><menu>root-menu</menu></action>
-    </mousebind>
-  </context>
-  <context name="MoveResize">
-    <mousebind button="Up" action="Press">
-      <action name="DesktopPrevious"/>
-    </mousebind>
-    <mousebind button="Down" action="Press">
-      <action name="DesktopNext"/>
-    </mousebind>
-    <mousebind button="A-Up" action="Press">
-      <action name="DesktopPrevious"/>
-    </mousebind>
-    <mousebind button="A-Down" action="Press">
-      <action name="DesktopNext"/>
-    </mousebind>
-  </context>
-</mouse>
-
-<menu>
-  <!-- You can specify more than one menu file in here and they are all loaded,
-       just don't make menu ids clash or, well, it'll be kind of pointless -->
-
-  <!-- default menu file (or custom one in $HOME/.config/openbox/) -->
-  <file>menu.xml</file>
-  <hideDelay>250</hideDelay>
-  <middle>no</middle>
-  <submenuShowDelay>0</submenuShowDelay>
-  <applicationIcons>yes</applicationIcons>
-</menu>
-
-<!-- this section is commented out.. remove this and the ending comment if you
-     want to use it -->
-<applications>
-  <!-- the name or the class can be set, or both. this is used to match
-       windows when they appear
-
-       role can optionally be set, and only as much as you provide will be 
-       checked to see if it matches, eg. if you set role="abc" and the window's
-       role is actually "abcde" it would match.
- -->
-  <application name="first element of window's WM_CLASS property (see xprop)"
-              class="second element of window's WM_CLASS property (see xprop)"
-               role="the window's WM_WINDOW_ROLE property (see xprop)">
-
-    <!-- each element can be left out or set to 'default' to specify to not 
-         change that attribute of the window -->
-
-    <decor>yes</decor>
-
-    <shade>no</shade>
-
-    <position>
-      <!-- the position is only used if both an x and y coordinate are provided
-           (and not set to 'default') -->
-      <x>center</x>
-      <!-- a number or 'center' to center on screen -->
-      <y>200</y>
-      <!-- a number or 'center' to center on screen -->
-      <monitor>1</monitor>
-      <!-- specifies the monitor in a xinerama setup.
-           1 is the first head, or 'mouse' for wherever the mouse is -->
-    </position>
-
-    <focus>yes</focus>
-    <!-- if the window should try be given focus when it appears -->
-
-    <desktop>1</desktop>
-    <!-- 1 is the first desktop, 'all' for all desktops -->
-
-    <layer>normal</layer>
-    <!-- 'above', 'normal', or 'below' -->
-
-    <iconic>no</iconic>
-
-    <skip_pager>no</skip_pager>
-    <!-- asks to not be shown in pagers -->
-
-    <skip_taskbar>no</skip_taskbar>
-    <!-- asks to not be shown in taskbars. window cycling actions will also
-         skip past such windows -->
-
-    <fullscreen>yes</fullscreen>
-
-    <maximized>true</maximized>
-    <!-- 'Horizontal', 'Vertical' or boolean (yes/no/on/off/true/false) -->
-  </application>
-</applications>
- -->
-
-</openbox_config>
diff --git a/data/xsession/openbox-gnome b/data/xsession/openbox-gnome
deleted file mode 100755 (executable)
index c146aa8..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-# A temporary script to be replaced by a real program..
-exec openbox --restart-binary openbox-gnome "$@"
diff --git a/data/xsession/openbox-gnome-session b/data/xsession/openbox-gnome-session
deleted file mode 100755 (executable)
index d2b7701..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-# Run GNOME with Openbox as its window manager
-export WINDOW_MANAGER=openbox-gnome
-exec gnome-session "$@"
diff --git a/data/xsession/openbox-kde b/data/xsession/openbox-kde
deleted file mode 100755 (executable)
index 87a5812..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-# A temporary script to be replaced by a real program..
-exec openbox --restart-binary openbox-kde "$@"
diff --git a/data/xsession/openbox-kde-session b/data/xsession/openbox-kde-session
deleted file mode 100755 (executable)
index 589a2c5..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-# Run KDE with Openbox as its window manager
-export KDEWM=openbox-kde
-exec startkde "$@"
index 0c4cce1..4c88daf 100644 (file)
@@ -451,7 +451,7 @@ void client_manage(Window window)
            raised to the top. Legacy begets legacy I guess?
         */
         if (!client_restore_session_stacking(self))
-            client_raise(self);
+            stacking_raise(CLIENT_AS_WINDOW(self));
     }
 
     /* this has to happen before we try focus the window, but we want it to
@@ -2344,13 +2344,25 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
     for (it = self->transients; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig,
                                     self->layer,
-                                    raised ? raised : self->layer != old);
+                                    raised ? raised : self->layer > old);
 
-    if (!raised && self->layer != old)
-        if (orig->frame) { /* only restack if the original window is managed */
+    /* restack. but only if the original window is managed.
+
+       raised is used so that only the bottom-most window in the stacking
+       order is raised, the others will automatically come with it.
+
+       also only the highest windows in the stacking order (no transients)
+       are lowered, cuz the rest come for free
+    */
+    if (!raised && orig->frame) {
+        if (self->layer > old) {
+            stacking_remove(CLIENT_AS_WINDOW(self));
+            stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
+        } else if (self->layer < old && self->transients == NULL) {
             stacking_remove(CLIENT_AS_WINDOW(self));
-            stacking_add(CLIENT_AS_WINDOW(self));
+            stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
         }
+    }
 }
 
 void client_calc_layer(ObClient *self)
@@ -3077,7 +3089,7 @@ void client_set_desktop_recursive(ObClient *self,
             client_showhide(self);
         /* raise if it was not already on the desktop */
         if (old != DESKTOP_ALL)
-            client_raise(self);
+            stacking_raise(CLIENT_AS_WINDOW(self));
         if (STRUT_EXISTS(self->strut))
             screen_update_areas();
     }
@@ -3302,7 +3314,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
         self->modal = modal;
         /* when a window changes modality, then its stacking order with its
            transients needs to change */
-        client_raise(self);
+        stacking_raise(CLIENT_AS_WINDOW(self));
     }
     if (iconic != self->iconic)
         client_iconify(self, iconic, FALSE);
@@ -3444,17 +3456,10 @@ static void client_present(ObClient *self, gboolean here, gboolean raise)
         return;
     if (self->shaded)
         client_shade(self, FALSE);
+    if (raise)
+        stacking_raise(CLIENT_AS_WINDOW(self));
 
     client_focus(self);
-
-    if (raise) {
-        /* we do this as an action here. this is rather important. this is
-           because we want the results from the focus change to take place 
-           BEFORE we go about raising the window. when a fullscreen window 
-           loses focus, we need this or else the raise wont be able to raise 
-           above the to-lose-focus fullscreen window. */
-        client_raise(self);
-    }
 }
 
 void client_activate(ObClient *self, gboolean here, gboolean user)
@@ -3510,16 +3515,6 @@ void client_bring_helper_windows(ObClient *self)
     client_bring_helper_windows_recursive(self, self->desktop);
 }
 
-void client_raise(ObClient *self)
-{
-    action_run_string("Raise", self, CurrentTime);
-}
-
-void client_lower(ObClient *self)
-{
-    action_run_string("Lower", self, CurrentTime);
-}
-
 gboolean client_focused(ObClient *self)
 {
     return self == focus_client;
index 30d4051..5a83739 100644 (file)
@@ -550,26 +550,6 @@ void client_bring_helper_windows(ObClient *self);
 /*! Calculates the stacking layer for the client window */
 void client_calc_layer(ObClient *self);
 
-/*! Raises the client to the top of its stacking layer
-  Normally actions call to the client_* functions to make stuff go, but this
-  one is an exception. It just fires off an action, which will be queued.
-  This is because stacking order rules can be changed by focus state, and so
-  any time focus changes you have to wait for it to complete before you can
-  properly restart windows. As such, this only queues an action for later
-  execution, once the focus change has gone through.
-*/
-void client_raise(ObClient *self);
-
-/*! Lowers the client to the bottom of its stacking layer
-  Normally actions call to the client_* functions to make stuff go, but this
-  one is an exception. It just fires off an action, which will be queued.
-  This is because stacking order rules can be changed by focus state, and so
-  any time focus changes you have to wait for it to complete before you can
-  properly restart windows. As such, this only queues an action for later
-  execution, once the focus change has gone through.
-*/
-void client_lower(ObClient *self);
-
 /*! Updates the window's transient status, and any parents of it */
 void client_update_transient_for(ObClient *self);
 /*! Update the protocols that the window supports and adjusts things if they
index 566739c..6bf6e87 100644 (file)
@@ -1019,22 +1019,20 @@ static void event_handle_client(ObClient *client, XEvent *e)
         }
 
         if (e->xconfigurerequest.value_mask & CWStackMode) {
-            switch (e->xconfigurerequest.detail) {
-            case Below:
-            case BottomIf:
-                /* Apps are so rude. And this is totally disconnected from
-                   activation/focus. Bleh. */
-                /*client_lower(client);*/
-                break;
-
-            case Above:
-            case TopIf:
-            default:
-                /* Apps are so rude. And this is totally disconnected from
-                   activation/focus. Bleh. */
-                /*client_raise(client);*/
-                break;
+            ObClient *sibling = NULL;
+
+            /* get the sibling */
+            if (e->xconfigurerequest.value_mask & CWSibling) {
+                ObWindow *win;
+                win = g_hash_table_lookup(window_map,
+                                          &e->xconfigurerequest.above);
+                if (WINDOW_IS_CLIENT(win) && WINDOW_AS_CLIENT(win) != client)
+                    sibling = WINDOW_AS_CLIENT(win);
             }
+
+            /* activate it rather than just focus it */
+            stacking_restack_request(client, sibling,
+                                     e->xconfigurerequest.detail, TRUE);
         }
         break;
     case UnmapNotify:
@@ -1211,6 +1209,43 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_convert_gravity(client, grav, &x, &y, w, h);
             client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure(client, x, y, w, h, FALSE, TRUE);
+        } else if (msgtype == prop_atoms.net_restack_window) {
+            if (e->xclient.data.l[0] != 2) {
+                ob_debug_type(OB_DEBUG_APP_BUGS,
+                              "_NET_RESTACK_WINDOW sent for window %s with "
+                              "invalid source indication %ld\n",
+                              client->title, e->xclient.data.l[0]);
+            } else {
+                ObClient *sibling = NULL;
+                if (e->xclient.data.l[1]) {
+                    ObWindow *win = g_hash_table_lookup(window_map,
+                                                        &e->xclient.data.l[1]);
+                    if (WINDOW_IS_CLIENT(win) &&
+                        WINDOW_AS_CLIENT(win) != client)
+                    {
+                        sibling = WINDOW_AS_CLIENT(win);
+                    }
+                    if (sibling == NULL)
+                        ob_debug_type(OB_DEBUG_APP_BUGS,
+                                      "_NET_RESTACK_WINDOW sent for window %s "
+                                      "with invalid sibling 0x%x\n",
+                                 client->title, e->xclient.data.l[1]);
+                }
+                if (e->xclient.data.l[2] == Below ||
+                    e->xclient.data.l[2] == BottomIf ||
+                    e->xclient.data.l[2] == Above ||
+                    e->xclient.data.l[2] == TopIf ||
+                    e->xclient.data.l[2] == Opposite)
+                {
+                    /* just raise, don't activate */
+                    stacking_restack_request(client, sibling,
+                                             e->xclient.data.l[2], FALSE);
+                } else
+                    ob_debug_type(OB_DEBUG_APP_BUGS,
+                                  "_NET_RESTACK_WINDOW sent for window %s "
+                                  "with invalid detail %d\n",
+                                  client->title, e->xclient.data.l[2]);
+            }
         }
         break;
     case PropertyNotify:
@@ -1601,7 +1636,7 @@ static gboolean focus_delay_func(gpointer data)
     event_curtime = d->time;
     if (focus_client != d->client) {
         if (client_focus(d->client) && config_focus_raise)
-            client_raise(d->client);
+            stacking_raise(CLIENT_AS_WINDOW(d->client));
     }
     event_curtime = old;
     return FALSE; /* no repeat */
index 9edda8e..9ca7987 100644 (file)
@@ -193,8 +193,8 @@ void mouse_event(ObClient *client, XEvent *e)
 
         px = e->xbutton.x_root;
         py = e->xbutton.y_root;
-        if (pwx == -1) pwx = e->xbutton.x;
-        if (pwy == -1) pwy = e->xbutton.y;
+        if (!button) pwx = e->xbutton.x;
+        if (!button) pwy = e->xbutton.y;
         button = e->xbutton.button;
         state = e->xbutton.state;
 
@@ -216,7 +216,8 @@ void mouse_event(ObClient *client, XEvent *e)
         context = frame_context(client, e->xbutton.window, pwx, pwy);
         context = mouse_button_frame_context(context, e->xbutton.button);
 
-        pwx = pwy = -1;
+        if (e->xbutton.button == button)
+            pwx = pwy = -1;
 
         if (e->xbutton.button == button) {
             /* clicks are only valid if its released over the window */
@@ -258,7 +259,8 @@ void mouse_event(ObClient *client, XEvent *e)
         fire_binding(OB_MOUSE_ACTION_RELEASE, context,
                      client, e->xbutton.state,
                      e->xbutton.button,
-                     e->xbutton.x_root, e->xbutton.y_root,
+                     e->xbutton.x_root,
+                     e->xbutton.y_root,
                      e->xbutton.time);
         if (click)
             fire_binding(OB_MOUSE_ACTION_CLICK, context,
@@ -281,10 +283,8 @@ void mouse_event(ObClient *client, XEvent *e)
             context = frame_context(client, e->xmotion.window, pwx, pwy);
             context = mouse_button_frame_context(context, button);
 
-            if (ABS(e->xmotion.x_root - px) >=
-                config_mouse_threshold ||
-                ABS(e->xmotion.y_root - py) >=
-                config_mouse_threshold) {
+            if (ABS(e->xmotion.x_root - px) >= config_mouse_threshold ||
+                ABS(e->xmotion.y_root - py) >= config_mouse_threshold) {
 
                 /* You can't drag on buttons */
                 if (context == OB_FRAME_CONTEXT_MAXIMIZE ||
index d3c8054..18d9884 100644 (file)
@@ -477,7 +477,7 @@ static void remove_args(gint *argc, gchar **argv, gint index, gint num)
 {
     gint i;
 
-    for (i = index; i < index + num; ++i)
+    for (i = index; i < *argc - num; ++i)
         argv[i] = argv[i+num];
     for (; i < *argc; ++i)
         argv[i] = NULL;
@@ -492,31 +492,41 @@ static void parse_args(gint *argc, gchar **argv)
         if (!strcmp(argv[i], "--version")) {
             print_version();
             exit(0);
-        } else if (!strcmp(argv[i], "--help")) {
+        }
+        else if (!strcmp(argv[i], "--help")) {
             print_help();
             exit(0);
-        } else if (!strcmp(argv[i], "--g-fatal-warnings")) {
+        }
+        else if (!strcmp(argv[i], "--g-fatal-warnings")) {
             g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL);
-        } else if (!strcmp(argv[i], "--replace")) {
+        }
+        else if (!strcmp(argv[i], "--replace")) {
             ob_replace_wm = TRUE;
-        } else if (!strcmp(argv[i], "--sync")) {
+            remove_args(argc, argv, i, 1);
+            --i; /* this arg was removed so go back */
+        }
+        else if (!strcmp(argv[i], "--sync")) {
             xsync = TRUE;
-        } else if (!strcmp(argv[i], "--debug")) {
+        }
+        else if (!strcmp(argv[i], "--debug")) {
             ob_debug_show_output(TRUE);
             ob_debug_enable(OB_DEBUG_SM, TRUE);
             ob_debug_enable(OB_DEBUG_APP_BUGS, TRUE);
-        } else if (!strcmp(argv[i], "--debug-focus")) {
+        }
+        else if (!strcmp(argv[i], "--debug-focus")) {
             ob_debug_show_output(TRUE);
             ob_debug_enable(OB_DEBUG_SM, TRUE);
             ob_debug_enable(OB_DEBUG_APP_BUGS, TRUE);
             ob_debug_enable(OB_DEBUG_FOCUS, TRUE);
-        } else if (!strcmp(argv[i], "--reconfigure")) {
+        }
+        else if (!strcmp(argv[i], "--reconfigure")) {
             remote_control = 1;
 /* don't make this do anything if it's not in --help ..
         } else if (!strcmp(argv[i], "--restart")) {
             remote_control = 2;
 */
-        } else if (!strcmp(argv[i], "--config")) {
+        }
+        else if (!strcmp(argv[i], "--config")) {
             if (i == *argc - 1) /* no args left */
                 g_printerr(_("--config requires an argument\n"));
             else {
@@ -533,8 +543,11 @@ static void parse_args(gint *argc, gchar **argv)
                 ob_sm_save_file = g_strdup(argv[i+1]);
                 remove_args(argc, argv, i, 2);
                 --i; /* this arg was removed so go back */
+                ob_debug_type(OB_DEBUG_SM, "--sm-save-file %s\n",
+                              ob_sm_save_file);
             }
-        } else if (!strcmp(argv[i], "--sm-client-id")) {
+        }
+        else if (!strcmp(argv[i], "--sm-client-id")) {
             if (i == *argc - 1) /* no args left */
                 /* not translated cuz it's sekret */
                 g_printerr("--sm-client-id requires an argument\n");
@@ -542,21 +555,14 @@ static void parse_args(gint *argc, gchar **argv)
                 ob_sm_id = g_strdup(argv[i+1]);
                 remove_args(argc, argv, i, 2);
                 --i; /* this arg was removed so go back */
+                ob_debug_type(OB_DEBUG_SM, "--sm-client-id %s\n", ob_sm_id);
             }
-        } else if (!strcmp(argv[i], "--sm-disable")) {
+        }
+        else if (!strcmp(argv[i], "--sm-disable")) {
             ob_sm_use = FALSE;
         }
 #endif
-        else if (!strcmp(argv[i], "--restart-binary")) {
-            if (i == *argc - 1) /* no args left */
-                /* not translated cuz it's sekret */
-                g_printerr("--restart-binary requires an argument\n");
-            else {
-                argv[0] = g_strdup(argv[i+1]);
-                remove_args(argc, argv, i, 2);
-                --i; /* this arg was removed so go back */
-            }
-        } else {
+        else {
             /* this is a memleak.. oh well.. heh */
             gchar *err = g_strdup_printf
                 ("Invalid command line argument '%s'\n", argv[i]);
index 3861f7c..e055906 100644 (file)
@@ -75,6 +75,8 @@ void prop_startup()
     CREATE(net_close_window, "_NET_CLOSE_WINDOW");
     CREATE(net_wm_moveresize, "_NET_WM_MOVERESIZE");
     CREATE(net_moveresize_window, "_NET_MOVERESIZE_WINDOW");
+    CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
+    CREATE(net_restack_window, "_NET_RESTACK_WINDOW");
 
     CREATE(net_startup_id, "_NET_STARTUP_ID");
 
@@ -95,7 +97,6 @@ void prop_startup()
     CREATE(net_wm_user_time_window, "_NET_WM_USER_TIME_WINDOW");
     CREATE(kde_net_wm_frame_strut, "_KDE_NET_WM_FRAME_STRUT");
     CREATE(net_frame_extents, "_NET_FRAME_EXTENTS");
-    CREATE(net_request_frame_extents, "_NET_REQUEST_FRAME_EXTENTS");
 
 /*   CREATE(net_wm_ping, "_NET_WM_PING"); */
 #ifdef SYNC
index 4f45b6d..d1d6a51 100644 (file)
@@ -108,6 +108,8 @@ typedef struct Atoms {
     Atom net_close_window;
     Atom net_wm_moveresize;
     Atom net_moveresize_window;
+    Atom net_request_frame_extents;
+    Atom net_restack_window;
 
     /* helpful hints to apps that aren't used for anything */
     Atom net_wm_full_placement;
@@ -132,7 +134,6 @@ typedef struct Atoms {
     Atom net_wm_user_time;
     Atom net_wm_user_time_window;
     Atom net_frame_extents;
-    Atom net_request_frame_extents;
 
     /* application protocols */
 /*  Atom net_wm_ping; */
index 077c466..729f83f 100644 (file)
@@ -36,6 +36,8 @@ void resist_move_windows(ObClient *c, gint resist, gint *x, gint *y)
 
     if (!resist) return;
 
+    frame_client_gravity(c->frame, x, y, c->area.width, c->area.height);
+
     w = c->frame->area.width;
     h = c->frame->area.height;
 
@@ -112,6 +114,8 @@ void resist_move_windows(ObClient *c, gint resist, gint *x, gint *y)
 
         if (snapx && snapy) break;
     }
+
+    frame_frame_gravity(c->frame, x, y, c->area.width, c->area.height);
 }
 
 void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
@@ -126,6 +130,8 @@ void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
 
     if (!resist) return;
 
+    frame_client_gravity(c->frame, x, y, c->area.width, c->area.height);
+
     w = c->frame->area.width;
     h = c->frame->area.height;
 
@@ -173,6 +179,8 @@ void resist_move_monitors(ObClient *c, gint resist, gint *x, gint *y)
         else if (cb <= pb && b > pb && b < pb + resist)
             *y = pb - h + 1;
     }
+
+    frame_frame_gravity(c->frame, x, y, c->area.width, c->area.height);
 }
 
 void resist_size_windows(ObClient *c, gint resist, gint *w, gint *h,
index 7c3ed3c..d61e7f2 100644 (file)
@@ -23,7 +23,13 @@ struct _ObClient;
 
 #include <glib.h>
 
+/*! @x The client's x destination (in the client's coordinates, not the frame's
+    @y The client's y destination (in the client's coordinates, not the frame's
+*/
 void resist_move_windows(struct _ObClient *c, gint resist, gint *x, gint *y);
+/*! @x The client's x destination (in the client's coordinates, not the frame's
+    @y The client's y destination (in the client's coordinates, not the frame's
+*/
 void resist_move_monitors(struct _ObClient *c, gint resist, gint *x, gint *y);
 void resist_size_windows(struct _ObClient *c, gint resist, gint *w, gint *h,
                          ObCorner corn);
index 190468a..51f226a 100644 (file)
@@ -276,6 +276,7 @@ gboolean screen_annex(const gchar *program_name)
     supported[i++] = prop_atoms.net_wm_user_time_window;
     supported[i++] = prop_atoms.net_frame_extents;
     supported[i++] = prop_atoms.net_request_frame_extents;
+    supported[i++] = prop_atoms.net_restack_window;
     supported[i++] = prop_atoms.net_startup_id;
 #ifdef SYNC
     supported[i++] = prop_atoms.net_wm_sync_request;
index 2c189ed..b07f169 100644 (file)
@@ -136,7 +136,8 @@ void session_shutdown(gboolean permanent)
     if (sm_conn) {
         /* if permanent is true then we will change our session state so that
            the SM won't run us again */
-        session_setup_restart_style(!permanent);
+        if (permanent)
+            session_setup_restart_style(FALSE);
 
         SmcCloseConnection(sm_conn, 0, NULL);
 
@@ -177,6 +178,7 @@ static gboolean session_connect()
                                 &cb, oldid, &ob_sm_id,
                                 SM_ERR_LEN-1, sm_err);
     g_free(oldid);
+    ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s\n", ob_sm_id);
     if (sm_conn == NULL)
         ob_debug("Failed to connect to session manager: %s\n", sm_err);
     return sm_conn != NULL;
@@ -195,6 +197,7 @@ static void session_setup_program()
         .vals = &vals
     };
     SmProp *list = &prop;
+    ob_debug_type(OB_DEBUG_SM, "Setting program: %s\n", sm_argv[0]);
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -215,6 +218,7 @@ static void session_setup_user()
         .vals = &vals
     };
     SmProp *list = &prop;
+    ob_debug_type(OB_DEBUG_SM, "Setting user: %s\n", user);
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -223,7 +227,7 @@ static void session_setup_user()
 
 static void session_setup_restart_style(gboolean restart)
 {
-    char restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
+    gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
 
     SmPropValue vals = {
         .value = &restart_hint,
@@ -236,6 +240,7 @@ static void session_setup_restart_style(gboolean restart)
         .vals = &vals
     };
     SmProp *list = &prop;
+    ob_debug_type(OB_DEBUG_SM, "Setting restart: %d\n", restart);
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -256,6 +261,7 @@ static void session_setup_pid()
         .vals = &vals
     };
     SmProp *list = &prop;
+    ob_debug_type(OB_DEBUG_SM, "Setting pid: %s\n", pid);
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -278,6 +284,7 @@ static void session_setup_priority()
         .vals = &vals
     };
     SmProp *list = &prop;
+    ob_debug_type(OB_DEBUG_SM, "Setting priority: %d\n", priority);
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -294,13 +301,15 @@ static void session_setup_clone_command()
         .num_vals = sm_argc,
         .vals = vals
     };
+    SmProp *list = &prop;
 
+    ob_debug_type(OB_DEBUG_SM, "Setting clone command: (%d)\n", sm_argc);
     for (i = 0; i < sm_argc; ++i) {
         vals[i].value = sm_argv[i];
         vals[i].length = strlen(sm_argv[i]) + 1;
+        ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i].value);
     }
 
-    SmProp *list = &prop;
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
@@ -318,23 +327,29 @@ static void session_setup_restart_command()
         .num_vals = sm_argc + 4,
         .vals = vals
     };
+    SmProp *list = &prop;
 
+    ob_debug_type(OB_DEBUG_SM, "Setting restart command: (%d)\n", sm_argc+4);
     for (i = 0; i < sm_argc; ++i) {
         vals[i].value = sm_argv[i];
         vals[i].length = strlen(sm_argv[i]) + 1;
+        ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i].value);
     }
 
-    vals[i].value = g_strdup("--sm-save-file");
-    vals[i].length = strlen("--sm-save-file") + 1;
-    vals[i+1].value = ob_sm_save_file;
-    vals[i+1].length = strlen(ob_sm_save_file) + 1;
+    vals[i].value = g_strdup("--sm-client-id");
+    vals[i].length = strlen("--sm-client-id") + 1;
+    vals[i+1].value = ob_sm_id;
+    vals[i+1].length = strlen(ob_sm_id) + 1;
+    ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i].value);
+    ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i+1].value);
 
-    vals[i+2].value = g_strdup("--sm-client-id");
-    vals[i+2].length = strlen("--sm-client-id") + 1;
-    vals[i+3].value = ob_sm_id;
-    vals[i+3].length = strlen(ob_sm_id) + 1;
+    vals[i+2].value = g_strdup("--sm-save-file");
+    vals[i+2].length = strlen("--sm-save-file") + 1;
+    vals[i+3].value = ob_sm_save_file;
+    vals[i+3].length = strlen(ob_sm_save_file) + 1;
+    ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i+2].value);
+    ob_debug_type(OB_DEBUG_SM, "    %s\n", vals[i+3].value);
 
-    SmProp *list = &prop;
     SmcSetProperties(sm_conn, 1, &list);
     g_free(prop.name);
     g_free(prop.type);
index 18747b9..564b995 100644 (file)
@@ -25,6 +25,7 @@
 #include "group.h"
 #include "frame.h"
 #include "window.h"
+#include "debug.h"
 
 GList  *stacking_list = NULL;
 
@@ -416,7 +417,7 @@ void stacking_add_nonintrusive(ObWindow *win)
     /* insert above its highest parent (or its highest child !) */
     it_below = find_highest_relative(client);
 
-    if (!it_below) {
+    if (!it_below && client != focus_client) {
         /* nothing to put it directly above, so try find the focused client to
            put it underneath it */
         if (focus_client && focus_client->layer == client->layer) {
@@ -425,10 +426,16 @@ void stacking_add_nonintrusive(ObWindow *win)
         }
     }
     if (!it_below) {
-        /* there is no window to put this directly above, so put it at the
-           bottom */
-        stacking_list = g_list_prepend(stacking_list, win);
-        stacking_lower(win);
+        if (client == focus_client) {
+            /* it's focused so put it at the top */
+            stacking_list = g_list_append(stacking_list, win);
+            stacking_raise(win);
+        } else {
+            /* there is no window to put this directly above, so put it at the
+               bottom */
+            stacking_list = g_list_prepend(stacking_list, win);
+            stacking_lower(win);
+        }
     } else {
         /* make sure it's not in the wrong layer though ! */
         for (; it_below; it_below = g_list_next(it_below))
@@ -453,3 +460,141 @@ void stacking_add_nonintrusive(ObWindow *win)
         g_list_free(wins);
     }
 }
+
+/*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it
+  tries against all other clients.
+*/
+static gboolean stacking_occluded(ObClient *client, ObClient *sibling)
+{
+    GList *it;
+    gboolean occluded = FALSE;
+    gboolean found = FALSE;
+
+    /* no need for any looping in this case */
+    if (sibling && client->layer != sibling->layer)
+        return occluded;
+
+    for (it = stacking_list; it;
+         it = (found ? g_list_previous(it) :g_list_next(it)))
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *c = it->data;
+            if (found) {
+                if (RECT_INTERSECTS_RECT(c->frame->area, client->frame->area))
+                {
+                    if (sibling != NULL) {
+                        if (c == sibling) {
+                            occluded = TRUE;
+                            break;
+                        }
+                    }
+                    else if (c->layer == client->layer) {
+                        occluded = TRUE;
+                        break;
+                    }
+                    else if (c->layer > client->layer)
+                        break; /* we past its layer */
+                }
+            }
+            else if (c == client)
+                found = TRUE;
+        }
+    return occluded;
+}
+
+/*! Returns TRUE if client is occludes the sibling. If sibling is NULL it tries
+  against all other clients.
+*/
+static gboolean stacking_occludes(ObClient *client, ObClient *sibling)
+{
+    GList *it;
+    gboolean occludes = FALSE;
+    gboolean found = FALSE;
+
+    /* no need for any looping in this case */
+    if (sibling && client->layer != sibling->layer)
+        return occludes;
+
+    for (it = stacking_list; it; it = g_list_next(it))
+        if (WINDOW_IS_CLIENT(it->data)) {
+            ObClient *c = it->data;
+            if (found) {
+                if (RECT_INTERSECTS_RECT(c->frame->area, client->frame->area))
+                {
+                    if (sibling != NULL) {
+                        if (c == sibling) {
+                            occludes = TRUE;
+                            break;
+                        }
+                    }
+                    else if (c->layer == client->layer) {
+                        occludes = TRUE;
+                        break;
+                    }
+                    else if (c->layer > client->layer)
+                        break; /* we past its layer */
+                }
+            }
+            else if (c == client)
+                found = TRUE;
+        }
+    return occludes;
+}
+
+void stacking_restack_request(ObClient *client, ObClient *sibling,
+                              gint detail, gboolean activate)
+{
+    switch (detail) {
+    case Below:
+        ob_debug("Restack request Below for client %s sibling %s\n",
+                 client->title, sibling ? sibling->title : "(all)");
+        /* just lower it */
+        stacking_lower(CLIENT_AS_WINDOW(client));
+        break;
+    case BottomIf:
+        ob_debug("Restack request BottomIf for client %s sibling "
+                 "%s\n",
+                 client->title, sibling ? sibling->title : "(all)");
+        /* if this client occludes sibling (or anything if NULL), then
+           lower it to the bottom */
+        if (stacking_occludes(client, sibling))
+            stacking_lower(CLIENT_AS_WINDOW(client));
+        break;
+    case Above:
+        ob_debug("Restack request Above for client %s sibling %s\n",
+                 client->title, sibling ? sibling->title : "(all)");
+        if (activate)
+            /* use user=TRUE because it is impossible to get a timestamp
+               for this */
+            client_activate(client, FALSE, TRUE);
+        else
+            stacking_raise(CLIENT_AS_WINDOW(client));
+        break;
+    case TopIf:
+        ob_debug("Restack request TopIf for client %s sibling %s\n",
+                 client->title, sibling ? sibling->title : "(all)");
+        if (stacking_occluded(client, sibling)) {
+            if (activate)
+                /* use user=TRUE because it is impossible to get a timestamp
+                   for this */
+                client_activate(client, FALSE, TRUE);
+            else
+                stacking_raise(CLIENT_AS_WINDOW(client));
+        }
+        break;
+    case Opposite:
+        ob_debug("Restack request Opposite for client %s sibling "
+                 "%s\n",
+                 client->title, sibling ? sibling->title : "(all)");
+        if (stacking_occluded(client, sibling)) {
+            if (activate)
+                /* use user=TRUE because it is impossible to get a timestamp
+                   for this */
+                client_activate(client, FALSE, TRUE);
+            else
+                stacking_raise(CLIENT_AS_WINDOW(client));
+        }
+        else if (stacking_occludes(client, sibling))
+            stacking_lower(CLIENT_AS_WINDOW(client));
+        break;
+    }
+}
index 2391f65..afa4a6c 100644 (file)
@@ -59,4 +59,18 @@ void stacking_lower(ObWindow *window);
 */
 void stacking_below(ObWindow *window, ObWindow *below);
 
+/*! Restack a window based upon a sibling (or all windows) in various ways.
+  @param client The client to be restacked
+  @param sibling Another client to compare to, or NULL to compare to all
+                 windows
+  @param detail One of Above, Below, TopIf, BottomIf, Opposite
+  @param activate If TRUE, and if the window is going to be raised, it will
+                  be activated instead
+  See http://tronche.com/gui/x/xlib/window/configure.html for details on
+  how each detail works with and without a sibling.
+*/
+void stacking_restack_request(struct _ObClient *client,
+                              struct _ObClient *sibling,
+                              gint detail, gboolean);
+
 #endif