Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Mon, 11 Jan 2010 21:20:53 +0000 (16:20 -0500)
committerDana Jansens <danakj@orodu.net>
Mon, 11 Jan 2010 21:20:53 +0000 (16:20 -0500)
Conflicts:

configure.ac
data/rc.xml
openbox/client.c
openbox/event.c
openbox/focus_cycle.c
openbox/focus_cycle_popup.c
openbox/openbox.c
openbox/prop.c
openbox/prop.h
openbox/screen.c
parser/parse.c
version.h.in

18 files changed:
1  2 
configure.ac
data/rc.xml
obt/prop.c
obt/prop.h
openbox/client.c
openbox/client.h
openbox/event.c
openbox/focus.c
openbox/focus.h
openbox/focus_cycle.c
openbox/focus_cycle.h
openbox/focus_cycle_popup.c
openbox/focus_cycle_popup.h
openbox/menuframe.c
openbox/menuframe.h
openbox/openbox.c
openbox/screen.c
version.h.in

diff --combined configure.ac
@@@ -1,68 -1,44 +1,71 @@@
  AC_PREREQ([2.54])
 -AC_INIT([openbox], [3.999.0], [http://bugzilla.icculus.org])
 +AC_INIT([openbox], [3.5.0-rc1], [http://bugzilla.icculus.org])
  AM_INIT_AUTOMAKE
  AC_CONFIG_SRCDIR([openbox/openbox.c])
  
++OB_VERSION=$PACKAGE_VERSION
++AC_SUBST(OB_VERSION)
++
  dnl Making releases:
 -dnl   OB_MICRO_VERSION += 1;
 -dnl   OB_INTERFACE_AGE += 1;
 -dnl   OB_BINARY_AGE += 1;
 -dnl if any functions have been added, set OB_INTERFACE_AGE to 0.
 +dnl   RR_MICRO_VERSION += 1;
 +dnl   RR_INTERFACE_AGE += 1;
 +dnl   R_BINARY_AGE += 1;
 +dnl if any functions have been added, set RR_INTERFACE_AGE to 0.
  dnl if backwards compatibility has been broken,
 -dnl set OB_BINARY_AGE and OB_INTERFACE_AGE to 0.
 +dnl set RR_BINARY_AGE and RR_INTERFACE_AGE to 0.
  dnl
  dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
  dnl
 -OB_MAJOR_VERSION=3
 -OB_MINOR_VERSION=4
 -OB_MICRO_VERSION=16
 -OB_INTERFACE_AGE=0
 -OB_BINARY_AGE=0
 -OB_VERSION=$PACKAGE_VERSION
 -
 -AC_SUBST(OB_MAJOR_VERSION)
 -AC_SUBST(OB_MINOR_VERSION)
 -AC_SUBST(OB_MICRO_VERSION)
 -AC_SUBST(OB_INTERFACE_AGE)
 -AC_SUBST(OB_BINARY_AGE)
 -AC_SUBST(OB_VERSION)
 +RR_MAJOR_VERSION=3
 +RR_MINOR_VERSION=5
 +RR_MICRO_VERSION=27
 +RR_INTERFACE_AGE=0
 +RR_BINARY_AGE=0
 +RR_VERSION=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
 +
 +OBT_MAJOR_VERSION=3
 +OBT_MINOR_VERSION=5
 +OBT_MICRO_VERSION=0
 +OBT_INTERFACE_AGE=0
 +OBT_BINARY_AGE=0
 +OBT_VERSION=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
 +
 +AC_SUBST(RR_MAJOR_VERSION)
 +AC_SUBST(RR_MINOR_VERSION)
 +AC_SUBST(RR_MICRO_VERSION)
 +AC_SUBST(RR_INTERFACE_AGE)
 +AC_SUBST(RR_BINARY_AGE)
 +AC_SUBST(RR_VERSION)
 +AC_SUBST(OBT_MAJOR_VERSION)
 +AC_SUBST(OBT_MINOR_VERSION)
 +AC_SUBST(OBT_MICRO_VERSION)
 +AC_SUBST(OBT_INTERFACE_AGE)
 +AC_SUBST(OBT_BINARY_AGE)
 +AC_SUBST(OBT_VERSION)
  
  dnl Libtool versioning
 -LT_RELEASE=$OB_MAJOR_VERSION.$OB_MINOR_VERSION
 -LT_CURRENT=`expr $OB_MICRO_VERSION - $OB_INTERFACE_AGE`
 -LT_REVISION=$OB_INTERFACE_AGE
 -LT_AGE=`expr $OB_BINARY_AGE - $OB_INTERFACE_AGE`
 -LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
 -
 -AC_SUBST(LT_RELEASE)
 -AC_SUBST(LT_CURRENT)
 -AC_SUBST(LT_REVISION)
 -AC_SUBST(LT_AGE)
 -AC_SUBST(LT_CURRENT_MINUS_AGE)
 +RR_RELEASE=$RR_MAJOR_VERSION.$RR_MINOR_VERSION
 +RR_CURRENT=`expr $RR_MICRO_VERSION - $RR_INTERFACE_AGE`
 +RR_REVISION=$RR_INTERFACE_AGE
 +RR_AGE=`expr $RR_BINARY_AGE - $RR_INTERFACE_AGE`
 +RR_CURRENT_MINUS_AGE=`expr $RR_CURRENT - $RR_AGE`
 +
 +OBT_RELEASE=$OBT_MAJOR_VERSION.$OBT_MINOR_VERSION
 +OBT_CURRENT=`expr $OBT_MICRO_VERSION - $OBT_INTERFACE_AGE`
 +OBT_REVISION=$OBT_INTERFACE_AGE
 +OBT_AGE=`expr $OBT_BINARY_AGE - $OBT_INTERFACE_AGE`
 +OBT_CURRENT_MINUS_AGE=`expr $OBT_CURRENT - $OBT_AGE`
 +
 +AC_SUBST(RR_RELEASE)
 +AC_SUBST(RR_CURRENT)
 +AC_SUBST(RR_REVISION)
 +AC_SUBST(RR_AGE)
 +AC_SUBST(RR_CURRENT_MINUS_AGE)
 +AC_SUBST(OBT_RELEASE)
 +AC_SUBST(OBT_CURRENT)
 +AC_SUBST(OBT_REVISION)
 +AC_SUBST(OBT_AGE)
 +AC_SUBST(OBT_CURRENT_MINUS_AGE)
  
  AC_PREFIX_DEFAULT([/usr/local])
  test "$prefix" = "NONE" && prefix=$ac_default_prefix
@@@ -85,8 -61,7 +88,8 @@@ AM_GNU_GETTEXT_VERSION(0.15
  AM_GNU_GETTEXT([external])
  
  AC_CHECK_HEADERS(ctype.h fcntl.h locale.h signal.h string.h stdio.h stdlib.h)
 -AC_CHECK_HEADERS(unistd.h sys/stat.h sys/select.h sys/time.h sys/wait.h)
 +AC_CHECK_HEADERS(unistd.h sys/stat.h sys/select.h sys/socket.h sys/time.h)
 +AC_CHECK_HEADERS(sys/wait.h)
  # AC_HEADER_TIME
  # AC_TYPE_SIGNAL
  
@@@ -103,6 -78,10 +106,6 @@@ PKG_CHECK_MODULES(PANGO, [pango >= 1.8.
  AC_SUBST(PANGO_CFLAGS)
  AC_SUBST(PANGO_LIBS)
  
 -PKG_CHECK_MODULES(XFT, [xft])
 -AC_SUBST(XFT_CFLAGS)
 -AC_SUBST(XFT_LIBS)
 -
  PKG_CHECK_MODULES(XML, [libxml-2.0 >= 2.6.0])
  AC_SUBST(XML_CFLAGS)
  AC_SUBST(XML_LIBS)
@@@ -157,33 -136,6 +160,33 @@@ els
    xcursor_found=no
  fi
  
 +AC_ARG_ENABLE(imlib2,
 +  AC_HELP_STRING(
 +    [--disable-imlib2],
 +    [disable use of Imlib2 image library for loading icons. [[default=enabled]]]
 +  ),
 +  [enable_imlib2=$enableeval],
 +  [enable_imlib2=yes]
 +)
 +
 +if test "$enable_imlib2" = yes; then
 +PKG_CHECK_MODULES(IMLIB2, [imlib2],
 +  [
 +    AC_DEFINE(USE_IMLIB2, [1], [Use Imlib2 image library])
 +    AC_SUBST(IMLIB2_CFLAGS)
 +    AC_SUBST(IMLIB2_LIBS)
 +    imlib2_found=yes
 +  ],
 +  [
 +    imlib2_found=no
 +  ]
 +)
 +else
 +  imlib2_found=no
 +fi
 +
 +AM_CONDITIONAL(USE_IMLIB2, [test $imlib2_found = yes])
 +
  dnl Check for session management
  X11_SM
  
@@@ -202,10 -154,9 +205,11 @@@ AC_CONFIG_FILES(
    Makefile
    m4/Makefile
    po/Makefile.in
 -  render/obrender-3.0.pc
 -  parser/obparser-3.0.pc
 +  obrender/obrender-3.5.pc
 +  obt/obt-3.5.pc
 +  obrender/version.h
 +  obt/version.h
+   version.h
  ])
  AC_CONFIG_COMMANDS([doc],
                     [test -d doc || mkdir doc])
@@@ -220,6 -171,5 +224,6 @@@ AC_MSG_RESULT([Compiling with these opt
                 Startup Notification... $sn_found
                 X Cursor Library... $xcursor_found
                 Session Management... $SM
 +               Imlib2 library... $imlib2_found
                 ])
  AC_MSG_RESULT([configure complete, now type "make"])
diff --combined data/rc.xml
      <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>
  <!--
    # this is an example with comments through out. use these to make your
    # own rules, but without the comments of course.
 +  # you may use one or more of the name/class/role/type rules to specify
 +  # windows to match
  
-   <application name="the window's _OB_NAME property (see obxprop)"
-               class="the window's _OB_CLASS property (see obxprop)"
-                role="the window's _OB_ROLE property (see obxprop)"
-                type="the window's _NET_WM_WINDOW_TYPE (see obxprob)..
-                       (if unspecified, then it is 'dialog' for child windows)
-                       one of: normal, dialog, splash, utility, menu, toolbar,
-                               dock, desktop">
-   # the name or the class can be set, or both. this is used to match
-   # windows when they appear. role can optionally be set as well, to
-   # further restrict your matches.
+   <application name="the window's _OB_APP_NAME property (see obxprop)"
+               class="the window's _OB_APP_CLASS property (see obxprop)"
+                role="the window's _OB_APP_ROLE property (see obxprop)"
+                type="the window's _OB_APP_TYPE property (see obxprob)..
+                       (if unspecified, then it is 'dialog' for child windows)">
+   # you may set only one of name/class/role/type, or you may use more than one
+   # together to restrict your matches.
  
    # the name, class, and role use simple wildcard matching such as those
    # used by a shell. you can use * to match any characters and ? to match
    # order that they appear in this list
  
  
-     # each element can be left out or set to 'default' to specify to not 
+     # each rule element can be left out or set to 'default' to specify to not 
      # change that attribute of the window
  
      <decor>yes</decor>
diff --combined obt/prop.c
index f4c8db1,0000000..3af9c7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,501 -1,0 +1,503 @@@
-     CREATE_(OB_ROLE);
-     CREATE_(OB_NAME);
-     CREATE_(OB_CLASS);
 +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 +
 +   obt/prop.c for the Openbox window manager
 +   Copyright (c) 2006        Mikael Magnusson
 +   Copyright (c) 2003-2007   Dana Jansens
 +
 +   This program is free software; you can redistribute it and/or modify
 +   it under the terms of the GNU General Public License as published by
 +   the Free Software Foundation; either version 2 of the License, or
 +   (at your option) any later version.
 +
 +   This program is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
 +
 +   See the COPYING file for a copy of the GNU General Public License.
 +*/
 +
 +#include "obt/prop.h"
 +#include "obt/display.h"
 +
 +#include <X11/Xatom.h>
 +#ifdef HAVE_STRING_H
 +#  include <string.h>
 +#endif
 +
 +Atom prop_atoms[OBT_PROP_NUM_ATOMS];
 +gboolean prop_started = FALSE;
 +
 +#define CREATE_NAME(var, name) (prop_atoms[OBT_PROP_##var] = \
 +                                XInternAtom((obt_display), (name), FALSE))
 +#define CREATE(var) CREATE_NAME(var, #var)
 +#define CREATE_(var) CREATE_NAME(var, "_" #var)
 +
 +void obt_prop_startup(void)
 +{
 +    if (prop_started) return;
 +    prop_started = TRUE;
 +
 +    g_assert(obt_display);
 +
 +    CREATE(CARDINAL);
 +    CREATE(WINDOW);
 +    CREATE(PIXMAP);
 +    CREATE(ATOM);
 +    CREATE(STRING);
 +    CREATE_NAME(UTF8, "UTF8_STRING");
 +
 +    CREATE(MANAGER);
 +
 +    CREATE(WM_COLORMAP_WINDOWS);
 +    CREATE(WM_PROTOCOLS);
 +    CREATE(WM_STATE);
 +    CREATE(WM_CHANGE_STATE);
 +    CREATE(WM_DELETE_WINDOW);
 +    CREATE(WM_TAKE_FOCUS);
 +    CREATE(WM_NAME);
 +    CREATE(WM_ICON_NAME);
 +    CREATE(WM_CLASS);
 +    CREATE(WM_WINDOW_ROLE);
 +    CREATE(WM_CLIENT_MACHINE);
 +    CREATE(WM_COMMAND);
 +    CREATE(WM_CLIENT_LEADER);
 +    CREATE(WM_TRANSIENT_FOR);
 +    CREATE_(MOTIF_WM_HINTS);
 +    CREATE_(MOTIF_WM_INFO);
 +
 +    CREATE(SM_CLIENT_ID);
 +
 +    CREATE_(NET_WM_FULL_PLACEMENT);
 +
 +    CREATE_(NET_SUPPORTED);
 +    CREATE_(NET_CLIENT_LIST);
 +    CREATE_(NET_CLIENT_LIST_STACKING);
 +    CREATE_(NET_NUMBER_OF_DESKTOPS);
 +    CREATE_(NET_DESKTOP_GEOMETRY);
 +    CREATE_(NET_DESKTOP_VIEWPORT);
 +    CREATE_(NET_CURRENT_DESKTOP);
 +    CREATE_(NET_DESKTOP_NAMES);
 +    CREATE_(NET_ACTIVE_WINDOW);
 +/*    CREATE_(NET_RESTACK_WINDOW);*/
 +    CREATE_(NET_WORKAREA);
 +    CREATE_(NET_SUPPORTING_WM_CHECK);
 +    CREATE_(NET_DESKTOP_LAYOUT);
 +    CREATE_(NET_SHOWING_DESKTOP);
 +
 +    CREATE_(NET_CLOSE_WINDOW);
 +    CREATE_(NET_WM_MOVERESIZE);
 +    CREATE_(NET_MOVERESIZE_WINDOW);
 +    CREATE_(NET_REQUEST_FRAME_EXTENTS);
 +    CREATE_(NET_RESTACK_WINDOW);
 +
 +    CREATE_(NET_STARTUP_ID);
 +
 +    CREATE_(NET_WM_NAME);
 +    CREATE_(NET_WM_VISIBLE_NAME);
 +    CREATE_(NET_WM_ICON_NAME);
 +    CREATE_(NET_WM_VISIBLE_ICON_NAME);
 +    CREATE_(NET_WM_DESKTOP);
 +    CREATE_(NET_WM_WINDOW_TYPE);
 +    CREATE_(NET_WM_STATE);
 +    CREATE_(NET_WM_STRUT);
 +    CREATE_(NET_WM_STRUT_PARTIAL);
 +    CREATE_(NET_WM_ICON);
 +    CREATE_(NET_WM_ICON_GEOMETRY);
 +    CREATE_(NET_WM_PID);
 +    CREATE_(NET_WM_ALLOWED_ACTIONS);
 +    CREATE_(NET_WM_USER_TIME);
 +/*  CREATE_(NET_WM_USER_TIME_WINDOW); */
 +    CREATE_(KDE_NET_WM_FRAME_STRUT);
 +    CREATE_(NET_FRAME_EXTENTS);
 +
 +    CREATE_(NET_WM_PING);
 +#ifdef SYNC
 +    CREATE_(NET_WM_SYNC_REQUEST);
 +    CREATE_(NET_WM_SYNC_REQUEST_COUNTER);
 +#endif
 +
 +    CREATE_(NET_WM_WINDOW_TYPE_DESKTOP);
 +    CREATE_(NET_WM_WINDOW_TYPE_DOCK);
 +    CREATE_(NET_WM_WINDOW_TYPE_TOOLBAR);
 +    CREATE_(NET_WM_WINDOW_TYPE_MENU);
 +    CREATE_(NET_WM_WINDOW_TYPE_UTILITY);
 +    CREATE_(NET_WM_WINDOW_TYPE_SPLASH);
 +    CREATE_(NET_WM_WINDOW_TYPE_DIALOG);
 +    CREATE_(NET_WM_WINDOW_TYPE_NORMAL);
 +    CREATE_(NET_WM_WINDOW_TYPE_POPUP_MENU);
 +
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT] = 0;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP] = 1;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT] = 2;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT] = 3;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT] = 4;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM] = 5;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT] = 6;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT] = 7;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE] = 8;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD] = 9;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD] = 10;
 +    prop_atoms[OBT_PROP_NET_WM_MOVERESIZE_CANCEL] = 11;
 +
 +    CREATE_(NET_WM_ACTION_MOVE);
 +    CREATE_(NET_WM_ACTION_RESIZE);
 +    CREATE_(NET_WM_ACTION_MINIMIZE);
 +    CREATE_(NET_WM_ACTION_SHADE);
 +    CREATE_(NET_WM_ACTION_MAXIMIZE_HORZ);
 +    CREATE_(NET_WM_ACTION_MAXIMIZE_VERT);
 +    CREATE_(NET_WM_ACTION_FULLSCREEN);
 +    CREATE_(NET_WM_ACTION_CHANGE_DESKTOP);
 +    CREATE_(NET_WM_ACTION_CLOSE);
 +    CREATE_(NET_WM_ACTION_ABOVE);
 +    CREATE_(NET_WM_ACTION_BELOW);
 +
 +    CREATE_(NET_WM_STATE_MODAL);
 +/*    CREATE_(NET_WM_STATE_STICKY);*/
 +    CREATE_(NET_WM_STATE_MAXIMIZED_VERT);
 +    CREATE_(NET_WM_STATE_MAXIMIZED_HORZ);
 +    CREATE_(NET_WM_STATE_SHADED);
 +    CREATE_(NET_WM_STATE_SKIP_TASKBAR);
 +    CREATE_(NET_WM_STATE_SKIP_PAGER);
 +    CREATE_(NET_WM_STATE_HIDDEN);
 +    CREATE_(NET_WM_STATE_FULLSCREEN);
 +    CREATE_(NET_WM_STATE_ABOVE);
 +    CREATE_(NET_WM_STATE_BELOW);
 +    CREATE_(NET_WM_STATE_DEMANDS_ATTENTION);
 +
 +    prop_atoms[OBT_PROP_NET_WM_STATE_ADD] = 1;
 +    prop_atoms[OBT_PROP_NET_WM_STATE_REMOVE] = 0;
 +    prop_atoms[OBT_PROP_NET_WM_STATE_TOGGLE] = 2;
 +
 +    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_HORZ] = 0;
 +    prop_atoms[OBT_PROP_NET_WM_ORIENTATION_VERT] = 1;
 +    prop_atoms[OBT_PROP_NET_WM_TOPLEFT] = 0;
 +    prop_atoms[OBT_PROP_NET_WM_TOPRIGHT] = 1;
 +    prop_atoms[OBT_PROP_NET_WM_BOTTOMRIGHT] = 2;
 +    prop_atoms[OBT_PROP_NET_WM_BOTTOMLEFT] = 3;
 +
 +    CREATE_(KDE_WM_CHANGE_STATE);
 +    CREATE_(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
 +
 +/*
 +    CREATE_NAME(ROOTPMAPId, "_XROOTPMAP_ID");
 +    CREATE_NAME(ESETROOTId, "ESETROOT_PMAP_ID");
 +*/
 +
 +    CREATE_(OPENBOX_PID);
 +    CREATE_(OB_THEME);
 +    CREATE_(OB_CONFIG_FILE);
 +    CREATE_(OB_WM_ACTION_UNDECORATE);
 +    CREATE_(OB_WM_STATE_UNDECORATED);
 +    CREATE_(OB_CONTROL);
++    CREATE_(OB_VERSION);
++    CREATE_(OB_APP_ROLE);
++    CREATE_(OB_APP_NAME);
++    CREATE_(OB_APP_CLASS);
++    CREATE_(OB_APP_TYPE);
 +}
 +
 +Atom obt_prop_atom(ObtPropAtom a)
 +{
 +    g_assert(prop_started);
 +    g_assert(a < OBT_PROP_NUM_ATOMS);
 +    return prop_atoms[a];
 +}
 +
 +static gboolean get_prealloc(Window win, Atom prop, Atom type, gint size,
 +                             guchar *data, gulong num)
 +{
 +    gboolean ret = FALSE;
 +    gint res;
 +    guchar *xdata = NULL;
 +    Atom ret_type;
 +    gint ret_size;
 +    gulong ret_items, bytes_left;
 +    glong num32 = 32 / size * num; /* num in 32-bit elements */
 +
 +    res = XGetWindowProperty(obt_display, win, prop, 0l, num32,
 +                             FALSE, type, &ret_type, &ret_size,
 +                             &ret_items, &bytes_left, &xdata);
 +    if (res == Success && ret_items && xdata) {
 +        if (ret_size == size && ret_items >= num) {
 +            guint i;
 +            for (i = 0; i < num; ++i)
 +                switch (size) {
 +                case 8:
 +                    data[i] = xdata[i];
 +                    break;
 +                case 16:
 +                    ((guint16*)data)[i] = ((gushort*)xdata)[i];
 +                    break;
 +                case 32:
 +                    ((guint32*)data)[i] = ((gulong*)xdata)[i];
 +                    break;
 +                default:
 +                    g_assert_not_reached(); /* unhandled size */
 +                }
 +            ret = TRUE;
 +        }
 +        XFree(xdata);
 +    }
 +    return ret;
 +}
 +
 +static gboolean get_all(Window win, Atom prop, Atom type, gint size,
 +                        guchar **data, guint *num)
 +{
 +    gboolean ret = FALSE;
 +    gint res;
 +    guchar *xdata = NULL;
 +    Atom ret_type;
 +    gint ret_size;
 +    gulong ret_items, bytes_left;
 +
 +    res = XGetWindowProperty(obt_display, win, prop, 0l, G_MAXLONG,
 +                             FALSE, type, &ret_type, &ret_size,
 +                             &ret_items, &bytes_left, &xdata);
 +    if (res == Success) {
 +        if (ret_size == size && ret_items > 0) {
 +            guint i;
 +
 +            *data = g_malloc(ret_items * (size / 8));
 +            for (i = 0; i < ret_items; ++i)
 +                switch (size) {
 +                case 8:
 +                    (*data)[i] = xdata[i];
 +                    break;
 +                case 16:
 +                    ((guint16*)*data)[i] = ((gushort*)xdata)[i];
 +                    break;
 +                case 32:
 +                    ((guint32*)*data)[i] = ((gulong*)xdata)[i];
 +                    break;
 +                default:
 +                    g_assert_not_reached(); /* unhandled size */
 +                }
 +            *num = ret_items;
 +            ret = TRUE;
 +        }
 +        XFree(xdata);
 +    }
 +    return ret;
 +}
 +
 +static gboolean get_stringlist(Window win, Atom prop, gchar ***list, gint *nstr)
 +{
 +    XTextProperty tprop;
 +    gboolean ret = FALSE;
 +
 +    if (XGetTextProperty(obt_display, win, &tprop, prop) && tprop.nitems) {
 +        if (XTextPropertyToStringList(&tprop, list, nstr))
 +            ret = TRUE;
 +        XFree(tprop.value);
 +    }
 +    return ret;
 +}
 +
 +gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret)
 +{
 +    return get_prealloc(win, prop, type, 32, (guchar*)ret, 1);
 +}
 +
 +gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
 +                              guint *nret)
 +{
 +    return get_all(win, prop, type, 32, (guchar**)ret, nret);
 +}
 +
 +gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret)
 +{
 +    gchar **list;
 +    gint nstr;
 +    gchar *s;
 +
 +    if (get_stringlist(win, prop, &list, &nstr) && nstr) {
 +        s = g_locale_to_utf8(list[0], -1, NULL, NULL, NULL);
 +        XFreeStringList(list);
 +        if (s) {
 +            *ret = s;
 +            return TRUE;
 +        }
 +    }
 +    return FALSE;
 +}
 +
 +gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret)
 +{
 +    GSList *strs = NULL, *it;
 +    gchar *raw, *p;
 +    guint num, i, count = 0;
 +
 +    if (get_all(win, prop, OBT_PROP_ATOM(STRING), 8,
 +                (guchar**)&raw, &num))
 +    {
 +        p = raw;
 +        while (p < raw + num) {
 +            ++count;
 +            strs = g_slist_append(strs, p);
 +            p += strlen(p) + 1; /* next string */
 +        }
 +
 +        *ret = g_new0(gchar*, count + 1);
 +        (*ret)[count] = NULL; /* null terminated list */
 +
 +        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
 +            (*ret)[i] = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
 +            /* make sure translation did not fail */
 +            if (!(*ret)[i])
 +                (*ret)[i] = g_strdup("");
 +        }
 +        g_free(raw);
 +        g_slist_free(strs);
 +        return TRUE;
 +    }
 +    return FALSE;
 +}
 +
 +gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret)
 +{
 +    gchar *raw;
 +    gchar *str;
 +    guint num;
 +
 +    if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
 +                (guchar**)&raw, &num))
 +    {
 +        str = g_strndup(raw, num); /* grab the first string from the list */
 +        g_free(raw);
 +        if (g_utf8_validate(str, -1, NULL)) {
 +            *ret = str;
 +            return TRUE;
 +        }
 +        g_free(str);
 +    }
 +    return FALSE;
 +}
 +
 +gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret)
 +{
 +    GSList *strs = NULL, *it;
 +    gchar *raw, *p;
 +    guint num, i, count = 0;
 +
 +    if (get_all(win, prop, OBT_PROP_ATOM(UTF8), 8,
 +                (guchar**)&raw, &num))
 +    {
 +        p = raw;
 +        while (p < raw + num) {
 +            ++count;
 +            strs = g_slist_append(strs, p);
 +            p += strlen(p) + 1; /* next string */
 +        }
 +
 +        *ret = g_new0(gchar*, count + 1);
 +
 +        for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
 +            if (g_utf8_validate(it->data, -1, NULL))
 +                (*ret)[i] = g_strdup(it->data);
 +            else
 +                (*ret)[i] = g_strdup("");
 +        }
 +        g_free(raw);
 +        g_slist_free(strs);
 +        return TRUE;
 +    }
 +    return FALSE;
 +}
 +
 +void obt_prop_set32(Window win, Atom prop, Atom type, gulong val)
 +{
 +    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
 +                    (guchar*)&val, 1);
 +}
 +
 +void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
 +                      guint num)
 +{
 +    XChangeProperty(obt_display, win, prop, type, 32, PropModeReplace,
 +                    (guchar*)val, num);
 +}
 +
 +void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val)
 +{
 +    gchar const *s[2] = { val, NULL };
 +    obt_prop_set_strings_locale(win, prop, s);
 +}
 +
 +void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs)
 +{
 +    gint i, count;
 +    gchar **lstrs;
 +    XTextProperty tprop;
 +
 +    /* count the strings in strs, and convert them to the locale format */
 +    for (count = 0; strs[count]; ++count);
 +    lstrs = g_new0(char*, count);
 +    for (i = 0; i < count; ++i) {
 +        lstrs[i] = g_locale_from_utf8(strs[i], -1, NULL, NULL, NULL);
 +        if (!lstrs[i]) {
 +            lstrs[i] = g_strdup(""); /* make it an empty string */
 +            g_warning("Unable to translate string '%s' from UTF8 to locale "
 +                      "format", strs[i]);
 +        }
 +    }
 +
 +
 +    XStringListToTextProperty(lstrs, count, &tprop);
 +    XSetTextProperty(obt_display, win, &tprop, prop);
 +    XFree(tprop.value);
 +}
 +
 +void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val)
 +{
 +    XChangeProperty(obt_display, win, prop, OBT_PROP_ATOM(UTF8), 8,
 +                    PropModeReplace, (const guchar*)val, strlen(val));
 +}
 +
 +void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs)
 +{
 +    GString *str;
 +    gchar const **s;
 +
 +    str = g_string_sized_new(0);
 +    for (s = strs; *s; ++s) {
 +        str = g_string_append(str, *s);
 +        str = g_string_append_c(str, '\0');
 +    }
 +    XChangeProperty(obt_display, win, prop, obt_prop_atom(OBT_PROP_UTF8), 8,
 +                    PropModeReplace, (guchar*)str->str, str->len);
 +    g_string_free(str, TRUE);
 +}
 +
 +void obt_prop_erase(Window win, Atom prop)
 +{
 +    XDeleteProperty(obt_display, win, prop);
 +}
 +
 +void obt_prop_message(gint screen, Window about, Atom messagetype,
 +                      glong data0, glong data1, glong data2, glong data3,
 +                      glong data4, glong mask)
 +{
 +    obt_prop_message_to(obt_root(screen), about, messagetype,
 +                        data0, data1, data2, data3, data4, mask);
 +}
 +
 +void obt_prop_message_to(Window to, Window about,
 +                         Atom messagetype,
 +                         glong data0, glong data1, glong data2, glong data3,
 +                         glong data4, glong mask)
 +{
 +    XEvent ce;
 +    ce.xclient.type = ClientMessage;
 +    ce.xclient.message_type = messagetype;
 +    ce.xclient.display = obt_display;
 +    ce.xclient.window = about;
 +    ce.xclient.format = 32;
 +    ce.xclient.data.l[0] = data0;
 +    ce.xclient.data.l[1] = data1;
 +    ce.xclient.data.l[2] = data2;
 +    ce.xclient.data.l[3] = data3;
 +    ce.xclient.data.l[4] = data4;
 +    XSendEvent(obt_display, to, FALSE, mask, &ce);
 +}
