]> Dogcows Code - chaz/openbox/commitdiff
Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Fri, 8 Jan 2010 15:22:30 +0000 (10:22 -0500)
committerDana Jansens <danakj@orodu.net>
Fri, 8 Jan 2010 15:22:30 +0000 (10:22 -0500)
Conflicts:

Makefile.am
openbox/actions/focus.c
openbox/config.c
openbox/event.c
openbox/menuframe.c

1  2 
Makefile.am
data/rc.xml
openbox/actions/focus.c
openbox/config.c
openbox/config.h
openbox/event.c
openbox/focus_cycle.c
openbox/menuframe.c
openbox/menuframe.h

diff --combined Makefile.am
index 45a3bd2f9d66c04be5001840c2b020c27b21ef7d,14786f57d9e225c2327209148d15c34584c30b54..9617a1ca4738acd7b01275934662162052f2920f
@@@ -8,8 -8,7 +8,8 @@@ rcdir           = $(configdir)/openbo
  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@/obrender
  pixmapdir       = $(datadir)/pixmaps
  xsddir          = $(datadir)/openbox
  secretbindir    = $(libdir)/openbox
@@@ -24,11 -23,11 +24,11 @@@ ACLOCAL_AMFLAGS = -I m
  INCLUDES = -I.
  
  check_PROGRAMS = \
 -      render/rendertest
 +      obrender/rendertest
  
  lib_LTLIBRARIES = \
 -      parser/libobparser.la \
 -      render/libobrender.la
 +      obt/libobt.la \
 +      obrender/libobrender.la
  
  bin_PROGRAMS = \
        openbox/openbox \
@@@ -44,105 -43,90 +44,105 @@@ nodist_bin_SCRIPTS = 
        data/xsession/openbox-gnome-session \
        data/xsession/openbox-kde-session
  
 -## render ##
 +## obrender ##
  
 -render_rendertest_CPPFLAGS = \
 +obrender_rendertest_CPPFLAGS = \
        $(PANGO_CFLAGS) \
 -      $(XFT_CFLAGS) \
        $(GLIB_CFLAGS) \
        -DG_LOG_DOMAIN=\"RenderTest\"
 -render_rendertest_LDADD = \
 -      parser/libobparser.la \
 -      render/libobrender.la \
 +obrender_rendertest_LDADD = \
 +      obt/libobt.la \
 +      obrender/libobrender.la \
        $(GLIB_LIBS) \
        $(PANGO_LIBS) \
 -      $(XFT_LIBS) \
        $(XML_LIBS) \
        $(X_LIBS)
 -render_rendertest_SOURCES = render/test.c
 +obrender_rendertest_SOURCES = obrender/test.c
  
 -render_libobrender_la_CPPFLAGS = \
 +obrender_libobrender_la_CPPFLAGS = \
        $(X_CFLAGS) \
        $(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)
 -render_libobrender_la_LIBADD = \
 -      parser/libobparser.la \
 +obrender_libobrender_la_LDFLAGS = \
 +      -version-info $(RR_CURRENT):$(RR_REVISION):$(RR_AGE)
 +obrender_libobrender_la_LIBADD = \
 +      obt/libobt.la \
        $(X_LIBS) \
        $(PANGO_LIBS) \
 -      $(XFT_LIBS) \
        $(GLIB_LIBS) \
        $(XML_LIBS)
 -render_libobrender_la_SOURCES = \
 +obrender_libobrender_la_SOURCES = \
        gettext.h \
 -      render/color.h \
 -      render/color.c \
 -      render/font.h \
 -      render/font.c \
 -      render/geom.h \
 -      render/gradient.h \
 -      render/gradient.c \
 -      render/icon.h \
 -      render/image.h \
 -      render/image.c \
 -      render/imagecache.h \
 -      render/imagecache.c \
 -      render/instance.h \
 -      render/instance.c \
 -      render/mask.h \
 -      render/mask.c \
 -      render/render.h \
 -      render/render.c \
 -      render/theme.h \
 -      render/theme.c
 -
 -## parser ##
 -
 -parser_libobparser_la_CPPFLAGS = \
 +      obrender/color.h \
 +      obrender/color.c \
 +      obrender/font.h \
 +      obrender/font.c \
 +      obrender/geom.h \
 +      obrender/gradient.h \
 +      obrender/gradient.c \
 +      obrender/icon.h \
 +      obrender/image.h \
 +      obrender/image.c \
 +      obrender/imagecache.h \
 +      obrender/imagecache.c \
 +      obrender/instance.h \
 +      obrender/instance.c \
 +      obrender/mask.h \
 +      obrender/mask.c \
 +      obrender/render.h \
 +      obrender/render.c \
 +      obrender/theme.h \
 +      obrender/theme.c
 +
 +## obt ##
 +
 +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/xml.h \
 +      obt/xml.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) \
        -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) \
        $(XML_LIBS) \
        $(EFENCE_LIBS) \
        $(LIBINTL) \
 -      render/libobrender.la \
 -      parser/libobparser.la
 +      obrender/libobrender.la \
 +      obt/libobt.la
  openbox_openbox_LDFLAGS = -export-dynamic
  openbox_openbox_SOURCES = \
        gettext.h \
        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 \
        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 \
        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 \
        openbox/prompt.h \
        openbox/popup.c \
        openbox/popup.h \
 -      openbox/prop.c \
 -      openbox/prop.h \
        openbox/resist.c \
        openbox/resist.h \
        openbox/screen.c \
        openbox/translate.c \
        openbox/translate.h \
        openbox/window.c \
 -      openbox/window.h \
 -      openbox/xerror.c \
 -      openbox/xerror.h
 -
 +      openbox/window.h
  
  ## gnome-panel-control ##
  
@@@ -407,32 -406,24 +407,32 @@@ dist_syscrash_theme_DATA= 
  
  ## public headers ##
  
 -pubinclude_HEADERS = \
 -      render/color.h \
 -      render/font.h \
 -      render/geom.h \
 -      render/gradient.h \
 -      render/image.h \
 -      render/instance.h \
 -      render/mask.h \
 -      render/render.h \
 -      render/theme.h \
 -      parser/parse.h
 -
 -nodist_pubinclude_HEADERS = \
 -      version.h
 +rrpubinclude_HEADERS = \
 +      obrender/color.h \
 +      obrender/font.h \
 +      obrender/geom.h \
 +      obrender/gradient.h \
 +      obrender/image.h \
 +      obrender/instance.h \
 +      obrender/mask.h \
 +      obrender/render.h \
 +      obrender/theme.h \
 +      obrender/version.h
 +
 +obtpubinclude_HEADERS = \
 +      obt/display.h \
 +      obt/keyboard.h \
 +      obt/mainloop.h \
 +      obt/xml.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
 +      obrender/obrender-3.5.pc \
 +      obt/obt-3.5.pc
  
  ## data ##
  
@@@ -484,6 -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 \
        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 \
+       doc/obxprop.1.sgml \
+       doc/obxprop.1.in \
 +      obrender/version.h.in \
 +      obrender/obrender-3.5.pc.in \
 +      obt/obt-3.5.pc.in \
 +      obt/version.h.in \
        tools/themeupdate/themeupdate.py \
        tests/hideshow.py \
        tests/Makefile \
@@@ -560,7 -552,7 +562,7 @@@ CLEANFILES = 
  #       $(MAKE) -$(MAKEFLAGS) -C doc/doxygen doc
  
  distclean-local:
 -      for d in . m4 po render; do \
 +      for d in . m4 po obrender parser obt openbox; do \
                for p in core core.* gmon.out *\~ *.orig *.rej .\#*; do \
                        rm -f "$$d/$$p"; \
                done \
diff --combined data/rc.xml
index e5eb9178a8bd0789fbbada31e1cf502be2a0f6ee,c89625dd764815ec632af87112a9135d23ea8dc1..f5f3712f048abeb808dabe0cada04205ea812441
      <slant>normal</slant>
      <!-- 'italic' or 'normal' -->
    </font>
 -  <font place="OnScreenDisplay">
 +  <font place="ActiveOnScreenDisplay">
 +    <name>sans</name>
 +    <size>9</size>
 +    <!-- font size in points -->
 +    <weight>bold</weight>
 +    <!-- 'bold' or 'normal' -->
 +    <slant>normal</slant>
 +    <!-- 'italic' or 'normal' -->
 +  </font>
 +  <font place="InactiveOnScreenDisplay">
      <name>sans</name>
      <size>9</size>
      <!-- font size in points -->
      </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>
         menu is hidden again -->
    <middle>no</middle>
    <!-- center submenus vertically about the parent entry -->
-   <submenuShowDelay>100</submenuShowDelay>
-   <!-- this one is easy, time to delay before showing a submenu after hovering
-        over the parent entry -->
+   <submenuShowDelay>200</submenuShowDelay>
+   <!-- time to delay before showing a submenu after hovering over the parent
+        entry.
+        if this is a negative value, then the delay is infinite and the
+        submenu will not be shown until it is clicked on -->
+   <submenuHideDelay>400</submenuHideDelay>
+   <!-- time to delay before hiding a submenu when selecting another
+        entry in parent menu -->
+        if this is a negative value, then the delay is infinite and the
+        submenu will not be hidden until a different submenu is opened -->
    <applicationIcons>yes</applicationIcons>
    <!-- controls if icons appear in the client-list-(combined-)menu -->
    <manageDesktops>yes</manageDesktops>
diff --combined openbox/actions/focus.c
index 40c2c80d5c68506a0170769edf84e11e98ee3bf1,1b544910220f8143dedd588ceda914b620c0058d..8bae49c7a1aaf0778aa142d789f4a43b0366682f
@@@ -6,28 -6,44 +6,32 @@@
  
  typedef struct {
      gboolean here;
+     gboolean stop_int;
  } 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);
+     o->stop_int = TRUE;
  
 -    if ((n = parse_find_node("here", node)))
 -        o->here = parse_bool(doc, n);
 -    if ((n = parse_find_node("stopInteractive", node)))
 -        o->stop_int = parse_bool(doc, n);
 +    if ((n = obt_xml_find_node(node, "here")))
 +        o->here = obt_xml_node_bool(n);
