Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Fri, 18 Dec 2009 16:39:56 +0000 (11:39 -0500)
committerDana Jansens <danakj@orodu.net>
Fri, 18 Dec 2009 16:39:56 +0000 (11:39 -0500)
Conflicts:

openbox/screen.c

1  2 
openbox/event.c
openbox/focus_cycle.c
openbox/focus_cycle_popup.c
openbox/focus_cycle_popup.h
openbox/screen.c

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,8 -87,8 +84,8 @@@ typedef struc
  
  static void event_process(const XEvent *e, gpointer data);
  static void event_handle_root(XEvent *e);
 -static gboolean event_handle_menu_keyboard(XEvent *e);
 -static gboolean event_handle_menu(XEvent *e);
 +static gboolean event_handle_menu_input(XEvent *e);
 +static void event_handle_menu(ObMenuFrame *frame, XEvent *e);
  static gboolean event_handle_prompt(ObPrompt *p, XEvent *e);
  static void event_handle_dock(ObDock *s, XEvent *e);
  static void event_handle_dockapp(ObDockApp *app, XEvent *e);
@@@ -122,9 -125,9 +122,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;
      }
  }
@@@ -134,7 -137,7 +134,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);
@@@ -161,15 -164,9 +161,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
@@@ -237,8 -232,8 +237,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;
          }