diff --combined obt/prop.h
index 52c1de1,0000000..0a471cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,285 -1,0 +1,287 @@@
-     OBT_PROP_OB_ROLE,
-     OBT_PROP_OB_NAME,
-     OBT_PROP_OB_CLASS,
 +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 +
 +   obt/prop.h for the Openbox window manager
 +   Copyright (c) 2006        Mikael Magnusson
 +   Copyright (c) 2003-2007   Dana Jansens
 +
 +   This program is free software; you can redistribute it and/or modify
 +   it under the terms of the GNU General Public License as published by
 +   the Free Software Foundation; either version 2 of the License, or
 +   (at your option) any later version.
 +
 +   This program is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
 +
 +   See the COPYING file for a copy of the GNU General Public License.
 +*/
 +
 +#ifndef __obt_prop_h
 +#define __obt_prop_h
 +
 +#include <X11/Xlib.h>
 +#include <glib.h>
 +
 +G_BEGIN_DECLS
 +
 +typedef enum {
 +    /* types */
 +    OBT_PROP_CARDINAL, /*!< The atom which represents the Cardinal data type */
 +    OBT_PROP_WINDOW,   /*!< The atom which represents window ids */
 +    OBT_PROP_PIXMAP,   /*!< The atom which represents pixmap ids */
 +    OBT_PROP_ATOM,     /*!< The atom which represents atom values */
 +    OBT_PROP_STRING,   /*!< The atom which represents ascii strings */
 +    OBT_PROP_UTF8,     /*!< The atom which represents utf8-encoded strings */
 +
 +    /* selection stuff */
 +    OBT_PROP_MANAGER,
 +
 +    /* window hints */
 +    OBT_PROP_WM_COLORMAP_WINDOWS,
 +    OBT_PROP_WM_PROTOCOLS,
 +    OBT_PROP_WM_STATE,
 +    OBT_PROP_WM_DELETE_WINDOW,
 +    OBT_PROP_WM_TAKE_FOCUS,
 +    OBT_PROP_WM_CHANGE_STATE,
 +    OBT_PROP_WM_NAME,
 +    OBT_PROP_WM_ICON_NAME,
 +    OBT_PROP_WM_CLASS,
 +    OBT_PROP_WM_WINDOW_ROLE,
 +    OBT_PROP_WM_CLIENT_MACHINE,
 +    OBT_PROP_WM_COMMAND,
 +    OBT_PROP_WM_CLIENT_LEADER,
 +    OBT_PROP_WM_TRANSIENT_FOR,
 +    OBT_PROP_MOTIF_WM_HINTS,
 +    OBT_PROP_MOTIF_WM_INFO,
 +
 +    /* SM atoms */
 +    OBT_PROP_SM_CLIENT_ID,
 +
 +    /* NETWM atoms */
 +
 +    /* Atoms that are used inside messages - these don't go in net_supported */
 +
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPLEFT,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOP,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_TOPRIGHT,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_RIGHT,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOM,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_LEFT,
 +    OBT_PROP_NET_WM_MOVERESIZE_MOVE,
 +    OBT_PROP_NET_WM_MOVERESIZE_SIZE_KEYBOARD,
 +    OBT_PROP_NET_WM_MOVERESIZE_MOVE_KEYBOARD,
 +    OBT_PROP_NET_WM_MOVERESIZE_CANCEL,
 +
 +    OBT_PROP_NET_WM_STATE_ADD,
 +    OBT_PROP_NET_WM_STATE_REMOVE,
 +    OBT_PROP_NET_WM_STATE_TOGGLE,
 +
 +    OBT_PROP_NET_WM_ORIENTATION_HORZ,
 +    OBT_PROP_NET_WM_ORIENTATION_VERT,
 +    OBT_PROP_NET_WM_TOPLEFT,
 +    OBT_PROP_NET_WM_TOPRIGHT,
 +    OBT_PROP_NET_WM_BOTTOMRIGHT,
 +    OBT_PROP_NET_WM_BOTTOMLEFT,
 +
 +    OBT_PROP_NET_WM_WINDOW_TYPE_POPUP_MENU,
 +
 +    OBT_PROP_PRIVATE_PADDING1,
 +    OBT_PROP_PRIVATE_PADDING2,
 +    OBT_PROP_PRIVATE_PADDING3,
 +    OBT_PROP_PRIVATE_PADDING4,
 +    OBT_PROP_PRIVATE_PADDING5,
 +    OBT_PROP_PRIVATE_PADDING6,
 +    OBT_PROP_PRIVATE_PADDING7,
 +    OBT_PROP_PRIVATE_PADDING8,
 +    OBT_PROP_PRIVATE_PADDING9,
 +    OBT_PROP_PRIVATE_PADDING10,
 +    OBT_PROP_PRIVATE_PADDING11,
 +    OBT_PROP_PRIVATE_PADDING12,
 +
 +    /* Everything below here must go in net_supported on the root window */
 +
 +    /* root window properties */
 +    OBT_PROP_NET_SUPPORTED,
 +    OBT_PROP_NET_CLIENT_LIST,
 +    OBT_PROP_NET_CLIENT_LIST_STACKING,
 +    OBT_PROP_NET_NUMBER_OF_DESKTOPS,
 +    OBT_PROP_NET_DESKTOP_GEOMETRY,
 +    OBT_PROP_NET_DESKTOP_VIEWPORT,
 +    OBT_PROP_NET_CURRENT_DESKTOP,
 +    OBT_PROP_NET_DESKTOP_NAMES,
 +    OBT_PROP_NET_ACTIVE_WINDOW,
 +/*    Atom net_restack_window;*/
 +    OBT_PROP_NET_WORKAREA,
 +    OBT_PROP_NET_SUPPORTING_WM_CHECK,
 +    OBT_PROP_NET_DESKTOP_LAYOUT,
 +    OBT_PROP_NET_SHOWING_DESKTOP,
 +
 +    /* root window messages */
 +    OBT_PROP_NET_CLOSE_WINDOW,
 +    OBT_PROP_NET_WM_MOVERESIZE,
 +    OBT_PROP_NET_MOVERESIZE_WINDOW,
 +    OBT_PROP_NET_REQUEST_FRAME_EXTENTS,
 +    OBT_PROP_NET_RESTACK_WINDOW,
 +
 +    /* helpful hints to apps that aren't used for anything */
 +    OBT_PROP_NET_WM_FULL_PLACEMENT,
 +
 +    /* startup-notification extension */
 +    OBT_PROP_NET_STARTUP_ID,
 +
 +    /* application window properties */
 +    OBT_PROP_NET_WM_NAME,
 +    OBT_PROP_NET_WM_VISIBLE_NAME,
 +    OBT_PROP_NET_WM_ICON_NAME,
 +    OBT_PROP_NET_WM_VISIBLE_ICON_NAME,
 +    OBT_PROP_NET_WM_DESKTOP,
 +    OBT_PROP_NET_WM_WINDOW_TYPE,
 +    OBT_PROP_NET_WM_STATE,
 +    OBT_PROP_NET_WM_STRUT,
 +    OBT_PROP_NET_WM_STRUT_PARTIAL,
 +    OBT_PROP_NET_WM_ICON,
 +    OBT_PROP_NET_WM_ICON_GEOMETRY,
 +    OBT_PROP_NET_WM_PID,
 +    OBT_PROP_NET_WM_ALLOWED_ACTIONS,
 +    OBT_PROP_NET_WM_USER_TIME,
 +/*  OBT_PROP_NET_WM_USER_TIME_WINDOW, */
 +    OBT_PROP_NET_FRAME_EXTENTS,
 +
 +    /* application protocols */
 +    OBT_PROP_NET_WM_PING,
 +#ifdef SYNC
 +    OBT_PROP_NET_WM_SYNC_REQUEST,
 +    OBT_PROP_NET_WM_SYNC_REQUEST_COUNTER,
 +#endif
 +
 +    OBT_PROP_NET_WM_WINDOW_TYPE_DESKTOP,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_DOCK,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_TOOLBAR,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_MENU,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_UTILITY,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_SPLASH,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_DIALOG,
 +    OBT_PROP_NET_WM_WINDOW_TYPE_NORMAL,
 +
 +    OBT_PROP_NET_WM_ACTION_MOVE,
 +    OBT_PROP_NET_WM_ACTION_RESIZE,
 +    OBT_PROP_NET_WM_ACTION_MINIMIZE,
 +    OBT_PROP_NET_WM_ACTION_SHADE,
 +/*    OBT_PROP_NET_WM_ACTION_STICK,*/
 +    OBT_PROP_NET_WM_ACTION_MAXIMIZE_HORZ,
 +    OBT_PROP_NET_WM_ACTION_MAXIMIZE_VERT,
 +    OBT_PROP_NET_WM_ACTION_FULLSCREEN,
 +    OBT_PROP_NET_WM_ACTION_CHANGE_DESKTOP,
 +    OBT_PROP_NET_WM_ACTION_CLOSE,
 +    OBT_PROP_NET_WM_ACTION_ABOVE,
 +    OBT_PROP_NET_WM_ACTION_BELOW,
 +
 +    OBT_PROP_NET_WM_STATE_MODAL,
 +/*    OBT_PROP_NET_WM_STATE_STICKY,*/
 +    OBT_PROP_NET_WM_STATE_MAXIMIZED_VERT,
 +    OBT_PROP_NET_WM_STATE_MAXIMIZED_HORZ,
 +    OBT_PROP_NET_WM_STATE_SHADED,
 +    OBT_PROP_NET_WM_STATE_SKIP_TASKBAR,
 +    OBT_PROP_NET_WM_STATE_SKIP_PAGER,
 +    OBT_PROP_NET_WM_STATE_HIDDEN,
 +    OBT_PROP_NET_WM_STATE_FULLSCREEN,
 +    OBT_PROP_NET_WM_STATE_ABOVE,
 +    OBT_PROP_NET_WM_STATE_BELOW,
 +    OBT_PROP_NET_WM_STATE_DEMANDS_ATTENTION,
 +
 +    /* KDE atoms */
 +
 +    OBT_PROP_KDE_WM_CHANGE_STATE,
 +    OBT_PROP_KDE_NET_WM_FRAME_STRUT,
 +    OBT_PROP_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
 +
 +/*
 +    OBT_PROP_ROOTPMAPID,
 +    OBT_PROP_ESETROOTID,
 +*/
 +
 +    /* Openbox specific atoms */
 +
 +    OBT_PROP_OB_WM_ACTION_UNDECORATE,
 +    OBT_PROP_OB_WM_STATE_UNDECORATED,
 +    OBT_PROP_OPENBOX_PID, /* this is depreecated in favour of ob_control */
 +    OBT_PROP_OB_THEME,
 +    OBT_PROP_OB_CONFIG_FILE,
 +    OBT_PROP_OB_CONTROL,
++    OBT_PROP_OB_VERSION,
++    OBT_PROP_OB_APP_ROLE,
++    OBT_PROP_OB_APP_NAME,
++    OBT_PROP_OB_APP_CLASS,
++    OBT_PROP_OB_APP_TYPE,
 +
 +    OBT_PROP_NUM_ATOMS
 +} ObtPropAtom;
 +
 +Atom obt_prop_atom(ObtPropAtom a);
 +
 +gboolean obt_prop_get32(Window win, Atom prop, Atom type, guint32 *ret);
 +gboolean obt_prop_get_array32(Window win, Atom prop, Atom type, guint32 **ret,
 +                              guint *nret);
 +gboolean obt_prop_get_string_locale(Window win, Atom prop, gchar **ret);
 +gboolean obt_prop_get_string_utf8(Window win, Atom prop, gchar **ret);
 +gboolean obt_prop_get_strings_locale(Window win, Atom prop, gchar ***ret);
 +gboolean obt_prop_get_strings_utf8(Window win, Atom prop, gchar ***ret);
 +
 +void obt_prop_set32(Window win, Atom prop, Atom type, gulong val);
 +void obt_prop_set_array32(Window win, Atom prop, Atom type, gulong *val,
 +                          guint num);
 +void obt_prop_set_string_locale(Window win, Atom prop, const gchar *val);
 +void obt_prop_set_string_utf8(Window win, Atom prop, const gchar *val);
 +void obt_prop_set_strings_locale(Window win, Atom prop, const gchar **strs);
 +void obt_prop_set_strings_utf8(Window win, Atom prop, const gchar **strs);
 +
 +void obt_prop_erase(Window win, Atom prop);
 +
 +void obt_prop_message(gint screen, Window about, Atom messagetype,
 +                      glong data0, glong data1, glong data2, glong data3,
 +                      glong data4, glong mask);
 +void obt_prop_message_to(Window to, Window about, Atom messagetype,
 +                         glong data0, glong data1, glong data2, glong data3,
 +                         glong data4, glong mask);
 +
 +#define OBT_PROP_ATOM(prop) obt_prop_atom(OBT_PROP_##prop)
 +
 +#define OBT_PROP_GET32(win, prop, type, ret) \
 +    (obt_prop_get32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), ret))
 +#define OBT_PROP_GETA32(win, prop, type, ret, nret) \
 +    (obt_prop_get_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
 +                          ret, nret))
 +#define OBT_PROP_GETS(win, prop, type, ret) \
 +    (obt_prop_get_string_##type(win, OBT_PROP_ATOM(prop), ret))
 +#define OBT_PROP_GETSS(win, prop, type, ret) \
 +    (obt_prop_get_strings_##type(win, OBT_PROP_ATOM(prop), ret))
 +
 +#define OBT_PROP_SET32(win, prop, type, val) \
 +    (obt_prop_set32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), val))
 +#define OBT_PROP_SETA32(win, prop, type, val, num) \
 +    (obt_prop_set_array32(win, OBT_PROP_ATOM(prop), OBT_PROP_ATOM(type), \
 +                          val, num))
 +#define OBT_PROP_SETS(win, prop, type, val) \
 +    (obt_prop_set_string_##type(win, OBT_PROP_ATOM(prop), val))
 +#define OBT_PROP_SETSS(win, prop, type, strs) \
 +    (obt_prop_set_strings_##type(win, OBT_PROP_ATOM(prop), strs))
 +
 +#define OBT_PROP_ERASE(win, prop) (obt_prop_erase(win, OBT_PROP_ATOM(prop)))
 +
 +#define OBT_PROP_MSG(screen, about, msgtype, data0, data1, data2, data3, \
 +                     data4) \
 +    (obt_prop_message(screen, about, OBT_PROP_ATOM(msgtype), \
 +                      data0, data1, data2, data3, data4, \
 +                      SubstructureNotifyMask | SubstructureRedirectMask))
 +
 +#define OBT_PROP_MSG_TO(to, about, msgtype, data0, data1, data2, data3, \
 +                        data4, mask) \
 +    (obt_prop_message_to(to, about, OBT_PROP_ATOM(msgtype), \
 +                         data0, data1, data2, data3, data4, mask))
 +
 +G_END_DECLS
 +
 +#endif /* __obt_prop_h */
diff --combined openbox/client.c
  #include "debug.h"
  #include "startupnotify.h"
  #include "dock.h"
 -#include "xerror.h"
  #include "screen.h"
  #include "moveresize.h"
  #include "ping.h"
  #include "place.h"
 -#include "prop.h"
 -#include "extensions.h"
  #include "frame.h"
  #include "session.h"
  #include "event.h"
  #include "grab.h"
  #include "prompt.h"
  #include "focus.h"
+ #include "focus_cycle.h"
  #include "stacking.h"
  #include "openbox.h"
  #include "group.h"
  #include "menuframe.h"
  #include "keyboard.h"
  #include "mouse.h"
 -#include "render/render.h"
 +#include "obrender/render.h"
  #include "gettext.h"
 +#include "obt/display.h"
 +#include "obt/prop.h"
  
  #ifdef HAVE_UNISTD_H
  #  include <unistd.h>
@@@ -75,7 -77,7 +76,7 @@@ static RrImage *client_default_ico
  static void client_get_all(ObClient *self, gboolean real);
  static void client_get_startup_id(ObClient *self);
  static void client_get_session_ids(ObClient *self);
- static void client_save_session_ids(ObClient *self);
+ static void client_save_app_rule_values(ObClient *self);
  static void client_get_area(ObClient *self);
  static void client_get_desktop(ObClient *self);
  static void client_get_state(ObClient *self);
@@@ -185,8 -187,8 +186,8 @@@ void client_set_list(void
      } else
          windows = NULL;
  
 -    PROP_SETA32(RootWindow(ob_display, ob_screen),
 -                net_client_list, window, (gulong*)windows, size);
 +    OBT_PROP_SETA32(obt_root(ob_screen), NET_CLIENT_LIST, WINDOW,
 +                    (gulong*)windows, size);
  
      if (windows)
          g_free(windows);
      stacking_set_list();
  }
  
 -void client_manage_all(void)
 -{
 -    guint i, j, nchild;
 -    Window w, *children;
 -    XWMHints *wmhints;
 -    XWindowAttributes attrib;
 -
 -    XQueryTree(ob_display, RootWindow(ob_display, ob_screen),
 -               &w, &w, &children, &nchild);
 -
 -    /* remove all icon windows from the list */
 -    for (i = 0; i < nchild; i++) {
 -        if (children[i] == None) continue;
 -        wmhints = XGetWMHints(ob_display, children[i]);
 -        if (wmhints) {
 -            if ((wmhints->flags & IconWindowHint) &&
 -                (wmhints->icon_window != children[i]))
 -                for (j = 0; j < nchild; j++)
 -                    if (children[j] == wmhints->icon_window) {
 -                        children[j] = None;
 -                        break;
 -                    }
 -            XFree(wmhints);
 -        }
 -    }
 -
 -    /* manage windows in reverse order from how they were originally mapped.
 -       this is an attempt to manage children windows before their parents, so
 -       that when the parent is mapped, it can find the child */
 -    for (i = 0; i < nchild; ++i) {
 -        if (children[i] == None)
 -            continue;
 -        if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
 -            if (attrib.override_redirect) continue;
 -
 -            if (attrib.map_state != IsUnmapped)
 -                client_manage(children[i], NULL);
 -        }
 -    }
 -    XFree(children);
 -}
 -
  void client_manage(Window window, ObPrompt *prompt)
  {
      ObClient *self;
 -    XEvent e;
 -    XWindowAttributes attrib;
      XSetWindowAttributes attrib_set;
 -    XWMHints *wmhint;
      gboolean activate = FALSE;
      ObAppSettings *settings;
      gboolean transient = FALSE;
      Time launch_time, map_time;
      guint32 user_time;
  
 -    grab_server(TRUE);
 -
 -    /* check if it has already been unmapped by the time we started
 -       mapping. the grab does a sync so we don't have to here */
 -    if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
 -        XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
 -    {
 -        XPutBackEvent(ob_display, &e);
 -
 -        ob_debug("Trying to manage unmapped window. Aborting that.\n");
 -        grab_server(FALSE);
 -        return; /* don't manage it */
 -    }
 -
 -    /* make sure it isn't an override-redirect window */
 -    if (!XGetWindowAttributes(ob_display, window, &attrib) ||
 -        attrib.override_redirect)
 -    {
 -        grab_server(FALSE);
 -        return; /* don't manage it */
 -    }
 -
 -    /* is the window a docking app */
 -    if ((wmhint = XGetWMHints(ob_display, window))) {
 -        if ((wmhint->flags & StateHint) &&
 -            wmhint->initial_state == WithdrawnState)
 -        {
 -            dock_add(window, wmhint);
 -            grab_server(FALSE);
 -            XFree(wmhint);
 -            return;
 -        }
 -        XFree(wmhint);
 -    }
 -
 -    ob_debug("Managing window: 0x%lx\n", window);
 +    ob_debug("Managing window: 0x%lx", window);
  
      map_time = event_get_server_time();
  
      attrib_set.event_mask = CLIENT_EVENTMASK |
          (prompt ? prompt->event_mask : 0);
      attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
 -    XChangeWindowAttributes(ob_display, window,
 +    XChangeWindowAttributes(obt_display, window,
                              CWEventMask|CWDontPropagate, &attrib_set);
  
      /* create the ObClient struct, and populate it from the hints on the
         window */
      self = g_new0(ObClient, 1);
 -    self->obwin.type = Window_Client;
 +    self->obwin.type = OB_WINDOW_CLASS_CLIENT;
      self->window = window;
      self->prompt = prompt;
+     self->managed = TRUE;
  
      /* non-zero defaults */
      self->wmstate = WithdrawnState; /* make sure it gets updated first time */
      /* get all the stuff off the window */
      client_get_all(self, TRUE);
  
 -    ob_debug("Window type: %d\n", self->type);
 -    ob_debug("Window group: 0x%x\n", self->group?self->group->leader:0);
 -    ob_debug("Window name: %s class: %s role: %s\n", self->name, self->class, self->role);
 +    ob_debug("Window type: %d", self->type);
 +    ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
 +    ob_debug("Window name: %s class: %s role: %s", self->name, self->class, self->role);
  
      /* per-app settings override stuff from client_get_all, and return the
         settings for other uses too. the returned settings is a shallow copy,
         should be reparented back to root automatically, unless we are managing
         an internal ObPrompt window  */
      if (!self->prompt)
 -        XChangeSaveSet(ob_display, window, SetModeInsert);
 +        XChangeSaveSet(obt_display, window, SetModeInsert);
  
      /* create the decoration frame for the client window */
      self->frame = frame_new(self);
      /* tell startup notification that this app started */
      launch_time = sn_app_started(self->startup_id, self->class, self->name);
  
 -    if (!PROP_GET32(self->window, net_wm_user_time, cardinal, &user_time))
 +    if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time))
          user_time = map_time;
  
      /* do this after we have a frame.. it uses the frame to help determine the
          (user_time != 0) &&
          /* this checks for focus=false for the window */
          (!settings || settings->focus != 0) &&
 -        focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE,
 +        focus_valid_target(self, self->desktop,
 +                           FALSE, FALSE, TRUE, FALSE, FALSE,
                             settings->focus == 1))
      {
          activate = TRUE;
      }
  
      /* remove the client's border */
 -    XSetWindowBorderWidth(ob_display, self->window, 0);
 +    XSetWindowBorderWidth(obt_display, self->window, 0);
  
      /* adjust the frame to the client's size before showing or placing
         the window */
  
      /* figure out placement for the window if the window is new */
      if (ob_state() == OB_STATE_RUNNING) {
 -        ob_debug("Positioned: %s @ %d %d\n",
 +        ob_debug("Positioned: %s @ %d %d",
                   (!self->positioned ? "no" :
                    (self->positioned == PPosition ? "program specified" :
                     (self->positioned == USPosition ? "user specified" :
                       "program + user specified" :
                       "BADNESS !?")))), place.x, place.y);
  
 -        ob_debug("Sized: %s @ %d %d\n",
 +        ob_debug("Sized: %s @ %d %d",
                   (!self->sized ? "no" :
                    (self->sized == PSize ? "program specified" :
                     (self->sized == USSize ? "user specified" :
                       "program + user specified" :
                       "BADNESS !?")))), place.width, place.height);
  
 -        /* splash screens are also returned as TRUE for transient,
 -           and so will be forced on screen below */
 -        transient = place_client(self, &place.x, &place.y, settings);
 +        place_client(self, &place.x, &place.y, settings);
  
          /* make sure the window is visible. */
          client_find_onscreen(self, &place.x, &place.y,
                                  it is up to the placement routines to avoid
                                  the xinerama divides)
  
 -                                splash screens get "transient" set to TRUE by
 -                                the place_client call
 +                                children and splash screens are forced on
 +                                screen, but i don't remember why i decided to
 +                                do that.
                               */
                               ob_state() == OB_STATE_RUNNING &&
 -                             (transient ||
 +                             (self->type == OB_CLIENT_TYPE_DIALOG ||
 +                              self->type == OB_CLIENT_TYPE_SPLASH ||
                                (!((self->positioned & USPosition) ||
                                   (settings && settings->pos_given)) &&
                                 client_normal(self) &&
          place.width = MIN(place.width, a->width);
          place.height = MIN(place.height, a->height);
  
 -        ob_debug("setting window size to %dx%d\n", place.width, place.height);
 +        ob_debug("setting window size to %dx%d", place.width, place.height);
  
          /* get the size of the client back */
          place.width -= self->frame->size.left + self->frame->size.right;
      }
  
      ob_debug("placing window 0x%x at %d, %d with size %d x %d. "
 -             "some restrictions may apply\n",
 +             "some restrictions may apply",
               self->window, place.x, place.y, place.width, place.height);
      if (self->session)
          ob_debug("  but session requested %d, %d  %d x %d instead, "
 -                 "overriding\n",
 +                 "overriding",
                   self->session->x, self->session->y,
                   self->session->w, self->session->h);
  
      g_free(monitor);
      monitor = NULL;
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s\n",
 +    ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
                    activate ? "yes" : "no");
      if (activate) {
          activate = client_can_steal_focus(self, map_time, launch_time);
  
      /* add to client list/map */
      client_list = g_list_append(client_list, self);
 -    g_hash_table_insert(window_map, &self->window, self);
 +    window_add(&self->window, CLIENT_AS_WINDOW(self));
  
      /* this has to happen after we're in the client_list */
      if (STRUT_EXISTS(self->strut))
      /* free the ObAppSettings shallow copy */
      g_free(settings);
  
 -    ob_debug("Managed window 0x%lx plate 0x%x (%s)\n",
 +    ob_debug("Managed window 0x%lx plate 0x%x (%s)",
               window, self->frame->window, self->class);
 -
 -    return;
  }
  
  ObClient *client_fake_manage(Window window)
      ObClient *self;
      ObAppSettings *settings;
  
 -    ob_debug("Pretend-managing window: %lx\n", window);
 +    ob_debug("Pretend-managing window: %lx", window);
  
      /* do this minimal stuff to figure out the client's decorations */
  
      self->frame = frame_new(self);
      frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
  
 -    ob_debug("gave extents left %d right %d top %d bottom %d\n",
 +    ob_debug("gave extents left %d right %d top %d bottom %d",
               self->frame->size.left, self->frame->size.right,
               self->frame->size.top, self->frame->size.bottom);
  
@@@ -528,7 -612,7 +530,7 @@@ void client_unmanage(ObClient *self
      GSList *it;
      gulong ignore_start;
  
 -    ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n",
 +    ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)",
               self->window, self->frame->window,
               self->class, self->title ? self->title : "");
  
  
      /* we dont want events no more. do this before hiding the frame so we
         don't generate more events */
 -    XSelectInput(ob_display, self->window, NoEventMask);
 +    XSelectInput(obt_display, self->window, NoEventMask);
  
      /* ignore enter events from the unmap so it doesnt mess with the focus */
      if (!config_focus_under_mouse)
  
      frame_hide(self->frame);
      /* flush to send the hide to the server quickly */
 -    XFlush(ob_display);
 +    XFlush(obt_display);
  
      if (!config_focus_under_mouse)
          event_end_ignore_all_enters(ignore_start);
  
      mouse_grab_for_client(self, FALSE);
  
+     self->managed = FALSE;
      /* remove the window from our save set, unless we are managing an internal
         ObPrompt window */
      if (!self->prompt)
 -        XChangeSaveSet(ob_display, self->window, SetModeDelete);
 +        XChangeSaveSet(obt_display, self->window, SetModeDelete);
  
      /* update the focus lists */
      focus_order_remove(self);
  
      client_list = g_list_remove(client_list, self);
      stacking_remove(self);
 -    g_hash_table_remove(window_map, &self->window);
 +    window_remove(self->window);
  
      /* once the client is out of the list, update the struts to remove its
         influence */
          self->decorations = 0; /* unmanaged windows have no decor */
  
          /* give the client its border back */
 -        XSetWindowBorderWidth(ob_display, self->window, self->border_width);
 +        XSetWindowBorderWidth(obt_display, self->window, self->border_width);
  
          client_move_resize(self, a.x, a.y, a.width, a.height);
      }
      if (ob_state() != OB_STATE_EXITING) {
          /* these values should not be persisted across a window
             unmapping/mapping */
 -        PROP_ERASE(self->window, net_wm_desktop);
 -        PROP_ERASE(self->window, net_wm_state);
 -        PROP_ERASE(self->window, wm_state);
 +        OBT_PROP_ERASE(self->window, NET_WM_DESKTOP);
 +        OBT_PROP_ERASE(self->window, NET_WM_STATE);
 +        OBT_PROP_ERASE(self->window, WM_STATE);
      } else {
          /* if we're left in an unmapped state, the client wont be mapped.
             this is bad, since we will no longer be managing the window on
             restart */
 -        XMapWindow(ob_display, self->window);
 +        XMapWindow(obt_display, self->window);
      }
  
      /* these should not be left on the window ever.  other window managers
         don't necessarily use them and it will mess them up (like compiz) */
 -    PROP_ERASE(self->window, net_wm_visible_name);
 -    PROP_ERASE(self->window, net_wm_visible_icon_name);
 +    OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_NAME);
 +    OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_ICON_NAME);
  
      /* update the list hints */
      client_set_list();
  
 -    ob_debug("Unmanaged window 0x%lx\n", self->window);
 +    ob_debug("Unmanaged window 0x%lx", self->window);
  
      /* free all data allocated in the client struct */
      RrImageUnref(self->icon_set);
