merge r5928-5942 from trunk
authorDana Jansens <danakj@orodu.net>
Thu, 26 Apr 2007 05:09:18 +0000 (05:09 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 26 Apr 2007 05:09:18 +0000 (05:09 +0000)
15 files changed:
data/rc.xsd
openbox/action.c
openbox/action.h
openbox/client.c
openbox/client_menu.c
openbox/config.c
openbox/keyboard.c
openbox/keyboard.h
openbox/keytree.c
openbox/keytree.h
openbox/menu.c
openbox/menu.h
openbox/menuframe.c
openbox/menuframe.h
render/font.c

index 15c426c330e7ba180a3120f1aad0ae3c522de058..fdb98e7d50393a2ea23ba0cb869ccff1f1de98a5 100644 (file)
          Removed fourCorners option.
      Wed Apr 25 14:02:40 UTC 2007
          Fixed values for layer to be above/below, not top/bottom.
+         Add chroot attribute and keybind element to keybind element.
+         Remove xsd:sequence from everywhere, we don't care about order.
 -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     targetNamespace="http://openbox.org/"
     xmlns:ob="http://openbox.org/"
     elementFormDefault="qualified">
     <!--
          root node
       -->
-    <xs:element name="openbox_config">
-        <xs:annotation>
-            <xs:documentation>all these elements are expected in a openbox config file</xs:documentation>
-        </xs:annotation>
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element name="resistance" type="ob:resistance"/>
-                <xs:element name="focus" type="ob:focus"/>
-                <xs:element name="placement" type="ob:placement"/>
-                <xs:element name="theme" type="ob:theme"/>
-                <xs:element name="desktops" type="ob:desktops"/>
-                <xs:element name="resize" type="ob:resize"/>
-                <xs:element name="dock" type="ob:dock"/>
-                <xs:element name="keyboard" type="ob:keyboard"/>
-                <xs:element name="mouse" type="ob:mouse"/>
-                <xs:element name="menu" type="ob:menu"/>
-                <xs:element name="applications" type="ob:applications"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
+    <xsd:element name="openbox_config">
+        <xsd:annotation>
+            <xsd:documentation>all these elements are expected in a openbox config file</xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexType>
+            <xsd:element name="resistance" type="ob:resistance"/>
+            <xsd:element name="focus" type="ob:focus"/>
+            <xsd:element name="placement" type="ob:placement"/>
+            <xsd:element name="theme" type="ob:theme"/>
+            <xsd:element name="desktops" type="ob:desktops"/>
+            <xsd:element name="resize" type="ob:resize"/>
+            <xsd:element name="dock" type="ob:dock"/>
+            <xsd:element name="keyboard" type="ob:keyboard"/>
+            <xsd:element name="mouse" type="ob:mouse"/>
+            <xsd:element name="menu" type="ob:menu"/>
+            <xsd:element name="applications" type="ob:applications"/>
+        </xsd:complexType>
+    </xsd:element>
     <!--
          complex types
       -->
-    <xs:complexType name="resistance">
-        <xs:annotation>
-            <xs:documentation>defines behaviour of windows when close to each other or the screen edge</xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element minOccurs="0" name="strength" type="xs:integer"/>
-            <xs:element minOccurs="0" name="screen_edge_strength" type="xs:integer"/>
-            <xs:element minOccurs="0" name="edges_hit_layers_below" type="ob:bool"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="focus">
-        <xs:annotation>
-            <xs:documentation>defines aspects of window focus</xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element minOccurs="0" name="focusNew" type="ob:bool"/>
-            <xs:element minOccurs="0" name="focusLast" type="ob:bool"/>
-            <xs:element minOccurs="0" name="followMouse" type="ob:bool"/>
-            <xs:element minOccurs="0" name="focusDelay" type="xs:integer"/>
-            <xs:element minOccurs="0" name="raiseOnFocus" type="ob:bool"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="placement">
-        <xs:annotation>
-            <xs:documentation>defines how new windows are placed</xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="policy" type="ob:placementpolicy"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="theme">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="name" type="xs:string"/>
-            <xs:element minOccurs="0" name="titleLayout" type="xs:string"/>
-            <xs:element minOccurs="0" name="titleNumber" type="ob:bool"/>
-            <xs:element minOccurs="0" name="keepBorder" type="ob:bool"/>
-            <xs:element minOccurs="0" name="hideDisabled" type="ob:bool"/>
-            <xs:element minOccurs="0" name="font" type="ob:font"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="font">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="name" type="xs:string"/>
-            <xs:element minOccurs="0" name="size" type="xs:integer"/>
-            <xs:element minOccurs="0" name="weight" type="ob:fontweight"/>
-            <xs:element minOccurs="0" name="slant" type="ob:fontslant"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="desktops">
-        <xs:annotation>
-            <xs:documentation>defines the number and names of desktops</xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element minOccurs="0" name="number" type="xs:integer"/>
-            <xs:element minOccurs="0" name="firstdesk" type="xs:integer"/>
-            <xs:element minOccurs="0" name="names">
-                <xs:complexType>
-                    <xs:sequence>
-                        <xs:element maxOccurs="unbounded" name="name" type="xs:string"/>
-                    </xs:sequence>
-                </xs:complexType>
-            </xs:element>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="resize">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="drawContents" type="ob:bool"/>
-            <xs:element minOccurs="0" name="popupShow" type="ob:popupshow"/>
-            <xs:element minOccurs="0" name="popupPosition" type="ob:popupposition"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="dock">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="position" type="ob:dock_position"/>
-            <xs:element minOccurs="0" name="floatingX" type="xs:integer"/>
-            <xs:element minOccurs="0" name="floatingY" type="xs:integer"/>
-            <xs:element minOccurs="0" name="noStrut" type="ob:bool"/>
-            <xs:element minOccurs="0" name="stacking" type="ob:layer"/>
-            <xs:element minOccurs="0" name="direction" type="ob:direction"/>
-            <xs:element minOccurs="0" name="autoHide" type="ob:bool"/>
-            <xs:element minOccurs="0" name="hideDelay" type="xs:integer"/>
-            <xs:element minOccurs="0" name="showDelay" type="xs:integer"/>
-            <xs:element minOccurs="0" name="moveButton" type="ob:button"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="action">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="execute" type="xs:string"/>
-            <xs:element minOccurs="0" name="menu" type="xs:string"/>
-            <xs:element minOccurs="0" name="delta" type="xs:integer"/>
-            <xs:element minOccurs="0" name="x" type="xs:integer"/>
-            <xs:element minOccurs="0" name="y" type="xs:integer"/>
-            <xs:element minOccurs="0" name="left" type="xs:integer"/>
-            <xs:element minOccurs="0" name="right" type="xs:integer"/>
-            <xs:element minOccurs="0" name="up" type="xs:integer"/>
-            <xs:element minOccurs="0" name="down" type="xs:integer"/>
-            <xs:element minOccurs="0" name="desktop" type="xs:integer"/>
-            <xs:element minOccurs="0" name="wrap" type="ob:bool"/>
-            <xs:element minOccurs="0" name="follow" type="ob:bool"/>
-            <xs:element minOccurs="0" name="dialog" type="ob:bool"/>
-            <xs:element minOccurs="0" name="panels" type="ob:bool"/>
-            <xs:element minOccurs="0" name="here" type="ob:bool"/>
-            <xs:element minOccurs="0" name="linear" type="ob:bool"/>
-            <xs:element minOccurs="0" name="group" type="ob:bool"/>
-        </xs:sequence>
-        <xs:attribute name="name" type="ob:actionname" use="required"/>
-    </xs:complexType>
-    <xs:complexType name="keybind">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" name="action" type="ob:action"/>
-        </xs:sequence>
-        <xs:attribute name="key" type="ob:keyname" use="required"/>
-    </xs:complexType>
-    <xs:complexType name="keyboard">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="chainQuitKey" type="ob:keyname"/>
-            <xs:element maxOccurs="unbounded" name="keybind" type="ob:keybind"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="mousebind">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" name="action" type="ob:action"/>
-        </xs:sequence>
-        <xs:attribute name="action" type="ob:mouseaction" use="required"/>
-        <xs:attribute name="button" type="ob:button" use="required"/>
-    </xs:complexType>
-    <xs:complexType name="context">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" name="mousebind" type="ob:mousebind"/>
-        </xs:sequence>
-        <xs:attribute name="name" type="ob:contextname" use="required"/>
-    </xs:complexType>
-    <xs:complexType name="mouse">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="dragThreshold" type="xs:integer"/>
-            <xs:element minOccurs="0" name="doubleClickTime" type="xs:integer"/>
-            <xs:element maxOccurs="unbounded" name="context" type="ob:context"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="menu">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" name="file" type="xs:string"/>
-            <xs:element minOccurs="0" name="warpPointer" type="ob:bool"/>
-            <xs:element minOccurs="0" name="xorStyle" type="ob:bool"/>
-            <xs:element minOccurs="0" name="hideDelay" type="xs:integer"/>
-            <xs:element minOccurs="0" name="middle" type="ob:bool"/>
-            <xs:element minOccurs="0" name="submenuShowDelay" type="xs:integer"/>
-            <xs:element minOccurs="0" name="desktopMenuIcons" type="ob:bool"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="window_position">
-        <xs:sequence>
-            <xs:element name="x" type="ob:center_or_int"/>
-            <xs:element name="y" type="ob:center_or_int"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="application">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="decor" type="xs:string"/>
-            <xs:element minOccurs="0" name="shade" type="ob:bool"/>
-            <xs:element minOccurs="0" name="position" type="ob:window_position"/>
-            <xs:element minOccurs="0" name="focus" type="xs:string"/>
-            <xs:element minOccurs="0" name="desktop" type="xs:integer"/>
-            <xs:element minOccurs="0" name="head" type="xs:string"/>
-            <xs:element minOccurs="0" name="layer" type="ob:layer"/>
-            <xs:element minOccurs="0" name="iconic" type="ob:bool"/>
-            <xs:element minOccurs="0" name="skip_pager" type="ob:bool"/>
-            <xs:element minOccurs="0" name="skip_taskbar" type="ob:bool"/>
-            <xs:element minOccurs="0" name="fullscreen" type="ob:bool"/>
-            <xs:element minOccurs="0" name="maximized" type="ob:maximization"/>
-        </xs:sequence>
+    <xsd:complexType name="resistance">
+        <xsd:annotation>
+            <xsd:documentation>defines behaviour of windows when close to each other or the screen edge</xsd:documentation>
+        </xsd:annotation>
+        <xsd:element minOccurs="0" name="strength" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="screen_edge_strength" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="edges_hit_layers_below" type="ob:bool"/>
+    </xsd:complexType>
+    <xsd:complexType name="focus">
+        <xsd:annotation>
+            <xsd:documentation>defines aspects of window focus</xsd:documentation>
+        </xsd:annotation>
+        <xsd:element minOccurs="0" name="focusNew" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="focusLast" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="followMouse" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="focusDelay" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="raiseOnFocus" type="ob:bool"/>
+    </xsd:complexType>
+    <xsd:complexType name="placement">
+        <xsd:annotation>
+            <xsd:documentation>defines how new windows are placed</xsd:documentation>
+        </xsd:annotation>
+        <xsd:element name="policy" type="ob:placementpolicy"/>
+    </xsd:complexType>
+    <xsd:complexType name="theme">
+        <xsd:element minOccurs="0" name="name" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="titleLayout" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="titleNumber" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="keepBorder" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="hideDisabled" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="font" type="ob:font"/>
+    </xsd:complexType>
+    <xsd:complexType name="font">
+        <xsd:element minOccurs="0" name="name" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="size" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="weight" type="ob:fontweight"/>
+        <xsd:element minOccurs="0" name="slant" type="ob:fontslant"/>
+    </xsd:complexType>
+    <xsd:complexType name="desktops">
+        <xsd:annotation>
+            <xsd:documentation>defines the number and names of desktops</xsd:documentation>
+        </xsd:annotation>
+        <xsd:element minOccurs="0" name="number" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="firstdesk" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="names">
+            <xsd:complexType>
+                <xsd:element maxOccurs="unbounded" name="name" type="xsd:string"/>
+            </xsd:complexType>
+        </xsd:element>
+    </xsd:complexType>
+    <xsd:complexType name="resize">
+        <xsd:element minOccurs="0" name="drawContents" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="popupShow" type="ob:popupshow"/>
+        <xsd:element minOccurs="0" name="popupPosition" type="ob:popupposition"/>
+    </xsd:complexType>
+    <xsd:complexType name="dock">
+        <xsd:element minOccurs="0" name="position" type="ob:dock_position"/>
+        <xsd:element minOccurs="0" name="floatingX" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="floatingY" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="noStrut" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="stacking" type="ob:layer"/>
+        <xsd:element minOccurs="0" name="direction" type="ob:direction"/>
+        <xsd:element minOccurs="0" name="autoHide" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="hideDelay" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="showDelay" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="moveButton" type="ob:button"/>
+    </xsd:complexType>
+    <xsd:complexType name="action">
+        <xsd:element minOccurs="0" name="execute" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="menu" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="delta" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="x" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="y" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="left" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="right" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="up" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="down" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="desktop" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="wrap" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="follow" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="dialog" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="panels" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="here" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="linear" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="group" type="ob:bool"/>
+        <xsd:attribute name="name" type="ob:actionname" use="required"/>
+    </xsd:complexType>
+    <xsd:complexType name="keybind">
+        <xsd:choice>
+            <xsd:element maxOccurs="unbounded" name="action" type="ob:action"/>
+            <xsd:element maxOccurs="unbounded" name="keybind" type="ob:keybind"/>
+        </xsd:choice>
+        <xsd:attribute name="chroot" type="ob:bool"/>
+        <xsd:attribute name="key" type="ob:keyname" use="required"/>
+    </xsd:complexType>
+    <xsd:complexType name="keyboard">
+        <xsd:element minOccurs="0" name="chainQuitKey" type="ob:keyname"/>
+        <xsd:element maxOccurs="unbounded" name="keybind" type="ob:keybind"/>
+    </xsd:complexType>
+    <xsd:complexType name="mousebind">
+        <xsd:element maxOccurs="unbounded" name="action" type="ob:action"/>
+        <xsd:attribute name="action" type="ob:mouseaction" use="required"/>
+        <xsd:attribute name="button" type="ob:button" use="required"/>
+    </xsd:complexType>
+    <xsd:complexType name="context">
+        <xsd:element maxOccurs="unbounded" name="mousebind" type="ob:mousebind"/>
+        <xsd:attribute name="name" type="ob:contextname" use="required"/>
+    </xsd:complexType>
+    <xsd:complexType name="mouse">
+        <xsd:element minOccurs="0" name="dragThreshold" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="doubleClickTime" type="xsd:integer"/>
+        <xsd:element maxOccurs="unbounded" name="context" type="ob:context"/>
+    </xsd:complexType>
+    <xsd:complexType name="menu">
+        <xsd:element maxOccurs="unbounded" name="file" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="warpPointer" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="xorStyle" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="hideDelay" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="middle" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="submenuShowDelay" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="desktopMenuIcons" type="ob:bool"/>
+    </xsd:complexType>
+    <xsd:complexType name="window_position">
+        <xsd:element name="x" type="ob:center_or_int"/>
+        <xsd:element name="y" type="ob:center_or_int"/>
+    </xsd:complexType>
+    <xsd:complexType name="application">
+        <xsd:element minOccurs="0" name="decor" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="shade" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="position" type="ob:window_position"/>
+        <xsd:element minOccurs="0" name="focus" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="desktop" type="xsd:integer"/>
+        <xsd:element minOccurs="0" name="head" type="xsd:string"/>
+        <xsd:element minOccurs="0" name="layer" type="ob:layer"/>
+        <xsd:element minOccurs="0" name="iconic" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="skip_pager" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="skip_taskbar" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="fullscreen" type="ob:bool"/>
+        <xsd:element minOccurs="0" name="maximized" type="ob:maximization"/>
         <!-- at least one of these must be present -->
-        <xs:attribute name="name" type="xs:string"/>
-        <xs:attribute name="class" type="xs:string"/>
-        <xs:attribute name="role" type="xs:string"/>
-    </xs:complexType>
-    <xs:complexType name="applications">
-        <xs:sequence>
-            <xs:element minOccurs="0" maxOccurs="unbounded" name="application" type="ob:application"/>
-        </xs:sequence>
-    </xs:complexType>
+        <xsd:attribute name="name" type="xsd:string"/>
+        <xsd:attribute name="class" type="xsd:string"/>
+        <xsd:attribute name="role" type="xsd:string"/>
+    </xsd:complexType>
+    <xsd:complexType name="applications">
+        <xsd:element minOccurs="0" maxOccurs="unbounded" name="application" type="ob:application"/>
+    </xsd:complexType>
     <!--
          simple types / restrictions
       -->
-    <xs:simpleType name="actionname">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Activate"/>
-            <xs:enumeration value="Close"/>
-            <xs:enumeration value="Desktop"/>
-            <xs:enumeration value="DesktopDown"/>
-            <xs:enumeration value="DesktopLast"/>
-            <xs:enumeration value="DesktopLeft"/>
-            <xs:enumeration value="DesktopNext"/>
-            <xs:enumeration value="DesktopPrevious"/>
-            <xs:enumeration value="DesktopRight"/>
-            <xs:enumeration value="DesktopUp"/>
-            <xs:enumeration value="DirectionalFocusEast"/>
-            <xs:enumeration value="DirectionalFocusNorth"/>
-            <xs:enumeration value="DirectionalFocusNortheast"/>
-            <xs:enumeration value="DirectionalFocusNorthwest"/>
-            <xs:enumeration value="DirectionalFocusSouth"/>
-            <xs:enumeration value="DirectionalFocusSoutheast"/>
-            <xs:enumeration value="DirectionalFocusSouthwest"/>
-            <xs:enumeration value="DirectionalFocusWest"/>
-            <xs:enumeration value="Execute"/>
-            <xs:enumeration value="Exit"/>
-            <xs:enumeration value="Focus"/>
-            <xs:enumeration value="FocusToBottom"/>
-            <xs:enumeration value="GrowToEdgeEast"/>
-            <xs:enumeration value="GrowToEdgeNorth"/>
-            <xs:enumeration value="GrowToEdgeSouth"/>
-            <xs:enumeration value="GrowToEdgeWest"/>
-            <xs:enumeration value="Iconify"/>
-            <xs:enumeration value="Kill"/>
-            <xs:enumeration value="Lower"/>
-            <xs:enumeration value="MaximizeFull"/>
-            <xs:enumeration value="MaximizeHorz"/>
-            <xs:enumeration value="MaximizeVert"/>
-            <xs:enumeration value="Move"/>
-            <xs:enumeration value="MoveRelative"/>
-            <xs:enumeration value="MoveRelativeHorz"/>
-            <xs:enumeration value="MoveRelativeVert"/>
-            <xs:enumeration value="MoveToCenter"/>
-            <xs:enumeration value="MoveFromEdgeEast"/>
-            <xs:enumeration value="MoveFromEdgeNorth"/>
-            <xs:enumeration value="MoveFromEdgeSouth"/>
-            <xs:enumeration value="MoveFromEdgeWest"/>
-            <xs:enumeration value="MoveToEdgeEast"/>
-            <xs:enumeration value="MoveToEdgeNorth"/>
-            <xs:enumeration value="MoveToEdgeSouth"/>
-            <xs:enumeration value="MoveToEdgeWest"/>
-            <xs:enumeration value="NextWindow"/>
-            <xs:enumeration value="PreviousWindow"/>
-            <xs:enumeration value="Raise"/>
-            <xs:enumeration value="RaiseLower"/>
-            <xs:enumeration value="Reconfigure"/>
-            <xs:enumeration value="Resize"/>
-            <xs:enumeration value="ResizeRelative"/>
-            <xs:enumeration value="ResizeRelativeHorz"/>
-            <xs:enumeration value="ResizeRelativeVert"/>
-            <xs:enumeration value="Restart"/>
-            <xs:enumeration value="SendToBottomLayer"/>
-            <xs:enumeration value="SendToDesktop"/>
-            <xs:enumeration value="SendToDesktopDown"/>
-            <xs:enumeration value="SendToDesktopLeft"/>
-            <xs:enumeration value="SendToDesktopNext"/>
-            <xs:enumeration value="SendToDesktopPrevious"/>
-            <xs:enumeration value="SendToDesktopRight"/>
-            <xs:enumeration value="SendToDesktopUp"/>
-            <xs:enumeration value="SendToNormalLayer"/>
-            <xs:enumeration value="SendToTopLayer"/>
-            <xs:enumeration value="Shade"/>
-            <xs:enumeration value="ShadeLower"/>
-            <xs:enumeration value="ShowDesktop"/>
-            <xs:enumeration value="ShowMenu"/>
-            <xs:enumeration value="ToggleAlwaysOnBottom"/>
-            <xs:enumeration value="ToggleAlwaysOnTop"/>
-            <xs:enumeration value="ToggleDecorations"/>
-            <xs:enumeration value="ToggleDockAutoHide"/>
-            <xs:enumeration value="ToggleFullscreen"/>
-            <xs:enumeration value="ToggleMaximizeFull"/>
-            <xs:enumeration value="ToggleMaximizeHorz"/>
-            <xs:enumeration value="ToggleMaximizeVert"/>
-            <xs:enumeration value="ToggleOmnipresent"/>
-            <xs:enumeration value="ToggleShade"/>
-            <xs:enumeration value="ToggleShowDesktop"/>
-            <xs:enumeration value="Unfocus"/>
-            <xs:enumeration value="UnmaximizeFull"/>
-            <xs:enumeration value="UnmaximizeHorz"/>
-            <xs:enumeration value="UnmaximizeVert"/>
-            <xs:enumeration value="Unshade"/>
-            <xs:enumeration value="UnshadeRaise"/>
-            <xs:enumeration value="UnShowDesktop"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="bool">
+    <xsd:simpleType name="actionname">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Activate"/>
+            <xsd:enumeration value="BreakChroot"/>
+            <xsd:enumeration value="Close"/>
+            <xsd:enumeration value="Desktop"/>
+            <xsd:enumeration value="DesktopDown"/>
+            <xsd:enumeration value="DesktopLast"/>
+            <xsd:enumeration value="DesktopLeft"/>
+            <xsd:enumeration value="DesktopNext"/>
+            <xsd:enumeration value="DesktopPrevious"/>
+            <xsd:enumeration value="DesktopRight"/>
+            <xsd:enumeration value="DesktopUp"/>
+            <xsd:enumeration value="DirectionalFocusEast"/>
+            <xsd:enumeration value="DirectionalFocusNorth"/>
+            <xsd:enumeration value="DirectionalFocusNortheast"/>
+            <xsd:enumeration value="DirectionalFocusNorthwest"/>
+            <xsd:enumeration value="DirectionalFocusSouth"/>
+            <xsd:enumeration value="DirectionalFocusSoutheast"/>
+            <xsd:enumeration value="DirectionalFocusSouthwest"/>
+            <xsd:enumeration value="DirectionalFocusWest"/>
+            <xsd:enumeration value="Execute"/>
+            <xsd:enumeration value="Exit"/>
+            <xsd:enumeration value="Focus"/>
+            <xsd:enumeration value="FocusToBottom"/>
+            <xsd:enumeration value="GrowToEdgeEast"/>
+            <xsd:enumeration value="GrowToEdgeNorth"/>
+            <xsd:enumeration value="GrowToEdgeSouth"/>
+            <xsd:enumeration value="GrowToEdgeWest"/>
+            <xsd:enumeration value="Iconify"/>
+            <xsd:enumeration value="Kill"/>
+            <xsd:enumeration value="Lower"/>
+            <xsd:enumeration value="MaximizeFull"/>
+            <xsd:enumeration value="MaximizeHorz"/>
+            <xsd:enumeration value="MaximizeVert"/>
+            <xsd:enumeration value="Move"/>
+            <xsd:enumeration value="MoveRelative"/>
+            <xsd:enumeration value="MoveRelativeHorz"/>
+            <xsd:enumeration value="MoveRelativeVert"/>
+            <xsd:enumeration value="MoveToCenter"/>
+            <xsd:enumeration value="MoveFromEdgeEast"/>
+            <xsd:enumeration value="MoveFromEdgeNorth"/>
+            <xsd:enumeration value="MoveFromEdgeSouth"/>
+            <xsd:enumeration value="MoveFromEdgeWest"/>
+            <xsd:enumeration value="MoveToEdgeEast"/>
+            <xsd:enumeration value="MoveToEdgeNorth"/>
+            <xsd:enumeration value="MoveToEdgeSouth"/>
+            <xsd:enumeration value="MoveToEdgeWest"/>
+            <xsd:enumeration value="NextWindow"/>
+            <xsd:enumeration value="PreviousWindow"/>
+            <xsd:enumeration value="Raise"/>
+            <xsd:enumeration value="RaiseLower"/>
+            <xsd:enumeration value="Reconfigure"/>
+            <xsd:enumeration value="Resize"/>
+            <xsd:enumeration value="ResizeRelative"/>
+            <xsd:enumeration value="ResizeRelativeHorz"/>
+            <xsd:enumeration value="ResizeRelativeVert"/>
+            <xsd:enumeration value="Restart"/>
+            <xsd:enumeration value="SendToBottomLayer"/>
+            <xsd:enumeration value="SendToDesktop"/>
+            <xsd:enumeration value="SendToDesktopDown"/>
+            <xsd:enumeration value="SendToDesktopLeft"/>
+            <xsd:enumeration value="SendToDesktopNext"/>
+            <xsd:enumeration value="SendToDesktopPrevious"/>
+            <xsd:enumeration value="SendToDesktopRight"/>
+            <xsd:enumeration value="SendToDesktopUp"/>
+            <xsd:enumeration value="SendToNormalLayer"/>
+            <xsd:enumeration value="SendToTopLayer"/>
+            <xsd:enumeration value="Shade"/>
+            <xsd:enumeration value="ShadeLower"/>
+            <xsd:enumeration value="ShowDesktop"/>
+            <xsd:enumeration value="ShowMenu"/>
+            <xsd:enumeration value="ToggleAlwaysOnBottom"/>
+            <xsd:enumeration value="ToggleAlwaysOnTop"/>
+            <xsd:enumeration value="ToggleDecorations"/>
+            <xsd:enumeration value="ToggleDockAutoHide"/>
+            <xsd:enumeration value="ToggleFullscreen"/>
+            <xsd:enumeration value="ToggleMaximizeFull"/>
+            <xsd:enumeration value="ToggleMaximizeHorz"/>
+            <xsd:enumeration value="ToggleMaximizeVert"/>
+            <xsd:enumeration value="ToggleOmnipresent"/>
+            <xsd:enumeration value="ToggleShade"/>
+            <xsd:enumeration value="ToggleShowDesktop"/>
+            <xsd:enumeration value="Unfocus"/>
+            <xsd:enumeration value="UnmaximizeFull"/>
+            <xsd:enumeration value="UnmaximizeHorz"/>
+            <xsd:enumeration value="UnmaximizeVert"/>
+            <xsd:enumeration value="Unshade"/>
+            <xsd:enumeration value="UnshadeRaise"/>
+            <xsd:enumeration value="UnShowDesktop"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="bool">
         <!-- this is copied to maximization.  Keep that in sync. -->
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="yes"/>
-            <xs:enumeration value="no"/>
-            <xs:enumeration value="true"/>
-            <xs:enumeration value="false"/>
-            <xs:enumeration value="on"/>
-            <xs:enumeration value="off"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="fontweight">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="normal"/>
-            <xs:enumeration value="bold"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="fontslant">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="normal"/>
-            <xs:enumeration value="italic"/>
-            <xs:enumeration value="opaque"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="button">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Left"/>
-            <xs:enumeration value="Middle"/>
-            <xs:enumeration value="Right"/>
-            <xs:enumeration value="Up"/>
-            <xs:enumeration value="Down"/>
-            <xs:enumeration value="A-Left"/>
-            <xs:enumeration value="A-Middle"/>
-            <xs:enumeration value="A-Right"/>
-            <xs:enumeration value="A-Up"/>
-            <xs:enumeration value="A-Down"/>
-            <xs:enumeration value="C-A-Left"/>
-            <xs:enumeration value="C-A-Middle"/>
-            <xs:enumeration value="C-A-Right"/>
-            <xs:enumeration value="C-A-Up"/>
-            <xs:enumeration value="C-A-Down"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="center_or_int">
-        <xs:restriction base="xs:string">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="yes"/>
+            <xsd:enumeration value="no"/>
+            <xsd:enumeration value="true"/>
+            <xsd:enumeration value="false"/>
+            <xsd:enumeration value="on"/>
+            <xsd:enumeration value="off"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="fontweight">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="normal"/>
+            <xsd:enumeration value="bold"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="fontslant">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="normal"/>
+            <xsd:enumeration value="italic"/>
+            <xsd:enumeration value="opaque"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="button">
+        <xsd:restriction base="xsd:string">
+            <!-- FIXME what??? -->
+            <xsd:enumeration value="Left"/>
+            <xsd:enumeration value="Middle"/>
+            <xsd:enumeration value="Right"/>
+            <xsd:enumeration value="Up"/>
+            <xsd:enumeration value="Down"/>
+            <xsd:enumeration value="A-Left"/>
+            <xsd:enumeration value="A-Middle"/>
+            <xsd:enumeration value="A-Right"/>
+            <xsd:enumeration value="A-Up"/>
+            <xsd:enumeration value="A-Down"/>
+            <xsd:enumeration value="C-A-Left"/>
+            <xsd:enumeration value="C-A-Middle"/>
+            <xsd:enumeration value="C-A-Right"/>
+            <xsd:enumeration value="C-A-Up"/>
+            <xsd:enumeration value="C-A-Down"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="center_or_int">
+        <xsd:restriction base="xsd:string">
             <!-- ob: atoi($_) unless $_ eq 'center'; -->
             <!-- I think the regexp DTRT WRT atoi. -->
-            <xs:pattern value="center|0|[1-9][0-9]*"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="contextname">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Desktop"/>
-            <xs:enumeration value="Client"/>
-            <xs:enumeration value="Titlebar"/>
-            <xs:enumeration value="Handle"/>
-            <xs:enumeration value="Frame"/>
-            <xs:enumeration value="TLCorner"/>
-            <xs:enumeration value="TRCorner"/>
-            <xs:enumeration value="BLCorner"/>
-            <xs:enumeration value="BRCorner"/>
-            <xs:enumeration value="Maximize"/>
-            <xs:enumeration value="AllDesktops"/>
-            <xs:enumeration value="Shade"/>
-            <xs:enumeration value="Iconify"/>
-            <xs:enumeration value="Icon"/>
-            <xs:enumeration value="Close"/>
-            <xs:enumeration value="MoveResize"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="direction">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Horizontal"/>
-            <xs:enumeration value="Vertical"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="dock_position">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="TopLeft"/>
-            <xs:enumeration value="Top"/>
-            <xs:enumeration value="TopRight"/>
-            <xs:enumeration value="Right"/>
-            <xs:enumeration value="BottomRight"/>
-            <xs:enumeration value="Bottom"/>
-            <xs:enumeration value="BottomLeft"/>
-            <xs:enumeration value="Left"/>
-            <xs:enumeration value="Floating"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="keyname">
-        <xs:restriction base="xs:string">
+            <xsd:pattern value="center|0|[1-9][0-9]*"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="contextname">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Desktop"/>
+            <xsd:enumeration value="Client"/>
+            <xsd:enumeration value="Titlebar"/>
+            <xsd:enumeration value="Handle"/>
+            <xsd:enumeration value="Frame"/>
+            <xsd:enumeration value="TLCorner"/>
+            <xsd:enumeration value="TRCorner"/>
+            <xsd:enumeration value="BLCorner"/>
+            <xsd:enumeration value="BRCorner"/>
+            <xsd:enumeration value="Maximize"/>
+            <xsd:enumeration value="AllDesktops"/>
+            <xsd:enumeration value="Shade"/>
+            <xsd:enumeration value="Iconify"/>
+            <xsd:enumeration value="Icon"/>
+            <xsd:enumeration value="Close"/>
+            <xsd:enumeration value="MoveResize"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="direction">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Horizontal"/>
+            <xsd:enumeration value="Vertical"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="dock_position">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="TopLeft"/>
+            <xsd:enumeration value="Top"/>
+            <xsd:enumeration value="TopRight"/>
+            <xsd:enumeration value="Right"/>
+            <xsd:enumeration value="BottomRight"/>
+            <xsd:enumeration value="Bottom"/>
+            <xsd:enumeration value="BottomLeft"/>
+            <xsd:enumeration value="Left"/>
+            <xsd:enumeration value="Floating"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="keyname">
+        <xsd:restriction base="xsd:string">
             <!-- FIXME: M, Mod2, Mod5 in addition to S, A, C -->
             <!-- how do we do all substrings and permutations? -->
-            <xs:pattern value="(A-)?(S-)?(A-)?(C-)?(A-)?(S-)?(A-)?[a-zA-Z0-9]*"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="layer">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="above"/>
-            <xs:enumeration value="normal"/>
-            <xs:enumeration value="below"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="maximization">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Horizontal"/>
-            <xs:enumeration value="Vertical"/>
+            <xsd:pattern value="(A-)?(S-)?(A-)?(C-)?(A-)?(S-)?(A-)?[a-zA-Z0-9]*"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="layer">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="above"/>
+            <xsd:enumeration value="normal"/>
+            <xsd:enumeration value="below"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="maximization">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Horizontal"/>
+            <xsd:enumeration value="Vertical"/>
             <!-- this is a copy of ob:bool.  Keep it in sync. -->
-            <xs:enumeration value="yes"/>
-            <xs:enumeration value="no"/>
-            <xs:enumeration value="true"/>
-            <xs:enumeration value="false"/>
-            <xs:enumeration value="on"/>
-            <xs:enumeration value="off"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="mouseaction">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Click"/>
-            <xs:enumeration value="DoubleClick"/>
-            <xs:enumeration value="Drag"/>
-            <xs:enumeration value="Press"/>
-            <xs:enumeration value="Release"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="placementpolicy">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Smart"/>
-            <xs:enumeration value="UnderMouse"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="popupposition">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Top"/>
-            <xs:enumeration value="Center"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:simpleType name="popupshow">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="Always"/>
-            <xs:enumeration value="Never"/>
-            <xs:enumeration value="Nonpixel"/>
-        </xs:restriction>
-    </xs:simpleType>
-</xs:schema>
+            <xsd:enumeration value="yes"/>
+            <xsd:enumeration value="no"/>
+            <xsd:enumeration value="true"/>
+            <xsd:enumeration value="false"/>
+            <xsd:enumeration value="on"/>
+            <xsd:enumeration value="off"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="mouseaction">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Click"/>
+            <xsd:enumeration value="DoubleClick"/>
+            <xsd:enumeration value="Drag"/>
+            <xsd:enumeration value="Press"/>
+            <xsd:enumeration value="Release"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="placementpolicy">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Smart"/>
+            <xsd:enumeration value="UnderMouse"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="popupposition">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Top"/>
+            <xsd:enumeration value="Center"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+    <xsd:simpleType name="popupshow">
+        <xsd:restriction base="xsd:string">
+            <xsd:enumeration value="Always"/>
+            <xsd:enumeration value="Never"/>
+            <xsd:enumeration value="Nonpixel"/>
+        </xsd:restriction>
+    </xsd:simpleType>
+</xsd:schema>
index 556fc22564a50e36bbdee3f21341529b2c2f9324..80b0a8f11ce20a4511a640ef0ae23e6b18374cd0 100644 (file)
@@ -892,6 +892,11 @@ ActionString actionstrings[] =
         action_growtoedge,
         setup_action_growtoedge_east
     },