@@@ -266,34 -261,34 +266,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;
@@@ -323,7 -318,7 +323,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.. */
@@@ -416,7 -411,6 +416,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);
@@@ -461,15 -454,13 +461,15 @@@ static gboolean event_ignore(XEvent *e
  
  static void event_process(const XEvent *ec, gpointer data)
  {
 +    XEvent ee, *e;
 +    ObEventData *ed = data;
 +
      Window window;
      ObClient *client = NULL;
      ObDock *dock = NULL;
      ObDockApp *dockapp = NULL;
      ObWindow *obwin = NULL;
 -    XEvent ee, *e;
 -    ObEventData *ed = data;
 +    ObMenuFrame *menu = NULL;
      ObPrompt *prompt = NULL;
  
      /* make a copy we can mangle */
      e = &ee;
  
      window = event_get_window(e);
 -    if ((obwin = g_hash_table_lookup(window_map, &window))) {
 +    if (window == obt_root(ob_screen))
 +        /* don't do any lookups, waste of cpu */;
 +    else if ((obwin = window_find(window))) {
          switch (obwin->type) {
 -        case Window_Dock:
 +        case OB_WINDOW_CLASS_DOCK:
              dock = WINDOW_AS_DOCK(obwin);
              break;
 -        case Window_DockApp:
 -            dockapp = WINDOW_AS_DOCKAPP(obwin);
 -            break;
 -        case Window_Client:
 +        case OB_WINDOW_CLASS_CLIENT:
              client = WINDOW_AS_CLIENT(obwin);
              /* events on clients can be events on prompt windows too */
              prompt = client->prompt;
              break;
 -        case Window_Menu:
 -            /* not to be used for events */
 -            g_assert_not_reached();
 +        case OB_WINDOW_CLASS_MENUFRAME:
 +            menu = WINDOW_AS_MENUFRAME(obwin);
              break;
 -        case Window_Internal:
 +        case OB_WINDOW_CLASS_INTERNAL:
              /* we don't do anything with events directly on these windows */
              break;
 -        case Window_Prompt:
 +        case OB_WINDOW_CLASS_PROMPT:
              prompt = WINDOW_AS_PROMPT(obwin);
              break;
          }
      }
 +    else
 +        dockapp = dock_find_dockapp(window);
  
      event_set_curtime(e);
      event_curserial = e->xany.serial;
  
      /* deal with it in the kernel */
  
 -    if (menu_frame_visible &&
 -        (e->type == EnterNotify || e->type == LeaveNotify))
 -    {
 -        /* crossing events for menu */
 -        event_handle_menu(e);
 -    } else if (e->type == FocusIn) {
 +    if (e->type == FocusIn) {
          if (client &&
              e->xfocus.detail == NotifyInferior)
          {
              XEvent ce;
  
              ob_debug_type(OB_DEBUG_FOCUS,
 -                          "Focus went to root or pointer root/none\n");
 +                          "Focus went to root or pointer root/none");
  
              if (e->xfocus.detail == NotifyInferior ||
                  e->xfocus.detail == NotifyNonlinear)
                 But if the other focus in is something like PointerRoot then we
                 still want to fall back.
              */
 -            if (XCheckIfEvent(ob_display, &ce, event_look_for_focusin_client,
 +            if (XCheckIfEvent(obt_display, &ce, event_look_for_focusin_client,
                                NULL))
              {
 -                XPutBackEvent(ob_display, &ce);
 +                XPutBackEvent(obt_display, &ce);
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "  but another FocusIn is coming\n");
 +                              "  but another FocusIn is coming");
              } else {
                  /* Focus has been reverted.
  
          else if (!client)
          {
              ob_debug_type(OB_DEBUG_FOCUS,
 -                          "Focus went to a window that is already gone\n");
 +                          "Focus went to a window that is already gone");
  
              /* If you send focus to a window and then it disappears, you can
                 get the FocusIn for it, after it is unmanaged.
          XEvent ce;
  
          /* Look for the followup FocusIn */
 -        if (!XCheckIfEvent(ob_display, &ce, event_look_for_focusin, NULL)) {
 +        if (!XCheckIfEvent(obt_display, &ce, event_look_for_focusin, NULL)) {
              /* There is no FocusIn, this means focus went to a window that
                 is not being managed, or a window on another screen. */
              Window win, root;
              gint i;
              guint u;
 -            xerror_set_ignore(TRUE);
 -            if (XGetInputFocus(ob_display, &win, &i) != 0 &&
 -                XGetGeometry(ob_display, win, &root, &i,&i,&u,&u,&u,&u) != 0 &&
 -                root != RootWindow(ob_display, ob_screen))
 +            obt_display_ignore_errors(TRUE);
 +            if (XGetInputFocus(obt_display, &win, &i) &&
 +                XGetGeometry(obt_display, win, &root, &i,&i,&u,&u,&u,&u) &&
 +                root != obt_root(ob_screen))
              {
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to another screen !\n");
 +                              "Focus went to another screen !");
                  focus_left_screen = TRUE;
              }
              else
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to a black hole !\n");
 -            xerror_set_ignore(FALSE);
 +                              "Focus went to a black hole !");
 +            obt_display_ignore_errors(FALSE);
              /* nothing is focused */
              focus_set_client(NULL);
          } else {
                  /* The FocusIn was ignored, this means it was on a window
                     that isn't a client. */
                  ob_debug_type(OB_DEBUG_FOCUS,
 -                              "Focus went to an unmanaged window 0x%x !\n",
 +                              "Focus went to an unmanaged window 0x%x !",
                                ce.xfocus.window);
                  focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE);
              }
          event_handle_dockapp(dockapp, e);
      else if (dock)
          event_handle_dock(dock, e);
 -    else if (window == RootWindow(ob_display, ob_screen))
 +    else if (menu)
 +        event_handle_menu(menu, e);
 +    else if (window == obt_root(ob_screen))
          event_handle_root(e);
      else if (e->type == MapRequest)
 -        client_manage(window, NULL);
 +        window_manage(window);
      else if (e->type == MappingNotify) {
          /* keyboard layout changes for modifier mapping changes. reload the
             modifier map, and rebind all the key bindings as appropriate */
 -        ob_debug("Keyboard map changed. Reloading keyboard bindings.\n");
 +        ob_debug("Keyboard map changed. Reloading keyboard bindings.");
          ob_set_state(OB_STATE_RECONFIGURING);
 -        modkeys_shutdown(TRUE);
 -        modkeys_startup(TRUE);
 +        obt_keyboard_reload();
          keyboard_rebind();
          ob_set_state(OB_STATE_RUNNING);
      }
      else if (e->type == ClientMessage) {
          /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
             windows that are not managed yet. */
 -        if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
 +        if (e->xclient.message_type ==
 +            OBT_PROP_ATOM(NET_REQUEST_FRAME_EXTENTS))
 +        {
              /* Pretend to manage the client, getting information used to
                 determine its decorations */
              ObClient *c = client_fake_manage(e->xclient.window);
              vals[1] = c->frame->size.right;
              vals[2] = c->frame->size.top;
              vals[3] = c->frame->size.bottom;
 -            PROP_SETA32(e->xclient.window, net_frame_extents,
 -                        cardinal, vals, 4);
 +            OBT_PROP_SETA32(e->xclient.window, NET_FRAME_EXTENTS,
 +                            CARDINAL, vals, 4);
  
              /* Free the pretend client */
              client_fake_unmanage(c);
  
          /* we are not to be held responsible if someone sends us an
             invalid request! */
 -        xerror_set_ignore(TRUE);
 -        XConfigureWindow(ob_display, window,
 +        obt_display_ignore_errors(TRUE);
 +        XConfigureWindow(obt_display, window,
                           e->xconfigurerequest.value_mask, &xwc);
 -        xerror_set_ignore(FALSE);
 +        obt_display_ignore_errors(FALSE);
      }
  #ifdef SYNC
 -    else if (extensions_sync &&
 -        e->type == extensions_sync_event_basep + XSyncAlarmNotify)
 +    else if (obt_display_extension_sync &&
 +             e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
      {
          XSyncAlarmNotifyEvent *se = (XSyncAlarmNotifyEvent*)e;
          if (se->alarm == moveresize_alarm && moveresize_in_progress)
      else if (e->type == ButtonPress || e->type == ButtonRelease) {
          /* If the button press was on some non-root window, or was physically
             on the root window, then process it */
 -        if (window != RootWindow(ob_display, ob_screen) ||
 +        if (window != obt_root(ob_screen) ||
              e->xbutton.subwindow == None)
          {
              event_handle_user_input(client, e);
          else {
              ObWindow *w;
  
 -            if ((w = g_hash_table_lookup(window_map, &e->xbutton.subwindow)) &&
 +            if ((w = window_find(e->xbutton.subwindow)) &&
                  WINDOW_IS_INTERNAL(w))
              {
                  event_handle_user_input(client, e);
@@@ -754,7 -747,7 +754,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:
@@@ -824,17 -817,17 +824,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;
@@@ -884,12 -877,12 +884,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;
@@@ -1008,7 -1001,7 +1008,7 @@@ 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));
                     delay is up */
                  e->xcrossing.detail != NotifyInferior)
              {
 -                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);
              }
              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,
          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);
              }
@@@ -1647,11 -1623,11 +1647,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);
@@@ -1698,160 -1674,125 +1698,160 @@@ static gboolean event_handle_prompt(ObP
      return FALSE;
  }
  
 -static gboolean event_handle_menu_keyboard(XEvent *ev)
 +static gboolean event_handle_menu_input(XEvent *ev)
  {
 -    guint keycode, state;
 -    gunichar unikey;
 -    ObMenuFrame *frame;
      gboolean ret = FALSE;
  
 -    keycode = ev->xkey.keycode;
 -    state = ev->xkey.state;
 -    unikey = translate_unichar(keycode);
 +    if (ev->type == ButtonRelease || ev->type == ButtonPress) {
 +        ObMenuEntryFrame *e;
  
 -    frame = find_active_or_last_menu();
 -    if (frame == NULL)
 -        g_assert_not_reached(); /* there is no active menu */
 +        if (menu_hide_delay_reached() &&
 +            (ev->xbutton.button < 4 || ev->xbutton.button > 5))
 +        {
 +            if ((e = menu_entry_frame_under(ev->xbutton.x_root,
 +                                            ev->xbutton.y_root)))
 +            {
 +                if (ev->type == ButtonPress && e->frame->child)
 +                    menu_frame_select(e->frame->child, NULL, TRUE);
 +                menu_frame_select(e->frame, e, TRUE);
 +                if (ev->type == ButtonRelease)
 +                    menu_entry_frame_execute(e, ev->xbutton.state);
 +            }
 +            else if (ev->type == ButtonRelease)
 +                menu_frame_hide_all();
 +        }
 +        ret = TRUE;
 +    }
 +    else if (ev->type == MotionNotify) {
 +        ObMenuFrame *f;
 +        ObMenuEntryFrame *e;
  
 -    /* Allow control while going thru the menu */
 -    else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
 -        frame->got_press = TRUE;
 +        if ((e = menu_entry_frame_under(ev->xmotion.x_root,
 +                                        ev->xmotion.y_root)))
 +            if (!(f = find_active_menu()) ||
 +                f == e->frame ||
 +                f->parent == e->frame ||
 +                f->child == e->frame)
 +                menu_frame_select(e->frame, e, FALSE);
 +    }
 +    else if (ev->type == KeyPress || ev->type == KeyRelease) {
 +        guint keycode, state;
 +        gunichar unikey;
 +        ObMenuFrame *frame;
  
 -        if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
 -            menu_frame_hide_all();
 -            ret = TRUE;
 -        }
 +        keycode = ev->xkey.keycode;
 +        state = ev->xkey.state;
 +        unikey = obt_keyboard_keycode_to_unichar(keycode);
  
 -        else if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
 -            /* Left goes to the parent menu */
 -            if (frame->parent)
 -                menu_frame_select(frame, NULL, TRUE);
 -            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_RIGHT)) {
 -            /* Right goes to the selected submenu */
 -            if (frame->child) menu_frame_select_next(frame->child);
 -            ret = TRUE;
 -        }
 +        /* Allow control while going thru the menu */
 +        else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
 +            frame->got_press = TRUE;
  
 -        else if (ob_keycode_match(keycode, OB_KEY_UP)) {
 -            menu_frame_select_previous(frame);
 -            ret = TRUE;
 -        }
 +            if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
 +                menu_frame_hide_all();
 +                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_LEFT)) {
 +                /* Left goes to the parent menu */
 +                if (frame->parent)
 +                    menu_frame_select(frame, NULL, TRUE);
 +                ret = TRUE;
 +            }
  
 -    /* Use KeyRelease events for running things so that the key release doesn't
 -       get sent to the focused application.
 +            else if (ob_keycode_match(keycode, OB_KEY_RIGHT)) {
 +                /* Right goes to the selected submenu */
 +                if (frame->child) menu_frame_select_next(frame->child);
 +                ret = TRUE;
 +            }
  
 -       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;
 -        }
 +            else if (ob_keycode_match(keycode, OB_KEY_UP)) {
 +                menu_frame_select_previous(frame);
 +                ret = TRUE;
 +            }
  
 -        /* 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;
 +            else if (ob_keycode_match(keycode, OB_KEY_DOWN)) {
 +                menu_frame_select_next(frame);
 +                ret = TRUE;
              }
 +        }
  
 -            it = start;
 -            do {
 -                ObMenuEntryFrame *e = it->data;
 -                gunichar entrykey = 0;
 +        /* Use KeyRelease events for running things so that the key release
 +           doesn't get sent to the focused application.
  
 -                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;
 +           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;
 +            }
  
 -                if (unikey == entrykey) {
 -                    if (found == NULL) found = e;
 -                    ++num_found;
 +            /* 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;
                  }
  
 -                /* next with wraparound */
 -                it = g_list_next(it);
 -                if (it == NULL) it = frame->entries;
 -            } while (it != start);
 +                it = start;
 +                do {
 +                    ObMenuEntryFrame *e = it->data;
 +                    gunichar entrykey = 0;
  
 -            if (found) {
 -                if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
 -                    num_found == 1)
 -                {
 -                    menu_frame_select(frame, found, TRUE);
 -                    usleep(50000); /* highlight the item for a short bit so the
 -                                      user can see what happened */
 -                    menu_entry_frame_execute(found, state);
 -                } else {
 -                    menu_frame_select(frame, found, TRUE);
 -                    if (num_found == 1)
 -                        menu_frame_select_next(frame->child);
 -                }
 +                    if (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;
  
 -                ret = TRUE;
 +                    if (unikey == entrykey) {
 +                        if (found == NULL) found = e;
 +                        ++num_found;
 +                    }
 +
 +                    /* next with wraparound */
 +                    it = g_list_next(it);
 +                    if (it == NULL) it = frame->entries;
 +                } while (it != start);
 +
 +                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;
 +                }
              }
          }
      }
      return ret;
  }
  
 -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)
                  menu_frame_select(e->frame, NULL, FALSE);
          }
          break;
 -    case MotionNotify:
 -        if ((e = menu_entry_frame_under(ev->xmotion.x_root,
 -                                        ev->xmotion.y_root)))
 -            if (!(f = find_active_menu()) ||
 -                f == e->frame ||
 -                f->parent == e->frame ||
 -                f->child == e->frame)
 -                menu_frame_select(e->frame, e, FALSE);
 -        break;
 -    case KeyPress:
 -    case KeyRelease:
 -        ret = event_handle_menu_keyboard(ev);
 -        break;
      }
 -    return ret;
  }
  
  static void event_handle_user_input(ObClient *client, XEvent *e)
               e->type == KeyRelease);
  
      if (menu_frame_visible) {
 -        if (event_handle_menu(e))
 +        if (event_handle_menu_input(e))
              /* don't use the event if the menu used it, but if the menu
                 didn't use it and it's a keypress that is bound, it will
                 close the menu and be used */
@@@ -1948,9 -1918,6 +1948,6 @@@ static gboolean focus_delay_func(gpoint
      ObFocusDelayData *d = data;
      Time old = event_curtime;
  
-     /* don't move focus and kill the menu or the move/resize */
-     if (menu_frame_visible || moveresize_in_progress) return FALSE;
      event_curtime = d->time;
      event_curserial = d->serial;
      if (client_focus(d->client) && config_focus_raise)
  
  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);
  }
  
  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);
  }
  
  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)