@@@ -697,7 -783,7 +701,7 @@@ static gboolean client_can_steal_focus(
      /* This is focus stealing prevention */
      ob_debug_type(OB_DEBUG_FOCUS,
                    "Want to focus new window 0x%x at time %u "
 -                  "launched at %u (last user interaction time %u)\n",
 +                  "launched at %u (last user interaction time %u)",
                    self->window, steal_time, launch_time,
                    event_last_user_time);
  
              ob_debug_type(OB_DEBUG_FOCUS,
                            "Not focusing the window because the user is "
                            "working in another window that is not "
 -                          "its parent\n");
 +                          "its parent");
          }
          /* If the new window is a transient (and its relatives aren't
             focused) */
              steal = FALSE;
              ob_debug_type(OB_DEBUG_FOCUS,
                            "Not focusing the window because it is a "
 -                          "transient, and its relatives aren't focused\n");
 +                          "transient, and its relatives aren't focused");
          }
          /* Don't steal focus from globally active clients.
             I stole this idea from KWin. It seems nice.
              steal = FALSE;
              ob_debug_type(OB_DEBUG_FOCUS,
                            "Not focusing the window because a globally "
 -                          "active client has focus\n");
 +                          "active client has focus");
          }
          /* Don't move focus if it's not going to go to this window
             anyway */
              steal = FALSE;
              ob_debug_type(OB_DEBUG_FOCUS,
                            "Not focusing the window because another window "
 -                          "would get the focus anyway\n");
 +                          "would get the focus anyway");
          }
          /* Don't move focus if the window is not visible on the current
             desktop and none of its relatives are focused */
      if (!steal)
          ob_debug_type(OB_DEBUG_FOCUS,
                        "Focus stealing prevention activated for %s at "
 -                      "time %u (last user interaction time %u)\n",
 +                      "time %u (last user interaction time %u)",
                        self->title, steal_time, event_last_user_time);
      return steal;
  }
@@@ -791,9 -877,10 +795,9 @@@ static ObAppSettings *client_get_settin
          ObAppSettings *app = it->data;
          gboolean match = TRUE;
  
 -        g_assert(app->name != NULL || app->class != NULL);
 +        g_assert(app->name != NULL || app->class != NULL ||
 +                 app->role != NULL || (signed)app->type >= 0);
  
 -        /* we know that either name or class is not NULL so it will have to
 -           match to use the rule */
          if (app->name &&
              !g_pattern_match(app->name, strlen(self->name), self->name, NULL))
              match = FALSE;
                   !g_pattern_match(app->role,
                                    strlen(self->role), self->role, NULL))
              match = FALSE;
 -        else if ((signed)app->type >= 0 && app->type != self->type)
 +        else if ((signed)app->type >= 0 && app->type != self->type) {
              match = FALSE;
 +        }
  
          if (match) {
 -            ob_debug("Window matching: %s\n", app->name);
 +            ob_debug("Window matching: %s", app->name);
  
              /* copy the settings to our struct, overriding the existing
                 settings if they are not defaults */
@@@ -865,17 -951,17 +869,17 @@@ static void client_restore_session_stat
      GList *it;
  
      ob_debug_type(OB_DEBUG_SM,
 -                  "Restore session for client %s\n", self->title);
 +                  "Restore session for client %s", self->title);
  
      if (!(it = session_state_find(self))) {
          ob_debug_type(OB_DEBUG_SM,
 -                      "Session data not found for client %s\n", self->title);
 +                      "Session data not found for client %s", self->title);
          return;
      }
  
      self->session = it->data;
  
 -    ob_debug_type(OB_DEBUG_SM, "Session data loaded for client %s\n",
 +    ob_debug_type(OB_DEBUG_SM, "Session data loaded for client %s",
                    self->title);
  
      RECT_SET_POINT(self->area, self->session->x, self->session->y);
          self->area.width = self->session->w;
      if (self->session->h > 0)
          self->area.height = self->session->h;
 -    XResizeWindow(ob_display, self->window,
 +    XResizeWindow(obt_display, self->window,
                    self->area.width, self->area.height);
  
      self->desktop = (self->session->desktop == DESKTOP_ALL ?
                       self->session->desktop :
                       MIN(screen_num_desktops - 1, self->session->desktop));
 -    PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
 +    OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, self->desktop);
  
      self->shaded = self->session->shaded;
      self->iconic = self->session->iconic;
@@@ -1078,7 -1164,9 +1082,9 @@@ static void client_get_all(ObClient *se
      /* get the session related properties, these can change decorations
         from per-app settings */
      client_get_session_ids(self);
-     client_save_session_ids(self);
+     /* save the values of the variables used for app rule matching */
+     client_save_app_rule_values(self);
  
      /* now we got everything that can affect the decorations */
      if (!real)
  
  static void client_get_startup_id(ObClient *self)
  {
 -    if (!(PROP_GETS(self->window, net_startup_id, utf8, &self->startup_id)))
 +    if (!(OBT_PROP_GETS(self->window, NET_STARTUP_ID, utf8,
 +                        &self->startup_id)))
          if (self->group)
 -            PROP_GETS(self->group->leader,
 -                      net_startup_id, utf8, &self->startup_id);
 +            OBT_PROP_GETS(self->group->leader,
 +                          NET_STARTUP_ID, utf8, &self->startup_id);
  }
  
  static void client_get_area(ObClient *self)
      XWindowAttributes wattrib;
      Status ret;
  
 -    ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
 +    ret = XGetWindowAttributes(obt_display, self->window, &wattrib);
      g_assert(ret != BadWindow);
  
      RECT_SET(self->area, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
      POINT_SET(self->root_pos, wattrib.x, wattrib.y);
      self->border_width = wattrib.border_width;
  
 -    ob_debug("client area: %d %d  %d %d  bw %d\n", wattrib.x, wattrib.y,
 +    ob_debug("client area: %d %d  %d %d  bw %d", wattrib.x, wattrib.y,
               wattrib.width, wattrib.height, wattrib.border_width);
  }
  
@@@ -1146,12 -1233,12 +1152,12 @@@ static void client_get_desktop(ObClien
  {
      guint32 d = screen_num_desktops; /* an always-invalid value */
  
 -    if (PROP_GET32(self->window, net_wm_desktop, cardinal, &d)) {
 +    if (OBT_PROP_GET32(self->window, NET_WM_DESKTOP, CARDINAL, &d)) {
          if (d >= screen_num_desktops && d != DESKTOP_ALL)
              self->desktop = screen_num_desktops - 1;
          else
              self->desktop = d;
 -        ob_debug("client requested desktop 0x%x\n", self->desktop);
 +        ob_debug("client requested desktop 0x%x", self->desktop);
      } else {
          GSList *it;
          gboolean first = TRUE;
          if (all != screen_num_desktops) {
              self->desktop = all;
  
 -            ob_debug("client desktop set from parents: 0x%x\n",
 +            ob_debug("client desktop set from parents: 0x%x",
                       self->desktop);
          }
          /* try get from the startup-notification protocol */
              if (self->desktop >= screen_num_desktops &&
                  self->desktop != DESKTOP_ALL)
                  self->desktop = screen_num_desktops - 1;
 -            ob_debug("client desktop set from startup-notification: 0x%x\n",
 +            ob_debug("client desktop set from startup-notification: 0x%x",
                       self->desktop);
          }
          /* defaults to the current desktop */
          else {
              self->desktop = screen_desktop;
 -            ob_debug("client desktop set to the current desktop: %d\n",
 +            ob_debug("client desktop set to the current desktop: %d",
                       self->desktop);
          }
      }
@@@ -1199,32 -1286,32 +1205,32 @@@ static void client_get_state(ObClient *
      guint32 *state;
      guint num;
  
 -    if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) {
 +    if (OBT_PROP_GETA32(self->window, NET_WM_STATE, ATOM, &state, &num)) {
          gulong i;
          for (i = 0; i < num; ++i) {
 -            if (state[i] == prop_atoms.net_wm_state_modal)
 +            if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MODAL))
                  self->modal = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_shaded)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SHADED))
                  self->shaded = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_hidden)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN))
                  self->iconic = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_skip_taskbar)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR))
                  self->skip_taskbar = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_skip_pager)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER))
                  self->skip_pager = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_fullscreen)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN))
                  self->fullscreen = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_maximized_vert)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT))
                  self->max_vert = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_maximized_horz)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ))
                  self->max_horz = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_above)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_ABOVE))
                  self->above = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_below)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_BELOW))
                  self->below = TRUE;
 -            else if (state[i] == prop_atoms.net_wm_state_demands_attention)
 +            else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION))
                  self->demands_attention = TRUE;
 -            else if (state[i] == prop_atoms.ob_wm_state_undecorated)
 +            else if (state[i] == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
                  self->undecorated = TRUE;
          }
  
@@@ -1236,14 -1323,14 +1242,14 @@@ static void client_get_shaped(ObClient 
  {
      self->shaped = FALSE;
  #ifdef SHAPE
 -    if (extensions_shape) {
 +    if (obt_display_extension_shape) {
          gint foo;
          guint ufoo;
          gint s;
  
 -        XShapeSelectInput(ob_display, self->window, ShapeNotifyMask);
 +        XShapeSelectInput(obt_display, self->window, ShapeNotifyMask);
  
 -        XShapeQueryExtents(ob_display, self->window, &s, &foo,
 +        XShapeQueryExtents(obt_display, self->window, &s, &foo,
                             &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo,
                             &ufoo);
          self->shaped = !!s;
@@@ -1257,22 -1344,22 +1263,22 @@@ void client_update_transient_for(ObClie
      ObClient *target = NULL;
      gboolean trangroup = FALSE;
  
 -    if (XGetTransientForHint(ob_display, self->window, &t)) {
 +    if (XGetTransientForHint(obt_display, self->window, &t)) {
          if (t != self->window) { /* can't be transient to itself! */
 -            target = g_hash_table_lookup(window_map, &t);
 +            ObWindow *tw = window_find(t);
              /* if this happens then we need to check for it */
 -            g_assert(target != self);
 -            if (target && !WINDOW_IS_CLIENT(target)) {
 +            g_assert(tw != CLIENT_AS_WINDOW(self));
 +            if (tw && WINDOW_IS_CLIENT(tw)) {
                  /* watch out for windows with a parent that is something
                     different, like a dockapp for example */
 -                target = NULL;
 +                target = WINDOW_AS_CLIENT(tw);
              }
          }
  
          /* Setting the transient_for to Root is actually illegal, however
             applications from time have done this to specify transient for
             their group */
 -        if (!target && self->group && t == RootWindow(ob_display, ob_screen))
 +        if (!target && self->group && t == obt_root(ob_screen))
              trangroup = TRUE;
      } else if (self->group && self->transient)
          trangroup = TRUE;
@@@ -1407,8 -1494,8 +1413,8 @@@ void client_get_mwm_hints(ObClient *sel
  
      self->mwmhints.flags = 0; /* default to none */
  
 -    if (PROP_GETA32(self->window, motif_wm_hints, motif_wm_hints,
 -                    &hints, &num)) {
 +    if (OBT_PROP_GETA32(self->window, MOTIF_WM_HINTS, MOTIF_WM_HINTS,
 +                        &hints, &num)) {
          if (num >= OB_MWM_ELEMENTS) {
              self->mwmhints.flags = hints[0];
              self->mwmhints.functions = hints[1];
@@@ -1427,27 -1514,26 +1433,27 @@@ void client_get_type_and_transientness(
      self->type = -1;
      self->transient = FALSE;
  
 -    if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
 +    if (OBT_PROP_GETA32(self->window, NET_WM_WINDOW_TYPE, ATOM, &val, &num)) {
          /* use the first value that we know about in the array */
          for (i = 0; i < num; ++i) {
 -            if (val[i] == prop_atoms.net_wm_window_type_desktop)
 +            if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
                  self->type = OB_CLIENT_TYPE_DESKTOP;
 -            else if (val[i] == prop_atoms.net_wm_window_type_dock)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK))
                  self->type = OB_CLIENT_TYPE_DOCK;
 -            else if (val[i] == prop_atoms.net_wm_window_type_toolbar)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR))
                  self->type = OB_CLIENT_TYPE_TOOLBAR;
 -            else if (val[i] == prop_atoms.net_wm_window_type_menu)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
                  self->type = OB_CLIENT_TYPE_MENU;
 -            else if (val[i] == prop_atoms.net_wm_window_type_utility)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY))
                  self->type = OB_CLIENT_TYPE_UTILITY;
 -            else if (val[i] == prop_atoms.net_wm_window_type_splash)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH))
                  self->type = OB_CLIENT_TYPE_SPLASH;
 -            else if (val[i] == prop_atoms.net_wm_window_type_dialog)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG))
                  self->type = OB_CLIENT_TYPE_DIALOG;
 -            else if (val[i] == prop_atoms.net_wm_window_type_normal)
 +            else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL))
                  self->type = OB_CLIENT_TYPE_NORMAL;
 -            else if (val[i] == prop_atoms.kde_net_wm_window_type_override) {
 +            else if (val[i] == OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE))
 +            {
                  /* prevent this window from getting any decor or
                     functionality */
                  self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS |
          g_free(val);
      }
  
 -    if (XGetTransientForHint(ob_display, self->window, &t))
 +    if (XGetTransientForHint(obt_display, self->window, &t))
          self->transient = TRUE;
  
      if (self->type == (ObClientType) -1) {
  void client_update_protocols(ObClient *self)
  {
      guint32 *proto;
 -    guint num_return, i;
 +    guint num_ret, i;
  
      self->focus_notify = FALSE;
      self->delete_window = FALSE;
  
 -    if (PROP_GETA32(self->window, wm_protocols, atom, &proto, &num_return)) {
 -        for (i = 0; i < num_return; ++i) {
 -            if (proto[i] == prop_atoms.wm_delete_window)
 +    if (OBT_PROP_GETA32(self->window, WM_PROTOCOLS, ATOM, &proto, &num_ret)) {
 +        for (i = 0; i < num_ret; ++i) {
 +            if (proto[i] == OBT_PROP_ATOM(WM_DELETE_WINDOW))
                  /* this means we can request the window to close */
                  self->delete_window = TRUE;
 -            else if (proto[i] == prop_atoms.wm_take_focus)
 +            else if (proto[i] == OBT_PROP_ATOM(WM_TAKE_FOCUS))
                  /* if this protocol is requested, then the window will be
                     notified whenever we want it to receive focus */
                  self->focus_notify = TRUE;
 -            else if (proto[i] == prop_atoms.net_wm_ping)
 +            else if (proto[i] == OBT_PROP_ATOM(NET_WM_PING))
                  /* if this protocol is requested, then the window will allow
                     pings to determine if it is still alive */
                  self->ping = TRUE;
  #ifdef SYNC
 -            else if (proto[i] == prop_atoms.net_wm_sync_request)
 +            else if (proto[i] == OBT_PROP_ATOM(NET_WM_SYNC_REQUEST))
                  /* if this protocol is requested, then resizing the
                     window will be synchronized between the frame and the
                     client */
@@@ -1522,8 -1608,7 +1528,8 @@@ void client_update_sync_request_counter
  {
      guint32 i;
  
 -    if (PROP_GET32(self->window, net_wm_sync_request_counter, cardinal, &i)) {
 +    if (OBT_PROP_GET32(self->window, NET_WM_SYNC_REQUEST_COUNTER, CARDINAL,&i))
 +    {
          self->sync_counter = i;
      } else
          self->sync_counter = None;
@@@ -1534,7 -1619,7 +1540,7 @@@ static void client_get_colormap(ObClien
  {
      XWindowAttributes wa;
  
 -    if (XGetWindowAttributes(ob_display, self->window, &wa))
 +    if (XGetWindowAttributes(obt_display, self->window, &wa))
          client_update_colormap(self, wa.colormap);
  }
  
@@@ -1542,7 -1627,7 +1548,7 @@@ void client_update_colormap(ObClient *s
  {
      if (colormap == self->colormap) return;
  
 -    ob_debug("Setting client %s colormap: 0x%x\n", self->title, colormap);
 +    ob_debug("Setting client %s colormap: 0x%x", self->title, colormap);
  
      if (client_focused(self)) {
          screen_install_colormap(self, FALSE); /* uninstall old one */
@@@ -1566,7 -1651,7 +1572,7 @@@ void client_update_normal_hints(ObClien
      SIZE_SET(self->max_size, G_MAXINT, G_MAXINT);
  
      /* get the hints from the window */
 -    if (XGetWMNormalHints(ob_display, self->window, &size, &ret)) {
 +    if (XGetWMNormalHints(obt_display, self->window, &size, &ret)) {
          /* normal windows can't request placement! har har
          if (!client_normal(self))
          */
          if (size.flags & PResizeInc && size.width_inc && size.height_inc)
              SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
  
 -        ob_debug("Normal hints: min size (%d %d) max size (%d %d)\n   "
 -                 "size inc (%d %d) base size (%d %d)\n",
 +        ob_debug("Normal hints: min size (%d %d) max size (%d %d)",
                   self->min_size.width, self->min_size.height,
 -                 self->max_size.width, self->max_size.height,
 +                 self->max_size.width, self->max_size.height);
 +        ob_debug("size inc (%d %d) base size (%d %d)",
                   self->size_inc.width, self->size_inc.height,
                   self->base_size.width, self->base_size.height);
      }
      else
 -        ob_debug("Normal hints: not set\n");
 +        ob_debug("Normal hints: not set");
  }
  
  void client_setup_decor_and_functions(ObClient *self, gboolean reconfig)
@@@ -1779,38 -1864,38 +1785,38 @@@ static void client_change_allowed_actio
  
      /* desktop windows are kept on all desktops */
      if (self->type != OB_CLIENT_TYPE_DESKTOP)
 -        actions[num++] = prop_atoms.net_wm_action_change_desktop;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP);
  
      if (self->functions & OB_CLIENT_FUNC_SHADE)
 -        actions[num++] = prop_atoms.net_wm_action_shade;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE);
      if (self->functions & OB_CLIENT_FUNC_CLOSE)
 -        actions[num++] = prop_atoms.net_wm_action_close;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE);
      if (self->functions & OB_CLIENT_FUNC_MOVE)
 -        actions[num++] = prop_atoms.net_wm_action_move;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE);
      if (self->functions & OB_CLIENT_FUNC_ICONIFY)
 -        actions[num++] = prop_atoms.net_wm_action_minimize;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE);
      if (self->functions & OB_CLIENT_FUNC_RESIZE)
 -        actions[num++] = prop_atoms.net_wm_action_resize;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE);
      if (self->functions & OB_CLIENT_FUNC_FULLSCREEN)
 -        actions[num++] = prop_atoms.net_wm_action_fullscreen;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN);
      if (self->functions & OB_CLIENT_FUNC_MAXIMIZE) {
 -        actions[num++] = prop_atoms.net_wm_action_maximize_horz;
 -        actions[num++] = prop_atoms.net_wm_action_maximize_vert;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ);
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT);
      }
      if (self->functions & OB_CLIENT_FUNC_ABOVE)
 -        actions[num++] = prop_atoms.net_wm_action_above;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE);
      if (self->functions & OB_CLIENT_FUNC_BELOW)
 -        actions[num++] = prop_atoms.net_wm_action_below;
 +        actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW);
      if (self->functions & OB_CLIENT_FUNC_UNDECORATE)
 -        actions[num++] = prop_atoms.ob_wm_action_undecorate;
 +        actions[num++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE);
  
 -    PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
 +    OBT_PROP_SETA32(self->window, NET_WM_ALLOWED_ACTIONS, ATOM, actions, num);
  
 -   /* make sure the window isn't breaking any rules now
 +    /* make sure the window isn't breaking any rules now
  
 -   don't check ICONIFY here.  just cuz a window can't iconify doesnt mean
 -   it can't be iconified with its parent
 -   */
 +       don't check ICONIFY here.  just cuz a window can't iconify doesnt mean
 +       it can't be iconified with its parent
 +    */
  
      if (!(self->functions & OB_CLIENT_FUNC_SHADE) && self->shaded) {
          if (self->frame) client_shade(self, FALSE);
@@@ -1834,7 -1919,7 +1840,7 @@@ void client_update_wmhints(ObClient *se
      /* assume a window takes input if it doesn't specify */
      self->can_focus = TRUE;
  
 -    if ((hints = XGetWMHints(ob_display, self->window)) != NULL) {
 +    if ((hints = XGetWMHints(obt_display, self->window)) != NULL) {
          gboolean ur;
  
          if (hints->flags & InputHint)
  
          XFree(hints);
      }
+     focus_cycle_addremove(self, TRUE);
  }
  
  void client_update_title(ObClient *self)
      g_free(self->original_title);
  
      /* try netwm */
 -    if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
 +    if (!OBT_PROP_GETS(self->window, NET_WM_NAME, utf8, &data)) {
          /* try old x stuff */
 -        if (!(PROP_GETS(self->window, wm_name, locale, &data)
 -              || PROP_GETS(self->window, wm_name, utf8, &data))) {
 +        if (!(OBT_PROP_GETS(self->window, WM_NAME, locale, &data)
 +              || OBT_PROP_GETS(self->window, WM_NAME, utf8, &data))) {
              if (self->transient) {
      /*
      GNOME alert windows are not given titles:
          g_free(data);
      }
  
 -    PROP_SETS(self->window, net_wm_visible_name, visible);
 +    OBT_PROP_SETS(self->window, NET_WM_VISIBLE_NAME, utf8, visible);
      self->title = visible;
  
      if (self->frame)
      g_free(self->icon_title);
  
      /* try netwm */
 -    if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data))
 +    if (!OBT_PROP_GETS(self->window, NET_WM_ICON_NAME, utf8, &data))
          /* try old x stuff */
 -        if (!(PROP_GETS(self->window, wm_icon_name, locale, &data) ||
 -              PROP_GETS(self->window, wm_icon_name, utf8, &data)))
 +        if (!(OBT_PROP_GETS(self->window, WM_ICON_NAME, locale, &data) ||
 +              OBT_PROP_GETS(self->window, WM_ICON_NAME, utf8, &data)))
              data = g_strdup(self->title);
  
      if (self->client_machine) {
          g_free(data);
      }
  
 -    PROP_SETS(self->window, net_wm_visible_icon_name, visible);
 +    OBT_PROP_SETS(self->window, NET_WM_VISIBLE_ICON_NAME, utf8, visible);
      self->icon_title = visible;
  }
  
@@@ -1997,9 -2084,8 +2005,9 @@@ void client_update_strut(ObClient *self
      gboolean got = FALSE;
      StrutPartial strut;
  
 -    if (PROP_GETA32(self->window, net_wm_strut_partial, cardinal,
 -                    &data, &num)) {
 +    if (OBT_PROP_GETA32(self->window, NET_WM_STRUT_PARTIAL, CARDINAL,
 +                        &data, &num))
 +    {
          if (num == 12) {
              got = TRUE;
              STRUT_PARTIAL_SET(strut,
      }
  
      if (!got &&
 -        PROP_GETA32(self->window, net_wm_strut, cardinal, &data, &num)) {
 +        OBT_PROP_GETA32(self->window, NET_WM_STRUT, CARDINAL, &data, &num)) {
          if (num == 4) {
              Rect *a;
  
@@@ -2060,7 -2146,7 +2068,7 @@@ void client_update_icons(ObClient *self
         icon */
      grab_server(TRUE);
  
 -    if (PROP_GETA32(self->window, net_wm_icon, cardinal, &data, &num)) {
 +    if (OBT_PROP_GETA32(self->window, NET_WM_ICON, CARDINAL, &data, &num)) {
          /* figure out how many valid icons are in here */
          i = 0;
          num_seen = 0;
      if (!img) {
          XWMHints *hints;
  
 -        if ((hints = XGetWMHints(ob_display, self->window))) {
 +        if ((hints = XGetWMHints(obt_display, self->window))) {
              if (hints->flags & IconPixmapHint) {
                  gboolean xicon;
 -                xerror_set_ignore(TRUE);
 +                obt_display_ignore_errors(TRUE);
                  xicon = RrPixmapToRGBA(ob_rr_inst,
                                         hints->icon_pixmap,
                                         (hints->flags & IconMaskHint ?
                                          hints->icon_mask : None),
                                         (gint*)&w, (gint*)&h, &data);
 -                xerror_set_ignore(FALSE);
 +                obt_display_ignore_errors(FALSE);
  
                  if (xicon) {
                      if (w > 0 && h > 0) {
                  (((icon[i] >> RrDefaultRedOffset) & 0xff) << 16) +
                  (((icon[i] >> RrDefaultGreenOffset) & 0xff) << 8) +
                  (((icon[i] >> RrDefaultBlueOffset) & 0xff) << 0);
 -        PROP_SETA32(self->window, net_wm_icon, cardinal, ldata, w*h+2);
 +        OBT_PROP_SETA32(self->window, NET_WM_ICON, CARDINAL, ldata, w*h+2);
          g_free(ldata);
      } else if (self->frame)
          /* don't draw the icon empty if we're just setting one now anyways,
@@@ -2181,8 -2267,7 +2189,8 @@@ void client_update_icon_geometry(ObClie
  
      RECT_SET(self->icon_geometry, 0, 0, 0, 0);
  
 -    if (PROP_GETA32(self->window, net_wm_icon_geometry, cardinal, &data, &num))
 +    if (OBT_PROP_GETA32(self->window, NET_WM_ICON_GEOMETRY, CARDINAL,
 +                        &data, &num))
      {
          if (num == 4)
              /* don't let them set it with an area < 0 */
@@@ -2199,23 -2284,23 +2207,23 @@@ static void client_get_session_ids(ObCl
      gchar *s;
      gchar **ss;
  
 -    if (!PROP_GET32(self->window, wm_client_leader, window, &leader))
 +    if (!OBT_PROP_GET32(self->window, WM_CLIENT_LEADER, WINDOW, &leader))
          leader = None;
  
      /* get the SM_CLIENT_ID */
      got = FALSE;
      if (leader)
 -        got = PROP_GETS(leader, sm_client_id, locale, &self->sm_client_id);
 +        got = OBT_PROP_GETS(leader, SM_CLIENT_ID, locale, &self->sm_client_id);
      if (!got)
 -        PROP_GETS(self->window, sm_client_id, locale, &self->sm_client_id);
 +        OBT_PROP_GETS(self->window, SM_CLIENT_ID, locale, &self->sm_client_id);
  
      /* get the WM_CLASS (name and class). make them "" if they are not
         provided */
      got = FALSE;
      if (leader)
 -        got = PROP_GETSS(leader, wm_class, locale, &ss);
 +        got = OBT_PROP_GETSS(leader, WM_CLASS, locale, &ss);
      if (!got)
 -        got = PROP_GETSS(self->window, wm_class, locale, &ss);
 +        got = OBT_PROP_GETSS(self->window, WM_CLASS, locale, &ss);
  
      if (got) {
          if (ss[0]) {
      /* get the WM_WINDOW_ROLE. make it "" if it is not provided */
      got = FALSE;
      if (leader)
 -        got = PROP_GETS(leader, wm_window_role, locale, &s);
 +        got = OBT_PROP_GETS(leader, WM_WINDOW_ROLE, locale, &s);
      if (!got)
 -        got = PROP_GETS(self->window, wm_window_role, locale, &s);
 +        got = OBT_PROP_GETS(self->window, WM_WINDOW_ROLE, locale, &s);
  
      if (got)
          self->role = s;
      got = FALSE;
  
      if (leader)
 -        got = PROP_GETSS(leader, wm_command, locale, &ss);
 +        got = OBT_PROP_GETSS(leader, WM_COMMAND, locale, &ss);
      if (!got)
 -        got = PROP_GETSS(self->window, wm_command, locale, &ss);
 +        got = OBT_PROP_GETSS(self->window, WM_COMMAND, locale, &ss);
  
      if (got) {
          /* merge/mash them all together */
      /* get the WM_CLIENT_MACHINE */
      got = FALSE;
      if (leader)
 -        got = PROP_GETS(leader, wm_client_machine, locale, &s);
 +        got = OBT_PROP_GETS(leader, WM_CLIENT_MACHINE, locale, &s);
      if (!got)
 -        got = PROP_GETS(self->window, wm_client_machine, locale, &s);
 +        got = OBT_PROP_GETS(self->window, WM_CLIENT_MACHINE, locale, &s);
  
      if (got) {
          gchar localhost[128];
  
          /* see if it has the PID set too (the PID requires that the
             WM_CLIENT_MACHINE be set) */
 -        if (PROP_GET32(self->window, net_wm_pid, cardinal, &pid))
 +        if (OBT_PROP_GET32(self->window, NET_WM_PID, CARDINAL, &pid))
              self->pid = pid;
      }
  }
  
- /*! Save the session IDs as seen by Openbox when the window mapped, so that
-   users can still access them later if the app changes them */
- static void client_save_session_ids(ObClient *self)
+ /*! Save the properties used for app matching rules, as seen by Openbox when
+   the window mapped, so that users can still access them later if the app
+   changes them */
+ static void client_save_app_rule_values(ObClient *self)
  {
-     OBT_PROP_SETS(self->window, OB_ROLE, utf8, self->role);
-     OBT_PROP_SETS(self->window, OB_NAME, utf8, self->name);
-     OBT_PROP_SETS(self->window, OB_CLASS, utf8, self->class);
+     const gchar *type;
 -    PROP_SETS(self->window, ob_app_role, self->role);
 -    PROP_SETS(self->window, ob_app_name, self->name);
 -    PROP_SETS(self->window, ob_app_class, self->class);
++    OBT_PROP_SETS(self->window, OB_APP_ROLE, utf8, self->role);
++    OBT_PROP_SETS(self->window, OB_APP_NAME, utf8, self->name);
++    OBT_PROP_SETS(self->window, OB_APP_CLASS, utf8, self->class);
+     switch (self->type) {
+     case OB_CLIENT_TYPE_NORMAL:
+         type = "normal"; break;
+     case OB_CLIENT_TYPE_DIALOG:
+         type = "dialog"; break;
+     case OB_CLIENT_TYPE_UTILITY:
+         type = "utility"; break;
+     case OB_CLIENT_TYPE_MENU:
+         type = "menu"; break;
+     case OB_CLIENT_TYPE_TOOLBAR:
+         type = "toolbar"; break;
+     case OB_CLIENT_TYPE_SPLASH:
+         type = "splash"; break;
+     case OB_CLIENT_TYPE_DESKTOP:
+         type = "desktop"; break;
+     case OB_CLIENT_TYPE_DOCK:
+         type = "dock"; break;
+     }
 -    PROP_SETS(self->window, ob_app_type, type);
++    OBT_PROP_SETS(self->window, OB_APP_TYPE, utf8, type);
  }
  
  static void client_change_wm_state(ObClient *self)
          self->wmstate = NormalState;
  
      if (old != self->wmstate) {
 -        PROP_MSG(self->window, kde_wm_change_state,
 -                 self->wmstate, 1, 0, 0);
 +        OBT_PROP_MSG(ob_screen, self->window, KDE_WM_CHANGE_STATE,
 +                     self->wmstate, 1, 0, 0, 0);
  
          state[0] = self->wmstate;
          state[1] = None;
 -        PROP_SETA32(self->window, wm_state, wm_state, state, 2);
 +        OBT_PROP_SETA32(self->window, WM_STATE, WM_STATE, state, 2);
      }
  }
  
@@@ -2332,30 -2440,30 +2363,30 @@@ static void client_change_state(ObClien
  
      num = 0;
      if (self->modal)
 -        netstate[num++] = prop_atoms.net_wm_state_modal;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
      if (self->shaded)
 -        netstate[num++] = prop_atoms.net_wm_state_shaded;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED);
      if (self->iconic)
 -        netstate[num++] = prop_atoms.net_wm_state_hidden;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN);
      if (self->skip_taskbar)
 -        netstate[num++] = prop_atoms.net_wm_state_skip_taskbar;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR);
      if (self->skip_pager)
 -        netstate[num++] = prop_atoms.net_wm_state_skip_pager;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER);
      if (self->fullscreen)
 -        netstate[num++] = prop_atoms.net_wm_state_fullscreen;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN);
      if (self->max_vert)
 -        netstate[num++] = prop_atoms.net_wm_state_maximized_vert;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT);
      if (self->max_horz)
 -        netstate[num++] = prop_atoms.net_wm_state_maximized_horz;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ);
      if (self->above)
 -        netstate[num++] = prop_atoms.net_wm_state_above;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE);
      if (self->below)
 -        netstate[num++] = prop_atoms.net_wm_state_below;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW);
      if (self->demands_attention)
 -        netstate[num++] = prop_atoms.net_wm_state_demands_attention;
 +        netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
      if (self->undecorated)
 -        netstate[num++] = prop_atoms.ob_wm_state_undecorated;
 -    PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
 +        netstate[num++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
 +    OBT_PROP_SETA32(self->window, NET_WM_STATE, ATOM, netstate, num);
  
      if (self->frame)
          frame_adjust_state(self->frame);
@@@ -2380,7 -2488,7 +2411,7 @@@ ObClient *client_search_focus_tree_full
  
          for (it = self->parents; it; it = g_slist_next(it)) {
              ObClient *c = it->data;
 -            if ((c = client_search_focus_tree_full(it->data))) return c;
 +            if ((c = client_search_focus_tree_full(c))) return c;
          }
  
          return NULL;
@@@ -2649,7 -2757,7 +2680,7 @@@ static void client_apply_startup_state(
         pre-max/pre-fullscreen values
      */
      client_try_configure(self, &x, &y, &w, &h, &l, &l, FALSE);
 -    ob_debug("placed window 0x%x at %d, %d with size %d x %d\n",
 +    ob_debug("placed window 0x%x at %d, %d with size %d x %d",
               self->window, x, y, w, h);
      /* save the area, and make it where it should be for the premax stuff */
      oldarea = self->area;
      client_configure(self, x, y, w, h, FALSE, TRUE, FALSE);
  
      /* set the desktop hint, to make sure that it always exists */
 -    PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
 +    OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, self->desktop);
  
      /* nothing to do for the other states:
         skip_taskbar
@@@ -2967,7 -3075,7 +2998,7 @@@ void client_configure(ObClient *self, g
  
      /* if the client is enlarging, then resize the client before the frame */
      if (send_resize_client && (w > oldw || h > oldh)) {
 -        XMoveResizeWindow(ob_display, self->window,
 +        XMoveResizeWindow(obt_display, self->window,
                            self->frame->size.left, self->frame->size.top,
                            MAX(w, oldw), MAX(h, oldh));
          frame_adjust_client_area(self->frame);
          XEvent event;
  
          event.type = ConfigureNotify;
 -        event.xconfigure.display = ob_display;
 +        event.xconfigure.display = obt_display;
          event.xconfigure.event = self->window;
          event.xconfigure.window = self->window;
  
 -        ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d\n",
 +        ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d",
                   self->title, self->root_pos.x, self->root_pos.y, w, h);
  
          /* root window real coords */
       */
      if (send_resize_client && (w <= oldw || h <= oldh)) {
          frame_adjust_client_area(self->frame);
 -        XMoveResizeWindow(ob_display, self->window,
 +        XMoveResizeWindow(obt_display, self->window,
                            self->frame->size.left, self->frame->size.top, w, h);
      }
  
 -    XFlush(ob_display);
 +    XFlush(obt_display);
  
      /* if it moved between monitors, then this can affect the stacking
         layer of this window or others - for fullscreen windows */
@@@ -3114,7 -3222,7 +3145,7 @@@ void client_fullscreen(ObClient *self, 
          RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0);
      }
  
 -    ob_debug("Window %s going fullscreen (%d)\n",
 +    ob_debug("Window %s going fullscreen (%d)",
               self->title, self->fullscreen);
  
      client_setup_decor_and_functions(self, FALSE);
@@@ -3139,7 -3247,7 +3170,7 @@@ static void client_iconify_recursive(Ob
      gboolean changed = FALSE;
  
      if (self->iconic != iconic) {
 -        ob_debug("%sconifying window: 0x%lx\n", (iconic ? "I" : "Uni"),
 +        ob_debug("%sconifying window: 0x%lx", (iconic ? "I" : "Uni"),
                   self->window);
  
          if (iconic) {
                  self->iconic = iconic;
  
                  /* update the focus lists.. iconic windows go to the bottom of
-                    the list */
+                    the list. this will also call focus_cycle_addremove(). */
                  focus_order_to_bottom(self);
  
                  changed = TRUE;
                  self->desktop != DESKTOP_ALL)
                  client_set_desktop(self, screen_desktop, FALSE, FALSE);
  
-             /* this puts it after the current focused window */
-             focus_order_remove(self);
-             focus_order_add_new(self);
+             /* this puts it after the current focused window, this will
+                also cause focus_cycle_addremove() to be called for the
+                client */
+             focus_order_like_new(self);
  
              changed = TRUE;
          }
@@@ -3314,12 -3423,12 +3346,12 @@@ void client_close(ObClient *self
      if (!self->delete_window)
          /* don't use client_kill(), we should only kill based on PID in
             response to a lack of PING replies */
 -        XKillClient(ob_display, self->window);
 +        XKillClient(obt_display, self->window);
      else {
          /* request the client to close with WM_DELETE_WINDOW */
 -        PROP_MSG_TO(self->window, self->window, wm_protocols,
 -                    prop_atoms.wm_delete_window, event_curtime, 0, 0, 0,
 -                    NoEventMask);
 +        OBT_PROP_MSG_TO(self->window, self->window, WM_PROTOCOLS,
 +                        OBT_PROP_ATOM(WM_DELETE_WINDOW), event_curtime,
 +                        0, 0, 0, NoEventMask);
  
          /* we're trying to close the window, so see if it is responding. if it
             is not, then we will let them kill the window */
@@@ -3427,14 -3536,14 +3459,14 @@@ void client_kill(ObClient *self
              client_update_title(self);
          }
          else {
 -            ob_debug("killing window 0x%x with pid %lu, with SIGKILL\n",
 +            ob_debug("killing window 0x%x with pid %lu, with SIGKILL",
                       self->window, self->pid);
              kill(self->pid, SIGKILL); /* kill -9 */
          }
      }
      else {
          /* running on a remote host */
 -        XKillClient(ob_display, self->window);
 +        XKillClient(obt_display, self->window);
      }
  }
  
@@@ -3474,13 -3583,13 +3506,13 @@@ static void client_set_desktop_recursiv
  
      if (target != self->desktop && self->type != OB_CLIENT_TYPE_DESKTOP) {
  
 -        ob_debug("Setting desktop %u\n", target+1);
 +        ob_debug("Setting desktop %u", target+1);
  
          g_assert(target < screen_num_desktops || target == DESKTOP_ALL);
  
          old = self->desktop;
          self->desktop = target;
 -        PROP_SET32(self->window, net_wm_desktop, cardinal, target);
 +        OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, target);
          /* the frame can display the current desktop state */
          frame_adjust_state(self->frame);
          /* 'move' the window to the new desktop */
              /* the new desktop's geometry may be different, so we may need to
                 resize, for example if we are maximized */
              client_reconfigure(self, FALSE);
+         focus_cycle_addremove(self, FALSE);
      }
  
      /* move all transients */
@@@ -3511,6 -3622,8 +3545,8 @@@ void client_set_desktop(ObClient *self
  {
      self = client_search_top_direct_parent(self);
      client_set_desktop_recursive(self, target, donthide, dontraise);
+     focus_cycle_addremove(NULL, TRUE);
  }
  
  gboolean client_is_direct_child(ObClient *parent, ObClient *child)
@@@ -3537,14 -3650,14 +3573,14 @@@ static gboolean client_validate_unmap(O
      XEvent e;
      gboolean ret = TRUE;
  
 -    if (XCheckTypedWindowEvent(ob_display, self->window, UnmapNotify, &e)) {
 +    if (XCheckTypedWindowEvent(obt_display, self->window, UnmapNotify, &e)) {
          if (n < self->ignore_unmaps) // ignore this one, but look for more
              ret = client_validate_unmap(self, n+1);
          else
              ret = FALSE; // the window is going to become unmanaged
  
          /* put them back on the event stack so they end up in the same order */
 -        XPutBackEvent(ob_display, &e);
 +        XPutBackEvent(obt_display, &e);
      }
  
      return ret;
@@@ -3554,10 -3667,10 +3590,10 @@@ gboolean client_validate(ObClient *self
  {
      XEvent e;
  
 -    XSync(ob_display, FALSE); /* get all events on the server */
 +    XSync(obt_display, FALSE); /* get all events on the server */
  
 -    if (XCheckTypedWindowEvent(ob_display, self->window, DestroyNotify, &e)) {
 -        XPutBackEvent(ob_display, &e);
 +    if (XCheckTypedWindowEvent(obt_display, self->window, DestroyNotify, &e)) {
 +        XPutBackEvent(obt_display, &e);
          return FALSE;
      }
  
@@@ -3594,11 -3707,10 +3630,11 @@@ void client_set_state(ObClient *self, A
      gboolean above = self->above;
      gboolean below = self->below;
      gint i;
 +    gboolean value;
  
 -    if (!(action == prop_atoms.net_wm_state_add ||
 -          action == prop_atoms.net_wm_state_remove ||
 -          action == prop_atoms.net_wm_state_toggle))
 +    if (!(action == OBT_PROP_ATOM(NET_WM_STATE_ADD) ||
 +          action == OBT_PROP_ATOM(NET_WM_STATE_REMOVE) ||
 +          action == OBT_PROP_ATOM(NET_WM_STATE_TOGGLE)))
          /* an invalid action was passed to the client message, ignore it */
          return;
  
          if (!state) continue;
  
          /* if toggling, then pick whether we're adding or removing */
 -        if (action == prop_atoms.net_wm_state_toggle) {
 -            if (state == prop_atoms.net_wm_state_modal)
 -                action = modal ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_maximized_vert)
 -                action = self->max_vert ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_maximized_horz)
 -                action = self->max_horz ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_shaded)
 -                action = shaded ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_skip_taskbar)
 -                action = self->skip_taskbar ?
 -                    prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_skip_pager)
 -                action = self->skip_pager ?
 -                    prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_hidden)
 -                action = self->iconic ?
 -                    prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_fullscreen)
 -                action = fullscreen ?
 -                    prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_above)
 -                action = self->above ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_below)
 -                action = self->below ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.net_wm_state_demands_attention)
 -                action = self->demands_attention ?
 -                    prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 -            else if (state == prop_atoms.ob_wm_state_undecorated)
 -                action = undecorated ? prop_atoms.net_wm_state_remove :
 -                    prop_atoms.net_wm_state_add;
 +        if (action == OBT_PROP_ATOM(NET_WM_STATE_TOGGLE)) {
 +            if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL))
 +                value = modal;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT))
 +                value = self->max_vert;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ))
 +                value = self->max_horz;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED))
 +                value = shaded;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR))
 +                value = self->skip_taskbar;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER))
 +                value = self->skip_pager;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN))
 +                value = self->iconic;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN))
 +                value = fullscreen;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE))
 +                value = self->above;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW))
 +                value = self->below;
 +            else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION))
 +                value = self->demands_attention;
 +            else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
 +                value = undecorated;
 +            else
 +                g_assert_not_reached();
 +            action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) :
 +                             OBT_PROP_ATOM(NET_WM_STATE_ADD);
          }
  
 -        if (action == prop_atoms.net_wm_state_add) {
 -            if (state == prop_atoms.net_wm_state_modal) {
 -                modal = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_maximized_vert) {
 -                max_vert = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_maximized_horz) {
 -                max_horz = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_shaded) {
 -                shaded = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_skip_taskbar) {
 -                self->skip_taskbar = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_skip_pager) {
 -                self->skip_pager = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_hidden) {
 -                iconic = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_fullscreen) {
 -                fullscreen = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_above) {
 -                above = TRUE;
 +        value = action == OBT_PROP_ATOM(NET_WM_STATE_ADD);
 +        if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) {
 +            modal = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) {
 +            max_vert = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) {
 +            max_horz = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) {
 +            shaded = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) {
 +            self->skip_taskbar = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) {
 +            self->skip_pager = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) {
 +            iconic = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) {
 +            fullscreen = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) {
 +            above = value;
 +            /* only unset below when setting above, otherwise you can't get to
 +               the normal layer */
 +            if (value)
                  below = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_below) {
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) {
 +            /* and vice versa */
 +            if (value)
                  above = FALSE;
 -                below = TRUE;
 -            } else if (state == prop_atoms.net_wm_state_demands_attention) {
 -                demands_attention = TRUE;
 -            } else if (state == prop_atoms.ob_wm_state_undecorated) {
 -                undecorated = TRUE;
 -            }
 -
 -        } else { /* action == prop_atoms.net_wm_state_remove */
 -            if (state == prop_atoms.net_wm_state_modal) {
 -                modal = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_maximized_vert) {
 -                max_vert = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_maximized_horz) {
 -                max_horz = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_shaded) {
 -                shaded = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_skip_taskbar) {
 -                self->skip_taskbar = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_skip_pager) {
 -                self->skip_pager = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_hidden) {
 -                iconic = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_fullscreen) {
 -                fullscreen = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_above) {
 -                above = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_below) {
 -                below = FALSE;
 -            } else if (state == prop_atoms.net_wm_state_demands_attention) {
 -                demands_attention = FALSE;
 -            } else if (state == prop_atoms.ob_wm_state_undecorated) {
 -                undecorated = FALSE;
 -            }
 +            below = value;
 +        } else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)){
 +            demands_attention = value;
 +        } else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) {
 +            undecorated = value;
          }
      }
  
          client_hilite(self, demands_attention);
  
      client_change_state(self); /* change the hint to reflect these changes */
