Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Thu, 17 Dec 2009 15:33:39 +0000 (10:33 -0500)
committerDana Jansens <danakj@orodu.net>
Thu, 17 Dec 2009 15:33:39 +0000 (10:33 -0500)
142 files changed:
.gitignore
Makefile.am
README.GIT
configure.ac
data/rc.xml
m4/openbox.m4
m4/x11.m4
obt/Makefile [moved from parser/Makefile with 100% similarity]
obt/display.c [new file with mode: 0644]
obt/display.h [new file with mode: 0644]
obt/internal.h [moved from openbox/xerror.h with 70% similarity]
obt/keyboard.c [moved from openbox/modkeys.c with 65% similarity]
obt/keyboard.h [moved from openbox/modkeys.h with 51% similarity]
obt/mainloop.c [moved from openbox/mainloop.c with 75% similarity]
obt/mainloop.h [new file with mode: 0644]
obt/obt-4.0.pc.in [new file with mode: 0644]
obt/parse.c [new file with mode: 0644]
obt/parse.h [new file with mode: 0644]
obt/paths.c [new file with mode: 0644]
obt/paths.h [new file with mode: 0644]
obt/prop.c [new file with mode: 0644]
obt/prop.h [new file with mode: 0644]
obt/util.h [new file with mode: 0644]
obt/version.h.in [new file with mode: 0644]
obt/xevent.c [new file with mode: 0644]
obt/xevent.h [new file with mode: 0644]
openbox/actions.c
openbox/actions.h
openbox/actions/addremovedesktop.c
openbox/actions/all.c
openbox/actions/all.h
openbox/actions/breakchroot.c
openbox/actions/close.c
openbox/actions/cyclewindows.c
openbox/actions/debug.c
openbox/actions/decorations.c
openbox/actions/desktop.c
openbox/actions/directionalwindows.c
openbox/actions/dockautohide.c
openbox/actions/execute.c
openbox/actions/exit.c
openbox/actions/focus.c
openbox/actions/focustobottom.c
openbox/actions/fullscreen.c
openbox/actions/growtoedge.c
openbox/actions/iconify.c
openbox/actions/if.c
openbox/actions/kill.c
openbox/actions/layer.c
openbox/actions/lower.c
openbox/actions/maximize.c
openbox/actions/move.c
openbox/actions/moverelative.c
openbox/actions/moveresizeto.c
openbox/actions/movetoedge.c
openbox/actions/omnipresent.c
openbox/actions/raise.c
openbox/actions/raiselower.c
openbox/actions/reconfigure.c
openbox/actions/resize.c
openbox/actions/resizerelative.c
openbox/actions/restart.c
openbox/actions/session.c [new file with mode: 0644]
openbox/actions/shade.c
openbox/actions/shadelowerraise.c [new file with mode: 0644]
openbox/actions/showdesktop.c
openbox/actions/showmenu.c
openbox/actions/unfocus.c
openbox/client.c
openbox/client.h
openbox/client_menu.c
openbox/client_menu.h
openbox/config.c
openbox/config.h
openbox/debug.c
openbox/debug.h
openbox/dock.c
openbox/dock.h
openbox/event.c
openbox/event.h
openbox/extensions.c [deleted file]
openbox/extensions.h [deleted file]
openbox/focus.c
openbox/focus.h
openbox/focus_cycle.c
openbox/focus_cycle.h
openbox/focus_cycle_indicator.c
openbox/focus_cycle_popup.c
openbox/focus_cycle_popup.h
openbox/frame.c
openbox/framerender.c
openbox/grab.c
openbox/grab.h
openbox/keyboard.c
openbox/keyboard.h
openbox/mainloop.h [deleted file]
openbox/menu.c
openbox/menu.h
openbox/menuframe.c
openbox/menuframe.h
openbox/mouse.c
openbox/mouse.h
openbox/moveresize.c
openbox/openbox.c
openbox/openbox.h
openbox/ping.c
openbox/place.c
openbox/popup.c
openbox/popup.h
openbox/prompt.c
openbox/prompt.h
openbox/prop.c [deleted file]
openbox/prop.h [deleted file]
openbox/resist.c
openbox/resist.h
openbox/screen.c
openbox/screen.h
openbox/session.c
openbox/stacking.c
openbox/stacking.h
openbox/startupnotify.c
openbox/startupnotify.h
openbox/translate.c
openbox/translate.h
openbox/window.c
openbox/window.h
openbox/xerror.c [deleted file]
parser/obparser-3.0.pc.in [deleted file]
parser/parse.c [deleted file]
parser/parse.h [deleted file]
po/POTFILES.in
render/color.c
render/font.c
render/image.c
render/obrender-4.0.pc.in [moved from render/obrender-3.0.pc.in with 63% similarity]
render/render.h
render/theme.c
render/theme.h
render/version.h.in [new file with mode: 0644]
tests/mingrow.c [new file with mode: 0644]
tests/overrideinputonly.c [new file with mode: 0644]
version.h.in [deleted file]

index e1e0e41..fa2b390 100644 (file)
@@ -32,7 +32,7 @@ m4/*.m4
 missing
 .dirstamp
 openbox/openbox
-parser/obparser-3.0.pc
+parser/obparser-4.0.pc
 po/Makefile.in.in
 po/Makevars.template
 po/POTFILES
@@ -48,7 +48,8 @@ po/en@boldquot.insert-header
 po/en@quot.insert-header
 po/remove-potcdate.sed
 *.gmo
-render/obrender-3.0.pc
+render/obrender-4.0.pc
+obt/obt-4.0.pc
 tools/gnome-panel-control/gnome-panel-control
 tools/gdm-control/gdm-control
 tools/obprop/obprop
index 4b3e0b5..4384054 100644 (file)
@@ -8,7 +8,8 @@ rcdir           = $(configdir)/openbox
 xsessionsdir    = $(datadir)/xsessions
 gnomewmfilesdir = $(datadir)/gnome/wm-properties
 pkgconfigdir    = $(libdir)/pkgconfig
-pubincludedir   = $(includedir)/openbox/@OB_VERSION@/openbox
+obtpubincludedir= $(includedir)/openbox/@OBT_VERSION@/obt
+rrpubincludedir = $(includedir)/openbox/@RR_VERSION@/render
 pixmapdir       = $(datadir)/pixmaps
 xsddir          = $(datadir)/openbox
 secretbindir    = $(libdir)/openbox
@@ -26,7 +27,7 @@ check_PROGRAMS = \
        render/rendertest
 
 lib_LTLIBRARIES = \
-       parser/libobparser.la \
+       obt/libobt.la \
        render/libobrender.la
 
 bin_PROGRAMS = \
@@ -47,15 +48,13 @@ nodist_bin_SCRIPTS = \
 
 render_rendertest_CPPFLAGS = \
        $(PANGO_CFLAGS) \
-       $(XFT_CFLAGS) \
        $(GLIB_CFLAGS) \
        -DG_LOG_DOMAIN=\"RenderTest\"
 render_rendertest_LDADD = \
-       parser/libobparser.la \
+       obt/libobt.la \
        render/libobrender.la \
        $(GLIB_LIBS) \
        $(PANGO_LIBS) \
-       $(XFT_LIBS) \
        $(XML_LIBS) \
        $(X_LIBS)
 render_rendertest_SOURCES = render/test.c
@@ -65,16 +64,14 @@ render_libobrender_la_CPPFLAGS = \
        $(GLIB_CFLAGS) \
        $(XML_CFLAGS) \
        $(PANGO_CFLAGS) \
-       $(XFT_CFLAGS) \
        -DG_LOG_DOMAIN=\"ObRender\" \
        -DDEFAULT_THEME=\"$(theme)\"
 render_libobrender_la_LDFLAGS = \
-       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+       -version-info $(RR_CURRENT):$(RR_REVISION):$(RR_AGE)
 render_libobrender_la_LIBADD = \
-       parser/libobparser.la \
+       obt/libobt.la \
        $(X_LIBS) \
        $(PANGO_LIBS) \
-       $(XFT_LIBS) \
        $(GLIB_LIBS) \
        $(XML_LIBS)
 render_libobrender_la_SOURCES = \
@@ -100,33 +97,52 @@ render_libobrender_la_SOURCES = \
        render/theme.h \
        render/theme.c
 
-## parser ##
+## obt ##
 
-parser_libobparser_la_CPPFLAGS = \
+obt_libobt_la_CPPFLAGS = \
+       $(XINERAMA_CFLAGS) \
+       $(XKB_CFLAGS) \
+       $(XRANDR_CFLAGS) \
+       $(XSHAPE_CFLAGS) \
+       $(XSYNC_CFLAGS) \
        $(GLIB_CFLAGS) \
        $(XML_CFLAGS) \
-       -DG_LOG_DOMAIN=\"ObParser\" \
+       -DG_LOG_DOMAIN=\"Obt\" \
        -DLOCALEDIR=\"$(localedir)\" \
        -DDATADIR=\"$(datadir)\" \
        -DCONFIGDIR=\"$(configdir)\"
-parser_libobparser_la_LDFLAGS = \
-       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-parser_libobparser_la_LIBADD = \
+obt_libobt_la_LDFLAGS = \
+       -version-info $(OBT_CURRENT):$(OBT_REVISION):$(OBT_AGE)
+obt_libobt_la_LIBADD = \
+       $(XINERAMA_LIBS) \
+       $(XKB_LIBS) \
+       $(XRANDR_LIBS) \
+       $(XSHAPE_LIBS) \
+       $(XSYNC_LIBS) \
        $(GLIB_LIBS) \
-       $(XML_LIBS) 
-parser_libobparser_la_SOURCES = \
-       parser/parse.h \
-       parser/parse.c
+       $(XML_LIBS)
+obt_libobt_la_SOURCES = \
+       obt/display.h \
+       obt/display.c \
+       obt/internal.h \
+       obt/keyboard.h \
+       obt/keyboard.c \
+       obt/mainloop.h \
+       obt/mainloop.c \
+       obt/parse.h \
+       obt/parse.c \
+       obt/paths.h \
+       obt/paths.c \
+       obt/prop.h \
+       obt/prop.c \
+       obt/util.h \
+       obt/xevent.h \
+       obt/xevent.c
 
 ## openbox ##
 
 openbox_openbox_CPPFLAGS = \
        $(SM_CFLAGS) \
-       $(XINERAMA_CFLAGS) \
-       $(XKB_CFLAGS) \
-       $(XRANDR_CFLAGS) \
-       $(XSHAPE_CFLAGS) \
-       $(XSYNC_CFLAGS) \
        $(X_CFLAGS) \
        $(XCURSOR_CFLAGS) \
        $(SM_CFLAGS) \
@@ -140,11 +156,6 @@ openbox_openbox_CPPFLAGS = \
        -DG_LOG_DOMAIN=\"Openbox\"
 openbox_openbox_LDADD = \
        $(SM_LIBS) \
-       $(XINERAMA_LIBS) \
-       $(XKB_LIBS) \
-       $(XRANDR_LIBS) \
-       $(XSHAPE_LIBS) \
-       $(XSYNC_LIBS) \
        $(GLIB_LIBS) \
        $(X_LIBS) \
        $(XCURSOR_LIBS) \
@@ -153,7 +164,7 @@ openbox_openbox_LDADD = \
        $(EFENCE_LIBS) \
        $(LIBINTL) \
        render/libobrender.la \
-       parser/libobparser.la
+       obt/libobt.la
 openbox_openbox_LDFLAGS = -export-dynamic
 openbox_openbox_SOURCES = \
        gettext.h \
@@ -192,6 +203,7 @@ openbox_openbox_SOURCES = \
        openbox/actions/resizerelative.c \
        openbox/actions/restart.c \
        openbox/actions/shade.c \
+       openbox/actions/shadelowerraise.c \
        openbox/actions/showdesktop.c \
        openbox/actions/showmenu.c \
        openbox/actions/unfocus.c \
@@ -213,8 +225,6 @@ openbox_openbox_SOURCES = \
        openbox/dock.h \
        openbox/event.c \
        openbox/event.h \
-       openbox/extensions.c \
-       openbox/extensions.h \
        openbox/focus.c \
        openbox/focus.h \
        openbox/focus_cycle.c \
@@ -236,15 +246,11 @@ openbox_openbox_SOURCES = \
        openbox/keyboard.h \
        openbox/keytree.c \
        openbox/keytree.h \
-       openbox/mainloop.c \
-       openbox/mainloop.h \
        openbox/menuframe.c \
        openbox/menuframe.h \
        openbox/menu.c \
        openbox/menu.h \
        openbox/misc.h \
-       openbox/modkeys.c \
-       openbox/modkeys.h \
        openbox/mouse.c \
        openbox/mouse.h \
        openbox/moveresize.c \
@@ -260,8 +266,6 @@ openbox_openbox_SOURCES = \
        openbox/prompt.h \
        openbox/popup.c \
        openbox/popup.h \
-       openbox/prop.c \
-       openbox/prop.h \
        openbox/resist.c \
        openbox/resist.h \
        openbox/screen.c \
@@ -275,10 +279,7 @@ openbox_openbox_SOURCES = \
        openbox/translate.c \
        openbox/translate.h \
        openbox/window.c \
-       openbox/window.h \
-       openbox/xerror.c \
-       openbox/xerror.h
-
+       openbox/window.h
 
 ## gnome-panel-control ##
 
@@ -406,7 +407,7 @@ dist_syscrash_theme_DATA= \
 
 ## public headers ##
 
-pubinclude_HEADERS = \
+rrpubinclude_HEADERS = \
        render/color.h \
        render/font.h \
        render/geom.h \
@@ -416,14 +417,22 @@ pubinclude_HEADERS = \
        render/mask.h \
        render/render.h \
        render/theme.h \
-       parser/parse.h
-
-nodist_pubinclude_HEADERS = \
-       version.h
+       render/version.h
+
+obtpubinclude_HEADERS = \
+       obt/display.h \
+       obt/keyboard.h \
+       obt/mainloop.h \
+       obt/parse.h \
+       obt/paths.h \
+       obt/prop.h \
+       obt/util.h \
+       obt/version.h \
+       obt/xevent.h
 
 nodist_pkgconfig_DATA = \
-       render/obrender-3.0.pc \
-       parser/obparser-3.0.pc
+       render/obrender-4.0.pc \
+       obt/obt-4.0.pc
 
 ## data ##
 
@@ -475,7 +484,6 @@ nodist_xsessions_DATA = \
        data/xsession/openbox-kde.desktop
 
 dist_noinst_DATA = \
-       version.h.in \
        data/autostart.sh.in \
        data/rc.xsd \
        data/menu.xsd \
@@ -493,8 +501,10 @@ dist_noinst_DATA = \
        doc/openbox-gnome-session.1.in \
        doc/openbox-kde-session.1.sgml \
        doc/openbox-kde-session.1.in \
-       render/obrender-3.0.pc.in \
-       parser/obparser-3.0.pc.in \
+       render/version.h.in \
+       render/obrender-4.0.pc.in \
+       obt/obt-4.0.pc.in \
+       obt/version.h.in \
        tools/themeupdate/themeupdate.py \
        tests/hideshow.py \
        tests/Makefile \
@@ -550,7 +560,7 @@ CLEANFILES = \
 #       $(MAKE) -$(MAKEFLAGS) -C doc/doxygen doc
 
 distclean-local:
-       for d in . m4 po render; do \
+       for d in . m4 po render parser obt openbox; do \
                for p in core core.* gmon.out *\~ *.orig *.rej .\#*; do \
                        rm -f "$$d/$$p"; \
                done \
index c50118e..b4b0557 100644 (file)
@@ -3,7 +3,7 @@ To build Openbox from git you need:
 A C Compiler (GNU GCC 3.2+ suggested)
 GNU Gettext 0.14.4
 GNU Autoconf 2.50+
-GNU Automake 1.9+
+GNU Automake 1.9 (no more, no less)
 GNU Libtool
 Xlib library/headers (devel package)
 Pkg-Config
index bba1b5c..78d0753 100644 (file)
@@ -4,41 +4,65 @@ AM_INIT_AUTOMAKE
 AC_CONFIG_SRCDIR([openbox/openbox.c])
 
 dnl Making releases:
-dnl   OB_MICRO_VERSION += 1;
-dnl   OB_INTERFACE_AGE += 1;
-dnl   OB_BINARY_AGE += 1;
-dnl if any functions have been added, set OB_INTERFACE_AGE to 0.
+dnl   RR_MICRO_VERSION += 1;
+dnl   RR_INTERFACE_AGE += 1;
+dnl   R_BINARY_AGE += 1;
+dnl if any functions have been added, set RR_INTERFACE_AGE to 0.
 dnl if backwards compatibility has been broken,
-dnl set OB_BINARY_AGE and OB_INTERFACE_AGE to 0.
+dnl set RR_BINARY_AGE and RR_INTERFACE_AGE to 0.
 dnl
 dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
 dnl
-OB_MAJOR_VERSION=3
-OB_MINOR_VERSION=4
-OB_MICRO_VERSION=16
-OB_INTERFACE_AGE=0
-OB_BINARY_AGE=0
-OB_VERSION=$OB_MAJOR_VERSION.$OB_MINOR_VERSION
-
-AC_SUBST(OB_MAJOR_VERSION)
-AC_SUBST(OB_MINOR_VERSION)
-AC_SUBST(OB_MICRO_VERSION)
-AC_SUBST(OB_INTERFACE_AGE)
-AC_SUBST(OB_BINARY_AGE)
-AC_SUBST(OB_VERSION)
+RR_MAJOR_VERSION=4
+RR_MINOR_VERSION=0
+RR_MICRO_VERSION=17
+RR_INTERFACE_AGE=0
+RR_BINARY_AGE=0
+RR_VERSION=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
+
+OBT_MAJOR_VERSION=4
+OBT_MINOR_VERSION=0
+OBT_MICRO_VERSION=0
+OBT_INTERFACE_AGE=0
+OBT_BINARY_AGE=0
+OBT_VERSION=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
+
+AC_SUBST(RR_MAJOR_VERSION)
+AC_SUBST(RR_MINOR_VERSION)
+AC_SUBST(RR_MICRO_VERSION)
+AC_SUBST(RR_INTERFACE_AGE)
+AC_SUBST(RR_BINARY_AGE)
+AC_SUBST(RR_VERSION)
+AC_SUBST(OBT_MAJOR_VERSION)
+AC_SUBST(OBT_MINOR_VERSION)
+AC_SUBST(OBT_MICRO_VERSION)
+AC_SUBST(OBT_INTERFACE_AGE)
+AC_SUBST(OBT_BINARY_AGE)
+AC_SUBST(OBT_VERSION)
 
 dnl Libtool versioning
-LT_RELEASE=$OB_MAJOR_VERSION.$OB_MINOR_VERSION
-LT_CURRENT=`expr $OB_MICRO_VERSION - $OB_INTERFACE_AGE`
-LT_REVISION=$OB_INTERFACE_AGE
-LT_AGE=`expr $OB_BINARY_AGE - $OB_INTERFACE_AGE`
-LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
-
-AC_SUBST(LT_RELEASE)
-AC_SUBST(LT_CURRENT)
-AC_SUBST(LT_REVISION)
-AC_SUBST(LT_AGE)
-AC_SUBST(LT_CURRENT_MINUS_AGE)
+RR_RELEASE=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
+RR_CURRENT=`expr $RR_MICRO_VERSION - $RR_INTERFACE_AGE`
+RR_REVISION=$RR_INTERFACE_AGE
+RR_AGE=`expr $RR_BINARY_AGE - $RR_INTERFACE_AGE`
+RR_CURRENT_MINUS_AGE=`expr $RR_CURRENT - $RR_AGE`
+
+OBT_RELEASE=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
+OBT_CURRENT=`expr $OBT_MICRO_VERSION - $OBT_INTERFACE_AGE`
+OBT_REVISION=$OBT_INTERFACE_AGE
+OBT_AGE=`expr $OBT_BINARY_AGE - $OBT_INTERFACE_AGE`
+OBT_CURRENT_MINUS_AGE=`expr $OBT_CURRENT - $OBT_AGE`
+
+AC_SUBST(RR_RELEASE)
+AC_SUBST(RR_CURRENT)
+AC_SUBST(RR_REVISION)
+AC_SUBST(RR_AGE)
+AC_SUBST(RR_CURRENT_MINUS_AGE)
+AC_SUBST(OBT_RELEASE)
+AC_SUBST(OBT_CURRENT)
+AC_SUBST(OBT_REVISION)
+AC_SUBST(OBT_AGE)
+AC_SUBST(OBT_CURRENT_MINUS_AGE)
 
 AC_PREFIX_DEFAULT([/usr/local])
 test "$prefix" = "NONE" && prefix=$ac_default_prefix
@@ -78,10 +102,6 @@ PKG_CHECK_MODULES(PANGO, [pango >= 1.8.0 pangoxft >= 1.8.0])
 AC_SUBST(PANGO_CFLAGS)
 AC_SUBST(PANGO_LIBS)
 
-PKG_CHECK_MODULES(XFT, [xft])
-AC_SUBST(XFT_CFLAGS)
-AC_SUBST(XFT_LIBS)
-
 PKG_CHECK_MODULES(XML, [libxml-2.0 >= 2.6.0])
 AC_SUBST(XML_CFLAGS)
 AC_SUBST(XML_LIBS)
@@ -154,9 +174,10 @@ AC_CONFIG_FILES([
   Makefile
   m4/Makefile
   po/Makefile.in
-  render/obrender-3.0.pc
-  parser/obparser-3.0.pc
-  version.h
+  render/obrender-4.0.pc
+  obt/obt-4.0.pc
+  render/version.h
+  obt/version.h
 ])
 AC_CONFIG_COMMANDS([doc],
                    [test -d doc || mkdir doc])
index d7a31bd..dc73fb5 100644 (file)
     </action>
   </keybind>
 
+  <!-- Keybindings for window switching with the arrow keys -->
+  <keybind key="W-S-Right">
+    <action name="DirectionalCycleWindows">
+      <direction>right</direction>
+    </action>
+  </keybind>
+  <keybind key="W-S-Left">
+    <action name="DirectionalCycleWindows">
+      <direction>left</direction>
+    </action>
+  </keybind>
+  <keybind key="W-S-Up">
+    <action name="DirectionalCycleWindows">
+      <direction>up</direction>
+    </action>
+  </keybind>
+  <keybind key="W-S-Down">
+    <action name="DirectionalCycleWindows">
+      <direction>down</direction>
+    </action>
+  </keybind>
+
   <!-- Keybindings for running applications -->
   <keybind key="W-e">
     <action name="Execute">
     </mousebind>
 
     <mousebind button="Up" action="Click">
-      <action name="Shade"/>
-      <action name="FocusToBottom"/>
-      <action name="Unfocus"/>
-      <action name="Lower"/>
+      <action name="if">
+        <shaded>no</shaded>
+        <then>
+          <action name="Shade"/>
+          <action name="FocusToBottom"/>
+          <action name="Unfocus"/>
+          <action name="Lower"/>
+        </then>
+      </action>
     </mousebind>
     <mousebind button="Down" action="Click">
-      <action name="Unshade"/>
-      <action name="Raise"/>
+      <action name="if">
+        <shaded>yes</shaded>
+        <then>
+          <action name="Unshade"/>
+          <action name="Raise"/>
+        </then>
+      </action>
     </mousebind>
 
     <mousebind button="Right" action="Press">
   </context>
 
   <context name="Desktop">
-    <mousebind button="Up" action="Press">
+    <mousebind button="Up" action="Click">
       <action name="GoToDesktop"><to>previous</to></action>
     </mousebind>
-    <mousebind button="Down" action="Press">
+    <mousebind button="Down" action="Click">
       <action name="GoToDesktop"><to>next</to></action>
     </mousebind>
 
-    <mousebind button="A-Up" action="Press">
+    <mousebind button="A-Up" action="Click">
       <action name="GoToDesktop"><to>previous</to></action>
     </mousebind>
-    <mousebind button="A-Down" action="Press">
+    <mousebind button="A-Down" action="Click">
       <action name="GoToDesktop"><to>next</to></action>
     </mousebind>
-    <mousebind button="C-A-Up" action="Press">
+    <mousebind button="C-A-Up" action="Click">
       <action name="GoToDesktop"><to>previous</to></action>
     </mousebind>
-    <mousebind button="C-A-Down" action="Press">
+    <mousebind button="C-A-Down" action="Click">
       <action name="GoToDesktop"><to>next</to></action>
     </mousebind>
 
   </context>
 
   <context name="MoveResize">
-    <mousebind button="Up" action="Press">
+    <mousebind button="Up" action="Click">
       <action name="GoToDesktop"><to>previous</to></action>
     </mousebind>
-    <mousebind button="Down" action="Press">
+    <mousebind button="Down" action="Click">
       <action name="GoToDesktop"><to>next</to></action>
     </mousebind>
-    <mousebind button="A-Up" action="Press">
+    <mousebind button="A-Up" action="Click">
       <action name="GoToDesktop"><to>previous</to></action>
     </mousebind>
-    <mousebind button="A-Down" action="Press">
+    <mousebind button="A-Down" action="Click">
       <action name="GoToDesktop"><to>next</to></action>
     </mousebind>
   </context>
index 5c3aeec..5a95e84 100644 (file)
@@ -74,7 +74,7 @@ AC_DEFUN([OB_COMPILER_FLAGS],
     if test "$GCC" = "yes"; then
        AC_MSG_RESULT([yes])
        if test "$DEBUG" = "yes"; then
-           FLAGS="$FLAGS -O0 -g3 -fno-inline -Wwrite-strings"
+           FLAGS="$FLAGS -O0 -ggdb -fno-inline -Wwrite-strings"
            FLAGS="$FLAGS -Wall -Wsign-compare -Waggregate-return"
            FLAGS="$FLAGS -Wcast-qual -Wbad-function-cast -Wpointer-arith"
             # for Python.h
index fc7b36e..d840d34 100644 (file)
--- a/m4/x11.m4
+++ b/m4/x11.m4
@@ -29,155 +29,6 @@ AC_DEFUN([X11_DEVEL],
   CPPFLAGS=$OLDCPPFLAGS
 ])
 
-
-AC_DEFUN([XFT_ERROR],
-[
-  if test "$XFT_MIN"; then
-    AC_MSG_ERROR([$PACKAGE requires the Xft font library >= $XFT_MIN.
-                  See http://www.fontconfig.org/
-])
-  else
-    AC_MSG_ERROR([$PACKAGE requires the Xft font library.
-                  See http://www.fontconfig.org/
-])
-  fi
-])
-
-# XFT_DEVEL([required-version])
-#
-# Check for the XFT development package.
-# You can use the optional argument to check for a library of at least the
-# given version.
-# It provides the $(PYTHON_CFLAGS) $(PYTHON_LIBS) output variables.
-AC_DEFUN([XFT_DEVEL],
-[
-  AC_REQUIRE([X11_DEVEL])
-  
-  if test "$1"; then
-    XFT_MIN="$1"
-    XFT_MIN_MAJOR=${XFT_MIN%.*.*}
-    XFT_MIN_MINOR=${XFT_MIN%.*}
-    XFT_MIN_MINOR=${XFT_MIN_MINOR#*.}
-    XFT_MIN_REVISION=${XFT_MIN#*.*.}
-    XFT_MIN="$XFT_MIN_MAJOR.$XFT_MIN_MINOR.$XFT_MIN_REVISION"
-  else
-    XFT_MIN=""
-  fi
-
-  if test -z "$XFT_MIN"; then
-    AC_MSG_CHECKING([for Xft])
-    if ! pkg-config xft; then
-      AC_MSG_RESULT([no])
-      XFT_ERROR
-    fi
-  else
-    AC_MSG_CHECKING([for Xft version >= $XFT_MIN])
-    if ! pkg-config --atleast-version $XFT_MIN xft; then
-      AC_MSG_RESULT([no])
-      XFT_ERROR
-    fi
-  fi
-  AC_MSG_RESULT([yes])
-
-
-  # Store these
-  OLDLIBS=$LIBS
-  OLDCPPFLAGS=$CPPFLAGS
-
-  XFT_CFLAGS="`pkg-config --cflags xft`"
-  XFT_LIBS="`pkg-config --libs xft`"
-
-  # Set these for checking with the tests below. They'll be restored after
-  LIBS="$LIBS $XFT_LIBS"
-  CPPFLAGS="$XFT_CFLAGS $CPPFLAGS"
-
-  AC_CHECK_LIB([Xft], [XftGetVersion], # this was not defined in < 2.0
-    if test "$XFT_MIN"; then
-      AC_MSG_CHECKING([for X11/Xft/Xft.h for Xft >= $XFT_MIN])
-      AC_TRY_COMPILE(
-      [
-        #include <X11/Xlib.h>
-        #include <X11/Xft/Xft.h>
-      ],
-      [
-        #if !defined(XFT_MAJOR)
-        # error Xft.h is too old
-        #endif
-        #if XFT_MAJOR < $XFT_MIN_MAJOR
-        # error Xft.h is too old
-        #endif
-        #if XFT_MAJOR == $XFT_MIN_MAJOR
-        # if XFT_MINOR < $XFT_MIN_MINOR
-        #  error Xft.h is too old
-        # endif
-        #endif
-        #if XFT_MAJOR == $XFT_MIN_MAJOR
-        # if XFT_MAJOR == $XFT_MIN_MINOR
-        #  if XFT_REVISION < $XFT_MIN_REVISION
-        #   error Xft.h is too old
-        #  endif
-        # endif
-        #endif
-      
-        int i = XFT_MAJOR;
-        XftFont foo;
-      ],
-      [
-        AC_MSG_RESULT([yes])
-      ],
-      [
-        AC_MSG_RESULT([no])
-        XFT_ERROR
-      ])
-    else
-      AC_MSG_CHECKING([for X11/Xft/Xft.h])
-      AC_TRY_COMPILE(
-      [
-        #include <X11/Xlib.h>
-        #include <X11/Xft/Xft.h>
-      ],
-      [
-        int i = XFT_MAJOR; /* make sure were using Xft 2, not 1 */
-        XftFont foo;
-      ],
-      [
-        AC_MSG_RESULT([yes])
-      ],
-      [
-        AC_MSG_RESULT([no])
-        XFT_ERROR
-      ])
-    fi
-
-    AC_MSG_CHECKING([if we can compile with Xft])
-    AC_TRY_LINK(
-    [
-      #include <X11/Xlib.h>
-      #include <X11/Xft/Xft.h>
-    ],
-    [
-      int i = XFT_MAJOR;
-      XftFont foo
-    ],
-    [
-      AC_MSG_RESULT([yes])
-    ],
-    [ 
-      AC_MSG_RESULT([no])
-      AC_MSG_ERROR([Unable to compile with the Xft font library.
-])
-    ])
-  )
-
-  # Restore the old values. Use XFT_CFLAGS and XFT_LIBS in the Makefiles
-  LIBS=$OLDLIBS
-  CPPFLAGS=$OLDCPPFLAGS
-
-  AC_SUBST([XFT_CFLAGS])
-  AC_SUBST([XFT_LIBS])
-])
-
-
 # X11_EXT_XKB()
 #
 # Check for the presence of the "Xkb" X Window System extension.