@@@ -2031,24 -1998,24 +2028,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)
@@@ -2083,9 -2050,9 +2080,9 @@@ Time event_get_server_time(void
      /* Generate a timestamp */
      XEvent event;
  
 -    XChangeProperty(ob_display, screen_support_win,
 -                    prop_atoms.wm_class, prop_atoms.string,
 +    XChangeProperty(obt_display, screen_support_win,
 +                    OBT_PROP_ATOM(WM_CLASS), OBT_PROP_ATOM(STRING),
                      8, PropModeAppend, NULL, 0);
 -    XWindowEvent(ob_display, screen_support_win, PropertyChangeMask, &event);
 +    XWindowEvent(obt_display, screen_support_win, PropertyChangeMask, &event);
      return event.xproperty.time;
  }
diff --combined openbox/focus_cycle.c
@@@ -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"
@@@ -55,12 -56,8 +55,8 @@@ void focus_cycle_stop(ObClient *ifclien
      /* stop focus cycling if the given client is a valid focus target,
         and so the cycling is being disrupted */
      if (focus_cycle_target && ifclient &&
-         focus_valid_target(ifclient, TRUE,
-                            focus_cycle_iconic_windows,
-                            focus_cycle_all_desktops,
-                            focus_cycle_dock_windows,
-                            focus_cycle_desktop_windows,
-                            FALSE))
+         (ifclient == focus_cycle_target ||
+          focus_cycle_popup_is_showing(ifclient)))
      {
          focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE);
          focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
@@@ -70,7 -67,7 +66,7 @@@
  ObClient* focus_cycle(gboolean forward, gboolean all_desktops,
                        gboolean dock_windows, gboolean desktop_windows,
                        gboolean linear, gboolean interactive,
 -                      gboolean showbar, gboolean dialog,
 +                      gboolean showbar, ObFocusCyclePopupMode mode,
                        gboolean done, gboolean cancel)
  {
      static GList *order = NULL;
                      focus_cycle_target = ft;
                      focus_cycle_draw_indicator(showbar ? ft : NULL);
                  }
 -                if (dialog)
 -                    /* same arguments as focus_target_valid */
 -                    focus_cycle_popup_show(ft,
 -                                           focus_cycle_iconic_windows,
 -                                           focus_cycle_all_desktops,
 -                                           focus_cycle_dock_windows,
 -                                           focus_cycle_desktop_windows);
 +                /* same arguments as focus_target_valid */
 +                focus_cycle_popup_show(ft,
 +                                       focus_cycle_iconic_windows,
 +                                       focus_cycle_all_desktops,
 +                                       focus_cycle_dock_windows,
 +                                       focus_cycle_desktop_windows,
 +                                       mode);
                  return focus_cycle_target;
              } else if (ft != focus_cycle_target) {
                  focus_cycle_target = ft;
@@@ -23,7 -23,6 +23,7 @@@
  #include "screen.h"
  #include "focus.h"
  #include "openbox.h"
 +#include "config.h"
  #include "window.h"
  #include "event.h"
  #include "render/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 -44,7 +57,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 */
@@@ -111,7 -88,7 +111,7 @@@ static void   popup_render   (ObFocusCy
  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.obwin.type = OB_WINDOW_CLASS_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.a_hilite_text = RrAppearanceCopy(ob_rr_theme->osd_hilite_label);
 +    popup.a_text = RrAppearanceCopy(ob_rr_theme->a_unfocused_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_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;
 +
 +    /* create the hilite under the target icon */
 +    {
 +        RrPixel32 color;
 +        gint x, y, o;
 +
 +        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);
 +
 +        o = 0;
 +        for (x = 0; x < HILITE_SIZE; x++)
 +            for (y = 0; y < HILITE_SIZE; y++) {
 +                guchar a;
  
 -    XMapWindow(ob_display, popup.text);
 +                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);
  }
@@@ -272,17 -194,18 +272,17 @@@ static void popup_setup(ObFocusCyclePop
              p->a_text->texture[0].data.text.string = text;
              maxwidth = MAX(maxwidth, RrMinWidth(p->a_text));
  
 -            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;
@@@ -327,29 -250,16 +327,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;
 +    if (mode == OB_FOCUS_CYCLE_POPUP_MODE_LIST)
 +        /* leave space on the side for the icons */
 +        textw -= list_mode_icon_column_w;
  
 -    /* 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;
 -
 -    /* 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)
 -        popup_setup(&popup, TRUE, iconic_windows, all_desktops,
 +    if (!popup.mapped) {
 +        popup_setup(&popup, TRUE, iconic_windows, all_desktops, 
                      dock_windows, desktop_windows);
 +        /* 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();
      }
@@@ -674,8 -472,8 +674,8 @@@ 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);
  
  
          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);
      }
      popup.n_targets = 0;
      popup.last_target = NULL;
 -
 -    g_free(popup.hilite_rgba);
 -    popup.hilite_rgba = NULL;
  }
  
  void focus_cycle_popup_single_show(struct _ObClient *c,
@@@ -735,3 -535,17 +735,17 @@@ void focus_cycle_popup_single_hide(void
  {
      icon_popup_hide(single_popup);
  }
+ gboolean focus_cycle_popup_is_showing(ObClient *client)
+ {
+     if (popup.mapped) {
+         GList *it;
+         for (it = popup.targets; it; it = g_list_next(it)) {
+             ObFocusCyclePopupTarget *t = it->data;
+             if (t->client == client)
+                 return TRUE;
+         }
+     }
+     return FALSE;
+ }
@@@ -24,26 -24,22 +24,29 @@@ 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);
  #endif
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 "frame.h"
  #include "event.h"
  #include "focus.h"
+ #include "focus_cycle.h"
  #include "popup.h"
 -#include "extensions.h"
  #include "render/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
@@@ -77,7 -79,6 +78,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" */
@@@ -91,10 -92,10 +92,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;
  }
@@@ -159,33 -161,37 +160,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_role;
 -    supported[i++] = prop_atoms.ob_name;
 -    supported[i++] = prop_atoms.ob_class;
 +    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);
      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);
  
      screen_tell_ksplash();