+     focus_cycle_addremove(self, TRUE);
  }
  
  ObClient *client_focus_target(ObClient *self)
@@@ -3760,47 -3910,47 +3798,47 @@@ gboolean client_focus(ObClient *self
  
      if (!client_can_focus(self)) {
          ob_debug_type(OB_DEBUG_FOCUS,
 -                      "Client %s can't be focused\n", self->title);
 +                      "Client %s can't be focused", self->title);
          return FALSE;
      }
  
      ob_debug_type(OB_DEBUG_FOCUS,
 -                  "Focusing client \"%s\" (0x%x) at time %u\n",
 +                  "Focusing client \"%s\" (0x%x) at time %u",
                    self->title, self->window, event_curtime);
  
      /* if using focus_delay, stop the timer now so that focus doesn't
         go moving on us */
      event_halt_focus_delay();
  
 -    xerror_set_ignore(TRUE);
 -    xerror_occured = FALSE;
 +    obt_display_ignore_errors(TRUE);
  
      if (self->can_focus) {
          /* This can cause a BadMatch error with CurrentTime, or if an app
             passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
 -        XSetInputFocus(ob_display, self->window, RevertToPointerRoot,
 +        XSetInputFocus(obt_display, self->window, RevertToPointerRoot,
                         event_curtime);
      }
  
      if (self->focus_notify) {
          XEvent ce;
          ce.xclient.type = ClientMessage;
 -        ce.xclient.message_type = prop_atoms.wm_protocols;
 -        ce.xclient.display = ob_display;
 +        ce.xclient.message_type = OBT_PROP_ATOM(WM_PROTOCOLS);
 +        ce.xclient.display = obt_display;
          ce.xclient.window = self->window;
          ce.xclient.format = 32;
 -        ce.xclient.data.l[0] = prop_atoms.wm_take_focus;
 +        ce.xclient.data.l[0] = OBT_PROP_ATOM(WM_TAKE_FOCUS);
          ce.xclient.data.l[1] = event_curtime;
          ce.xclient.data.l[2] = 0l;
          ce.xclient.data.l[3] = 0l;
          ce.xclient.data.l[4] = 0l;
 -        XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
 +        XSendEvent(obt_display, self->window, FALSE, NoEventMask, &ce);
      }
  
 -    xerror_set_ignore(FALSE);
 +    obt_display_ignore_errors(FALSE);
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d\n", xerror_occured);
 -    return !xerror_occured;
 +    ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d",
 +                  obt_display_error_occured);
 +    return !obt_display_error_occured;
  }
  
  static void client_present(ObClient *self, gboolean here, gboolean raise,
@@@ -4116,15 -4266,15 +4154,15 @@@ static void detect_edge(Rect area, ObDi
              g_assert_not_reached();
      }
  
 -    ob_debug("my head %d size %d\n", my_head, my_size);
 -    ob_debug("head %d tail %d dest %d\n", head, tail, *dest);
 +    ob_debug("my head %d size %d", my_head, my_size);
 +    ob_debug("head %d tail %d dest %d", head, tail, *dest);
      if (!skip_head) {
 -        ob_debug("using near edge %d\n", head);
 +        ob_debug("using near edge %d", head);
          *dest = head;
          *near_edge = TRUE;
      }
      else if (!skip_tail) {
 -        ob_debug("using far edge %d\n", tail);
 +        ob_debug("using far edge %d", tail);
          *dest = tail;
          *near_edge = FALSE;
      }
@@@ -4185,7 -4335,7 +4223,7 @@@ void client_find_edge_directional(ObCli
              cur->desktop != screen_desktop)
              continue;
  
 -        ob_debug("trying window %s\n", cur->title);
 +        ob_debug("trying window %s", cur->title);
  
          detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
                      my_edge_size, dest, near_edge);
@@@ -4305,10 -4455,10 +4343,10 @@@ void client_find_resize_directional(ObC
          g_assert_not_reached();
      }
  
 -    ob_debug("head %d dir %d\n", head, dir);
 +    ob_debug("head %d dir %d", head, dir);
      client_find_edge_directional(self, dir, head, 1,
                                   e_start, e_size, &e, &near);
 -    ob_debug("edge %d\n", e);
 +    ob_debug("edge %d", e);
      *x = self->frame->area.x;
      *y = self->frame->area.y;
      *w = self->frame->area.width;
diff --combined openbox/client.h
@@@ -25,7 -25,7 +25,7 @@@
  #include "geom.h"
  #include "stacking.h"
  #include "window.h"
 -#include "render/color.h"
 +#include "obrender/color.h"
  
  #include <glib.h>
  #include <X11/Xlib.h>
@@@ -73,6 -73,7 +73,7 @@@ struct _ObClien
  {
      ObWindow obwin;
      Window  window;
+     gboolean managed;
  
      /*! If this client is managing an ObPrompt window, then this is set to the
        prompt */
@@@ -323,13 -324,15 +324,13 @@@ typedef void (*ObClientCallback)(ObClie
  void client_add_destroy_notify(ObClientCallback func, gpointer data);
  void client_remove_destroy_notify(ObClientCallback func);
  
 -/*! Manages all existing windows */
 -void client_manage_all();
  /*! Manages a given window
    @param prompt This specifies an ObPrompt which is being managed.  It is
                  possible to manage Openbox-owned windows through this.
  */
  void client_manage(Window win, struct _ObPrompt *prompt);
  /*! Unmanages all managed windows */
 -void client_unmanage_all();
 +void client_unmanage_all(void);
  /*! Unmanages a given client */
  void client_unmanage(ObClient *client);
  
@@@ -342,7 -345,7 +343,7 @@@ ObClient *client_fake_manage(Window win
  void client_fake_unmanage(ObClient *self);
  
  /*! Sets the client list on the root window from the client_list */
 -void client_set_list();
 +void client_set_list(void);
  
  /*! Determines if the client should be shown or hidden currently.
    @return TRUE if it should be visible; otherwise, FALSE.
@@@ -728,7 -731,7 +729,7 @@@ void client_set_layer(ObClient *self, g
  
  guint client_monitor(ObClient *self);
  
 -ObClient* client_under_pointer();
 +ObClient* client_under_pointer(void);
  
  gboolean client_has_group_siblings(ObClient *self);
  
diff --combined openbox/event.c
@@@ -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,20 -87,19 +84,20 @@@ 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);
  static void event_handle_client(ObClient *c, XEvent *e);
 -static void event_handle_user_input(ObClient *client, XEvent *e);
 +static gboolean event_handle_user_input(ObClient *client, XEvent *e);
  static gboolean is_enter_focus_event_ignored(gulong serial);
  static void event_ignore_enter_range(gulong start, gulong end);
  
  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,48 -454,45 +462,48 @@@ 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;
 +    gboolean used;
  
      /* make a copy we can mangle */
      ee = *ec;
      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)
      }
  #endif
  
 -    if (prompt && event_handle_prompt(prompt, e))
 -        ;
 -    else if (e->type == ButtonPress || e->type == ButtonRelease) {
 +    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);
 +            used = event_handle_user_input(client, e);
          }
          /* Otherwise only process it if it was physically on an openbox
             internal window */
          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);
 +                used = event_handle_user_input(client, e);
              }
          }
      }
      else if (e->type == KeyPress || e->type == KeyRelease ||
               e->type == MotionNotify)
 -        event_handle_user_input(client, e);
 +        used = event_handle_user_input(client, e);
 +
 +    if (prompt && !used)
 +        used = event_handle_prompt(prompt, e);
  
      /* if something happens and it's not from an XEvent, then we don't know
         the time */
@@@ -757,7 -747,7 +757,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:
@@@ -827,17 -817,17 +827,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) {
@@@ -922,12 -877,12 +922,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;
@@@ -1046,24 -1001,21 +1046,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);
              }
@@@ -1693,11 -1623,11 +1693,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);
@@@ -1744,165 -1674,144 +1744,180 @@@ 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;
 +
 +        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;
  
 -    /* Allow control while going thru the menu */
 -    else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
 -        frame->got_press = TRUE;
 +        keycode = ev->xkey.keycode;
 +        state = ev->xkey.state;
 +        unikey = obt_keyboard_keycode_to_unichar(keycode);
  
 -        if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
 -            menu_frame_hide_all();
 -            ret = TRUE;
 -        }
 +        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->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
 -                /* make sure it is visible */
 -                menu_frame_select(frame, frame->selected, TRUE);
 -                menu_frame_select_next(frame->child);
 +            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);
 +                }
 +                ret = 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);
++                if (frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
++                {
++                    /* make sure it is visible */
++                    menu_frame_select(frame, frame->selected, TRUE);
++                    menu_frame_select_next(frame->child);
++                }
 +                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_UP)) {
 +                menu_frame_select_previous(frame);
 +                ret = TRUE;
 +            }
  
 -        else if (ob_keycode_match(keycode, OB_KEY_HOME)) {
 -            menu_frame_select_first(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_END)) {
 -            menu_frame_select_last(frame);
 -            ret = TRUE;
++            else if (ob_keycode_match(keycode, OB_KEY_HOME)) {
++                menu_frame_select_first(frame);
++                ret = TRUE;
++            }
++
++            else if (ob_keycode_match(keycode, OB_KEY_END)) {
++                menu_frame_select_last(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;
 +                }
  
 -                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;
 +                it = start;
 +                do {
 +                    ObMenuEntryFrame *e = it->data;
 +                    gunichar entrykey = 0;
  
 -                if (unikey == entrykey) {
 -                    if (found == NULL) found = e;
 -                    ++num_found;
 -                }
 +                    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;
  
 -                /* next with wraparound */
 -                it = g_list_next(it);
 -                if (it == NULL) it = frame->entries;
 -            } while (it != start);
 +                    if (unikey == entrykey) {
 +                        if (found == NULL) found = e;
 +                        ++num_found;
 +                    }
  
 -            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);
 -                }
 +                    /* next with wraparound */
 +                    it = g_list_next(it);
 +                    if (it == NULL) it = frame->entries;
 +                } while (it != start);
  
 -                ret = TRUE;
 +                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;
 +                }
              }
          }
      }
@@@ -1919,12 -1828,27 +1934,12 @@@ static Bool event_look_for_menu_enter(D
          !e->ignore_enters && e->frame == f;
  }
  
 -static gboolean event_handle_menu(XEvent *ev)
 +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)
  
              /* 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)
 +static gboolean event_handle_user_input(ObClient *client, XEvent *e)
  {
      g_assert(e->type == ButtonPress || e->type == ButtonRelease ||
               e->type == MotionNotify || e->type == KeyPress ||
               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 */
 -            return;
 +            return TRUE;
      }
  
      /* if the keyboard interactive action uses the event then dont
         use it for bindings. likewise is moveresize uses the event. */
 -    if (!actions_interactive_input_event(e) && !moveresize_event(e)) {
 -        if (moveresize_in_progress)
 -            /* make further actions work on the client being
 -               moved/resized */
 -            client = moveresize_client;
 -
 -        if (e->type == ButtonPress ||
 -            e->type == ButtonRelease ||
 -            e->type == MotionNotify)
 -        {
 -            /* the frame may not be "visible" but they can still click on it
 -               in the case where it is animating before disappearing */
 -            if (!client || !frame_iconify_animating(client->frame))
 -                mouse_event(client, e);
 -        } else
 -            keyboard_event((focus_cycle_target ? focus_cycle_target :
 -                            (client ? client : focus_client)), e);
 -    }
 +    if (actions_interactive_input_event(e) || moveresize_event(e))
 +        return TRUE;
 +
 +    if (moveresize_in_progress)
 +        /* make further actions work on the client being
 +           moved/resized */
 +        client = moveresize_client;
 +
 +    if (e->type == ButtonPress ||
 +        e->type == ButtonRelease ||
 +        e->type == MotionNotify)
 +    {
 +        /* the frame may not be "visible" but they can still click on it
 +           in the case where it is animating before disappearing */
 +        if (!client || !frame_iconify_animating(client->frame))
 +            return mouse_event(client, e);
 +    } else
 +        return keyboard_event((focus_cycle_target ? focus_cycle_target :
 +                               (client ? client : focus_client)), e);
 +
 +    return FALSE;
  }
  
  static void focus_delay_dest(gpointer data)
