Merge branch 'backport' into work
authorDana Jansens <danakj@orodu.net>
Wed, 16 Dec 2009 20:39:25 +0000 (15:39 -0500)
committerDana Jansens <danakj@orodu.net>
Wed, 16 Dec 2009 20:39:25 +0000 (15:39 -0500)
Conflicts:

obt/keyboard.c
obt/keyboard.h
openbox/event.c
openbox/menuframe.c
openbox/moveresize.c
openbox/openbox.c
openbox/screen.c

16 files changed:
1  2 
obt/keyboard.c
obt/keyboard.h
openbox/actions/cyclewindows.c
openbox/actions/directionalwindows.c
openbox/event.c
openbox/focus_cycle_popup.c
openbox/keyboard.c
openbox/menuframe.c
openbox/menuframe.h
openbox/moveresize.c
openbox/openbox.c
openbox/openbox.h
openbox/prompt.c
openbox/screen.c
openbox/screen.h
render/image.c

diff --cc obt/keyboard.c
@@@ -185,40 -176,22 +185,48 @@@ static void set_modkey_mask(guchar mask
      /* CapsLock, Shift, and Control are special and hard-coded */
  }
  
- KeyCode obt_keyboard_keysym_to_keycode(KeySym sym)
 -KeyCode* modkeys_sym_to_code(KeySym sym)
++KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym)
  {
-     gint i, j;
+     KeyCode *ret;
+     gint i, j, n;
+     ret = g_new(KeyCode, 1);
+     n = 0;
+     ret[n] = 0;
  
      /* go through each keycode and look for the keysym */
      for (i = min_keycode; i <= max_keycode; ++i)
          for (j = 0; j < keysyms_per_keycode; ++j)
-             if (sym == keymap[(i-min_keycode) * keysyms_per_keycode + j])
-                 return i;
-     return 0;
+             if (sym == keymap[(i-min_keycode) * keysyms_per_keycode + j]) {
+                 ret = g_renew(KeyCode, ret, ++n);
+                 ret[n-1] = i;
+                 ret[n] = 0;
+             }
+     return ret;
  }
 +
 +gchar *obt_keyboard_keycode_to_string(guint keycode)
 +{
 +    KeySym sym;
 +
 +    if ((sym = XKeycodeToKeysym(obt_display, keycode, 0)) != NoSymbol)
 +        return g_locale_to_utf8(XKeysymToString(sym), -1, NULL, NULL, NULL);
 +    return NULL;
 +}
 +
 +gunichar obt_keyboard_keycode_to_unichar(guint keycode)
 +{
 +    gunichar unikey = 0;
 +    char *key;
 +
 +    if ((key = obt_keyboard_keycode_to_string(keycode)) != NULL &&
 +        /* don't accept keys that aren't a single letter, like "space" */
 +        key[1] == '\0')
 +    {
 +        unikey = g_utf8_get_char_validated(key, -1);
 +        if (unikey == (gunichar)-1 || unikey == (gunichar)-2 || unikey == 0)
 +            unikey = 0;
 +    }
 +    g_free(key);
 +    return unikey;
 +}
diff --cc obt/keyboard.h
@@@ -52,19 -51,9 +52,18 @@@ guint obt_keyboard_only_modmasks(guint 
  
  /*! Get the modifier masks for a modifier key. This includes both the left and
    right keys when there are both. */
 -guint modkeys_key_to_mask(ObModkeysKey key);
 +guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key);
  
- /*! Convert a KeySym to a KeyCode, because the X function is terrible - says
-   valgrind. */
- KeyCode obt_keyboard_keysym_to_keycode(KeySym sym);
+ /*! Convert a KeySym to all the KeyCodes which generate it. */
 -KeyCode* modkeys_sym_to_code(KeySym sym);
++KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym);
 +
 +/*! Give the string form of a KeyCode */
 +gchar *obt_keyboard_keycode_to_string(guint keycode);
 +
 +/*! Translate a KeyCode to the unicode character it represents */
 +gunichar obt_keyboard_keycode_to_unichar(guint keycode);
 +
 +
 +G_END_DECLS
  
 -#endif
 +#endif /* __obt_keyboard_h */
Simple merge
Simple merge
diff --cc openbox/event.c
@@@ -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;
  
-             if (keycode == ob_keycode(OB_KEY_ESCAPE)) {
 -        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 (keycode == ob_keycode(OB_KEY_LEFT)) {
 -        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;
 +            }
  
-             else if (keycode == ob_keycode(OB_KEY_RIGHT)) {
 -    /* 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;
 +            }
  
-             else if (keycode == ob_keycode(OB_KEY_UP)) {
 -       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;
 +            }
  
-             else if (keycode == ob_keycode(OB_KEY_DOWN)) {
 -        /* 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 (keycode == ob_keycode(OB_KEY_RETURN)) {
++            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;
 +                }
              }
          }
      }
@@@ -1885,10 -1841,29 +1885,15 @@@ static void event_handle_menu(ObMenuFra
              (f = find_active_menu()) && f->selected == e &&
              e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
          {
-             menu_frame_select(e->frame, NULL, FALSE);
+             ObMenuEntryFrame *u = menu_entry_frame_under(ev->xcrossing.x_root,
+                                                          ev->xcrossing.y_root);
+             /* if we're just going from one entry in the menu to the next,
+                don't unselect stuff first */
+             if (!u || e->frame != u->frame)
+                 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)
@@@ -330,28 -253,15 +330,28 @@@ static void popup_render(ObFocusCyclePo
      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();
+     screen_area = screen_physical_area_primary(FALSE);
  
      /* get the outside margins */
      RrMargins(p->a_bg, &ml, &mt, &mr, &mb);
Simple merge
  #include "client.h"
  #include "menu.h"
  #include "screen.h"
 -#include "prop.h"
  #include "actions.h"
+ #include "event.h"
  #include "grab.h"
  #include "openbox.h"
 -#include "mainloop.h"
  #include "config.h"
 +#include "obt/prop.h"
  #include "render/theme.h"
  
  #define PADDING 2
@@@ -90,9 -93,10 +92,10 @@@ ObMenuFrame* menu_frame_new(ObMenu *men
      XSetWindowAttributes attr;
  
      self = g_new0(ObMenuFrame, 1);
 -    self->type = Window_Menu;
 +    self->obwin.type = OB_WINDOW_CLASS_MENUFRAME;
      self->menu = menu;
      self->selected = NULL;
+     self->open_submenu = NULL;
      self->client = client;
      self->direction_right = TRUE;
      self->show_from = show_from;
@@@ -197,7 -195,8 +200,8 @@@ static void menu_entry_frame_free(ObMen
  void menu_frame_move(ObMenuFrame *self, gint x, gint y)
  {
      RECT_SET_POINT(self->area, x, y);
 -    XMoveWindow(ob_display, self->window, self->area.x, self->area.y);
+     self->monitor = screen_find_monitor_point(x, y);
 +    XMoveWindow(obt_display, self->window, self->area.x, self->area.y);
  }
  
  static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
@@@ -1062,7 -1047,9 +1058,9 @@@ static void menu_frame_hide(ObMenuFram
          ungrab_keyboard();
      }
  
 -    XUnmapWindow(ob_display, self->window);
+     ignore_start = event_start_ignore_all_enters();
 +    XUnmapWindow(obt_display, self->window);
+     event_end_ignore_all_enters(ignore_start);
  
      menu_frame_free(self);
  }
@@@ -1073,8 -1060,11 +1071,11 @@@ void menu_frame_hide_all(void
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
 -        ob_main_loop_timeout_remove(ob_main_loop,
 -                                    menu_entry_frame_submenu_show_timeout);
 +        obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_timeout);
++                                     menu_entry_frame_submenu_show_timeout);
+         /* remove any submenu close delays */
 -        ob_main_loop_timeout_remove(ob_main_loop,
 -                                    menu_entry_frame_submenu_hide_timeout);
++        obt_main_loop_timeout_remove(ob_main_loop,
++                                     menu_entry_frame_submenu_hide_timeout);
      }
      if ((it = g_list_last(menu_frame_visible)))
          menu_frame_hide(it->data);
@@@ -1088,8 -1078,13 +1089,13 @@@ void menu_frame_hide_all_client(ObClien
          if (f->client == client) {
              if (config_submenu_show_delay) {
                  /* remove any submenu open requests */
-                 obt_main_loop_timeout_remove(ob_main_loop,
-                                              menu_entry_frame_submenu_timeout);
 -                ob_main_loop_timeout_remove
++                obt_main_loop_timeout_remove
+                     (ob_main_loop,
+                      menu_entry_frame_submenu_show_timeout);
+                 /* remove any submenu close delays */
 -                ob_main_loop_timeout_remove
++                obt_main_loop_timeout_remove
+                     (ob_main_loop,
+                      menu_entry_frame_submenu_hide_timeout);
              }
              menu_frame_hide(f);
          }
@@@ -1154,28 -1156,66 +1167,68 @@@ void menu_frame_select(ObMenuFrame *sel
  
      if (config_submenu_show_delay) {
          /* remove any submenu open requests */
 -        ob_main_loop_timeout_remove(ob_main_loop,
 -                                    menu_entry_frame_submenu_show_timeout);
 +        obt_main_loop_timeout_remove(ob_main_loop,
-                                      menu_entry_frame_submenu_timeout);
++                                     menu_entry_frame_submenu_show_timeout);
+     }
+     if (!entry && self->open_submenu) {
+         /* we moved out of the menu, so move the selection back to the open
+            submenu */
+         entry = self->open_submenu;
+         oldchild = NULL;
+         /* remove any submenu close delays */
 -        ob_main_loop_timeout_remove(ob_main_loop,
 -                                    menu_entry_frame_submenu_hide_timeout);
++        obt_main_loop_timeout_remove(ob_main_loop,
++                                     menu_entry_frame_submenu_hide_timeout);
      }
  
      self->selected = entry;
  
      if (old)
          menu_entry_frame_render(old);
-     if (oldchild)
-         menu_frame_hide(oldchild);
+     if (oldchild) {
+         /* there is an open submenu */
+         if (config_submenu_show_delay && !immediate) {
+             if (entry == self->open_submenu) {
+                 /* we moved onto the entry that has an open submenu, so stop
+                    trying to close the submenu */
 -                ob_main_loop_timeout_remove
++                obt_main_loop_timeout_remove
+                     (ob_main_loop,
+                      menu_entry_frame_submenu_hide_timeout);
+             }
+             else if (old == self->open_submenu) {
+                 /* we just moved off the entry with an open submenu, so
+                    close the open submenu after a delay */
 -                ob_main_loop_timeout_add(ob_main_loop,
 -                                         config_submenu_show_delay * 1000,
 -                                         menu_entry_frame_submenu_hide_timeout,
 -                                         self->child, g_direct_equal,
 -                                         NULL);
++                obt_main_loop_timeout_add
++                    (ob_main_loop,
++                     config_submenu_show_delay * 1000,
++                     menu_entry_frame_submenu_hide_timeout,
++                     self->child, g_direct_equal,
++                     NULL);
+             }
+         }
+         else
+             menu_frame_hide(oldchild);
+     }
  
      if (self->selected) {
          menu_entry_frame_render(self->selected);
  
-         if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
+         /* if we've selected a submenu and it wasn't already open, then
+            show it */
+         if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU &&
+             self->selected != self->open_submenu)
+         {
              if (config_submenu_show_delay && !immediate) {
                  /* initiate a new submenu open request */
-                 obt_main_loop_timeout_add(ob_main_loop,
-                                           config_submenu_show_delay * 1000,
-                                           menu_entry_frame_submenu_timeout,
-                                           self->selected, g_direct_equal,
-                                           NULL);
 -                ob_main_loop_timeout_add(ob_main_loop,
 -                                         config_submenu_show_delay * 1000,
 -                                         menu_entry_frame_submenu_show_timeout,
 -                                         self->selected, g_direct_equal,
 -                                         NULL);
++                obt_main_loop_timeout_add
++                    (ob_main_loop,
++                     config_submenu_show_delay * 1000,
++                     menu_entry_frame_submenu_show_timeout,
++                     self->selected, g_direct_equal,
++                     NULL);
              } else {
                  menu_entry_frame_show_submenu(self->selected);
              }
Simple merge
@@@ -674,7 -667,8 +674,7 @@@ static void resize_with_keys(gint keyco
              key_resize_edge = OB_DIRECTION_EAST;
              return;
          }
-     } else if (keycode == ob_keycode(OB_KEY_LEFT)) {
 -    }
 -    if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
++    } else if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
          dir = OB_DIRECTION_WEST;
          if (key_resize_edge != OB_DIRECTION_WEST &&
              key_resize_edge != OB_DIRECTION_EAST)
              key_resize_edge = OB_DIRECTION_WEST;
              return;
          }