@@@ -331,14 -341,14 +332,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))
@@@ -450,16 -460,17 +451,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;
@@@ -472,8 -483,8 +473,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 */
@@@ -606,7 -620,8 +607,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();
      for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
          if (WINDOW_IS_CLIENT(it->data)) {
              ObClient *c = it->data;
-             if (client_hide(c) && c == focus_client) {
-                 /* c was focused and we didn't do fallback clearly so make sure
-                    openbox doesnt still consider the window focused.
-                    this happens when using NextWindow with allDesktops, since
-                    it doesnt want to move focus on desktop change, but the
-                    focus is not going to stay with the current window, which
-                    has now disappeared */
-                 focus_set_client(NULL);
+             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.
+                        this happens when using NextWindow with allDesktops,
+                        since it doesnt want to move focus on desktop change,
+                        but the focus is not going to stay with the current
+                        window, which has now disappeared.
+                        only do this if the client was actually hidden,
+                        otherwise it can keep focus. */
+                     focus_set_client(NULL);
+                 }
              }
          }
      }
@@@ -741,7 -763,7 +749,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);
              }
          }
@@@ -782,7 -804,7 +790,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);
@@@ -923,7 -945,7 +931,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,
@@@ -1118,13 -1131,13 +1126,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;
@@@ -1163,8 -1176,8 +1171,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 */
@@@ -1258,23 -1271,24 +1266,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);
      }
  }
  
@@@ -1303,55 -1317,6 +1311,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))
@@@ -1493,7 -1458,7 +1501,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) {
@@@ -1688,10 -1653,10 +1696,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));
  }
  
@@@ -1717,12 -1682,12 +1725,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;
      }