@@@ -2020,37 -1955,22 +2035,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)
@@@ -2107,24 -2027,24 +2122,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)
@@@ -2159,9 -2079,9 +2174,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.c
  #include "group.h"
  #include "focus_cycle.h"
  #include "screen.h"
 -#include "prop.h"
  #include "keyboard.h"
  #include "focus.h"
  #include "stacking.h"
 +#include "obt/prop.h"
  
  #include <X11/Xlib.h>
  #include <glib.h>
@@@ -52,7 -52,7 +52,7 @@@ void focus_shutdown(gboolean reconfig
      if (reconfig) return;
  
      /* reset focus to root */
 -    XSetInputFocus(ob_display, PointerRoot, RevertToNone, CurrentTime);
 +    XSetInputFocus(obt_display, PointerRoot, RevertToNone, CurrentTime);
  }
  
  static void push_to_top(ObClient *client)
@@@ -74,7 -74,7 +74,7 @@@ void focus_set_client(ObClient *client
      Window active;
  
      ob_debug_type(OB_DEBUG_FOCUS,
 -                  "focus_set_client 0x%lx\n", client ? client->window : 0);
 +                  "focus_set_client 0x%lx", client ? client->window : 0);
  
      if (focus_client == client)
          return;
          push_to_top(client);
          /* remove hiliting from the window when it gets focused */
          client_hilite(client, FALSE);
+         /* make sure the focus cycle popup shows things in the right order */
+         focus_cycle_reorder();
      }
  
      /* set the NET_ACTIVE_WINDOW hint, but preserve it on shutdown */
      if (ob_state() != OB_STATE_EXITING) {
          active = client ? client->window : None;
 -        PROP_SET32(RootWindow(ob_display, ob_screen),
 -                   net_active_window, window, active);
 +        OBT_PROP_SET32(obt_root(ob_screen), NET_ACTIVE_WINDOW, WINDOW, active);
      }
  }
  
@@@ -107,18 -111,18 +110,18 @@@ static ObClient* focus_fallback_target(
      GList *it;
      ObClient *c;
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff\n");
 +    ob_debug_type(OB_DEBUG_FOCUS, "trying pointer stuff");
      if (allow_pointer && config_focus_follow)
          if ((c = client_under_pointer()) &&
              (allow_refocus || client_focus_target(c) != old) &&
              (client_normal(c) &&
               client_focus(c)))
          {
 -            ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff\n");
 +            ob_debug_type(OB_DEBUG_FOCUS, "found in pointer stuff");
              return c;
          }
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n");
 +    ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order");
      for (it = focus_order; it; it = g_list_next(it)) {
          c = it->data;
          /* fallback focus to a window if:
             3. it is not shaded
          */
          if ((allow_omnipresent || c->desktop == screen_desktop) &&
 -            focus_valid_target(c, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) &&
 +            focus_valid_target(c, screen_desktop,
 +                               TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) &&
              !c->shaded &&
              (allow_refocus || client_focus_target(c) != old) &&
              client_focus(c))
          {
 -            ob_debug_type(OB_DEBUG_FOCUS, "found in focus order\n");
 +            ob_debug_type(OB_DEBUG_FOCUS, "found in focus order");
              return c;
          }
      }
  
 -    ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window\n");
 +    ob_debug_type(OB_DEBUG_FOCUS, "trying a desktop window");
      for (it = focus_order; it; it = g_list_next(it)) {
          c = it->data;
          /* fallback focus to a window if:
             a splashscreen or a desktop window (save the desktop as a
             backup fallback though)
          */
 -        if (focus_valid_target(c, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) &&
 +        if (focus_valid_target(c, screen_desktop,
 +                               TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) &&
              (allow_refocus || client_focus_target(c) != old) &&
              client_focus(c))
          {
 -            ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window\n");
 +            ob_debug_type(OB_DEBUG_FOCUS, "found a desktop window");
              return c;
          }
      }
@@@ -189,7 -191,7 +192,7 @@@ void focus_nothing(void
      focus_set_client(NULL);
  
      /* when nothing will be focused, send focus to the backup target */
 -    XSetInputFocus(ob_display, screen_support_win, RevertToPointerRoot,
 +    XSetInputFocus(obt_display, screen_support_win, RevertToPointerRoot,
                     event_curtime);
  }
  
@@@ -199,7 -201,7 +202,7 @@@ void focus_order_add_new(ObClient *c
          focus_order_to_top(c);
      else {
          g_assert(!g_list_find(focus_order, c));
-         /* if there are any iconic windows, put this above them in the order,
+         /* if there are only iconic windows, put this above them in the order,
             but if there are not, then put it under the currently focused one */
          if (focus_order && ((ObClient*)focus_order->data)->iconic)
              focus_order = g_list_insert(focus_order, c, 0);
              focus_order = g_list_insert(focus_order, c, 1);
      }
  
-     /* in the middle of cycling..? kill it. */
-     focus_cycle_stop(c);
+     focus_cycle_addremove(c, TRUE);
  }
  
  void focus_order_remove(ObClient *c)
  {
      focus_order = g_list_remove(focus_order, c);
  
-     /* in the middle of cycling..? kill it. */
-     focus_cycle_stop(c);
+     focus_cycle_addremove(c, TRUE);
+ }
+ void focus_order_like_new(struct _ObClient *c)
+ {
+     focus_order = g_list_remove(focus_order, c);
+     focus_order_add_new(c);
  }
  
  void focus_order_to_top(ObClient *c)
               it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
          focus_order = g_list_insert_before(focus_order, it, c);
      }
+     focus_cycle_reorder();
  }
  
  void focus_order_to_bottom(ObClient *c)
               it && !((ObClient*)it->data)->iconic; it = g_list_next(it));
          focus_order = g_list_insert_before(focus_order, it, c);
      }
+     focus_cycle_reorder();
  }
  
  ObClient *focus_order_find_first(guint desktop)