++    if ((n = obt_xml_find_node(node, "stopInteractive")))
++        o->stop_int = obt_xml_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)
  {
              (data->context != OB_FRAME_CONTEXT_CLIENT &&
               data->context != OB_FRAME_CONTEXT_FRAME))
          {
+             if (o->stop_int)
+                 actions_interactive_cancel_act();
              actions_client_move(data, TRUE);
              client_activate(data->client, TRUE, o->here, FALSE, FALSE, TRUE);
              actions_client_move(data, FALSE);
          }
      } else if (data->context == OB_FRAME_CONTEXT_DESKTOP) {
+         if (o->stop_int)
+             actions_interactive_cancel_act();
          /* focus action on the root window. make keybindings work for this
             openbox instance, but don't focus any specific client */
          focus_nothing();
diff --combined openbox/config.c
index 92445517b77b708d0b434ca10d468142c7152961,240606a43e591d3f3f7a1166bc809a162cbffadc..0241e3f49f4a022add8526d9572145d84f6864c3
  #include "keyboard.h"
  #include "mouse.h"
  #include "actions.h"
 -#include "prop.h"
  #include "translate.h"
  #include "client.h"
  #include "screen.h"
 -#include "parser/parse.h"
  #include "openbox.h"
  #include "gettext.h"
 +#include "obt/paths.h"
  
  gboolean config_focus_new;
  gboolean config_focus_follow;
@@@ -34,7 -35,6 +34,7 @@@ guint    config_focus_delay
  gboolean config_focus_raise;
  gboolean config_focus_last;
  gboolean config_focus_under_mouse;
 +gboolean config_unfocus_leave;
  
  ObPlacePolicy  config_place_policy;
  gboolean       config_place_center;
@@@ -47,7 -47,6 +47,7 @@@ StrutPartial config_margins
  
  gchar   *config_theme;
  gboolean config_theme_keepborder;
 +guint    config_theme_window_list_icon_size;
  
  gchar   *config_title_layout;
  
@@@ -57,8 -56,7 +57,8 @@@ RrFont *config_font_activewindow
  RrFont *config_font_inactivewindow;
  RrFont *config_font_menuitem;
  RrFont *config_font_menutitle;
 -RrFont *config_font_osd;
 +RrFont *config_font_activeosd;
 +RrFont *config_font_inactiveosd;
  
  guint   config_desktops_num;
  GSList *config_desktops_names;
@@@ -93,6 -91,7 +93,7 @@@ gint config_mouse_screenedgetime
  guint    config_menu_hide_delay;
  gboolean config_menu_middle;
  guint    config_submenu_show_delay;
+ guint    config_submenu_hide_delay;
  gboolean config_menu_client_list_icons;
  gboolean config_menu_manage_desktops;
  
@@@ -152,9 -151,10 +153,9 @@@ void config_app_settings_copy_non_defau
      }
  }
  
 -static void config_parse_gravity_coord(xmlDocPtr doc, xmlNodePtr node,
 -                                       GravityCoord *c)
 +static void config_parse_gravity_coord(xmlNodePtr node, GravityCoord *c)
  {
 -    gchar *s = parse_string(doc, node);
 +    gchar *s = obt_xml_node_string(node);
      if (!g_ascii_strcasecmp(s, "center"))
          c->center = TRUE;
      else {
     the monitor, so <position><x>center</x></position><monitor>2</monitor>
     will center the window on the second monitor.
  */
 -static void parse_per_app_settings(ObParseInst *inst, xmlDocPtr doc,
 -                                   xmlNodePtr node, gpointer data)
 +static void parse_per_app_settings(xmlNodePtr node, gpointer d)
  {
 -    xmlNodePtr app = parse_find_node("application", node->children);
 +    xmlNodePtr app = obt_xml_find_node(node->children, "application");
      gchar *name = NULL, *class = NULL, *role = NULL, *type = NULL;
      gboolean name_set, class_set, type_set;
      gboolean x_pos_given;
  
      while (app) {
 -        name_set = class_set = type_set = x_pos_given = FALSE;
 +        x_pos_given = FALSE;
  
 -        class_set = parse_attr_string("class", app, &class);
 -        name_set = parse_attr_string("name", app, &name);
 -        type_set = parse_attr_string("type", app, &type);
 +        class_set = obt_xml_attr_string(app, "class", &class);
 +        name_set = obt_xml_attr_string(app, "name", &name);
 +        type_set = obt_xml_attr_string(app, "type", &type);
          if (class_set || name_set) {
              xmlNodePtr n, c;
              ObAppSettings *settings = config_create_app_settings();;
                      settings->type = OB_CLIENT_TYPE_DESKTOP;
              }
  
 -            if (parse_attr_string("role", app, &role))
 +            if (obt_xml_attr_string(app, "role", &role))
                  settings->role = g_pattern_spec_new(role);
  
 -            if ((n = parse_find_node("decor", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->decor = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "decor")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->decor = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("shade", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->shade = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "shade")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->shade = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("position", app->children))) {
 -                if ((c = parse_find_node("x", n->children)))
 -                    if (!parse_contains("default", doc, c)) {
 -                        config_parse_gravity_coord(doc, c,
 -                                                   &settings->position.x);
 +            if ((n = obt_xml_find_node(app->children, "position"))) {
 +                if ((c = obt_xml_find_node(n->children, "x")))
 +                    if (!obt_xml_node_contains(c, "default")) {
 +                        config_parse_gravity_coord(c, &settings->position.x);
                          x_pos_given = TRUE;
                      }
  
 -                if (x_pos_given && (c = parse_find_node("y", n->children)))
 -                    if (!parse_contains("default", doc, c)) {
 -                        config_parse_gravity_coord(doc, c,
 -                                                   &settings->position.y);
 +                if (x_pos_given && (c = obt_xml_find_node(n->children, "y")))
 +                    if (!obt_xml_node_contains(c, "default")) {
 +                        config_parse_gravity_coord(c, &settings->position.y);
                          settings->pos_given = TRUE;
                      }
  
                  if (settings->pos_given &&
 -                    (c = parse_find_node("monitor", n->children)))
 -                    if (!parse_contains("default", doc, c)) {
 -                        gchar *s = parse_string(doc, c);
 +                    (c = obt_xml_find_node(n->children, "monitor")))
 +                    if (!obt_xml_node_contains(c, "default")) {
 +                        gchar *s = obt_xml_node_string(c);
                          if (!g_ascii_strcasecmp(s, "mouse"))
                              settings->monitor = 0;
                          else
 -                            settings->monitor = parse_int(doc, c);
 +                            settings->monitor = obt_xml_node_int(c);
                          g_free(s);
                      }
  
 -                parse_attr_bool("force", n, &settings->pos_force);
 +                obt_xml_attr_bool(n, "force", &settings->pos_force);
              }
  
 -            if ((n = parse_find_node("focus", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->focus = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "focus")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->focus = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("desktop", app->children))) {
 -                if (!parse_contains("default", doc, n)) {
 -                    gchar *s = parse_string(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "desktop"))) {
 +                if (!obt_xml_node_contains(n, "default")) {
 +                    gchar *s = obt_xml_node_string(n);
                      if (!g_ascii_strcasecmp(s, "all"))
                          settings->desktop = DESKTOP_ALL;
                      else {
 -                        gint i = parse_int(doc, n);
 +                        gint i = obt_xml_node_int(n);
                          if (i > 0)
                              settings->desktop = i;
                      }
                  }
              }
  
 -            if ((n = parse_find_node("layer", app->children)))
 -                if (!parse_contains("default", doc, n)) {
 -                    gchar *s = parse_string(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "layer")))
 +                if (!obt_xml_node_contains(n, "default")) {
 +                    gchar *s = obt_xml_node_string(n);
                      if (!g_ascii_strcasecmp(s, "above"))
                          settings->layer = 1;
                      else if (!g_ascii_strcasecmp(s, "below"))
                      g_free(s);
                  }
  
 -            if ((n = parse_find_node("iconic", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->iconic = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "iconic")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->iconic = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("skip_pager", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->skip_pager = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "skip_pager")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->skip_pager = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("skip_taskbar", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->skip_taskbar = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "skip_taskbar")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->skip_taskbar = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("fullscreen", app->children)))
 -                if (!parse_contains("default", doc, n))
 -                    settings->fullscreen = parse_bool(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "fullscreen")))
 +                if (!obt_xml_node_contains(n, "default"))
 +                    settings->fullscreen = obt_xml_node_bool(n);
  
 -            if ((n = parse_find_node("maximized", app->children)))
 -                if (!parse_contains("default", doc, n)) {
 -                    gchar *s = parse_string(doc, n);
 +            if ((n = obt_xml_find_node(app->children, "maximized")))
 +                if (!obt_xml_node_contains(n, "default")) {
 +                    gchar *s = obt_xml_node_string(n);
                      if (!g_ascii_strcasecmp(s, "horizontal")) {
                          settings->max_horz = TRUE;
                          settings->max_vert = FALSE;
                          settings->max_vert = TRUE;
                      } else
                          settings->max_horz = settings->max_vert =
 -                            parse_bool(doc, n);
 +                            obt_xml_node_bool(n);
                      g_free(s);
                  }
  
              name = class = role = NULL;
          }
  
 -        app = parse_find_node("application", app->next);
 +        app = obt_xml_find_node(app->next, "application");
      }
  }
  
  
  */
  
 -static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                      GList *keylist)
 +static void parse_key(xmlNodePtr node, GList *keylist)
  {
      gchar *key;
      xmlNodePtr n;
      gboolean is_chroot = FALSE;
  
 -    if (!parse_attr_string("key", node, &key))
 +    if (!obt_xml_attr_string(node, "key", &key))
          return;
  
 -    parse_attr_bool("chroot", node, &is_chroot);
 +    obt_xml_attr_bool(node, "chroot", &is_chroot);
  
      keylist = g_list_append(keylist, key);
  
 -    if ((n = parse_find_node("keybind", node->children))) {
 +    if ((n = obt_xml_find_node(node->children, "keybind"))) {
          while (n) {
 -            parse_key(i, doc, n, keylist);
 -            n = parse_find_node("keybind", n->next);
 +            parse_key(n, keylist);
 +            n = obt_xml_find_node(n->next, "keybind");
          }
      }
 -    else if ((n = parse_find_node("action", node->children))) {
 +    else if ((n = obt_xml_find_node(node->children, "action"))) {
          while (n) {
              ObActionsAct *action;
  
 -            action = actions_parse(i, doc, n);
 +            action = actions_parse(n);
              if (action)
                  keyboard_bind(keylist, action);
 -            n = parse_find_node("action", n->next);
 +            n = obt_xml_find_node(n->next, "action");
          }
      }
  
      keylist = g_list_delete_link(keylist, g_list_last(keylist));
  }
  
 -static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                           gpointer data)
 +static void parse_keyboard(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
      gchar *key;
  
      keyboard_unbind_all();
  
 -    if ((n = parse_find_node("chainQuitKey", node->children))) {
 -        key = parse_string(doc, n);
 +    if ((n = obt_xml_find_node(node->children, "chainQuitKey"))) {
 +        key = obt_xml_node_string(n);
          translate_key(key, &config_keyboard_reset_state,
                        &config_keyboard_reset_keycode);
          g_free(key);
      }
  
 -    if ((n = parse_find_node("keybind", node->children)))
 +    if ((n = obt_xml_find_node(node->children, "keybind")))
          while (n) {
 -            parse_key(i, doc, n, NULL);
 -            n = parse_find_node("keybind", n->next);
 +            parse_key(n, NULL);
 +            n = obt_xml_find_node(n->next, "keybind");
          }
  }
  
  
  */
  
 -static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                        gpointer data)
 +static void parse_mouse(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n, nbut, nact;
      gchar *buttonstr;
  
      node = node->children;
  
 -    if ((n = parse_find_node("dragThreshold", node)))
 -        config_mouse_threshold = parse_int(doc, n);
 -    if ((n = parse_find_node("doubleClickTime", node)))
 -        config_mouse_dclicktime = parse_int(doc, n);
 -    if ((n = parse_find_node("screenEdgeWarpTime", node))) {
 -        config_mouse_screenedgetime = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "dragThreshold")))
 +        config_mouse_threshold = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "doubleClickTime")))
 +        config_mouse_dclicktime = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "screenEdgeWarpTime"))) {
 +        config_mouse_screenedgetime = obt_xml_node_int(n);
          /* minimum value of 25 for this property, when it is 1 and you hit the
             edge it basically never stops */
          if (config_mouse_screenedgetime && config_mouse_screenedgetime < 25)
              config_mouse_screenedgetime = 25;
      }
  
 -    n = parse_find_node("context", node);
 +    n = obt_xml_find_node(node, "context");
      while (n) {
 -        if (!parse_attr_string("name", n, &contextstr))
 +        if (!obt_xml_attr_string(n, "name", &contextstr))
              goto next_n;
 -        nbut = parse_find_node("mousebind", n->children);
 +        nbut = obt_xml_find_node(n->children, "mousebind");
          while (nbut) {
 -            if (!parse_attr_string("button", nbut, &buttonstr))
 +            if (!obt_xml_attr_string(nbut, "button", &buttonstr))
                  goto next_nbut;
 -            if (parse_attr_contains("press", nbut, "action")) {
 +            if (obt_xml_attr_contains(nbut, "action", "press")) {
                  mact = OB_MOUSE_ACTION_PRESS;
 -            } else if (parse_attr_contains("release", nbut, "action")) {
 +            } else if (obt_xml_attr_contains(nbut, "action", "release")) {
                  mact = OB_MOUSE_ACTION_RELEASE;
 -            } else if (parse_attr_contains("click", nbut, "action")) {
 +            } else if (obt_xml_attr_contains(nbut, "action", "click")) {
                  mact = OB_MOUSE_ACTION_CLICK;
 -            } else if (parse_attr_contains("doubleclick", nbut,"action")) {
 +            } else if (obt_xml_attr_contains(nbut, "action","doubleclick")) {
                  mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
 -            } else if (parse_attr_contains("drag", nbut, "action")) {
 +            } else if (obt_xml_attr_contains(nbut, "action", "drag")) {
                  mact = OB_MOUSE_ACTION_MOTION;
              } else
                  goto next_nbut;
 -            nact = parse_find_node("action", nbut->children);
 +            nact = obt_xml_find_node(nbut->children, "action");
              while (nact) {
                  ObActionsAct *action;
  
 -                if ((action = actions_parse(i, doc, nact)))
 +                if ((action = actions_parse(nact)))
                      mouse_bind(buttonstr, contextstr, mact, action);
 -                nact = parse_find_node("action", nact->next);
 +                nact = obt_xml_find_node(nact->next, "action");
              }
              g_free(buttonstr);
          next_nbut:
 -            nbut = parse_find_node("mousebind", nbut->next);
 +            nbut = obt_xml_find_node(nbut->next, "mousebind");
          }
          g_free(contextstr);
      next_n:
 -        n = parse_find_node("context", n->next);
 +        n = obt_xml_find_node(n->next, "context");
      }
  }
  
 -static void parse_focus(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                        gpointer data)
 +static void parse_focus(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("focusNew", node)))
 -        config_focus_new = parse_bool(doc, n);
 -    if ((n = parse_find_node("followMouse", node)))
 -        config_focus_follow = parse_bool(doc, n);
 -    if ((n = parse_find_node("focusDelay", node)))
 -        config_focus_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("raiseOnFocus", node)))
 -        config_focus_raise = parse_bool(doc, n);
 -    if ((n = parse_find_node("focusLast", node)))
 -        config_focus_last = parse_bool(doc, n);
 -    if ((n = parse_find_node("underMouse", node)))
 -        config_focus_under_mouse = parse_bool(doc, n);
 +    if ((n = obt_xml_find_node(node, "focusNew")))
 +        config_focus_new = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "followMouse")))
 +        config_focus_follow = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "focusDelay")))
 +        config_focus_delay = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "raiseOnFocus")))
 +        config_focus_raise = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "focusLast")))
 +        config_focus_last = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "underMouse")))
 +        config_focus_under_mouse = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "unfocusOnLeave")))
 +        config_unfocus_leave = obt_xml_node_bool(n);
  }
  
 -static void parse_placement(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                            gpointer data)
 +static void parse_placement(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("policy", node)))
 -        if (parse_contains("UnderMouse", doc, n))
 +    if ((n = obt_xml_find_node(node, "policy")))
 +        if (obt_xml_node_contains(n, "UnderMouse"))
              config_place_policy = OB_PLACE_POLICY_MOUSE;
 -    if ((n = parse_find_node("center", node)))
 -        config_place_center = parse_bool(doc, n);
 -    if ((n = parse_find_node("monitor", node))) {
 -        if (parse_contains("active", doc, n))
 +    if ((n = obt_xml_find_node(node, "center")))
 +        config_place_center = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "monitor"))) {
 +        if (obt_xml_node_contains(n, "active"))
              config_place_monitor = OB_PLACE_MONITOR_ACTIVE;
 -        else if (parse_contains("mouse", doc, n))
 +        else if (obt_xml_node_contains(n, "mouse"))
              config_place_monitor = OB_PLACE_MONITOR_MOUSE;
      }
 -    if ((n = parse_find_node("primaryMonitor", node))) {
 -        config_primary_monitor_index = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "primaryMonitor"))) {
 +        config_primary_monitor_index = obt_xml_node_int(n);
          if (!config_primary_monitor_index) {
 -            if (parse_contains("mouse", doc, n))
 +            if (obt_xml_node_contains(n, "mouse"))
                  config_primary_monitor = OB_PLACE_MONITOR_MOUSE;
          }
      }
  }
  
 -static void parse_margins(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                          gpointer data)
 +static void parse_margins(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("top", node)))
 -        config_margins.top = MAX(0, parse_int(doc, n));
 -    if ((n = parse_find_node("left", node)))
 -        config_margins.left = MAX(0, parse_int(doc, n));
 -    if ((n = parse_find_node("right", node)))
 -        config_margins.right = MAX(0, parse_int(doc, n));
 -    if ((n = parse_find_node("bottom", node)))
 -        config_margins.bottom = MAX(0, parse_int(doc, n));
 +    if ((n = obt_xml_find_node(node, "top")))
 +        config_margins.top = MAX(0, obt_xml_node_int(n));
 +    if ((n = obt_xml_find_node(node, "left")))
 +        config_margins.left = MAX(0, obt_xml_node_int(n));
 +    if ((n = obt_xml_find_node(node, "right")))
 +        config_margins.right = MAX(0, obt_xml_node_int(n));
 +    if ((n = obt_xml_find_node(node, "bottom")))
 +        config_margins.bottom = MAX(0, obt_xml_node_int(n));
  }
  
 -static void parse_theme(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                        gpointer data)
 +static void parse_theme(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("name", node))) {
 +    if ((n = obt_xml_find_node(node, "name"))) {
          gchar *c;
  
          g_free(config_theme);
 -        c = parse_string(doc, n);
 -        config_theme = parse_expand_tilde(c);
 +        c = obt_xml_node_string(n);
 +        config_theme = obt_paths_expand_tilde(c);
          g_free(c);
      }
 -    if ((n = parse_find_node("titleLayout", node))) {
 +    if ((n = obt_xml_find_node(node, "titleLayout"))) {
          gchar *c, *d;
  
          g_free(config_title_layout);
 -        config_title_layout = parse_string(doc, n);
 +        config_title_layout = obt_xml_node_string(n);
  
          /* replace duplicates with spaces */
          for (c = config_title_layout; *c != '\0'; ++c)
              for (d = c+1; *d != '\0'; ++d)
                  if (*c == *d) *d = ' ';
      }
 -    if ((n = parse_find_node("keepBorder", node)))
 -        config_theme_keepborder = parse_bool(doc, n);
 -    if ((n = parse_find_node("animateIconify", node)))
 -        config_animate_iconify = parse_bool(doc, n);
 +    if ((n = obt_xml_find_node(node, "keepBorder")))
 +        config_theme_keepborder = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "animateIconify")))
 +        config_animate_iconify = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "windowListIconSize"))) {
 +        config_theme_window_list_icon_size = obt_xml_node_int(n);
 +        if (config_theme_window_list_icon_size < 16)
 +            config_theme_window_list_icon_size = 16;
 +        else if (config_theme_window_list_icon_size > 96)
 +            config_theme_window_list_icon_size = 96;
 +    }
  
 -    n = parse_find_node("font", node);
 +    n = obt_xml_find_node(node, "font");
      while (n) {
          xmlNodePtr   fnode;
          RrFont     **font;
          RrFontWeight weight = RrDefaultFontWeight;
          RrFontSlant  slant = RrDefaultFontSlant;
  
 -        if (parse_attr_contains("ActiveWindow", n, "place"))
 +        if (obt_xml_attr_contains(n, "place", "ActiveWindow"))
              font = &config_font_activewindow;
 -        else if (parse_attr_contains("InactiveWindow", n, "place"))
 +        else if (obt_xml_attr_contains(n, "place", "InactiveWindow"))
              font = &config_font_inactivewindow;
 -        else if (parse_attr_contains("MenuHeader", n, "place"))
 +        else if (obt_xml_attr_contains(n, "place", "MenuHeader"))
              font = &config_font_menutitle;
 -        else if (parse_attr_contains("MenuItem", n, "place"))
 +        else if (obt_xml_attr_contains(n, "place", "MenuItem"))
              font = &config_font_menuitem;
 -        else if (parse_attr_contains("OnScreenDisplay", n, "place"))
 -            font = &config_font_osd;
 +        else if (obt_xml_attr_contains(n, "place", "ActiveOnScreenDisplay"))
 +            font = &config_font_activeosd;
 +        else if (obt_xml_attr_contains(n, "place", "OnScreenDisplay"))
 +            font = &config_font_activeosd;
 +        else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay"))
 +            font = &config_font_inactiveosd;
          else
              goto next_font;
  
 -        if ((fnode = parse_find_node("name", n->children))) {
 +        if ((fnode = obt_xml_find_node(n->children, "name"))) {
              g_free(name);
 -            name = parse_string(doc, fnode);
 +            name = obt_xml_node_string(fnode);
          }
 -        if ((fnode = parse_find_node("size", n->children))) {
 -            int s = parse_int(doc, fnode);
 +        if ((fnode = obt_xml_find_node(n->children, "size"))) {
 +            int s = obt_xml_node_int(fnode);
              if (s > 0) size = s;
          }
 -        if ((fnode = parse_find_node("weight", n->children))) {
 -            gchar *w = parse_string(doc, fnode);
 +        if ((fnode = obt_xml_find_node(n->children, "weight"))) {
 +            gchar *w = obt_xml_node_string(fnode);
              if (!g_ascii_strcasecmp(w, "Bold"))
                  weight = RR_FONTWEIGHT_BOLD;
              g_free(w);
          }
 -        if ((fnode = parse_find_node("slant", n->children))) {
 -            gchar *s = parse_string(doc, fnode);
 +        if ((fnode = obt_xml_find_node(n->children, "slant"))) {
 +            gchar *s = obt_xml_node_string(fnode);
              if (!g_ascii_strcasecmp(s, "Italic"))
                  slant = RR_FONTSLANT_ITALIC;
              if (!g_ascii_strcasecmp(s, "Oblique"))
          *font = RrFontOpen(ob_rr_inst, name, size, weight, slant);
          g_free(name);
      next_font:
 -        n = parse_find_node("font", n->next);
 +        n = obt_xml_find_node(n->next, "font");
      }
  }
  
 -static void parse_desktops(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                           gpointer data)
 +static void parse_desktops(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("number", node))) {
 -        gint d = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "number"))) {
 +        gint d = obt_xml_node_int(n);
          if (d > 0)
              config_desktops_num = (unsigned) d;
      }
 -    if ((n = parse_find_node("firstdesk", node))) {
 -        gint d = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "firstdesk"))) {
 +        gint d = obt_xml_node_int(n);
          if (d > 0)
              config_screen_firstdesk = (unsigned) d;
      }
 -    if ((n = parse_find_node("names", node))) {
 +    if ((n = obt_xml_find_node(node, "names"))) {
          GSList *it;
          xmlNodePtr nname;
  
          g_slist_free(config_desktops_names);
          config_desktops_names = NULL;
  
 -        nname = parse_find_node("name", n->children);
 +        nname = obt_xml_find_node(n->children, "name");
          while (nname) {
 -            config_desktops_names = g_slist_append(config_desktops_names,
 -                                                   parse_string(doc, nname));
 -            nname = parse_find_node("name", nname->next);
 +            config_desktops_names =
 +                g_slist_append(config_desktops_names,
 +                               obt_xml_node_string(nname));
 +            nname = obt_xml_find_node(nname->next, "name");
          }
      }
 -    if ((n = parse_find_node("popupTime", node)))
 -        config_desktop_popup_time = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "popupTime")))
 +        config_desktop_popup_time = obt_xml_node_int(n);
  }
  
 -static void parse_resize(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                         gpointer data)
 +static void parse_resize(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("drawContents", node)))
 -        config_resize_redraw = parse_bool(doc, n);
 -    if ((n = parse_find_node("popupShow", node))) {
 -        config_resize_popup_show = parse_int(doc, n);
 -        if (parse_contains("Always", doc, n))
 +    if ((n = obt_xml_find_node(node, "drawContents")))
 +        config_resize_redraw = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "popupShow"))) {
 +        config_resize_popup_show = obt_xml_node_int(n);
 +        if (obt_xml_node_contains(n, "Always"))
              config_resize_popup_show = 2;
 -        else if (parse_contains("Never", doc, n))
 +        else if (obt_xml_node_contains(n, "Never"))
              config_resize_popup_show = 0;
 -        else if (parse_contains("Nonpixel", doc, n))
 +        else if (obt_xml_node_contains(n, "Nonpixel"))
              config_resize_popup_show = 1;
      }
 -    if ((n = parse_find_node("popupPosition", node))) {
 -        if (parse_contains("Top", doc, n))
 +    if ((n = obt_xml_find_node(node, "popupPosition"))) {
 +        if (obt_xml_node_contains(n, "Top"))
              config_resize_popup_pos = OB_RESIZE_POS_TOP;
 -        else if (parse_contains("Center", doc, n))
 +        else if (obt_xml_node_contains(n, "Center"))
              config_resize_popup_pos = OB_RESIZE_POS_CENTER;
 -        else if (parse_contains("Fixed", doc, n)) {
 +        else if (obt_xml_node_contains(n, "Fixed")) {
              config_resize_popup_pos = OB_RESIZE_POS_FIXED;
  
 -            if ((n = parse_find_node("popupFixedPosition", node))) {
 +            if ((n = obt_xml_find_node(node, "popupFixedPosition"))) {
                  xmlNodePtr n2;
  
 -                if ((n2 = parse_find_node("x", n->children)))
 -                    config_parse_gravity_coord(doc, n2,
 +                if ((n2 = obt_xml_find_node(n->children, "x")))
 +                    config_parse_gravity_coord(n2,
                                                 &config_resize_popup_fixed.x);
 -                if ((n2 = parse_find_node("y", n->children)))
 -                    config_parse_gravity_coord(doc, n2,
 +                if ((n2 = obt_xml_find_node(n->children, "y")))
 +                    config_parse_gravity_coord(n2,
                                                 &config_resize_popup_fixed.y);
  
                  config_resize_popup_fixed.x.pos =
      }
  }
  
 -static void parse_dock(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                       gpointer data)
 +static void parse_dock(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
  
 -    if ((n = parse_find_node("position", node))) {
 -        if (parse_contains("TopLeft", doc, n))
 +    if ((n = obt_xml_find_node(node, "position"))) {
 +        if (obt_xml_node_contains(n, "TopLeft"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_NORTHWEST;
 -        else if (parse_contains("Top", doc, n))
 +        else if (obt_xml_node_contains(n, "Top"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_NORTH;
 -        else if (parse_contains("TopRight", doc, n))
 +        else if (obt_xml_node_contains(n, "TopRight"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_NORTHEAST;
 -        else if (parse_contains("Right", doc, n))
 +        else if (obt_xml_node_contains(n, "Right"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_EAST;
 -        else if (parse_contains("BottomRight", doc, n))
 +        else if (obt_xml_node_contains(n, "BottomRight"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_SOUTHEAST;
 -        else if (parse_contains("Bottom", doc, n))
 +        else if (obt_xml_node_contains(n, "Bottom"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_SOUTH;
 -        else if (parse_contains("BottomLeft", doc, n))
 +        else if (obt_xml_node_contains(n, "BottomLeft"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_SOUTHWEST;
 -        else if (parse_contains("Left", doc, n))
 +        else if (obt_xml_node_contains(n, "Left"))
              config_dock_floating = FALSE,
              config_dock_pos = OB_DIRECTION_WEST;
 -        else if (parse_contains("Floating", doc, n))
 +        else if (obt_xml_node_contains(n, "Floating"))
              config_dock_floating = TRUE;
      }
      if (config_dock_floating) {
 -        if ((n = parse_find_node("floatingX", node)))
 -            config_dock_x = parse_int(doc, n);
 -        if ((n = parse_find_node("floatingY", node)))
 -            config_dock_y = parse_int(doc, n);
 +        if ((n = obt_xml_find_node(node, "floatingX")))
 +            config_dock_x = obt_xml_node_int(n);
 +        if ((n = obt_xml_find_node(node, "floatingY")))
 +            config_dock_y = obt_xml_node_int(n);
      } else {
 -        if ((n = parse_find_node("noStrut", node)))
 -            config_dock_nostrut = parse_bool(doc, n);
 +        if ((n = obt_xml_find_node(node, "noStrut")))
 +            config_dock_nostrut = obt_xml_node_bool(n);
      }
 -    if ((n = parse_find_node("stacking", node))) {
 -        if (parse_contains("above", doc, n))
 -            config_dock_layer = OB_STACKING_LAYER_ABOVE;
 -        else if (parse_contains("normal", doc, n))
 +    if ((n = obt_xml_find_node(node, "stacking"))) {
 +        if (obt_xml_node_contains(n, "normal"))
              config_dock_layer = OB_STACKING_LAYER_NORMAL;
 -        else if (parse_contains("below", doc, n))
 +        else if (obt_xml_node_contains(n, "below"))
              config_dock_layer = OB_STACKING_LAYER_BELOW;
 +        else if (obt_xml_node_contains(n, "above"))
 +            config_dock_layer = OB_STACKING_LAYER_ABOVE;
      }
 -    if ((n = parse_find_node("direction", node))) {
 -        if (parse_contains("horizontal", doc, n))
 +    if ((n = obt_xml_find_node(node, "direction"))) {
 +        if (obt_xml_node_contains(n, "horizontal"))
              config_dock_orient = OB_ORIENTATION_HORZ;
 -        else if (parse_contains("vertical", doc, n))
 +        else if (obt_xml_node_contains(n, "vertical"))
              config_dock_orient = OB_ORIENTATION_VERT;
      }
 -    if ((n = parse_find_node("autoHide", node)))
 -        config_dock_hide = parse_bool(doc, n);
 -    if ((n = parse_find_node("hideDelay", node)))
 -        config_dock_hide_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("showDelay", node)))
 -        config_dock_show_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("moveButton", node))) {
 -        gchar *str = parse_string(doc, n);
 +    if ((n = obt_xml_find_node(node, "autoHide")))
 +        config_dock_hide = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "hideDelay")))
 +        config_dock_hide_delay = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "showDelay")))
 +        config_dock_show_delay = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "moveButton"))) {
 +        gchar *str = obt_xml_node_string(n);
          guint b, s;
          if (translate_button(str, &s, &b)) {
              config_dock_app_move_button = b;
      }
  }
  
 -static void parse_menu(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                       gpointer data)
 +static void parse_menu(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
      node = node->children;
  
 -    if ((n = parse_find_node("hideDelay", node)))
 -        config_menu_hide_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("middle", node)))
 -        config_menu_middle = parse_bool(doc, n);
 -    if ((n = parse_find_node("submenuShowDelay", node)))
 -        config_submenu_show_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("submenuHideDelay", node)))
 -        config_submenu_hide_delay = parse_int(doc, n);
 -    if ((n = parse_find_node("applicationIcons", node)))
 -        config_menu_client_list_icons = parse_bool(doc, n);
 -    if ((n = parse_find_node("manageDesktops", node)))
 -        config_menu_manage_desktops = parse_bool(doc, n);
 -
 -    while ((node = parse_find_node("file", node))) {
 -            gchar *c = parse_string(doc, node);
 +    if ((n = obt_xml_find_node(node, "hideDelay")))
 +        config_menu_hide_delay = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "middle")))
 +        config_menu_middle = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "submenuShowDelay")))
 +        config_submenu_show_delay = obt_xml_node_int(n);
++    if ((n = obt_xml_find_node(node, "submenuHideDelay")))
++        config_submenu_hide_delay = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "applicationIcons")))
 +        config_menu_client_list_icons = obt_xml_node_bool(n);
 +    if ((n = obt_xml_find_node(node, "manageDesktops")))
 +        config_menu_manage_desktops = obt_xml_node_bool(n);
 +
 +    while ((node = obt_xml_find_node(node, "file"))) {
 +            gchar *c = obt_xml_node_string(node);
              config_menu_files = g_slist_append(config_menu_files,
 -                                               parse_expand_tilde(c));
 +                                               obt_paths_expand_tilde(c));
              g_free(c);
              node = node->next;
      }
  }
  
 -static void parse_resistance(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
 -                             gpointer data)
 +static void parse_resistance(xmlNodePtr node, gpointer d)
  {
      xmlNodePtr n;
  
      node = node->children;
 -    if ((n = parse_find_node("strength", node)))
 -        config_resist_win = parse_int(doc, n);
 -    if ((n = parse_find_node("screen_edge_strength", node)))
 -        config_resist_edge = parse_int(doc, n);
 +    if ((n = obt_xml_find_node(node, "strength")))
 +        config_resist_win = obt_xml_node_int(n);
 +    if ((n = obt_xml_find_node(node, "screen_edge_strength")))
 +        config_resist_edge = obt_xml_node_int(n);
  }
  
  typedef struct