-     } else if (keycode == ob_keycode(OB_KEY_UP)) {
 -    }
 -    if (ob_keycode_match(keycode, OB_KEY_UP)) {
++    } else if (ob_keycode_match(keycode, OB_KEY_UP)) {
          dir = OB_DIRECTION_NORTH;
          if (key_resize_edge != OB_DIRECTION_NORTH &&
              key_resize_edge != OB_DIRECTION_SOUTH)
              key_resize_edge = OB_DIRECTION_NORTH;
              return;
          }
-     } else /* if (keycode == ob_keycode(OB_KEY_DOWN)) */ {
 -    }
 -    if (ob_keycode_match(keycode, OB_KEY_DOWN)) {
++    } else /* if (ob_keycode_match(keycode, OB_KEY_DOWN)) */ {
          dir = OB_DIRECTION_SOUTH;
          if (key_resize_edge != OB_DIRECTION_NORTH &&
              key_resize_edge != OB_DIRECTION_SOUTH)
      }
  
      /* shift means jump to edge */
 -    if (state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
 +    if (state & obt_keyboard_modkey_to_modmask(OBT_KEYBOARD_MODKEY_SHIFT)) {
          gint x, y, w, h;
  
-         if (keycode == ob_keycode(OB_KEY_RIGHT))
+         if (ob_keycode_match(keycode, OB_KEY_RIGHT))
              dir = OB_DIRECTION_EAST;
-         else if (keycode == ob_keycode(OB_KEY_LEFT))
+         else if (ob_keycode_match(keycode, OB_KEY_LEFT))
              dir = OB_DIRECTION_WEST;
-         else if (keycode == ob_keycode(OB_KEY_DOWN))
+         else if (ob_keycode_match(keycode, OB_KEY_DOWN))
              dir = OB_DIRECTION_SOUTH;
-         else /* if (keycode == ob_keycode(OB_KEY_UP)) */
+         else /* if (ob_keycode_match(keycode, OB_KEY_UP)) */
              dir = OB_DIRECTION_NORTH;
  
          client_find_resize_directional(moveresize_client, key_resize_edge,
@@@ -912,23 -901,21 +912,23 @@@ gboolean moveresize_event(XEvent *e
          }
          used = TRUE;
      } else if (e->type == KeyPress) {
-         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
+         if (ob_keycode_match(e->xkey.keycode, OB_KEY_ESCAPE)) {
              moveresize_end(TRUE);
              used = TRUE;
-         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
+         } else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RETURN)) {
              moveresize_end(FALSE);
              used = TRUE;
-         } else if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT) ||
-                    e->xkey.keycode == ob_keycode(OB_KEY_LEFT) ||
-                    e->xkey.keycode == ob_keycode(OB_KEY_DOWN) ||
-                    e->xkey.keycode == ob_keycode(OB_KEY_UP))
+         } else if (ob_keycode_match(e->xkey.keycode, OB_KEY_RIGHT) ||
+                    ob_keycode_match(e->xkey.keycode, OB_KEY_LEFT) ||
+                    ob_keycode_match(e->xkey.keycode, OB_KEY_DOWN) ||
+                    ob_keycode_match(e->xkey.keycode, OB_KEY_UP))
          {
 -            if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
 +            if (corner == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_KEYBOARD)) {
                  resize_with_keys(e->xkey.keycode, e->xkey.state);
                  used = TRUE;
 -            } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
 +            } else if (corner ==
 +                       OBT_PROP_ATOM(NET_WM_MOVERESIZE_MOVE_KEYBOARD))
 +            {
                  move_with_keys(e->xkey.keycode, e->xkey.state);
                  used = TRUE;
              }