@@@ -275,8 -285,7 +286,8 @@@ static gboolean focus_target_has_siblin
          ObClient *c = it->data;
          /* check that it's not a helper window to avoid infinite recursion */
          if (c != ft && c->type == OB_CLIENT_TYPE_NORMAL &&
 -            focus_valid_target(c, TRUE, iconic_windows, all_desktops,
 +            focus_valid_target(c, screen_desktop,
 +                               TRUE, iconic_windows, all_desktops,
                                 FALSE, FALSE, FALSE))
          {
              return TRUE;
  }
  
  gboolean focus_valid_target(ObClient *ft,
 +                            guint    desktop,
                              gboolean helper_windows,
                              gboolean iconic_windows,
                              gboolean all_desktops,
                              gboolean desktop_windows,
                              gboolean user_request)
  {
+     /* NOTE: if any of these things change on a client, then they should call
+        focus_cycle_addremove() to make sure the client is not shown/hidden
+        when it should not be */
      gboolean ok = FALSE;
  
+     /* see if the window is still managed or is going away */
+     if (!ft->managed) return FALSE;
      /* it's on this desktop unless you want all desktops.
  
         do this check first because it will usually filter out the most
         windows */
 -    ok = (all_desktops || ft->desktop == screen_desktop ||
 +    ok = (all_desktops || ft->desktop == desktop ||
            ft->desktop == DESKTOP_ALL);
  
      /* the window can receive focus somehow */
  
      /* it's not set to skip the taskbar (but this only applies to normal typed
         windows, and is overridden if the window is modal or if the user asked
 -       for this window to be focused) */
 +       for this window to be focused, or if the window is iconified) */
      ok = ok && (ft->type != OB_CLIENT_TYPE_NORMAL ||
                  ft->modal ||
 +                ft->iconic ||
                  user_request ||
                  !ft->skip_taskbar);
  
      {
          ObClient *cft = client_focus_target(ft);
          ok = ok && (ft == cft || !focus_valid_target(cft,
 +                                                     screen_desktop,
                                                       TRUE,
                                                       iconic_windows,
                                                       all_desktops,
diff --combined openbox/focus.h
@@@ -41,7 -41,7 +41,7 @@@ void focus_shutdown(gboolean reconfig)
  void focus_set_client(struct _ObClient *client);
  
  /*! Focus nothing, but let keyboard events be caught. */
 -void focus_nothing();
 +void focus_nothing(void);
  
  /*! Call this when you need to focus something! */
  struct _ObClient* focus_fallback(gboolean allow_refocus,
@@@ -58,6 -58,10 +58,10 @@@ void focus_order_remove(struct _ObClien
  /*! Move a client to the top of the focus order */
  void focus_order_to_top(struct _ObClient *c);
  
+ /*! Move a client to where it would be if it was newly added to the focus order
+  */
+ void focus_order_like_new(struct _ObClient *c);
  /*! Move a client to the bottom of the focus order (keeps iconic windows at the
    very bottom always though). */
  void focus_order_to_bottom(struct _ObClient *c);
@@@ -65,7 -69,6 +69,7 @@@
  struct _ObClient *focus_order_find_first(guint desktop);
  
  gboolean focus_valid_target(struct _ObClient *ft,
 +                            guint    desktop,
                              gboolean helper_windows,
                              gboolean iconic_windows,
                              gboolean all_desktops,
diff --combined openbox/focus_cycle.c
@@@ -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"
  #include <X11/Xlib.h>
  #include <glib.h>
  
+ typedef enum {
+     OB_CYCLE_NONE = 0,
+     OB_CYCLE_NORMAL,
+     OB_CYCLE_DIRECTIONAL
+ } ObCycleType;
  ObClient       *focus_cycle_target = NULL;
+ static ObCycleType focus_cycle_type = OB_CYCLE_NONE;
  static gboolean focus_cycle_iconic_windows;
  static gboolean focus_cycle_all_desktops;
  static gboolean focus_cycle_dock_windows;
@@@ -50,24 -58,47 +57,47 @@@ void focus_cycle_shutdown(gboolean reco
      if (reconfig) return;
  }
  
- void focus_cycle_stop(ObClient *ifclient)
+ void focus_cycle_addremove(ObClient *c, gboolean redraw)
  {
-     /* 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))) ||
-          !ifclient))
-     {
-         focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE);
-         focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
+     if (!focus_cycle_type)
+         return;
+     if (focus_cycle_type == OB_CYCLE_DIRECTIONAL) {
+         if (c && focus_cycle_target == c) {
+             focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE,
+                                     TRUE, TRUE, TRUE);
+         }
+     }
+     else if (c && redraw) {
+         gboolean v, s;
+         v = focus_cycle_valid(c);
+         s = focus_cycle_popup_is_showing(c);
+         if (v != s)
+             focus_cycle_reorder();
+     }
+     else if (redraw) {
+         focus_cycle_reorder();
+     }
+ }
+ void focus_cycle_reorder()
+ {
+     if (focus_cycle_type == OB_CYCLE_NORMAL) {
+         focus_cycle_target = focus_cycle_popup_refresh(focus_cycle_target,
+                                                        TRUE);
+         focus_cycle_update_indicator(focus_cycle_target);
+         if (!focus_cycle_target)
+             focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE,
+                         TRUE, TRUE, TRUE, TRUE, TRUE);
      }
  }
  
  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;
              if (it == NULL) it = g_list_last(list);
          }
          ft = it->data;
-         if (focus_valid_target(ft, screen_desktop, TRUE,
-                                focus_cycle_iconic_windows,
-                                focus_cycle_all_desktops,
-                                focus_cycle_dock_windows,
-                                focus_cycle_desktop_windows,
-                                FALSE))
-         {
+         if (focus_cycle_valid(ft)) {
              if (interactive) {
                  if (ft != focus_cycle_target) { /* prevents flicker */
                      focus_cycle_target = ft;
+                     focus_cycle_type = OB_CYCLE_NORMAL;
                      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;
+                 focus_cycle_type = OB_CYCLE_NORMAL;
                  done = TRUE;
                  break;
              }
@@@ -147,6 -174,7 +173,7 @@@ done_cycle
      if (done && !cancel) ret = focus_cycle_target;
  
      focus_cycle_target = NULL;
+     focus_cycle_type = OB_CYCLE_NONE;
      g_list_free(order);
      order = NULL;
  
@@@ -186,9 -214,7 +213,7 @@@ static ObClient *focus_find_directional
          /* the currently selected window isn't interesting */
          if (cur == c)
              continue;
-         if (!focus_valid_target(it->data, screen_desktop,
-                                 TRUE, FALSE, FALSE, dock_windows,
-                                 desktop_windows, FALSE))
+         if (!focus_cycle_valid(it->data))
              continue;
  
          /* find the centre coords of this window, from the
@@@ -292,16 -318,15 +317,15 @@@ ObClient* focus_directional_cycle(ObDir
          GList *it;
  
          for (it = focus_order; it; it = g_list_next(it))
-             if (focus_valid_target(it->data, screen_desktop, TRUE,
-                                    focus_cycle_iconic_windows,
-                                    focus_cycle_all_desktops,
-                                    focus_cycle_dock_windows,
-                                    focus_cycle_desktop_windows, FALSE))
+             if (focus_cycle_valid(it->data)) {
                  ft = it->data;
+                 break;
+             }
      }
  
      if (ft && ft != focus_cycle_target) {/* prevents flicker */
          focus_cycle_target = ft;
+         focus_cycle_type = OB_CYCLE_DIRECTIONAL;
          if (!interactive)
              goto done_cycle;
          focus_cycle_draw_indicator(showbar ? ft : NULL);
@@@ -320,9 -345,20 +344,20 @@@ done_cycle
  
      first = NULL;
      focus_cycle_target = NULL;
+     focus_cycle_type = OB_CYCLE_NONE;
  
      focus_cycle_draw_indicator(NULL);
      focus_cycle_popup_single_hide();
  
      return ret;
  }
 -    return focus_valid_target(client, TRUE,
+ gboolean focus_cycle_valid(struct _ObClient *client)
+ {
++    return focus_valid_target(client, screen_desktop, TRUE,
+                               focus_cycle_iconic_windows,
+                               focus_cycle_all_desktops,
+                               focus_cycle_dock_windows,
+                               focus_cycle_desktop_windows,
+                               FALSE);
+ }
diff --combined openbox/focus_cycle.h
@@@ -21,7 -21,6 +21,7 @@@
  #define __focus_cycle_h
  
  #include "misc.h"
 +#include "focus_cycle_popup.h"
  
  #include <X11/Xlib.h>
  #include <glib.h>
@@@ -38,7 -37,7 +38,7 @@@ void focus_cycle_shutdown(gboolean reco
  struct _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);
  struct _ObClient* focus_directional_cycle(ObDirection dir,
                                            gboolean dock_windows,
                                            gboolean dialog,
                                            gboolean done, gboolean cancel);
  
- void focus_cycle_stop(struct _ObClient *ifclient);
+ /*! Set @redraw to FALSE if there are more clients to be added/removed first */
+ void focus_cycle_addremove(struct _ObClient *ifclient, gboolean redraw);
+ void focus_cycle_reorder();
+ gboolean focus_cycle_valid(struct _ObClient *client);
  
  #endif
  */
  
  #include "focus_cycle_popup.h"
+ #include "focus_cycle.h"
  #include "popup.h"
  #include "client.h"
  #include "screen.h"
  #include "focus.h"
  #include "openbox.h"
 +#include "config.h"
  #include "window.h"
  #include "event.h"
 -#include "render/render.h"
 +#include "obrender/render.h"
  
  #include <X11/Xlib.h>
  #include <glib.h>
  
 -#define ICON_SIZE 40
 -#define ICON_HILITE_WIDTH 2
 -#define ICON_HILITE_MARGIN 1
 +/* Size of the icons, which can appear inside or outside of a hilite box */
 +#define ICON_SIZE (gint)config_theme_window_list_icon_size
 +/* Size of the hilite box around a window's icon */
 +#define HILITE_SIZE (ICON_SIZE + 2*HILITE_OFFSET)
 +/* Width of the outer ring around the hilite box */
 +#define HILITE_WIDTH 2
 +/* Space between the outer ring around the hilite box and the icon inside it */
 +#define HILITE_MARGIN 1
 +/* Total distance from the edge of the hilite box to the icon inside it */
 +#define HILITE_OFFSET (HILITE_WIDTH + HILITE_MARGIN)
 +/* Margin area around the outside of the dialog */
  #define OUTSIDE_BORDER 3
 +/* Margin area around the text */
  #define TEXT_BORDER 2
 +/* Scroll the list-mode list when the cursor gets within this many rows of the
 +   top or bottom */
 +#define SCROLL_MARGIN 4
  
  typedef struct _ObFocusCyclePopup       ObFocusCyclePopup;
  typedef struct _ObFocusCyclePopupTarget ObFocusCyclePopupTarget;
@@@ -57,9 -45,7 +58,9 @@@ struct _ObFocusCyclePopupTarge
      ObClient *client;
      RrImage *icon;
      gchar *text;
 -    Window win;
 +    Window iconwin;
 +    /* This is used when the popup is in list mode */
 +    Window textwin;
  };
  
  struct _ObFocusCyclePopup
      ObWindow obwin;
      Window bg;
  
 -    Window text;
 +    /* This is used when the popup is in icon mode */
 +    Window icon_mode_text;
 +
 +    Window list_mode_up;
 +    Window list_mode_down;
  
      GList *targets;
      gint n_targets;
  
      gint maxtextw;
  
 +    /* How are the list is scrolled, in scroll mode */
 +    gint scroll;
 +
      RrAppearance *a_bg;
      RrAppearance *a_text;
 +    RrAppearance *a_hilite_text;
      RrAppearance *a_icon;
 -
 -    RrPixel32 *hilite_rgba;
 +    RrAppearance *a_arrow;
  
      gboolean mapped;
 +    ObFocusCyclePopupMode mode;
  };
  
  /*! This popup shows all possible windows */
@@@ -98,20 -76,17 +99,17 @@@ static ObFocusCyclePopup popup
  /*! This popup shows a single window */
  static ObIconPopup *single_popup;
  
- static gchar *popup_get_name (ObClient *c);
- static void   popup_setup    (ObFocusCyclePopup *p,
-                               gboolean create_targets,
-                               gboolean iconic_windows,
-                               gboolean all_desktops,
-                               gboolean dock_windows,
-                               gboolean desktop_windows);
- static void   popup_render   (ObFocusCyclePopup *p,
-                               const ObClient *c);
+ static gchar   *popup_get_name (ObClient *c);
+ static gboolean popup_setup    (ObFocusCyclePopup *p,
+                                 gboolean create_targets,
+                                 gboolean refresh_targets);
+ static void     popup_render   (ObFocusCyclePopup *p,
+                                 const ObClient *c);
  
  static Window create_window(Window parent, guint bwidth, gulong mask,
                              XSetWindowAttributes *attr)
  {
 -    return XCreateWindow(ob_display, parent, 0, 0, 1, 1, bwidth,
 +    return XCreateWindow(obt_display, parent, 0, 0, 1, 1, bwidth,
                           RrDepth(ob_rr_inst), InputOutput,
                           RrVisual(ob_rr_inst), mask, attr);
  }
  void focus_cycle_popup_startup(gboolean reconfig)
  {
      XSetWindowAttributes attrib;
 +    RrPixel32 *p;
  
      single_popup = icon_popup_new();
  
 -    popup.obwin.type = Window_Internal;
 -    popup.a_bg = RrAppearanceCopy(ob_rr_theme->osd_hilite_bg);
 -    popup.a_text = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
 -    popup.a_icon = RrAppearanceCopy(ob_rr_theme->a_clear_tex);
 +    popup.obwin.type = OB_WINDOW_CLASS_INTERNAL;
 +    popup.a_bg = RrAppearanceCopy(ob_rr_theme->osd_bg);
 +    popup.a_hilite_text = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
 +    popup.a_text = RrAppearanceCopy(ob_rr_theme->osd_unhilite_label);
 +    popup.a_icon = RrAppearanceCopy(ob_rr_theme->a_clear);
 +    popup.a_arrow = RrAppearanceCopy(ob_rr_theme->a_clear_tex);
  
 +    popup.a_hilite_text->surface.parent = popup.a_bg;
      popup.a_text->surface.parent = popup.a_bg;
      popup.a_icon->surface.parent = popup.a_bg;
  
 +    popup.a_text->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
 +    popup.a_hilite_text->texture[0].data.text.justify = RR_JUSTIFY_LEFT;
 +
 +    /* 2 textures. texture[0] is the icon.  texture[1] is the hilight, and
 +       may or may not be used */
 +    RrAppearanceAddTextures(popup.a_icon, 2);
 +
      RrAppearanceClearTextures(popup.a_icon);
      popup.a_icon->texture[0].type = RR_TEXTURE_IMAGE;
  
 -    RrAppearanceAddTextures(popup.a_bg, 1);
 -    popup.a_bg->texture[0].type = RR_TEXTURE_RGBA;
 +    RrAppearanceClearTextures(popup.a_arrow);
 +    popup.a_arrow->texture[0].type = RR_TEXTURE_MASK;
 +    popup.a_arrow->texture[0].data.mask.color =
 +        ob_rr_theme->osd_text_active_color;
  
      attrib.override_redirect = True;
      attrib.border_pixel=RrColorPixel(ob_rr_theme->osd_border_color);
 -    popup.bg = create_window(RootWindow(ob_display, ob_screen),
 -                             ob_rr_theme->obwidth,
 +    popup.bg = create_window(obt_root(ob_screen), ob_rr_theme->obwidth,
                               CWOverrideRedirect | CWBorderPixel, &attrib);
  
 -    popup.text = create_window(popup.bg, 0, 0, NULL);
 +    /* create the text window used for the icon-mode popup */
 +    popup.icon_mode_text = create_window(popup.bg, 0, 0, NULL);
 +
 +    /* create the windows for the up and down arrows */
 +    popup.list_mode_up = create_window(popup.bg, 0, 0, NULL);
 +    popup.list_mode_down = create_window(popup.bg, 0, 0, NULL);
  
      popup.targets = NULL;
      popup.n_targets = 0;
      popup.last_target = NULL;
  
 -    popup.hilite_rgba = NULL;
 +    /* set up the hilite texture for the icon */
 +    popup.a_icon->texture[1].data.rgba.width = HILITE_SIZE;
 +    popup.a_icon->texture[1].data.rgba.height = HILITE_SIZE;
 +    popup.a_icon->texture[1].data.rgba.alpha = 0xff;
 +    p = g_new(RrPixel32, HILITE_SIZE * HILITE_SIZE);
 +    popup.a_icon->texture[1].data.rgba.data = p;
  
 -    XMapWindow(ob_display, popup.text);
 +    /* create the hilite under the target icon */
 +    {
 +        RrPixel32 color;
 +        RrColor *tc;
 +        gint x, y, o;
 +
 +        tc = ob_rr_theme->osd_text_active_color;
 +        color = ((tc->r & 0xff) << RrDefaultRedOffset) +
 +            ((tc->g & 0xff) << RrDefaultGreenOffset) +
 +            ((tc->b & 0xff) << RrDefaultBlueOffset);
 +
 +        o = 0;
 +        for (x = 0; x < HILITE_SIZE; x++)
 +            for (y = 0; y < HILITE_SIZE; y++) {
 +                guchar a;
 +
 +                if (x < HILITE_WIDTH ||
 +                    x >= HILITE_SIZE - HILITE_WIDTH ||
 +                    y < HILITE_WIDTH ||
 +                    y >= HILITE_SIZE - HILITE_WIDTH)
 +                {
 +                    /* the border of the target */
 +                    a = 0x88;
 +                } else {
 +                    /* the background of the target */
 +                    a = 0x22;
 +                }
 +
 +                p[o++] = color + (a << RrDefaultAlphaOffset);
 +            }
 +    }
  
      stacking_add(INTERNAL_AS_WINDOW(&popup));
 -    g_hash_table_insert(window_map, &popup.bg, &popup);
 +    window_add(&popup.bg, INTERNAL_AS_WINDOW(&popup));
  }
  
  void focus_cycle_popup_shutdown(gboolean reconfig)
  {
      icon_popup_free(single_popup);
  
 -    g_hash_table_remove(window_map, &popup.bg);
 +    window_remove(popup.bg);
      stacking_remove(INTERNAL_AS_WINDOW(&popup));
  
      while(popup.targets) {
  
          RrImageUnref(t->icon);
          g_free(t->text);
 -        XDestroyWindow(ob_display, t->win);
 +        XDestroyWindow(obt_display, t->iconwin);
 +        XDestroyWindow(obt_display, t->textwin);
          g_free(t);
  
          popup.targets = g_list_delete_link(popup.targets, popup.targets);
      }
  
 -    g_free(popup.hilite_rgba);
 -    popup.hilite_rgba = NULL;
 +    g_free(popup.a_icon->texture[1].data.rgba.data);
 +    popup.a_icon->texture[1].data.rgba.data = NULL;
  
 -    XDestroyWindow(ob_display, popup.text);
 -    XDestroyWindow(ob_display, popup.bg);
 +    XDestroyWindow(obt_display, popup.list_mode_up);
 +    XDestroyWindow(obt_display, popup.list_mode_down);
 +    XDestroyWindow(obt_display, popup.icon_mode_text);
 +    XDestroyWindow(obt_display, popup.bg);
  
 +    RrAppearanceFree(popup.a_arrow);
      RrAppearanceFree(popup.a_icon);
 +    RrAppearanceFree(popup.a_hilite_text);
      RrAppearanceFree(popup.a_text);
      RrAppearanceFree(popup.a_bg);
  }
  
- static void popup_setup(ObFocusCyclePopup *p, gboolean create_targets,
-                         gboolean iconic_windows, gboolean all_desktops,
-                         gboolean dock_windows, gboolean desktop_windows)
+ static void popup_target_free(ObFocusCyclePopupTarget *t)
+ {
+     RrImageUnref(t->icon);
+     g_free(t->text);
 -    XDestroyWindow(ob_display, t->win);
++    XDestroyWindow(obt_display, t->iconwin);
++    XDestroyWindow(obt_display, t->textwin);
+     g_free(t);
+ }
+ static gboolean popup_setup(ObFocusCyclePopup *p, gboolean create_targets,
+                             gboolean refresh_targets)
  {
      gint maxwidth, n;
      GList *it;
+     GList *rtargets; /* old targets for refresh */
+     GList *rtlast;
+     gboolean change;
+     if (refresh_targets) {
+         rtargets = p->targets;
+         rtlast = g_list_last(rtargets);
+         p->targets = NULL;
+         p->n_targets = 0;
+         change = FALSE;
+     }
+     else {
+         rtargets = rtlast = NULL;
+         change = TRUE;
+     }
  
      g_assert(p->targets == NULL);
      g_assert(p->n_targets == 0);
      for (it = g_list_last(focus_order); it; it = g_list_previous(it)) {
          ObClient *ft = it->data;
  
-         if (focus_valid_target(ft, screen_desktop, TRUE,
-                                iconic_windows,
-                                all_desktops,
-                                dock_windows,
-                                desktop_windows,
-                                FALSE))
-         {
-             gchar *text = popup_get_name(ft);
+         if (focus_cycle_valid(ft)) {
+             GList *rit;
  
-             /* measure */
-             p->a_text->texture[0].data.text.string = text;
-             maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
+             /* reuse the target if possible during refresh */
+             for (rit = rtlast; rit; rit = g_list_previous(rit)) {
+                 ObFocusCyclePopupTarget *t = rit->data;
+                 if (t->client == ft) {
+                     if (rit == rtlast)
+                         rtlast = g_list_previous(rit);
+                     rtargets = g_list_remove_link(rtargets, rit);
  
-             if (!create_targets) {
-                 g_free(text);
-             } else {
-                 ObFocusCyclePopupTarget *t = g_new(ObFocusCyclePopupTarget, 1);
+                     p->targets = g_list_concat(rit, p->targets);
+                     ++n;
+                     if (rit != rtlast)
+                         change = TRUE; /* order changed */
+                     break;
+                 }
+             }
+             if (!rit) {
+                 gchar *text = popup_get_name(ft);
+                 /* measure */
+                 p->a_text->texture[0].data.text.string = text;
+                 maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
  
-                 t->client = ft;
-                 t->text = text;
-                 t->icon = client_icon(t->client);
-                 RrImageRef(t->icon); /* own the icon so it won't go away */
-                 t->iconwin = create_window(p->bg, 0, 0, NULL);
-                 t->textwin = create_window(p->bg, 0, 0, NULL);
 -                if (!create_targets)
++                if (!create_targets) {
+                     g_free(text);
 -                else {
++                } else {
+                     ObFocusCyclePopupTarget *t =
+                         g_new(ObFocusCyclePopupTarget, 1);
+                     t->client = ft;
+                     t->text = text;
+                     t->icon = client_icon(t->client);
+                     RrImageRef(t->icon); /* own the icon so it won't go away */
 -                    t->win = create_window(p->bg, 0, 0, NULL);
 -
 -                    XMapWindow(ob_display, t->win);
++                    t->iconwin = create_window(p->bg, 0, 0, NULL);
++                    t->textwin = create_window(p->bg, 0, 0, NULL);
  
-                 p->targets = g_list_prepend(p->targets, t);
-                 ++n;
+                     p->targets = g_list_prepend(p->targets, t);
+                     ++n;
+                     change = TRUE; /* added a window */
+                 }
              }
          }
      }
  
+     if (rtargets) {
+         change = TRUE; /* removed a window */
+         while (rtargets) {
+             popup_target_free(rtargets->data);
+             rtargets = g_list_delete_link(rtargets, rtargets);
+         }
+     }
      p->n_targets = n;
--    p->maxtextw = maxwidth;
++    if (refresh_targets)
++        /* don't shrink when refreshing */
++        p->maxtextw = MAX(p->maxtextw, maxwidth);
++    else
++        p->maxtextw = maxwidth;
+     return change;
+ }
+ static void popup_cleanup(void)
+ {
+     while(popup.targets) {
+         popup_target_free(popup.targets->data);
+         popup.targets = g_list_delete_link(popup.targets, popup.targets);
+     }
+     popup.n_targets = 0;
+     popup.last_target = NULL;
  }
  
  static gchar *popup_get_name(ObClient *c)
@@@ -329,29 -309,16 +393,29 @@@ static void popup_render(ObFocusCyclePo
      gint l, t, r, b;
      gint x, y, w, h;
      Rect *screen_area = NULL;
 -    gint icons_per_row;
 -    gint icon_rows;
 -    gint textx, texty, textw, texth;
 -    gint rgbax, rgbay, rgbaw, rgbah;
 -    gint icons_center_x;
 -    gint innerw, innerh;
      gint i;
      GList *it;
      const ObFocusCyclePopupTarget *newtarget;
 -    gint newtargetx, newtargety;
 +    ObFocusCyclePopupMode mode = p->mode;
 +    gint icons_per_row;
 +    gint icon_rows;
 +    gint textw, texth;
 +    gint selected_pos;
 +    gint last_scroll;
 +
 +    /* vars for icon mode */
 +    gint icon_mode_textx;
 +    gint icon_mode_texty;
 +    gint icons_center_x;
 +
 +    /* vars for list mode */
 +    gint list_mode_icon_column_w = HILITE_SIZE + OUTSIDE_BORDER;
 +    gint up_arrow_x, down_arrow_x;
 +    gint up_arrow_y, down_arrow_y;
 +    gboolean showing_arrows = FALSE;
 +
 +    g_assert(mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS ||
 +             mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST);
  
      screen_area = screen_physical_area_primary(FALSE);
  
      t = mt + OUTSIDE_BORDER;
      b = mb + OUTSIDE_BORDER;
  
 -    /* get the icon pictures' sizes */
 -    innerw = ICON_SIZE - (ICON_HILITE_WIDTH + ICON_HILITE_MARGIN) * 2;
 -    innerh = ICON_SIZE - (ICON_HILITE_WIDTH + ICON_HILITE_MARGIN) * 2;
 -
      /* get the width from the text and keep it within limits */
      w = l + r + p->maxtextw;
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +        /* when in list mode, there are icons down the side */
 +        w += list_mode_icon_column_w;
      w = MIN(w, MAX(screen_area->width/3, POPUP_WIDTH)); /* max width */
      w = MAX(w, POPUP_WIDTH); /* min width */
  
 -    /* how many icons will fit in that row? make the width fit that */
 -    w -= l + r;
 -    icons_per_row = (w + ICON_SIZE - 1) / ICON_SIZE;
 -    w = icons_per_row * ICON_SIZE + l + r;
 -
 -    /* how many rows do we need? */
 -    icon_rows = (p->n_targets-1) / icons_per_row + 1;
 +    /* get the text height */
 +    texth = RrMinHeight(p->a_hilite_text);
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +        texth = MAX(MAX(texth, RrMinHeight(p->a_text)), HILITE_SIZE);
 +    else
 +        texth += TEXT_BORDER * 2;
 +
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS) {
 +        /* how many icons will fit in that row? make the width fit that */
 +        w -= l + r;
 +        icons_per_row = (w + HILITE_SIZE - 1) / HILITE_SIZE;
 +        w = icons_per_row * HILITE_SIZE + l + r;
 +
 +        /* how many rows do we need? */
 +        icon_rows = (p->n_targets-1) / icons_per_row + 1;
 +    } else {
 +        /* in list mode, there is one column of icons.. */
 +        icons_per_row = 1;
 +        /* maximum is 80% of the screen height */
 +        icon_rows = MIN(p->n_targets,
 +                        (4*screen_area->height/5) /* 80% of the screen */
 +                        /
 +                        MAX(HILITE_SIZE, texth)); /* height of each row */
 +        /* but make sure there is always one */
 +        icon_rows = MAX(icon_rows, 1);
 +    }
  
 -    /* get the text dimensions */
 +    /* get the text width */
      textw = w - l - r;
 -    texth = RrMinHeight(p->a_text) + TEXT_BORDER * 2;
 -
 -    /* find the height of the dialog */
 -    h = t + b + (icon_rows * ICON_SIZE) + (OUTSIDE_BORDER + texth);
 -
 -    /* get the position of the text */
 -    textx = l;
 -    texty = h - texth - b;
 -
 -    /* find the position for the popup (include the outer borders) */
 -    x = screen_area->x + (screen_area->width -
 -                          (w + ob_rr_theme->obwidth * 2)) / 2;
 -    y = screen_area->y + (screen_area->height -
 -                          (h + ob_rr_theme->obwidth * 2)) / 2;
 -
 -    /* get the dimensions of the target hilite texture */
 -    rgbax = ml;
 -    rgbay = mt;
 -    rgbaw = w - ml - mr;
 -    rgbah = h - mt - mb;
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +        /* leave space on the side for the icons */
 +        textw -= list_mode_icon_column_w;
  
 -    /* center the icons if there is less than one row */
 -    if (icon_rows == 1)
 -        icons_center_x = (w - p->n_targets * ICON_SIZE) / 2;
 -    else
 -        icons_center_x = 0;
 +    if (!p->mapped)
 +        /* reset the scrolling when the dialog is first shown */
 +        p->scroll = 0;
  
 -    if (!p->mapped) {
 -        /* position the background but don't draw it*/
 -        XMoveResizeWindow(ob_display, p->bg, x, y, w, h);
 -
 -        /* set up the hilite texture for the background */
 -        p->a_bg->texture[0].data.rgba.width = rgbaw;
 -        p->a_bg->texture[0].data.rgba.height = rgbah;
 -        p->a_bg->texture[0].data.rgba.alpha = 0xff;
 -        p->hilite_rgba = g_new(RrPixel32, rgbaw * rgbah);
 -        p->a_bg->texture[0].data.rgba.data = p->hilite_rgba;
 -
 -        /* position the text, but don't draw it */
 -        XMoveResizeWindow(ob_display, p->text, textx, texty, textw, texth);
 -        p->a_text->surface.parentx = textx;
 -        p->a_text->surface.parenty = texty;
 -    }
 +    /* find the height of the dialog */
 +    h = t + b + (icon_rows * MAX(HILITE_SIZE, texth));
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS)
 +        /* in icon mode the text sits below the icons, so make some space */
 +        h += OUTSIDE_BORDER + texth;
  
      /* find the focused target */
 +    newtarget = NULL;
      for (i = 0, it = p->targets; it; ++i, it = g_list_next(it)) {
          const ObFocusCyclePopupTarget *target = it->data;
 -        const gint row = i / icons_per_row; /* starting from 0 */
 -        const gint col = i % icons_per_row; /* starting from 0 */
 -
          if (target->client == c) {
              /* save the target */
              newtarget = target;
 -            newtargetx = icons_center_x + l + (col * ICON_SIZE);
 -            newtargety = t + (row * ICON_SIZE);
 +            break;
 +        }
 +    }
 +    selected_pos = i;
 +    g_assert(newtarget != NULL);
  
 -            if (!p->mapped)
 -                break; /* if we're not dimensioning, then we're done */
 +    /* scroll the list if needed */
 +    last_scroll = p->scroll;
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST) {
 +        const gint top = p->scroll + SCROLL_MARGIN;
 +        const gint bottom = p->scroll + icon_rows - SCROLL_MARGIN;
 +        const gint min_scroll = 0;
 +        const gint max_scroll = p->n_targets - icon_rows;
 +
 +        if (top - selected_pos >= 0) {
 +            p->scroll -= top - selected_pos + 1;
 +            p->scroll = MAX(p->scroll, min_scroll);
 +        } else if (selected_pos - bottom >= 0) {
 +            p->scroll += selected_pos - bottom + 1;
 +            p->scroll = MIN(p->scroll, max_scroll);
          }
      }
  
 -    g_assert(newtarget != NULL);
 +    /* show the scroll arrows when appropriate */
 +    if (p->scroll && mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST) {
 +        XMapWindow(obt_display, p->list_mode_up);
 +        showing_arrows = TRUE;
 +    } else
 +        XUnmapWindow(obt_display, p->list_mode_up);
  
 -    /* create the hilite under the target icon */
 +    if (p->scroll < p->n_targets - icon_rows &&
 +        mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
      {
 -        RrPixel32 color;
 -        gint i, j, o;
 +        XMapWindow(obt_display, p->list_mode_down);
 +        showing_arrows = TRUE;
 +    } else
 +        XUnmapWindow(obt_display, p->list_mode_down);
  
 -        color = ((ob_rr_theme->osd_color->r & 0xff) << RrDefaultRedOffset) +
 -            ((ob_rr_theme->osd_color->g & 0xff) << RrDefaultGreenOffset) +
 -            ((ob_rr_theme->osd_color->b & 0xff) << RrDefaultBlueOffset);
 +    /* make space for the arrows */
 +    if (showing_arrows)
 +        h += ob_rr_theme->up_arrow_mask->height + OUTSIDE_BORDER
 +            + ob_rr_theme->down_arrow_mask->height + OUTSIDE_BORDER;
  
 -        o = 0;
 -        for (i = 0; i < rgbah; ++i)
 -            for (j = 0; j < rgbaw; ++j) {
 -                guchar a;
 -                const gint x = j + rgbax - newtargetx;
 -                const gint y = i + rgbay - newtargety;
 +    /* center the icons if there is less than one row */
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS && icon_rows == 1)
 +        icons_center_x = (w - p->n_targets * HILITE_SIZE) / 2;
 +    else
 +        icons_center_x = 0;
  
 -                if (x < 0 || x >= ICON_SIZE ||
 -                    y < 0 || y >= ICON_SIZE)
 -                {
 -                    /* outside the target */
 -                    a = 0x00;
 -                }
 -                else if (x < ICON_HILITE_WIDTH ||
 -                         x >= ICON_SIZE - ICON_HILITE_WIDTH ||
 -                         y < ICON_HILITE_WIDTH ||
 -                         y >= ICON_SIZE - ICON_HILITE_WIDTH)
 -                {
 -                    /* the border of the target */
 -                    a = 0x88;
 -                }
 -                else {
 -                    /* the background of the target */
 -                    a = 0x22;
 -                }
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS) {
 +        /* get the position of the text */
 +        icon_mode_textx = l;
 +        icon_mode_texty = h - texth - b;
 +    }
  
 -                p->hilite_rgba[o++] =
 -                    color + (a << RrDefaultAlphaOffset);
 -            }
 +    /* find the position for the popup (include the outer borders) */
 +    x = screen_area->x + (screen_area->width -
 +                          (w + ob_rr_theme->obwidth * 2)) / 2;
 +    y = screen_area->y + (screen_area->height -
 +                          (h + ob_rr_theme->obwidth * 2)) / 2;
 +
 +    if (!p->mapped) {
 +        /* position the background but don't draw it */
 +        XMoveResizeWindow(obt_display, p->bg, x, y, w, h);
 +
 +        if (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS) {
 +            /* position the text */
 +            XMoveResizeWindow(obt_display, p->icon_mode_text,
 +                              icon_mode_textx, icon_mode_texty, textw, texth);
 +            XMapWindow(obt_display, popup.icon_mode_text);
 +        } else {
 +            XUnmapWindow(obt_display, popup.icon_mode_text);
 +
 +            up_arrow_x = (w - ob_rr_theme->up_arrow_mask->width) / 2;
 +            up_arrow_y = t;
 +
 +            down_arrow_x = (w - ob_rr_theme->down_arrow_mask->width) / 2;
 +            down_arrow_y = h - b - ob_rr_theme->down_arrow_mask->height;
 +
 +            /* position the arrows */
 +            XMoveResizeWindow(obt_display, p->list_mode_up,
 +                              up_arrow_x, up_arrow_y,
 +                              ob_rr_theme->up_arrow_mask->width,
 +                              ob_rr_theme->up_arrow_mask->height);
 +            XMoveResizeWindow(obt_display, p->list_mode_down,
 +                              down_arrow_x, down_arrow_y,
 +                              ob_rr_theme->down_arrow_mask->width,
 +                              ob_rr_theme->down_arrow_mask->height);
 +        }
      }
  
      /* * * draw everything * * */
  
      /* draw the background */
 -    RrPaint(p->a_bg, p->bg, w, h);
 +    if (!p->mapped)
 +        RrPaint(p->a_bg, p->bg, w, h);
 +
 +    /* draw the scroll arrows */
 +    if (!p->mapped && mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST) {
 +        p->a_arrow->texture[0].data.mask.mask =
 +            ob_rr_theme->up_arrow_mask;
 +        p->a_arrow->surface.parent = p->a_bg;
 +        p->a_arrow->surface.parentx = up_arrow_x;
 +        p->a_arrow->surface.parenty = up_arrow_y;
 +        RrPaint(p->a_arrow, p->list_mode_up, 
 +                ob_rr_theme->up_arrow_mask->width,
 +                ob_rr_theme->up_arrow_mask->height);
 +
 +        p->a_arrow->texture[0].data.mask.mask =
 +            ob_rr_theme->down_arrow_mask;
 +        p->a_arrow->surface.parent = p->a_bg;
 +        p->a_arrow->surface.parentx = down_arrow_x;
 +        p->a_arrow->surface.parenty = down_arrow_y;
 +        RrPaint(p->a_arrow, p->list_mode_down, 
 +                ob_rr_theme->down_arrow_mask->width,
 +                ob_rr_theme->down_arrow_mask->height);
 +    }
  
 -    /* draw the icons */
 +    /* draw the icons and text */
      for (i = 0, it = p->targets; it; ++i, it = g_list_next(it)) {
          const ObFocusCyclePopupTarget *target = it->data;
  
 -        /* have to redraw the targetted icon and last targetted icon,
 -           they can pick up the hilite changes in the backgroud */
 -        if (!p->mapped || newtarget == target || p->last_target == target) {
 -            const gint row = i / icons_per_row; /* starting from 0 */
 -            const gint col = i % icons_per_row; /* starting from 0 */
 -            gint innerx, innery;
 -
 -            /* find the dimensions of the icon inside it */
 -            innerx = icons_center_x + l + (col * ICON_SIZE);
 -            innerx += ICON_HILITE_WIDTH + ICON_HILITE_MARGIN;
 -            innery = t + (row * ICON_SIZE);
 -            innery += ICON_HILITE_WIDTH + ICON_HILITE_MARGIN;
 -
 -            /* move the icon */
 -            XMoveResizeWindow(ob_display, target->win,
 -                              innerx, innery, innerw, innerh);
 +        /* have to redraw the targetted icon and last targetted icon
 +         * to update the hilite */
 +        if (!p->mapped || newtarget == target || p->last_target == target ||
 +            last_scroll != p->scroll)
 +        {
 +            /* row and column start from 0 */
 +            const gint row = i / icons_per_row - p->scroll;
 +            const gint col = i % icons_per_row;
 +            gint iconx, icony;
 +            gint list_mode_textx, list_mode_texty;
 +            RrAppearance *text;
 +
 +            /* find the coordinates for the icon */
 +            iconx = icons_center_x + l + (col * HILITE_SIZE);
 +            icony = t + (showing_arrows ? ob_rr_theme->up_arrow_mask->height
 +                                          + OUTSIDE_BORDER
 +                         : 0)
 +                + (row * MAX(texth, HILITE_SIZE))
 +                + MAX(texth - HILITE_SIZE, 0) / 2;
 +
 +            /* find the dimensions of the text box */
 +            list_mode_textx = iconx + HILITE_SIZE + TEXT_BORDER;
 +            list_mode_texty = icony;
 +
 +            /* position the icon */
 +            XMoveResizeWindow(obt_display, target->iconwin,
 +                              iconx, icony, HILITE_SIZE, HILITE_SIZE);
 +
 +            /* position the text */
 +            if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +                XMoveResizeWindow(obt_display, target->textwin,
 +                                  list_mode_textx, list_mode_texty,
 +                                  textw, texth);
 +
 +            /* show/hide the right windows */
 +            if (row >= 0 && row < icon_rows) {
 +                XMapWindow(obt_display, target->iconwin);
 +                if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +                    XMapWindow(obt_display, target->textwin);
 +                else
 +                    XUnmapWindow(obt_display, target->textwin);
 +            } else {
 +                XUnmapWindow(obt_display, target->textwin);
 +                if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +                    XUnmapWindow(obt_display, target->iconwin);
 +                else
 +                    XMapWindow(obt_display, target->iconwin);
 +            }
  
              /* get the icon from the client */
 +            p->a_icon->texture[0].data.image.twidth = ICON_SIZE;
 +            p->a_icon->texture[0].data.image.theight = ICON_SIZE;
 +            p->a_icon->texture[0].data.image.tx = HILITE_OFFSET;
 +            p->a_icon->texture[0].data.image.ty = HILITE_OFFSET;
              p->a_icon->texture[0].data.image.alpha =
                  target->client->iconic ? OB_ICONIC_ALPHA : 0xff;
              p->a_icon->texture[0].data.image.image = target->icon;
  
 +            /* Draw the hilite? */
 +            p->a_icon->texture[1].type = (target == newtarget) ?
 +                RR_TEXTURE_RGBA : RR_TEXTURE_NONE;
 +
              /* draw the icon */
 -            p->a_icon->surface.parentx = innerx;
 -            p->a_icon->surface.parenty = innery;
 -            RrPaint(p->a_icon, target->win, innerw, innerh);
 +            p->a_icon->surface.parentx = iconx;
 +            p->a_icon->surface.parenty = icony;
 +            RrPaint(p->a_icon, target->iconwin, HILITE_SIZE, HILITE_SIZE);
 +
 +            /* draw the text */
 +            if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST ||
 +                target == newtarget)
 +            {
 +                text = (target == newtarget) ? p->a_hilite_text : p->a_text;
 +                text->texture[0].data.text.string = target->text;
 +                text->surface.parentx =
 +                    mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS ?
 +                    icon_mode_textx : list_mode_textx;
 +                text->surface.parenty =
 +                    mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS ?
 +                    icon_mode_texty : list_mode_texty;
 +                RrPaint(text,
 +                        (mode == OB_FOCUS_CYCLE_POPUP_MODE_ICONS ?
 +                         p->icon_mode_text : target->textwin),
 +                        textw, texth);
 +            }
          }
      }
  
 -    /* draw the text */
 -    p->a_text->texture[0].data.text.string = newtarget->text;
 -    p->a_text->surface.parentx = textx;
 -    p->a_text->surface.parenty = texty;
 -    RrPaint(p->a_text, p->text, textw, texth);
 -
      p->last_target = newtarget;
  
      g_free(screen_area);
 +
 +    XFlush(obt_display);
  }
  
  void focus_cycle_popup_show(ObClient *c, gboolean iconic_windows,
                              gboolean all_desktops, gboolean dock_windows,
 -                            gboolean desktop_windows)
 +                            gboolean desktop_windows,
 +                            ObFocusCyclePopupMode mode)
  {
      g_assert(c != NULL);
  
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_NONE) {
 +        focus_cycle_popup_hide();
 +        return;
 +    }
 +
      /* do this stuff only when the dialog is first showing */
 -    if (!popup.mapped)
 +    if (!popup.mapped) {
-         popup_setup(&popup, TRUE, iconic_windows, all_desktops, 
-                     dock_windows, desktop_windows);
+         popup_setup(&popup, TRUE, FALSE);
 +        /* this is fixed once the dialog is shown */
 +        popup.mode = mode;
 +    }
      g_assert(popup.targets != NULL);
  
      popup_render(&popup, c);
  
      if (!popup.mapped) {
          /* show the dialog */
 -        XMapWindow(ob_display, popup.bg);
 -        XFlush(ob_display);
 +        XMapWindow(obt_display, popup.bg);
 +        XFlush(obt_display);
          popup.mapped = TRUE;
          screen_hide_desktop_popup();
      }
@@@ -676,26 -530,17 +739,14 @@@ void focus_cycle_popup_hide(void
  
      ignore_start = event_start_ignore_all_enters();
  
 -    XUnmapWindow(ob_display, popup.bg);
 -    XFlush(ob_display);
 +    XUnmapWindow(obt_display, popup.bg);
 +    XFlush(obt_display);
  
      event_end_ignore_all_enters(ignore_start);
  
      popup.mapped = FALSE;
  
-     while(popup.targets) {
-         ObFocusCyclePopupTarget *t = popup.targets->data;
-         RrImageUnref(t->icon);
-         g_free(t->text);
-         XDestroyWindow(obt_display, t->iconwin);
-         XDestroyWindow(obt_display, t->textwin);
-         g_free(t);
-         popup.targets = g_list_delete_link(popup.targets, popup.targets);
-     }
-     popup.n_targets = 0;
-     popup.last_target = NULL;
+     popup_cleanup();
 -
 -    g_free(popup.hilite_rgba);
 -    popup.hilite_rgba = NULL;
  }
  
  void focus_cycle_popup_single_show(struct _ObClient *c,
      if (!popup.mapped) {
          Rect *a;
  
-         popup_setup(&popup, FALSE, iconic_windows, all_desktops,
-                     dock_windows, desktop_windows);
+         popup_setup(&popup, FALSE, FALSE);
          g_assert(popup.targets == NULL);
  
          /* position the popup */
@@@ -738,16 -582,67 +788,67 @@@ void focus_cycle_popup_single_hide(void
      icon_popup_hide(single_popup);
  }
  
- gboolean focus_cycle_popup_is_showing(ObClient *client)
+ gboolean focus_cycle_popup_is_showing(ObClient *c)
  {
      if (popup.mapped) {
          GList *it;
  
          for (it = popup.targets; it; it = g_list_next(it)) {
              ObFocusCyclePopupTarget *t = it->data;
-             if (t->client == client)
+             if (t->client == c)
                  return TRUE;
          }
      }
      return FALSE;
  }
 -        XFlush(ob_display);
+ static ObClient* popup_revert(ObClient *target)
+ {
+     GList *it, *itt;
+     for (it = popup.targets; it; it = g_list_next(it)) {
+         ObFocusCyclePopupTarget *t = it->data;
+         if (t->client == target) {
+             /* move to a previous window if possible */
+             for (itt = it->prev; itt; itt = g_list_previous(itt)) {
+                 ObFocusCyclePopupTarget *t2 = itt->data;
+                 if (focus_cycle_valid(t2->client))
+                     return t2->client;
+             }
+             /* otherwise move to a following window if possible */
+             for (itt = it->next; itt; itt = g_list_next(itt)) {
+                 ObFocusCyclePopupTarget *t2 = itt->data;
+                 if (focus_cycle_valid(t2->client))
+                     return t2->client;
+             }
+             /* otherwise, we can't go anywhere there is nowhere valid to go */
+             return NULL;
+         }
+     }
+     return NULL;
+ }
+ ObClient* focus_cycle_popup_refresh(ObClient *target,
+                                     gboolean redraw)
+ {
+     if (!popup.mapped) return NULL;
+     if (!focus_cycle_valid(target))
+         target = popup_revert(target);
+     redraw = popup_setup(&popup, TRUE, TRUE) && redraw;
+     if (!target && popup.targets)
+         target = ((ObFocusCyclePopupTarget*)popup.targets->data)->client;
+     if (target && redraw) {
+         popup.mapped = FALSE;
+         popup_render(&popup, target);
++        XFlush(obt_display);
+         popup.mapped = TRUE;
+     }
+     return target;
+ }
@@@ -24,29 -24,28 +24,35 @@@ struct _ObClient
  
  #include <glib.h>
  
 +typedef enum {
 +    OB_FOCUS_CYCLE_POPUP_MODE_NONE,
 +    OB_FOCUS_CYCLE_POPUP_MODE_ICONS,
 +    OB_FOCUS_CYCLE_POPUP_MODE_LIST
 +} ObFocusCyclePopupMode;
 +
  void focus_cycle_popup_startup(gboolean reconfig);
  void focus_cycle_popup_shutdown(gboolean reconfig);
  
  void focus_cycle_popup_show(struct _ObClient *c, gboolean iconic_windows,
                              gboolean all_desktops, gboolean dock_windows,
 -                            gboolean desktop_windows);
 -void focus_cycle_popup_hide();
 +                            gboolean desktop_windows,
 +                            ObFocusCyclePopupMode mode);
 +void focus_cycle_popup_hide(void);
  
  void focus_cycle_popup_single_show(struct _ObClient *c,
                                     gboolean iconic_windows,
                                     gboolean all_desktops,
                                     gboolean dock_windows,
                                     gboolean desktop_windows);
 -void focus_cycle_popup_single_hide();
 +void focus_cycle_popup_single_hide(void);
  
- /*! Returns TRUE if the popup is showing the client, otherwise FALSE. */
- gboolean focus_cycle_popup_is_showing(struct _ObClient *client);
+ gboolean focus_cycle_popup_is_showing(struct _ObClient *c);
+ /*! Redraws the focus cycle popup, and returns the current target.  If
+     the target given to the function is no longer valid, this will return
+     a different target that is valid, and which should be considered the
+     current focus cycling target. */
+ struct _ObClient *focus_cycle_popup_refresh(struct _ObClient *target,
+                                             gboolean redraw);
  
  #endif
diff --combined openbox/menuframe.c
  #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
@@@ -56,7 -57,7 +56,7 @@@ static gboolean submenu_hide_timeout(gp
  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);
  }
@@@ -93,7 -94,7 +93,7 @@@ 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->client = client;
      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);
  */
  static void remove_submenu_hide_timeout(ObMenuFrame *child)
  {
 -    ob_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout,
 -                                     child, FALSE);
 +    obt_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout,
 +                                      child, FALSE);
  }
  
  gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
      }
      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);
@@@ -1072,7 -1061,7 +1072,7 @@@ static void menu_frame_hide(ObMenuFram
      }
  
      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);
@@@ -1084,7 -1073,7 +1084,7 @@@ void menu_frame_hide_all(void
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
 -        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);
@@@ -1098,8 -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 */
 -                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);
          }
@@@ -1181,7 -1170,7 +1181,7 @@@ void menu_frame_select(ObMenuFrame *sel
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
 -        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 (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);
          }
      }
  
                  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 */
@@@ -1300,7 -1289,7 +1300,7 @@@ void menu_frame_select_previous(ObMenuF
              }
          }
      }
-     menu_frame_select(self, it ? it->data : NULL, TRUE);
+     menu_frame_select(self, it ? it->data : NULL, FALSE);
  }
  
  void menu_frame_select_next(ObMenuFrame *self)
              }
          }
      }
-     menu_frame_select(self, it ? it->data : NULL, TRUE);
+     menu_frame_select(self, it ? it->data : NULL, FALSE);
+ }
+ void menu_frame_select_first(ObMenuFrame *self)
+ {
+     GList *it = NULL;
+     if (self->entries) {
+         for (it = self->entries; it; it = g_list_next(it)) {
+             ObMenuEntryFrame *e = it->data;
+             if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                 break;
+             if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
+                 break;
+         }
+     }
+     menu_frame_select(self, it ? it->data : NULL, FALSE);
+ }
+ void menu_frame_select_last(ObMenuFrame *self)
+ {
+     GList *it = NULL;
+     if (self->entries) {
+         for (it = g_list_last(self->entries); it; it = g_list_previous(it)) {
+             ObMenuEntryFrame *e = it->data;
+             if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                 break;
+             if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
+                 break;
+         }
+     }
+     menu_frame_select(self, it ? it->data : NULL, FALSE);
  }
diff --combined openbox/menuframe.h
@@@ -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;
@@@ -118,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);
@@@ -127,6 -127,8 +127,8 @@@ void menu_frame_select(ObMenuFrame *sel
                         gboolean immediate);
  void menu_frame_select_previous(ObMenuFrame *self);
  void menu_frame_select_next(ObMenuFrame *self);