+    {
+        "breakchroot",
+        action_break_chroot,
+        NULL
+    },
     {
         NULL,
         NULL,
@@ -1727,7 +1732,7 @@ void action_showmenu(union ActionData *data)
 {
     if (data->showmenu.name) {
         menu_show(data->showmenu.name, data->any.x, data->any.y,
-                  data->showmenu.any.c);
+                  data->any.button, data->showmenu.any.c);
     }
 }
 
@@ -1899,3 +1904,9 @@ void action_unshow_desktop(union ActionData *data)
 {
     screen_show_desktop(FALSE);
 }
+
+void action_break_chroot(union ActionData *data)
+{
+    /* break out of one chroot */
+    keyboard_reset_chains(1);
+}
index 4039146041e6dc945b6aea1f4375364df1a32116..c4c06fa886db8fcde92d45be0bf291346de69e2f 100644 (file)
@@ -341,5 +341,7 @@ void action_toggle_show_desktop(union ActionData *data);
 void action_show_desktop(union ActionData *data);
 /* Any */
 void action_unshow_desktop(union ActionData *data);
+/* Any */
+void action_break_chroot(union ActionData *data);
 
 #endif
index 4b8e621b486acea3cf82a6389ac6b659371916d3..84f739ac46f9e17c576564e3c0e29115a8e1f02a 100644 (file)
@@ -483,11 +483,8 @@ void client_unmanage(ObClient *self)
     /* flush to send the hide to the server quickly */
     XFlush(ob_display);
 