@@@ -400,6 -417,18 +400,16 @@@ gint main(gint argc, gchar **argv
              event_shutdown(reconfigure);
              config_shutdown();
              actions_shutdown(reconfigure);
 -
 -            modkeys_shutdown(reconfigure);
+             /* Free the key codes for built in keys */
+             g_free(keys[OB_KEY_RETURN]);
+             g_free(keys[OB_KEY_ESCAPE]);
+             g_free(keys[OB_KEY_LEFT]);
+             g_free(keys[OB_KEY_RIGHT]);
+             g_free(keys[OB_KEY_UP]);
+             g_free(keys[OB_KEY_DOWN]);
+             g_free(keys[OB_KEY_TAB]);
+             g_free(keys[OB_KEY_SPACE]);
          } while (reconfigure);
      }
  
@@@ -716,13 -743,17 +726,17 @@@ Cursor ob_cursor(ObCursor cursor
      return cursors[cursor];
  }
  
KeyCode ob_keycode(ObKey key)
gboolean ob_keycode_match(KeyCode code, ObKey key)
  {
+     KeyCode *k;
+     
      g_assert(key < OB_NUM_KEYS);
-     return keys[key];
+     for (k = keys[key]; *k; ++k)
+         if (*k == code) return TRUE;
+     return FALSE;
  }
  
 -ObState ob_state()
 +ObState ob_state(void)
  {
      return state;
  }