+ void menu_frame_select_first(ObMenuFrame *self);
+ void menu_frame_select_last(ObMenuFrame *self);
  
  ObMenuFrame* menu_frame_under(gint x, gint y);
  ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y);
diff --combined openbox/openbox.c
  #include "openbox.h"
  #include "session.h"
  #include "dock.h"
 -#include "modkeys.h"
  #include "event.h"
  #include "menu.h"
  #include "client.h"
 -#include "xerror.h"
 -#include "prop.h"
  #include "screen.h"
  #include "actions.h"
  #include "startupnotify.h"
  #include "framerender.h"
  #include "keyboard.h"
  #include "mouse.h"
 -#include "extensions.h"
  #include "menuframe.h"
  #include "grab.h"
  #include "group.h"
  #include "config.h"
  #include "ping.h"
 -#include "mainloop.h"
  #include "prompt.h"
  #include "gettext.h"
 -#include "parser/parse.h"
 -#include "render/render.h"
 -#include "render/theme.h"
 +#include "obrender/render.h"
 +#include "obrender/theme.h"
 +#include "obt/display.h"
 +#include "obt/prop.h"
 +#include "obt/keyboard.h"
 +#include "obt/xml.h"
  
  #ifdef HAVE_FCNTL_H
  #  include <fcntl.h>
@@@ -86,7 -88,8 +86,7 @@@
  RrInstance   *ob_rr_inst;
  RrImageCache *ob_rr_icons;
  RrTheme      *ob_rr_theme;
 -ObMainLoop   *ob_main_loop;
 -Display      *ob_display;
 +ObtMainLoop  *ob_main_loop;
  gint          ob_screen;
  gboolean      ob_replace_wm = FALSE;
  gboolean      ob_sm_use = TRUE;
@@@ -119,8 -122,6 +119,8 @@@ gint main(gint argc, gchar **argv
  
      ob_set_state(OB_STATE_STARTING);
  
 +    ob_debug_startup();
 +
      /* initialize the locale */
      if (!setlocale(LC_ALL, ""))
          g_message("Couldn't set locale from environment.");
      program_name = g_path_get_basename(argv[0]);
      g_set_prgname(program_name);
  
 -    if (!remote_control) {
 -        parse_paths_startup();
 -
 +    if (!remote_control)
          session_startup(argc, argv);
 -    }
  
 -    ob_display = XOpenDisplay(NULL);
 -    if (ob_display == NULL)
 +    if (!obt_display_open(NULL))
          ob_exit_with_error(_("Failed to open the display from the DISPLAY environment variable."));
 -    if (fcntl(ConnectionNumber(ob_display), F_SETFD, 1) == -1)
 -        ob_exit_with_error("Failed to set display as close-on-exec");
  
      if (remote_control) {
 -        prop_startup();
 -
          /* Send client message telling the OB process to:
           * remote_control = 1 -> reconfigure
           * remote_control = 2 -> restart */
 -        PROP_MSG(RootWindow(ob_display, ob_screen),
 -                 ob_control, remote_control, 0, 0, 0);
 -        XCloseDisplay(ob_display);
 +        OBT_PROP_MSG(ob_screen, obt_root(ob_screen),
 +                     OB_CONTROL, remote_control, 0, 0, 0, 0);
 +        obt_display_close();
          exit(EXIT_SUCCESS);
      }
  
 -    ob_main_loop = ob_main_loop_new(ob_display);
 +    ob_main_loop = obt_main_loop_new();
  
      /* set up signal handler */
 -    ob_main_loop_signal_add(ob_main_loop, SIGUSR1, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGUSR2, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGTERM, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGINT, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGHUP, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGPIPE, signal_handler, NULL, NULL);
 -    ob_main_loop_signal_add(ob_main_loop, SIGCHLD, signal_handler, NULL, NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGUSR1, signal_handler, NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGUSR2, signal_handler, NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGTERM, signal_handler, NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGINT, signal_handler,  NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGHUP, signal_handler,  NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGPIPE, signal_handler, NULL,NULL);
 +    obt_main_loop_signal_add(ob_main_loop, SIGCHLD, signal_handler, NULL,NULL);
  
 -    ob_screen = DefaultScreen(ob_display);
 +    ob_screen = DefaultScreen(obt_display);
  
 -    ob_rr_inst = RrInstanceNew(ob_display, ob_screen);
 +    ob_rr_inst = RrInstanceNew(obt_display, ob_screen);
      if (ob_rr_inst == NULL)
          ob_exit_with_error(_("Failed to initialize the obrender library."));
      /* Saving 3 resizes of an RrImage makes a lot of sense for icons, as there
      */
      ob_rr_icons = RrImageCacheNew(3);
  
 -    XSynchronize(ob_display, xsync);
 +    XSynchronize(obt_display, xsync);
  
      /* check for locale support */
      if (!XSupportsLocale())
      if (!XSetLocaleModifiers(""))
          g_message(_("Cannot set locale modifiers for the X server."));
  
 -    /* set our error handler */
 -    XSetErrorHandler(xerror_handler);
 -
      /* set the DISPLAY environment variable for any lauched children, to the
         display we're using, so they open in the right place. */
 -    setenv("DISPLAY", DisplayString(ob_display), TRUE);
 +    setenv("DISPLAY", DisplayString(obt_display), TRUE);
  
      /* create available cursors */
      cursors[OB_CURSOR_NONE] = None;
      cursors[OB_CURSOR_NORTHWEST] = load_cursor("top_left_corner",
                                                 XC_top_left_corner);
  
 -    prop_startup(); /* get atoms values for the display */
 -    extensions_query_all(); /* find which extensions are present */
 -
      if (screen_annex()) { /* it will be ours! */
          do {
              ObPrompt *xmlprompt = NULL;
  
 -            modkeys_startup(reconfigure);
 +            if (reconfigure) obt_keyboard_reload();
  
              /* get the keycodes for keys we use */
 -            keys[OB_KEY_RETURN] = modkeys_sym_to_code(XK_Return);
 -            keys[OB_KEY_ESCAPE] = modkeys_sym_to_code(XK_Escape);
 -            keys[OB_KEY_LEFT] = modkeys_sym_to_code(XK_Left);
 -            keys[OB_KEY_RIGHT] = modkeys_sym_to_code(XK_Right);
 -            keys[OB_KEY_UP] = modkeys_sym_to_code(XK_Up);
 -            keys[OB_KEY_DOWN] = modkeys_sym_to_code(XK_Down);
 -            keys[OB_KEY_TAB] = modkeys_sym_to_code(XK_Tab);
 -            keys[OB_KEY_SPACE] = modkeys_sym_to_code(XK_space);
 -            keys[OB_KEY_HOME] = modkeys_sym_to_code(XK_Home);
 -            keys[OB_KEY_END] = modkeys_sym_to_code(XK_End);
 +            keys[OB_KEY_RETURN] = obt_keyboard_keysym_to_keycode(XK_Return);
 +            keys[OB_KEY_ESCAPE] = obt_keyboard_keysym_to_keycode(XK_Escape);
 +            keys[OB_KEY_LEFT] = obt_keyboard_keysym_to_keycode(XK_Left);
 +            keys[OB_KEY_RIGHT] = obt_keyboard_keysym_to_keycode(XK_Right);
 +            keys[OB_KEY_UP] = obt_keyboard_keysym_to_keycode(XK_Up);
 +            keys[OB_KEY_DOWN] = obt_keyboard_keysym_to_keycode(XK_Down);
 +            keys[OB_KEY_TAB] = obt_keyboard_keysym_to_keycode(XK_Tab);
 +            keys[OB_KEY_SPACE] = obt_keyboard_keysym_to_keycode(XK_space);
++            keys[OB_KEY_HOME] = obt_keyboard_keysym_to_keycode(XK_Home);
++            keys[OB_KEY_END] = obt_keyboard_keysym_to_keycode(XK_End);
  
              {
 -                ObParseInst *i;
 -                xmlDocPtr doc;
 -                xmlNodePtr node;
 +                ObtXmlInst *i;
  
                  /* startup the parsing so everything can register sections
                     of the rc */
 -                i = parse_startup();
 +                i = obt_xml_instance_new();
  
                  /* register all the available actions */
                  actions_startup(reconfigure);
                  config_startup(i);
  
                  /* parse/load user options */
 -                if (parse_load_rc(config_file, &doc, &node)) {
 -                    parse_tree(i, doc, node->xmlChildrenNode);
 -                    parse_close(doc);
 +                if ((config_file &&
 +                     obt_xml_load_file(i, config_file, "openbox_config")) ||
 +                    obt_xml_load_config_file(i, "openbox", "rc.xml",
 +                                             "openbox_config"))
 +                {
 +                    obt_xml_tree_from_root(i);
 +                    obt_xml_close(i);
                  }
                  else {
                      g_message(_("Unable to find a valid config file, using some simple defaults"));
                      gchar *p = g_filename_to_utf8(config_file, -1,
                                                    NULL, NULL, NULL);
                      if (p)
 -                        PROP_SETS(RootWindow(ob_display, ob_screen),
 -                                  ob_config_file, p);
 +                        OBT_PROP_SETS(obt_root(ob_screen), OB_CONFIG_FILE,
 +                                      utf8, p);
                      g_free(p);
                  }
                  else
 -                    PROP_ERASE(RootWindow(ob_display, ob_screen),
 -                               ob_config_file);
 +                    OBT_PROP_ERASE(obt_root(ob_screen), OB_CONFIG_FILE);
  
                  /* we're done with parsing now, kill it */
 -                parse_shutdown(i);
 +                obt_xml_instance_unref(i);
              }
  
              /* load the theme specified in the rc file */
                                          config_font_inactivewindow,
                                          config_font_menutitle,
                                          config_font_menuitem,
 -                                        config_font_osd)))
 +                                        config_font_activeosd,
 +                                        config_font_inactiveosd)))
                  {
                      RrThemeFree(ob_rr_theme);
                      ob_rr_theme = theme;
                  if (ob_rr_theme == NULL)
                      ob_exit_with_error(_("Unable to load a theme."));
  
 -                PROP_SETS(RootWindow(ob_display, ob_screen),
 -                          ob_theme, ob_rr_theme->name);
 +                OBT_PROP_SETS(obt_root(ob_screen),
 +                              OB_THEME, utf8, ob_rr_theme->name);
              }
  
              if (reconfigure) {
                  ObWindow *w;
  
                  /* get all the existing windows */
 -                client_manage_all();
 +                window_manage_all();
                  focus_nothing();
  
                  /* focus what was focused if a wm was already running */
 -                if (PROP_GET32(RootWindow(ob_display, ob_screen),
 -                               net_active_window, window, &xid) &&
 -                    (w = g_hash_table_lookup(window_map, &xid)) &&
 -                    WINDOW_IS_CLIENT(w))
 +                if (OBT_PROP_GET32(obt_root(ob_screen),
 +                                   NET_ACTIVE_WINDOW, WINDOW, &xid) &&
 +                    (w = window_find(xid)) && WINDOW_IS_CLIENT(w))
                  {
                      client_focus(WINDOW_AS_CLIENT(w));
                  }
                  }
              }
  
 -            ob_main_loop_run(ob_main_loop);
 +            obt_main_loop_run(ob_main_loop);
              ob_set_state(reconfigure ?
                           OB_STATE_RECONFIGURING : OB_STATE_EXITING);
  
                  xmlprompt = NULL;
              }
  
 -            if (!reconfigure) {
 -                dock_remove_all();
 -                client_unmanage_all();
 -            }
 +            if (!reconfigure)
 +                window_unmanage_all();
  
              prompt_shutdown(reconfigure);
              menu_shutdown(reconfigure);
              g_free(keys[OB_KEY_DOWN]);
              g_free(keys[OB_KEY_TAB]);
              g_free(keys[OB_KEY_SPACE]);
 -
 -            modkeys_shutdown(reconfigure);