-    if (focus_client == self) {
-        /* ignore enter events from the unmap so it doesnt mess with the focus
-         */
-        event_ignore_queued_enters();
-    }
+    /* ignore enter events from the unmap so it doesnt mess with the focus */
+    event_ignore_queued_enters();
 
     mouse_grab_for_client(self, FALSE);
 
@@ -1137,7 +1134,8 @@ void client_update_transient_for(ObClient *self)
             /* remove from old parents */
             for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
-                if (c != self && !c->transient_for)
+                if (c != self && (!c->transient_for ||
+                                  c->transient_for != OB_TRAN_GROUP))
                     c->transients = g_slist_remove(c->transients, self);
             }
         } else if (self->transient_for != NULL) { /* transient of window */
@@ -1152,7 +1150,8 @@ void client_update_transient_for(ObClient *self)
             /* add to new parents */
             for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
-                if (c != self && !c->transient_for)
+                if (c != self && (!c->transient_for ||
+                                  c->transient_for != OB_TRAN_GROUP))
                     c->transients = g_slist_append(c->transients, self);
             }
 
index be76715520c50fc52f4ab889d00de84c9561a4d8..4efef8a83014e7c6d6fa005e5d6e015eac7eed81 100644 (file)
@@ -157,6 +157,69 @@ static void send_to_update(ObMenuFrame *frame, gpointer data)
     }
 }
 