Simple merge
Simple merge
@@@ -1308,58 -1310,9 +1295,58 @@@ 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, j;
+     guint j;
      gulong *dims;
      GList *it;
      GSList *sit;
      VALIDATE_STRUTS(struts_bottom, bottom,
                      monitor_area[screen_num_monitors].height / 2);
  
-     /* set up the work areas to be full screen */
-     for (i = 0; i < screen_num_monitors; ++i)
-         for (j = 0; j < screen_num_desktops; ++j) {
-             dims[(i * screen_num_desktops + j) * 4+0] = monitor_area[i].x;
-             dims[(i * screen_num_desktops + j) * 4+1] = monitor_area[i].y;
-             dims[(i * screen_num_desktops + j) * 4+2] = monitor_area[i].width;
-             dims[(i * screen_num_desktops + j) * 4+3] = monitor_area[i].height;
-         }
-     /* calculate the work areas from the struts */
-     for (i = 0; i < screen_num_monitors; ++i)
-         for (j = 0; j < screen_num_desktops; ++j) {
-             gint l = 0, r = 0, t = 0, b = 0;
+     /* set up the work area to be full screen across all monitors */
+     for (j = 0; j < screen_num_desktops; ++j) {
+         dims[j*4 + 0] =
+             monitor_area[screen_num_monitors].x;
+         dims[j*4 + 1] =
+             monitor_area[screen_num_monitors].y;
+         dims[j*4 + 2] =
+             monitor_area[screen_num_monitors].width;
+         dims[j*4 + 3] =
+             monitor_area[screen_num_monitors].height;
+     }
  
-             /* only add the strut to the area if it touches the monitor */
+     /* calculate the work area from the struts */
+     for (j = 0; j < screen_num_desktops; ++j) {
+         gint l = 0, r = 0, t = 0, b = 0;
  
-             for (sit = struts_left; sit; sit = g_slist_next(sit)) {
-                 ObScreenStrut *s = sit->data;
-                 if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
-                     STRUT_LEFT_ON_MONITOR(s->strut, i))
-                     l = MAX(l, s->strut->left);
-             }
-             for (sit = struts_top; sit; sit = g_slist_next(sit)) {
-                 ObScreenStrut *s = sit->data;
-                 if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
-                     STRUT_TOP_ON_MONITOR(s->strut, i))
-                     t = MAX(t, s->strut->top);
-             }
-             for (sit = struts_right; sit; sit = g_slist_next(sit)) {
-                 ObScreenStrut *s = sit->data;
-                 if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
-                     STRUT_RIGHT_ON_MONITOR(s->strut, i))
-                     r = MAX(r, s->strut->right);
-             }
-             for (sit = struts_bottom; sit; sit = g_slist_next(sit)) {
-                 ObScreenStrut *s = sit->data;
-                 if ((s->desktop == j || s->desktop == DESKTOP_ALL) &&
-                     STRUT_BOTTOM_ON_MONITOR(s->strut, i))
-                     b = MAX(b, s->strut->bottom);
-             }
-             /* if the monitor is not against the edge of the root window,
-                the struts will include the distance from the root window's edge
-                to the monitor, so add that back into the monitor's work area */
-             if (l) l += RECT_LEFT  (monitor_area[screen_num_monitors])
-                         - RECT_LEFT  (monitor_area[i]);
-             if (t) t += RECT_TOP   (monitor_area[screen_num_monitors])
-                         - RECT_TOP   (monitor_area[i]);
-             if (r) r -= RECT_RIGHT (monitor_area[screen_num_monitors])
-                         - RECT_RIGHT (monitor_area[i]);
-             if (b) b -= RECT_BOTTOM(monitor_area[screen_num_monitors])
-                         - RECT_BOTTOM(monitor_area[i]);
-             /* based on these margins, set the work area for the
-                monitor/desktop */
-             dims[(i * screen_num_desktops + j) * 4 + 0] += l;
-             dims[(i * screen_num_desktops + j) * 4 + 1] += t;
-             dims[(i * screen_num_desktops + j) * 4 + 2] -= l + r;
-             dims[(i * screen_num_desktops + j) * 4 + 3] -= t + b;
+         for (sit = struts_left; sit; sit = g_slist_next(sit)) {
+             ObScreenStrut *s = sit->data;
+             if (s->desktop == j || s->desktop == DESKTOP_ALL)
+                 l = MAX(l, s->strut->left);
+         }
+         for (sit = struts_top; sit; sit = g_slist_next(sit)) {
+             ObScreenStrut *s = sit->data;
+             if (s->desktop == j || s->desktop == DESKTOP_ALL)
+                 t = MAX(t, s->strut->top);
+         }
+         for (sit = struts_right; sit; sit = g_slist_next(sit)) {
+             ObScreenStrut *s = sit->data;
+             if (s->desktop == j || s->desktop == DESKTOP_ALL)
+                 r = MAX(r, s->strut->right);
          }