+             g_free(keys[OB_KEY_HOME]);
+             g_free(keys[OB_KEY_END]);
          } while (reconfigure);
      }
  
 -    XSync(ob_display, FALSE);
 +    XSync(obt_display, FALSE);
  
      RrThemeFree(ob_rr_theme);
      RrImageCacheUnref(ob_rr_icons);
  
      session_shutdown(being_replaced);
  
 -    XCloseDisplay(ob_display);
 -
 -    parse_paths_shutdown();
 +    obt_display_close();
  
      if (restart) {
 +        ob_debug_shutdown();
          if (restart_path != NULL) {
              gint argcp;
              gchar **argvp;
      g_free(ob_sm_id);
      g_free(program_name);
  
 +    if (!restart)
 +        ob_debug_shutdown();
 +
      return exitcode;
  }
  
@@@ -489,11 -509,11 +493,11 @@@ static void signal_handler(gint signal
  {
      switch (signal) {
      case SIGUSR1:
 -        ob_debug("Caught signal %d. Restarting.\n", signal);
 +        ob_debug("Caught signal %d. Restarting.", signal);
          ob_restart();
          break;
      case SIGUSR2:
 -        ob_debug("Caught signal %d. Reconfiguring.\n", signal);
 +        ob_debug("Caught signal %d. Reconfiguring.", signal);
          ob_reconfigure();
          break;
      case SIGCHLD:
          while (waitpid(-1, NULL, WNOHANG) > 0);
          break;
      default:
 -        ob_debug("Caught signal %d. Exiting.\n", signal);
 +        ob_debug("Caught signal %d. Exiting.", signal);
          /* TERM and INT return a 0 code */
          ob_exit(!(signal == SIGTERM || signal == SIGINT));
      }
  }
  
 -static void print_version()
 +static void print_version(void)
  {
      g_print("Openbox %s\n", PACKAGE_VERSION);
      g_print(_("Copyright (c)"));
      g_print("under certain conditions. See the file COPYING for details.\n\n");
  }
  
 -static void print_help()
 +static void print_help(void)
  {
      g_print(_("Syntax: openbox [options]\n"));
      g_print(_("\nOptions:\n"));
      g_print(_("  --sync              Run in synchronous mode\n"));
      g_print(_("  --debug             Display debugging output\n"));
      g_print(_("  --debug-focus       Display debugging output for focus handling\n"));
 +    g_print(_("  --debug-session     Display debugging output for session management\n"));
      g_print(_("  --debug-xinerama    Split the display into fake xinerama screens\n"));
      g_print(_("\nPlease report bugs at %s\n"), PACKAGE_BUGREPORT);
  }
@@@ -555,7 -574,7 +559,7 @@@ static void remove_args(gint *argc, gch
      *argc -= num;
  }
  
 -static void parse_env()
 +static void parse_env(void)
  {
      const gchar *id;
  
@@@ -599,15 -618,16 +603,15 @@@ static void parse_args(gint *argc, gcha
              xsync = TRUE;
          }
          else if (!strcmp(argv[i], "--debug")) {
 -            ob_debug_show_output(TRUE);
 -            ob_debug_enable(OB_DEBUG_SM, TRUE);
 +            ob_debug_enable(OB_DEBUG_NORMAL, TRUE);
              ob_debug_enable(OB_DEBUG_APP_BUGS, TRUE);
          }
          else if (!strcmp(argv[i], "--debug-focus")) {
 -            ob_debug_show_output(TRUE);
 -            ob_debug_enable(OB_DEBUG_SM, TRUE);
 -            ob_debug_enable(OB_DEBUG_APP_BUGS, TRUE);
              ob_debug_enable(OB_DEBUG_FOCUS, TRUE);
          }
 +        else if (!strcmp(argv[i], "--debug-session")) {
 +            ob_debug_enable(OB_DEBUG_SM, TRUE);
 +        }
          else if (!strcmp(argv[i], "--debug-xinerama")) {
              ob_debug_xinerama = TRUE;
          }
                     what we want */
                  config_file = argv[i+1];
                  ++i; /* skip the argument */
 -                ob_debug("--config-file %s\n", config_file);
 +                ob_debug("--config-file %s", config_file);
              }
          }
          else if (!strcmp(argv[i], "--sm-save-file")) {
                  ob_sm_save_file = g_strdup(argv[i+1]);
                  remove_args(argc, argv, i, 2);
                  --i; /* this arg was removed so go back */
 -                ob_debug_type(OB_DEBUG_SM, "--sm-save-file %s\n",
 +                ob_debug_type(OB_DEBUG_SM, "--sm-save-file %s",
                                ob_sm_save_file);
              }
          }
                  ob_sm_id = g_strdup(argv[i+1]);
                  remove_args(argc, argv, i, 2);
                  --i; /* this arg was removed so go back */
 -                ob_debug_type(OB_DEBUG_SM, "--sm-client-id %s\n", ob_sm_id);
 +                ob_debug_type(OB_DEBUG_SM, "--sm-client-id %s", ob_sm_id);
              }
          }
          else if (!strcmp(argv[i], "--sm-disable")) {
@@@ -676,16 -696,16 +680,16 @@@ static Cursor load_cursor(const gchar *
      Cursor c = None;
  
  #if USE_XCURSOR
 -    c = XcursorLibraryLoadCursor(ob_display, name);
 +    c = XcursorLibraryLoadCursor(obt_display, name);
  #endif
      if (c == None)
 -        c = XCreateFontCursor(ob_display, fontval);
 +        c = XCreateFontCursor(obt_display, fontval);
      return c;
  }
  
  void ob_exit_with_error(const gchar *msg)
  {
 -    g_message(msg);
 +    g_message("%s", msg);
      session_shutdown(TRUE);
      exit(EXIT_FAILURE);
  }
@@@ -696,13 -716,13 +700,13 @@@ void ob_restart_other(const gchar *path
      ob_restart();
  }
  
 -void ob_restart()
 +void ob_restart(void)
  {
      restart = TRUE;
      ob_exit(0);
  }
  
 -void ob_reconfigure()
 +void ob_reconfigure(void)
  {
      reconfigure = TRUE;
      ob_exit(0);
  void ob_exit(gint code)
  {
      exitcode = code;
 -    ob_main_loop_exit(ob_main_loop);
 +    obt_main_loop_exit(ob_main_loop);
  }
  
 -void ob_exit_replace()
 +void ob_exit_replace(void)
  {
      exitcode = 0;
      being_replaced = TRUE;
 -    ob_main_loop_exit(ob_main_loop);
 +    obt_main_loop_exit(ob_main_loop);
  }
  
  Cursor ob_cursor(ObCursor cursor)
@@@ -737,7 -757,7 +741,7 @@@ gboolean ob_keycode_match(KeyCode code
      return FALSE;
  }
  
 -ObState ob_state()
 +ObState ob_state(void)
  {
      return state;
  }
diff --combined openbox/screen.c
  #include "debug.h"
  #include "openbox.h"
  #include "dock.h"
 -#include "xerror.h"
 -#include "prop.h"
  #include "grab.h"
  #include "startupnotify.h"
  #include "moveresize.h"
  #include "config.h"
 -#include "mainloop.h"
  #include "screen.h"
  #include "client.h"
  #include "session.h"
  #include "focus.h"
  #include "focus_cycle.h"
  #include "popup.h"
 -#include "extensions.h"
 -#include "render/render.h"
++#include "version.h"
 +#include "obrender/render.h"
  #include "gettext.h"
 +#include "obt/display.h"
 +#include "obt/prop.h"
 +#include "obt/mainloop.h"
  
  #include <X11/Xlib.h>
  #ifdef HAVE_UNISTD_H
@@@ -78,7 -79,6 +79,7 @@@ static GSList *struts_right = NULL
  static GSList *struts_bottom = NULL;
  
  static ObPagerPopup *desktop_popup;
 +static gboolean      desktop_popup_perm;
  
  /*! The number of microseconds that you need to be on a desktop before it will
    replace the remembered "last desktop" */
@@@ -92,10 -92,10 +93,10 @@@ static gboolean replace_wm(void
      Time timestamp;
  
      wm_sn = g_strdup_printf("WM_S%d", ob_screen);
 -    wm_sn_atom = XInternAtom(ob_display, wm_sn, FALSE);
 +    wm_sn_atom = XInternAtom(obt_display, wm_sn, FALSE);
      g_free(wm_sn);
  
 -    current_wm_sn_owner = XGetSelectionOwner(ob_display, wm_sn_atom);
 +    current_wm_sn_owner = XGetSelectionOwner(obt_display, wm_sn_atom);
      if (current_wm_sn_owner == screen_support_win)
          current_wm_sn_owner = None;
      if (current_wm_sn_owner) {
                        ob_screen);
              return FALSE;
          }
 -        xerror_set_ignore(TRUE);
 -        xerror_occured = FALSE;
 +        obt_display_ignore_errors(TRUE);
  
          /* We want to find out when the current selection owner dies */
 -        XSelectInput(ob_display, current_wm_sn_owner, StructureNotifyMask);
 -        XSync(ob_display, FALSE);
 +        XSelectInput(obt_display, current_wm_sn_owner, StructureNotifyMask);
 +        XSync(obt_display, FALSE);
  
 -        xerror_set_ignore(FALSE);
 -        if (xerror_occured)
 +        obt_display_ignore_errors(FALSE);
 +        if (obt_display_error_occured)
              current_wm_sn_owner = None;
      }
  
      timestamp = event_get_server_time();
  
 -    XSetSelectionOwner(ob_display, wm_sn_atom, screen_support_win,
 +    XSetSelectionOwner(obt_display, wm_sn_atom, screen_support_win,
                         timestamp);
  
 -    if (XGetSelectionOwner(ob_display, wm_sn_atom) != screen_support_win) {
 +    if (XGetSelectionOwner(obt_display, wm_sn_atom) != screen_support_win) {
          g_message(_("Could not acquire window manager selection on screen %d"),
                    ob_screen);
          return FALSE;
        const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
  
        while (wait < timeout) {
 -          if (XCheckWindowEvent(ob_display, current_wm_sn_owner,
 +          if (XCheckWindowEvent(obt_display, current_wm_sn_owner,
                                  StructureNotifyMask, &event) &&
                event.type == DestroyNotify)
                break;
      }
  
      /* Send client message indicating that we are now the WM */
 -    prop_message(RootWindow(ob_display, ob_screen), prop_atoms.manager,
 -                 timestamp, wm_sn_atom, screen_support_win, 0,
 -                 SubstructureNotifyMask);
 +    obt_prop_message(ob_screen, obt_root(ob_screen), OBT_PROP_ATOM(MANAGER),
 +                     timestamp, wm_sn_atom, screen_support_win, 0, 0,
 +                     SubstructureNotifyMask);
  
      return TRUE;
  }
@@@ -160,33 -161,37 +161,33 @@@ gboolean screen_annex(void
      XSetWindowAttributes attrib;
      pid_t pid;
      gint i, num_support;
 -    Atom *prop_atoms_start, *wm_supported_pos;
      gulong *supported;
  
      /* create the netwm support window */
      attrib.override_redirect = TRUE;
      attrib.event_mask = PropertyChangeMask;
 -    screen_support_win = XCreateWindow(ob_display,
 -                                       RootWindow(ob_display, ob_screen),
 +    screen_support_win = XCreateWindow(obt_display, obt_root(ob_screen),
                                         -100, -100, 1, 1, 0,
                                         CopyFromParent, InputOutput,
                                         CopyFromParent,
                                         CWEventMask | CWOverrideRedirect,
                                         &attrib);
 -    XMapWindow(ob_display, screen_support_win);
 -    XLowerWindow(ob_display, screen_support_win);
 +    XMapWindow(obt_display, screen_support_win);
 +    XLowerWindow(obt_display, screen_support_win);
  
      if (!replace_wm()) {
 -        XDestroyWindow(ob_display, screen_support_win);
 +        XDestroyWindow(obt_display, screen_support_win);
          return FALSE;
      }
  
 -    xerror_set_ignore(TRUE);
 -    xerror_occured = FALSE;
 -    XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
 -                 ROOT_EVENTMASK);
 -    xerror_set_ignore(FALSE);
 -    if (xerror_occured) {
 +    obt_display_ignore_errors(TRUE);
 +    XSelectInput(obt_display, obt_root(ob_screen), ROOT_EVENTMASK);
 +    obt_display_ignore_errors(FALSE);
 +    if (obt_display_error_occured) {
          g_message(_("A window manager is already running on screen %d"),
                    ob_screen);
  
 -        XDestroyWindow(ob_display, screen_support_win);
 +        XDestroyWindow(obt_display, screen_support_win);
          return FALSE;
      }
  
  
      /* set the OPENBOX_PID hint */
      pid = getpid();
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               openbox_pid, cardinal, pid);
 +    OBT_PROP_SET32(obt_root(ob_screen), OPENBOX_PID, CARDINAL, pid);
  
      /* set supporting window */
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               net_supporting_wm_check, window, screen_support_win);
 +    OBT_PROP_SET32(obt_root(ob_screen),
 +                   NET_SUPPORTING_WM_CHECK, WINDOW, screen_support_win);
  
      /* set properties on the supporting window */
 -    PROP_SETS(screen_support_win, net_wm_name, "Openbox");
 -    PROP_SET32(screen_support_win, net_supporting_wm_check,
 -               window, screen_support_win);
 +    OBT_PROP_SETS(screen_support_win, NET_WM_NAME, utf8, "Openbox");
 +    OBT_PROP_SET32(screen_support_win, NET_SUPPORTING_WM_CHECK,
 +                   WINDOW, screen_support_win);
  
      /* set the _NET_SUPPORTED_ATOMS hint */
  
 -    /* this is all the atoms after net_supported in the prop_atoms struct */
 -    prop_atoms_start = (Atom*)&prop_atoms;
 -    wm_supported_pos = (Atom*)&(prop_atoms.net_supported);
 -    num_support = sizeof(prop_atoms) / sizeof(Atom) -
 -        (wm_supported_pos - prop_atoms_start) - 1;
 +    /* this is all the atoms after NET_SUPPORTED in the ObtPropAtoms enum */
 +    num_support = OBT_PROP_NUM_ATOMS - OBT_PROP_NET_SUPPORTED - 1;
      i = 0;
      supported = g_new(gulong, num_support);
 -    supported[i++] = prop_atoms.net_supporting_wm_check;
 -    supported[i++] = prop_atoms.net_wm_full_placement;
 -    supported[i++] = prop_atoms.net_current_desktop;
 -    supported[i++] = prop_atoms.net_number_of_desktops;
 -    supported[i++] = prop_atoms.net_desktop_geometry;
 -    supported[i++] = prop_atoms.net_desktop_viewport;
 -    supported[i++] = prop_atoms.net_active_window;
 -    supported[i++] = prop_atoms.net_workarea;
 -    supported[i++] = prop_atoms.net_client_list;
 -    supported[i++] = prop_atoms.net_client_list_stacking;
 -    supported[i++] = prop_atoms.net_desktop_names;
 -    supported[i++] = prop_atoms.net_close_window;
 -    supported[i++] = prop_atoms.net_desktop_layout;
 -    supported[i++] = prop_atoms.net_showing_desktop;
 -    supported[i++] = prop_atoms.net_wm_name;
 -    supported[i++] = prop_atoms.net_wm_visible_name;
 -    supported[i++] = prop_atoms.net_wm_icon_name;
 -    supported[i++] = prop_atoms.net_wm_visible_icon_name;
 -    supported[i++] = prop_atoms.net_wm_desktop;
 -    supported[i++] = prop_atoms.net_wm_strut;
 -    supported[i++] = prop_atoms.net_wm_strut_partial;
 -    supported[i++] = prop_atoms.net_wm_icon;
 -    supported[i++] = prop_atoms.net_wm_icon_geometry;
 -    supported[i++] = prop_atoms.net_wm_window_type;
 -    supported[i++] = prop_atoms.net_wm_window_type_desktop;
 -    supported[i++] = prop_atoms.net_wm_window_type_dock;
 -    supported[i++] = prop_atoms.net_wm_window_type_toolbar;
 -    supported[i++] = prop_atoms.net_wm_window_type_menu;
 -    supported[i++] = prop_atoms.net_wm_window_type_utility;
 -    supported[i++] = prop_atoms.net_wm_window_type_splash;
 -    supported[i++] = prop_atoms.net_wm_window_type_dialog;
 -    supported[i++] = prop_atoms.net_wm_window_type_normal;
 -    supported[i++] = prop_atoms.net_wm_allowed_actions;
 -    supported[i++] = prop_atoms.net_wm_action_move;
 -    supported[i++] = prop_atoms.net_wm_action_resize;
 -    supported[i++] = prop_atoms.net_wm_action_minimize;
 -    supported[i++] = prop_atoms.net_wm_action_shade;
 -    supported[i++] = prop_atoms.net_wm_action_maximize_horz;
 -    supported[i++] = prop_atoms.net_wm_action_maximize_vert;
 -    supported[i++] = prop_atoms.net_wm_action_fullscreen;
 -    supported[i++] = prop_atoms.net_wm_action_change_desktop;
 -    supported[i++] = prop_atoms.net_wm_action_close;
 -    supported[i++] = prop_atoms.net_wm_action_above;
 -    supported[i++] = prop_atoms.net_wm_action_below;
 -    supported[i++] = prop_atoms.net_wm_state;
 -    supported[i++] = prop_atoms.net_wm_state_modal;
 -    supported[i++] = prop_atoms.net_wm_state_maximized_vert;
 -    supported[i++] = prop_atoms.net_wm_state_maximized_horz;
 -    supported[i++] = prop_atoms.net_wm_state_shaded;
 -    supported[i++] = prop_atoms.net_wm_state_skip_taskbar;
 -    supported[i++] = prop_atoms.net_wm_state_skip_pager;
 -    supported[i++] = prop_atoms.net_wm_state_hidden;
 -    supported[i++] = prop_atoms.net_wm_state_fullscreen;
 -    supported[i++] = prop_atoms.net_wm_state_above;
 -    supported[i++] = prop_atoms.net_wm_state_below;
 -    supported[i++] = prop_atoms.net_wm_state_demands_attention;
 -    supported[i++] = prop_atoms.net_moveresize_window;
 -    supported[i++] = prop_atoms.net_wm_moveresize;
 -    supported[i++] = prop_atoms.net_wm_user_time;
 +    supported[i++] = OBT_PROP_ATOM(NET_SUPPORTING_WM_CHECK);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_FULL_PLACEMENT);
 +    supported[i++] = OBT_PROP_ATOM(NET_CURRENT_DESKTOP);
 +    supported[i++] = OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS);
 +    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_GEOMETRY);
 +    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_VIEWPORT);
 +    supported[i++] = OBT_PROP_ATOM(NET_ACTIVE_WINDOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_WORKAREA);
 +    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST);
 +    supported[i++] = OBT_PROP_ATOM(NET_CLIENT_LIST_STACKING);
 +    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_NAMES);
 +    supported[i++] = OBT_PROP_ATOM(NET_CLOSE_WINDOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_DESKTOP_LAYOUT);
 +    supported[i++] = OBT_PROP_ATOM(NET_SHOWING_DESKTOP);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_NAME);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_NAME);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_NAME);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_VISIBLE_ICON_NAME);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_DESKTOP);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ICON_GEOMETRY);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ALLOWED_ACTIONS);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
 +    supported[i++] = OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_MOVERESIZE);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME);
  /*
 -    supported[i++] = prop_atoms.net_wm_user_time_window;
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_USER_TIME_WINDOW);
  */
 -    supported[i++] = prop_atoms.net_frame_extents;
 -    supported[i++] = prop_atoms.net_request_frame_extents;
 -    supported[i++] = prop_atoms.net_restack_window;
 -    supported[i++] = prop_atoms.net_startup_id;
 +    supported[i++] = OBT_PROP_ATOM(NET_FRAME_EXTENTS);
 +    supported[i++] = OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS);
 +    supported[i++] = OBT_PROP_ATOM(NET_RESTACK_WINDOW);
 +    supported[i++] = OBT_PROP_ATOM(NET_STARTUP_ID);
  #ifdef SYNC
 -    supported[i++] = prop_atoms.net_wm_sync_request;
 -    supported[i++] = prop_atoms.net_wm_sync_request_counter;
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER);
  #endif
 -    supported[i++] = prop_atoms.net_wm_pid;
 -    supported[i++] = prop_atoms.net_wm_ping;
 -
 -    supported[i++] = prop_atoms.kde_wm_change_state;
 -    supported[i++] = prop_atoms.kde_net_wm_frame_strut;
 -    supported[i++] = prop_atoms.kde_net_wm_window_type_override;
 -
 -    supported[i++] = prop_atoms.ob_wm_action_undecorate;
 -    supported[i++] = prop_atoms.ob_wm_state_undecorated;
 -    supported[i++] = prop_atoms.openbox_pid;
 -    supported[i++] = prop_atoms.ob_theme;
 -    supported[i++] = prop_atoms.ob_config_file;
 -    supported[i++] = prop_atoms.ob_control;
 -    supported[i++] = prop_atoms.ob_version;
 -    supported[i++] = prop_atoms.ob_app_role;
 -    supported[i++] = prop_atoms.ob_app_name;
 -    supported[i++] = prop_atoms.ob_app_class;
 -    supported[i++] = prop_atoms.ob_app_type;
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_PID);
 +    supported[i++] = OBT_PROP_ATOM(NET_WM_PING);
 +
 +    supported[i++] = OBT_PROP_ATOM(KDE_WM_CHANGE_STATE);
 +    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_FRAME_STRUT);
 +    supported[i++] = OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE);
 +
 +    supported[i++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE);
 +    supported[i++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
 +    supported[i++] = OBT_PROP_ATOM(OPENBOX_PID);
 +    supported[i++] = OBT_PROP_ATOM(OB_THEME);
 +    supported[i++] = OBT_PROP_ATOM(OB_CONFIG_FILE);
 +    supported[i++] = OBT_PROP_ATOM(OB_CONTROL);
-     supported[i++] = OBT_PROP_ATOM(OB_ROLE);
-     supported[i++] = OBT_PROP_ATOM(OB_NAME);
-     supported[i++] = OBT_PROP_ATOM(OB_CLASS);
++    supported[i++] = OBT_PROP_ATOM(OB_VERSION);
++    supported[i++] = OBT_PROP_ATOM(OB_APP_ROLE);
++    supported[i++] = OBT_PROP_ATOM(OB_APP_NAME);
++    supported[i++] = OBT_PROP_ATOM(OB_APP_CLASS);
++    supported[i++] = OBT_PROP_ATOM(OB_APP_TYPE);
      g_assert(i == num_support);
  
 -    PROP_SETA32(RootWindow(ob_display, ob_screen),
 -                net_supported, atom, supported, num_support);
 +    OBT_PROP_SETA32(obt_root(ob_screen),
 +                    NET_SUPPORTED, ATOM, supported, num_support);
      g_free(supported);
  
 -    PROP_SETS(RootWindow(ob_display, ob_screen), ob_version,
 -              OB_VERSION);
++    OBT_PROP_SETS(RootWindow(obt_display, ob_screen), OB_VERSION, utf8,
++                  OPENBOX_VERSION);
      screen_tell_ksplash();
  
      return TRUE;
@@@ -332,14 -346,14 +338,14 @@@ static void screen_tell_ksplash(void
         hear it anyways. perhaps it is for old ksplash. or new ksplash. or
         something. oh well. */
      e.xclient.type = ClientMessage;
 -    e.xclient.display = ob_display;
 -    e.xclient.window = RootWindow(ob_display, ob_screen);
 +    e.xclient.display = obt_display;
 +    e.xclient.window = obt_root(ob_screen);
      e.xclient.message_type =
 -        XInternAtom(ob_display, "_KDE_SPLASH_PROGRESS", False);
 +        XInternAtom(obt_display, "_KDE_SPLASH_PROGRESS", False);
      e.xclient.format = 8;
      strcpy(e.xclient.data.b, "wm started");
 -    XSendEvent(ob_display, RootWindow(ob_display, ob_screen),
 -               False, SubstructureNotifyMask, &e );
 +    XSendEvent(obt_display, obt_root(ob_screen),
 +               False, SubstructureNotifyMask, &e);
  }
  
  void screen_startup(gboolean reconfig)
      gboolean namesexist = FALSE;
  
      desktop_popup = pager_popup_new();
 +    desktop_popup_perm = FALSE;
      pager_popup_height(desktop_popup, POPUP_HEIGHT);
  
      if (reconfig) {
      screen_resize();
  
      /* have names already been set for the desktops? */
 -    if (PROP_GETSS(RootWindow(ob_display, ob_screen),
 -                   net_desktop_names, utf8, &names))
 -    {
 +    if (OBT_PROP_GETSS(obt_root(ob_screen), NET_DESKTOP_NAMES, utf8, &names)) {
          g_strfreev(names);
          namesexist = TRUE;
      }
              names[i] = g_strdup(it->data);
  
          /* set the root window property */
 -        PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,names);
 +        OBT_PROP_SETSS(obt_root(ob_screen),
 +                       NET_DESKTOP_NAMES, utf8, (const gchar**)names);
  
          g_strfreev(names);
      }
         this will also set the default names from the config file up for
         desktops that don't have names yet */
      screen_num_desktops = 0;
 -    if (PROP_GET32(RootWindow(ob_display, ob_screen),
 -                   net_number_of_desktops, cardinal, &d))
 +    if (OBT_PROP_GET32(obt_root(ob_screen),
 +                       NET_NUMBER_OF_DESKTOPS, CARDINAL, &d))
      {
          if (d != config_desktops_num) {
              /* TRANSLATORS: If you need to specify a different order of the
  
      screen_desktop = screen_num_desktops;  /* something invalid */
      /* start on the current desktop when a wm was already running */
 -    if (PROP_GET32(RootWindow(ob_display, ob_screen),
 -                   net_current_desktop, cardinal, &d) &&
 +    if (OBT_PROP_GET32(obt_root(ob_screen),
 +                       NET_CURRENT_DESKTOP, CARDINAL, &d) &&
          d < screen_num_desktops)
      {
          screen_set_desktop(d, FALSE);
  
      /* don't start in showing-desktop mode */
      screen_showing_desktop = FALSE;
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               net_showing_desktop, cardinal, screen_showing_desktop);
 +    OBT_PROP_SET32(obt_root(ob_screen),
 +                   NET_SHOWING_DESKTOP, CARDINAL, screen_showing_desktop);
  
      if (session_desktop_layout_present &&
          screen_validate_layout(&session_desktop_layout))
@@@ -451,16 -465,17 +457,16 @@@ void screen_shutdown(gboolean reconfig
      if (reconfig)
          return;
  
 -    XSelectInput(ob_display, RootWindow(ob_display, ob_screen),
 -                 NoEventMask);
 +    XSelectInput(obt_display, obt_root(ob_screen), NoEventMask);
  
      /* we're not running here no more! */
 -    PROP_ERASE(RootWindow(ob_display, ob_screen), openbox_pid);
 +    OBT_PROP_ERASE(obt_root(ob_screen), OPENBOX_PID);
      /* not without us */
 -    PROP_ERASE(RootWindow(ob_display, ob_screen), net_supported);
 +    OBT_PROP_ERASE(obt_root(ob_screen), NET_SUPPORTED);
      /* don't keep this mode */
 -    PROP_ERASE(RootWindow(ob_display, ob_screen), net_showing_desktop);
 +    OBT_PROP_ERASE(obt_root(ob_screen), NET_SHOWING_DESKTOP);
  
 -    XDestroyWindow(ob_display, screen_support_win);
 +    XDestroyWindow(obt_display, screen_support_win);
  
      g_strfreev(screen_desktop_names);
      screen_desktop_names = NULL;
@@@ -473,8 -488,8 +479,8 @@@ void screen_resize(void
      GList *it;
      gulong geometry[2];
  
 -    w = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
 -    h = HeightOfScreen(ScreenOfDisplay(ob_display, ob_screen));
 +    w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
 +    h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
  
      if (w == oldw && h == oldh) return;
  
      /* Set the _NET_DESKTOP_GEOMETRY hint */
      screen_physical_size.width = geometry[0] = w;
      screen_physical_size.height = geometry[1] = h;
 -    PROP_SETA32(RootWindow(ob_display, ob_screen),
 -                net_desktop_geometry, cardinal, geometry, 2);
 +    OBT_PROP_SETA32(obt_root(ob_screen),
 +                    NET_DESKTOP_GEOMETRY, CARDINAL, geometry, 2);
  
      if (ob_state() != OB_STATE_RUNNING)
          return;
  
  void screen_set_num_desktops(guint num)
  {
 -    guint old;
      gulong *viewport;
      GList *it, *stacking_copy;
  
  
      if (screen_num_desktops == num) return;
  
 -    old = screen_num_desktops;
      screen_num_desktops = num;
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               net_number_of_desktops, cardinal, num);
 +    OBT_PROP_SET32(obt_root(ob_screen), NET_NUMBER_OF_DESKTOPS, CARDINAL, num);
  
      /* set the viewport hint */
      viewport = g_new0(gulong, num * 2);
 -    PROP_SETA32(RootWindow(ob_display, ob_screen),
 -                net_desktop_viewport, cardinal, viewport, num * 2);
 +    OBT_PROP_SETA32(obt_root(ob_screen),
 +                    NET_DESKTOP_VIEWPORT, CARDINAL, viewport, num * 2);
      g_free(viewport);
  
      /* the number of rows/columns will differ */
@@@ -607,7 -625,8 +613,7 @@@ void screen_set_desktop(guint num, gboo
  
      if (previous == num) return;
  
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               net_current_desktop, cardinal, num);
 +    OBT_PROP_SET32(obt_root(ob_screen), NET_CURRENT_DESKTOP, CARDINAL, num);
  
      /* This whole thing decides when/how to save the screen_last_desktop so
         that it can be restored later if you want */
          }
      }
      screen_desktop_timeout = FALSE;
 -    ob_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
 -    ob_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
 -                             last_desktop_func, NULL, NULL, NULL);
 +    obt_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
 +    obt_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
 +                              last_desktop_func, NULL, NULL, NULL);
  
 -    ob_debug("Moving to desktop %d\n", num+1);
 +    ob_debug("Moving to desktop %d", num+1);
  
      if (ob_state() == OB_STATE_RUNNING)
 -        screen_show_desktop_popup(screen_desktop);
 +        screen_show_desktop_popup(screen_desktop, FALSE);
  
      /* ignore enter events caused by the move */
      ignore_start = event_start_ignore_all_enters();
          if (WINDOW_IS_CLIENT(it->data)) {
              ObClient *c = it->data;
              if (client_hide(c)) {
-                 /* in the middle of cycling..? kill it. */
-                 focus_cycle_stop(c);
                  if (c == focus_client) {
                      /* c was focused and we didn't do fallback clearly so make
                         sure openbox doesnt still consider the window focused.
          }
      }
  
+     focus_cycle_addremove(NULL, TRUE);
      event_end_ignore_all_enters(ignore_start);
  
      if (event_curtime != CurrentTime)
@@@ -749,7 -767,7 +754,7 @@@ void screen_add_desktop(gboolean curren
                     parent - which will have to be on the same desktop */
                  !client_direct_parent(c))
              {
 -                ob_debug("moving window %s\n", c->title);
 +                ob_debug("moving window %s", c->title);
                  client_set_desktop(c, c->desktop+1, FALSE, TRUE);
              }
          }
@@@ -790,7 -808,7 +795,7 @@@ void screen_remove_desktop(gboolean cur
                     parent - which will have to be on the same desktop */
                  !client_direct_parent(c))
              {
 -                ob_debug("moving window %s\n", c->title);
 +                ob_debug("moving window %s", c->title);
                  client_set_desktop(c, c->desktop - 1, TRUE, TRUE);
              }
              /* raise all the windows that are on the current desktop which
                  (d == DESKTOP_ALL || d == screen_desktop))
              {
                  stacking_raise(CLIENT_AS_WINDOW(c));
 -                ob_debug("raising window %s\n", c->title);
 +                ob_debug("raising window %s", c->title);
              }
          }
      }
      /* fallback focus like we're changing desktops */
      if (screen_desktop < screen_num_desktops - 1) {
          screen_fallback_focus();
 -        ob_debug("fake desktop change\n");
 +        ob_debug("fake desktop change");
      }
  
      screen_set_num_desktops(screen_num_desktops-1);
@@@ -931,7 -949,7 +936,7 @@@ static gboolean hide_desktop_popup_func
      return FALSE; /* don't repeat */
  }
  
 -void screen_show_desktop_popup(guint d)
 +void screen_show_desktop_popup(guint d, gboolean perm)
  {
      Rect *a;
  
                            MAX(a->width/3, POPUP_WIDTH));
      pager_popup_show(desktop_popup, screen_desktop_names[d], d);
  
 -    ob_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
 -    ob_main_loop_timeout_add(ob_main_loop, config_desktop_popup_time * 1000,
 -                             hide_desktop_popup_func, NULL, NULL, NULL);
 +    obt_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
 +    if (!perm && !desktop_popup_perm)
 +        /* only hide if its not already being show permanently */
 +        obt_main_loop_timeout_add(ob_main_loop,
 +                                  config_desktop_popup_time * 1000,
 +                                  hide_desktop_popup_func, desktop_popup,
 +                                  g_direct_equal, NULL);
 +    if (perm)
 +        desktop_popup_perm = TRUE;
 +
      g_free(a);
  }
  
  void screen_hide_desktop_popup(void)
  {
 -    ob_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
 +    obt_main_loop_timeout_remove_data(ob_main_loop, hide_desktop_popup_func,
 +                                      desktop_popup, FALSE);
      pager_popup_hide(desktop_popup);
 +    desktop_popup_perm = FALSE;
  }
  
  guint screen_find_desktop(guint from, ObDirection dir,
@@@ -1126,13 -1135,13 +1131,13 @@@ void screen_update_layout(void
      screen_desktop_layout.rows = 1;
      screen_desktop_layout.columns = screen_num_desktops;
  
 -    if (PROP_GETA32(RootWindow(ob_display, ob_screen),
 -                    net_desktop_layout, cardinal, &data, &num)) {
 +    if (OBT_PROP_GETA32(obt_root(ob_screen),
 +                        NET_DESKTOP_LAYOUT, CARDINAL, &data, &num)) {
          if (num == 3 || num == 4) {
  
 -            if (data[0] == prop_atoms.net_wm_orientation_vert)
 +            if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_VERT))
                  l.orientation = OB_ORIENTATION_VERT;
 -            else if (data[0] == prop_atoms.net_wm_orientation_horz)
 +            else if (data[0] == OBT_PROP_ATOM(NET_WM_ORIENTATION_HORZ))
                  l.orientation = OB_ORIENTATION_HORZ;
              else
                  return;
              if (num < 4)
                  l.start_corner = OB_CORNER_TOPLEFT;
              else {
 -                if (data[3] == prop_atoms.net_wm_topleft)
 +                if (data[3] == OBT_PROP_ATOM(NET_WM_TOPLEFT))
                      l.start_corner = OB_CORNER_TOPLEFT;
 -                else if (data[3] == prop_atoms.net_wm_topright)
 +                else if (data[3] == OBT_PROP_ATOM(NET_WM_TOPRIGHT))
                      l.start_corner = OB_CORNER_TOPRIGHT;
 -                else if (data[3] == prop_atoms.net_wm_bottomright)
 +                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMRIGHT))
                      l.start_corner = OB_CORNER_BOTTOMRIGHT;
 -                else if (data[3] == prop_atoms.net_wm_bottomleft)
 +                else if (data[3] == OBT_PROP_ATOM(NET_WM_BOTTOMLEFT))
                      l.start_corner = OB_CORNER_BOTTOMLEFT;
                  else
                      return;
@@@ -1171,8 -1180,8 +1176,8 @@@ void screen_update_desktop_names(void
      g_strfreev(screen_desktop_names);
      screen_desktop_names = NULL;
  
 -    if (PROP_GETSS(RootWindow(ob_display, ob_screen),
 -                   net_desktop_names, utf8, &screen_desktop_names))
 +    if (OBT_PROP_GETSS(obt_root(ob_screen),
 +                       NET_DESKTOP_NAMES, utf8, &screen_desktop_names))
          for (i = 0; screen_desktop_names[i] && i < screen_num_desktops; ++i);
      else
          i = 0;
  
          /* if we changed any names, then set the root property so we can
             all agree on the names */
 -        PROP_SETSS(RootWindow(ob_display, ob_screen), net_desktop_names,
 -                   screen_desktop_names);
 +        OBT_PROP_SETSS(obt_root(ob_screen), NET_DESKTOP_NAMES,
 +                       utf8, (const gchar**)screen_desktop_names);
      }
  
      /* resize the pager for these names */
@@@ -1266,23 -1275,24 +1271,23 @@@ void screen_show_desktop(gboolean show
      }
  
      show = !!show; /* make it boolean */
 -    PROP_SET32(RootWindow(ob_display, ob_screen),
 -               net_showing_desktop, cardinal, show);
 +    OBT_PROP_SET32(obt_root(ob_screen), NET_SHOWING_DESKTOP, CARDINAL, show);
  }
  
  void screen_install_colormap(ObClient *client, gboolean install)
  {
      if (client == NULL || client->colormap == None) {
          if (install)
 -            XInstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
 +            XInstallColormap(obt_display, RrColormap(ob_rr_inst));
          else
 -            XUninstallColormap(RrDisplay(ob_rr_inst), RrColormap(ob_rr_inst));
 +            XUninstallColormap(obt_display, RrColormap(ob_rr_inst));
      } else {
 -        xerror_set_ignore(TRUE);
 +        obt_display_ignore_errors(TRUE);
          if (install)
 -            XInstallColormap(RrDisplay(ob_rr_inst), client->colormap);
 +            XInstallColormap(obt_display, client->colormap);
          else
 -            XUninstallColormap(RrDisplay(ob_rr_inst), client->colormap);
 -        xerror_set_ignore(FALSE);
 +            XUninstallColormap(obt_display, client->colormap);
 +        obt_display_ignore_errors(FALSE);
      }
  }
  
@@@ -1311,55 -1321,6 +1316,55 @@@ typedef struct 
      } \
  }
  
 +static void get_xinerama_screens(Rect **xin_areas, guint *nxin)
 +{
 +    guint i;
 +    gint n, l, r, t, b;
 +#ifdef XINERAMA
 +    XineramaScreenInfo *info;
 +#endif
 +
 +    if (ob_debug_xinerama) {
 +        gint w = WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen));
 +        gint h = HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen));
 +        *nxin = 2;
 +        *xin_areas = g_new(Rect, *nxin + 1);
 +        RECT_SET((*xin_areas)[0], 0, 0, w/2, h);
 +        RECT_SET((*xin_areas)[1], w/2, 0, w-(w/2), h);
 +    }
 +#ifdef XINERAMA
 +    else if (obt_display_extension_xinerama &&
 +             (info = XineramaQueryScreens(obt_display, &n))) {
 +        *nxin = n;
 +        *xin_areas = g_new(Rect, *nxin + 1);
 +        for (i = 0; i < *nxin; ++i)
 +            RECT_SET((*xin_areas)[i], info[i].x_org, info[i].y_org,
 +                     info[i].width, info[i].height);
 +        XFree(info);
 +    }
 +#endif
 +    else {
 +        *nxin = 1;
 +        *xin_areas = g_new(Rect, *nxin + 1);
 +        RECT_SET((*xin_areas)[0], 0, 0,
 +                 WidthOfScreen(ScreenOfDisplay(obt_display, ob_screen)),
 +                 HeightOfScreen(ScreenOfDisplay(obt_display, ob_screen)));
 +    }
 +
 +    /* returns one extra with the total area in it */
 +    l = (*xin_areas)[0].x;
 +    t = (*xin_areas)[0].y;
 +    r = (*xin_areas)[0].x + (*xin_areas)[0].width - 1;
 +    b = (*xin_areas)[0].y + (*xin_areas)[0].height - 1;
 +    for (i = 1; i < *nxin; ++i) {
 +        l = MIN(l, (*xin_areas)[i].x);
 +        t = MIN(l, (*xin_areas)[i].y);
 +        r = MAX(r, (*xin_areas)[i].x + (*xin_areas)[i].width - 1);
 +        b = MAX(b, (*xin_areas)[i].y + (*xin_areas)[i].height - 1);
 +    }
 +    RECT_SET((*xin_areas)[*nxin], l, t, r - l + 1, b - t + 1);
 +}
 +
  void screen_update_areas(void)
  {
      guint i;
      GList *it;
  
      g_free(monitor_area);
 -    extensions_xinerama_screens(&monitor_area, &screen_num_monitors);
 +    get_xinerama_screens(&monitor_area, &screen_num_monitors);
  
      /* set up the user-specified margins */
      config_margins.top_start = RECT_LEFT(monitor_area[screen_num_monitors]);
      }
  
      /* set the legacy workarea hint to the union of all the monitors */
 -    PROP_SETA32(RootWindow(ob_display, ob_screen), net_workarea, cardinal,
 -                dims, 4 * screen_num_desktops);
 +    OBT_PROP_SETA32(obt_root(ob_screen), NET_WORKAREA, CARDINAL,
 +                    dims, 4 * screen_num_desktops);
  
      /* the area has changed, adjust all the windows if they need it */
      for (it = client_list; it; it = g_list_next(it))
@@@ -1501,7 -1462,7 +1506,7 @@@ Rect* screen_area(guint desktop, guint 
  {
      Rect *a;
      GSList *it;
 -    gint l, r, t, b, al, ar, at, ab;
 +    gint l, r, t, b;
      guint i, d;
      gboolean us = search != NULL; /* user provided search */
  
  
      /* only include monitors which the search area lines up with */
      if (RECT_INTERSECTS_RECT(monitor_area[screen_num_monitors], *search)) {
 -        al = l = RECT_RIGHT(monitor_area[screen_num_monitors]);
 -        at = t = RECT_BOTTOM(monitor_area[screen_num_monitors]);
 -        ar = r = RECT_LEFT(monitor_area[screen_num_monitors]);
 -        ab = b = RECT_TOP(monitor_area[screen_num_monitors]);
 +        l = RECT_RIGHT(monitor_area[screen_num_monitors]);
 +        t = RECT_BOTTOM(monitor_area[screen_num_monitors]);
 +        r = RECT_LEFT(monitor_area[screen_num_monitors]);
 +        b = RECT_TOP(monitor_area[screen_num_monitors]);
          for (i = 0; i < screen_num_monitors; ++i) {
              /* add the monitor if applicable */
              if (RANGES_INTERSECT(search->x, search->width,
                                   monitor_area[i].x, monitor_area[i].width))
              {
 -                at = t = MIN(t, RECT_TOP(monitor_area[i]));
 -                ab = b = MAX(b, RECT_BOTTOM(monitor_area[i]));
 +                t = MIN(t, RECT_TOP(monitor_area[i]));
 +                b = MAX(b, RECT_BOTTOM(monitor_area[i]));
              }
              if (RANGES_INTERSECT(search->y, search->height,
                                   monitor_area[i].y, monitor_area[i].height))
              {
 -                al = l = MIN(l, RECT_LEFT(monitor_area[i]));
 -                ar = r = MAX(r, RECT_RIGHT(monitor_area[i]));
 +                l = MIN(l, RECT_LEFT(monitor_area[i]));
 +                r = MAX(r, RECT_RIGHT(monitor_area[i]));
              }
          }
      } else {
 -        al = l = RECT_LEFT(monitor_area[screen_num_monitors]);
 -        at = t = RECT_TOP(monitor_area[screen_num_monitors]);
 -        ar = r = RECT_RIGHT(monitor_area[screen_num_monitors]);
 -        ab = b = RECT_BOTTOM(monitor_area[screen_num_monitors]);
 +        l = RECT_LEFT(monitor_area[screen_num_monitors]);
 +        t = RECT_TOP(monitor_area[screen_num_monitors]);
 +        r = RECT_RIGHT(monitor_area[screen_num_monitors]);
 +        b = RECT_BOTTOM(monitor_area[screen_num_monitors]);
      }
  
      for (d = 0; d < screen_num_desktops; ++d) {
@@@ -1696,10 -1657,10 +1701,10 @@@ Rect *screen_physical_area_primary(gboo
  void screen_set_root_cursor(void)
  {
      if (sn_app_starting())
 -        XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
 +        XDefineCursor(obt_display, obt_root(ob_screen),
                        ob_cursor(OB_CURSOR_BUSYPOINTER));
      else
 -        XDefineCursor(ob_display, RootWindow(ob_display, ob_screen),
 +        XDefineCursor(obt_display, obt_root(ob_screen),
                        ob_cursor(OB_CURSOR_POINTER));
  }
  
@@@ -1725,12 -1686,12 +1730,12 @@@ gboolean screen_pointer_pos(gint *x, gi
      guint u;
      gboolean ret;
  
 -    ret = !!XQueryPointer(ob_display, RootWindow(ob_display, ob_screen),
 +    ret = !!XQueryPointer(obt_display, obt_root(ob_screen),
                            &w, &w, x, y, &i, &i, &u);
      if (!ret) {
 -        for (i = 0; i < ScreenCount(ob_display); ++i)
 +        for (i = 0; i < ScreenCount(obt_display); ++i)
              if (i != ob_screen)
 -                if (XQueryPointer(ob_display, RootWindow(ob_display, i),
 +                if (XQueryPointer(obt_display, obt_root(i),
                                    &w, &w, x, y, &i, &i, &u))
                      break;
      }
diff --combined version.h.in
index 0000000,70cfcec..1cfeb5c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,15 +1,6 @@@
 -#define OB_MAJOR_VERSION @OB_MAJOR_VERSION@
 -#define OB_MINOR_VERSION @OB_MINOR_VERSION@
 -#define OB_MICRO_VERSION @OB_MICRO_VERSION@
 -#define OB_VERSION "@OB_VERSION@"
 -
 -#define OB_CHECK_VERSION(major,minor,micro) \
 -    (OB_MAJOR_VERSION > (major) || \
 -     (OB_MAJOR_VERSION == (major) && OB_MINOR_VERSION > (minor)) || \
 -     (OB_MAJOR_VERSION == (major) && OB_MINOR_VERSION == (minor) && \
 -      OB_MICRO_VERSION >= (micro)))
+ #ifndef ob__version_h
+ #define ob__version_h
++#define OPENBOX_VERSION "@OPENBOX_VERSION@"
+ #endif