similarity index 100%
rename from parser/Makefile
rename to obt/Makefile
diff --git a/obt/display.c b/obt/display.c
new file mode 100644 (file)
index 0000000..f34fc57
--- /dev/null
@@ -0,0 +1,152 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/display.c for the Openbox window manager
+   Copyright (c) 2007        Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/display.h"
+#include "obt/prop.h"
+#include "obt/internal.h"
+#include "obt/keyboard.h"
+
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#  include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+Display* obt_display = NULL;
+
+gboolean obt_display_error_occured = FALSE;
+
+gboolean obt_display_extension_xkb       = FALSE;
+gint     obt_display_extension_xkb_basep;
+gboolean obt_display_extension_shape     = FALSE;
+gint     obt_display_extension_shape_basep;
+gboolean obt_display_extension_xinerama  = FALSE;
+gint     obt_display_extension_xinerama_basep;
+gboolean obt_display_extension_randr     = FALSE;
+gint     obt_display_extension_randr_basep;
+gboolean obt_display_extension_sync      = FALSE;
+gint     obt_display_extension_sync_basep;
+
+static gint xerror_handler(Display *d, XErrorEvent *e);
+
+static gboolean xerror_ignore = FALSE;
+
+gboolean obt_display_open(const char *display_name)
+{
+    gchar *n;
+    Display *d = NULL;
+
+    n = display_name ? g_strdup(display_name) : NULL;
+    obt_display = d = XOpenDisplay(n);
+    if (d) {
+        gint junk;
+        (void)junk;
+
+        if (fcntl(ConnectionNumber(d), F_SETFD, 1) == -1)
+            g_message("Failed to set display as close-on-exec");
+        XSetErrorHandler(xerror_handler);
+
+        /* read what extensions are present */
+#ifdef XKB
+        obt_display_extension_xkb =
+            XkbQueryExtension(d, &junk,
+                              &obt_display_extension_xkb_basep, &junk,
+                              NULL, NULL);
+        if (!obt_display_extension_xkb)
+            g_message("XKB extension is not present on the server");
+#endif
+
+#ifdef SHAPE
+        obt_display_extension_shape =
+            XShapeQueryExtension(d, &obt_display_extension_shape_basep,
+                                 &junk);
+        if (!obt_display_extension_shape)
+            g_message("X Shape extension is not present on the server");
+#endif
+
+#ifdef XINERAMA
+        obt_display_extension_xinerama =
+            XineramaQueryExtension(d,
+                                   &obt_display_extension_xinerama_basep,
+                                   &junk) && XineramaIsActive(d);
+        if (!obt_display_extension_xinerama)
+            g_message("Xinerama extension is not present on the server");
+#endif
+
+#ifdef XRANDR
+        obt_display_extension_randr =
+            XRRQueryExtension(d, &obt_display_extension_randr_basep,
+                              &junk);
+        if (!obt_display_extension_randr)
+            g_message("XRandR extension is not present on the server");
+#endif
+
+#ifdef SYNC
+        obt_display_extension_sync =
+            XSyncQueryExtension(d, &obt_display_extension_sync_basep,
+                                &junk) && XSyncInitialize(d, &junk, &junk);
+        if (!obt_display_extension_sync)
+            g_message("X Sync extension is not present on the server or is an "
+                      "incompatible version");
+#endif
+
+        obt_prop_startup();
+        obt_keyboard_reload();
+    }
+    g_free(n);
+
+    return obt_display != NULL;
+}
+
+void obt_display_close(void)
+{
+    obt_keyboard_shutdown();
+    if (obt_display) XCloseDisplay(obt_display);
+}
+
+static gint xerror_handler(Display *d, XErrorEvent *e)
+{
+#ifdef DEBUG
+    gchar errtxt[128];
+
+    XGetErrorText(d, e->error_code, errtxt, 127);
+    if (!xerror_ignore) {
+        if (e->error_code == BadWindow)
+            /*g_debug(_("X Error: %s\n"), errtxt)*/;
+        else
+            g_error("X Error: %s", errtxt);
+    } else
+        g_debug("Ignoring XError code %d '%s'", e->error_code, errtxt);
+#else
+    (void)d; (void)e;
+#endif
+
+    obt_display_error_occured = TRUE;
+    return 0;
+}
+
+void obt_display_ignore_errors(gboolean ignore)
+{
+    XSync(obt_display, FALSE);
+    xerror_ignore = ignore;
+    if (ignore) obt_display_error_occured = FALSE;
+}
diff --git a/obt/display.h b/obt/display.h
new file mode 100644 (file)
index 0000000..ff20f9c
--- /dev/null
@@ -0,0 +1,68 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/display.h for the Openbox window manager
+   Copyright (c) 2007        Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_display_h
+#define __obt_display_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+#include <X11/Xutil.h> /* shape.h uses Region which is in here */
+#ifdef    XKB
+#include <X11/XKBlib.h>
+#endif
+#ifdef    SHAPE
+#include <X11/extensions/shape.h>
+#endif
+#ifdef    XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+#ifdef    XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+#ifdef    SYNC
+#include <X11/extensions/sync.h>
+#endif
+
+G_BEGIN_DECLS
+
+extern gboolean obt_display_error_occured;
+
+extern gboolean obt_display_extension_xkb;
+extern gint     obt_display_extension_xkb_basep;
+extern gboolean obt_display_extension_shape;
+extern gint     obt_display_extension_shape_basep;
+extern gboolean obt_display_extension_xinerama;
+extern gint     obt_display_extension_xinerama_basep;
+extern gboolean obt_display_extension_randr;
+extern gint     obt_display_extension_randr_basep;
+extern gboolean obt_display_extension_sync;
+extern gint     obt_display_extension_sync_basep;
+
+extern Display* obt_display;
+
+gboolean obt_display_open(const char *display_name);
+void     obt_display_close(void);
+
+void     obt_display_ignore_errors(gboolean ignore);
+
+#define  obt_root(screen) (RootWindow(obt_display, screen))
+
+G_END_DECLS
+
+#endif /*__obt_display_h*/
similarity index 70%
rename from openbox/xerror.h
rename to obt/internal.h
index de1aa5a..818107d 100644 (file)
@@ -1,6 +1,7 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
-   xerror.h for the Openbox window manager
+   obt/internal.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
    Copyright (c) 2003-2007   Dana Jansens
 
    This program is free software; you can redistribute it and/or modify
    See the COPYING file for a copy of the GNU General Public License.
 */
 
-#ifndef __xerror_h
-#define __xerror_h
+#ifndef __obt_internal_h
+#define __obt_internal_h
 
-#include <X11/Xlib.h>
-#include <glib.h>
+void obt_prop_startup(void);
 
-/* can be used to track errors */
-extern gboolean xerror_occured;
+void obt_keyboard_shutdown(void);
 
-gint xerror_handler(Display *, XErrorEvent *);
-
-void xerror_set_ignore(gboolean ignore);
-
-#endif
+#endif /* __obt_internal_h */
similarity index 65%
rename from openbox/modkeys.c
rename to obt/keyboard.c
index e897ccb..264201a 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
-   modkeys.c for the Openbox window manager
+   obt/keyboard.c for the Openbox window manager
    Copyright (c) 2007        Dana Jansens
 
    This program is free software; you can redistribute it and/or modify
@@ -16,8 +16,8 @@
    See the COPYING file for a copy of the GNU General Public License.
 */
 
-#include "modkeys.h"
-#include "openbox.h"
+#include "obt/display.h"
+#include "obt/keyboard.h"
 
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
 #define nth_mask(n) (1 << n)
 
 static void set_modkey_mask(guchar mask, KeySym sym);
+void obt_keyboard_shutdown();
 
 static XModifierKeymap *modmap;
 static KeySym *keymap;
 static gint min_keycode, max_keycode, keysyms_per_keycode;
 /* This is a bitmask of the different masks for each modifier key */
-static guchar modkeys_keys[OB_MODKEY_NUM_KEYS];
+static guchar modkeys_keys[OBT_KEYBOARD_NUM_MODKEYS];
 
 static gboolean alt_l = FALSE;
 static gboolean meta_l = FALSE;
 static gboolean super_l = FALSE;
 static gboolean hyper_l = FALSE;
 
-void modkeys_startup(gboolean reconfigure)
+static gboolean started = FALSE;
+
+void obt_keyboard_reload(void)
 {
     gint i, j, k;
 
+    if (started) obt_keyboard_shutdown(); /* free stuff */
+    started = TRUE;
+
     /* reset the keys to not be bound to any masks */
-    for (i = 0; i < OB_MODKEY_NUM_KEYS; ++i)
+    for (i = 0; i < OBT_KEYBOARD_NUM_MODKEYS; ++i)
         modkeys_keys[i] = 0;
 
-    modmap = XGetModifierMapping(ob_display);
+    modmap = XGetModifierMapping(obt_display);
     g_assert(modmap->max_keypermod > 0);
 
-    XDisplayKeycodes(ob_display, &min_keycode, &max_keycode);
-    keymap = XGetKeyboardMapping(ob_display, min_keycode,
+    XDisplayKeycodes(obt_display, &min_keycode, &max_keycode);
+    keymap = XGetKeyboardMapping(obt_display, min_keycode,
                                  max_keycode - min_keycode + 1,
                                  &keysyms_per_keycode);
 
@@ -86,18 +92,21 @@ void modkeys_startup(gboolean reconfigure)
     }
 
     /* CapsLock, Shift, and Control are special and hard-coded */
-    modkeys_keys[OB_MODKEY_KEY_CAPSLOCK] = LockMask;
-    modkeys_keys[OB_MODKEY_KEY_SHIFT] = ShiftMask;
-    modkeys_keys[OB_MODKEY_KEY_CONTROL] = ControlMask;
+    modkeys_keys[OBT_KEYBOARD_MODKEY_CAPSLOCK] = LockMask;
+    modkeys_keys[OBT_KEYBOARD_MODKEY_SHIFT] = ShiftMask;
+    modkeys_keys[OBT_KEYBOARD_MODKEY_CONTROL] = ControlMask;
 }
 
-void modkeys_shutdown(gboolean reconfigure)
+void obt_keyboard_shutdown(void)
 {
     XFreeModifiermap(modmap);
+    modmap = NULL;
     XFree(keymap);
+    keymap = NULL;
+    started = FALSE;
 }
 
-guint modkeys_keycode_to_mask(guint keycode)
+guint obt_keyboard_keycode_to_modmask(guint keycode)
 {
     gint i, j;
     guint mask = 0;
@@ -116,7 +125,7 @@ guint modkeys_keycode_to_mask(guint keycode)
     return mask;
 }
 
-guint modkeys_only_modifier_masks(guint mask)
+guint obt_keyboard_only_modmasks(guint mask)
 {
     mask &= ALL_MASKS;
     /* strip off these lock keys. they shouldn't affect key bindings */
@@ -124,12 +133,12 @@ guint modkeys_only_modifier_masks(guint mask)
                           because you could bind it to something else and it
                           should work as that modifier then. i think capslock
                           is weird in xkb. */
-    mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_NUMLOCK);
-    mask &= ~modkeys_key_to_mask(OB_MODKEY_KEY_SCROLLLOCK);
+    mask &= ~obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_NUMLOCK);
+    mask &= ~obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SCROLLLOCK);
     return mask;
 }
 
-guint modkeys_key_to_mask(ObModkeysKey key)
+guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key)
 {
     return modkeys_keys[key];
 }
@@ -139,44 +148,44 @@ static void set_modkey_mask(guchar mask, KeySym sym)
     /* find what key this is, and bind it to the mask */
 
     if (sym == XK_Num_Lock)
-        modkeys_keys[OB_MODKEY_KEY_NUMLOCK] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_NUMLOCK] |= mask;
     else if (sym == XK_Scroll_Lock)
-        modkeys_keys[OB_MODKEY_KEY_SCROLLLOCK] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_SCROLLLOCK] |= mask;
 
     else if (sym == XK_Super_L && super_l)
-        modkeys_keys[OB_MODKEY_KEY_SUPER] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] |= mask;
     else if (sym == XK_Super_L && !super_l)
         /* left takes precident over right, so erase any masks the right
            key may have set */
-        modkeys_keys[OB_MODKEY_KEY_SUPER] = mask, super_l = TRUE;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] = mask, super_l = TRUE;
     else if (sym == XK_Super_R && !super_l)
-        modkeys_keys[OB_MODKEY_KEY_SUPER] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_SUPER] |= mask;
 
     else if (sym == XK_Hyper_L && hyper_l)
-        modkeys_keys[OB_MODKEY_KEY_HYPER] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] |= mask;
     else if (sym == XK_Hyper_L && !hyper_l)
-        modkeys_keys[OB_MODKEY_KEY_HYPER] = mask, hyper_l = TRUE;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] = mask, hyper_l = TRUE;
     else if (sym == XK_Hyper_R && !hyper_l)
-        modkeys_keys[OB_MODKEY_KEY_HYPER] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_HYPER] |= mask;
 
     else if (sym == XK_Alt_L && alt_l)
-        modkeys_keys[OB_MODKEY_KEY_ALT] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] |= mask;
     else if (sym == XK_Alt_L && !alt_l)
-        modkeys_keys[OB_MODKEY_KEY_ALT] = mask, alt_l = TRUE;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] = mask, alt_l = TRUE;
     else if (sym == XK_Alt_R && !alt_l)
-        modkeys_keys[OB_MODKEY_KEY_ALT] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_ALT] |= mask;
 
     else if (sym == XK_Meta_L && meta_l)
-        modkeys_keys[OB_MODKEY_KEY_META] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_META] |= mask;
     else if (sym == XK_Meta_L && !meta_l)
-        modkeys_keys[OB_MODKEY_KEY_META] = mask, meta_l = TRUE;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_META] = mask, meta_l = TRUE;
     else if (sym == XK_Meta_R && !meta_l)
-        modkeys_keys[OB_MODKEY_KEY_META] |= mask;
+        modkeys_keys[OBT_KEYBOARD_MODKEY_META] |= mask;
 
     /* CapsLock, Shift, and Control are special and hard-coded */
 }
 
-KeyCode* modkeys_sym_to_code(KeySym sym)
+KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym)
 {
     KeyCode *ret;
     gint i, j, n;
@@ -195,3 +204,29 @@ KeyCode* modkeys_sym_to_code(KeySym sym)
             }
     return ret;
 }
+
+gchar *obt_keyboard_keycode_to_string(guint keycode)
+{
+    KeySym sym;
+
+    if ((sym = XKeycodeToKeysym(obt_display, keycode, 0)) != NoSymbol)
+        return g_locale_to_utf8(XKeysymToString(sym), -1, NULL, NULL, NULL);
+    return NULL;
+}
+
+gunichar obt_keyboard_keycode_to_unichar(guint keycode)
+{
+    gunichar unikey = 0;
+    char *key;
+
+    if ((key = obt_keyboard_keycode_to_string(keycode)) != NULL &&
+        /* don't accept keys that aren't a single letter, like "space" */
+        key[1] == '\0')
+    {
+        unikey = g_utf8_get_char_validated(key, -1);
+        if (unikey == (gunichar)-1 || unikey == (gunichar)-2 || unikey == 0)
+            unikey = 0;
+    }
+    g_free(key);
+    return unikey;
+}
similarity index 51%
rename from openbox/modkeys.h
rename to obt/keyboard.h
index 8e795f7..4fb6018 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
-   masks.h for the Openbox window manager
+   obt/keyboard.h for the Openbox window manager
    Copyright (c) 2007        Dana Jansens
 
    This program is free software; you can redistribute it and/or modify
    See the COPYING file for a copy of the GNU General Public License.
 */
 
-#ifndef ob__modkeys_h
-#define ob__modkeys_h
+#ifndef __obt_keyboard_h
+#define __obt_keyboard_h
 
 #include <glib.h>
 #include <X11/Xlib.h>
 
+G_BEGIN_DECLS
+
 /*! These keys are bound to the modifier masks in any fashion,
   except for CapsLock, Shift, and Control. */
 typedef enum {
-    OB_MODKEY_KEY_CAPSLOCK,
-    OB_MODKEY_KEY_NUMLOCK,
-    OB_MODKEY_KEY_SCROLLLOCK,
-    OB_MODKEY_KEY_SHIFT,
-    OB_MODKEY_KEY_CONTROL,
-    OB_MODKEY_KEY_SUPER,
-    OB_MODKEY_KEY_HYPER,
-    OB_MODKEY_KEY_META,
-    OB_MODKEY_KEY_ALT,
-
-    OB_MODKEY_NUM_KEYS
-} ObModkeysKey;
-
-void modkeys_startup(gboolean reconfigure);
-void modkeys_shutdown(gboolean reconfigure);
-
-/*! Get the modifier masks for a keycode. (eg. a keycode bound to Alt_L could
+    OBT_KEYBOARD_MODKEY_CAPSLOCK,
+    OBT_KEYBOARD_MODKEY_NUMLOCK,
+    OBT_KEYBOARD_MODKEY_SCROLLLOCK,
+    OBT_KEYBOARD_MODKEY_SHIFT,
+    OBT_KEYBOARD_MODKEY_CONTROL,
+    OBT_KEYBOARD_MODKEY_SUPER,
+    OBT_KEYBOARD_MODKEY_HYPER,
+    OBT_KEYBOARD_MODKEY_META,
+    OBT_KEYBOARD_MODKEY_ALT,
+
+    OBT_KEYBOARD_NUM_MODKEYS
+} ObtModkeysKey;
+
+void obt_keyboard_reload(void);
+
+/*! Get the modifier mask(s) for a KeyCode. (eg. a keycode bound to Alt_L could
   return a mask of (Mod1Mask | Mask3Mask)) */
-guint modkeys_keycode_to_mask(guint keycode);
+guint obt_keyboard_keycode_to_modmask(guint keycode);
 
 /*! Strip off all modifiers except for the modifier keys. This strips stuff
-  like Button1Mask, and also LockMask, NumLockMask, and ScrollLockMask */
-guint modkeys_only_modifier_masks(guint mask);
+  like Button1Mask, and also LockMask, NumlockMask, and ScrolllockMask */
+guint obt_keyboard_only_modmasks(guint mask);
 
 /*! Get the modifier masks for a modifier key. This includes both the left and
   right keys when there are both. */
-guint modkeys_key_to_mask(ObModkeysKey key);
+guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key);
 
 /*! Convert a KeySym to all the KeyCodes which generate it. */
-KeyCode* modkeys_sym_to_code(KeySym sym);
+KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym);
+
+/*! Give the string form of a KeyCode */
+gchar *obt_keyboard_keycode_to_string(guint keycode);
+
+/*! Translate a KeyCode to the unicode character it represents */
+gunichar obt_keyboard_keycode_to_unichar(guint keycode);
+
+
+G_END_DECLS
 
-#endif
+#endif /* __obt_keyboard_h */
similarity index 75%
rename from openbox/mainloop.c
rename to obt/mainloop.c
index b292120..691c687 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
-   mainloop.c for the Openbox window manager
+   obt/mainloop.c for the Openbox window manager
    Copyright (c) 2006        Mikael Magnusson
    Copyright (c) 2003-2007   Dana Jansens
 
    See the COPYING file for a copy of the GNU General Public License.
 */
 
-#include "mainloop.h"
-#include "event.h"
+#include "obt/mainloop.h"
+#include "obt/display.h"
+#include "obt/util.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/select.h>
 #include <signal.h>
 
-typedef struct _ObMainLoopTimer             ObMainLoopTimer;
-typedef struct _ObMainLoopSignal            ObMainLoopSignal;
-typedef struct _ObMainLoopSignalHandlerType ObMainLoopSignalHandlerType;
-typedef struct _ObMainLoopXHandlerType      ObMainLoopXHandlerType;
-typedef struct _ObMainLoopFdHandlerType     ObMainLoopFdHandlerType;
+typedef struct _ObtMainLoopTimer             ObtMainLoopTimer;
+typedef struct _ObtMainLoopSignal            ObtMainLoopSignal;
+typedef struct _ObtMainLoopSignalHandlerType ObtMainLoopSignalHandlerType;
+typedef struct _ObtMainLoopXHandlerType      ObtMainLoopXHandlerType;
+typedef struct _ObtMainLoopFdHandlerType     ObtMainLoopFdHandlerType;
 
 /* this should be more than the number of possible signals on any
    architecture... */
 #define NUM_SIGNALS 99
 
-/* all created ObMainLoops. Used by the signal handler to pass along signals */
+/* all created ObtMainLoops. Used by the signal handler to pass along
+   signals */
 static GSList *all_loops;
 
 /* signals are global to all loops */
@@ -64,11 +66,13 @@ static gint core_signals[] =
 #define NUM_CORE_SIGNALS (sizeof(core_signals) / sizeof(core_signals[0]))
 
 static void sighandler(gint sig);
-static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait);
+static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait);
 static void fd_handler_destroy(gpointer data);
+static void calc_max_fd(ObtMainLoop *loop);
 
-struct _ObMainLoop
+struct _ObtMainLoop
 {
+    gint ref;
     Display *display;
 
     gboolean run;     /* do keep running */
@@ -90,7 +94,7 @@ struct _ObMainLoop
     GSList *signal_handlers[NUM_SIGNALS];
 };
 
-struct _ObMainLoopTimer
+struct _ObtMainLoopTimer
 {
     gulong delay;
     GSourceFunc func;
@@ -110,42 +114,41 @@ struct _ObMainLoopTimer
     gboolean fired;
 };
 
-struct _ObMainLoopSignalHandlerType
+struct _ObtMainLoopSignalHandlerType
 {
-    ObMainLoop *loop;
+    ObtMainLoop *loop;
     gint signal;
     gpointer data;
-    ObMainLoopSignalHandler func;
+    ObtMainLoopSignalHandler func;
     GDestroyNotify destroy;
 };
 
-struct _ObMainLoopXHandlerType
+struct _ObtMainLoopXHandlerType
 {
-    ObMainLoop *loop;
+    ObtMainLoop *loop;
     gpointer data;
-    ObMainLoopXHandler func;
+    ObtMainLoopXHandler func;
     GDestroyNotify destroy;
 };
 
-struct _ObMainLoopFdHandlerType
+struct _ObtMainLoopFdHandlerType
 {
-    ObMainLoop *loop;
+    ObtMainLoop *loop;
     gint fd;
     gpointer data;
-    ObMainLoopFdHandler func;
+    ObtMainLoopFdHandler func;
     GDestroyNotify destroy;
 };
 
-ObMainLoop *ob_main_loop_new(Display *display)
+ObtMainLoop *obt_main_loop_new(void)
 {
-    ObMainLoop *loop;
+    ObtMainLoop *loop;
 
-    loop = g_new0(ObMainLoop, 1);
-    loop->display = display;
-    loop->fd_x = ConnectionNumber(display);
+    loop = g_new0(ObtMainLoop, 1);
+    loop->ref = 1;
     FD_ZERO(&loop->fd_set);
-    FD_SET(loop->fd_x, &loop->fd_set);
-    loop->fd_max = loop->fd_x;
+    loop->fd_x = -1;
+    loop->fd_max = -1;
 
     loop->fd_handlers = g_hash_table_new_full(g_int_hash, g_int_equal,
                                               NULL, fd_handler_destroy);
@@ -185,24 +188,29 @@ ObMainLoop *ob_main_loop_new(Display *display)
     return loop;
 }
 
-void ob_main_loop_destroy(ObMainLoop *loop)
+void obt_main_loop_ref(ObtMainLoop *loop)
+{
+    ++loop->ref;
+}
+
+void obt_main_loop_unref(ObtMainLoop *loop)
 {
     guint i;
     GSList *it, *next;
 
-    if (loop) {
+    if (loop && --loop->ref == 0) {
         g_assert(loop->running == FALSE);
 
         for (it = loop->x_handlers; it; it = next) {
-            ObMainLoopXHandlerType *h = it->data;
+            ObtMainLoopXHandlerType *h = it->data;
             next = g_slist_next(it);
-            ob_main_loop_x_remove(loop, h->func);
+            obt_main_loop_x_remove(loop, h->func);
         }
 
         g_hash_table_destroy(loop->fd_handlers);
 
         for (it = loop->timers; it; it = g_slist_next(it)) {
-            ObMainLoopTimer *t = it->data;
+            ObtMainLoopTimer *t = it->data;
             if (t->destroy) t->destroy(t->data);
             g_free(t);
         }
@@ -211,9 +219,9 @@ void ob_main_loop_destroy(ObMainLoop *loop)
 
         for (i = 0; i < NUM_SIGNALS; ++i)
             for (it = loop->signal_handlers[i]; it; it = next) {
-                ObMainLoopSignalHandlerType *h = it->data;
+                ObtMainLoopSignalHandlerType *h = it->data;
                 next = g_slist_next(it);
-                ob_main_loop_signal_remove(loop, h->func);
+                obt_main_loop_signal_remove(loop, h->func);
             }
 
         all_loops = g_slist_remove(all_loops, loop);
@@ -230,7 +238,7 @@ void ob_main_loop_destroy(ObMainLoop *loop)
             }
         }
 
-        g_free(loop);
+        obt_free0(loop, ObtMainLoop, 1);
     }
 }
 
@@ -238,14 +246,14 @@ static void fd_handle_foreach(gpointer key,
                               gpointer value,
                               gpointer data)
 {
-    ObMainLoopFdHandlerType *h = value;
+    ObtMainLoopFdHandlerType *h = value;
     fd_set *set = data;
 
     if (FD_ISSET(h->fd, set))
         h->func(h->fd, h->data);
 }
 