+static void client_menu_place(ObMenuFrame *frame, gint *x, gint *y,
+                              gint button, gpointer data)
+{
+    gint dx, dy;
+
+    if (button == 0 && frame->client) {
+        *x = frame->client->frame->area.x;
+
+        /* try below the titlebar */
+        *y = frame->client->frame->area.y + frame->client->frame->size.top -
+            frame->client->frame->bwidth;
+        menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+        if (dy != 0) {
+            /* try above the titlebar */
+            *y = frame->client->frame->area.y + frame->client->frame->bwidth -
+                frame->area.height;
+            menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+        }
+        if (dy != 0) {
+            /* didnt fit either way, use move on screen's values */
+            *y = frame->client->frame->area.y + frame->client->frame->size.top;
+            menu_frame_move_on_screen(frame, *x, *y, &dx, &dy);
+        }
+
+        *x += dx;
+        *y += dy;
+    } else {
+        gint myx, myy;
+
+        myx = *x;
+        myy = *y;
+
+        /* try to the bottom right of the cursor */
+        menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+        if (dx != 0 || dy != 0) {
+            /* try to the bottom left of the cursor */
+            myx = *x - frame->area.width;
+            myy = *y;
+            menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* try to the top right of the cursor */
+            myx = *x;
+            myy = *y - frame->area.height;
+            menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* try to the top left of the cursor */
+            myx = *x - frame->area.width;
+            myy = *y - frame->area.height;
+            menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* if didnt fit on either side so just use what it says */
+            myx = *x;
+            myy = *y;
+            menu_frame_move_on_screen(frame, myx, myy, &dx, &dy);
+        }
+        *x = myx + dx;
+        *y = myy + dy;
+    }
+}
+
 void client_menu_startup()
 {
     GSList *acts;
@@ -189,6 +252,7 @@ void client_menu_startup()
     menu = menu_new(CLIENT_MENU_NAME, _("Client menu"), TRUE, NULL);
     menu_show_all_shortcuts(menu, TRUE);
     menu_set_update_func(menu, client_update);
+    menu_set_place_func(menu, client_menu_place);
 
     menu_add_submenu(menu, CLIENT_SEND_TO, SEND_TO_MENU_NAME);
 
index fda9d9f08e9b21b9384326153237059d5b5a195c..f8b3fd95449bd1de7bb68fc8de76bde8f04e27ce 100644 (file)
@@ -273,47 +273,60 @@ static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
                       GList *keylist)
 {
     gchar *key;
-    ObAction *action;
-    xmlNodePtr n, nact;
-    GList *it;
+    xmlNodePtr n;
+    gboolean is_chroot = FALSE;
 
-    if ((n = parse_find_node("chainQuitKey", node))) {
-        key = parse_string(doc, n);
-        translate_key(key, &config_keyboard_reset_state,
-                      &config_keyboard_reset_keycode);
-        g_free(key);
-    }
+    if (!parse_attr_string("key", node, &key))
+        return;
 
-    n = parse_find_node("keybind", node);
-    while (n) {
-        if (parse_attr_string("key", n, &key)) {
-            keylist = g_list_append(keylist, key);
+    parse_attr_bool("chroot", node, &is_chroot);
 
-            parse_key(i, doc, n->children, keylist);
+    keylist = g_list_append(keylist, key);
 
-            it = g_list_last(keylist);
-            g_free(it->data);
-            keylist = g_list_delete_link(keylist, it);
+    if ((n = parse_find_node("keybind", node->children))) {
+        while (n) {
+            parse_key(i, doc, n, keylist);
+            n = parse_find_node("keybind", n->next);
         }
-        n = parse_find_node("keybind", n->next);
     }
-    if (keylist) {
-        nact = parse_find_node("action", node);
-        while (nact) {
-            if ((action = action_parse(i, doc, nact,
-                                       OB_USER_ACTION_KEYBOARD_KEY)))
+    else if ((n = parse_find_node("action", node->children))) {
+        while (n) {
+            ObAction *action;
+            
+            action = action_parse(i, doc, n, OB_USER_ACTION_KEYBOARD_KEY);
+            if (action)
                 keyboard_bind(keylist, action);
-            nact = parse_find_node("action", nact->next);
+            n = parse_find_node("action", n->next);
         }
     }
+
+    if (is_chroot)
+        keyboard_chroot(keylist);
+
+    g_free(key);
+    keylist = g_list_delete_link(keylist, g_list_last(keylist));
 }
 
 static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
                            gpointer d)
 {
+    xmlNodePtr n;
+    gchar *key;
+
     keyboard_unbind_all();
 
-    parse_key(i, doc, node->children, NULL);
+    if ((n = parse_find_node("chainQuitKey", node->children))) {
+        key = parse_string(doc, n);
+        translate_key(key, &config_keyboard_reset_state,
+                      &config_keyboard_reset_keycode);
+        g_free(key);
+    }
+
+    if ((n = parse_find_node("keybind", node->children)))
+        while (n) {
+            parse_key(i, doc, n, NULL);
+            n = parse_find_node("keybind", n->next);
+        }
 }
 
 /*
index f9716c3028f91389151dcadced0a1bdaf01103e3..c1151eb392eda2b8bb803c37390a08ae12148d63 100644 (file)
 #include "keyboard.h"
 #include "translate.h"
 #include "moveresize.h"
+#include "popup.h"
 #include "gettext.h"
 
 #include <glib.h>
 
-KeyBindingTree *keyboard_firstnode;
-
 typedef struct {
     guint state;
     ObClient *client;
@@ -45,61 +44,112 @@ typedef struct {
     ObFrameContext context;
 } ObInteractiveState;
 
+KeyBindingTree *keyboard_firstnode = NULL;
+static ObPopup *popup = NULL;
 static GSList *interactive_states;
-
 static KeyBindingTree *curpos;
 
-static void grab_for_window(Window win, gboolean grab)
+static void grab_keys(gboolean grab)
 {
     KeyBindingTree *p;
 
-    ungrab_all_keys(win);
+    ungrab_all_keys(RootWindow(ob_display, ob_screen));
 
     if (grab) {
         p = curpos ? curpos->first_child : keyboard_firstnode;
         while (p) {
-            grab_key(p->key, p->state, win, GrabModeAsync);
+            grab_key(p->key, p->state, RootWindow(ob_display, ob_screen),
+                     GrabModeAsync);
             p = p->next_sibling;
         }
         if (curpos)
             grab_key(config_keyboard_reset_keycode,
                      config_keyboard_reset_state,
-                     win, GrabModeAsync);
+                     RootWindow(ob_display, ob_screen), GrabModeAsync);
     }
 }
 
-static void grab_keys(gboolean grab)
+static gboolean chain_timeout(gpointer data)
 {
-    GList *it;
-
-    grab_for_window(screen_support_win, grab);
-    grab_for_window(RootWindow(ob_display, ob_screen), grab);
+    keyboard_reset_chains(0);
+    return FALSE; /* don't repeat */
 }
 
-static gboolean chain_timeout(gpointer data)
+static gboolean popup_show_timeout(gpointer data)
 {
-    keyboard_reset_chains();
+    gchar *text = data;
+    popup_show(popup, text);
 
     return FALSE; /* don't repeat */
 }
 
-void keyboard_reset_chains()
+static void set_curpos(KeyBindingTree *newpos)
 {
-    ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+    grab_keys(FALSE);
+    curpos = newpos;
+    grab_keys(TRUE);
+
+    if (curpos != NULL) {
+        gchar *text = NULL;
+        GList *it;
+
+        for (it = curpos->keylist; it; it = g_list_next(it)) {
+            gchar *oldtext = text;
+            if (text == NULL)
+                text = g_strdup(it->data);
+            else
+                text = g_strconcat(text, " - ", it->data, NULL);
+            g_free(oldtext);
+        }
+
+        popup_position(popup, NorthWestGravity, 10, 10);
+        if (popup->mapped) {
+            popup_show_timeout(text);
+            g_free(text);
+        } else {
+            ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
+            /* 1 second delay for the popup to show */
+            ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC,
+                                     popup_show_timeout, text,
+                                     g_direct_equal, g_free);
+        }
+    } else {
+        popup_hide(popup);
+        ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
+    }
+}
 
-    if (curpos) {
-        grab_keys(FALSE);
-        curpos = NULL;
-        grab_keys(TRUE);
+void keyboard_reset_chains(gint break_chroots)
+{
+    KeyBindingTree *p;
+
+    for (p = curpos; p; p = p->parent) {
+        if (p->chroot) {
+            if (break_chroots == 0) break; /* stop here */
+            if (break_chroots > 0)
+                --break_chroots;
+        }
     }
+    set_curpos(p);
 }
 
 void keyboard_unbind_all()
 {
     tree_destroy(keyboard_firstnode);
     keyboard_firstnode = NULL;
-    grab_keys(FALSE);
-    curpos = NULL;
+}
+
+void keyboard_chroot(GList *keylist)
+{
+    /* try do it in the existing tree. if we can't that means it is an empty
+       chroot binding. so add it to the tree then. */
+    if (!tree_chroot(keyboard_firstnode, keylist)) {
+        KeyBindingTree *tree;
+        if (!(tree = tree_build(keylist)))
+            return;
+        tree_chroot(tree, keylist);
+        tree_assimilate(tree);
+    }
 }
 
 gboolean keyboard_bind(GList *keylist, ObAction *action)
@@ -190,7 +240,6 @@ void keyboard_interactive_end(ObInteractiveState *s,
     if (!interactive_states) {
         grab_keyboard(FALSE);
         grab_pointer(FALSE, FALSE, OB_CURSOR_NONE);
-        keyboard_reset_chains();
     }
 }
 
@@ -251,7 +300,8 @@ void keyboard_event(ObClient *client, const XEvent *e)
     if (e->xkey.keycode == config_keyboard_reset_keycode &&
         e->xkey.state == config_keyboard_reset_state)
     {
-        keyboard_reset_chains();
+        ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+        keyboard_reset_chains(-1);
         return;
     }
 
@@ -265,16 +315,15 @@ void keyboard_event(ObClient *client, const XEvent *e)
         {
             if (p->first_child != NULL) { /* part of a chain */
                 ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
-                /* 5 second timeout for chains */
-                ob_main_loop_timeout_add(ob_main_loop, 5 * G_USEC_PER_SEC,
+                /* 3 second timeout for chains */
+                ob_main_loop_timeout_add(ob_main_loop, 3 * G_USEC_PER_SEC,
                                          chain_timeout, NULL,
                                          g_direct_equal, NULL);
-                grab_keys(FALSE);
-                curpos = p;
-                grab_keys(TRUE);
-            } else {
-
-                keyboard_reset_chains();
+                set_curpos(p);
+            } else if (p->chroot)         /* an empty chroot */
+                set_curpos(p);
+            else {
+                keyboard_reset_chains(0);
 
                 action_run_key(p->actions, client, e->xkey.state,
                                e->xkey.x_root, e->xkey.y_root,
@@ -294,6 +343,7 @@ gboolean keyboard_interactively_grabbed()
 void keyboard_startup(gboolean reconfig)
 {
     grab_keys(TRUE);
+    popup = popup_new(FALSE);
 
     if (!reconfig)
         client_add_destructor(keyboard_interactive_end_client, NULL);
@@ -312,7 +362,12 @@ void keyboard_shutdown(gboolean reconfig)
     interactive_states = NULL;
 
     ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+    ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
 
     keyboard_unbind_all();
+    set_curpos(NULL);
+
+    popup_free(popup);
+    popup = NULL;
 }
 
index 80709fa51d464bc9ee23c30d341618b6c5b706ab..4c6f3bb59ec1c830a7e7b84cf7760d61f5016831 100644 (file)
@@ -34,11 +34,14 @@ extern KeyBindingTree *keyboard_firstnode;
 void keyboard_startup(gboolean reconfig);
 void keyboard_shutdown(gboolean reconfig);
 
+void keyboard_chroot(GList *keylist);
 gboolean keyboard_bind(GList *keylist, ObAction *action);
 void keyboard_unbind_all();
 
 void keyboard_event(struct _ObClient *client, const XEvent *e);
-void keyboard_reset_chains();
+/*! @param break_chroots how many chroots to break. -1 means to break them ALL!
+ */
+void keyboard_reset_chains(gint break_chroots);
 
 gboolean keyboard_interactive_grab(guint state, struct _ObClient *client,
                                    struct _ObAction *action);
index e86fb4c6a47f6edee9b0c867e0c620c1d4e208e9..202dd32c9864e55c1623c7b04852bbcead34e871 100644 (file)
@@ -52,17 +52,16 @@ KeyBindingTree *tree_build(GList *keylist)
         return NULL; /* nothing in the list.. */
 
     for (it = g_list_last(keylist); it; it = g_list_previous(it)) {
+        GList *kit;
+
         p = ret;
         ret = g_new0(KeyBindingTree, 1);
-        if (p == NULL) {
-            GList *it;
 
-            /* this is the first built node, the bottom node of the tree */
-            ret->keylist = g_list_copy(keylist); /* shallow copy */
-            for (it = ret->keylist; it; it = g_list_next(it)) /* deep copy */
-                it->data = g_strdup(it->data);
-        }
+        for (kit = it; kit != NULL; kit = g_list_previous(kit))
+            ret->keylist = g_list_prepend(ret->keylist,
+                                          g_strdup(kit->data)); /* deep copy */
         ret->first_child = p;
+        if (p != NULL) p->parent = ret;
         if (!translate_key(it->data, &ret->state, &ret->key)) {
             tree_destroy(ret);
             return NULL;
@@ -93,10 +92,12 @@ void tree_assimilate(KeyBindingTree *node)
                 a = a->first_child;
             }
         }
-        if (!(last->state == b->state && last->key == b->key))
+        if (!(last->state == b->state && last->key == b->key)) {
             last->next_sibling = b;
-        else {
+            b->parent = last->parent;
+        } else {
             last->first_child = b->first_child;
+            last->first_child->parent = last;
             g_free(b);
         }
     }
@@ -129,3 +130,20 @@ KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict)
     }
     return NULL; /* it just isn't in here */
 }
+
+gboolean tree_chroot(KeyBindingTree *tree, GList *keylist)
+{
+    guint key, state;
+    if (translate_key(keylist->data, &state, &key)) {
+        while (tree != NULL && !(tree->state == state && tree->key == key))
+            tree = tree->next_sibling;
+        if (tree != NULL) {
+            if (keylist->next == NULL) {
+                tree->chroot = TRUE;
+                return TRUE;
+            } else
+                return tree_chroot(tree->first_child, keylist->next);
+        }
+    }
+    return FALSE;
+}
index c3be065959a78c9286b848d4f2042236f569cd63..d3544f80b6988f392d102d9cd5795c0a829e8182 100644 (file)
@@ -28,7 +28,10 @@ typedef struct KeyBindingTree {
     guint key;
     GList *keylist;
     GSList *actions; /* list of Action pointers */
+    gboolean chroot;
 
+    /* the level up in the tree */
+    struct KeyBindingTree *parent; 
     /* the next binding in the tree at the same level */
     struct KeyBindingTree *next_sibling; 
     /* the first child of this binding (next binding in a chained sequence).*/
@@ -39,5 +42,7 @@ void tree_destroy(KeyBindingTree *tree);
 KeyBindingTree *tree_build(GList *keylist);
 void tree_assimilate(KeyBindingTree *node);
 KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict);
+gboolean tree_chroot(KeyBindingTree *tree, GList *keylist);
+
 
 #endif
index 7197868b79c76230fd335813b57bc20f5b43854a..9aed40aa8d6311bffc4adb20da9635a94ac83849 100644 (file)
@@ -360,7 +360,7 @@ void menu_free(ObMenu *menu)
     g_hash_table_remove(menu_hash, menu->name);
 }
 
-void menu_show(gchar *name, gint x, gint y, ObClient *client)
+void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client)
 {
     ObMenu *self;
     ObMenuFrame *frame;
@@ -379,7 +379,7 @@ void menu_show(gchar *name, gint x, gint y, ObClient *client)
     menu_frame_hide_all();
 
     frame = menu_frame_new(self, client);
-    if (!menu_frame_show_topmenu(frame, x, y))
+    if (!menu_frame_show_topmenu(frame, x, y, button))
         menu_frame_free(frame);
     else if (frame->entries) {
         ObMenuEntryFrame *e = frame->entries->data;
@@ -515,6 +515,11 @@ void menu_set_destroy_func(ObMenu *self, ObMenuDestroyFunc func)
     self->destroy_func = func;
 }
 
+void menu_set_place_func(ObMenu *self, ObMenuPlaceFunc func)
+{
+    self->place_func = func;
+}
+
 ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id)
 {
     ObMenuEntry *ret = NULL;
index 2315351ab37c4796f84076896e729e230ae87335..fc859a8b1675d79df00a0f558c8b4365909e8fed 100644 (file)
@@ -41,6 +41,13 @@ typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
 typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
                                   guint state, gpointer data, Time time);
 typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
+/*! @param x is the mouse x coordinate. on return it should be the x coordinate
+             for the menu
+    @param y is the mouse y coordinate. on return it should be the y coordinate
+             for the menu
+*/
+typedef void (*ObMenuPlaceFunc)(struct _ObMenuFrame *frame, gint *x, gint *y,
+                                gint button, gpointer data);
 
 struct _ObMenu
 {
@@ -70,6 +77,7 @@ struct _ObMenu
     ObMenuUpdateFunc update_func;
     ObMenuExecuteFunc execute_func;
     ObMenuDestroyFunc destroy_func;
+    ObMenuPlaceFunc place_func;
 
     /* Pipe-menu parent, we get destroyed when it is destroyed */
     ObMenu *pipe_creator;
@@ -144,11 +152,13 @@ void menu_pipe_execute(ObMenu *self);
 
 void menu_show_all_shortcuts(ObMenu *self, gboolean show);
 
-void menu_show(gchar *name, gint x, gint y, struct _ObClient *client);
+void menu_show(gchar *name, gint x, gint y, gint button,
+               struct _ObClient *client);
 
 void menu_set_update_func(ObMenu *menu, ObMenuUpdateFunc func);
 void menu_set_execute_func(ObMenu *menu, ObMenuExecuteFunc func);
 void menu_set_destroy_func(ObMenu *menu, ObMenuDestroyFunc func);
+void menu_set_place_func(ObMenu *menu, ObMenuPlaceFunc func);
 
 /* functions for building menus */
 /*! @param allow_shortcut this should be false when the label is coming from
index 7ca2136ca1f13ab98947be969788331ffb36e147..25131435644ec5ccccb19cc0a652aed74330e8f3 100644 (file)
@@ -209,21 +209,69 @@ void menu_frame_move(ObMenuFrame *self, gint x, gint y)
     XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
 }
 
-void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y)
+static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
 {
-    if (self->client && x < 0 && y < 0) {
-        x = self->client->frame->area.x + self->client->frame->size.left;
-        y = self->client->frame->area.y + self->client->frame->size.top;
+    gint dx, dy;
+
+    if (config_menu_middle) {
+        gint myx;
+
+        myx = *x;
+        *y -= self->area.height / 2;
+
+        /* try to the right of the cursor */
+        menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        if (dx != 0) {
+            /* try to the left of the cursor */
+            myx = *x - self->area.width;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        if (dx != 0) {
+            /* if didnt fit on either side so just use what it says */
+            myx = *x;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        *x = myx + dx;
+        *y += dy;
     } else {
-        if (config_menu_middle)
-            y -= self->area.height / 2;
+        gint myx, myy;
+
+        myx = *x;
+        myy = *y;
+
+        /* try to the bottom right of the cursor */
+        menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        if (dx != 0 || dy != 0) {
+            /* try to the bottom left of the cursor */
+            myx = *x - self->area.width;
+            myy = *y;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* try to the top right of the cursor */
+            myx = *x;
+            myy = *y - self->area.height;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* try to the top left of the cursor */
+            myx = *x - self->area.width;
+            myy = *y - self->area.height;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        if (dx != 0 || dy != 0) {
+            /* if didnt fit on either side so just use what it says */
+            myx = *x;
+            myy = *y;
+            menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        }
+        *x = myx + dx;
+        *y = myy + dy;
     }
-    menu_frame_move(self, x, y);
 }
 
-void menu_frame_place_submenu(ObMenuFrame *self)
+static void menu_frame_place_submenu(ObMenuFrame *self, gint *x, gint *y)
 {
-    gint x, y;
     gint overlap;
     gint bwidth;
 
@@ -231,20 +279,20 @@ void menu_frame_place_submenu(ObMenuFrame *self)
     bwidth = ob_rr_theme->mbwidth;
 
     if (self->direction_right)
-        x = self->parent->area.x + self->parent->area.width - overlap - bwidth;
+        *x = self->parent->area.x + self->parent->area.width -
+            overlap - bwidth;
     else
-        x = self->parent->area.x - self->area.width + overlap + bwidth;
+        *x = self->parent->area.x - self->area.width + overlap + bwidth;
 
-    y = self->parent->area.y + self->parent_entry->area.y;
+    *y = self->parent->area.y + self->parent_entry->area.y;
     if (config_menu_middle)
-        y -= (self->area.height - (bwidth * 2) - self->item_h) / 2;
+        *y -= (self->area.height - (bwidth * 2) - self->item_h) / 2;
     else
-        y += overlap;
-
-    menu_frame_move(self, x, y);
+        *y += overlap;
 }
 
-void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy)
+void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y,
+                               gint *dx, gint *dy)
 {
     Rect *a = NULL;
     gint pos, half;
@@ -259,16 +307,16 @@ void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy)
     /* if in the bottom half then check this stuff first, will keep the bottom
        edge of the menu visible */
     if (pos > half) {
-        *dx = MAX(*dx, a->x - self->area.x);
-        *dy = MAX(*dy, a->y - self->area.y);
+        *dx = MAX(*dx, a->x - x);
+        *dy = MAX(*dy, a->y - y);
     }
-    *dx = MIN(*dx, (a->x + a->width) - (self->area.x + self->area.width));
-    *dy = MIN(*dy, (a->y + a->height) - (self->area.y + self->area.height));
+    *dx = MIN(*dx, (a->x + a->width) - (x + self->area.width));
+    *dy = MIN(*dy, (a->y + a->height) - (y + self->area.height));
     /* if in the top half then check this stuff last, will keep the top
        edge of the menu visible */
     if (pos <= half) {
-        *dx = MAX(*dx, a->x - self->area.x);
-        *dy = MAX(*dy, a->y - self->area.y);
+        *dx = MAX(*dx, a->x - x);
+        *dy = MAX(*dy, a->y - y);
     }
 }
 