+         for (sit = struts_bottom; sit; sit = g_slist_next(sit)) {
+             ObScreenStrut *s = sit->data;
+             if (s->desktop == j || s->desktop == DESKTOP_ALL)
+                 b = MAX(b, s->strut->bottom);
+         }
+         /* based on these margins, set the work area for the desktop */
+         dims[j*4 + 0] += l;
+         dims[j*4 + 1] += t;
+         dims[j*4 + 2] -= l + r;
+         dims[j*4 + 3] -= t + b;
+     }
  
-     /* all the work areas are not used here, only the ones for the first
-        monitor are */
+     /* 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))
@@@ -134,9 -142,12 +142,12 @@@ gboolean screen_physical_area_monitor_c
  */
  guint screen_find_monitor(Rect *search);
  
+ /*! Finds the monitor which contains the point @x, @y */
+ guint screen_find_monitor_point(guint x, guint y);
  /*! Sets the root cursor. This function decides which cursor to use, but you
    gotta call it to let it know it should change. */
 -void screen_set_root_cursor();
 +void screen_set_root_cursor(void);
  
  /*! Gives back the pointer's position in x and y. Returns TRUE if the pointer
    is on this screen and FALSE if it is on another screen. */
diff --cc render/image.c
@@@ -73,12 -73,14 +73,14 @@@ static void AddPicture(RrImage *self, R
      /* add the picture as a key to point to this image in the cache */
      g_hash_table_insert(self->cache->table, (*list)[0], self);
  
+ /*
  #ifdef DEBUG
 -    g_message("Adding %s picture to the cache:\n    "
 -              "Image 0x%x, w %d h %d Hash %u",
 -              (*list == self->original ? "ORIGINAL" : "RESIZED"),
 -              (guint)self, pic->width, pic->height, RrImagePicHash(pic));
 +    g_debug("Adding %s picture to the cache:\n    "
 +            "Image 0x%lx, w %d h %d Hash %u",
 +            (*list == self->original ? "ORIGINAL" : "RESIZED"),
 +            (gulong)self, pic->width, pic->height, RrImagePicHash(pic));
  #endif
+ */
  }
  
  /*! Remove a picture from an Image.  This may remove it from the "originals"
@@@ -88,13 -90,15 +90,15 @@@ static void RemovePicture(RrImage *self
  {
      gint j;
  
+ /*
  #ifdef DEBUG
 -    g_message("Removing %s picture from the cache:\n    "
 -              "Image 0x%x, w %d h %d Hash %u",
 -              (*list == self->original ? "ORIGINAL" : "RESIZED"),
 -              (guint)self, (*list)[i]->width, (*list)[i]->height,
 -              RrImagePicHash((*list)[i]));
 +    g_debug("Removing %s picture from the cache:\n    "
 +            "Image 0x%lx, w %d h %d Hash %u",
 +            (*list == self->original ? "ORIGINAL" : "RESIZED"),
 +            (gulong)self, (*list)[i]->width, (*list)[i]->height,
 +            RrImagePicHash((*list)[i]));
  #endif
+ */
  
      /* remove the picture as a key in the cache */
      g_hash_table_remove(self->cache->table, (*list)[i]);