-void ob_main_loop_run(ObMainLoop *loop)
+void obt_main_loop_run(ObtMainLoop *loop)
 {
     XEvent e;
     struct timeval *wait;
@@ -268,7 +276,7 @@ void ob_main_loop_run(ObMainLoop *loop)
                 while (loop->signals_fired[i]) {
                     for (it = loop->signal_handlers[i];
                             it; it = g_slist_next(it)) {
-                        ObMainLoopSignalHandlerType *h = it->data;
+                        ObtMainLoopSignalHandlerType *h = it->data;
                         h->func(i, h->data);
                     }
                     loop->signals_fired[i]--;
@@ -277,12 +285,12 @@ void ob_main_loop_run(ObMainLoop *loop)
             loop->signal_fired = FALSE;
 
             sigprocmask(SIG_SETMASK, &oldset, NULL);
-        } else if (XPending(loop->display)) {
+        } else if (loop->display && XPending(loop->display)) {
             do {
                 XNextEvent(loop->display, &e);
 
                 for (it = loop->x_handlers; it; it = g_slist_next(it)) {
-                    ObMainLoopXHandlerType *h = it->data;
+                    ObtMainLoopXHandlerType *h = it->data;
                     h->func(&e, h->data);
                 }
             } while (XPending(loop->display) && loop->run);
@@ -312,35 +320,45 @@ void ob_main_loop_run(ObMainLoop *loop)
     loop->running = FALSE;
 }
 
-void ob_main_loop_exit(ObMainLoop *loop)
+void obt_main_loop_exit(ObtMainLoop *loop)
 {
     loop->run = FALSE;
 }
 
 /*** XEVENT WATCHERS ***/
 
-void ob_main_loop_x_add(ObMainLoop *loop,
-                        ObMainLoopXHandler handler,
-                        gpointer data,
-                        GDestroyNotify notify)
+void obt_main_loop_x_add(ObtMainLoop *loop,
+                         ObtMainLoopXHandler handler,
+                         gpointer data,
+                         GDestroyNotify notify)
 {
-    ObMainLoopXHandlerType *h;
+    ObtMainLoopXHandlerType *h;
 
-    h = g_new(ObMainLoopXHandlerType, 1);
+    h = g_new(ObtMainLoopXHandlerType, 1);
     h->loop = loop;
     h->func = handler;
     h->data = data;
     h->destroy = notify;
+
+    if (!loop->x_handlers) {
+        g_assert(obt_display); /* is the display open? */
+
+        loop->display = obt_display;
+        loop->fd_x = ConnectionNumber(loop->display);
+        FD_SET(loop->fd_x, &loop->fd_set);
+        calc_max_fd(loop);
+    }
+
     loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
 }
 
-void ob_main_loop_x_remove(ObMainLoop *loop,
-                           ObMainLoopXHandler handler)
+void obt_main_loop_x_remove(ObtMainLoop *loop,
+                            ObtMainLoopXHandler handler)
 {
     GSList *it, *next;
 
     for (it = loop->x_handlers; it; it = next) {
-        ObMainLoopXHandlerType *h = it->data;
+        ObtMainLoopXHandlerType *h = it->data;
         next = g_slist_next(it);
         if (h->func == handler) {
             loop->x_handlers = g_slist_delete_link(loop->x_handlers, it);
@@ -348,6 +366,11 @@ void ob_main_loop_x_remove(ObMainLoop *loop,
             g_free(h);
         }
     }
+
+    if (!loop->x_handlers) {
+        FD_CLR(loop->fd_x, &loop->fd_set);
+        calc_max_fd(loop);
+    }
 }
 
 /*** SIGNAL WATCHERS ***/
@@ -372,23 +395,23 @@ static void sighandler(gint sig)
         }
 
     for (it = all_loops; it; it = g_slist_next(it)) {
-        ObMainLoop *loop = it->data;
+        ObtMainLoop *loop = it->data;
         loop->signal_fired = TRUE;
         loop->signals_fired[sig]++;
     }
 }
 