@@ -723,9 +771,9 @@ static gboolean menu_frame_show(ObMenuFrame *self)
     return TRUE;
 }
 
-gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y)
+gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y,
+                                 gint button)
 {
-    gint dx, dy;
     guint i;
 
     if (menu_frame_is_visible(self))
@@ -733,8 +781,6 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y)
     if (!menu_frame_show(self))
         return FALSE;
 
-    menu_frame_place_topmenu(self, x, y);
-
     /* find the monitor the menu is on */
     for (i = 0; i < screen_num_monitors; ++i) {
         Rect *a = screen_physical_area_monitor(i);
@@ -744,8 +790,12 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y)
         }
     }
 
-    menu_frame_move_on_screen(self, &dx, &dy);
-    menu_frame_move(self, self->area.x + dx, self->area.y + dy);
+    if (self->menu->place_func)
+        self->menu->place_func(self, &x, &y, button, self->menu->data);
+    else
+        menu_frame_place_topmenu(self, &x, &y);
+
+    menu_frame_move(self, x, y);
 
     XMapWindow(ob_display, self->window);
 
@@ -756,7 +806,7 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
                                  ObMenuEntryFrame *parent_entry)
 {
     ObMenuEntryFrame *e;
-    gint dx, dy;
+    gint x, y, dx, dy;
 
     if (menu_frame_is_visible(self))
         return TRUE;
@@ -773,29 +823,16 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
     if (!menu_frame_show(self))
         return FALSE;
 
-    menu_frame_place_submenu(self);
-    menu_frame_move_on_screen(self, &dx, &dy);
-
-    if (dx == 0) {
-        menu_frame_move(self, self->area.x, self->area.y + dy);
-    } else {
-        gboolean dir;
+    menu_frame_place_submenu(self, &x, &y);
+    menu_frame_move_on_screen(self, x, y, &dx, &dy);
 
-        /* flip the direction in which we're placing submenus */
-        if (dx > 0)
-            dir = TRUE;
-        else
-            dir = FALSE;
-
-        /* if it changed, then replace the menu on the opposite side,
-           and try keep it on the screen too */
-        if (dir != self->direction_right) {
-            self->direction_right = dir;
-            menu_frame_place_submenu(self);
-            menu_frame_move_on_screen(self, &dx, &dy);
-            menu_frame_move(self, self->area.x + dx, self->area.y + dy);
-        }
+    if (dx != 0) {
+        /*try the other side */
+        self->direction_right = !self->direction_right;
+        menu_frame_place_submenu(self, &x, &y);
+        menu_frame_move_on_screen(self, x, y, &dx, &dy);
     }
+    menu_frame_move(self, x + dx, y + dy);
 
     XMapWindow(ob_display, self->window);
 
index 4cd27d3767c74f767c2392b0032c9abcd70bf028..5c87683201bbc15757e4478c4541c2133f6d00be 100644 (file)
@@ -111,12 +111,11 @@ ObMenuFrame* menu_frame_new(struct _ObMenu *menu, struct _ObClient *client);
 void menu_frame_free(ObMenuFrame *self);
 
 void menu_frame_move(ObMenuFrame *self, gint x, gint y);
-void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy);
+void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y,
+                               gint *dx, gint *dy);
 