@@@ -926,7 -929,7 +929,7 @@@ static void bind_default_mouse(void
                     actions_parse_string(it->actname));
  }
  
 -void config_startup(ObParseInst *i)
 +void config_startup(ObtXmlInst *i)
  {
      config_focus_new = TRUE;
      config_focus_follow = FALSE;
      config_focus_raise = FALSE;
      config_focus_last = TRUE;
      config_focus_under_mouse = FALSE;
 +    config_unfocus_leave = FALSE;
  
 -    parse_register(i, "focus", parse_focus, NULL);
 +    obt_xml_register(i, "focus", parse_focus, NULL);
  
      config_place_policy = OB_PLACE_POLICY_SMART;
      config_place_center = TRUE;
      config_primary_monitor_index = 1;
      config_primary_monitor = OB_PLACE_MONITOR_ACTIVE;
  
 -    parse_register(i, "placement", parse_placement, NULL);
 +    obt_xml_register(i, "placement", parse_placement, NULL);
  
      STRUT_PARTIAL_SET(config_margins, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  
 -    parse_register(i, "margins", parse_margins, NULL);
 +    obt_xml_register(i, "margins", parse_margins, NULL);
  
      config_theme = NULL;
  
      config_animate_iconify = TRUE;
      config_title_layout = g_strdup("NLIMC");
      config_theme_keepborder = TRUE;
 +    config_theme_window_list_icon_size = 36;
  
      config_font_activewindow = NULL;
      config_font_inactivewindow = NULL;
      config_font_menuitem = NULL;
      config_font_menutitle = NULL;
  
 -    parse_register(i, "theme", parse_theme, NULL);
 +    obt_xml_register(i, "theme", parse_theme, NULL);
  
      config_desktops_num = 4;
      config_screen_firstdesk = 1;
      config_desktops_names = NULL;
      config_desktop_popup_time = 875;
  
 -    parse_register(i, "desktops", parse_desktops, NULL);
 +    obt_xml_register(i, "desktops", parse_desktops, NULL);
  
      config_resize_redraw = TRUE;
      config_resize_popup_show = 1; /* nonpixel increments */
      GRAVITY_COORD_SET(config_resize_popup_fixed.x, 0, FALSE, FALSE);
      GRAVITY_COORD_SET(config_resize_popup_fixed.y, 0, FALSE, FALSE);
  
 -    parse_register(i, "resize", parse_resize, NULL);
 +    obt_xml_register(i, "resize", parse_resize, NULL);
  
      config_dock_layer = OB_STACKING_LAYER_ABOVE;
      config_dock_pos = OB_DIRECTION_NORTHEAST;
      config_dock_app_move_button = 2; /* middle */
      config_dock_app_move_modifiers = 0;
  
 -    parse_register(i, "dock", parse_dock, NULL);
 +    obt_xml_register(i, "dock", parse_dock, NULL);
  
      translate_key("C-g", &config_keyboard_reset_state,
                    &config_keyboard_reset_keycode);
  
      bind_default_keyboard();
  
 -    parse_register(i, "keyboard", parse_keyboard, NULL);
 +    obt_xml_register(i, "keyboard", parse_keyboard, NULL);
  
      config_mouse_threshold = 8;
      config_mouse_dclicktime = 200;
  
      bind_default_mouse();
  
 -    parse_register(i, "mouse", parse_mouse, NULL);
 +    obt_xml_register(i, "mouse", parse_mouse, NULL);
  
      config_resist_win = 10;
      config_resist_edge = 20;
  
 -    parse_register(i, "resistance", parse_resistance, NULL);
 +    obt_xml_register(i, "resistance", parse_resistance, NULL);
  
      config_menu_hide_delay = 250;
      config_menu_middle = FALSE;
-     config_submenu_show_delay = 0;
+     config_submenu_show_delay = 200;
+     config_submenu_hide_delay = 400;
      config_menu_client_list_icons = TRUE;
      config_menu_manage_desktops = TRUE;
      config_menu_files = NULL;
  
 -    parse_register(i, "menu", parse_menu, NULL);
 +    obt_xml_register(i, "menu", parse_menu, NULL);
  
      config_per_app_settings = NULL;
  
 -    parse_register(i, "applications", parse_per_app_settings, NULL);
 +    obt_xml_register(i, "applications", parse_per_app_settings, NULL);
  }
  
  void config_shutdown(void)
      RrFontClose(config_font_inactivewindow);
      RrFontClose(config_font_menuitem);
      RrFontClose(config_font_menutitle);
 -    RrFontClose(config_font_osd);
 +    RrFontClose(config_font_activeosd);
 +    RrFontClose(config_font_inactiveosd);
  
      for (it = config_desktops_names; it; it = g_slist_next(it))
          g_free(it->data);
diff --combined openbox/config.h
index d6295f527c2bddc88b60dab5274ef08584786c43,7713936897d827c1c6393b898fdccf933dc06167..89c4c6f6807ab79ac0423b2a17dce49bcf35ff47
  #include "client.h"
  #include "geom.h"
  #include "moveresize.h"
 -#include "render/render.h"
 +#include "obrender/render.h"
 +#include "obt/xml.h"
  
  #include <glib.h>
  
 -struct _ObParseInst;
 -
  typedef struct _ObAppSettings ObAppSettings;
  
  struct _ObAppSettings
@@@ -73,9 -74,6 +73,9 @@@ extern gboolean config_focus_last
  /*! Try keep focus on the window under the mouse when the mouse is not moving
   */
  extern gboolean config_focus_under_mouse;
 +/*! Remove focus from windows when the mouse leaves them
 + */
 +extern gboolean config_unfocus_leave;
  
  /*! The algorithm to use for placing new windows */
  extern ObPlacePolicy config_place_policy;
@@@ -141,8 -139,6 +141,8 @@@ extern gboolean config_theme_keepborder
  extern gchar *config_title_layout;
  /*! Animate windows iconifying and restoring */
  extern gboolean config_animate_iconify;
 +/*! Size of icons in focus switching dialogs */
 +extern guint config_theme_window_list_icon_size;
  
  /*! The font for the active window's title */
  extern RrFont *config_font_activewindow;
@@@ -152,10 -148,8 +152,10 @@@ extern RrFont *config_font_inactivewind
  extern RrFont *config_font_menutitle;
  /*! The font for menu items */
  extern RrFont *config_font_menuitem;
 -/*! The font for on-screen-displays/popups */
 -extern RrFont *config_font_osd;
 +/*! The font for on-screen-displays/popups' active text */
 +extern RrFont *config_font_activeosd;
 +/*! The font for on-screen-displays/popups' inactive text */
 +extern RrFont *config_font_inactiveosd;
  
  /*! The number of desktops */
  extern guint config_desktops_num;
@@@ -191,6 -185,8 +191,8 @@@ extern guint    config_menu_hide_delay
  extern gboolean config_menu_middle;
  /*! Delay before opening a submenu in milliseconds */
  extern guint    config_submenu_show_delay;
+ /*! Delay before closing a submenu in milliseconds */
+ extern guint    config_submenu_hide_delay;
  /*! Show icons in client_list_menu */
  extern gboolean config_menu_client_list_icons;
  /*! Show manage desktops in client_list_menu */
@@@ -200,11 -196,11 +202,11 @@@ extern GSList *config_menu_files
  /*! Per app settings */
  extern GSList *config_per_app_settings;
  
 -void config_startup(struct _ObParseInst *i);
 -void config_shutdown();
 +void config_startup(ObtXmlInst *i);
 +void config_shutdown(void);
  
  /*! Create an ObAppSettings structure with the default values */
 -ObAppSettings* config_create_app_settings();
 +ObAppSettings* config_create_app_settings(void);
  /*! Copies any settings in src to dest, if they are their default value in
    src. */
  void config_app_settings_copy_non_defaults(const ObAppSettings *src,
diff --combined openbox/event.c
index 2f853fbbc40d8a0a52e8d9a775a132e8a2ba3b9e,ad9dade6941aa254fe2c80f7e2facb77b916271b..5127c28f972740c890ff6cfde2506b7e1648b11a
@@@ -24,6 -24,8 +24,6 @@@
  #include "dock.h"
  #include "actions.h"
  #include "client.h"
 -#include "xerror.h"
 -#include "prop.h"
  #include "config.h"
  #include "screen.h"
  #include "frame.h"
  #include "prompt.h"
  #include "menuframe.h"
  #include "keyboard.h"
 -#include "modkeys.h"
  #include "mouse.h"
 -#include "mainloop.h"
  #include "focus.h"
  #include "focus_cycle.h"
  #include "moveresize.h"
  #include "group.h"
  #include "stacking.h"
 -#include "extensions.h"
 -#include "translate.h"
  #include "ping.h"
 +#include "obt/display.h"
 +#include "obt/prop.h"
 +#include "obt/keyboard.h"
  
  #include <X11/Xlib.h>
  #include <X11/Xatom.h>
@@@ -84,8 -87,8 +84,8 @@@ typedef struc
  
  static void event_process(const XEvent *e, gpointer data);
  static void event_handle_root(XEvent *e);
 -static gboolean event_handle_menu_keyboard(XEvent *e);
 -static gboolean event_handle_menu(XEvent *e);
 +static gboolean event_handle_menu_input(XEvent *e);
 +static void event_handle_menu(ObMenuFrame *frame, XEvent *e);
  static gboolean event_handle_prompt(ObPrompt *p, XEvent *e);
  static void event_handle_dock(ObDock *s, XEvent *e);
  static void event_handle_dockapp(ObDockApp *app, XEvent *e);
@@@ -97,7 -100,6 +97,7 @@@ static void event_ignore_enter_range(gu
  static void focus_delay_dest(gpointer data);
  static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
  static gboolean focus_delay_func(gpointer data);
 +static gboolean unfocus_delay_func(gpointer data);
  static void focus_delay_client_dest(ObClient *client, gpointer data);
  
  Time event_curtime = CurrentTime;
@@@ -123,9 -125,9 +123,9 @@@ static void ice_watch(IceConn conn, Ice
  
      if (opening) {
          fd = IceConnectionNumber(conn);
 -        ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
 +        obt_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
      } else {
 -        ob_main_loop_fd_remove(ob_main_loop, fd);
 +        obt_main_loop_fd_remove(ob_main_loop, fd);
          fd = -1;
      }
  }
@@@ -135,7 -137,7 +135,7 @@@ void event_startup(gboolean reconfig
  {
      if (reconfig) return;
  
 -    ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
 +    obt_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
  
  #ifdef USE_SM
      IceAddConnectionWatch(ice_watch, NULL);
@@@ -162,15 -164,9 +162,15 @@@ static Window event_get_window(XEvent *
      /* pick a window */
      switch (e->type) {
      case SelectionClear:
 -        window = RootWindow(ob_display, ob_screen);
 +        window = obt_root(ob_screen);
 +        break;
 +    case CreateNotify:
 +        window = e->xcreatewindow.window;
          break;
      case MapRequest:
 +        window = e->xmaprequest.window;
 +        break;
 +    case MapNotify:
          window = e->xmap.window;
          break;
      case UnmapNotify:
          break;
      default:
  #ifdef XKB
 -        if (extensions_xkb && e->type == extensions_xkb_event_basep) {
 +        if (obt_display_extension_xkb &&
 +            e->type == obt_display_extension_xkb_basep)
 +        {
              switch (((XkbAnyEvent*)e)->xkb_type) {
              case XkbBellNotify:
                  window = ((XkbBellNotifyEvent*)e)->window;
          } else
  #endif
  #ifdef SYNC
 -        if (extensions_sync &&
 -            e->type == extensions_sync_event_basep + XSyncAlarmNotify)
 +        if (obt_display_extension_sync &&
 +            e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
          {
              window = None;
          } else
@@@ -238,8 -232,8 +238,8 @@@ static void event_set_curtime(XEvent *e
          break;
      default:
  #ifdef SYNC
 -        if (extensions_sync &&
 -            e->type == extensions_sync_event_basep + XSyncAlarmNotify)
 +        if (obt_display_extension_sync &&
 +            e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
          {
              t = ((XSyncAlarmNotifyEvent*)e)->time;
          }
@@@ -267,34 -261,34 +267,34 @@@ static void event_hack_mods(XEvent *e
      switch (e->type) {
      case ButtonPress:
      case ButtonRelease:
 -        e->xbutton.state = modkeys_only_modifier_masks(e->xbutton.state);
 +        e->xbutton.state = obt_keyboard_only_modmasks(e->xbutton.state);
          break;
      case KeyPress:
 -        e->xkey.state = modkeys_only_modifier_masks(e->xkey.state);
 +        e->xkey.state = obt_keyboard_only_modmasks(e->xkey.state);
          break;
      case KeyRelease:
  #ifdef XKB
          /* If XKB is present, then the modifiers are all strange from its
             magic.  Our X core protocol stuff won't work, so we use this to
             find what the modifier state is instead. */
 -        if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success)
 +        if (XkbGetState(obt_display, XkbUseCoreKbd, &xkb_state) == Success)
              e->xkey.state =
 -                modkeys_only_modifier_masks(xkb_state.compat_state);
 +                obt_keyboard_only_modmasks(xkb_state.compat_state);
          else
  #endif
          {
 -            e->xkey.state = modkeys_only_modifier_masks(e->xkey.state);
 +            e->xkey.state = obt_keyboard_only_modmasks(e->xkey.state);
              /* remove from the state the mask of the modifier key being
                 released, if it is a modifier key being released that is */
 -            e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode);
 +            e->xkey.state &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
          }
          break;
      case MotionNotify:
 -        e->xmotion.state = modkeys_only_modifier_masks(e->xmotion.state);
 +        e->xmotion.state = obt_keyboard_only_modmasks(e->xmotion.state);
          /* compress events */
          {
              XEvent ce;
 -            while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
 +            while (XCheckTypedWindowEvent(obt_display, e->xmotion.window,
                                            e->type, &ce)) {
                  e->xmotion.x = ce.xmotion.x;
                  e->xmotion.y = ce.xmotion.y;
@@@ -324,7 -318,7 +324,7 @@@ static gboolean wanted_focusevent(XEven
  
          /* These are the ones we want.. */
  
 -        if (win == RootWindow(ob_display, ob_screen)) {
 +        if (win == obt_root(ob_screen)) {
              /* If looking for a focus in on a client, then always return
                 FALSE for focus in's to the root window */
              if (in_client_only)
             but has disappeared.
          */
          if (in_client_only) {
 -            ObWindow *w = g_hash_table_lookup(window_map, &e->xfocus.window);
 +            ObWindow *w = window_find(e->xfocus.window);
              if (!w || !WINDOW_IS_CLIENT(w))
                  return FALSE;
          }
              return FALSE;
  
          /* Focus left the root window revertedto state */
 -        if (win == RootWindow(ob_display, ob_screen))
 +        if (win == obt_root(ob_screen))
              return FALSE;
  
          /* These are the ones we want.. */
@@@ -417,7 -411,6 +417,7 @@@ static void print_focusevent(XEvent *e
      case NotifyGrab:         modestr="NotifyGrab";         break;
      case NotifyUngrab:       modestr="NotifyUngrab";       break;
      case NotifyWhileGrabbed: modestr="NotifyWhileGrabbed"; break;
 +    default:                 g_assert_not_reached();
      }
      switch (detail) {
      case NotifyAncestor:    detailstr="NotifyAncestor";    break;
      case NotifyPointer:     detailstr="NotifyPointer";     break;
      case NotifyPointerRoot: detailstr="NotifyPointerRoot"; break;
      case NotifyDetailNone:  detailstr="NotifyDetailNone";  break;
 +    default:                g_assert_not_reached();
      }
  
      if (mode == NotifyGrab || mode == NotifyUngrab)
  
      g_assert(modestr);
      g_assert(detailstr);
 -    ob_debug_type(OB_DEBUG_FOCUS, "Focus%s 0x%x mode=%s detail=%s\n",
 +    ob_debug_type(OB_DEBUG_FOCUS, "Focus%s 0x%x mode=%s detail=%s",
                    (e->xfocus.type == FocusIn ? "In" : "Out"),
                    win,
                    modestr, detailstr);
@@@ -462,15 -454,13 +462,15 @@@ static gboolean event_ignore(XEvent *e
  
  static void event_process(const XEvent *ec, gpointer data)
  {
 +    XEvent ee, *e;
 +    ObEventData *ed = data;
 +
      Window window;
      ObClient *client = NULL;
      ObDock *dock = NULL;
      ObDockApp *dockapp = NULL;
      ObWindow *obwin = NULL;
 -    XEvent ee, *e;
 -    ObEventData *ed = data;
 +    ObMenuFrame *menu = NULL;
      ObPrompt *prompt = NULL;
  
      /* make a copy we can mangle */
      e = &ee;
  
      window = event_get_window(e);
 -    if ((obwin = g_hash_table_lookup(window_map, &window))) {
 +    if (window == obt_root(ob_screen))
 +        /* don't do any lookups, waste of cpu */;
 +    else if ((obwin = window_find(window))) {
          switch (obwin->type) {
 -        case Window_Dock:
 +        case OB_WINDOW_CLASS_DOCK:
              dock = WINDOW_AS_DOCK(obwin);
              break;
 -        case Window_DockApp:
 -            dockapp = WINDOW_AS_DOCKAPP(obwin);
 -            break;
 -        case Window_Client:
 +        case OB_WINDOW_CLASS_CLIENT:
              client = WINDOW_AS_CLIENT(obwin);
              /* events on clients can be events on prompt windows too */
              prompt = client->prompt;
              break;
 -        case Window_Menu:
 -            /* not to be used for events */
 -            g_assert_not_reached();
 +        case OB_WINDOW_CLASS_MENUFRAME:
 +            menu = WINDOW_AS_MENUFRAME(obwin);
              break;
 -        case Window_Internal:
 +        case OB_WINDOW_CLASS_INTERNAL:
              /* we don't do anything with events directly on these windows */
              break;
 -        case Window_Prompt:
 +        case OB_WINDOW_CLASS_PROMPT:
              prompt = WINDOW_AS_PROMPT(obwin);
              break;
          }
      }
 +    else
 +        dockapp = dock_find_dockapp(window);
  
      event_set_curtime(e);
      event_curserial = e->xany.serial;
  
      /* deal with it in the kernel */
  
 -    if (menu_frame_visible &&
 -        (e->type == EnterNotify || e->type == LeaveNotify))
 -    {
 -        /* crossing events for menu */
 -        event_handle_menu(e);
 -    } else if (e->type == FocusIn) {
 +    if (e->type == FocusIn) {
          if (client &&
              e->xfocus.detail == NotifyInferior)
          {
              XEvent ce;
  
              ob_debug_type(OB_DEBUG_FOCUS,
 -                          "Focus went to root or pointer root/none\n");
 +                          "Focus went to root or pointer root/none");
  
              if (e->xfocus.detail == NotifyInferior ||
                  e->xfocus.detail == NotifyNonlinear)
                 But if the other focus in is something like PointerRoot then we
                 still want to fall back.
              */
 -            if (XCheckIfEvent(ob_display, &ce, event_look_for_focusin_client,
 +            if (XCheckIfEvent(obt_display, &ce, event_look_for_focusin_client,
                                NULL))
              {
 -                XPutBackEvent(ob_display, &ce);
 +                XPutBackEvent(obt_display, &ce);
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "  but another FocusIn is coming\n");
 +                              "  but another FocusIn is coming");
              } else {
                  /* Focus has been reverted.
  
          else if (!client)
          {
              ob_debug_type(OB_DEBUG_FOCUS,
 -                          "Focus went to a window that is already gone\n");
 +                          "Focus went to a window that is already gone");
  
              /* If you send focus to a window and then it disappears, you can
                 get the FocusIn for it, after it is unmanaged.
          XEvent ce;
  
          /* Look for the followup FocusIn */
 -        if (!XCheckIfEvent(ob_display, &ce, event_look_for_focusin, NULL)) {
 +        if (!XCheckIfEvent(obt_display, &ce, event_look_for_focusin, NULL)) {
              /* There is no FocusIn, this means focus went to a window that
                 is not being managed, or a window on another screen. */
              Window win, root;
              gint i;
              guint u;
 -            xerror_set_ignore(TRUE);
 -            if (XGetInputFocus(ob_display, &win, &i) != 0 &&
 -                XGetGeometry(ob_display, win, &root, &i,&i,&u,&u,&u,&u) != 0 &&
 -                root != RootWindow(ob_display, ob_screen))
 +            obt_display_ignore_errors(TRUE);
 +            if (XGetInputFocus(obt_display, &win, &i) &&
 +                XGetGeometry(obt_display, win, &root, &i,&i,&u,&u,&u,&u) &&
 +                root != obt_root(ob_screen))
              {
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to another screen !\n");
 +                              "Focus went to another screen !");
                  focus_left_screen = TRUE;
              }
              else
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to a black hole !\n");
 -            xerror_set_ignore(FALSE);
 +                              "Focus went to a black hole !");
 +            obt_display_ignore_errors(FALSE);
              /* nothing is focused */
              focus_set_client(NULL);
          } else {
                  /* The FocusIn was ignored, this means it was on a window
                     that isn't a client. */
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to an unmanaged window 0x%x !\n",
 +                              "Focus went to an unmanaged window 0x%x !",
                                ce.xfocus.window);
                  focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE);
              }
          event_handle_dockapp(dockapp, e);
      else if (dock)
          event_handle_dock(dock, e);
 -    else if (window == RootWindow(ob_display, ob_screen))
 +    else if (menu)
 +        event_handle_menu(menu, e);
 +    else if (window == obt_root(ob_screen))
          event_handle_root(e);
      else if (e->type == MapRequest)
 -        client_manage(window, NULL);
 +        window_manage(window);
      else if (e->type == MappingNotify) {
          /* keyboard layout changes for modifier mapping changes. reload the
             modifier map, and rebind all the key bindings as appropriate */
 -        ob_debug("Keyboard map changed. Reloading keyboard bindings.\n");
 +        ob_debug("Keyboard map changed. Reloading keyboard bindings.");
          ob_set_state(OB_STATE_RECONFIGURING);
 -        modkeys_shutdown(TRUE);
 -        modkeys_startup(TRUE);
 +        obt_keyboard_reload();
          keyboard_rebind();
          ob_set_state(OB_STATE_RUNNING);
      }
      else if (e->type == ClientMessage) {
          /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
             windows that are not managed yet. */
 -        if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
 +        if (e->xclient.message_type ==
 +            OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS))
 +        {
              /* Pretend to manage the client, getting information used to
                 determine its decorations */
              ObClient *c = client_fake_manage(e->xclient.window);
              vals[1] = c->frame->size.right;
              vals[2] = c->frame->size.top;
              vals[3] = c->frame->size.bottom;
 -            PROP_SETA32(e->xclient.window, net_frame_extents,
 -                        cardinal, vals, 4);
 +            OBT_PROP_SETA32(e->xclient.window, NET_FRAME_EXTENTS,
 +                            CARDINAL, vals, 4);
  
              /* Free the pretend client */
              client_fake_unmanage(c);
  
          /* we are not to be held responsible if someone sends us an
             invalid request! */
 -        xerror_set_ignore(TRUE);
 -        XConfigureWindow(ob_display, window,
 +        obt_display_ignore_errors(TRUE);
 +        XConfigureWindow(obt_display, window,
                           e->xconfigurerequest.value_mask, &xwc);
 -        xerror_set_ignore(FALSE);
 +        obt_display_ignore_errors(FALSE);
      }
  #ifdef SYNC
 -    else if (extensions_sync &&
 -        e->type == extensions_sync_event_basep + XSyncAlarmNotify)
 +    else if (obt_display_extension_sync &&
 +             e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
      {
          XSyncAlarmNotifyEvent *se = (XSyncAlarmNotifyEvent*)e;
          if (se->alarm == moveresize_alarm && moveresize_in_progress)
      else if (e->type == ButtonPress || e->type == ButtonRelease) {
          /* If the button press was on some non-root window, or was physically
             on the root window, then process it */
 -        if (window != RootWindow(ob_display, ob_screen) ||
 +        if (window != obt_root(ob_screen) ||
              e->xbutton.subwindow == None)
          {
              event_handle_user_input(client, e);
          else {
              ObWindow *w;
  
 -            if ((w = g_hash_table_lookup(window_map, &e->xbutton.subwindow)) &&
 +            if ((w = window_find(e->xbutton.subwindow)) &&
                  WINDOW_IS_INTERNAL(w))
              {
                  event_handle_user_input(client, e);
@@@ -755,7 -747,7 +755,7 @@@ static void event_handle_root(XEvent *e
  
      switch(e->type) {
      case SelectionClear:
 -        ob_debug("Another WM has requested to replace us. Exiting.\n");
 +        ob_debug("Another WM has requested to replace us. Exiting.");
          ob_exit_replace();
          break;
  
          if (e->xclient.format != 32) break;
  
          msgtype = e->xclient.message_type;
 -        if (msgtype == prop_atoms.net_current_desktop) {
 +        if (msgtype == OBT_PROP_ATOM(NET_CURRENT_DESKTOP)) {
              guint d = e->xclient.data.l[0];
              if (d < screen_num_desktops) {
                  event_curtime = e->xclient.data.l[1];
                  if (event_curtime == 0)
                      ob_debug_type(OB_DEBUG_APP_BUGS,
                                    "_NET_CURRENT_DESKTOP message is missing "
 -                                  "a timestamp\n");
 +                                  "a timestamp");
                  screen_set_desktop(d, TRUE);
              }
 -        } else if (msgtype == prop_atoms.net_number_of_desktops) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS)) {
              guint d = e->xclient.data.l[0];
              if (d > 0 && d <= 1000)
                  screen_set_num_desktops(d);
 -        } else if (msgtype == prop_atoms.net_showing_desktop) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_SHOWING_DESKTOP)) {
              screen_show_desktop(e->xclient.data.l[0] != 0, NULL);
 -        } else if (msgtype == prop_atoms.ob_control) {
 -            ob_debug("OB_CONTROL: %d\n", e->xclient.data.l[0]);
 +        } else if (msgtype == OBT_PROP_ATOM(OB_CONTROL)) {
 +            ob_debug("OB_CONTROL: %d", e->xclient.data.l[0]);
              if (e->xclient.data.l[0] == 1)
                  ob_reconfigure();
              else if (e->xclient.data.l[0] == 2)
                  ob_restart();
              else if (e->xclient.data.l[0] == 3)
                  ob_exit(0);
 -        } else if (msgtype == prop_atoms.wm_protocols) {
 -            if ((Atom)e->xclient.data.l[0] == prop_atoms.net_wm_ping)
 +        } else if (msgtype == OBT_PROP_ATOM(WM_PROTOCOLS)) {
 +            if ((Atom)e->xclient.data.l[0] == OBT_PROP_ATOM(NET_WM_PING))
                  ping_got_pong(e->xclient.data.l[1]);
          }
          break;
      case PropertyNotify:
 -        if (e->xproperty.atom == prop_atoms.net_desktop_names) {
 -            ob_debug("UPDATE DESKTOP NAMES\n");
 +        if (e->xproperty.atom == OBT_PROP_ATOM(NET_DESKTOP_NAMES)) {
 +            ob_debug("UPDATE DESKTOP NAMES");
              screen_update_desktop_names();
          }
 -        else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
 +        else if (e->xproperty.atom == OBT_PROP_ATOM(NET_DESKTOP_LAYOUT))
              screen_update_layout();
          break;
      case ConfigureNotify:
@@@ -825,17 -817,17 +825,17 @@@ void event_enter_client(ObClient *clien
          if (config_focus_delay) {
              ObFocusDelayData *data;
  
 -            ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
 +            obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
  
              data = g_new(ObFocusDelayData, 1);
              data->client = client;
              data->time = event_curtime;
              data->serial = event_curserial;
  
 -            ob_main_loop_timeout_add(ob_main_loop,
 -                                     config_focus_delay * 1000,
 -                                     focus_delay_func,
 -                                     data, focus_delay_cmp, focus_delay_dest);
 +            obt_main_loop_timeout_add(ob_main_loop,
 +                                      config_focus_delay * 1000,
 +                                      focus_delay_func,
 +                                      data, focus_delay_cmp, focus_delay_dest);
          } else {
              ObFocusDelayData data;
              data.client = client;
      }
  }
  
 +void event_leave_client(ObClient *client)
 +{
 +    g_assert(config_focus_follow);
 +
 +    if (is_enter_focus_event_ignored(event_curserial)) {
 +        ob_debug_type(OB_DEBUG_FOCUS, "Ignoring leave event with serial %lu\n"
 +                      "on client 0x%x", event_curserial, client->window);
 +        return;
 +    }
 +
 +    if (client == focus_client) {
 +        if (config_focus_delay) {
 +            ObFocusDelayData *data;
 +
 +            obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
 +
 +            data = g_new(ObFocusDelayData, 1);
 +            data->client = client;
 +            data->time = event_curtime;
 +            data->serial = event_curserial;
 +
 +            obt_main_loop_timeout_add(ob_main_loop,
 +                                      config_focus_delay * 1000,
 +                                      unfocus_delay_func,
 +                                      data, focus_delay_cmp, focus_delay_dest);
 +        } else {
 +            ObFocusDelayData data;
 +            data.client = client;
 +            data.time = event_curtime;
 +            data.serial = event_curserial;
 +            unfocus_delay_func(&data);
 +        }
 +    }
 +}
 +
  static gboolean *context_to_button(ObFrame *f, ObFrameContext con, gboolean press)
  {
      if (press) {
@@@ -920,12 -877,12 +920,12 @@@ static void compress_client_message_eve
                                            Atom msgtype)
  {
      /* compress changes into a single change */
 -    while (XCheckTypedWindowEvent(ob_display, window, e->type, ce)) {
 +    while (XCheckTypedWindowEvent(obt_display, window, e->type, ce)) {
          /* XXX: it would be nice to compress ALL messages of a
             type, not just messages in a row without other
             message types between. */
          if (ce->xclient.message_type != msgtype) {
 -            XPutBackEvent(ob_display, ce);
 +            XPutBackEvent(obt_display, ce);
              break;
          }
          e->xclient = ce->xclient;
@@@ -1044,24 -1001,21 +1044,24 @@@ static void event_handle_client(ObClien
                  event_end_ignore_all_enters(event_start_ignore_all_enters());
  
              ob_debug_type(OB_DEBUG_FOCUS,
 -                          "%sNotify mode %d detail %d on %lx\n",
 +                          "%sNotify mode %d detail %d on %lx",
                            (e->type == EnterNotify ? "Enter" : "Leave"),
                            e->xcrossing.mode,
                            e->xcrossing.detail, (client?client->window:0));
              if (grab_on_keyboard())
                  break;
 -            if (config_focus_follow && config_focus_delay &&
 +            if (config_focus_follow &&
                  /* leave inferior events can happen when the mouse goes onto
                     the window's border and then into the window before the
                     delay is up */
                  e->xcrossing.detail != NotifyInferior)
              {
 -                ob_main_loop_timeout_remove_data(ob_main_loop,
 -                                                 focus_delay_func,
 -                                                 client, FALSE);
 +                if (config_focus_delay)
 +                    obt_main_loop_timeout_remove_data(ob_main_loop,
 +                                                      focus_delay_func,
 +                                                      client, FALSE);
 +                if (config_unfocus_leave)
 +                    event_leave_client(client);
              }
              break;
          default:
              {
                  ob_debug_type(OB_DEBUG_FOCUS,
                                "%sNotify mode %d detail %d serial %lu on %lx "
 -                              "IGNORED\n",
 +                              "IGNORED",
                                (e->type == EnterNotify ? "Enter" : "Leave"),
                                e->xcrossing.mode,
                                e->xcrossing.detail,
              else {
                  ob_debug_type(OB_DEBUG_FOCUS,
                                "%sNotify mode %d detail %d serial %lu on %lx, "
 -                              "focusing window\n",
 +                              "focusing window",
                                (e->type == EnterNotify ? "Enter" : "Leave"),
                                e->xcrossing.mode,
                                e->xcrossing.detail,
                                e->xcrossing.serial,
                                (client?client->window:0));
 -                if (config_focus_follow)
 +                if (config_focus_follow) {
 +                    if (config_focus_delay)
 +                        obt_main_loop_timeout_remove_data(ob_main_loop,
 +                                                          unfocus_delay_func,
 +                                                          client, FALSE);
                      event_enter_client(client);
 +                }
              }
              break;
          default:
          RECT_TO_DIMS(client->area, x, y, w, h);
  
          ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d "
 -                 "visible %d\n"
 -                 "                     x %d y %d w %d h %d b %d\n",
 +                 "visible %d",
                   client->title,
 -                 screen_desktop, client->wmstate, client->frame->visible,
 +                 screen_desktop, client->wmstate, client->frame->visible);
 +        ob_debug("                     x %d y %d w %d h %d b %d",
                   x, y, w, h, client->border_width);
  
          if (e->xconfigurerequest.value_mask & CWBorderWidth)
              /* get the sibling */
              if (e->xconfigurerequest.value_mask & CWSibling) {
                  ObWindow *win;
 -                win = g_hash_table_lookup(window_map,
 -                                          &e->xconfigurerequest.above);
 +                win = window_find(e->xconfigurerequest.above);
                  if (win && WINDOW_IS_CLIENT(win) &&
                      WINDOW_AS_CLIENT(win) != client)
                  {
          }
  
          ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d "
 -                 "move %d resize %d\n",
 +                 "move %d resize %d",
                   e->xconfigurerequest.value_mask & CWX, x,
                   e->xconfigurerequest.value_mask & CWY, y,
                   e->xconfigurerequest.value_mask & CWWidth, w,
              ob_debug_type(OB_DEBUG_APP_BUGS,
                            "Application %s is trying to move via "
                            "ConfigureRequest to it's root window position "
 -                          "but it is not using StaticGravity\n",
 +                          "but it is not using StaticGravity",
                            client->title);
              /* don't move it */
              x = client->area.x;
  
              client_find_onscreen(client, &x, &y, w, h, FALSE);
  
 -            ob_debug("Granting ConfigureRequest x %d y %d w %d h %d\n",
 +            ob_debug("Granting ConfigureRequest x %d y %d w %d h %d",
                       x, y, w, h);
              client_configure(client, x, y, w, h, FALSE, TRUE, TRUE);
          }
          break;
      }
      case UnmapNotify:
 +        ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d "
 +                 "ignores left %d",
 +                 client->window, e->xunmap.event, e->xunmap.from_configure,
 +                 client->ignore_unmaps);
          if (client->ignore_unmaps) {
              client->ignore_unmaps--;
              break;
          }
 -        ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d "
 -                 "ignores left %d\n",
 -                 client->window, e->xunmap.event, e->xunmap.from_configure,
 -                 client->ignore_unmaps);
          client_unmanage(client);
          break;
      case DestroyNotify:
 -        ob_debug("DestroyNotify for window 0x%x\n", client->window);
 +        ob_debug("DestroyNotify for window 0x%x", client->window);
          client_unmanage(client);
          break;
      case ReparentNotify:
  
          /* we don't want the reparent event, put it back on the stack for the
             X server to deal with after we unmanage the window */
 -        XPutBackEvent(ob_display, e);
 +        XPutBackEvent(obt_display, e);
  
 -        ob_debug("ReparentNotify for window 0x%x\n", client->window);
 +        ob_debug("ReparentNotify for window 0x%x", client->window);
          client_unmanage(client);
          break;
      case MapRequest:
 -        ob_debug("MapRequest for 0x%lx\n", client->window);
 +        ob_debug("MapRequest for 0x%lx", client->window);
          if (!client->iconic) break; /* this normally doesn't happen, but if it
                                         does, we don't want it!
                                         it can happen now when the window is on
          if (e->xclient.format != 32) return;
  
          msgtype = e->xclient.message_type;
 -        if (msgtype == prop_atoms.wm_change_state) {
 +        if (msgtype == OBT_PROP_ATOM(WM_CHANGE_STATE)) {
              compress_client_message_event(e, &ce, client->window, msgtype);
              client_set_wm_state(client, e->xclient.data.l[0]);
 -        } else if (msgtype == prop_atoms.net_wm_desktop) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_WM_DESKTOP)) {
              compress_client_message_event(e, &ce, client->window, msgtype);
              if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
                  (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
                  client_set_desktop(client, (unsigned)e->xclient.data.l[0],
                                     FALSE, FALSE);
 -        } else if (msgtype == prop_atoms.net_wm_state) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_WM_STATE)) {
              gulong ignore_start;
  
              /* can't compress these */
 -            ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
 +            ob_debug("net_wm_state %s %ld %ld for 0x%lx",
                       (e->xclient.data.l[0] == 0 ? "Remove" :
                        e->xclient.data.l[0] == 1 ? "Add" :
                        e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
                               e->xclient.data.l[1], e->xclient.data.l[2]);
              if (!config_focus_under_mouse)
                  event_end_ignore_all_enters(ignore_start);
 -        } else if (msgtype == prop_atoms.net_close_window) {
 -            ob_debug("net_close_window for 0x%lx\n", client->window);
 +        } else if (msgtype == OBT_PROP_ATOM(NET_CLOSE_WINDOW)) {
 +            ob_debug("net_close_window for 0x%lx", client->window);
              client_close(client);
 -        } else if (msgtype == prop_atoms.net_active_window) {
 -            ob_debug("net_active_window for 0x%lx source=%s\n",
 +        } else if (msgtype == OBT_PROP_ATOM(NET_ACTIVE_WINDOW)) {
 +            ob_debug("net_active_window for 0x%lx source=%s",
                       client->window,
                       (e->xclient.data.l[0] == 0 ? "unknown" :
                        (e->xclient.data.l[0] == 1 ? "application" :
                  if (e->xclient.data.l[1] == 0)
                      ob_debug_type(OB_DEBUG_APP_BUGS,
                                    "_NET_ACTIVE_WINDOW message for window %s is"
 -                                  " missing a timestamp\n", client->title);
 +                                  " missing a timestamp", client->title);
              } else
                  ob_debug_type(OB_DEBUG_APP_BUGS,
                                "_NET_ACTIVE_WINDOW message for window %s is "
 -                              "missing source indication\n", client->title);
 +                              "missing source indication", client->title);
              client_activate(client, FALSE, FALSE, TRUE, TRUE,
                              (e->xclient.data.l[0] == 0 ||
                               e->xclient.data.l[0] == 2));
 -        } else if (msgtype == prop_atoms.net_wm_moveresize) {
 -            ob_debug("net_wm_moveresize for 0x%lx direction %d\n",
 +        } else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) {
 +            ob_debug("net_wm_moveresize for 0x%lx direction %d",
                       client->window, e->xclient.data.l[2]);
              if ((Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_topleft ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_top ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOP) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_topright ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPRIGHT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_right ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_right ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_RIGHT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_bottomright ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_bottom ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOM) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_bottomleft ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_left ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_LEFT) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_move ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_size_keyboard ||
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD) ||
                  (Atom)e->xclient.data.l[2] ==
 -                prop_atoms.net_wm_moveresize_move_keyboard) {
 -
 +                OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
 +            {
                  moveresize_start(client, e->xclient.data.l[0],
                                   e->xclient.data.l[1], e->xclient.data.l[3],
                                   e->xclient.data.l[2]);
              }
              else if ((Atom)e->xclient.data.l[2] ==
 -                     prop_atoms.net_wm_moveresize_cancel)
 +                     OBT_PROP_ATOM(NET_WM_MOVERESIZE_CANCEL))
                  moveresize_end(TRUE);
 -        } else if (msgtype == prop_atoms.net_moveresize_window) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW)) {
              gint ograv, x, y, w, h;
  
              ograv = client->gravity;
              else
                  h = client->area.height;
  
 -            ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)\n",
 +            ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)",
                       e->xclient.data.l[0] & 1 << 8, x,
                       e->xclient.data.l[0] & 1 << 9, y,
                       client->gravity);
              client_configure(client, x, y, w, h, FALSE, TRUE, FALSE);
  
              client->gravity = ograv;
 -        } else if (msgtype == prop_atoms.net_restack_window) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_RESTACK_WINDOW)) {
              if (e->xclient.data.l[0] != 2) {
                  ob_debug_type(OB_DEBUG_APP_BUGS,
                                "_NET_RESTACK_WINDOW sent for window %s with "
 -                              "invalid source indication %ld\n",
 +                              "invalid source indication %ld",
                                client->title, e->xclient.data.l[0]);
              } else {
                  ObClient *sibling = NULL;
                  if (e->xclient.data.l[1]) {
 -                    ObWindow *win = g_hash_table_lookup
 -                        (window_map, &e->xclient.data.l[1]);
 +                    ObWindow *win = window_find(e->xclient.data.l[1]);
                      if (WINDOW_IS_CLIENT(win) &&
                          WINDOW_AS_CLIENT(win) != client)
                      {
                      if (sibling == NULL)
                          ob_debug_type(OB_DEBUG_APP_BUGS,
                                        "_NET_RESTACK_WINDOW sent for window %s "
 -                                      "with invalid sibling 0x%x\n",
 +                                      "with invalid sibling 0x%x",
                                   client->title, e->xclient.data.l[1]);
                  }
                  if (e->xclient.data.l[2] == Below ||
                  } else
                      ob_debug_type(OB_DEBUG_APP_BUGS,
                                    "_NET_RESTACK_WINDOW sent for window %s "
 -                                  "with invalid detail %d\n",
 +                                  "with invalid detail %d",
                                    client->title, e->xclient.data.l[2]);
              }
          }
          if (!client_validate(client)) break;
  
          /* compress changes to a single property into a single change */
 -        while (XCheckTypedWindowEvent(ob_display, client->window,
 +        while (XCheckTypedWindowEvent(obt_display, client->window,
                                        e->type, &ce)) {
              Atom a, b;
  
  
              if (a == b)
                  continue;
 -            if ((a == prop_atoms.net_wm_name ||
 -                 a == prop_atoms.wm_name ||
 -                 a == prop_atoms.net_wm_icon_name ||
 -                 a == prop_atoms.wm_icon_name)
 +            if ((a == OBT_PROP_ATOM(NET_WM_NAME) ||
 +                 a == OBT_PROP_ATOM(WM_NAME) ||
 +                 a == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
 +                 a == OBT_PROP_ATOM(WM_ICON_NAME))
                  &&
 -                (b == prop_atoms.net_wm_name ||
 -                 b == prop_atoms.wm_name ||
 -                 b == prop_atoms.net_wm_icon_name ||
 -                 b == prop_atoms.wm_icon_name)) {
 +                (b == OBT_PROP_ATOM(NET_WM_NAME) ||
 +                 b == OBT_PROP_ATOM(WM_NAME) ||
 +                 b == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
 +                 b == OBT_PROP_ATOM(WM_ICON_NAME))) {
                  continue;
              }
 -            if (a == prop_atoms.net_wm_icon &&
 -                b == prop_atoms.net_wm_icon)
 +            if (a == OBT_PROP_ATOM(NET_WM_ICON) &&
 +                b == OBT_PROP_ATOM(NET_WM_ICON))
                  continue;
  
 -            XPutBackEvent(ob_display, &ce);
 +            XPutBackEvent(obt_display, &ce);
              break;
          }
  
          msgtype = e->xproperty.atom;
          if (msgtype == XA_WM_NORMAL_HINTS) {
 -            ob_debug("Update NORMAL hints\n");
 +            int x, y, w, h, lw, lh;
 +
 +            ob_debug("Update NORMAL hints");
              client_update_normal_hints(client);
              /* normal hints can make a window non-resizable */
              client_setup_decor_and_functions(client, FALSE);
  
 -            /* make sure the client's sizes are within its bounds, but only
 -               reconfigure the window if it needs to. emacs will update its
 -               normal hints every time it receives a conigurenotify */
 -            client_reconfigure(client, FALSE);
 -        } else if (msgtype == prop_atoms.motif_wm_hints) {
 +            x = client->area.x;
 +            y = client->area.y;
 +            w = client->area.width;
 +            h = client->area.height;
 +
 +            /* apply the new normal hints */
 +            client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
 +            /* make sure the window is visible, and if the window is resized
 +               off-screen due to the normal hints changing then this will push
 +               it back onto the screen. */
 +            client_find_onscreen(client, &x, &y, w, h, FALSE);
 +
 +            /* make sure the client's sizes are within its bounds, but don't
 +               make it reply with a configurenotify unless something changed.
 +               emacs will update its normal hints every time it receives a
 +               configurenotify */
 +            client_configure(client, x, y, w, h, FALSE, TRUE, FALSE);
 +        } else if (msgtype == OBT_PROP_ATOM(MOTIF_WM_HINTS)) {
              client_get_mwm_hints(client);
              /* This can override some mwm hints */
              client_get_type_and_transientness(client);
              /* type may have changed, so update the layer */
              client_calc_layer(client);
              client_setup_decor_and_functions(client, TRUE);
 -        } else if (msgtype == prop_atoms.net_wm_name ||
 -                   msgtype == prop_atoms.wm_name ||
 -                   msgtype == prop_atoms.net_wm_icon_name ||
 -                   msgtype == prop_atoms.wm_icon_name) {
 +        } else if (msgtype == OBT_PROP_ATOM(NET_WM_NAME) ||
 +                   msgtype == OBT_PROP_ATOM(WM_NAME) ||
 +                   msgtype == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
 +                   msgtype == OBT_PROP_ATOM(WM_ICON_NAME)) {
              client_update_title(client);
 -        } else if (msgtype == prop_atoms.wm_protocols) {
 +        } else if (msgtype == OBT_PROP_ATOM(WM_PROTOCOLS)) {
              client_update_protocols(client);
              client_setup_decor_and_functions(client, TRUE);
          }
 -        else if (msgtype == prop_atoms.net_wm_strut ||
 -                 msgtype == prop_atoms.net_wm_strut_partial) {
 +        else if (msgtype == OBT_PROP_ATOM(NET_WM_STRUT) ||
 +                 msgtype == OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL)) {
              client_update_strut(client);
          }
 -        else if (msgtype == prop_atoms.net_wm_icon) {
 +        else if (msgtype == OBT_PROP_ATOM(NET_WM_ICON)) {
              client_update_icons(client);
          }
 -        else if (msgtype == prop_atoms.net_wm_icon_geometry) {
 +        else if (msgtype == OBT_PROP_ATOM(NET_WM_ICON_GEOMETRY)) {
              client_update_icon_geometry(client);
          }
 -        else if (msgtype == prop_atoms.net_wm_user_time) {
 +        else if (msgtype == OBT_PROP_ATOM(NET_WM_USER_TIME)) {
              guint32 t;
              if (client == focus_client &&
 -                PROP_GET32(client->window, net_wm_user_time, cardinal, &t) &&
 -                t && !event_time_after(t, e->xproperty.time) &&
 +                OBT_PROP_GET32(client->window, NET_WM_USER_TIME, CARDINAL, &t)
 +                && t && !event_time_after(t, e->xproperty.time) &&
                  (!event_last_user_time ||
                   event_time_after(t, event_last_user_time)))
              {
              }
          }
  #ifdef SYNC
 -        else if (msgtype == prop_atoms.net_wm_sync_request_counter) {
 +        else if (msgtype == OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER)) {
              client_update_sync_request_counter(client);
          }
  #endif
  #ifdef SHAPE
          {
              int kind;
 -            if (extensions_shape && e->type == extensions_shape_event_basep) {
 +            if (obt_display_extension_shape &&
 +                e->type == obt_display_extension_shape_basep)
 +            {
                  switch (((XShapeEvent*)e)->kind) {
                      case ShapeBounding:
                      case ShapeClip:
                          client->shaped_input = ((XShapeEvent*)e)->shaped;
                          kind = ShapeInput;
                          break;
 +                    default:
 +                        g_assert_not_reached();
                  }
                  frame_adjust_shape_kind(client->frame, kind);
              }
@@@ -1691,11 -1623,11 +1691,11 @@@ static void event_handle_dockapp(ObDock
              app->ignore_unmaps--;
              break;
          }
 -        dock_remove(app, TRUE);
 +        dock_unmanage(app, TRUE);
          break;
      case DestroyNotify:
      case ReparentNotify:
 -        dock_remove(app, FALSE);
 +        dock_unmanage(app, FALSE);
          break;
      case ConfigureNotify:
          dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
@@@ -1742,160 -1674,130 +1742,165 @@@ static gboolean event_handle_prompt(ObP
      return FALSE;
  }
  
 -static gboolean event_handle_menu_keyboard(XEvent *ev)
 +static gboolean event_handle_menu_input(XEvent *ev)
  {
 -    guint keycode, state;
 -    gunichar unikey;
 -    ObMenuFrame *frame;
      gboolean ret = FALSE;
  
 -    keycode = ev->xkey.keycode;
 -    state = ev->xkey.state;
 -    unikey = translate_unichar(keycode);
 +    if (ev->type == ButtonRelease || ev->type == ButtonPress) {
 +        ObMenuEntryFrame *e;
  
 -    frame = find_active_or_last_menu();
 -    if (frame == NULL)
 -        g_assert_not_reached(); /* there is no active menu */
 +        if (menu_hide_delay_reached() &&
 +            (ev->xbutton.button < 4 || ev->xbutton.button > 5))
 +        {
 +            if ((e = menu_entry_frame_under(ev->xbutton.x_root,
 +                                            ev->xbutton.y_root)))
 +            {
 +                if (ev->type == ButtonPress && e->frame->child)
 +                    menu_frame_select(e->frame->child, NULL, TRUE);
 +                menu_frame_select(e->frame, e, TRUE);
 +                if (ev->type == ButtonRelease)
 +                    menu_entry_frame_execute(e, ev->xbutton.state);
 +            }
 +            else if (ev->type == ButtonRelease)
 +                menu_frame_hide_all();
 +        }
 +        ret = TRUE;
 +    }
 +    else if (ev->type == MotionNotify) {
 +        ObMenuFrame *f;
 +        ObMenuEntryFrame *e;
  
 -    /* Allow control while going thru the menu */
 -    else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
 -        frame->got_press = TRUE;
 +        if ((e = menu_entry_frame_under(ev->xmotion.x_root,
 +                                        ev->xmotion.y_root)))
 +            if (!(f = find_active_menu()) ||
 +                f == e->frame ||
 +                f->parent == e->frame ||
 +                f->child == e->frame)
 +                menu_frame_select(e->frame, e, FALSE);
 +    }
 +    else if (ev->type == KeyPress || ev->type == KeyRelease) {
 +        guint keycode, state;
 +        gunichar unikey;
 +        ObMenuFrame *frame;
  
 -        if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
 -            menu_frame_hide_all();
 -            ret = TRUE;
 -        }
 +        keycode = ev->xkey.keycode;
 +        state = ev->xkey.state;
 +        unikey = obt_keyboard_keycode_to_unichar(keycode);
 +
 +        frame = find_active_or_last_menu();
 +        if (frame == NULL)
 +            g_assert_not_reached(); /* there is no active menu */
  
 -        else if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
 -            /* Left goes to the parent menu */
 -            if (frame->parent) {
 -                /* remove focus from the child */
 -                menu_frame_select(frame, NULL, TRUE);
 -                /* and put it in the parent */
 -                menu_frame_select(frame->parent, frame->parent->selected,
 -                                  TRUE);
 +        /* Allow control while going thru the menu */
 +        else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
 +            frame->got_press = TRUE;
 +
 +            if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
 +                menu_frame_hide_all();
 +                ret = TRUE;
              }
 -            ret = TRUE;
 -        }
  
 -        else if (ob_keycode_match(keycode, OB_KEY_RIGHT)) {
 -            /* Right goes to the selected submenu */
 -            if (frame->child) menu_frame_select_next(frame->child);
 -            ret = TRUE;
 -        }
 +            else if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
 +                /* Left goes to the parent menu */
-                 if (frame->parent)
++                if (frame->parent) {
++                    /* remove focus from the child */
 +                    menu_frame_select(frame, NULL, TRUE);
++                    /* and put it in the parent */
++                    menu_frame_select(frame->parent, frame->parent->selected,
++                                      TRUE);
++                }
 +                ret = TRUE;
 +            }
  
 -        else if (ob_keycode_match(keycode, OB_KEY_UP)) {
 -            menu_frame_select_previous(frame);
 -            ret = TRUE;
 -        }
 +            else if (ob_keycode_match(keycode, OB_KEY_RIGHT)) {
 +                /* Right goes to the selected submenu */
 +                if (frame->child) menu_frame_select_next(frame->child);
 +                ret = TRUE;
 +            }
 +
 +            else if (ob_keycode_match(keycode, OB_KEY_UP)) {
 +                menu_frame_select_previous(frame);
 +                ret = TRUE;
 +            }
  
 -        else if (ob_keycode_match(keycode, OB_KEY_DOWN)) {
 -            menu_frame_select_next(frame);
 -            ret = TRUE;
 +            else if (ob_keycode_match(keycode, OB_KEY_DOWN)) {
 +                menu_frame_select_next(frame);
 +                ret = TRUE;
 +            }
          }
 -    }
  
 -    /* Use KeyRelease events for running things so that the key release doesn't
 -       get sent to the focused application.
 +        /* Use KeyRelease events for running things so that the key release
 +           doesn't get sent to the focused application.
  
 -       Allow ControlMask only, and don't bother if the menu is empty */
 -    else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 &&
 -             frame->entries && frame->got_press)
 -    {
 -        if (ob_keycode_match(keycode, OB_KEY_RETURN)) {
 -            /* Enter runs the active item or goes into the submenu.
 -               Control-Enter runs it without closing the menu. */
 -            if (frame->child)
 -                menu_frame_select_next(frame->child);
 -            else if (frame->selected)
 -                menu_entry_frame_execute(frame->selected, state);
 -
 -            ret = TRUE;
 -        }
 +           Allow ControlMask only, and don't bother if the menu is empty */
 +        else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 &&
 +                 frame->entries && frame->got_press)
 +        {
 +            if (ob_keycode_match(keycode, OB_KEY_RETURN)) {
 +                /* Enter runs the active item or goes into the submenu.
 +                   Control-Enter runs it without closing the menu. */
 +                if (frame->child)
 +                    menu_frame_select_next(frame->child);
 +                else if (frame->selected)
 +                    menu_entry_frame_execute(frame->selected, state);
  
 -        /* keyboard accelerator shortcuts. (if it was a valid key) */
 -        else if (unikey != 0) {
 -            GList *start;
 -            GList *it;
 -            ObMenuEntryFrame *found = NULL;
 -            guint num_found = 0;
 -
 -            /* start after the selected one */
 -            start = frame->entries;
 -            if (frame->selected) {
 -                for (it = start; frame->selected != it->data;
 -                     it = g_list_next(it))
 -                    g_assert(it != NULL); /* nothing was selected? */
 -                /* next with wraparound */
 -                start = g_list_next(it);
 -                if (start == NULL) start = frame->entries;
 +                ret = TRUE;
              }
  
 -            it = start;
 -            do {
 -                ObMenuEntryFrame *e = it->data;
 -                gunichar entrykey = 0;
 +            /* keyboard accelerator shortcuts. (if it was a valid key) */
 +            else if (unikey != 0) {
 +                GList *start;
 +                GList *it;
 +                ObMenuEntryFrame *found = NULL;
 +                guint num_found = 0;
 +
 +                /* start after the selected one */
 +                start = frame->entries;
 +                if (frame->selected) {
 +                    for (it = start; frame->selected != it->data;
 +                         it = g_list_next(it))
 +                        g_assert(it != NULL); /* nothing was selected? */
 +                    /* next with wraparound */
 +                    start = g_list_next(it);
 +                    if (start == NULL) start = frame->entries;
 +                }
 +
 +                it = start;
 +                do {
 +                    ObMenuEntryFrame *e = it->data;
 +                    gunichar entrykey = 0;
  
 -                if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
 -                    entrykey = e->entry->data.normal.shortcut;
 -                else if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
 -                    entrykey = e->entry->data.submenu.submenu->shortcut;
 +                    if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
 +                        entrykey = e->entry->data.normal.shortcut;
 +                    else if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
 +                        entrykey = e->entry->data.submenu.submenu->shortcut;
  
 -                if (unikey == entrykey) {
 -                    if (found == NULL) found = e;
 -                    ++num_found;
 -                }
 +                    if (unikey == entrykey) {
 +                        if (found == NULL) found = e;
 +                        ++num_found;
 +                    }
  
 -                /* next with wraparound */
 -                it = g_list_next(it);
 -                if (it == NULL) it = frame->entries;
 -            } while (it != start);
 +                    /* next with wraparound */
 +                    it = g_list_next(it);
 +                    if (it == NULL) it = frame->entries;
 +                } while (it != start);
  
 -            if (found) {
 -                if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
 -                    num_found == 1)
 -                {
 -                    menu_frame_select(frame, found, TRUE);
 -                    usleep(50000); /* highlight the item for a short bit so the
 -                                      user can see what happened */
 -                    menu_entry_frame_execute(found, state);
 -                } else {
 -                    menu_frame_select(frame, found, TRUE);
 -                    if (num_found == 1)
 -                        menu_frame_select_next(frame->child);
 -                }
 +                if (found) {
 +                    if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
 +                        num_found == 1)
 +                    {
 +                        menu_frame_select(frame, found, TRUE);
 +                        usleep(50000); /* highlight the item for a short bit so
 +                                          the user can see what happened */
 +                        menu_entry_frame_execute(found, state);
 +                    } else {
 +                        menu_frame_select(frame, found, TRUE);
 +                        if (num_found == 1)
 +                            menu_frame_select_next(frame->child);
 +                    }
  
 -                ret = TRUE;
 +                    ret = TRUE;
 +                }
              }
          }
      }
      return ret;
  }
  
 -static gboolean event_handle_menu(XEvent *ev)
+ static Bool event_look_for_menu_enter(Display *d, XEvent *ev, XPointer arg)
+ {
+     ObMenuFrame *f = (ObMenuFrame*)arg;
+     ObMenuEntryFrame *e;
+     return ev->type == EnterNotify &&
+         (e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
+         !e->ignore_enters && e->frame == f;
+ }
 +static void event_handle_menu(ObMenuFrame *frame, XEvent *ev)
  {
      ObMenuFrame *f;
      ObMenuEntryFrame *e;
 -    gboolean ret = TRUE;
  
      switch (ev->type) {
 -    case ButtonRelease:
 -        if (menu_hide_delay_reached() &&
 -            (ev->xbutton.button < 4 || ev->xbutton.button > 5))
 -        {
 -            if ((e = menu_entry_frame_under(ev->xbutton.x_root,
 -                                            ev->xbutton.y_root)))
 -            {
 -                menu_frame_select(e->frame, e, TRUE);
 -                menu_entry_frame_execute(e, ev->xbutton.state);
 -            }
 -            else
 -                menu_frame_hide_all();
 -        }
 -        break;
      case EnterNotify:
          if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
              if (e->ignore_enters)
          if (ev->xcrossing.detail == NotifyInferior)
              break;
  
-         if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
-             (f = find_active_menu()) && f->selected == e)
+         if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)))
          {
-             ObMenuEntryFrame *u = menu_entry_frame_under(ev->xcrossing.x_root,
-                                                          ev->xcrossing.y_root);
-             /* if we're just going from one entry in the menu to the next,
-                don't unselect stuff first */
-             if (!u || e->frame != u->frame)
+             XEvent ce;
+             /* check if an EnterNotify event is coming, and if not, then select
+                nothing in the menu */
 -            if (XCheckIfEvent(ob_display, &ce, event_look_for_menu_enter,
++            if (XCheckIfEvent(obt_display, &ce, event_look_for_menu_enter,
+                               (XPointer)e->frame))
 -                XPutBackEvent(ob_display, &ce);
++                XPutBackEvent(obt_display, &ce);
+             else
                  menu_frame_select(e->frame, NULL, FALSE);
          }
          break;
 -    case MotionNotify:
 -        if ((e = menu_entry_frame_under(ev->xmotion.x_root,
 -                                        ev->xmotion.y_root)))
 -            if (!(f = find_active_menu()) ||
 -                f == e->frame ||
 -                f->parent == e->frame ||
 -                f->child == e->frame)
 -                menu_frame_select(e->frame, e, FALSE);
 -        break;
 -    case KeyPress:
 -    case KeyRelease:
 -        ret = event_handle_menu_keyboard(ev);
 -        break;
      }
 -    return ret;
  }
  
  static void event_handle_user_input(ObClient *client, XEvent *e)
               e->type == KeyRelease);
  
      if (menu_frame_visible) {
 -        if (event_handle_menu(e))
 +        if (event_handle_menu_input(e))
              /* don't use the event if the menu used it, but if the menu
                 didn't use it and it's a keypress that is bound, it will
                 close the menu and be used */
@@@ -1999,37 -1941,22 +2015,37 @@@ static gboolean focus_delay_func(gpoint
      return FALSE; /* no repeat */
  }
  
 +static gboolean unfocus_delay_func(gpointer data)
 +{
 +    ObFocusDelayData *d = data;
 +    Time old = event_curtime;
 +
 +    event_curtime = d->time;
 +    event_curserial = d->serial;
 +    focus_nothing();
 +    event_curtime = old;
 +    return FALSE; /* no repeat */
 +}
 +
  static void focus_delay_client_dest(ObClient *client, gpointer data)
  {
 -    ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
 -                                     client, FALSE);
 +    obt_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
 +                                      client, FALSE);
 +    obt_main_loop_timeout_remove_data(ob_main_loop, unfocus_delay_func,
 +                                      client, FALSE);
  }
  
  void event_halt_focus_delay(void)
  {
      /* ignore all enter events up till the event which caused this to occur */
      if (event_curserial) event_ignore_enter_range(1, event_curserial);
 -    ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
 +    obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
 +    obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
  }
  
  gulong event_start_ignore_all_enters(void)
  {
 -    return NextRequest(ob_display);
 +    return NextRequest(obt_display);
  }
  
  static void event_ignore_enter_range(gulong start, gulong end)
      r->end = end;
      ignore_serials = g_slist_prepend(ignore_serials, r);
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu\n",
 +    ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu",
                    r->start, r->end);
  
      /* increment the serial so we don't ignore events we weren't meant to */
 -    PROP_ERASE(screen_support_win, motif_wm_hints);
 +    OBT_PROP_ERASE(screen_support_win, MOTIF_WM_HINTS);
  }
  
  void event_end_ignore_all_enters(gulong start)
         movement will be ignored until we create some further network traffic.
         Instead ignore up to NextRequest-1, then when we increment the serial,
         we will be *past* the range of ignored serials */
 -    event_ignore_enter_range(start, NextRequest(ob_display)-1);
 +    event_ignore_enter_range(start, NextRequest(obt_display)-1);
  }
  
  static gboolean is_enter_focus_event_ignored(gulong serial)
@@@ -2086,24 -2013,24 +2102,24 @@@ void event_cancel_all_key_grabs(void
  {
      if (actions_interactive_act_running()) {
          actions_interactive_cancel_act();
 -        ob_debug("KILLED interactive action\n");
 +        ob_debug("KILLED interactive action");
      }
      else if (menu_frame_visible) {
          menu_frame_hide_all();
 -        ob_debug("KILLED open menus\n");
 +        ob_debug("KILLED open menus");
      }
      else if (moveresize_in_progress) {
          moveresize_end(TRUE);
 -        ob_debug("KILLED interactive moveresize\n");
 +        ob_debug("KILLED interactive moveresize");
      }
      else if (grab_on_keyboard()) {
          ungrab_keyboard();
 -        ob_debug("KILLED active grab on keyboard\n");
 +        ob_debug("KILLED active grab on keyboard");
      }
      else
          ungrab_passive_key();
  
 -    XSync(ob_display, FALSE);
 +    XSync(obt_display, FALSE);
  }
  
  gboolean event_time_after(guint32 t1, guint32 t2)
@@@ -2138,9 -2065,9 +2154,9 @@@ Time event_get_server_time(void
      /* Generate a timestamp */
      XEvent event;
  
 -    XChangeProperty(ob_display, screen_support_win,
 -                    prop_atoms.wm_class, prop_atoms.string,
 +    XChangeProperty(obt_display, screen_support_win,
 +                    OBT_PROP_ATOM(WM_CLASS), OBT_PROP_ATOM(STRING),
                      8, PropModeAppend, NULL, 0);
 -    XWindowEvent(ob_display, screen_support_win, PropertyChangeMask, &event);
 +    XWindowEvent(obt_display, screen_support_win, PropertyChangeMask, &event);
      return event.xproperty.time;
  }
diff --combined openbox/focus_cycle.c
index a616db64b2de0c86121c848cf86a5b489453dae4,c92b5a54fe7c148221aaf01204cf857e72ab2e73..a70151fdce236ea31ae0e6798217f93b461bdf09
@@@ -19,6 -19,7 +19,6 @@@
  
  #include "focus_cycle.h"
  #include "focus_cycle_indicator.h"
 -#include "focus_cycle_popup.h"
  #include "client.h"
  #include "frame.h"
  #include "focus.h"
@@@ -54,9 -55,10 +54,10 @@@ void focus_cycle_stop(ObClient *ifclien
  {
      /* stop focus cycling if the given client is a valid focus target,
         and so the cycling is being disrupted */
-     if (focus_cycle_target && ifclient &&
-         (ifclient == focus_cycle_target ||
-          focus_cycle_popup_is_showing(ifclient)))
+     if (focus_cycle_target &&
+         ((ifclient && (ifclient == focus_cycle_target ||
+                        focus_cycle_popup_is_showing(ifclient))) ||
+          !ifclient))
      {
          focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE);
          focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
@@@ -66,7 -68,7 +67,7 @@@
  ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
                        gboolean dock_windows, gboolean desktop_windows,
                        gboolean linear, gboolean interactive,
 -                      gboolean showbar, gboolean dialog,
 +                      gboolean showbar, ObFocusCyclePopupMode mode,
                        gboolean done, gboolean cancel)
  {
      static GList *order = NULL;
                      focus_cycle_target = ft;
                      focus_cycle_draw_indicator(showbar ? ft : NULL);
                  }
 -                if (dialog)
 -                    /* same arguments as focus_target_valid */
 -                    focus_cycle_popup_show(ft,
 -                                           focus_cycle_iconic_windows,
 -                                           focus_cycle_all_desktops,
 -                                           focus_cycle_dock_windows,
 -                                           focus_cycle_desktop_windows);
 +                /* same arguments as focus_target_valid */
 +                focus_cycle_popup_show(ft,
 +                                       focus_cycle_iconic_windows,
 +                                       focus_cycle_all_desktops,
 +                                       focus_cycle_dock_windows,
 +                                       focus_cycle_desktop_windows,
 +                                       mode);
                  return focus_cycle_target;
              } else if (ft != focus_cycle_target) {
                  focus_cycle_target = ft;
diff --combined openbox/menuframe.c
index ee374de5e538e81ec913fce5085625ec8943b2a3,076fe6efc295ff231405ac4c4bb6a7ab6668476d..57f2943886767a15a4a11a2f842faf8431897766
  #include "client.h"
  #include "menu.h"
  #include "screen.h"
 -#include "prop.h"
  #include "actions.h"
  #include "event.h"
  #include "grab.h"
  #include "openbox.h"
 -#include "mainloop.h"
  #include "config.h"
 -#include "render/theme.h"
 +#include "obt/prop.h"
 +#include "obrender/theme.h"
  
  #define PADDING 2
  #define MAX_MENU_WIDTH 400
@@@ -48,14 -49,15 +48,15 @@@ static ObMenuEntryFrame* menu_entry_fra
                                                ObMenuFrame *frame);
  static void menu_entry_frame_free(ObMenuEntryFrame *self);
  static void menu_frame_update(ObMenuFrame *self);
- static gboolean menu_entry_frame_submenu_hide_timeout(gpointer data);
- static gboolean menu_entry_frame_submenu_show_timeout(gpointer data);
+ static gboolean submenu_show_timeout(gpointer data);
  static void menu_frame_hide(ObMenuFrame *self);
  
+ static gboolean submenu_hide_timeout(gpointer data);
  static Window createWindow(Window parent, gulong mask,
                             XSetWindowAttributes *attrib)
  {
 -    return XCreateWindow(ob_display, parent, 0, 0, 1, 1, 0,
 +    return XCreateWindow(obt_display, parent, 0, 0, 1, 1, 0,
                           RrDepth(ob_rr_inst), InputOutput,
                           RrVisual(ob_rr_inst), mask, attrib);
  }
@@@ -92,30 -94,28 +93,29 @@@ ObMenuFrame* menu_frame_new(ObMenu *men
      XSetWindowAttributes attr;
  
      self = g_new0(ObMenuFrame, 1);
 -    self->type = Window_Menu;
 +    self->obwin.type = OB_WINDOW_CLASS_MENUFRAME;
      self->menu = menu;
      self->selected = NULL;
-     self->open_submenu = NULL;
      self->client = client;
      self->direction_right = TRUE;
      self->show_from = show_from;
  
      attr.event_mask = FRAME_EVENTMASK;
 -    self->window = createWindow(RootWindow(ob_display, ob_screen),
 +    self->window = createWindow(obt_root(ob_screen),
                                  CWEventMask, &attr);
  
      /* make it a popup menu type window */
 -    PROP_SET32(self->window, net_wm_window_type, atom,
 -               prop_atoms.net_wm_window_type_popup_menu);
 +    OBT_PROP_SET32(self->window, NET_WM_WINDOW_TYPE, ATOM,
 +                   OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_POPUP_MENU));
  
 -    XSetWindowBorderWidth(ob_display, self->window, ob_rr_theme->mbwidth);
 -    XSetWindowBorder(ob_display, self->window,
 +    XSetWindowBorderWidth(obt_display, self->window, ob_rr_theme->mbwidth);
 +    XSetWindowBorder(obt_display, self->window,
                       RrColorPixel(ob_rr_theme->menu_border_color));
  
      self->a_items = RrAppearanceCopy(ob_rr_theme->a_menu);
  
 -    stacking_add(MENU_AS_WINDOW(self));
 +    window_add(&self->window, MENUFRAME_AS_WINDOW(self));
 +    stacking_add(MENUFRAME_AS_WINDOW(self));
  
      return self;
  }
@@@ -128,12 -128,11 +128,12 @@@ void menu_frame_free(ObMenuFrame *self
              self->entries = g_list_delete_link(self->entries, self->entries);
          }
  
 -        stacking_remove(MENU_AS_WINDOW(self));
 +        stacking_remove(MENUFRAME_AS_WINDOW(self));
 +        window_remove(self->window);
  
          RrAppearanceFree(self->a_items);
  
 -        XDestroyWindow(ob_display, self->window);
 +        XDestroyWindow(obt_display, self->window);
  
          g_free(self);
      }
@@@ -165,10 -164,8 +165,10 @@@ static ObMenuEntryFrame* menu_entry_fra
          g_hash_table_insert(menu_frame_map, &self->bullet, self);
      }
  
 -    XMapWindow(ob_display, self->window);
 -    XMapWindow(ob_display, self->text);
 +    XMapWindow(obt_display, self->window);
 +    XMapWindow(obt_display, self->text);
 +
 +    window_add(&self->window, MENUFRAME_AS_WINDOW(self->frame));
  
      return self;
  }
@@@ -178,18 -175,16 +178,18 @@@ static void menu_entry_frame_free(ObMen
      if (self) {
          menu_entry_unref(self->entry);
  
 -        XDestroyWindow(ob_display, self->text);
 -        XDestroyWindow(ob_display, self->window);
 +        window_remove(self->window);
 +
 +        XDestroyWindow(obt_display, self->text);
 +        XDestroyWindow(obt_display, self->window);
          g_hash_table_remove(menu_frame_map, &self->text);
          g_hash_table_remove(menu_frame_map, &self->window);
          if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) {
 -            XDestroyWindow(ob_display, self->icon);
 +            XDestroyWindow(obt_display, self->icon);
              g_hash_table_remove(menu_frame_map, &self->icon);
          }
          if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
 -            XDestroyWindow(ob_display, self->bullet);
 +            XDestroyWindow(obt_display, self->bullet);
              g_hash_table_remove(menu_frame_map, &self->bullet);
          }
  
@@@ -201,7 -196,7 +201,7 @@@ void menu_frame_move(ObMenuFrame *self
  {
      RECT_SET_POINT(self->area, x, y);
      self->monitor = screen_find_monitor_point(x, y);
 -    XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
 +    XMoveWindow(obt_display, self->window, self->area.x, self->area.y);
  }
  
  static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
@@@ -363,7 -358,7 +363,7 @@@ static void menu_entry_frame_render(ObM
      }
  
      RECT_SET_SIZE(self->area, self->frame->inner_w, th);
 -    XResizeWindow(ob_display, self->window,
 +    XResizeWindow(obt_display, self->window,
                    self->area.width, self->area.height);
      item_a->surface.parent = self->frame->a_items;
      item_a->surface.parentx = self->area.x;
                    ob_rr_theme->a_menu_text_normal);
          sub = self->entry->data.submenu.submenu;
          text_a->texture[0].data.text.string = sub ? sub->title : "";
 -        if (sub->shortcut && (self->frame->menu->show_all_shortcuts ||
 +        if (sub && sub->shortcut && (self->frame->menu->show_all_shortcuts ||
                                sub->shortcut_always_show ||
                                sub->shortcut_position > 0))
          {
          else
              text_a = ob_rr_theme->a_menu_text_normal;
          break;
 +    default:
 +        g_assert_not_reached();
      }
  
      switch (self->entry->type) {
      case OB_MENU_ENTRY_TYPE_NORMAL:
 -        XMoveResizeWindow(ob_display, self->text,
 +        XMoveResizeWindow(obt_display, self->text,
                            self->frame->text_x, PADDING,
                            self->frame->text_w,
                            ITEM_HEIGHT - 2*PADDING);
                  ITEM_HEIGHT - 2*PADDING);
          break;
      case OB_MENU_ENTRY_TYPE_SUBMENU:
 -        XMoveResizeWindow(ob_display, self->text,
 +        XMoveResizeWindow(obt_display, self->text,
                            self->frame->text_x, PADDING,
                            self->frame->text_w - ITEM_HEIGHT,
                            ITEM_HEIGHT - 2*PADDING);
      case OB_MENU_ENTRY_TYPE_SEPARATOR:
          if (self->entry->data.separator.label != NULL) {
              /* labeled separator */
 -            XMoveResizeWindow(ob_display, self->text,
 +            XMoveResizeWindow(obt_display, self->text,
                                ob_rr_theme->paddingx, ob_rr_theme->paddingy,
                                self->area.width - 2*ob_rr_theme->paddingx,
                                ob_rr_theme->menu_title_height -
              gint i;
  
              /* unlabeled separator */
 -            XMoveResizeWindow(ob_display, self->text, 0, 0,
 +            XMoveResizeWindow(obt_display, self->text, 0, 0,
                                self->area.width,
                                ob_rr_theme->menu_sep_width +
                                2*ob_rr_theme->menu_sep_paddingy);
                      2*ob_rr_theme->menu_sep_paddingy);
          }
          break;
 +    default:
 +        g_assert_not_reached();
      }
  
      if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
      {
          RrAppearance *clear;
  
 -        XMoveResizeWindow(ob_display, self->icon,
 +        XMoveResizeWindow(obt_display, self->icon,
                            PADDING, frame->item_margin.top,
                            ITEM_HEIGHT - frame->item_margin.top
                            - frame->item_margin.bottom,
                  - frame->item_margin.bottom,
                  ITEM_HEIGHT - frame->item_margin.top
                  - frame->item_margin.bottom);
 -        XMapWindow(ob_display, self->icon);
 +        XMapWindow(obt_display, self->icon);
      } else if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
                 self->entry->data.normal.mask)
      {
          RrColor *c;
          RrAppearance *clear;
  
 -        XMoveResizeWindow(ob_display, self->icon,
 +        XMoveResizeWindow(obt_display, self->icon,
                            PADDING, frame->item_margin.top,
                            ITEM_HEIGHT - frame->item_margin.top
                            - frame->item_margin.bottom,
                  - frame->item_margin.bottom,
                  ITEM_HEIGHT - frame->item_margin.top
                  - frame->item_margin.bottom);
 -        XMapWindow(ob_display, self->icon);
 +        XMapWindow(obt_display, self->icon);
      } else
 -        XUnmapWindow(ob_display, self->icon);
 +        XUnmapWindow(obt_display, self->icon);
  
      if (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
          RrAppearance *bullet_a;
 -        XMoveResizeWindow(ob_display, self->bullet,
 +        XMoveResizeWindow(obt_display, self->bullet,
                            self->frame->text_x + self->frame->text_w -
                            ITEM_HEIGHT + PADDING, PADDING,
                            ITEM_HEIGHT - 2*PADDING,
          RrPaint(bullet_a, self->bullet,
                  ITEM_HEIGHT - 2*PADDING,
                  ITEM_HEIGHT - 2*PADDING);
 -        XMapWindow(ob_display, self->bullet);
 +        XMapWindow(obt_display, self->bullet);
      } else
 -        XUnmapWindow(ob_display, self->bullet);
 +        XUnmapWindow(obt_display, self->bullet);
  
 -    XFlush(ob_display);
 +    XFlush(obt_display);
  }
  
  /*! this code is taken from the menu_frame_render. if that changes, this won't
@@@ -703,10 -694,10 +703,10 @@@ void menu_frame_render(ObMenuFrame *sel
          }
  
          RECT_SET_POINT(e->area, 0, h+e->border);
 -        XMoveWindow(ob_display, e->window,
 +        XMoveWindow(obt_display, e->window,
                      e->area.x-e->border, e->area.y-e->border);
 -        XSetWindowBorderWidth(ob_display, e->window, e->border);
 -        XSetWindowBorder(ob_display, e->window,
 +        XSetWindowBorderWidth(obt_display, e->window, e->border);
 +        XSetWindowBorder(obt_display, e->window,
                           RrColorPixel(ob_rr_theme->menu_border_color));
  
          text_a = (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
                      2*ob_rr_theme->menu_sep_paddingy - 2*PADDING;
              }
              break;
 +        default:
 +            g_assert_not_reached();
          }
          tw += 2*PADDING;
          th += 2*PADDING;
      if (!w) w = 10;
      if (!h) h = 3;
  
 -    XResizeWindow(ob_display, self->window, w, h);
 +    XResizeWindow(obt_display, self->window, w, h);
  
      self->inner_w = w;
  
  
      RECT_SET_SIZE(self->area, w, h);
  
 -    XFlush(ob_display);
 +    XFlush(obt_display);
  }
  
  static void menu_frame_update(ObMenuFrame *self)
@@@ -974,7 -963,7 +974,7 @@@ gboolean menu_frame_show_topmenu(ObMenu
  
      menu_frame_move(self, x, y);
  
 -    XMapWindow(ob_display, self->window);
 +    XMapWindow(obt_display, self->window);
  
      if (screen_pointer_pos(&px, &py)) {
          ObMenuEntryFrame *e = menu_entry_frame_under(px, py);
      return TRUE;
  }
  
 -    ob_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout,
 -                                     child, FALSE);
+ /*! Stop hiding an open submenu.
+     @child The OnMenuFrame of the submenu to be hidden
+ */
+ static void remove_submenu_hide_timeout(ObMenuFrame *child)
+ {
++    obt_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout,
++                                      child, FALSE);
+ }
  gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
                                   ObMenuEntryFrame *parent_entry)
  {
      self->monitor = parent->monitor;
      self->parent = parent;
      self->parent_entry = parent_entry;
-     parent->open_submenu = parent_entry;
  
      /* set up parent's child to be us */
-     if (parent->child)
-         menu_frame_hide(parent->child);
-     parent->child = self;
+     if ((parent->child) != self) {
+         if (parent->child)
+             menu_frame_hide(parent->child);
+         parent->child = self;
+         parent->child_entry = parent_entry;
+     }
  
      if (!menu_frame_show(self))
          return FALSE;
      }
      menu_frame_move(self, x + dx, y + dy);
  
 -    XMapWindow(ob_display, self->window);
 +    XMapWindow(obt_display, self->window);
  
      if (screen_pointer_pos(&px, &py)) {
          ObMenuEntryFrame *e = menu_entry_frame_under(px, py);
@@@ -1043,9 -1043,11 +1054,11 @@@ static void menu_frame_hide(ObMenuFram
      if (self->child)
          menu_frame_hide(self->child);
  
-     if (self->parent && self->parent->child == self) {
+     if (self->parent) {
+         remove_submenu_hide_timeout(self);
          self->parent->child = NULL;
-         self->parent->open_submenu = NULL;
+         self->parent->child_entry = NULL;
      }
      self->parent = NULL;
      self->parent_entry = NULL;
      }
  
      ignore_start = event_start_ignore_all_enters();
 -    XUnmapWindow(ob_display, self->window);
 +    XUnmapWindow(obt_display, self->window);
      event_end_ignore_all_enters(ignore_start);
  
      menu_frame_free(self);
@@@ -1071,11 -1073,7 +1084,7 @@@ void menu_frame_hide_all(void
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
-         obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_show_timeout);
-         /* remove any submenu close delays */
-         obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_hide_timeout);
 -        ob_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
++        obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
      }
      if ((it = g_list_last(menu_frame_visible)))
          menu_frame_hide(it->data);
@@@ -1089,13 -1087,8 +1098,8 @@@ void menu_frame_hide_all_client(ObClien
          if (f->client == client) {
              if (config_submenu_show_delay) {
                  /* remove any submenu open requests */
-                 obt_main_loop_timeout_remove
-                     (ob_main_loop,
-                      menu_entry_frame_submenu_show_timeout);
-                 /* remove any submenu close delays */
-                 obt_main_loop_timeout_remove
-                     (ob_main_loop,
-                      menu_entry_frame_submenu_hide_timeout);
 -                ob_main_loop_timeout_remove(ob_main_loop,
 -                                            submenu_show_timeout);
++                obt_main_loop_timeout_remove(ob_main_loop,
++                                             submenu_show_timeout);
              }
              menu_frame_hide(f);
          }
@@@ -1130,6 -1123,7 +1134,7 @@@ ObMenuEntryFrame* menu_entry_frame_unde
  
          for (it = frame->entries; it; it = g_list_next(it)) {
              ObMenuEntryFrame *e = it->data;
              if (RECT_CONTAINS(e->area, x, y)) {
                  ret = e;
                  break;
      return ret;
  }
  
- static gboolean menu_entry_frame_submenu_hide_timeout(gpointer data)
+ static gboolean submenu_show_timeout(gpointer data)
  {
      g_assert(menu_frame_visible);
-     g_assert(((ObMenuFrame*)data)->parent != NULL);
-     menu_frame_hide((ObMenuFrame*)data);
+     menu_entry_frame_show_submenu((ObMenuEntryFrame*)data);
      return FALSE;
  }
  
- static gboolean menu_entry_frame_submenu_show_timeout(gpointer data)
+ static gboolean submenu_hide_timeout(gpointer data)
  {
      g_assert(menu_frame_visible);
-     menu_entry_frame_show_submenu((ObMenuEntryFrame*)data);
+     menu_frame_hide((ObMenuFrame*)data);
      return FALSE;
  }
  
@@@ -1159,27 -1152,25 +1163,25 @@@ void menu_frame_select(ObMenuFrame *sel
  {
      ObMenuEntryFrame *old = self->selected;
      ObMenuFrame *oldchild = self->child;
+     ObMenuEntryFrame *oldchild_entry = self->child_entry;
  
+     /* if the user selected a separator, ignore it and reselect what we had
+        selected before */
      if (entry && entry->entry->type == OB_MENU_ENTRY_TYPE_SEPARATOR)
          entry = old;
  
-     if (old == entry) return;
+     if (old == entry &&
+         (!old || old->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU))
+         return;
+     /* if the user left this menu but we have a submenu open, move the
+        selection back to that submenu */
+     if (!entry && oldchild_entry)
+         entry = oldchild_entry;
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
-         obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_show_timeout);
-     }
-     if (!entry && self->open_submenu) {
-         /* we moved out of the menu, so move the selection back to the open
-            submenu */
-         entry = self->open_submenu;
-         oldchild = NULL;
-         /* remove any submenu close delays */
-         obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_hide_timeout);
 -        ob_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
++        obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
      }
  
      self->selected = entry;
      if (old)
          menu_entry_frame_render(old);
  
-     if (oldchild) {
-         /* there is an open submenu */
-         if (config_submenu_show_delay && !immediate) {
-             if (entry == self->open_submenu) {
-                 /* we moved onto the entry that has an open submenu, so stop
-                    trying to close the submenu */
-                 obt_main_loop_timeout_remove
-                     (ob_main_loop,
-                      menu_entry_frame_submenu_hide_timeout);
-             }
-             else if (old == self->open_submenu) {
-                 /* we just moved off the entry with an open submenu, so
-                    close the open submenu after a delay */
-                 obt_main_loop_timeout_add
-                     (ob_main_loop,
-                      config_submenu_show_delay * 1000,
-                      menu_entry_frame_submenu_hide_timeout,
-                      self->child, g_direct_equal,
-                      NULL);
-             }
+     if (oldchild_entry) {
+         /* There is an open submenu */
+         if (oldchild_entry == self->selected) {
+             /* The open submenu has been reselected, so stop hiding the
+                submenu */
+             remove_submenu_hide_timeout(oldchild);
+         }
+         else if (oldchild_entry == old) {
+             /* The open submenu was selected and is no longer, so hide the
+                submenu */
+             if (immediate || config_submenu_hide_delay == 0)
+                 menu_frame_hide(oldchild);
+             else if (config_submenu_hide_delay > 0)
 -                ob_main_loop_timeout_add(ob_main_loop,
 -                                         config_submenu_hide_delay * 1000,
 -                                         submenu_hide_timeout,
 -                                         oldchild, g_direct_equal,
 -                                         NULL);
++                obt_main_loop_timeout_add(ob_main_loop,
++                                          config_submenu_hide_delay * 1000,
++                                          submenu_hide_timeout,
++                                          oldchild, g_direct_equal,
++                                          NULL);
          }
-         else
-             menu_frame_hide(oldchild);
      }
  
      if (self->selected) {
          menu_entry_frame_render(self->selected);
  
-         /* if we've selected a submenu and it wasn't already open, then
-            show it */
-         if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU &&
-             self->selected != self->open_submenu)
-         {
-             if (config_submenu_show_delay && !immediate) {
-                 /* initiate a new submenu open request */
-                 obt_main_loop_timeout_add
-                     (ob_main_loop,
-                      config_submenu_show_delay * 1000,
-                      menu_entry_frame_submenu_show_timeout,
-                      self->selected, g_direct_equal,
-                      NULL);
-             } else {
-                 menu_entry_frame_show_submenu(self->selected);
+         if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
+             /* only show if the submenu isn't already showing */
+             if (oldchild_entry != self->selected) {
+                 if (immediate || config_submenu_hide_delay == 0)
+                     menu_entry_frame_show_submenu(self->selected);
+                 else if (config_submenu_hide_delay > 0)
 -                    ob_main_loop_timeout_add(ob_main_loop,
 -                                             config_submenu_show_delay * 1000,
 -                                             submenu_show_timeout,
 -                                             self->selected, g_direct_equal,
 -                                             NULL);
++                    obt_main_loop_timeout_add(ob_main_loop,
++                                              config_submenu_show_delay * 1000,
++                                              submenu_show_timeout,
++                                              self->selected, g_direct_equal,
++                                              NULL);
+             }
+             /* hide the grandchildren of this menu. and move the cursor to
+                the current menu */
+             else if (immediate && self->child && self->child->child) {
+                 menu_frame_hide(self->child->child);
+                 menu_frame_select(self->child, NULL, TRUE);
              }
          }
      }
diff --combined openbox/menuframe.h
index 87a718e79fbf377bb44492ce618a75a1f547dcf1,926b844e815414c4784e61f7031e5fe8f5f114a2..a57b0dcbda2fe3ff4eaf0d04b4585141219d5a56
@@@ -22,7 -22,7 +22,7 @@@
  
  #include "geom.h"
  #include "window.h"
 -#include "render/render.h"
 +#include "obrender/render.h"
  
  #include <glib.h>
  
@@@ -38,7 -38,7 +38,7 @@@ extern GList *menu_frame_visible
  struct _ObMenuFrame
  {
      /* stuff to be an ObWindow */
 -    Window_InternalType type;
 +    ObWindow obwin;
      Window window;
  
      struct _ObMenu *menu;
      ObMenuFrame *parent;
      ObMenuEntryFrame *parent_entry;
      ObMenuFrame *child;
+     ObMenuEntryFrame *child_entry;
  
      GList *entries;
      ObMenuEntryFrame *selected;
-     /* if a submenu was selected, then this holds the entry for that submenu
-        until it is closed */
-     ObMenuEntryFrame *open_submenu;
  
      /* show entries from the menu starting at this index */
      guint show_from;
@@@ -120,7 -118,7 +118,7 @@@ gboolean menu_frame_show_topmenu(ObMenu
  gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
                                   ObMenuEntryFrame *parent_entry);
  
 -void menu_frame_hide_all();
 +void menu_frame_hide_all(void);
  void menu_frame_hide_all_client(struct _ObClient *client);
  
  void menu_frame_render(ObMenuFrame *self);
This page took 0.172922 seconds and 4 git commands to generate.