-void ob_main_loop_signal_add(ObMainLoop *loop,
-                             gint signal,
-                             ObMainLoopSignalHandler handler,
-                             gpointer data,
-                             GDestroyNotify notify)
+void obt_main_loop_signal_add(ObtMainLoop *loop,
+                              gint signal,
+                              ObtMainLoopSignalHandler handler,
+                              gpointer data,
+                              GDestroyNotify notify)
 {
-    ObMainLoopSignalHandlerType *h;
+    ObtMainLoopSignalHandlerType *h;
 
     g_return_if_fail(signal < NUM_SIGNALS);
 
-    h = g_new(ObMainLoopSignalHandlerType, 1);
+    h = g_new(ObtMainLoopSignalHandlerType, 1);
     h->loop = loop;
     h->signal = signal;
     h->func = handler;
@@ -412,15 +435,15 @@ void ob_main_loop_signal_add(ObMainLoop *loop,
     all_signals[signal].installed++;
 }
 
-void ob_main_loop_signal_remove(ObMainLoop *loop,
-                                ObMainLoopSignalHandler handler)
+void obt_main_loop_signal_remove(ObtMainLoop *loop,
+                                 ObtMainLoopSignalHandler handler)
 {
     guint i;
     GSList *it, *next;
 
     for (i = 0; i < NUM_SIGNALS; ++i) {
         for (it = loop->signal_handlers[i]; it; it = next) {
-            ObMainLoopSignalHandlerType *h = it->data;
+            ObtMainLoopSignalHandlerType *h = it->data;
 
             next = g_slist_next(it);
 
@@ -447,28 +470,28 @@ void ob_main_loop_signal_remove(ObMainLoop *loop,
 
 static void max_fd_func(gpointer key, gpointer value, gpointer data)
 {
-    ObMainLoop *loop = data;
+    ObtMainLoop *loop = data;
 
     /* key is the fd */
     loop->fd_max = MAX(loop->fd_max, *(gint*)key);
 }
 
-static void calc_max_fd(ObMainLoop *loop)
+static void calc_max_fd(ObtMainLoop *loop)
 {
     loop->fd_max = loop->fd_x;
 
     g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
 }
 
-void ob_main_loop_fd_add(ObMainLoop *loop,
-                         gint fd,
-                         ObMainLoopFdHandler handler,
-                         gpointer data,
-                         GDestroyNotify notify)
+void obt_main_loop_fd_add(ObtMainLoop *loop,
+                          gint fd,
+                          ObtMainLoopFdHandler handler,
+                          gpointer data,
+                          GDestroyNotify notify)
 {
-    ObMainLoopFdHandlerType *h;
+    ObtMainLoopFdHandlerType *h;
 
-    h = g_new(ObMainLoopFdHandlerType, 1);
+    h = g_new(ObtMainLoopFdHandlerType, 1);
     h->loop = loop;
     h->fd = fd;
     h->func = handler;
@@ -482,7 +505,7 @@ void ob_main_loop_fd_add(ObMainLoop *loop,
 
 static void fd_handler_destroy(gpointer data)
 {
-    ObMainLoopFdHandlerType *h = data;
+    ObtMainLoopFdHandlerType *h = data;
 
     FD_CLR(h->fd, &h->loop->fd_set);
 
@@ -490,16 +513,17 @@ static void fd_handler_destroy(gpointer data)
         h->destroy(h->data);
 }
 
-void ob_main_loop_fd_remove(ObMainLoop *loop,
-                            gint fd)
+void obt_main_loop_fd_remove(ObtMainLoop *loop,
+                             gint fd)
 {
     g_hash_table_remove(loop->fd_handlers, &fd);
+    calc_max_fd(loop);
 }
 
 /*** TIMEOUTS ***/
 
 #define NEAREST_TIMEOUT(loop) \
-    (((ObMainLoopTimer*)(loop)->timers->data)->timeout)
+    (((ObtMainLoopTimer*)(loop)->timers->data)->timeout)
 
 static glong timecompare(GTimeVal *a, GTimeVal *b)
 {
@@ -508,11 +532,11 @@ static glong timecompare(GTimeVal *a, GTimeVal *b)
     return a->tv_usec - b->tv_usec;
 }
 
-static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins)
+static void insert_timer(ObtMainLoop *loop, ObtMainLoopTimer *ins)
 {
     GSList *it;
     for (it = loop->timers; it; it = g_slist_next(it)) {
-        ObMainLoopTimer *t = it->data;
+        ObtMainLoopTimer *t = it->data;
         if (timecompare(&ins->timeout, &t->timeout) <= 0) {
             loop->timers = g_slist_insert_before(loop->timers, it, ins);
             break;
@@ -522,14 +546,14 @@ static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins)
         loop->timers = g_slist_append(loop->timers, ins);
 }
 
-void ob_main_loop_timeout_add(ObMainLoop *loop,
-                              gulong microseconds,
-                              GSourceFunc handler,
-                              gpointer data,
-                              GEqualFunc cmp,
-                              GDestroyNotify notify)
+void obt_main_loop_timeout_add(ObtMainLoop *loop,
+                               gulong microseconds,
+                               GSourceFunc handler,
+                               gpointer data,
+                               GEqualFunc cmp,
+                               GDestroyNotify notify)
 {
-    ObMainLoopTimer *t = g_new(ObMainLoopTimer, 1);
+    ObtMainLoopTimer *t = g_new(ObtMainLoopTimer, 1);
 
     g_assert(microseconds > 0); /* if it's 0 it'll cause an infinite loop */
 
@@ -546,25 +570,25 @@ void ob_main_loop_timeout_add(ObMainLoop *loop,
     insert_timer(loop, t);
 }
 
-void ob_main_loop_timeout_remove(ObMainLoop *loop,
-                                 GSourceFunc handler)
+void obt_main_loop_timeout_remove(ObtMainLoop *loop,
+                                  GSourceFunc handler)
 {
     GSList *it;
 
     for (it = loop->timers; it; it = g_slist_next(it)) {
-        ObMainLoopTimer *t = it->data;
+        ObtMainLoopTimer *t = it->data;
         if (t->func == handler)
             t->del_me = TRUE;
     }
 }
 
-void ob_main_loop_timeout_remove_data(ObMainLoop *loop, GSourceFunc handler,
-                                      gpointer data, gboolean cancel_dest)
+void obt_main_loop_timeout_remove_data(ObtMainLoop *loop, GSourceFunc handler,
+                                       gpointer data, gboolean cancel_dest)
 {
     GSList *it;
 
     for (it = loop->timers; it; it = g_slist_next(it)) {
-        ObMainLoopTimer *t = it->data;
+        ObtMainLoopTimer *t = it->data;
         if (t->func == handler && t->equal(t->data, data)) {
             t->del_me = TRUE;
             if (cancel_dest)
@@ -574,7 +598,7 @@ void ob_main_loop_timeout_remove_data(ObMainLoop *loop, GSourceFunc handler,
 }
 
 /* find the time to wait for the nearest timeout */
-static gboolean nearest_timeout_wait(ObMainLoop *loop, GTimeVal *tm)
+static gboolean nearest_timeout_wait(ObtMainLoop *loop, GTimeVal *tm)
 {
   if (loop->timers == NULL)
     return FALSE;
@@ -594,7 +618,7 @@ static gboolean nearest_timeout_wait(ObMainLoop *loop, GTimeVal *tm)
   return TRUE;
 }
 
-static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait)
+static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait)
 {
     GSList *it, *next;
 
@@ -603,7 +627,7 @@ static void timer_dispatch(ObMainLoop *loop, GTimeVal **wait)
     g_get_current_time(&loop->now);
 
     for (it = loop->timers; it; it = next) {
-        ObMainLoopTimer *curr;
+        ObtMainLoopTimer *curr;
 
         next = g_slist_next(it);
 
diff --git a/obt/mainloop.h b/obt/mainloop.h
new file mode 100644 (file)
index 0000000..f455d62
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/mainloop.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_mainloop_h
+#define __obt_mainloop_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtMainLoop ObtMainLoop;
+
+ObtMainLoop *obt_main_loop_new(void);
+void        obt_main_loop_ref(ObtMainLoop *loop);
+void        obt_main_loop_unref(ObtMainLoop *loop);
+
+typedef void (*ObtMainLoopXHandler) (const XEvent *e, gpointer data);
+
+void obt_main_loop_x_add(ObtMainLoop *loop,
+                         ObtMainLoopXHandler handler,
+                         gpointer data,
+                         GDestroyNotify notify);
+void obt_main_loop_x_remove(ObtMainLoop *loop,
+                            ObtMainLoopXHandler handler);
+
+typedef void (*ObtMainLoopFdHandler) (gint fd, gpointer data);
+
+void obt_main_loop_fd_add(ObtMainLoop *loop,
+                          gint fd,
+                          ObtMainLoopFdHandler handler,
+                          gpointer data,
+                          GDestroyNotify notify);
+void obt_main_loop_fd_remove(ObtMainLoop *loop,
+                             gint fd);
+
+typedef void (*ObtMainLoopSignalHandler) (gint signal, gpointer data);
+
+void obt_main_loop_signal_add(ObtMainLoop *loop,
+                              gint signal,
+                              ObtMainLoopSignalHandler handler,
+                              gpointer data,
+                              GDestroyNotify notify);
+void obt_main_loop_signal_remove(ObtMainLoop *loop,
+                                 ObtMainLoopSignalHandler handler);
+
+void obt_main_loop_timeout_add(ObtMainLoop *loop,
+                               gulong microseconds,
+                               GSourceFunc handler,
+                               gpointer data,
+                               GEqualFunc cmp,
+                               GDestroyNotify notify);
+void obt_main_loop_timeout_remove(ObtMainLoop *loop,
+                                  GSourceFunc handler);
+void obt_main_loop_timeout_remove_data(ObtMainLoop *loop,
+                                       GSourceFunc handler,
+                                       gpointer data,
+                                       gboolean cancel_dest);
+
+void obt_main_loop_run(ObtMainLoop *loop);
+void obt_main_loop_exit(ObtMainLoop *loop);
+
+G_END_DECLS
+
+#endif
diff --git a/obt/obt-4.0.pc.in b/obt/obt-4.0.pc.in
new file mode 100644 (file)
index 0000000..840de16
--- /dev/null
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+xcflags=@X_CFLAGS@
+xlibs=@X_LIBS@
+
+Name: Obt
+Description: Openbox Toolkit Library
+Version: @OBT_VERSION@
+Requires: glib-2.0
+Libs: -L${libdir} -lobrender ${xlibs}
+Cflags: -I${includedir}/openbox/@OBT_VERSION@ ${xcflags}
diff --git a/obt/parse.c b/obt/parse.c
new file mode 100644 (file)
index 0000000..b7c34ab
--- /dev/null
@@ -0,0 +1,424 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/parse.c for the Openbox window manager
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/parse.h"
+#include "obt/paths.h"
+
+#include <glib.h>
+
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#  include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+struct Callback {
+    gchar *tag;
+    ObtParseCallback func;
+    gpointer data;
+};
+
+struct _ObtParseInst {
+    gint ref;
+    ObtPaths *xdg_paths;
+    GHashTable *callbacks;
+    xmlDocPtr doc;
+    xmlNodePtr root;
+    gchar *path;
+};
+
+static void destfunc(struct Callback *c)
+{
+    g_free(c->tag);
+    g_free(c);
+}
+
+ObtParseInst* obt_parse_instance_new(void)
+{
+    ObtParseInst *i = g_new(ObtParseInst, 1);
+    i->ref = 1;
+    i->xdg_paths = obt_paths_new();
+    i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+                                         (GDestroyNotify)destfunc);
+    i->doc = NULL;
+    i->root = NULL;
+    i->path = NULL;
+    return i;
+}
+
+void obt_parse_instance_ref(ObtParseInst *i)
+{
+    ++i->ref;
+}
+
+void obt_parse_instance_unref(ObtParseInst *i)
+{
+    if (i && --i->ref == 0) {
+        obt_paths_unref(i->xdg_paths);
+        g_hash_table_destroy(i->callbacks);
+        g_free(i);
+    }
+}
+
+xmlDocPtr obt_parse_doc(ObtParseInst *i)
+{
+    g_assert(i->doc); /* a doc is open? */
+    return i->doc;
+}
+
+xmlNodePtr obt_parse_root(ObtParseInst *i)
+{
+    g_assert(i->doc); /* a doc is open? */
+    return i->root;
+}
+
+void obt_parse_register(ObtParseInst *i, const gchar *tag,
+                        ObtParseCallback func, gpointer data)
+{
+    struct Callback *c;
+
+    if (g_hash_table_lookup(i->callbacks, tag)) {
+        g_error("Tag '%s' already registered", tag);
+        return;
+    }
+
+    c = g_new(struct Callback, 1);
+    c->tag = g_strdup(tag);
+    c->func = func;
+    c->data = data;
+    g_hash_table_insert(i->callbacks, c->tag, c);
+}
+
+static gboolean load_file(ObtParseInst *i,
+                          const gchar *domain,
+                          const gchar *filename,
+                          const gchar *root_node,
+                          GSList *paths)
+{
+    GSList *it;
+    gboolean r = FALSE;
+
+    g_assert(i->doc == NULL); /* another doc isn't open already? */
+
+    for (it = paths; !r && it; it = g_slist_next(it)) {
+        gchar *path;
+        struct stat s;
+
+        if (!domain && !filename) /* given a full path to the file */
+            path = g_strdup(it->data);
+        else
+            path = g_build_filename(it->data, domain, filename, NULL);
+
+        if (stat(path, &s) >= 0) {
+            /* XML_PARSE_BLANKS is needed apparently, or the tree can end up
+               with extra nodes in it. */
+            i->doc = xmlReadFile(path, NULL, (XML_PARSE_NOBLANKS |
+                                              XML_PARSE_RECOVER));
+            if (i->doc) {
+                i->root = xmlDocGetRootElement(i->doc);
+                if (!i->root) {
+                    xmlFreeDoc(i->doc);
+                    i->doc = NULL;
+                    g_message("%s is an empty XML document", path);
+                }
+                else if (xmlStrcmp(i->root->name,
+                                   (const xmlChar*)root_node)) {
+                    xmlFreeDoc(i->doc);
+                    i->doc = NULL;
+                    i->root = NULL;
+                    g_message("XML document %s is of wrong type. Root "
+                              "node is not '%s'", path, root_node);
+                }
+                else {
+                    i->path = g_strdup(path);
+                    r = TRUE; /* ok! */
+                }
+            }
+        }
+
+        g_free(path);
+    }
+
+    return r;
+}
+
+gboolean obt_parse_load_file(ObtParseInst *i,
+                             const gchar *path,
+                             const gchar *root_node)
+{
+    GSList *paths;
+    gboolean r;
+
+    paths = g_slist_append(NULL, g_strdup(path));
+
+    r = load_file(i, NULL, NULL, root_node, paths);
+
+    while (paths) {
+        g_free(paths->data);
+        paths = g_slist_delete_link(paths, paths);
+    }
+    return r;
+}
+
+gboolean obt_parse_load_config_file(ObtParseInst *i,
+                                    const gchar *domain,
+                                    const gchar *filename,
+                                    const gchar *root_node)
+{
+    GSList *it, *paths = NULL;
+    gboolean r;
+
+    for (it = obt_paths_config_dirs(i->xdg_paths); it; it = g_slist_next(it))
+        paths = g_slist_append(paths, g_strdup(it->data));
+
+    r = load_file(i, domain, filename, root_node, paths);
+
+    while (paths) {
+        g_free(paths->data);
+        paths = g_slist_delete_link(paths, paths);
+    }
+    return r;
+}
+
+gboolean obt_parse_load_data_file(ObtParseInst *i,
+                                  const gchar *domain,
+                                  const gchar *filename,
+                                  const gchar *root_node)
+{
+    GSList *it, *paths = NULL;
+    gboolean r;
+
+    for (it = obt_paths_data_dirs(i->xdg_paths); it; it = g_slist_next(it))
+        paths = g_slist_append(paths, g_strdup(it->data));
+
+    r = load_file(i, domain, filename, root_node, paths);
+
+    while (paths) {
+        g_free(paths->data);
+        paths = g_slist_delete_link(paths, paths);
+    }
+    return r;
+}
+
+gboolean obt_parse_load_theme_file(ObtParseInst *i,
+                                   const gchar *theme,
+                                   const gchar *domain,
+                                   const gchar *filename,
+                                   const gchar *root_node)
+{
+    GSList *it, *paths = NULL;
+    gboolean r;
+
+    /* use ~/.themes for backwards compatibility */
+    paths = g_slist_append
+        (paths, g_build_filename(g_get_home_dir(), ".themes", theme, NULL));
+
+    for (it = obt_paths_data_dirs(i->xdg_paths); it; it = g_slist_next(it))
+        paths = g_slist_append
+            (paths, g_build_filename(it->data, "themes", theme, NULL));
+
+    r = load_file(i, domain, filename, root_node, paths);
+
+    while (paths) {
+        g_free(paths->data);
+        paths = g_slist_delete_link(paths, paths);
+    }
+    return r;
+}
+
+
+gboolean obt_parse_load_mem(ObtParseInst *i,
+                            gpointer data, guint len, const gchar *root_node)
+{
+    gboolean r = FALSE;
+
+    g_assert(i->doc == NULL); /* another doc isn't open already? */
+
+    i->doc = xmlParseMemory(data, len);
+    if (i) {
+        i->root = xmlDocGetRootElement(i->doc);
+        if (!i->root) {
+            xmlFreeDoc(i->doc);
+            i->doc = NULL;
+            g_message("Given memory is an empty document");
+        }
+        else if (xmlStrcmp(i->root->name, (const xmlChar*)root_node)) {
+            xmlFreeDoc(i->doc);
+            i->doc = NULL;
+            i->root = NULL;
+            g_message("XML Document in given memory is of wrong "
+                      "type. Root node is not '%s'\n", root_node);
+        }
+        else
+            r = TRUE; /* ok ! */
+    }
+    return r;
+}
+
+void obt_parse_close(ObtParseInst *i)
+{
+    if (i && i->doc) {
+        xmlFreeDoc(i->doc);
+        g_free(i->path);
+        i->doc = NULL;
+        i->root = NULL;
+        i->path = NULL;
+    }
+}
+
+void obt_parse_tree(ObtParseInst *i, xmlNodePtr node)
+{
+    g_assert(i->doc); /* a doc is open? */
+
+    while (node) {
+        struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
+        if (c) c->func(node, c->data);
+        node = node->next;
+    }
+}
+
+void obt_parse_tree_from_root(ObtParseInst *i)
+{
+    obt_parse_tree(i, i->root->children);
+}
+
+gchar *obt_parse_node_string(xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeGetContent(node);
+    gchar *s;
+    if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+    s = g_strdup(c ? (gchar*)c : "");
+    xmlFree(c);
+    return s;
+}
+
+gint obt_parse_node_int(xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeGetContent(node);
+    gint i;
+    if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+    i = c ? atoi((gchar*)c) : 0;
+    xmlFree(c);
+    return i;
+}
+
+gboolean obt_parse_node_bool(xmlNodePtr node)
+{
+    xmlChar *c = xmlNodeGetContent(node);
+    gboolean b = FALSE;
+    if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+    if (c && !xmlStrcasecmp(c, (const xmlChar*) "true"))
+        b = TRUE;
+    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "yes"))
+        b = TRUE;
+    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "on"))
+        b = TRUE;
+    xmlFree(c);
+    return b;
+}
+
+gboolean obt_parse_node_contains(xmlNodePtr node, const gchar *val)
+{
+    xmlChar *c = xmlNodeGetContent(node);
+    gboolean r;
+    if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
+    r = !xmlStrcasecmp(c, (const xmlChar*) val);
+    xmlFree(c);
+    return r;
+}
+
+xmlNodePtr obt_parse_find_node(xmlNodePtr node, const gchar *tag)
+{
+    while (node) {
+        if (!xmlStrcmp(node->name, (const xmlChar*) tag))
+            return node;
+        node = node->next;
+    }
+    return NULL;
+}
+
+gboolean obt_parse_attr_bool(xmlNodePtr node, const gchar *name,
+                             gboolean *value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        g_strstrip((char*)c); /* strip leading/trailing whitespace */
+        if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
+            *value = TRUE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "false"))
+            *value = FALSE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "no"))
+            *value = FALSE, r = TRUE;
+        else if (!xmlStrcasecmp(c, (const xmlChar*) "off"))
+            *value = FALSE, r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean obt_parse_attr_int(xmlNodePtr node, const gchar *name, gint *value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        g_strstrip((char*)c); /* strip leading/trailing whitespace */
+        *value = atoi((gchar*)c);
+        r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean obt_parse_attr_string(xmlNodePtr node, const gchar *name,
+                               gchar **value)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        g_strstrip((char*)c); /* strip leading/trailing whitespace */
+        *value = g_strdup((gchar*)c);
+        r = TRUE;
+    }
+    xmlFree(c);
+    return r;
+}
+
+gboolean obt_parse_attr_contains(xmlNodePtr node, const gchar *name,
+                                 const gchar *val)
+{
+    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
+    gboolean r = FALSE;
+    if (c) {
+        g_strstrip((char*)c); /* strip leading/trailing whitespace */
+        r = !xmlStrcasecmp(c, (const xmlChar*) val);
+    }
+    xmlFree(c);
+    return r;
+}
diff --git a/obt/parse.h b/obt/parse.h
new file mode 100644 (file)
index 0000000..acc3f5c
--- /dev/null
@@ -0,0 +1,85 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/parse.h for the Openbox window manager
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_parse_h
+#define __obt_parse_h
+
+#include <libxml/parser.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtParseInst ObtParseInst;
+
+typedef void (*ObtParseCallback)(xmlNodePtr node, gpointer data);
+
+ObtParseInst* obt_parse_instance_new(void);
+void obt_parse_instance_ref(ObtParseInst *inst);
+void obt_parse_instance_unref(ObtParseInst *inst);
+
+gboolean obt_parse_load_file(ObtParseInst *inst,
+                             const gchar *path,
+                             const gchar *root_node);
+gboolean obt_parse_load_config_file(ObtParseInst *inst,
+                                    const gchar *domain,
+                                    const gchar *filename,
+                                    const gchar *root_node);
+gboolean obt_parse_load_data_file(ObtParseInst *inst,
+                                  const gchar *domain,
+                                  const gchar *filename,
+                                  const gchar *root_node);
+gboolean obt_parse_load_theme_file(ObtParseInst *inst,
+                                   const gchar *theme,
+                                   const gchar *domain,
+                                   const gchar *filename,
+                                   const gchar *root_node);
+gboolean obt_parse_load_mem(ObtParseInst *inst,
+                            gpointer data, guint len, const gchar *root_node);
+
+xmlDocPtr obt_parse_doc(ObtParseInst *inst);
+xmlNodePtr obt_parse_root(ObtParseInst *inst);
+
+void obt_parse_close(ObtParseInst *inst);
+
+void obt_parse_register(ObtParseInst *inst, const gchar *tag,
+                        ObtParseCallback func, gpointer data);
+void obt_parse_tree(ObtParseInst *i, xmlNodePtr node);
+void obt_parse_tree_from_root(ObtParseInst *i);
+
+
+/* helpers */
+
+xmlNodePtr obt_parse_find_node(xmlNodePtr node, const gchar *name);
+
+gboolean obt_parse_node_contains (xmlNodePtr node, const gchar *val);
+gchar   *obt_parse_node_string   (xmlNodePtr node);
+gint     obt_parse_node_int      (xmlNodePtr node);
+gboolean obt_parse_node_bool     (xmlNodePtr node);
+
+gboolean obt_parse_attr_contains (xmlNodePtr node, const gchar *name,
+                                  const gchar *val);
+gboolean obt_parse_attr_string   (xmlNodePtr node, const gchar *name,
+                                  gchar **value);
+gboolean obt_parse_attr_int      (xmlNodePtr node, const gchar *name,
+                                  gint *value);
+gboolean obt_parse_attr_bool     (xmlNodePtr node, const gchar *name,
+                                  gboolean *value);
+
+G_END_DECLS
+
+#endif
diff --git a/obt/paths.c b/obt/paths.c
new file mode 100644 (file)
index 0000000..6861543
--- /dev/null
@@ -0,0 +1,249 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/paths.c for the Openbox window manager
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/paths.h"
+#include "obt/util.h"
+
+#ifdef HAVE_SYS_STAT_H
+#  include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+
+struct _ObtPaths
+{
+    gint   ref;
+    gchar  *config_home;
+    gchar  *data_home;
+    gchar  *cache_home;
+    GSList *config_dirs;
+    GSList *data_dirs;
+};
+
+static gint slist_path_cmp(const gchar *a, const gchar *b)
+{
+    return strcmp(a, b);
+}
+
+typedef GSList* (*GSListFunc) (gpointer list, gconstpointer data);
+
+static GSList* slist_path_add(GSList *list, gpointer data, GSListFunc func)
+{
+    g_assert(func);
+
+    if (!data)
+        return list;
+
+    if (!g_slist_find_custom(list, data, (GCompareFunc) slist_path_cmp))
+        list = func(list, data);
+    else
+        g_free(data);
+
+    return list;
+}
+
+static GSList* split_paths(const gchar *paths)
+{
+    GSList *list = NULL;
+    gchar **spl, **it;
+
+    if (!paths)
+        return NULL;
+    spl = g_strsplit(paths, ":", -1);
+    for (it = spl; *it; ++it)
+        list = slist_path_add(list, *it, (GSListFunc) g_slist_append);
+    g_free(spl);
+    return list;
+}
+
+ObtPaths* obt_paths_new(void)
+{
+    ObtPaths *p;
+    const gchar *path;
+
+    p = g_new0(ObtPaths, 1);
+    p->ref = 1;
+
+    path = g_getenv("XDG_CONFIG_HOME");
+    if (path && path[0] != '\0') /* not unset or empty */
+        p->config_home = g_build_filename(path, NULL);
+    else
+        p->config_home = g_build_filename(g_get_home_dir(), ".config", NULL);
+
+    path = g_getenv("XDG_DATA_HOME");
+    if (path && path[0] != '\0') /* not unset or empty */
+        p->data_home = g_build_filename(path, NULL);
+    else
+        p->data_home = g_build_filename(g_get_home_dir(), ".local",
+                                        "share", NULL);
+
+    path = g_getenv("XDG_CACHE_HOME");
+    if (path && path[0] != '\0') /* not unset or empty */
+        p->cache_home = g_build_filename(path, NULL);
+    else
+        p->cache_home = g_build_filename(g_get_home_dir(), ".cache", NULL);
+
+    path = g_getenv("XDG_CONFIG_DIRS");
+    if (path && path[0] != '\0') /* not unset or empty */
+        p->config_dirs = split_paths(path);
+    else {
+        p->config_dirs = slist_path_add(p->config_dirs,
+                                        g_strdup(CONFIGDIR),
+                                        (GSListFunc) g_slist_append);
+        p->config_dirs = slist_path_add(p->config_dirs,
+                                        g_build_filename
+                                        (G_DIR_SEPARATOR_S,
+                                         "etc", "xdg", NULL),
+                                        (GSListFunc) g_slist_append);
+    }
+    p->config_dirs = slist_path_add(p->config_dirs,
+                                    g_strdup(p->config_home),
+                                    (GSListFunc) g_slist_prepend);
+
+    path = g_getenv("XDG_DATA_DIRS");
+    if (path && path[0] != '\0') /* not unset or empty */
+        p->data_dirs = split_paths(path);
+    else {
+        p->data_dirs = slist_path_add(p->data_dirs,
+                                      g_strdup(DATADIR),
+                                      (GSListFunc) g_slist_append);
+        p->data_dirs = slist_path_add(p->data_dirs,
+                                      g_build_filename
+                                      (G_DIR_SEPARATOR_S,
+                                       "usr", "local", "share", NULL),
+                                      (GSListFunc) g_slist_append);
+        p->data_dirs = slist_path_add(p->data_dirs,
+                                      g_build_filename
+                                      (G_DIR_SEPARATOR_S,
+                                       "usr", "share", NULL),
+                                      (GSListFunc) g_slist_append);
+    }
+    p->data_dirs = slist_path_add(p->data_dirs,
+                                  g_strdup(p->data_home),
+                                  (GSListFunc) g_slist_prepend);
+    return p;
+}
+
+void obt_paths_ref(ObtPaths *p)
+{
+    ++p->ref;
+}
+
+void obt_paths_unref(ObtPaths *p)
+{
+    if (p && --p->ref == 0) {
+        GSList *it;
+
+        for (it = p->config_dirs; it; it = g_slist_next(it))
+            g_free(it->data);
+        g_slist_free(p->config_dirs);
+        for (it = p->data_dirs; it; it = g_slist_next(it))
+            g_free(it->data);
+        g_slist_free(p->data_dirs);
+        g_free(p->config_home);
+        g_free(p->data_home);
+        g_free(p->cache_home);
+
+        obt_free0(p, ObtPaths, 1);
+    }
+}
+
+gchar *obt_paths_expand_tilde(const gchar *f)
+{
+    gchar *ret;
+    GRegex *regex;
+
+    if (!f)
+        return NULL;
+
+    regex = g_regex_new("(?:^|(?<=[ \\t]))~(?=[/ \\t$])", G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
+    ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
+    g_regex_unref(regex);
+
+    return ret;
+}
+
+gboolean obt_paths_mkdir(const gchar *path, gint mode)
+{
+    gboolean ret = TRUE;
+
+    g_return_val_if_fail(path != NULL, FALSE);
+    g_return_val_if_fail(path[0] != '\0', FALSE);
+
+    if (!g_file_test(path, G_FILE_TEST_IS_DIR))
+        if (mkdir(path, mode) == -1)
+            ret = FALSE;
+
+    return ret;
+}
+
+gboolean obt_paths_mkdir_path(const gchar *path, gint mode)
+{
+    gboolean ret = TRUE;
+
+    g_return_val_if_fail(path != NULL, FALSE);
+    g_return_val_if_fail(path[0] == '/', FALSE);
+
+    if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
+        gchar *c, *e;
+
+        c = g_strdup(path);
+        e = c;
+        while ((e = strchr(e + 1, '/'))) {
+            *e = '\0';
+            if (!(ret = obt_paths_mkdir(c, mode)))
+                goto parse_mkdir_path_end;
+            *e = '/';
+        }
+        ret = obt_paths_mkdir(c, mode);
+
+    parse_mkdir_path_end:
+        g_free(c);
+    }
+
+    return ret;
+}
+
+const gchar* obt_paths_config_home(ObtPaths *p)
+{
+    return p->config_home;
+}
+
+const gchar* obt_paths_data_home(ObtPaths *p)
+{
+    return p->data_home;
+}
+
+const gchar* obt_paths_cache_home(ObtPaths *p)
+{
+    return p->cache_home;
+}
+
+GSList* obt_paths_config_dirs(ObtPaths *p)
+{
+    return p->config_dirs;
+}
+
+GSList* obt_paths_data_dirs(ObtPaths *p)
+{
+    return p->data_dirs;
+}
diff --git a/obt/paths.h b/obt/paths.h
new file mode 100644 (file)
index 0000000..8753d4f
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/paths.h for the Openbox window manager
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_paths_h
+#define __obt_paths_h
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtPaths ObtPaths;
+
+ObtPaths* obt_paths_new(void);
+void obt_paths_ref(ObtPaths *p);
+void obt_paths_unref(ObtPaths *p);
+
+const gchar* obt_paths_config_home(ObtPaths *p);
+const gchar* obt_paths_data_home(ObtPaths *p);
+const gchar* obt_paths_cache_home(ObtPaths *p);
+GSList* obt_paths_config_dirs(ObtPaths *p);
+GSList* obt_paths_data_dirs(ObtPaths *p);
+
+gchar *obt_paths_expand_tilde(const gchar *f);
+gboolean obt_paths_mkdir(const gchar *path, gint mode);
+gboolean obt_paths_mkdir_path(const gchar *path, gint mode);
+
+G_END_DECLS
+
+#endif
diff --git a/obt/prop.c b/obt/prop.c
new file mode 100644 (file)
index 0000000..f4c8db1
--- /dev/null
@@ -0,0 +1,501 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/prop.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/prop.h"
+#include "obt/display.h"
+
+#include <X11/Xatom.h>
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+
+Atom prop_atoms[OBT_PROP_NUM_ATOMS];
+gboolean prop_started = FALSE;
+
+#define CREATE_NAME(var, name) (prop_atoms[OBT_PROP_##var] = \
+                                XInternAtom((obt_display), (name), FALSE))
+#define CREATE(var) CREATE_NAME(var, #var)
+#define CREATE_(var) CREATE_NAME(var, "_" #var)
+
+void obt_prop_startup(void)
+{
+    if (prop_started) return;
+    prop_started = TRUE;
+
+    g_assert(obt_display);
+
+    CREATE(CARDINAL);
+    CREATE(WINDOW);
+    CREATE(PIXMAP);
+    CREATE(ATOM);
+    CREATE(STRING);
+    CREATE_NAME(UTF8, "UTF8_STRING");
+
+    CREATE(MANAGER);
+
+    CREATE(WM_COLORMAP_WINDOWS);
+    CREATE(WM_PROTOCOLS);
+    CREATE(WM_STATE);
+    CREATE(WM_CHANGE_STATE);
+    CREATE(WM_DELETE_WINDOW);
+    CREATE(WM_TAKE_FOCUS);
+    CREATE(WM_NAME);
+    CREATE(WM_ICON_NAME);
+    CREATE(WM_CLASS);
+    CREATE(WM_WINDOW_ROLE);
+    CREATE(WM_CLIENT_MACHINE);
+    CREATE(WM_COMMAND);
+    CREATE(WM_CLIENT_LEADER);
+    CREATE(WM_TRANSIENT_FOR);
+    CREATE_(MOTIF_WM_HINTS);
+    CREATE_(MOTIF_WM_INFO);
+
+    CREATE(SM_CLIENT_ID);
+
+    CREATE_(NET_WM_FULL_PLACEMENT);
+
+    CREATE_(NET_SUPPORTED);
+    CREATE_(NET_CLIENT_LIST);
+    CREATE_(NET_CLIENT_LIST_STACKING);
+    CREATE_(NET_NUMBER_OF_DESKTOPS);
+    CREATE_(NET_DESKTOP_GEOMETRY);
+    CREATE_(NET_DESKTOP_VIEWPORT);
+    CREATE_(NET_CURRENT_DESKTOP);
+    CREATE_(NET_DESKTOP_NAMES);
+    CREATE_(NET_ACTIVE_WINDOW);
+/*    CREATE_(NET_RESTACK_WINDOW);*/
+    CREATE_(NET_WORKAREA);
+    CREATE_(NET_SUPPORTING_WM_CHECK);
+    CREATE_(NET_DESKTOP_LAYOUT);
+    CREATE_(NET_SHOWING_DESKTOP);
+
+    CREATE_(NET_CLOSE_WINDOW);
+    CREATE_(NET_WM_MOVERESIZE);
+    CREATE_(NET_MOVERESIZE_WINDOW);
+    CREATE_(NET_REQUEST_FRAME_EXTENTS);
+    CREATE_(NET_RESTACK_WINDOW);
+
+    CREATE_(NET_STARTUP_ID);
+
+    CREATE_(NET_WM_NAME);
+    CREATE_(NET_WM_VISIBLE_NAME);
+    CREATE_(NET_WM_ICON_NAME);
+    CREATE_(NET_WM_VISIBLE_ICON_NAME);
+    CREATE_(NET_WM_DESKTOP);
+    CREATE_(NET_WM_WINDOW_TYPE);
+    CREATE_(NET_WM_STATE);
+    CREATE_(NET_WM_STRUT);
+    CREATE_(NET_WM_STRUT_PARTIAL);
+    CREATE_(NET_WM_ICON);
+    CREATE_(NET_WM_ICON_GEOMETRY);
+    CREATE_(NET_WM_PID);
+    CREATE_(NET_WM_ALLOWED_ACTIONS);
+    CREATE_(NET_WM_USER_TIME);
+/*  CREATE_(NET_WM_USER_TIME_WINDOW); */
+    CREATE_(KDE_NET_WM_FRAME_STRUT);
+    CREATE_(NET_FRAME_EXTENTS);
+
+    CREATE_(NET_WM_PING);
+#ifdef SYNC
+    CREATE_(NET_WM_SYNC_REQUEST);
+    CREATE_(NET_WM_SYNC_REQUEST_COUNTER);
+#endif
+
+    CREATE_(NET_WM_WINDOW_TYPE_DESKTOP);
+    CREATE_(NET_WM_WINDOW_TYPE_DOCK);
+    CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR);
+    CREATE_(NET_WM_WINDOW_TYPE_MENU);
+    CREATE_(NET_WM_WINDOW_TYPE_UTILITY);
+    CREATE_(NET_WM_WINDOW_TYPE_SPLASH);
+    CREATE_(NET_WM_WINDOW_TYPE_DIALOG);
+    CREATE_(NET_WM_WINDOW_TYPE_NORMAL);
+    CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU);
+
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT] = 0;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP] = 1;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT] = 2;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT] = 3;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT] = 4;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM] = 5;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT] = 6;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT] = 7;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE] = 8;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD] = 9;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD] = 10;
+    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_CANCEL] = 11;
+
+    CREATE_(NET_WM_ACTION_MOVE);
+    CREATE_(NET_WM_ACTION_RESIZE);
+    CREATE_(NET_WM_ACTION_MINIMIZE);
+    CREATE_(NET_WM_ACTION_SHADE);
+    CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ);
+    CREATE_(NET_WM_ACTION_MAXIMIZE_VERT);
+    CREATE_(NET_WM_ACTION_FULLSCREEN);
+    CREATE_(NET_WM_ACTION_CHANGE_DESKTOP);
+    CREATE_(NET_WM_ACTION_CLOSE);
+    CREATE_(NET_WM_ACTION_ABOVE);
+    CREATE_(NET_WM_ACTION_BELOW);
+
+    CREATE_(NET_WM_STATE_MODAL);
+/*    CREATE_(NET_WM_STATE_STICKY);*/
+    CREATE_(NET_WM_STATE_MAXIMIZED_VERT);
+    CREATE_(NET_WM_STATE_MAXIMIZED_HORZ);
+    CREATE_(NET_WM_STATE_SHADED);
+    CREATE_(NET_WM_STATE_SKIP_TASKBAR);
+    CREATE_(NET_WM_STATE_SKIP_PAGER);
+    CREATE_(NET_WM_STATE_HIDDEN);
+    CREATE_(NET_WM_STATE_FULLSCREEN);
+    CREATE_(NET_WM_STATE_ABOVE);
+    CREATE_(NET_WM_STATE_BELOW);
+    CREATE_(NET_WM_STATE_DEMANDS_ATTENTION);
+
+    prop_atoms[OBT_PROP_NET_WM_STATE_ADD] = 1;
+    prop_atoms[OBT_PROP_NET_WM_STATE_REMOVE] = 0;
+    prop_atoms[OBT_PROP_NET_WM_STATE_TOGGLE] = 2;
+
+    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_HORZ] = 0;
+    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_VERT] = 1;
+    prop_atoms[OBT_PROP_NET_WM_TOPLEFT] = 0;
+    prop_atoms[OBT_PROP_NET_WM_TOPRIGHT] = 1;
+    prop_atoms[OBT_PROP_NET_WM_BOTTOMRIGHT] = 2;
+    prop_atoms[OBT_PROP_NET_WM_BOTTOMLEFT] = 3;
+
+    CREATE_(KDE_WM_CHANGE_STATE);
+    CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
+
+/*
+    CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
+    CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
+*/
+
+    CREATE_(OPENBOX_PID);
+    CREATE_(OB_THEME);
+    CREATE_(OB_CONFIG_FILE);
+    CREATE_(OB_WM_ACTION_UNDECORATE);
+    CREATE_(OB_WM_STATE_UNDECORATED);
+    CREATE_(OB_CONTROL);
+    CREATE_(OB_ROLE);
+    CREATE_(OB_NAME);
+    CREATE_(OB_CLASS);
+}
+
+Atom obt_prop_atom(ObtPropAtom a)
+{
+    g_assert(prop_started);
+    g_assert(a < OBT_PROP_NUM_ATOMS);
+    return prop_atoms[a];
+}
+
+static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
+                             guchar *data, gulong num)
+{
+    gboolean ret = FALSE;
+    gint res;
+    guchar *xdata = NULL;
+    Atom ret_type;
+    gint ret_size;
+    gulong ret_items, bytes_left;
+    glong num32 = 32 / size * num; /* num in 32-bit elements */
+
+    res = XGetWindowProperty(obt_display, win, prop, 0l, num32,
+                             FALSE, type, &ret_type, &ret_size,
+                             &ret_items, &bytes_left, &xdata);
+    if (res == Success && ret_items && xdata) {
+        if (ret_size == size && ret_items >= num) {
+            guint i;
+            for (i = 0; i < num; ++i)
+                switch (size) {
+                case 8:
+                    data[i] = xdata[i];
+                    break;
+                case 16:
+                    ((guint16*)data)[i] = ((gushort*)xdata)[i];
+                    break;
+                case 32:
+                    ((guint32*)data)[i] = ((gulong*)xdata)[i];
+                    break;
+                default:
+                    g_assert_not_reached(); /* unhandled size */
+                }
+            ret = TRUE;
+        }
+        XFree(xdata);
+    }
+    return ret;
+}
+
+static gboolean get_all(Window win, Atom prop, Atom type, gint size,
+                        guchar **data, guint *num)
+{
+    gboolean ret = FALSE;
+    gint res;
+    guchar *xdata = NULL;
+    Atom ret_type;
+    gint ret_size;
+    gulong ret_items, bytes_left;
+
+    res = XGetWindowProperty(obt_display, win, prop, 0l, G_MAXLONG,
+                             FALSE, type, &ret_type, &ret_size,
+                             &ret_items, &bytes_left, &xdata);
+    if (res == Success) {
+        if (ret_size == size && ret_items > 0) {
+            guint i;
+
+            *data = g_malloc(ret_items * (size / 8));
+            for (i = 0; i < ret_items; ++i)
+                switch (size) {
+                case 8:
+                    (*data)[i] = xdata[i];
+                    break;
+                case 16:
+                    ((guint16*)*data)[i] = ((gushort*)xdata)[i];
+                    break;
+                case 32:
+                    ((guint32*)*data)[i] = ((gulong*)xdata)[i];
+                    break;
+                default:
+                    g_assert_not_reached(); /* unhandled size */
+                }
+            *num = ret_items;
+            ret = TRUE;
+        }
+        XFree(xdata);
+    }
+    return ret;
+}
+
+static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr)
+{
+    XTextProperty tprop;
+    gboolean ret = FALSE;
+
+    if (XGetTextProperty(obt_display, win, &tprop, prop) && tprop.nitems) {
+        if (XTextPropertyToStringList(&tprop, list, nstr))
+            ret = TRUE;
+        XFree(tprop.value);
+    }
+    return ret;
+}
+
+gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
+{
+    return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
+}
+
+gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+                              guint *nret)
+{
+    return get_all(win, prop, type, 32, (guchar**)ret, nret);
+}
+
+gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret)
+{
+    gchar **list;
+    gint nstr;
+    gchar *s;
+
+    if (get_stringlist(win, prop, &list, &nstr) && nstr) {
+        s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
+        XFreeStringList(list);
+        if (s) {
+            *ret = s;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret)
+{
+    GSList *strs = NULL, *it;
+    gchar *raw, *p;
+    guint num, i, count = 0;
+
+    if (get_all(win, prop, OBT_PROP_ATOM(STRING), 8,
+                (guchar**)&raw, &num))
+    {
+        p = raw;
+        while (p < raw + num) {
+            ++count;
+            strs = g_slist_append(strs, p);
+            p += strlen(p) + 1; /* next string */
+        }
+
+        *ret = g_new0(gchar*, count + 1);
+        (*ret)[count] = NULL; /* null terminated list */
+
+        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+            (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
+            /* make sure translation did not fail */
+            if (!(*ret)[i])
+                (*ret)[i] = g_strdup("");
+        }
+        g_free(raw);
+        g_slist_free(strs);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret)
+{
+    gchar *raw;
+    gchar *str;
+    guint num;
+
+    if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
+                (guchar**)&raw, &num))
+    {
+        str = g_strndup(raw, num); /* grab the first string from the list */
+        g_free(raw);
+        if (g_utf8_validate(str, -1, NULL)) {
+            *ret = str;
+            return TRUE;
+        }
+        g_free(str);
+    }
+    return FALSE;
+}
+
+gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret)
+{
+    GSList *strs = NULL, *it;
+    gchar *raw, *p;
+    guint num, i, count = 0;
+
+    if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
+                (guchar**)&raw, &num))
+    {
+        p = raw;
+        while (p < raw + num) {
+            ++count;
+            strs = g_slist_append(strs, p);
+            p += strlen(p) + 1; /* next string */
+        }
+
+        *ret = g_new0(gchar*, count + 1);
+
+        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
+            if (g_utf8_validate(it->data, -1, NULL))
+                (*ret)[i] = g_strdup(it->data);
+            else
+                (*ret)[i] = g_strdup("");
+        }
+        g_free(raw);
+        g_slist_free(strs);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void obt_prop_set32(Window win, Atom prop, Atom type, gulong val)
+{
+    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
+                    (guchar*)&val, 1);
+}
+
+void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+                      guint num)
+{
+    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
+                    (guchar*)val, num);
+}
+
+void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val)
+{
+    gchar const *s[2] = { val, NULL };
+    obt_prop_set_strings_locale(win, prop, s);
+}
+
+void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs)
+{
+    gint i, count;
+    gchar **lstrs;
+    XTextProperty tprop;
+
+    /* count the strings in strs, and convert them to the locale format */
+    for (count = 0; strs[count]; ++count);
+    lstrs = g_new0(char*, count);
+    for (i = 0; i < count; ++i) {
+        lstrs[i] = g_locale_from_utf8(strs[i], -1, NULL, NULL, NULL);
+        if (!lstrs[i]) {
+            lstrs[i] = g_strdup(""); /* make it an empty string */
+            g_warning("Unable to translate string '%s' from UTF8 to locale "
+                      "format", strs[i]);
+        }
+    }
+
+
+    XStringListToTextProperty(lstrs, count, &tprop);
+    XSetTextProperty(obt_display, win, &tprop, prop);
+    XFree(tprop.value);
+}
+
+void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val)
+{
+    XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8), 8,
+                    PropModeReplace, (const guchar*)val, strlen(val));
+}
+
+void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs)
+{
+    GString *str;
+    gchar const **s;
+
+    str = g_string_sized_new(0);
+    for (s = strs; *s; ++s) {
+        str = g_string_append(str, *s);
+        str = g_string_append_c(str, '\0');
+    }
+    XChangeProperty(obt_display, win, prop, obt_prop_atom(OBT_PROP_UTF8), 8,
+                    PropModeReplace, (guchar*)str->str, str->len);
+    g_string_free(str, TRUE);
+}
+
+void obt_prop_erase(Window win, Atom prop)
+{
+    XDeleteProperty(obt_display, win, prop);
+}
+
+void obt_prop_message(gint screen, Window about, Atom messagetype,
+                      glong data0, glong data1, glong data2, glong data3,
+                      glong data4, glong mask)
+{
+    obt_prop_message_to(obt_root(screen), about, messagetype,
+                        data0, data1, data2, data3, data4, mask);
+}
+
+void obt_prop_message_to(Window to, Window about,
+                         Atom messagetype,
+                         glong data0, glong data1, glong data2, glong data3,
+                         glong data4, glong mask)
+{
+    XEvent ce;
+    ce.xclient.type = ClientMessage;
+    ce.xclient.message_type = messagetype;
+    ce.xclient.display = obt_display;
+    ce.xclient.window = about;
+    ce.xclient.format = 32;
+    ce.xclient.data.l[0] = data0;
+    ce.xclient.data.l[1] = data1;
+    ce.xclient.data.l[2] = data2;
+    ce.xclient.data.l[3] = data3;
+    ce.xclient.data.l[4] = data4;
+    XSendEvent(obt_display, to, FALSE, mask, &ce);
+}
diff --git a/obt/prop.h b/obt/prop.h
new file mode 100644 (file)
index 0000000..52c1de1
--- /dev/null
@@ -0,0 +1,285 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/prop.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_prop_h
+#define __obt_prop_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+    /* types */
+    OBT_PROP_CARDINAL, /*!< The atom which represents the Cardinal data type */
+    OBT_PROP_WINDOW,   /*!< The atom which represents window ids */
+    OBT_PROP_PIXMAP,   /*!< The atom which represents pixmap ids */
+    OBT_PROP_ATOM,     /*!< The atom which represents atom values */
+    OBT_PROP_STRING,   /*!< The atom which represents ascii strings */
+    OBT_PROP_UTF8,     /*!< The atom which represents utf8-encoded strings */
+
+    /* selection stuff */
+    OBT_PROP_MANAGER,
+
+    /* window hints */
+    OBT_PROP_WM_COLORMAP_WINDOWS,
+    OBT_PROP_WM_PROTOCOLS,
+    OBT_PROP_WM_STATE,
+    OBT_PROP_WM_DELETE_WINDOW,
+    OBT_PROP_WM_TAKE_FOCUS,
+    OBT_PROP_WM_CHANGE_STATE,
+    OBT_PROP_WM_NAME,
+    OBT_PROP_WM_ICON_NAME,
+    OBT_PROP_WM_CLASS,
+    OBT_PROP_WM_WINDOW_ROLE,
+    OBT_PROP_WM_CLIENT_MACHINE,
+    OBT_PROP_WM_COMMAND,
+    OBT_PROP_WM_CLIENT_LEADER,
+    OBT_PROP_WM_TRANSIENT_FOR,
+    OBT_PROP_MOTIF_WM_HINTS,
+    OBT_PROP_MOTIF_WM_INFO,
+
+    /* SM atoms */
+    OBT_PROP_SM_CLIENT_ID,
+
+    /* NETWM atoms */
+
+    /* Atoms that are used inside messages - these don't go in net_supported */
+
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT,
+    OBT_PROP_NET_WM_MOVERESIZE_MOVE,
+    OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD,
+    OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD,
+    OBT_PROP_NET_WM_MOVERESIZE_CANCEL,
+
+    OBT_PROP_NET_WM_STATE_ADD,
+    OBT_PROP_NET_WM_STATE_REMOVE,
+    OBT_PROP_NET_WM_STATE_TOGGLE,
+
+    OBT_PROP_NET_WM_ORIENTATION_HORZ,
+    OBT_PROP_NET_WM_ORIENTATION_VERT,
+    OBT_PROP_NET_WM_TOPLEFT,
+    OBT_PROP_NET_WM_TOPRIGHT,
+    OBT_PROP_NET_WM_BOTTOMRIGHT,
+    OBT_PROP_NET_WM_BOTTOMLEFT,
+
+    OBT_PROP_NET_WM_WINDOW_TYPE_POPUP_MENU,
+
+    OBT_PROP_PRIVATE_PADDING1,
+    OBT_PROP_PRIVATE_PADDING2,
+    OBT_PROP_PRIVATE_PADDING3,
+    OBT_PROP_PRIVATE_PADDING4,
+    OBT_PROP_PRIVATE_PADDING5,
+    OBT_PROP_PRIVATE_PADDING6,
+    OBT_PROP_PRIVATE_PADDING7,
+    OBT_PROP_PRIVATE_PADDING8,
+    OBT_PROP_PRIVATE_PADDING9,
+    OBT_PROP_PRIVATE_PADDING10,
+    OBT_PROP_PRIVATE_PADDING11,
+    OBT_PROP_PRIVATE_PADDING12,
+
+    /* Everything below here must go in net_supported on the root window */
+
+    /* root window properties */
+    OBT_PROP_NET_SUPPORTED,
+    OBT_PROP_NET_CLIENT_LIST,
+    OBT_PROP_NET_CLIENT_LIST_STACKING,
+    OBT_PROP_NET_NUMBER_OF_DESKTOPS,
+    OBT_PROP_NET_DESKTOP_GEOMETRY,
+    OBT_PROP_NET_DESKTOP_VIEWPORT,
+    OBT_PROP_NET_CURRENT_DESKTOP,
+    OBT_PROP_NET_DESKTOP_NAMES,
+    OBT_PROP_NET_ACTIVE_WINDOW,
+/*    Atom net_restack_window;*/
+    OBT_PROP_NET_WORKAREA,
+    OBT_PROP_NET_SUPPORTING_WM_CHECK,
+    OBT_PROP_NET_DESKTOP_LAYOUT,
+    OBT_PROP_NET_SHOWING_DESKTOP,
+
+    /* root window messages */
+    OBT_PROP_NET_CLOSE_WINDOW,
+    OBT_PROP_NET_WM_MOVERESIZE,
+    OBT_PROP_NET_MOVERESIZE_WINDOW,
+    OBT_PROP_NET_REQUEST_FRAME_EXTENTS,
+    OBT_PROP_NET_RESTACK_WINDOW,
+
+    /* helpful hints to apps that aren't used for anything */
+    OBT_PROP_NET_WM_FULL_PLACEMENT,
+
+    /* startup-notification extension */
+    OBT_PROP_NET_STARTUP_ID,
+
+    /* application window properties */
+    OBT_PROP_NET_WM_NAME,
+    OBT_PROP_NET_WM_VISIBLE_NAME,
+    OBT_PROP_NET_WM_ICON_NAME,
+    OBT_PROP_NET_WM_VISIBLE_ICON_NAME,
+    OBT_PROP_NET_WM_DESKTOP,
+    OBT_PROP_NET_WM_WINDOW_TYPE,
+    OBT_PROP_NET_WM_STATE,
+    OBT_PROP_NET_WM_STRUT,
+    OBT_PROP_NET_WM_STRUT_PARTIAL,
+    OBT_PROP_NET_WM_ICON,
+    OBT_PROP_NET_WM_ICON_GEOMETRY,
+    OBT_PROP_NET_WM_PID,
+    OBT_PROP_NET_WM_ALLOWED_ACTIONS,
+    OBT_PROP_NET_WM_USER_TIME,
+/*  OBT_PROP_NET_WM_USER_TIME_WINDOW, */
+    OBT_PROP_NET_FRAME_EXTENTS,
+
+    /* application protocols */
+    OBT_PROP_NET_WM_PING,
+#ifdef SYNC
+    OBT_PROP_NET_WM_SYNC_REQUEST,
+    OBT_PROP_NET_WM_SYNC_REQUEST_COUNTER,
+#endif
+
+    OBT_PROP_NET_WM_WINDOW_TYPE_DESKTOP,
+    OBT_PROP_NET_WM_WINDOW_TYPE_DOCK,
+    OBT_PROP_NET_WM_WINDOW_TYPE_TOOLBAR,
+    OBT_PROP_NET_WM_WINDOW_TYPE_MENU,
+    OBT_PROP_NET_WM_WINDOW_TYPE_UTILITY,
+    OBT_PROP_NET_WM_WINDOW_TYPE_SPLASH,
+    OBT_PROP_NET_WM_WINDOW_TYPE_DIALOG,
+    OBT_PROP_NET_WM_WINDOW_TYPE_NORMAL,
+
+    OBT_PROP_NET_WM_ACTION_MOVE,
+    OBT_PROP_NET_WM_ACTION_RESIZE,
+    OBT_PROP_NET_WM_ACTION_MINIMIZE,
+    OBT_PROP_NET_WM_ACTION_SHADE,
+/*    OBT_PROP_NET_WM_ACTION_STICK,*/
+    OBT_PROP_NET_WM_ACTION_MAXIMIZE_HORZ,
+    OBT_PROP_NET_WM_ACTION_MAXIMIZE_VERT,
+    OBT_PROP_NET_WM_ACTION_FULLSCREEN,
+    OBT_PROP_NET_WM_ACTION_CHANGE_DESKTOP,
+    OBT_PROP_NET_WM_ACTION_CLOSE,
+    OBT_PROP_NET_WM_ACTION_ABOVE,
+    OBT_PROP_NET_WM_ACTION_BELOW,
+
+    OBT_PROP_NET_WM_STATE_MODAL,
+/*    OBT_PROP_NET_WM_STATE_STICKY,*/
+    OBT_PROP_NET_WM_STATE_MAXIMIZED_VERT,
+    OBT_PROP_NET_WM_STATE_MAXIMIZED_HORZ,
+    OBT_PROP_NET_WM_STATE_SHADED,
+    OBT_PROP_NET_WM_STATE_SKIP_TASKBAR,
+    OBT_PROP_NET_WM_STATE_SKIP_PAGER,
+    OBT_PROP_NET_WM_STATE_HIDDEN,
+    OBT_PROP_NET_WM_STATE_FULLSCREEN,
+    OBT_PROP_NET_WM_STATE_ABOVE,
+    OBT_PROP_NET_WM_STATE_BELOW,
+    OBT_PROP_NET_WM_STATE_DEMANDS_ATTENTION,
+
+    /* KDE atoms */
+
+    OBT_PROP_KDE_WM_CHANGE_STATE,
+    OBT_PROP_KDE_NET_WM_FRAME_STRUT,
+    OBT_PROP_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+
+/*
+    OBT_PROP_ROOTPMAPID,
+    OBT_PROP_ESETROOTID,
+*/
+
+    /* Openbox specific atoms */
+
+    OBT_PROP_OB_WM_ACTION_UNDECORATE,
+    OBT_PROP_OB_WM_STATE_UNDECORATED,
+    OBT_PROP_OPENBOX_PID, /* this is depreecated in favour of ob_control */
+    OBT_PROP_OB_THEME,
+    OBT_PROP_OB_CONFIG_FILE,
+    OBT_PROP_OB_CONTROL,
+    OBT_PROP_OB_ROLE,
+    OBT_PROP_OB_NAME,
+    OBT_PROP_OB_CLASS,
+
+    OBT_PROP_NUM_ATOMS
+} ObtPropAtom;
+
+Atom obt_prop_atom(ObtPropAtom a);
+
+gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret);
+gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
+                              guint *nret);
+gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret);
+gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret);
+gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret);
+gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret);
+
+void obt_prop_set32(Window win, Atom prop, Atom type, gulong val);
+void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
+                          guint num);
+void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val);
+void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val);
+void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs);
+void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs);
+
+void obt_prop_erase(Window win, Atom prop);
+
+void obt_prop_message(gint screen, Window about, Atom messagetype,
+                      glong data0, glong data1, glong data2, glong data3,
+                      glong data4, glong mask);
+void obt_prop_message_to(Window to, Window about, Atom messagetype,
+                         glong data0, glong data1, glong data2, glong data3,
+                         glong data4, glong mask);
+
+#define OBT_PROP_ATOM(prop) obt_prop_atom(OBT_PROP_##prop)
+
+#define OBT_PROP_GET32(win, prop, type, ret) \
+    (obt_prop_get32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), ret))
+#define OBT_PROP_GETA32(win, prop, type, ret, nret) \
+    (obt_prop_get_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
+                          ret, nret))
+#define OBT_PROP_GETS(win, prop, type, ret) \
+    (obt_prop_get_string_##type(win, OBT_PROP_ATOM(prop), ret))
+#define OBT_PROP_GETSS(win, prop, type, ret) \
+    (obt_prop_get_strings_##type(win, OBT_PROP_ATOM(prop), ret))
+
+#define OBT_PROP_SET32(win, prop, type, val) \
+    (obt_prop_set32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), val))
+#define OBT_PROP_SETA32(win, prop, type, val, num) \
+    (obt_prop_set_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
+                          val, num))
+#define OBT_PROP_SETS(win, prop, type, val) \
+    (obt_prop_set_string_##type(win, OBT_PROP_ATOM(prop), val))
+#define OBT_PROP_SETSS(win, prop, type, strs) \
+    (obt_prop_set_strings_##type(win, OBT_PROP_ATOM(prop), strs))
+
+#define OBT_PROP_ERASE(win, prop) (obt_prop_erase(win, OBT_PROP_ATOM(prop)))
+
+#define OBT_PROP_MSG(screen, about, msgtype, data0, data1, data2, data3, \
+                     data4) \
+    (obt_prop_message(screen, about, OBT_PROP_ATOM(msgtype), \
+                      data0, data1, data2, data3, data4, \
+                      SubstructureNotifyMask | SubstructureRedirectMask))
+
+#define OBT_PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, \
+                        data4, mask) \
+    (obt_prop_message_to(to, about, OBT_PROP_ATOM(msgtype), \
+                         data0, data1, data2, data3, data4, mask))
+
+G_END_DECLS
+
+#endif /* __obt_prop_h */
diff --git a/obt/util.h b/obt/util.h
new file mode 100644 (file)
index 0000000..ff44d36
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/util.h for the Openbox window manager
+   Copyright (c) 2007        Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_util_h
+#define __obt_util_h
+
+#include <glib.h>
+
+#ifdef HAVE_STRING_H
+#  include <string.h> /* for memset() */
+#endif
+
+G_BEGIN_DECLS
+
+/* Util funcs */
+#define obt_free g_free
+#define obt_free0(p, type, num) memset((p), 0, sizeof(type) * (num)), g_free(p)
+
+G_END_DECLS
+
+
+#endif /*__obt_util_h*/
diff --git a/obt/version.h.in b/obt/version.h.in
new file mode 100644 (file)
index 0000000..8adfcf8
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef obt__version_h
+#define obt__version_h
+
+#define OBT_MAJOR_VERSION @OBT_MAJOR_VERSION@
+#define OBT_MINOR_VERSION @OBT_MINOR_VERSION@
+#define OBT_MICRO_VERSION @OBT_MICRO_VERSION@
+#define OBT_VERSION OBT_MAJOR_VERSION.OBT_MINOR_VERSION.OBT_MICRO_VERSION
+
+#define OBT_CHECK_VERSION(major,minor,micro) \
+    (OBT_MAJOR_VERSION > (major) || \
+     (OBT_MAJOR_VERSION == (major) && OBT_MINOR_VERSION > (minor)) || \
+     (OBT_MAJOR_VERSION == (major) && OBT_MINOR_VERSION == (minor) && \
+      OBT_MICRO_VERSION >= (micro)))
+
+#endif
diff --git a/obt/xevent.c b/obt/xevent.c
new file mode 100644 (file)
index 0000000..1cc32a9
--- /dev/null
@@ -0,0 +1,134 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/xevent.c for the Openbox window manager
+   Copyright (c) 2007        Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "obt/xevent.h"
+#include "obt/mainloop.h"
+#include "obt/util.h"
+
+typedef struct _ObtXEventBinding ObtXEventBinding;
+
+struct _ObtXEventHandler
+{
+    gint ref;
+    ObtMainLoop *loop;
+
+    /* An array of hash tables where the key is the window, and the value is
+       the ObtXEventBinding */
+    GHashTable **bindings;
+    gint num_event_types; /* the length of the bindings array */
+};
+
+struct _ObtXEventBinding
+{
+    Window win;
+    ObtXEventCallback func;
+    gpointer data;
+};
+
+static void xevent_handler(const XEvent *e, gpointer data);
+static guint window_hash(Window *w) { return *w; }
+static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
+
+ObtXEventHandler* xevent_new(void)
+{
+    ObtXEventHandler *h;
+
+    h = g_new0(ObtXEventHandler, 1);
+    h->ref = 1;
+
+    return h;
+}
+
+void xevent_ref(ObtXEventHandler *h)
+{
+    ++h->ref;
+}
+
+void xevent_unref(ObtXEventHandler *h)
+{
+    if (h && --h->ref == 0) {
+        gint i;
+
+        if (h->loop)
+            obt_main_loop_x_remove(h->loop, xevent_handler);
+        for (i = 0; i < h->num_event_types; ++i)
+            g_hash_table_destroy(h->bindings[i]);
+        g_free(h->bindings);
+
+        obt_free0(h, ObtXEventHandler, 1);
+    }
+}
+
+void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
+{
+    h->loop = loop;
+    obt_main_loop_x_add(loop, xevent_handler, h, NULL);
+}
+
+void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
+                        ObtXEventCallback func, gpointer data)
+{
+    ObtXEventBinding *b;
+
+    g_assert(func);
+
+    /* make sure we have a spot for the event */
+    if (type + 1 < h->num_event_types) {
+        gint i;
+        h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
+        for (i = h->num_event_types; i < type + 1; ++i)
+            h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
+                                                   (GEqualFunc)window_comp,
+                                                   NULL, g_free);
+        h->num_event_types = type + 1;
+    }
+
+    b = g_new(ObtXEventBinding, 1);
+    b->win = win;
+    b->func = func;
+    b->data = data;
+    g_hash_table_replace(h->bindings[type], &b->win, b);
+}
+
+void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
+{
+    g_assert(type < h->num_event_types);
+    g_assert(win);
+
+    g_hash_table_remove(h->bindings[type], &win);
+}
+
+static void xevent_handler(const XEvent *e, gpointer data)
+{
+    ObtXEventHandler *h;
+    ObtXEventBinding *b;
+
+    h = data;
+
+    if (e->type < h->num_event_types) {
+        const gint all = OBT_XEVENT_ALL_WINDOWS;
+        /* run the all_windows handler first */
+        b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
+        if (b) b->func(e, b->data);
+        /* then run the per-window handler */
+        b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
+        if (b) b->func(e, b->data);
+    }
+    else
+        g_message("Unhandled X Event type %d", e->xany.type);
+}
diff --git a/obt/xevent.h b/obt/xevent.h
new file mode 100644 (file)
index 0000000..ec0b66e
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   obt/xevent.h for the Openbox window manager
+   Copyright (c) 2007        Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __obt_xevent_h
+#define __obt_xevent_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+struct _ObtMainLoop;
+
+typedef struct _ObtXEventHandler ObtXEventHandler;
+
+typedef void (*ObtXEventCallback) (const XEvent *e, gpointer data);
+
+ObtXEventHandler* xevent_new(void);
+void              xevent_ref(ObtXEventHandler *h);
+void              xevent_unref(ObtXEventHandler *h);
+
+void              xevent_register(ObtXEventHandler *h,
+                                  struct _ObtMainLoop *loop);
+
+#define OBT_XEVENT_ALL_WINDOWS None
+
+void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
+                        ObtXEventCallback func, gpointer data);
+void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win);
+
+G_END_DECLS
+
+#endif /*__obt_xevent_h*/
index 948ac2c..7854636 100644 (file)
@@ -42,17 +42,23 @@ struct _ObActionsDefinition {
 
     gchar *name;
 
-    ObActionsDataSetupFunc setup;
+    gboolean canbeinteractive;
+    union {
+        ObActionsIDataSetupFunc i;
+        ObActionsDataSetupFunc n;
+    } setup;
     ObActionsDataFreeFunc free;
     ObActionsRunFunc run;
-    ObActionsInteractiveInputFunc i_input;
-    ObActionsInteractiveCancelFunc i_cancel;
 };
 
 struct _ObActionsAct {
     guint ref;
 
     ObActionsDefinition *def;
+    ObActionsIPreFunc i_pre;
+    ObActionsIInputFunc i_input;
+    ObActionsICancelFunc i_cancel;
+    ObActionsIPostFunc i_post;
     gpointer options;
 };
 