@@@ -329,10 -333,12 +333,12 @@@ void RrImageRef(RrImage *self
  void RrImageUnref(RrImage *self)
  {
      if (self && --self->ref == 0) {
+ /*
  #ifdef DEBUG
 -        g_message("Refcount to 0, removing ALL pictures from the cache:\n    "
 -                  "Image 0x%x", (guint)self);
 +        g_debug("Refcount to 0, removing ALL pictures from the cache:\n    "
 +                "Image 0x%lx", (gulong)self);
  #endif
+ */
          while (self->n_original > 0)
              RemovePicture(self, &self->original, 0, &self->n_original);
          while (self->n_resized > 0)
@@@ -352,10 -358,12 +358,12 @@@ void RrImageAddPicture(RrImage *self, R
      /* make sure we don't already have this size.. */
      for (i = 0; i < self->n_original; ++i)
          if (self->original[i]->width == w && self->original[i]->height == h) {
+ /*
  #ifdef DEBUG
 -            g_message("Found duplicate ORIGINAL image:\n    "
 -                      "Image 0x%x, w %d h %d", (guint)self, w, h);
 +            g_debug("Found duplicate ORIGINAL image:\n    "
 +                    "Image 0x%lx, w %d h %d", (gulong)self, w, h);
  #endif
+ */
              return;
          }