-void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y);
-void menu_frame_place_submenu(ObMenuFrame *self);
-
-gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y);
+gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y,
+                                 gint button);
 gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
                                  ObMenuEntryFrame *parent_entry);
 void menu_frame_hide(ObMenuFrame *self);
index 8692a9d10dd195300d771e223d518a3ea3aba5c6..50b4208fb6a0f6b429f2215362ae0d3d2d8b536d 100644 (file)
@@ -252,19 +252,17 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
     if (t->shortcut) {
         const gchar *c = t->string + t->shortcut_pos;
 
-        if (g_utf8_validate(c, -1, NULL)) {
-            t->font->shortcut_underline->start_index = t->shortcut_pos;
-            t->font->shortcut_underline->end_index = t->shortcut_pos +
-                (g_utf8_next_char(c) - c);
-
-            /* the attributes are owned by the layout.
-               re-add the attributes to the layout after changing the
-               start and end index */
-            attrlist = pango_layout_get_attributes(t->font->layout);
-            pango_attr_list_ref(attrlist);
-            pango_layout_set_attributes(t->font->layout, attrlist);
-            pango_attr_list_unref(attrlist);
-        }
+        t->font->shortcut_underline->start_index = t->shortcut_pos;
+        t->font->shortcut_underline->end_index = t->shortcut_pos +
+            (g_utf8_next_char(c) - c);
+
+        /* the attributes are owned by the layout.
+           re-add the attributes to the layout after changing the
+           start and end index */
+        attrlist = pango_layout_get_attributes(t->font->layout);
+        pango_attr_list_ref(attrlist);
+        pango_layout_set_attributes(t->font->layout, attrlist);
+        pango_attr_list_unref(attrlist);
     }
 
     /* layout_line() uses y to specify the baseline