@@ -78,37 +84,55 @@ void actions_shutdown(gboolean reconfig)
     }
 }
 
-gboolean actions_register(const gchar *name,
-                          ObActionsDataSetupFunc setup,
-                          ObActionsDataFreeFunc free,
-                          ObActionsRunFunc run,
-                          ObActionsInteractiveInputFunc i_input,
-                          ObActionsInteractiveCancelFunc i_cancel)
+ObActionsDefinition* do_register(const gchar *name,
+                                 ObActionsDataFreeFunc free,
+                                 ObActionsRunFunc run)
 {
     GSList *it;
     ObActionsDefinition *def;
 
     g_assert(run != NULL);
-    g_assert((i_input == NULL) == (i_cancel == NULL));
 
     for (it = registered; it; it = g_slist_next(it)) {
         def = it->data;
         if (!g_ascii_strcasecmp(name, def->name)) /* already registered */
-            return FALSE;
+            return NULL;
     }
 
     def = g_new(ObActionsDefinition, 1);
     def->ref = 1;
     def->name = g_strdup(name);
-    def->setup = setup;
     def->free = free;
     def->run = run;
-    def->i_input = i_input;
-    def->i_cancel = i_cancel;
 
     registered = g_slist_prepend(registered, def);
+    return def;
+}
 
-    return TRUE;
+gboolean actions_register_i(const gchar *name,
+                            ObActionsIDataSetupFunc setup,
+                            ObActionsDataFreeFunc free,
+                            ObActionsRunFunc run)
+{
+    ObActionsDefinition *def = do_register(name, free, run);
+    if (def) {
+        def->canbeinteractive = TRUE;
+        def->setup.i = setup;
+    }
+    return def != NULL;
+}
+
+gboolean actions_register(const gchar *name,
+                          ObActionsDataSetupFunc setup,
+                          ObActionsDataFreeFunc free,
+                          ObActionsRunFunc run)
+{
+    ObActionsDefinition *def = do_register(name, free, run);
+    if (def) {
+        def->canbeinteractive = FALSE;
+        def->setup.n = setup;
+    }
+    return def != NULL;
 }
 
 static void actions_definition_ref(ObActionsDefinition *def)
@@ -144,6 +168,10 @@ static ObActionsAct* actions_build_act_from_string(const gchar *name)
         act->ref = 1;
         act->def = def;
         actions_definition_ref(act->def);
+        act->i_pre = NULL;
+        act->i_input = NULL;
+        act->i_cancel = NULL;
+        act->i_post = NULL;
         act->options = NULL;
     } else
         g_message(_("Invalid action \"%s\" requested. No such action exists."),
@@ -156,26 +184,46 @@ ObActionsAct* actions_parse_string(const gchar *name)
 {
     ObActionsAct *act = NULL;
 
-    if ((act = actions_build_act_from_string(name)))
-        if (act->def->setup)
-            act->options = act->def->setup(NULL, NULL, NULL);
+    if ((act = actions_build_act_from_string(name))) {
+        if (act->def->canbeinteractive) {
+            if (act->def->setup.i)
+                act->options = act->def->setup.i(NULL,
+                                                 &act->i_pre,
+                                                 &act->i_input,
+                                                 &act->i_cancel,
+                                                 &act->i_post);
+        }
+        else {
+            if (act->def->setup.n)
+                act->options = act->def->setup.n(NULL);
+        }
+    }
+                
 
     return act;
 }
 
-ObActionsAct* actions_parse(ObParseInst *i,
-                            xmlDocPtr doc,
-                            xmlNodePtr node)
+ObActionsAct* actions_parse(xmlNodePtr node)
 {
     gchar *name;
     ObActionsAct *act = NULL;
 
-    if (parse_attr_string("name", node, &name)) {
-        if ((act = actions_build_act_from_string(name)))
+    if (obt_parse_attr_string(node, "name", &name)) {
+        if ((act = actions_build_act_from_string(name))) {
             /* there is more stuff to parse here */
-            if (act->def->setup)
-                act->options = act->def->setup(i, doc, node->xmlChildrenNode);
-
+            if (act->def->canbeinteractive) {
+                if (act->def->setup.i)
+                    act->options = act->def->setup.i(node->children,
+                                                     &act->i_pre,
+                                                     &act->i_input,
+                                                     &act->i_cancel,
+                                                     &act->i_post);
+            }
+            else {
+                if (act->def->setup.n)
+                    act->options = act->def->setup.n(node->children);
+            }
+        }
         g_free(name);
     }
 
@@ -184,7 +232,7 @@ ObActionsAct* actions_parse(ObParseInst *i,
 
 gboolean actions_act_is_interactive(ObActionsAct *act)
 {
-    return act->def->i_cancel != NULL;
+    return act->i_input != NULL;
 }
 
 void actions_act_ref(ObActionsAct *act)
@@ -255,8 +303,13 @@ void actions_run_acts(GSList *acts,
                 /* cancel the old one */
                 if (interactive_act)
                     actions_interactive_cancel_act();
-                ok = actions_interactive_begin_act(act, state);
+                if (act->i_pre)
+                    if (!act->i_pre(state, act->options))
+                        act->i_input = NULL; /* remove the interactivity */
             }
+            /* check again cuz it might have been cancelled */
+            if (actions_act_is_interactive(act))
+                ok = actions_interactive_begin_act(act, state);
         }
 
         /* fire the action's run function with this data */
@@ -266,7 +319,7 @@ void actions_run_acts(GSList *acts,
                     actions_interactive_end_act();
             } else {
                 /* make sure its interactive if it returned TRUE */
-                g_assert(act->def->i_cancel && act->def->i_input);
+                g_assert(act->i_input);
 
                 /* no actions are run after the interactive one */
                 break;
@@ -283,7 +336,8 @@ gboolean actions_interactive_act_running(void)
 void actions_interactive_cancel_act(void)
 {
     if (interactive_act) {
-        interactive_act->def->i_cancel(interactive_act->options);
+        if (interactive_act->i_cancel)
+            interactive_act->i_cancel(interactive_act->options);
         actions_interactive_end_act();
     }
 }
@@ -311,6 +365,9 @@ static void actions_interactive_end_act(void)
     if (interactive_act) {
         ungrab_keyboard();
 
+        if (interactive_act->i_post)
+            interactive_act->i_post(interactive_act->options);
+
         actions_act_unref(interactive_act);
         interactive_act = NULL;
     }
@@ -320,8 +377,8 @@ gboolean actions_interactive_input_event(XEvent *e)
 {
     gboolean used = FALSE;
     if (interactive_act) {
-        if (!interactive_act->def->i_input(interactive_initial_state, e,
-                                           interactive_act->options, &used))
+        if (!interactive_act->i_input(interactive_initial_state, e,
+                                      interactive_act->options, &used))
         {
             used = TRUE; /* if it cancelled the action then it has to of
                             been used */
index 6db6f8d..94fc15c 100644 (file)
@@ -18,7 +18,8 @@
 
 #include "misc.h"
 #include "frame.h"
-#include "parser/parse.h"
+#include "obt/parse.h"
+
 #include <glib.h>
 #include <X11/Xlib.h>
 
@@ -30,16 +31,26 @@ typedef struct _ObActionsGlobalData   ObActionsGlobalData;
 typedef struct _ObActionsClientData   ObActionsClientData;
 typedef struct _ObActionsSelectorData ObActionsSelectorData;
 
-typedef gpointer (*ObActionsDataSetupFunc)(ObParseInst *i,
-                                           xmlDocPtr doc, xmlNodePtr node);
 typedef void     (*ObActionsDataFreeFunc)(gpointer options);
 typedef gboolean (*ObActionsRunFunc)(ObActionsData *data,
                                      gpointer options);
-typedef gboolean (*ObActionsInteractiveInputFunc)(guint initial_state,
+typedef gpointer (*ObActionsDataSetupFunc)(xmlNodePtr node);
+
+/* functions for interactive actions */
+/* return TRUE if the action is going to be interactive, or false to change
+   your mind and make it not */
+typedef gboolean (*ObActionsIPreFunc)(guint initial_state, gpointer options);
+typedef void     (*ObActionsIPostFunc)(gpointer options);
+typedef gboolean (*ObActionsIInputFunc)(guint initial_state,
                                                   XEvent *e,
                                                   gpointer options,
                                                   gboolean *used);
-typedef void     (*ObActionsInteractiveCancelFunc)(gpointer options);
+typedef void     (*ObActionsICancelFunc)(gpointer options);
+typedef gpointer (*ObActionsIDataSetupFunc)(xmlNodePtr node,
+                                            ObActionsIPreFunc *pre,
+                                            ObActionsIInputFunc *input,
+                                            ObActionsICancelFunc *cancel,
+                                            ObActionsIPostFunc *post);
 
 struct _ObActionsData {
     ObUserAction uact;
@@ -55,18 +66,18 @@ struct _ObActionsData {
 void actions_startup(gboolean reconfigure);
 void actions_shutdown(gboolean reconfigure);
 
-/*! If the action is interactive, then i_input and i_cancel are not NULL.
-  Otherwise, they should both be NULL. */
+/*! Use this if the actions created from this name may be interactive */
+gboolean actions_register_i(const gchar *name,
+                            ObActionsIDataSetupFunc setup,
+                            ObActionsDataFreeFunc free,
+                            ObActionsRunFunc run);
+
 gboolean actions_register(const gchar *name,
                           ObActionsDataSetupFunc setup,
                           ObActionsDataFreeFunc free,
-                          ObActionsRunFunc run,
-                          ObActionsInteractiveInputFunc i_input,
-                          ObActionsInteractiveCancelFunc i_cancel);
+                          ObActionsRunFunc run);
 
-ObActionsAct* actions_parse(ObParseInst *i,
-                            xmlDocPtr doc,
-                            xmlNodePtr node);
+ObActionsAct* actions_parse(xmlNodePtr node);
 ObActionsAct* actions_parse_string(const gchar *name);
 
 gboolean actions_act_is_interactive(ObActionsAct *act);
@@ -81,7 +92,7 @@ void actions_act_unref(ObActionsAct *act);
 void actions_set_need_pointer_replay_before_move(gboolean replay);
 /*! Returns if a ReplayPointer is still needed.  If it was called while running
   actions then this will be false */
-gboolean actions_get_need_pointer_replay_before_move();
+gboolean actions_get_need_pointer_replay_before_move(void);
 
 /*! Pass in a GSList of ObActionsAct's to be run. */
 void actions_run_acts(GSList *acts,
@@ -93,8 +104,8 @@ void actions_run_acts(GSList *acts,
                       ObFrameContext con,
                       struct _ObClient *client);
 
-gboolean actions_interactive_act_running();
-void actions_interactive_cancel_act();
+gboolean actions_interactive_act_running(void);
+void actions_interactive_cancel_act(void);
 
 gboolean actions_interactive_input_event(XEvent *e);
 
index 8125b9b..111742c 100644 (file)
@@ -7,36 +7,40 @@ typedef struct {
     gboolean add;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_add_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_remove_func(ObParseInst *i,
-                                  xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_add_func(xmlNodePtr node);
+static gpointer setup_remove_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_addcurrent_func(xmlNodePtr node);
+static gpointer setup_addlast_func(xmlNodePtr node);
+static gpointer setup_removecurrent_func(xmlNodePtr node);
+static gpointer setup_removelast_func(xmlNodePtr node);
 
 void action_addremovedesktop_startup(void)
 {
-    actions_register("AddDesktop",
-                     setup_add_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
-    actions_register("RemoveDesktop",
-                     setup_remove_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("AddDesktop", setup_add_func, g_free, run_func);
+    actions_register("RemoveDesktop", setup_remove_func, g_free, run_func);
+
+    /* 3.4-compatibility */
+    actions_register("AddDesktopLast", setup_addlast_func, g_free, run_func);
+    actions_register("RemoveDesktopLast", setup_removelast_func,
+                     g_free, run_func);
+    actions_register("AddDesktopCurrent", setup_addcurrent_func,
+                     g_free, run_func);
+    actions_register("RemoveDesktopCurrent", setup_removecurrent_func,
+                     g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("where", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "where"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "last"))
             o->current = FALSE;
         else if (!g_ascii_strcasecmp(s, "current"))
@@ -47,28 +51,20 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static gpointer setup_add_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_add_func(xmlNodePtr node)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node);
     o->add = TRUE;
     return o;
 }
 
-static gpointer setup_remove_func(ObParseInst *i,
-                                  xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_remove_func(xmlNodePtr node)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node);
     o->add = FALSE;
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
@@ -85,3 +81,32 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_addcurrent_func(xmlNodePtr node)
+{
+    Options *o = setup_add_func(node);
+    o->current = TRUE;
+    return o;
+}
+
+static gpointer setup_addlast_func(xmlNodePtr node)
+{
+    Options *o = setup_add_func(node);
+    o->current = FALSE;
+    return o;
+}
+
+static gpointer setup_removecurrent_func(xmlNodePtr node)
+{
+    Options *o = setup_remove_func(node);
+    o->current = TRUE;
+    return o;
+}
+
+static gpointer setup_removelast_func(xmlNodePtr node)
+{
+    Options *o = setup_remove_func(node);
+    o->current = FALSE;
+    return o;
+}
index 47141ac..4563e65 100644 (file)
@@ -38,4 +38,6 @@ void action_all_startup(void)
     action_growtoedge_startup();
     action_if_startup();
     action_focustobottom_startup();
+    /* 3.4-compatibility */
+    action_shadelowerraise_startup();
 }
index 5f3f573..6acbc9c 100644 (file)
@@ -1,43 +1,45 @@
 #ifndef __actions_all_h
 #define __actions_all_h
 
-void action_all_startup();
+void action_all_startup(void);
 
-void action_execute_startup();
-void action_debug_startup();
-void action_showmenu_startup();
-void action_showdesktop_startup();
-void action_reconfigure_startup();
-void action_exit_startup();
-void action_restart_startup();
-void action_cyclewindows_startup();
-void action_breakchroot_startup();
-void action_close_startup();
-void action_move_startup();
-void action_focus_startup();
-void action_raise_startup();
-void action_lower_startup();
-void action_raiselower_startup();
-void action_unfocus_startup();
-void action_iconify_startup();
-void action_fullscreen_startup();
-void action_maximize_startup();
-void action_moveresizeto_startup();
-void action_moverelative_startup();
-void action_shade_startup();
-void action_kill_startup();
-void action_omnipresent_startup();
-void action_directionalwindows_startup();
-void action_resize_startup();
-void action_decorations_startup();
-void action_desktop_startup();
-void action_resizerelative_startup();
-void action_addremovedesktop_startup();
-void action_dockautohide_startup();
-void action_layer_startup();
-void action_movetoedge_startup();
-void action_growtoedge_startup();
-void action_if_startup();
-void action_focustobottom_startup();
+void action_execute_startup(void);
+void action_debug_startup(void);
+void action_showmenu_startup(void);
+void action_showdesktop_startup(void);
+void action_reconfigure_startup(void);
+void action_exit_startup(void);
+void action_restart_startup(void);
+void action_cyclewindows_startup(void);
+void action_breakchroot_startup(void);
+void action_close_startup(void);
+void action_move_startup(void);
+void action_focus_startup(void);
+void action_raise_startup(void);
+void action_lower_startup(void);
+void action_raiselower_startup(void);
+void action_unfocus_startup(void);
+void action_iconify_startup(void);
+void action_fullscreen_startup(void);
+void action_maximize_startup(void);
+void action_moveresizeto_startup(void);
+void action_moverelative_startup(void);
+void action_shade_startup(void);
+void action_kill_startup(void);
+void action_omnipresent_startup(void);
+void action_directionalwindows_startup(void);
+void action_resize_startup(void);
+void action_decorations_startup(void);
+void action_desktop_startup(void);
+void action_resizerelative_startup(void);
+void action_addremovedesktop_startup(void);
+void action_dockautohide_startup(void);
+void action_layer_startup(void);
+void action_movetoedge_startup(void);
+void action_growtoedge_startup(void);
+void action_if_startup(void);
+void action_focustobottom_startup(void);
+/* 3.4-compatibility */
+void action_shadelowerraise_startup(void);
 
 #endif
index 9804091..8c00458 100644 (file)
@@ -7,8 +7,7 @@ void action_breakchroot_startup(void)
 {
     actions_register("BreakChroot",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index ab75e05..d2bc96c 100644 (file)
@@ -7,8 +7,7 @@ void action_close_startup(void)
 {
     actions_register("Close",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 32d6a45..28618ef 100644 (file)
@@ -8,23 +8,36 @@
 
 typedef struct {
     gboolean linear;
-    gboolean dialog;
     gboolean dock_windows;
     gboolean desktop_windows;
     gboolean all_desktops;
     gboolean forward;
     gboolean bar;
     gboolean raise;
+    ObFocusCyclePopupMode dialog_mode;
     GSList *actions;
-} Options;
 
-static gboolean cycling = FALSE;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
-                                   xmlNodePtr node);
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
-                                    xmlNodePtr node);
+    /* options for after we're done */
+    gboolean cancel; /* did the user cancel or not */
+    guint state;     /* keyboard state when finished */
+} Options;
+
+static gpointer setup_func(xmlNodePtr node,
+                           ObActionsIPreFunc *pre,
+                           ObActionsIInputFunc *in,
+                           ObActionsICancelFunc *c,
+                           ObActionsIPostFunc *post);
+static gpointer setup_forward_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *in,
+                                   ObActionsICancelFunc *c,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_backward_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *in,
+                                    ObActionsICancelFunc *c,
+                                    ObActionsIPostFunc *post);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 static gboolean i_input_func(guint initial_state,
@@ -32,49 +45,55 @@ static gboolean i_input_func(guint initial_state,
                              gpointer options,
                              gboolean *used);
 static void     i_cancel_func(gpointer options);
-
-static void     end_cycle(gboolean cancel, guint state, Options *o);
+static void     i_post_func(gpointer options);
 
 void action_cyclewindows_startup(void)
 {
-    actions_register("NextWindow", setup_forward_func, free_func,
-                     run_func, i_input_func, i_cancel_func);
-    actions_register("PreviousWindow", setup_backward_func, free_func,
-                     run_func, i_input_func, i_cancel_func);
+    actions_register_i("NextWindow", setup_forward_func, free_func, run_func);
+    actions_register_i("PreviousWindow", setup_backward_func, free_func,
+                       run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node,
+                           ObActionsIPreFunc *pre,
+                           ObActionsIInputFunc *input,
+                           ObActionsICancelFunc *cancel,
+                           ObActionsIPostFunc *post)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
-    o->dialog = TRUE;
     o->bar = TRUE;
-
-    if ((n = parse_find_node("linear", node)))
-        o->linear = parse_bool(doc, n);
-    if ((n = parse_find_node("dialog", node)))
-        o->dialog = parse_bool(doc, n);
-    if ((n = parse_find_node("bar", node)))
-        o->bar = parse_bool(doc, n);
-    if ((n = parse_find_node("raise", node)))
-        o->raise = parse_bool(doc, n);
-    if ((n = parse_find_node("panels", node)))
-        o->dock_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("desktop", node)))
-        o->desktop_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("allDesktops", node)))
-        o->all_desktops = parse_bool(doc, n);
-
-    if ((n = parse_find_node("finalactions", node))) {
+    o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_LIST;
+
+    if ((n = obt_parse_find_node(node, "linear")))
+        o->linear = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "dialog"))) {
+        if (obt_parse_node_contains(n, "none"))
+            o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
+        else if (obt_parse_node_contains(n, "icons"))
+            o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_ICONS;
+    }
+    if ((n = obt_parse_find_node(node, "bar")))
+        o->bar = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "raise")))
+        o->raise = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "panels")))
+        o->dock_windows = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "desktop")))
+        o->desktop_windows = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "allDesktops")))
+        o->all_desktops = obt_parse_node_bool(n);
+
+    if ((n = obt_parse_find_node(node, "finalactions"))) {
         xmlNodePtr m;
 
-        m = parse_find_node("action", n->xmlChildrenNode);
+        m = obt_parse_find_node(n->children, "action");
         while (m) {
-            ObActionsAct *action = actions_parse(i, doc, m);
+            ObActionsAct *action = actions_parse(m);
             if (action) o->actions = g_slist_append(o->actions, action);
-            m = parse_find_node("action", m->next);
+            m = obt_parse_find_node(m->next, "action");
         }
     }
     else {
@@ -86,21 +105,30 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
                                      actions_parse_string("Unshade"));
     }
 
+    *input = i_input_func;
+    *cancel = i_cancel_func;
+    *post = i_post_func;
     return o;
 }
 
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
-                                   xmlNodePtr node)
+static gpointer setup_forward_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node, pre, input, cancel, post);
     o->forward = TRUE;
     return o;
 }
 
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
-                                    xmlNodePtr node)
+static gpointer setup_backward_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *input,
+                                    ObActionsICancelFunc *cancel,
+                                    ObActionsIPostFunc *post)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node, pre, input, cancel, post);
     o->forward = FALSE;
     return o;
 }
@@ -129,9 +157,8 @@ static gboolean run_func(ObActionsData *data, gpointer options)
                      o->linear,
                      TRUE,
                      o->bar,
-                     o->dialog,
+                     o->dialog_mode,
                      FALSE, FALSE);
-    cycling = TRUE;
 
     stacking_restore();
     if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
@@ -144,10 +171,13 @@ static gboolean i_input_func(guint initial_state,
                              gpointer options,
                              gboolean *used)
 {
+    Options *o = options;
+
     if (e->type == KeyPress) {
         /* Escape cancels no matter what */
         if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
-            end_cycle(TRUE, e->xkey.state, options);
+            o->cancel = TRUE;
+            o->state = e->xkey.state;
             return FALSE;
         }
 
@@ -155,7 +185,8 @@ static gboolean i_input_func(guint initial_state,
         else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
                  !initial_state)
         {
-            end_cycle(FALSE, e->xkey.state, options);
+            o->cancel = FALSE;
+            o->state = e->xkey.state;
             return FALSE;
         }
     }
@@ -163,7 +194,8 @@ static gboolean i_input_func(guint initial_state,
     else if (e->type == KeyRelease && initial_state &&
              (e->xkey.state & initial_state) == 0)
     {
-        end_cycle(FALSE, e->xkey.state, options);
+        o->cancel = FALSE;
+        o->state = e->xkey.state;
         return FALSE;
     }
 
@@ -172,14 +204,14 @@ static gboolean i_input_func(guint initial_state,
 
 static void i_cancel_func(gpointer options)
 {
-    /* we get cancelled when we move focus, but we're not cycling anymore, so
-       just ignore that */
-    if (cycling)
-        end_cycle(TRUE, 0, options);
+    Options *o = options;
+    o->cancel = TRUE;
+    o->state = 0;
 }
 
-static void end_cycle(gboolean cancel, guint state, Options *o)
+static void i_post_func(gpointer options)
 {
+    Options *o = options;
     struct _ObClient *ft;
 
     ft = focus_cycle(o->forward,
@@ -189,13 +221,12 @@ static void end_cycle(gboolean cancel, guint state, Options *o)
                      o->linear,
                      TRUE,
                      o->bar,
-                     o->dialog,
-                     TRUE, cancel);
-    cycling = FALSE;
+                     o->dialog_mode,
+                     TRUE, o->cancel);
 
     if (ft)
         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
-                         state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
+                         o->state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
 
     stacking_restore();
 }
index f71b685..3ae0901 100644 (file)
@@ -5,39 +5,32 @@ typedef struct {
     gchar   *str;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_debug_startup(void)
 {
-    actions_register("Debug",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Debug", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("string", node)))
-        o->str = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "string")))
+        o->str = obt_parse_node_string(n);
     return o;
 }
 
 static void free_func(gpointer options)
 {
     Options *o = options;
-
-    if (o) {
-        g_free(o->str);
-        g_free(o);
-    }
+    g_free(o->str);
+    g_free(o);
 }
 
 /* Always return FALSE because its not interactive */
index e85fb8e..f6fd2cb 100644 (file)
@@ -7,10 +7,9 @@ static gboolean run_func_toggle(ObActionsData *data, gpointer options);
 
 void action_decorations_startup(void)
 {
-    actions_register("Decorate", NULL, NULL, run_func_on, NULL, NULL);
-    actions_register("Undecorate", NULL, NULL, run_func_off, NULL, NULL);
-    actions_register("ToggleDecorations", NULL, NULL, run_func_toggle,
-                     NULL, NULL);
+    actions_register("Decorate", NULL, NULL, run_func_on);
+    actions_register("Undecorate", NULL, NULL, run_func_off);
+    actions_register("ToggleDecorations", NULL, NULL, run_func_toggle);
 }
 
 /* Always return FALSE because its not interactive */
index 0741615..14f6ef2 100644 (file)
@@ -1,6 +1,7 @@
 #include "openbox/actions.h"
 #include "openbox/screen.h"
 #include "openbox/client.h"
+#include "openbox/openbox.h"
 #include <glib.h>
 
 typedef enum {
@@ -24,37 +25,143 @@ typedef struct {
     } u;
     gboolean send;
     gboolean follow;
+    gboolean interactive;
 } Options;
 
-static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node);
-static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
-                                xmlNodePtr node);
+static gpointer setup_go_func(xmlNodePtr node,
+                              ObActionsIPreFunc *pre,
+                              ObActionsIInputFunc *input,
+                              ObActionsICancelFunc *cancel,
+                              ObActionsIPostFunc *post);
+static gpointer setup_send_func(xmlNodePtr node,
+                                ObActionsIPreFunc *pre,
+                                ObActionsIInputFunc *input,
+                                ObActionsICancelFunc *cancel,
+                                ObActionsIPostFunc *post);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
+static gboolean i_pre_func(guint state, gpointer options);
+static gboolean i_input_func(guint initial_state,
+                             XEvent *e,
+                             gpointer options,
+                             gboolean *used);
+static void i_post_func(gpointer options);
+
+/* 3.4-compatibility */
+static gpointer setup_go_last_func(xmlNodePtr node);
+static gpointer setup_send_last_func(xmlNodePtr node);
+static gpointer setup_go_abs_func(xmlNodePtr node);
+static gpointer setup_send_abs_func(xmlNodePtr node);
+static gpointer setup_go_next_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_send_next_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post);
+static gpointer setup_go_prev_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_send_prev_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post);
+static gpointer setup_go_left_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_send_left_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post);
+static gpointer setup_go_right_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *input,
+                                    ObActionsICancelFunc *cancel,
+                                    ObActionsIPostFunc *post);
+static gpointer setup_send_right_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *input,
+                                      ObActionsICancelFunc *cancel,
+                                      ObActionsIPostFunc *post);
+static gpointer setup_go_up_func(xmlNodePtr node,
+                                 ObActionsIPreFunc *pre,
+                                 ObActionsIInputFunc *input,
+                                 ObActionsICancelFunc *cancel,
+                                 ObActionsIPostFunc *post);
+static gpointer setup_send_up_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_go_down_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_send_down_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post);
 void action_desktop_startup(void)
 {
-    actions_register("GoToDesktop", setup_go_func, g_free, run_func,
-                     NULL, NULL);
-    actions_register("SendToDesktop", setup_send_func, g_free, run_func,
-                     NULL, NULL);
+    actions_register_i("GoToDesktop", setup_go_func, g_free, run_func);
+    actions_register_i("SendToDesktop", setup_send_func, g_free, run_func);
+    /* 3.4-compatibility */
+    actions_register("DesktopLast", setup_go_last_func, g_free, run_func);
+    actions_register("SendToDesktopLast", setup_send_last_func,
+                     g_free, run_func);
+    actions_register("Desktop", setup_go_abs_func, g_free, run_func);
+    actions_register("SendToDesktop", setup_send_abs_func, g_free, run_func);
+    actions_register_i("DesktopNext", setup_go_next_func, g_free, run_func);
+    actions_register_i("SendToDesktopNext", setup_send_next_func,
+                       g_free, run_func);
+    actions_register_i("DesktopPrevious", setup_go_prev_func,
+                       g_free, run_func);
+    actions_register_i("SendToDesktopPrevious", setup_send_prev_func,
+                       g_free, run_func);
+    actions_register_i("DesktopLeft", setup_go_left_func, g_free, run_func);
+    actions_register_i("SendToDesktopLeft", setup_send_left_func,
+                       g_free, run_func);
+    actions_register_i("DesktopRight", setup_go_right_func, g_free, run_func);
+    actions_register_i("SendToDesktopRight", setup_send_right_func,
+                       g_free, run_func);
+    actions_register_i("DesktopUp", setup_go_up_func, g_free, run_func);
+    actions_register_i("SendToDesktopUp", setup_send_up_func,
+                       g_free, run_func);
+    actions_register_i("DesktopDown", setup_go_down_func, g_free, run_func);
+    actions_register_i("SendToDesktopDown", setup_send_down_func,
+                       g_free, run_func);
 }
 
-static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node,
+                           ObActionsIPreFunc *pre,
+                           ObActionsIInputFunc *input,
+                           ObActionsICancelFunc *cancel,
+                           ObActionsIPostFunc *post)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
-    /* don't go anywhere if theres no options given */
+    /* don't go anywhere if there are no options given */
     o->type = ABSOLUTE;
     o->u.abs.desktop = screen_desktop;
     /* wrap by default - it's handy! */
     o->u.rel.wrap = TRUE;
 
-    if ((n = parse_find_node("to", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "to"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "last"))
             o->type = LAST;
         else if (!g_ascii_strcasecmp(s, "next")) {
@@ -94,24 +201,54 @@ static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
         g_free(s);
     }
 
-    if ((n = parse_find_node("wrap", node)))
-        o->u.rel.wrap = parse_bool(doc, n);
+    if ((n = obt_parse_find_node(node, "wrap")))
+        o->u.rel.wrap = obt_parse_node_bool(n);
 
     return o;
 }
 
-static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
-                                xmlNodePtr node)
+
+static gpointer setup_go_func(xmlNodePtr node,
+                              ObActionsIPreFunc *pre,
+                              ObActionsIInputFunc *input,
+                              ObActionsICancelFunc *cancel,
+                              ObActionsIPostFunc *post)
+{
+    Options *o;
+
+    o = setup_func(node, pre, input, cancel, post);
+    if (o->type == RELATIVE) {
+        o->interactive = TRUE;
+        *pre = i_pre_func;
+        *input = i_input_func;
+        *post = i_post_func;
+    }
+
+    return o;
+}
+
+static gpointer setup_send_func(xmlNodePtr node,
+                                ObActionsIPreFunc *pre,
+                                ObActionsIInputFunc *input,
+                                ObActionsICancelFunc *cancel,
+                                ObActionsIPostFunc *post)
 {
     xmlNodePtr n;
     Options *o;
 
-    o = setup_go_func(i, doc, node);
+    o = setup_func(node, pre, input, cancel, post);
     o->send = TRUE;
     o->follow = TRUE;
 
-    if ((n = parse_find_node("follow", node)))
-        o->follow = parse_bool(doc, n);
+    if ((n = obt_parse_find_node(node, "follow")))
+        o->follow = obt_parse_node_bool(n);
+
+    if (o->type == RELATIVE && o->follow) {
+        o->interactive = TRUE;
+        *pre = i_pre_func;
+        *input = i_input_func;
+        *post = i_post_func;
+    }
 
     return o;
 }
@@ -133,6 +270,8 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         d = screen_find_desktop(screen_desktop,
                                 o->u.rel.dir, o->u.rel.wrap, o->u.rel.linear);
         break;
+    default:
+        g_assert_not_reached();
     }
 
     if (d < screen_num_desktops && d != screen_desktop) {
@@ -152,5 +291,264 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
         actions_client_move(data, FALSE);
     }
-    return FALSE;
+
+    return o->interactive;
+}
+
+static gboolean i_input_func(guint initial_state,
+                             XEvent *e,
+                             gpointer options,
+                             gboolean *used)
+{
+    if (e->type == KeyPress) {
+        /* Escape cancels no matter what */
+        if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
+            return FALSE;
+        }
+
+        /* There were no modifiers and they pressed enter */
+        else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN) &&
+                 !initial_state)
+        {
+            return FALSE;
+        }
+    }
+    /* They released the modifiers */
+    else if (e->type == KeyRelease && initial_state &&
+             (e->xkey.state & initial_state) == 0)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean i_pre_func(guint initial_state, gpointer options)
+{
+    if (!initial_state) {
+        Options *o = options;
+        o->interactive = FALSE;
+        return FALSE;
+    }
+    else {
+        screen_show_desktop_popup(screen_desktop, TRUE);
+        return TRUE;
+    }
+}
+
+static void i_post_func(gpointer options)
+{
+    screen_hide_desktop_popup();
+}
+
+/* 3.4-compatilibity */
+static gpointer setup_follow(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o = g_new0(Options, 1);
+    o->send = TRUE;
+    o->follow = TRUE;
+    if ((n = obt_parse_find_node(node, "follow")))
+        o->follow = obt_parse_node_bool(n);
+    return o;
+}
+
+static gpointer setup_go_last_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->type = LAST;
+    return o;
+}
+
+static gpointer setup_send_last_func(xmlNodePtr node)
+{
+    Options *o = setup_follow(node);
+    o->type = LAST;
+    return o;
+}
+
+static gpointer setup_go_abs_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o = g_new0(Options, 1);
+    o->type = ABSOLUTE;
+    if ((n = obt_parse_find_node(node, "desktop")))
+        o->u.abs.desktop = obt_parse_node_int(n) - 1;
+    else
+        o->u.abs.desktop = screen_desktop;
+    return o;
+}
+
+static gpointer setup_send_abs_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o = setup_follow(node);
+    o->type = ABSOLUTE;
+    if ((n = obt_parse_find_node(node, "desktop")))
+        o->u.abs.desktop = obt_parse_node_int(n) - 1;
+    else
+        o->u.abs.desktop = screen_desktop;
+    return o;
+}
+
+static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
+                      ObDirection dir,
+                      ObActionsIPreFunc *pre,
+                      ObActionsIInputFunc *input,
+                      ObActionsIPostFunc *post)
+{
+    xmlNodePtr n;
+
+    o->type = RELATIVE;
+    o->u.rel.linear = lin;
+    o->u.rel.dir = dir;
+    o->u.rel.wrap = TRUE;
+
+    if ((n = obt_parse_find_node(node, "wrap")))
+        o->u.rel.wrap = obt_parse_node_bool(n);
+
+    if (input) {
+        o->interactive = TRUE;
+        *pre = i_pre_func;
+        *input = i_input_func;
+        *post = i_post_func;
+    }
+}
+
+static gpointer setup_go_next_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_next_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
+              pre, (o->follow ? input : NULL), post);
+    return o;
+}
+
+static gpointer setup_go_prev_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_prev_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
+              pre, (o->follow ? input : NULL), post);
+    return o;
+}
+
+static gpointer setup_go_left_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_left_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
+              pre, (o->follow ? input : NULL), post);
+    return o;
+}
+
+static gpointer setup_go_right_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *input,
+                                    ObActionsICancelFunc *cancel,
+                                    ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_right_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *input,
+                                      ObActionsICancelFunc *cancel,
+                                      ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
+              pre, (o->follow ? input : NULL), post);
+    return o;
+}
+
+static gpointer setup_go_up_func(xmlNodePtr node,
+                                 ObActionsIPreFunc *pre,
+                                 ObActionsIInputFunc *input,
+                                 ObActionsICancelFunc *cancel,
+                                 ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_up_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
+              pre, (o->follow ? input : NULL), post);
+    return o;
+}
+
+static gpointer setup_go_down_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
+{
+    Options *o = g_new0(Options, 1);
+    setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
+    return o;
+}
+
+static gpointer setup_send_down_func(xmlNodePtr node,
+                                     ObActionsIPreFunc *pre,
+                                     ObActionsIInputFunc *input,
+                                     ObActionsICancelFunc *cancel,
+                                     ObActionsIPostFunc *post)
+{
+    Options *o = setup_follow(node);
+    setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
+              pre, (o->follow ? input : NULL), post);
+    return o;
 }
index 6559e44..0d1476c 100644 (file)
@@ -20,11 +20,13 @@ typedef struct {
 
 static gboolean cycling = FALSE;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
-                                 xmlNodePtr node);
-static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_cycle_func(xmlNodePtr node,
+                                 ObActionsIPreFunc *pre,
+                                 ObActionsIInputFunc *input,
+                                 ObActionsICancelFunc *cancel,
+                                 ObActionsIPostFunc *post);
+static gpointer setup_target_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 static gboolean i_input_func(guint initial_state,
@@ -35,15 +37,98 @@ static void     i_cancel_func(gpointer options);
 
 static void     end_cycle(gboolean cancel, guint state, Options *o);
 
+/* 3.4-compatibility */
+static gpointer setup_north_cycle_func(xmlNodePtr node,
+                                       ObActionsIPreFunc *pre,
+                                       ObActionsIInputFunc *in,
+                                       ObActionsICancelFunc *c,
+                                       ObActionsIPostFunc *post);
+static gpointer setup_south_cycle_func(xmlNodePtr node,
+                                       ObActionsIPreFunc *pre,
+                                       ObActionsIInputFunc *in,
+                                       ObActionsICancelFunc *c,
+                                       ObActionsIPostFunc *post);
+static gpointer setup_east_cycle_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *in,
+                                      ObActionsICancelFunc *c,
+                                      ObActionsIPostFunc *post);
+static gpointer setup_west_cycle_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *in,
+                                      ObActionsICancelFunc *c,
+                                      ObActionsIPostFunc *post);
+static gpointer setup_northwest_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *in,
+                                           ObActionsICancelFunc *c,
+                                           ObActionsIPostFunc *post);
+static gpointer setup_northeast_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *in,
+                                           ObActionsICancelFunc *c,
+                                           ObActionsIPostFunc *post);
+static gpointer setup_southwest_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *in,
+                                           ObActionsICancelFunc *c,
+                                           ObActionsIPostFunc *post);
+static gpointer setup_southeast_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *in,
+                                           ObActionsICancelFunc *c,
+                                           ObActionsIPostFunc *post);
+static gpointer setup_north_target_func(xmlNodePtr node);
+static gpointer setup_south_target_func(xmlNodePtr node);
+static gpointer setup_east_target_func(xmlNodePtr node);
+static gpointer setup_west_target_func(xmlNodePtr node);
+static gpointer setup_northwest_target_func(xmlNodePtr node);
+static gpointer setup_northeast_target_func(xmlNodePtr node);
+static gpointer setup_southwest_target_func(xmlNodePtr node);
+static gpointer setup_southeast_target_func(xmlNodePtr node);
+
 void action_directionalwindows_startup(void)
 {
-    actions_register("DirectionalCycleWindows", setup_cycle_func, free_func,
-                     run_func, i_input_func, i_cancel_func);
+    actions_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
+                       run_func);
     actions_register("DirectionalTargetWindow", setup_target_func, free_func,
-                     run_func, NULL, NULL);
+                     run_func);
+    /* 3.4-compatibility */
+    actions_register_i("DirectionalFocusNorth", setup_north_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusSouth", setup_south_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusWest", setup_west_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusEast", setup_east_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusNorthWest", setup_northwest_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusNorthEast", setup_northeast_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusSouthWest", setup_southwest_cycle_func,
+                       free_func, run_func);
+    actions_register_i("DirectionalFocusSouthEast", setup_southeast_cycle_func,
+                       free_func, run_func);
+    actions_register("DirectionalTargetNorth", setup_north_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetSouth", setup_south_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetWest", setup_west_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetEast", setup_east_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
+                     free_func, run_func);
+    actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
+                     free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
@@ -52,18 +137,18 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     o->dialog = TRUE;
     o->bar = TRUE;
 
-    if ((n = parse_find_node("dialog", node)))
-        o->dialog = parse_bool(doc, n);
-    if ((n = parse_find_node("bar", node)))
-        o->bar = parse_bool(doc, n);
-    if ((n = parse_find_node("raise", node)))
-        o->raise = parse_bool(doc, n);
-    if ((n = parse_find_node("panels", node)))
-        o->dock_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("desktop", node)))
-        o->desktop_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("direction", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "dialog")))
+        o->dialog = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "bar")))
+        o->bar = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "raise")))
+        o->raise = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "panels")))
+        o->dock_windows = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "desktop")))
+        o->desktop_windows = obt_parse_node_bool(n);
+    if ((n = obt_parse_find_node(node, "direction"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "north") ||
             !g_ascii_strcasecmp(s, "up"))
             o->direction = OB_DIRECTION_NORTH;
@@ -87,14 +172,14 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
         g_free(s);
     }
 
-    if ((n = parse_find_node("finalactions", node))) {
+    if ((n = obt_parse_find_node(node, "finalactions"))) {
         xmlNodePtr m;
 
-        m = parse_find_node("action", n->xmlChildrenNode);
+        m = obt_parse_find_node(n->children, "action");
         while (m) {
-            ObActionsAct *action = actions_parse(i, doc, m);
+            ObActionsAct *action = actions_parse(m);
             if (action) o->actions = g_slist_append(o->actions, action);
-            m = parse_find_node("action", m->next);
+            m = obt_parse_find_node(m->next, "action");
         }
     }
     else {
@@ -109,18 +194,22 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
-                                 xmlNodePtr node)
+static gpointer setup_cycle_func(xmlNodePtr node,
+                                 ObActionsIPreFunc *pre,
+                                 ObActionsIInputFunc *input,
+                                 ObActionsICancelFunc *cancel,
+                                 ObActionsIPostFunc *post)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node);
     o->interactive = TRUE;
+    *input = i_input_func;
+    *cancel = i_cancel_func;
     return o;
 }
 
-static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node)
+static gpointer setup_target_func(xmlNodePtr node)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node);
     o->interactive = FALSE;
     return o;
 }
@@ -220,3 +309,149 @@ static void end_cycle(gboolean cancel, guint state, Options *o)
 
     stacking_restore();
 }
+
+/* 3.4-compatibility */
+static gpointer setup_north_cycle_func(xmlNodePtr node,
+                                       ObActionsIPreFunc *pre,
+                                       ObActionsIInputFunc *input,
+                                       ObActionsICancelFunc *cancel,
+                                       ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_NORTH;
+    return o;
+}
+
+static gpointer setup_south_cycle_func(xmlNodePtr node,
+                                       ObActionsIPreFunc *pre,
+                                       ObActionsIInputFunc *input,
+                                       ObActionsICancelFunc *cancel,
+                                       ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_SOUTH;
+    return o;
+}
+
+static gpointer setup_east_cycle_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *input,
+                                      ObActionsICancelFunc *cancel,
+                                      ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_EAST;
+    return o;
+}
+
+static gpointer setup_west_cycle_func(xmlNodePtr node,
+                                      ObActionsIPreFunc *pre,
+                                      ObActionsIInputFunc *input,
+                                      ObActionsICancelFunc *cancel,
+                                      ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_WEST;
+    return o;
+}
+
+static gpointer setup_northwest_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *input,
+                                           ObActionsICancelFunc *cancel,
+                                           ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_NORTHWEST;
+    return o;
+}
+
+static gpointer setup_northeast_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *input,
+                                           ObActionsICancelFunc *cancel,
+                                           ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_EAST;
+    return o;
+}
+
+static gpointer setup_southwest_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *input,
+                                           ObActionsICancelFunc *cancel,
+                                           ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_SOUTHWEST;
+    return o;
+}
+
+static gpointer setup_southeast_cycle_func(xmlNodePtr node,
+                                           ObActionsIPreFunc *pre,
+                                           ObActionsIInputFunc *input,
+                                           ObActionsICancelFunc *cancel,
+                                           ObActionsIPostFunc *post)
+{
+    Options *o = setup_cycle_func(node, pre, input, cancel, post);
+    o->direction = OB_DIRECTION_SOUTHEAST;
+    return o;
+}
+
+static gpointer setup_north_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_NORTH;
+    return o;
+}
+
+static gpointer setup_south_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_SOUTH;
+    return o;
+}
+
+static gpointer setup_east_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_EAST;
+    return o;
+}
+
+static gpointer setup_west_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_WEST;
+    return o;
+}
+
+static gpointer setup_northwest_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_NORTHWEST;
+    return o;
+}
+
+static gpointer setup_northeast_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_NORTHEAST;
+    return o;
+}
+
+static gpointer setup_southwest_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_SOUTHWEST;
+    return o;
+}
+
+static gpointer setup_southeast_target_func(xmlNodePtr node)
+{
+    Options *o = setup_target_func(node);
+    o->direction = OB_DIRECTION_SOUTHEAST;
+    return o;
+}
+
index 5e5382d..4a750b2 100644 (file)
@@ -8,8 +8,7 @@ void action_dockautohide_startup(void)
 {
     actions_register("ToggleDockAutoHide",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index cb3ab24..bde7f5d 100644 (file)
@@ -1,8 +1,10 @@
 #include "openbox/actions.h"
 #include "openbox/event.h"
 #include "openbox/startupnotify.h"
+#include "openbox/client.h"
 #include "openbox/prompt.h"
 #include "openbox/screen.h"
+#include "obt/paths.h"
 #include "gettext.h"
 
 #ifdef HAVE_STDLIB_H
@@ -18,7 +20,7 @@ typedef struct {
     gchar   *prompt;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 /*
@@ -31,41 +33,37 @@ static void     i_cancel_func(gpointer options);
 
 void action_execute_startup(void)
 {
-    actions_register("Execute",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Execute", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("command", node)) ||
-        (n = parse_find_node("execute", node)))
+    if ((n = obt_parse_find_node(node, "command")) ||
+        (n = obt_parse_find_node(node, "execute")))
     {
-        gchar *s = parse_string(doc, n);
-        o->cmd = parse_expand_tilde(s);
+        gchar *s = obt_parse_node_string(n);
+        o->cmd = obt_paths_expand_tilde(s);
         g_free(s);
     }
 
-    if ((n = parse_find_node("prompt", node)))
-        o->prompt = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "prompt")))
+        o->prompt = obt_parse_node_string(n);
 
-    if ((n = parse_find_node("startupnotify", node))) {
+    if ((n = obt_parse_find_node(node, "startupnotify"))) {
         xmlNodePtr m;
-        if ((m = parse_find_node("enabled", n->xmlChildrenNode)))
-            o->sn = parse_bool(doc, m);
-        if ((m = parse_find_node("name", n->xmlChildrenNode)))
-            o->sn_name = parse_string(doc, m);
-        if ((m = parse_find_node("icon", n->xmlChildrenNode)))
-            o->sn_icon = parse_string(doc, m);
-        if ((m = parse_find_node("wmclass", n->xmlChildrenNode)))
-            o->sn_wmclass = parse_string(doc, m);
+        if ((m = obt_parse_find_node(n->children, "enabled")))
+            o->sn = obt_parse_node_bool(m);
+        if ((m = obt_parse_find_node(n->children, "name")))
+            o->sn_name = obt_parse_node_string(m);
+        if ((m = obt_parse_find_node(n->children, "icon")))
+            o->sn_icon = obt_parse_node_string(m);
+        if ((m = obt_parse_find_node(n->children, "wmclass")))
+            o->sn_wmclass = obt_parse_node_string(m);
     }
     return o;
 }
@@ -114,7 +112,7 @@ static void prompt_cleanup(ObPrompt *p, gpointer options)
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
-    GError *e = NULL;
+    GError *e;
     gchar **argv = NULL;
     gchar *cmd;
     Options *o = options;
@@ -143,16 +141,81 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         return FALSE;
     }
 
+    if (data->client) {
+        gchar *c, *before, *expand;
+
+        /* replace occurrences of $pid and $wid */
+
+        expand = NULL;
+        before = cmd;
+
+        while ((c = strchr(before, '$'))) {
+            if ((c[1] == 'p' || c[1] == 'P') &&
+                (c[2] == 'i' || c[2] == 'I') &&
+                (c[3] == 'd' || c[3] == 'D') &&
+                !g_ascii_isalnum(c[4]))
+            {
+                /* found $pid */
+                gchar *tmp;
+
+                *c = '\0';
+                tmp = expand;
+                expand = g_strdup_printf("%s%s%u",
+                                         (expand ? expand : ""),
+                                         before,
+                                         data->client->pid);
+                g_free(tmp);
+
+                before = c + 4; /* 4 = strlen("$pid") */
+            }
+            else if ((c[1] == 'w' || c[1] == 'W') &&
+                     (c[2] == 'i' || c[2] == 'I') &&
+                     (c[3] == 'd' || c[3] == 'D') &&
+                     !g_ascii_isalnum(c[4]))
+            {
+                /* found $wid */
+                gchar *tmp;
+
+                *c = '\0';
+                tmp = expand;
+                expand = g_strdup_printf("%s%s%lu",
+                                         (expand ? expand : ""),
+                                         before,
+                                         data->client->window);
+                g_free(tmp);
+
+                before = c + 4; /* 4 = strlen("$wid") */
+            }
+            else
+                before = c + 1; /* no infinite loops plz */
+        }
+
+        if (expand) {
+            gchar *tmp;
+
+            /* add on the end of the string after the last replacement */
+            tmp = expand;
+            expand = g_strconcat(expand, before, NULL);
+            g_free(tmp);
+
+            /* replace the command with the expanded one */
+            g_free(cmd);
+            cmd = expand;
+        }
+    }
+
     /* If there is a keyboard grab going on then we need to cancel
        it so the application can grab things */
     event_cancel_all_key_grabs();
 
+    e = NULL;
     if (!g_shell_parse_argv(cmd, NULL, &argv, &e)) {
         g_message(e->message, o->cmd);
         g_error_free(e);
     }
     else {
         gchar *program = NULL;
+        gboolean ok;
 
         if (o->sn) {
             program = g_path_get_basename(argv[0]);
@@ -163,18 +226,20 @@ static gboolean run_func(ObActionsData *data, gpointer options)
                                        screen_desktop);
         }
 
-        if (!g_spawn_async(NULL, argv, NULL,
-                           G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-                           NULL, NULL, NULL, &e))
-        {
+        e = NULL;
+        ok = g_spawn_async(NULL, argv, NULL,
+                           G_SPAWN_SEARCH_PATH |
+                           G_SPAWN_DO_NOT_REAP_CHILD,
+                           NULL, NULL, NULL, &e);
+        if (!ok) {
             g_message(e->message, o->cmd);
             g_error_free(e);
-
-            if (o->sn)
-                sn_spawn_cancel();
         }
-        if (o->sn)
+
+        if (o->sn) {
+            if (!ok) sn_spawn_cancel();
             unsetenv("DESKTOP_STARTUP_ID");
+        }
 
         g_free(program);
         g_strfreev(argv);
index 567926e..55d89a0 100644 (file)
@@ -8,16 +8,16 @@ typedef struct {
     gboolean prompt;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_exit_startup(void)
 {
-    actions_register("Exit", setup_func, NULL, run_func, NULL, NULL);
-    actions_register("SessionLogout", setup_func, NULL, run_func, NULL, NULL);
+    actions_register("Exit", setup_func, NULL, run_func);
+    actions_register("SessionLogout", setup_func, NULL, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
@@ -25,8 +25,8 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     o = g_new0(Options, 1);
     o->prompt = TRUE;
 
-    if ((n = parse_find_node("prompt", node)))
-        o->prompt = parse_bool(doc, n);
+    if ((n = obt_parse_find_node(node, "prompt")))
+        o->prompt = obt_parse_node_bool(n);
 
     return o;
 }
index 8da8ed5..0e546de 100644 (file)
@@ -8,38 +8,26 @@ typedef struct {
     gboolean here;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_focus_startup(void)
 {
-    actions_register("Focus",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Focus", setup_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("here", node)))
-        o->here = parse_bool(doc, n);
+    if ((n = obt_parse_find_node(node, "here")))
+        o->here = obt_parse_node_bool(n);
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
index 49c945b..a3e5b5a 100644 (file)
@@ -5,7 +5,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_focustobottom_startup(void)
 {
-    actions_register("FocusToBottom", NULL, NULL, run_func, NULL, NULL);
+    actions_register("FocusToBottom", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 7579b95..e1fdf23 100644 (file)
@@ -5,8 +5,7 @@ static gboolean run_func_toggle(ObActionsData *data, gpointer options);
 
 void action_fullscreen_startup(void)
 {
-    actions_register("ToggleFullscreen", NULL, NULL, run_func_toggle,
-                     NULL, NULL);
+    actions_register("ToggleFullscreen", NULL, NULL, run_func_toggle);
 }
 
 /* Always return FALSE because its not interactive */
index 69b8ef7..0c39a63 100644 (file)
@@ -7,31 +7,42 @@
 
 typedef struct {
     ObDirection dir;
+    gboolean shrink;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
+static gpointer setup_shrink_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_north_func(xmlNodePtr node);
+static gpointer setup_south_func(xmlNodePtr node);
+static gpointer setup_east_func(xmlNodePtr node);
+static gpointer setup_west_func(xmlNodePtr node);
 
 void action_growtoedge_startup(void)
 {
-    actions_register("GrowToEdge",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("GrowToEdge", setup_func,
+                     g_free, run_func);
+    actions_register("ShrinkToEdge", setup_shrink_func,
+                     g_free, run_func);
+    /* 3.4-compatibility */
+    actions_register("GrowToEdgeNorth", setup_north_func, g_free, run_func);
+    actions_register("GrowToEdgeSouth", setup_south_func, g_free, run_func);
+    actions_register("GrowToEdgeEast", setup_east_func, g_free, run_func);
+    actions_register("GrowToEdgeWest", setup_west_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
     o->dir = OB_DIRECTION_NORTH;
+    o->shrink = FALSE;
 
-    if ((n = parse_find_node("direction", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "direction"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "north") ||
             !g_ascii_strcasecmp(s, "up"))
             o->dir = OB_DIRECTION_NORTH;
@@ -50,11 +61,14 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static void free_func(gpointer options)
+static gpointer setup_shrink_func(xmlNodePtr node)
 {
-    Options *o = options;
+    Options *o;
 
-    g_free(o);
+    o = setup_func(node);
+    o->shrink = TRUE;
+
+    return o;
 }
 
 static gboolean do_grow(ObActionsData *data, gint x, gint y, gint w, gint h)
@@ -98,11 +112,13 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         return FALSE;
     }
 
-    /* try grow */
-    client_find_resize_directional(data->client, o->dir, TRUE,
-                                   &x, &y, &w, &h);
-    if (do_grow(data, x, y, w, h))
-        return FALSE;
+    if (!o->shrink) {
+        /* try grow */
+        client_find_resize_directional(data->client, o->dir, TRUE,
+                                       &x, &y, &w, &h);
+        if (do_grow(data, x, y, w, h))
+            return FALSE;
+    }
 
     /* we couldn't grow, so try shrink! */
     opp = (o->dir == OB_DIRECTION_NORTH ? OB_DIRECTION_SOUTH :
@@ -143,3 +159,36 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_north_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->shrink = FALSE;
+    o->dir = OB_DIRECTION_NORTH;
+    return o;
+}
+
+static gpointer setup_south_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->shrink = FALSE;
+    o->dir = OB_DIRECTION_SOUTH;
+    return o;
+}
+
+static gpointer setup_east_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->shrink = FALSE;
+    o->dir = OB_DIRECTION_EAST;
+    return o;
+}
+
+static gpointer setup_west_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->shrink = FALSE;
+    o->dir = OB_DIRECTION_WEST;
+    return o;
+}
index 6f14a2e..e6bdbb7 100644 (file)
@@ -7,8 +7,7 @@ void action_iconify_startup(void)
 {
     actions_register("Iconify",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 4c98966..47ff2fd 100644 (file)
@@ -23,81 +23,77 @@ typedef struct {
     GSList *elseacts;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_if_startup(void)
 {
-    actions_register("If",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("If", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("shaded", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "shaded"))) {
+        if (obt_parse_node_bool(n))
             o->shaded_on = TRUE;
         else
             o->shaded_off = TRUE;
     }
-    if ((n = parse_find_node("maximized", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "maximized"))) {
+        if (obt_parse_node_bool(n))
             o->maxfull_on = TRUE;
         else
             o->maxfull_off = TRUE;
     }
-    if ((n = parse_find_node("maximizedhorizontal", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "maximizedhorizontal"))) {
+        if (obt_parse_node_bool(n))
             o->maxhorz_on = TRUE;
         else
             o->maxhorz_off = TRUE;
     }
-    if ((n = parse_find_node("maximizedvertical", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "maximizedvertical"))) {
+        if (obt_parse_node_bool(n))
             o->maxvert_on = TRUE;
         else
             o->maxvert_off = TRUE;
     }
-    if ((n = parse_find_node("iconified", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "iconified"))) {
+        if (obt_parse_node_bool(n))
             o->iconic_on = TRUE;
         else
             o->iconic_off = TRUE;
     }
-    if ((n = parse_find_node("focused", node))) {
-        if (parse_bool(doc, n))
+    if ((n = obt_parse_find_node(node, "focused"))) {
+        if (obt_parse_node_bool(n))
             o->focused = TRUE;
         else
             o->unfocused = TRUE;
     }
 
-    if ((n = parse_find_node("then", node))) {
+    if ((n = obt_parse_find_node(node, "then"))) {
         xmlNodePtr m;
 
-        m = parse_find_node("action", n->xmlChildrenNode);
+        m = obt_parse_find_node(n->children, "action");
         while (m) {
-            ObActionsAct *action = actions_parse(i, doc, m);
+            ObActionsAct *action = actions_parse(m);
             if (action) o->thenacts = g_slist_append(o->thenacts, action);
-            m = parse_find_node("action", m->next);
+            m = obt_parse_find_node(m->next, "action");
         }
     }
-    if ((n = parse_find_node("else", node))) {
+    if ((n = obt_parse_find_node(node, "else"))) {
         xmlNodePtr m;
 
-        m = parse_find_node("action", n->xmlChildrenNode);
+        m = obt_parse_find_node(n->children, "action");
         while (m) {
-            ObActionsAct *action = actions_parse(i, doc, m);
+            ObActionsAct *action = actions_parse(m);
             if (action) o->elseacts = g_slist_append(o->elseacts, action);
-            m = parse_find_node("action", m->next);
+            m = obt_parse_find_node(m->next, "action");
         }
     }
 
@@ -108,6 +104,15 @@ static void free_func(gpointer options)
 {
     Options *o = options;
 
+    while (o->thenacts) {
+        actions_act_unref(o->thenacts->data);
+        o->thenacts = g_slist_delete_link(o->thenacts, o->thenacts);
+    }
+    while (o->elseacts) {
+        actions_act_unref(o->elseacts->data);
+        o->elseacts = g_slist_delete_link(o->elseacts, o->elseacts);
+    }
+
     g_free(o);
 }
 
index 6824440..b7d547b 100644 (file)
@@ -7,8 +7,7 @@ void action_kill_startup(void)
 {
     actions_register("Kill",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 92fa480..1dc7c4c 100644 (file)
@@ -6,24 +6,33 @@ typedef struct {
     gboolean toggle;
 } Options;
 
-static gpointer setup_func_top(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_func_bottom(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node);
-static gpointer setup_func_send(ObParseInst *i, xmlDocPtr doc,
-                                xmlNodePtr node);
+static gpointer setup_func_top(xmlNodePtr node);
+static gpointer setup_func_bottom(xmlNodePtr node);
+static gpointer setup_func_send(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_sendtop_func(xmlNodePtr node);
+static gpointer setup_sendbottom_func(xmlNodePtr node);
+static gpointer setup_sendnormal_func(xmlNodePtr node);
 
 void action_layer_startup(void)
 {
     actions_register("ToggleAlwaysOnTop", setup_func_top, g_free,
-                     run_func, NULL, NULL);
+                     run_func);
     actions_register("ToggleAlwaysOnBottom", setup_func_bottom, g_free,
-                     run_func, NULL, NULL);
+                     run_func);
     actions_register("SendToLayer", setup_func_send, g_free,
-                     run_func, NULL, NULL);
+                     run_func);
+    /* 3.4-compatibility */
+    actions_register("SendToTopLayer", setup_sendtop_func, g_free,
+                     run_func);
+    actions_register("SendToBottomLayer", setup_sendbottom_func, g_free,
+                     run_func);
+    actions_register("SendToNormalLayer", setup_sendnormal_func, g_free,
+                     run_func);
 }
 
-static gpointer setup_func_top(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func_top(xmlNodePtr node)
 {
     Options *o = g_new0(Options, 1);
     o->layer = 1;
@@ -31,8 +40,7 @@ static gpointer setup_func_top(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static gpointer setup_func_bottom(ObParseInst *i, xmlDocPtr doc,
-                                  xmlNodePtr node)
+static gpointer setup_func_bottom(xmlNodePtr node)
 {
     Options *o = g_new0(Options, 1);
     o->layer = -1;
@@ -40,16 +48,15 @@ static gpointer setup_func_bottom(ObParseInst *i, xmlDocPtr doc,
     return o;
 }
 
-static gpointer setup_func_send(ObParseInst *i, xmlDocPtr doc,
-                                xmlNodePtr node)
+static gpointer setup_func_send(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("layer", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "layer"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "above") ||
             !g_ascii_strcasecmp(s, "top"))
             o->layer = 1;
@@ -91,3 +98,29 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_sendtop_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->layer = 1;
+    o->toggle = FALSE;
+    return o;
+}
+
+static gpointer setup_sendbottom_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->layer = -1;
+    o->toggle = FALSE;
+    return o;
+}
+
+static gpointer setup_sendnormal_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->layer = 0;
+    o->toggle = FALSE;
+    return o;
+}
+
index d34e933..80ca6b8 100644 (file)
@@ -8,8 +8,7 @@ void action_lower_startup(void)
 {
     actions_register("Lower",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
index bb6f470..90a8403 100644 (file)
@@ -12,22 +12,42 @@ typedef struct {
     MaxDirection dir;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func_on(ObActionsData *data, gpointer options);
 static gboolean run_func_off(ObActionsData *data, gpointer options);
 static gboolean run_func_toggle(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_both_func(xmlNodePtr node);
+static gpointer setup_horz_func(xmlNodePtr node);
+static gpointer setup_vert_func(xmlNodePtr node);
 
 void action_maximize_startup(void)
 {
-    actions_register("Maximize", setup_func, g_free, run_func_on,
-                     NULL, NULL);
-    actions_register("Unmaximize", setup_func, g_free, run_func_off,
-                     NULL, NULL);
-    actions_register("ToggleMaximize", setup_func, g_free, run_func_toggle,
-                     NULL, NULL);
+    actions_register("Maximize", setup_func, g_free, run_func_on);
+    actions_register("Unmaximize", setup_func, g_free, run_func_off);
+    actions_register("ToggleMaximize", setup_func, g_free, run_func_toggle);
+    /* 3.4-compatibility */
+    actions_register("MaximizeFull", setup_both_func, g_free,
+                     run_func_on);
+    actions_register("UnmaximizeFull", setup_both_func, g_free,
+                     run_func_off);
+    actions_register("ToggleMaximizeFull", setup_both_func, g_free,
+                     run_func_toggle);
+    actions_register("MaximizeHorz", setup_horz_func, g_free,
+                     run_func_on);
+    actions_register("UnmaximizeHorz", setup_horz_func, g_free,
+                     run_func_off);
+    actions_register("ToggleMaximizeHorz", setup_horz_func, g_free,
+                     run_func_toggle);
+    actions_register("MaximizeVert", setup_vert_func, g_free,
+                     run_func_on);
+    actions_register("UnmaximizeVert", setup_vert_func, g_free,
+                     run_func_off);
+    actions_register("ToggleMaximizeVert", setup_vert_func, g_free,
+                     run_func_toggle);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
@@ -35,8 +55,8 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     o = g_new0(Options, 1);
     o->dir = BOTH;
 
-    if ((n = parse_find_node("direction", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "direction"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "vertical") ||
             !g_ascii_strcasecmp(s, "vert"))
             o->dir = VERT;
@@ -89,3 +109,26 @@ static gboolean run_func_toggle(ObActionsData *data, gpointer options)
     }
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_both_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = BOTH;
+    return o;
+}
+
+static gpointer setup_horz_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = HORZ;
+    return o;
+}
+
+static gpointer setup_vert_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = VERT;
+    return o;
+}
+
index 1a8ea20..ba8372a 100644 (file)
@@ -1,6 +1,6 @@
 #include "openbox/actions.h"
-#include "openbox/prop.h"
 #include "openbox/moveresize.h"
+#include "obt/prop.h"
 
 static gboolean run_func(ObActionsData *data, gpointer options);
 
@@ -8,8 +8,7 @@ void action_move_startup(void)
 {
     actions_register("Move",
                      NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+                     run_func);
 }
 
 /* Always return FALSE because its not interactive */
@@ -19,8 +18,8 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         guint32 corner;
 
         corner = data->button != 0 ?
-            prop_atoms.net_wm_moveresize_move :
-            prop_atoms.net_wm_moveresize_move_keyboard;
+            OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE) :
+            OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD);
 
         moveresize_start(data->client, data->x, data->y, data->button, corner);
     }
index 1d1189c..5bcdda4 100644 (file)
@@ -9,41 +9,29 @@ typedef struct {
     gint y;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_moverelative_startup(void)
 {
-    actions_register("MoveRelative",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("MoveRelative", setup_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("x", node)))
-        o->x = parse_int(doc, n);
-    if ((n = parse_find_node("y", node)))
-        o->y = parse_int(doc, n);
+    if ((n = obt_parse_find_node(node, "x")))
+        o->x = obt_parse_node_int(n);
+    if ((n = obt_parse_find_node(node, "y")))
+        o->y = obt_parse_node_int(n);
 
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
@@ -54,15 +42,15 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         gint x, y, lw, lh, w, h;
 
         c = data->client;
-        x = data->client->area.x + o->x;
-        y = data->client->area.y + o->y;
-        w = data->client->area.width;
-        h = data->client->area.height;
-        client_try_configure(data->client, &x, &y, &w, &h, &lw, &lh, TRUE);
-        client_find_onscreen(data->client, &x, &y, w, h, FALSE);
+        x = c->area.x + o->x;
+        y = c->area.y + o->y;
+        w = c->area.width;
+        h = c->area.height;
+        client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE);
+        client_find_onscreen(c, &x, &y, w, h, FALSE);
 
         actions_client_move(data, TRUE);
-        client_configure(data->client, x, y, w, h, TRUE, TRUE, FALSE);
+        client_configure(c, x, y, w, h, TRUE, TRUE, FALSE);
         actions_client_move(data, FALSE);
     }
 
index 29780c4..3c135c8 100644 (file)
@@ -23,23 +23,22 @@ typedef struct {
     gint monitor;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_center_func(xmlNodePtr node);
 
 void action_moveresizeto_startup(void)
 {
-    actions_register("MoveResizeTo",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("MoveResizeTo", setup_func, g_free, run_func);
+    /* 3.4-compatibility */
+    actions_register("MoveToCenter", setup_center_func, g_free, run_func);
 }
 
-static void parse_coord(xmlDocPtr doc, xmlNodePtr n, gint *pos,
+static void parse_coord(xmlNodePtr n, gint *pos,
                         gboolean *opposite, gboolean *center)
 {
-    gchar *s = parse_string(doc, n);
+    gchar *s = obt_parse_node_string(n);
     if (g_ascii_strcasecmp(s, "current") != 0) {
         if (!g_ascii_strcasecmp(s, "center"))
             *center = TRUE;
@@ -55,7 +54,7 @@ static void parse_coord(xmlDocPtr doc, xmlNodePtr n, gint *pos,
     g_free(s);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
@@ -67,27 +66,27 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     o->h = G_MININT;
     o->monitor = CURRENT_MONITOR;
 
-    if ((n = parse_find_node("x", node)))
-        parse_coord(doc, n, &o->x, &o->xopposite, &o->xcenter);
+    if ((n = obt_parse_find_node(node, "x")))
+        parse_coord(n, &o->x, &o->xopposite, &o->xcenter);
 
-    if ((n = parse_find_node("y", node)))
-        parse_coord(doc, n, &o->y, &o->yopposite, &o->ycenter);
+    if ((n = obt_parse_find_node(node, "y")))
+        parse_coord(n, &o->y, &o->yopposite, &o->ycenter);
 
-    if ((n = parse_find_node("width", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "width"))) {
+        gchar *s = obt_parse_node_string(n);
         if (g_ascii_strcasecmp(s, "current") != 0)
-            o->w = parse_int(doc, n);
+            o->w = obt_parse_node_int(n);
         g_free(s);
     }
-    if ((n = parse_find_node("height", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "height"))) {
+        gchar *s = obt_parse_node_string(n);
         if (g_ascii_strcasecmp(s, "current") != 0)
-            o->h = parse_int(doc, n);
+            o->h = obt_parse_node_int(n);
         g_free(s);
     }
 
-    if ((n = parse_find_node("monitor", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "monitor"))) {
+        gchar *s = obt_parse_node_string(n);
         if (g_ascii_strcasecmp(s, "current") != 0) {
             if (!g_ascii_strcasecmp(s, "all"))
                 o->monitor = ALL_MONITORS;
@@ -96,7 +95,7 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
             else if(!g_ascii_strcasecmp(s, "prev"))
                 o->monitor = PREV_MONITOR;
             else
-                o->monitor = parse_int(doc, n) - 1;
+                o->monitor = obt_parse_node_int(n) - 1;
         }
         g_free(s);
     }
@@ -104,13 +103,6 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
@@ -188,3 +180,19 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_center_func(xmlNodePtr node)
+{
+    Options *o;
+
+    o = g_new0(Options, 1);
+    o->x = G_MININT;
+    o->y = G_MININT;
+    o->w = G_MININT;
+    o->h = G_MININT;
+    o->monitor = -1;
+    o->xcenter = TRUE;
+    o->ycenter = TRUE;
+    return o;
+}
index 5941bde..e7384da 100644 (file)
@@ -9,20 +9,25 @@ typedef struct {
     ObDirection dir;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
+/* 3.4-compatibility */
+static gpointer setup_north_func(xmlNodePtr node);
+static gpointer setup_south_func(xmlNodePtr node);
+static gpointer setup_east_func(xmlNodePtr node);
+static gpointer setup_west_func(xmlNodePtr node);
 
 void action_movetoedge_startup(void)
 {
-    actions_register("MoveToEdge",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("MoveToEdge", setup_func, g_free, run_func);
+    /* 3.4-compatibility */
+    actions_register("MoveToEdgeNorth", setup_north_func, g_free, run_func);
+    actions_register("MoveToEdgeSouth", setup_south_func, g_free, run_func);
+    actions_register("MoveToEdgeEast", setup_east_func, g_free, run_func);
+    actions_register("MoveToEdgeWest", setup_west_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
@@ -30,8 +35,8 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     o = g_new0(Options, 1);
     o->dir = OB_DIRECTION_NORTH;
 
-    if ((n = parse_find_node("direction", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "direction"))) {
+        gchar *s = obt_parse_node_string(n);
         if (!g_ascii_strcasecmp(s, "north") ||
             !g_ascii_strcasecmp(s, "up"))
             o->dir = OB_DIRECTION_NORTH;
@@ -50,13 +55,6 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
@@ -75,3 +73,33 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     return FALSE;
 }
+
+/* 3.4-compatibility */
+static gpointer setup_north_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = OB_DIRECTION_NORTH;
+    return o;
+}
+
+static gpointer setup_south_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = OB_DIRECTION_SOUTH;
+    return o;
+}
+
+static gpointer setup_east_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = OB_DIRECTION_EAST;
+    return o;
+}
+
+static gpointer setup_west_func(xmlNodePtr node)
+{
+    Options *o = g_new0(Options, 1);
+    o->dir = OB_DIRECTION_WEST;
+    return o;
+}
+
index 030a015..4309acc 100644 (file)
@@ -6,8 +6,7 @@ static gboolean run_func_toggle(ObActionsData *data, gpointer options);
 
 void action_omnipresent_startup(void)
 {
-    actions_register("ToggleOmnipresent", NULL, NULL, run_func_toggle,
-                     NULL, NULL);
+    actions_register("ToggleOmnipresent", NULL, NULL, run_func_toggle);
 }
 
 /* Always return FALSE because its not interactive */
index 6837bce..f6ac145 100644 (file)
@@ -6,10 +6,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_raise_startup(void)
 {
-    actions_register("Raise",
-                     NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Raise", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 80fc917..dbe41d8 100644 (file)
@@ -5,10 +5,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_raiselower_startup(void)
 {
-    actions_register("RaiseLower",
-                     NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+    actions_register("RaiseLower", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index cef8141..813a122 100644 (file)
@@ -5,10 +5,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_reconfigure_startup(void)
 {
-    actions_register("Reconfigure",
-                     NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Reconfigure", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index 3714e38..3df44b6 100644 (file)
@@ -1,16 +1,15 @@
 #include "openbox/actions.h"
-#include "openbox/prop.h"
 #include "openbox/moveresize.h"
 #include "openbox/client.h"
 #include "openbox/frame.h"
+#include "obt/prop.h"
 
 typedef struct {
     gboolean corner_specified;
     guint32 corner;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
@@ -18,40 +17,36 @@ static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
 
 void action_resize_startup(void)
 {
-    actions_register("Resize",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Resize", setup_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("edge", node))) {
-        gchar *s = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "edge"))) {
+        gchar *s = obt_parse_node_string(n);
 
         o->corner_specified = TRUE;
         if (!g_ascii_strcasecmp(s, "top"))
-            o->corner = prop_atoms.net_wm_moveresize_size_top;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
         else if (!g_ascii_strcasecmp(s, "bottom"))
-            o->corner = prop_atoms.net_wm_moveresize_size_bottom;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
         else if (!g_ascii_strcasecmp(s, "left"))
-            o->corner = prop_atoms.net_wm_moveresize_size_left;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
         else if (!g_ascii_strcasecmp(s, "right"))
-            o->corner = prop_atoms.net_wm_moveresize_size_right;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
         else if (!g_ascii_strcasecmp(s, "topleft"))
-            o->corner = prop_atoms.net_wm_moveresize_size_topleft;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
         else if (!g_ascii_strcasecmp(s, "topright"))
-            o->corner = prop_atoms.net_wm_moveresize_size_topright;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
         else if (!g_ascii_strcasecmp(s, "bottomleft"))
-            o->corner = prop_atoms.net_wm_moveresize_size_bottomleft;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
         else if (!g_ascii_strcasecmp(s, "bottomright"))
-            o->corner = prop_atoms.net_wm_moveresize_size_bottomright;
+            o->corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
         else
             o->corner_specified = FALSE;
 
@@ -60,13 +55,6 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
@@ -77,7 +65,7 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         guint32 corner;
 
         if (!data->button)
-            corner = prop_atoms.net_wm_moveresize_size_keyboard;
+            corner = OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD);
         else if (o->corner_specified)
             corner = o->corner; /* it was specified in the binding */
         else
@@ -163,30 +151,30 @@ static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
     if (shaded) {
         /* for shaded windows, you can only resize west/east and move */
         if (b)
-            return prop_atoms.net_wm_moveresize_size_left;
+            return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
         if (c)
-            return prop_atoms.net_wm_moveresize_size_right;
-        return prop_atoms.net_wm_moveresize_move;
+            return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);
     }
 
     if (y < A && y >= C)
-        return prop_atoms.net_wm_moveresize_size_topleft;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT);
     else if (y >= A && y >= B && a)
-        return prop_atoms.net_wm_moveresize_size_top;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP);
     else if (y < B && y >= D)
-        return prop_atoms.net_wm_moveresize_size_topright;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
     else if (y < C && y >= E && b)
-        return prop_atoms.net_wm_moveresize_size_left;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT);
     else if (y < D && y >= F && c)
-        return prop_atoms.net_wm_moveresize_size_right;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT);
     else if (y < E && y >= G)
-        return prop_atoms.net_wm_moveresize_size_bottomleft;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
     else if (y < G && y < H && d)
-        return prop_atoms.net_wm_moveresize_size_bottom;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM);
     else if (y >= H && y < F)
-        return prop_atoms.net_wm_moveresize_size_bottomright;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
     else
-        return prop_atoms.net_wm_moveresize_move;
+        return OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE);
 
 #undef X
 #undef A
index f705c29..b4db73b 100644 (file)
@@ -11,47 +11,35 @@ typedef struct {
     gint bottom;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static void     free_func(gpointer options);
+static gpointer setup_func(xmlNodePtr node);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_resizerelative_startup(void)
 {
-    actions_register("ResizeRelative",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("ResizeRelative", setup_func, g_free, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("left", node)))
-        o->left = parse_int(doc, n);
-    if ((n = parse_find_node("right", node)))
-        o->right = parse_int(doc, n);
-    if ((n = parse_find_node("top", node)) ||
-        (n = parse_find_node("up", node)))
-        o->top = parse_int(doc, n);
-    if ((n = parse_find_node("bottom", node)) ||
-        (n = parse_find_node("down", node)))
-        o->bottom = parse_int(doc, n);
+    if ((n = obt_parse_find_node(node, "left")))
+        o->left = obt_parse_node_int(n);
+    if ((n = obt_parse_find_node(node, "right")))
+        o->right = obt_parse_node_int(n);
+    if ((n = obt_parse_find_node(node, "top")) ||
+        (n = obt_parse_find_node(node, "up")))
+        o->top = obt_parse_node_int(n);
+    if ((n = obt_parse_find_node(node, "bottom")) ||
+        (n = obt_parse_find_node(node, "down")))
+        o->bottom = obt_parse_node_int(n);
 
     return o;
 }
 
-static void free_func(gpointer options)
-{
-    Options *o = options;
-
-    g_free(o);
-}
-
 /* Always return FALSE because its not interactive */
 static gboolean run_func(ObActionsData *data, gpointer options)
 {
index 4b52f9d..01de4f9 100644 (file)
@@ -1,35 +1,32 @@
 #include "openbox/actions.h"
 #include "openbox/openbox.h"
+#include "obt/paths.h"
 
 typedef struct {
     gchar   *cmd;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_restart_startup(void)
 {
-    actions_register("Restart",
-                     setup_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
+    actions_register("Restart", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("command", node)) ||
-        (n = parse_find_node("execute", node)))
+    if ((n = obt_parse_find_node(node, "command")) ||
+        (n = obt_parse_find_node(node, "execute")))
     {
-        gchar *s = parse_string(doc, n);
-        o->cmd = parse_expand_tilde(s);
+        gchar *s = obt_parse_node_string(n);
+        o->cmd = obt_paths_expand_tilde(s);
         g_free(s);
     }
     return o;
@@ -38,11 +35,8 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
 static void free_func(gpointer options)
 {
     Options *o = options;
-
-    if (o) {
-        g_free(o->cmd);
-        g_free(o);
-    }
+    g_free(o->cmd);
+    g_free(o);
 }
 
 /* Always return FALSE because its not interactive */
diff --git a/openbox/actions/session.c b/openbox/actions/session.c
new file mode 100644 (file)
index 0000000..b9e33b7
--- /dev/null
@@ -0,0 +1,78 @@
+#include "openbox/actions.h"
+#include "openbox/prompt.h"
+#include "openbox/session.h"
+#include "gettext.h"
+
+typedef struct {
+    gboolean prompt;
+    gboolean silent;
+} Options;
+
+static gpointer setup_func(xmlNodePtr node);
+static gboolean logout_func(ObActionsData *data, gpointer options);
+
+void action_session_startup(void)
+{
+    actions_register("SessionLogout", setup_func, NULL, logout_func,
+                     NULL, NULL);
+}
+
+static gpointer setup_func(xmlNodePtr node)
+{
+    xmlNodePtr n;
+    Options *o;
+
+    o = g_new0(Options, 1);
+    o->prompt = TRUE;
+
+    if ((n = obt_parse_find_node(node, "prompt")))
+        o->prompt = obt_parse_node_bool(n);
+
+    return o;
+}
+
+static gboolean prompt_cb(ObPrompt *p, gint result, gpointer data)
+{
+    if (result) {
+#ifdef USE_SM
+        Options *o = data;
+        session_request_logout(o->silent);
+#else
+        /* TRANSLATORS: Don't translate the word "SessionLogout" as it's the
+           name of the action you write in rc.xml */
+        g_message(_("The SessionLogout action is not available since Openbox was built without session management support"));
+#endif
+    }
+    return TRUE; /* call cleanup func */
+}
+
+static void prompt_cleanup(ObPrompt *p, gpointer data)
+{
+    g_free(data);
+    prompt_unref(p);
+}
+
+/* Always return FALSE because its not interactive */
+static gboolean logout_func(ObActionsData *data, gpointer options)
+{
+    Options *o = options;
+
+    if (o->prompt) {
+        Options *o2;
+        ObPrompt *p;
+        ObPromptAnswer answers[] = {
+            { _("Cancel"), 0 },
+            { _("Log Out"), 1 }
+        };
+
+        o2 = g_memdup(o, sizeof(Options));
+        p = prompt_new(_("Are you sure you want to log out?"),
+                       _("Log Out"),
+                       answers, 2, 0, 0, prompt_cb, prompt_cleanup, o2);
+        prompt_show(p, NULL, FALSE);
+    }
+    else
+        prompt_cb(NULL, 1, o);
+
+    return FALSE;
+}
index 2342067..502781d 100644 (file)
@@ -7,9 +7,9 @@ static gboolean run_func_toggle(ObActionsData *data, gpointer options);
 
 void action_shade_startup(void)
 {
-    actions_register("Shade", NULL, NULL, run_func_on, NULL, NULL);
-    actions_register("Unshade", NULL, NULL, run_func_off, NULL, NULL);
-    actions_register("ToggleShade", NULL, NULL, run_func_toggle, NULL, NULL);
+    actions_register("Shade", NULL, NULL, run_func_on);
+    actions_register("Unshade", NULL, NULL, run_func_off);
+    actions_register("ToggleShade", NULL, NULL, run_func_toggle);
 }
 
 /* Always return FALSE because its not interactive */
diff --git a/openbox/actions/shadelowerraise.c b/openbox/actions/shadelowerraise.c
new file mode 100644 (file)
index 0000000..414e281
--- /dev/null
@@ -0,0 +1,40 @@
+#include "openbox/actions.h"
+#include "openbox/client.h"
+
+static gboolean run_func_sl(ObActionsData *data, gpointer options);
+static gboolean run_func_ur(ObActionsData *data, gpointer options);
+
+void action_shadelowerraise_startup()
+{
+    /* 3.4-compatibility */
+    actions_register("ShadeLower", NULL, NULL, run_func_sl);
+    actions_register("UnshadeRaise", NULL, NULL, run_func_ur);
+}
+
+/* Always return FALSE because its not interactive */
+static gboolean run_func_sl(ObActionsData *data, gpointer options)
+{
+    if (data->client) {
+        actions_client_move(data, TRUE);
+        if (data->client->shaded)
+            stacking_lower(CLIENT_AS_WINDOW(data->client));
+        else
+            client_shade(data->client, TRUE);
+        actions_client_move(data, FALSE);
+    }
+    return FALSE;
+}
+
+/* Always return FALSE because its not interactive */
+static gboolean run_func_ur(ObActionsData *data, gpointer options)
+{
+    if (data->client) {
+        actions_client_move(data, TRUE);
+        if (data->client->shaded)
+            client_shade(data->client, FALSE);
+        else
+            stacking_raise(CLIENT_AS_WINDOW(data->client));
+        actions_client_move(data, FALSE);
+    }
+    return FALSE;
+}
index c9ba86c..6dc77d5 100644 (file)
@@ -5,10 +5,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_showdesktop_startup(void)
 {
-    actions_register("ToggleShowDesktop",
-                     NULL, NULL,
-                     run_func,
-                     NULL, NULL);
+    actions_register("ToggleShowDesktop", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index c1d53e4..546be5a 100644 (file)
@@ -6,25 +6,24 @@ typedef struct {
     gchar   *name;
 } Options;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+static gpointer setup_func(xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_showmenu_startup(void)
 {
-    actions_register("ShowMenu", setup_func, free_func, run_func,
-                     NULL, NULL);
+    actions_register("ShowMenu", setup_func, free_func, run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node)
 {
     xmlNodePtr n;
     Options *o;
 
     o = g_new0(Options, 1);
 
-    if ((n = parse_find_node("menu", node)))
-        o->name = parse_string(doc, n);
+    if ((n = obt_parse_find_node(node, "menu")))
+        o->name = obt_parse_node_string(n);
     return o;
 }
 
index 22a9378..3db00ca 100644 (file)
@@ -5,7 +5,7 @@ static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_unfocus_startup(void)
 {
-    actions_register("Unfocus", NULL, NULL, run_func, NULL, NULL);
+    actions_register("Unfocus", NULL, NULL, run_func);
 }
 
 /* Always return FALSE because its not interactive */
index e3a7d6e..184ae17 100644 (file)
 #include "debug.h"
 #include "startupnotify.h"
 #include "dock.h"
-#include "xerror.h"
 #include "screen.h"
 #include "moveresize.h"
 #include "ping.h"
 #include "place.h"
-#include "prop.h"
-#include "extensions.h"
 #include "frame.h"
 #include "session.h"
 #include "event.h"
@@ -43,6 +40,8 @@
 #include "mouse.h"
 #include "render/render.h"
 #include "gettext.h"
+#include "obt/display.h"
+#include "obt/prop.h"
 
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
@@ -186,8 +185,8 @@ void client_set_list(void)
     } else
         windows = NULL;
 
-    PROP_SETA32(RootWindow(ob_display, ob_screen),
-                net_client_list, window, (gulong*)windows, size);
+    OBT_PROP_SETA32(obt_root(ob_screen), NET_CLIENT_LIST, WINDOW,
+                    (gulong*)windows, size);
 
     if (windows)
         g_free(windows);
@@ -195,55 +194,10 @@ void client_set_list(void)
     stacking_set_list();
 }
 
-void client_manage_all(void)
-{
-    guint i, j, nchild;
-    Window w, *children;
-    XWMHints *wmhints;
-    XWindowAttributes attrib;
-
-    XQueryTree(ob_display, RootWindow(ob_display, ob_screen),
-               &w, &w, &children, &nchild);
-
-    /* remove all icon windows from the list */
-    for (i = 0; i < nchild; i++) {
-        if (children[i] == None) continue;
-        wmhints = XGetWMHints(ob_display, children[i]);
-        if (wmhints) {
-            if ((wmhints->flags & IconWindowHint) &&
-                (wmhints->icon_window != children[i]))
-                for (j = 0; j < nchild; j++)
-                    if (children[j] == wmhints->icon_window) {
-                        children[j] = None;
-                        break;
-                    }
-            XFree(wmhints);
-        }
-    }
-
-    /* manage windows in reverse order from how they were originally mapped.
-       this is an attempt to manage children windows before their parents, so
-       that when the parent is mapped, it can find the child */
-    for (i = 0; i < nchild; ++i) {
-        if (children[i] == None)
-            continue;
-        if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
-            if (attrib.override_redirect) continue;
-
-            if (attrib.map_state != IsUnmapped)
-                client_manage(children[i], NULL);
-        }
-    }
-    XFree(children);
-}
-
 void client_manage(Window window, ObPrompt *prompt)
 {
     ObClient *self;
-    XEvent e;
-    XWindowAttributes attrib;
     XSetWindowAttributes attrib_set;
-    XWMHints *wmhint;
     gboolean activate = FALSE;
     ObAppSettings *settings;
     gboolean transient = FALSE;
@@ -251,42 +205,7 @@ void client_manage(Window window, ObPrompt *prompt)
     Time launch_time, map_time;
     guint32 user_time;
 
-    grab_server(TRUE);
-
-    /* check if it has already been unmapped by the time we started
-       mapping. the grab does a sync so we don't have to here */
-    if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
-        XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
-    {
-        XPutBackEvent(ob_display, &e);
-
-        ob_debug("Trying to manage unmapped window. Aborting that.\n");
-        grab_server(FALSE);
-        return; /* don't manage it */
-    }
-
-    /* make sure it isn't an override-redirect window */
-    if (!XGetWindowAttributes(ob_display, window, &attrib) ||
-        attrib.override_redirect)
-    {
-        grab_server(FALSE);
-        return; /* don't manage it */
-    }
-
-    /* is the window a docking app */
-    if ((wmhint = XGetWMHints(ob_display, window))) {
-        if ((wmhint->flags & StateHint) &&
-            wmhint->initial_state == WithdrawnState)
-        {
-            dock_add(window, wmhint);
-            grab_server(FALSE);
-            XFree(wmhint);
-            return;
-        }
-        XFree(wmhint);
-    }
-
-    ob_debug("Managing window: 0x%lx\n", window);
+    ob_debug("Managing window: 0x%lx", window);
 
     map_time = event_get_server_time();
 
@@ -295,13 +214,13 @@ void client_manage(Window window, ObPrompt *prompt)
     attrib_set.event_mask = CLIENT_EVENTMASK |
         (prompt ? prompt->event_mask : 0);
     attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
-    XChangeWindowAttributes(ob_display, window,
+    XChangeWindowAttributes(obt_display, window,
                             CWEventMask|CWDontPropagate, &attrib_set);
 
     /* create the ObClient struct, and populate it from the hints on the
        window */
     self = g_new0(ObClient, 1);
-    self->obwin.type = Window_Client;
+    self->obwin.type = OB_WINDOW_CLASS_CLIENT;
     self->window = window;
     self->prompt = prompt;
 
@@ -313,9 +232,9 @@ void client_manage(Window window, ObPrompt *prompt)
     /* get all the stuff off the window */
     client_get_all(self, TRUE);
 
-    ob_debug("Window type: %d\n", self->type);
-    ob_debug("Window group: 0x%x\n", self->group?self->group->leader:0);
-    ob_debug("Window name: %s class: %s role: %s\n", self->name, self->class, self->role);
+    ob_debug("Window type: %d", self->type);
+    ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
+    ob_debug("Window name: %s class: %s role: %s", self->name, self->class, self->role);
 
     /* per-app settings override stuff from client_get_all, and return the
        settings for other uses too. the returned settings is a shallow copy,
@@ -331,7 +250,7 @@ void client_manage(Window window, ObPrompt *prompt)
        should be reparented back to root automatically, unless we are managing
        an internal ObPrompt window  */
     if (!self->prompt)
-        XChangeSaveSet(ob_display, window, SetModeInsert);
+        XChangeSaveSet(obt_display, window, SetModeInsert);
 
     /* create the decoration frame for the client window */
     self->frame = frame_new(self);
@@ -348,7 +267,7 @@ void client_manage(Window window, ObPrompt *prompt)
     /* tell startup notification that this app started */
     launch_time = sn_app_started(self->startup_id, self->class, self->name);
 
-    if (!PROP_GET32(self->window, net_wm_user_time, cardinal, &user_time))
+    if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time))
         user_time = map_time;
 
     /* do this after we have a frame.. it uses the frame to help determine the
@@ -378,7 +297,7 @@ void client_manage(Window window, ObPrompt *prompt)
     }
 
     /* remove the client's border */
-    XSetWindowBorderWidth(ob_display, self->window, 0);
+    XSetWindowBorderWidth(obt_display, self->window, 0);
 
     /* adjust the frame to the client's size before showing or placing
        the window */
@@ -391,7 +310,7 @@ void client_manage(Window window, ObPrompt *prompt)
 
     /* figure out placement for the window if the window is new */
     if (ob_state() == OB_STATE_RUNNING) {
-        ob_debug("Positioned: %s @ %d %d\n",
+        ob_debug("Positioned: %s @ %d %d",
                  (!self->positioned ? "no" :
                   (self->positioned == PPosition ? "program specified" :
                    (self->positioned == USPosition ? "user specified" :
@@ -399,7 +318,7 @@ void client_manage(Window window, ObPrompt *prompt)
                      "program + user specified" :
                      "BADNESS !?")))), place.x, place.y);
 
-        ob_debug("Sized: %s @ %d %d\n",
+        ob_debug("Sized: %s @ %d %d",
                  (!self->sized ? "no" :
                   (self->sized == PSize ? "program specified" :
                    (self->sized == USSize ? "user specified" :
@@ -471,7 +390,7 @@ void client_manage(Window window, ObPrompt *prompt)
         place.width = MIN(place.width, a->width);
         place.height = MIN(place.height, a->height);
 
-        ob_debug("setting window size to %dx%d\n", place.width, place.height);
+        ob_debug("setting window size to %dx%d", place.width, place.height);
 
         /* get the size of the client back */
         place.width -= self->frame->size.left + self->frame->size.right;
@@ -481,11 +400,11 @@ void client_manage(Window window, ObPrompt *prompt)
     }
 
     ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
-             "some restrictions may apply\n",
+             "some restrictions may apply",
              self->window, place.x, place.y, place.width, place.height);
     if (self->session)
         ob_debug("  but session requested %d, %d  %d x %d instead, "
-                 "overriding\n",
+                 "overriding",
                  self->session->x, self->session->y,
                  self->session->w, self->session->h);
 
@@ -500,7 +419,7 @@ void client_manage(Window window, ObPrompt *prompt)
     g_free(monitor);
     monitor = NULL;
 
-    ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s\n",
+    ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
                   activate ? "yes" : "no");
     if (activate) {
         activate = client_can_steal_focus(self, map_time, launch_time);
@@ -548,7 +467,7 @@ void client_manage(Window window, ObPrompt *prompt)
 
     /* add to client list/map */
     client_list = g_list_append(client_list, self);
-    g_hash_table_insert(window_map, &self->window, self);
+    window_add(&self->window, CLIENT_AS_WINDOW(self));
 
     /* this has to happen after we're in the client_list */
     if (STRUT_EXISTS(self->strut))
@@ -560,10 +479,8 @@ void client_manage(Window window, ObPrompt *prompt)
     /* free the ObAppSettings shallow copy */
     g_free(settings);
 
-    ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
+    ob_debug("Managed window 0x%lx plate 0x%x (%s)",
              window, self->frame->window, self->class);
-
-    return;
 }
 
 ObClient *client_fake_manage(Window window)
@@ -571,7 +488,7 @@ ObClient *client_fake_manage(Window window)
     ObClient *self;
     ObAppSettings *settings;
 
-    ob_debug("Pretend-managing window: %lx\n", window);
+    ob_debug("Pretend-managing window: %lx", window);
 
     /* do this minimal stuff to figure out the client's decorations */
 
@@ -589,7 +506,7 @@ ObClient *client_fake_manage(Window window)
     self->frame = frame_new(self);
     frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
 
-    ob_debug("gave extents left %d right %d top %d bottom %d\n",
+    ob_debug("gave extents left %d right %d top %d bottom %d",
              self->frame->size.left, self->frame->size.right,
              self->frame->size.top, self->frame->size.bottom);
 
@@ -610,7 +527,7 @@ void client_unmanage(ObClient *self)
     GSList *it;
     gulong ignore_start;
 
-    ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n",
+    ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)",
              self->window, self->frame->window,
              self->class, self->title ? self->title : "");
 
@@ -618,7 +535,7 @@ void client_unmanage(ObClient *self)
 
     /* we dont want events no more. do this before hiding the frame so we
        don't generate more events */
-    XSelectInput(ob_display, self->window, NoEventMask);
+    XSelectInput(obt_display, self->window, NoEventMask);
 
     /* ignore enter events from the unmap so it doesnt mess with the focus */
     if (!config_focus_under_mouse)
@@ -626,7 +543,7 @@ void client_unmanage(ObClient *self)
 
     frame_hide(self->frame);
     /* flush to send the hide to the server quickly */
-    XFlush(ob_display);
+    XFlush(obt_display);
 
     if (!config_focus_under_mouse)
         event_end_ignore_all_enters(ignore_start);
@@ -636,7 +553,7 @@ void client_unmanage(ObClient *self)
     /* remove the window from our save set, unless we are managing an internal
        ObPrompt window */
     if (!self->prompt)
-        XChangeSaveSet(ob_display, self->window, SetModeDelete);
+        XChangeSaveSet(obt_display, self->window, SetModeDelete);
 
     /* update the focus lists */
     focus_order_remove(self);
@@ -651,7 +568,7 @@ void client_unmanage(ObClient *self)
 
     client_list = g_list_remove(client_list, self);
     stacking_remove(self);
-    g_hash_table_remove(window_map, &self->window);
+    window_remove(self->window);
 
     /* once the client is out of the list, update the struts to remove its
        influence */
@@ -704,7 +621,7 @@ void client_unmanage(ObClient *self)
         self->decorations = 0; /* unmanaged windows have no decor */
 
         /* give the client its border back */
-        XSetWindowBorderWidth(ob_display, self->window, self->border_width);
+        XSetWindowBorderWidth(obt_display, self->window, self->border_width);
 
         client_move_resize(self, a.x, a.y, a.width, a.height);
     }
@@ -717,25 +634,25 @@ void client_unmanage(ObClient *self)
     if (ob_state() != OB_STATE_EXITING) {
         /* these values should not be persisted across a window
            unmapping/mapping */
-        PROP_ERASE(self->window, net_wm_desktop);
-        PROP_ERASE(self->window, net_wm_state);
-        PROP_ERASE(self->window, wm_state);
+        OBT_PROP_ERASE(self->window, NET_WM_DESKTOP);
+        OBT_PROP_ERASE(self->window, NET_WM_STATE);
+        OBT_PROP_ERASE(self->window, WM_STATE);
     } else {
         /* if we're left in an unmapped state, the client wont be mapped.
            this is bad, since we will no longer be managing the window on
            restart */
-        XMapWindow(ob_display, self->window);
+        XMapWindow(obt_display, self->window);
     }
 
     /* these should not be left on the window ever.  other window managers
        don't necessarily use them and it will mess them up (like compiz) */
-    PROP_ERASE(self->window, net_wm_visible_name);
-    PROP_ERASE(self->window, net_wm_visible_icon_name);
+    OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_NAME);
+    OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_ICON_NAME);
 
     /* update the list hints */
     client_set_list();
 
-    ob_debug("Unmanaged window 0x%lx\n", self->window);
+    ob_debug("Unmanaged window 0x%lx", self->window);
 
     /* free all data allocated in the client struct */
     RrImageUnref(self->icon_set);
@@ -779,7 +696,7 @@ static gboolean client_can_steal_focus(ObClient *self, Time steal_time,
     /* This is focus stealing prevention */
     ob_debug_type(OB_DEBUG_FOCUS,
                   "Want to focus new window 0x%x at time %u "
-                  "launched at %u (last user interaction time %u)\n",
+                  "launched at %u (last user interaction time %u)",
                   self->window, steal_t