merge r5968-5975 from trunk
authorDana Jansens <danakj@orodu.net>
Wed, 2 May 2007 03:11:35 +0000 (03:11 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 2 May 2007 03:11:35 +0000 (03:11 +0000)
15 files changed:
openbox/client.c
openbox/dock.c
openbox/event.c
openbox/focus.c
openbox/geom.h
openbox/keyboard.c
openbox/menuframe.c
openbox/moveresize.c
openbox/popup.c
openbox/popup.h
openbox/screen.c
openbox/translate.c
openbox/translate.h
render/render.c
render/render.h

index 3396796201c0b2bcb4e45f748a6777823cbffa62..5e1a78513992929a178fb871bfbffa0b89a1b3b2 100644 (file)
@@ -751,66 +751,94 @@ void client_move_onscreen(ObClient *self, gboolean rude)
 gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
                               gboolean rude)
 {
-    Rect *a;
+    Rect *mon_a, *all_a;
     gint ox = *x, oy = *y;
+    gboolean rudel = rude, ruder = rude, rudet = rude, rudeb = rude;
+    gint fw, fh;
+
+    all_a = screen_area(self->desktop);
+    mon_a = screen_area_monitor(self->desktop, client_monitor(self));
 
     /* get where the frame would be */
     frame_client_gravity(self->frame, x, y, w, h);
 
-    /* XXX watch for xinerama dead areas */
+    /* get the requested size of the window with decorations */
+    fw = self->frame->size.left + w + self->frame->size.right;
+    fh = self->frame->size.top + h + self->frame->size.bottom;
+
     /* This makes sure windows aren't entirely outside of the screen so you
        can't see them at all.
        It makes sure 10% of the window is on the screen at least. At don't let
        it move itself off the top of the screen, which would hide the titlebar
        on you. (The user can still do this if they want too, it's only limiting
        the application.
+
+       XXX watch for xinerama dead areas...
     */
     if (client_normal(self)) {
-        a = screen_area(self->desktop);
-        if (!self->strut.right &&
-            *x + self->frame->area.width/10 >= a->x + a->width - 1)
-            *x = a->x + a->width - self->frame->area.width/10;
-        if (!self->strut.bottom &&
-            *y + self->frame->area.height/10 >= a->y + a->height - 1)
-            *y = a->y + a->height - self->frame->area.height/10;
-        if (!self->strut.left && *x + self->frame->area.width*9/10 - 1 < a->x)
-            *x = a->x - self->frame->area.width*9/10;
-        if (!self->strut.top && *y + self->frame->area.height*9/10 - 1 < a->y)
-            *y = a->y - self->frame->area.width*9/10;
+        if (!self->strut.right && *x + fw/10 >= all_a->x + all_a->width - 1)
+            *x = all_a->x + all_a->width - fw/10;
+        if (!self->strut.bottom && *y + fh/10 >= all_a->y + all_a->height - 1)
+            *y = all_a->y + all_a->height - fh/10;
+        if (!self->strut.left && *x + fw*9/10 - 1 < all_a->x)
+            *x = all_a->x - fw*9/10;
+        if (!self->strut.top && *y + fh*9/10 - 1 < all_a->y)
+            *y = all_a->y - fw*9/10;
     }
 
     /* If rudeness wasn't requested, then figure out of the client is currently
-       entirely on the screen. If it is, then be rude even though it wasn't
+       entirely on the screen. If it is, and the position isn't changing by
+       request, and it is enlarging, then be rude even though it wasn't
        requested */
     if (!rude) {
-        a = screen_area_monitor(self->desktop, client_monitor(self));
-        if (RECT_CONTAINS_RECT(*a, self->area))
-            rude = TRUE;
-    }
-
-    /* This here doesn't let windows even a pixel outside the screen,
-     * when called from client_manage, programs placing themselves are
+        Point oldtl, oldtr, oldbl, oldbr;
+        Point newtl, newtr, newbl, newbr;
+        gboolean stationary;
+
+        POINT_SET(oldtl, self->frame->area.x, self->frame->area.y);
+        POINT_SET(oldbr, self->frame->area.x + self->frame->area.width - 1,
+                  self->frame->area.y + self->frame->area.height - 1);
+        POINT_SET(oldtr, oldbr.x, oldtl.y);
+        POINT_SET(oldbl, oldtl.x, oldbr.y);
+
+        POINT_SET(newtl, *x, *y);
+        POINT_SET(newbr, *x + fw - 1, *y + fh - 1);
+        POINT_SET(newtr, newbr.x, newtl.y);
+        POINT_SET(newbl, newtl.x, newbr.y);
+
+        /* is it moving or just resizing from some corner? */
+        stationary = (POINT_EQUAL(oldtl, newtl) || POINT_EQUAL(oldtr, newtr) ||
+                      POINT_EQUAL(oldbl, newbl) || POINT_EQUAL(oldbr, newbr));
+
+        /* if left edge is growing */
+        if (stationary && newtl.x < oldtl.x)
+            rudel = TRUE;
+        /* if right edge is growing */
+        if (stationary && newtr.x > oldtr.x)
+            ruder = TRUE;
+        /* if top edge is growing */
+        if (stationary && newtl.y < oldtl.y)
+            rudet = TRUE;
+        /* if bottom edge is growing */
+        if (stationary && newbl.y > oldbl.y)
+            rudeb = TRUE;
+    }
+
+    /* This here doesn't let windows even a pixel outside the struts/screen.
+     * When called from client_manage, programs placing themselves are
      * forced completely onscreen, while things like
      * xterm -geometry resolution-width/2 will work fine. Trying to
      * place it completely offscreen will be handled in the above code.
      * Sorry for this confused comment, i am tired. */
-    if (rude) {
-        /* avoid the xinerama monitor divide while we're at it,
-         * remember to fix the placement stuff to avoid it also and
-         * then remove this XXX */
-        a = screen_area_monitor(self->desktop, client_monitor(self));
-        /* dont let windows map into the strut unless they
-           are bigger than the available area */
-        if (w <= a->width) {
-            if (!self->strut.left && *x < a->x) *x = a->x;
-            if (!self->strut.right && *x + w > a->x + a->width)
-                *x = a->x + a->width - w;
-        }
-        if (h <= a->height) {
-            if (!self->strut.top && *y < a->y) *y = a->y;
-            if (!self->strut.bottom && *y + h > a->y + a->height)
-                *y = a->y + a->height - h;
-        }
+    if (fw <= mon_a->width) {
+        if (rudel && !self->strut.left && *x < mon_a->x) *x = mon_a->x;
+        if (ruder && !self->strut.right && *x + fw > mon_a->x + mon_a->width)
+            *x = mon_a->x + mon_a->width - fw;
+    }
+    if (fh <= mon_a->height) {
+        if (rudet && !self->strut.top && *y < mon_a->y) *y = mon_a->y;
+        if (rudeb && !self->strut.bottom && *y + fh > mon_a->y + mon_a->height)
+            *y = mon_a->y + mon_a->height - fh;
     }
 
     /* get where the client should be */
index 2e191f1c5a883c5f5273f326c6f28dfc1ac45757..5e61f00fb198b48d903a7a149d2fc7294213f844 100644 (file)
@@ -220,7 +220,7 @@ void dock_configure()
     gint strw, strh;
     Rect *a;
 
-    RrMinsize(dock->a_frame, &minw, &minh);
+    RrMinSize(dock->a_frame, &minw, &minh);
 
     dock->w = dock->h = 0;
 
index 78768a62235d3a5eb1fb882781a5545968e58a20..a36e9223d3d345195735cee2474d16dc4a3942c5 100644 (file)
@@ -76,8 +76,8 @@ typedef struct
 
 static void event_process(const XEvent *e, gpointer data);
 static void event_handle_root(XEvent *e);
-static void event_handle_menu_shortcut(XEvent *e);
-static void event_handle_menu(XEvent *e);
+static gboolean event_handle_menu_keyboard(XEvent *e);
+static gboolean event_handle_menu(XEvent *e);
 static void event_handle_dock(ObDock *s, XEvent *e);
 static void event_handle_dockapp(ObDockApp *app, XEvent *e);
 static void event_handle_client(ObClient *c, XEvent *e);
@@ -571,9 +571,17 @@ static void event_process(const XEvent *ec, gpointer data)
         e->type == MotionNotify || e->type == KeyPress ||
         e->type == KeyRelease)
     {
-        if (menu_frame_visible)
-            event_handle_menu(e);
-        else {
+        gboolean useevent = TRUE;
+
+        if (menu_frame_visible) {
+            if (event_handle_menu(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 */
+                useevent = FALSE;
+        }
+
+        if (useevent) {
             if (!keyboard_process_interactive_grab(e, &client)) {
                 if (moveresize_in_progress) {
                     moveresize_event(e);
@@ -886,7 +894,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             h = (e->xconfigurerequest.value_mask & CWHeight) ?
                 e->xconfigurerequest.height : client->area.height;
 
-            client_find_onscreen(client, &x, &y, w, h, client_normal(client));
+            client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure_full(client, x, y, w, h, FALSE, TRUE, TRUE);
         }
 
@@ -1074,7 +1082,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 h = client->area.height;
 
             client_convert_gravity(client, grav, &x, &y, w, h);
-            client_find_onscreen(client, &x, &y, w, h, client_normal(client));
+            client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure(client, x, y, w, h, FALSE, TRUE);
         }
         break;
@@ -1236,86 +1244,128 @@ static ObMenuFrame* find_active_or_last_menu()
     return ret;
 }
 
-static void event_handle_menu_shortcut(XEvent *ev)
+static gboolean event_handle_menu_keyboard(XEvent *ev)
 {
-    gunichar unikey = 0;
+    guint keycode, state;
+    gunichar unikey;
     ObMenuFrame *frame;
-    GList *start;
-    GList *it;
-    ObMenuEntryFrame *found = NULL;
-    guint num_found = 0;
+    gboolean ret = TRUE;
+
+    keycode = ev->xkey.keycode;
+    state = ev->xkey.state;
+    unikey = translate_unichar(keycode);
 
+    frame = find_active_or_last_menu();
+    if (frame == NULL)
+        ret = FALSE;
+
+    else if (keycode == ob_keycode(OB_KEY_ESCAPE) && state == 0) {
+        /* Escape closes the active menu */
+        menu_frame_hide(frame);
+    }
+
+    else if (keycode == ob_keycode(OB_KEY_RETURN) && (state == 0 ||
+                                                      state == ControlMask))
     {
-        const char *key;
-        if ((key = translate_keycode(ev->xkey.keycode)) == NULL)
-            return;
-        unikey = g_utf8_get_char_validated(key, -1);
-        if (unikey == (gunichar)-1 || unikey == (gunichar)-2 || unikey == 0)
-            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
+            menu_entry_frame_execute(frame->selected, state, ev->xkey.time);
     }
 
-    if ((frame = find_active_or_last_menu()) == NULL)
-        return;
+    else if (keycode == ob_keycode(OB_KEY_LEFT) && ev->xkey.state == 0) {
+        /* Left goes to the parent menu */
+        menu_frame_select(frame, NULL, TRUE);
+    }
 
+    else if (keycode == ob_keycode(OB_KEY_RIGHT) && ev->xkey.state == 0) {
+        /* Right goes to the selected submenu */
+        if (frame->child) menu_frame_select_next(frame->child);
+    }
 
-    if (!frame->entries)
-        return; /* nothing in the menu anyways */
+    else if (keycode == ob_keycode(OB_KEY_UP) && state == 0) {
+        menu_frame_select_previous(frame);
+    }
 
-    /* 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 (keycode == ob_keycode(OB_KEY_DOWN) && state == 0) {
+        menu_frame_select_next(frame);
     }
 
-    it = start;
-    do {
-        ObMenuEntryFrame *e = it->data;
-        gunichar entrykey = 0;
+    /* keyboard accelerator shortcuts. */
+    else if (ev->xkey.state == 0 &&
+             /* was it a valid key? */
+             unikey != 0 &&
+             /* don't bother if the menu is empty. */
+             frame->entries)
+    {
+        GList *start;
+        GList *it;
+        ObMenuEntryFrame *found = NULL;
+        guint num_found = 0;
+
+        /* start after the selected one */
+        start = frame->entries;
+        if (frame->selected) {
+            for (it = start; frame->selected != it->data; it = g_list_next(it))
+                g_assert(it != NULL); /* nothing was selected? */
+            /* next with wraparound */
+            start = g_list_next(it);
+            if (start == NULL) start = frame->entries;
+        }
 
-        if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
-            e->entry->data.normal.enabled)
-            entrykey = e->entry->data.normal.shortcut;
-        else if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
-            entrykey = e->entry->data.submenu.submenu->shortcut;
+        it = start;
+        do {
+            ObMenuEntryFrame *e = it->data;
+            gunichar entrykey = 0;
 
-        if (unikey == entrykey) {
-            if (found == NULL) found = e;
-            ++num_found;
-        }
+            if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+                e->entry->data.normal.enabled)
+                entrykey = e->entry->data.normal.shortcut;
+            else if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
+                entrykey = e->entry->data.submenu.submenu->shortcut;
 
-        /* next with wraparound */
-        it = g_list_next(it);
-        if (it == NULL) it = frame->entries;
-    } while (it != start);
+            if (unikey == entrykey) {
+                if (found == NULL) found = e;
+                ++num_found;
+            }
 
-    if (found) {
-        if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
-            num_found == 1)
-        {
-            menu_frame_select(frame, found, TRUE);
-            usleep(50000);
-            menu_entry_frame_execute(found, ev->xkey.state,
-                                     ev->xkey.time);
-        } else {
-            menu_frame_select(frame, found, TRUE);
-            if (num_found == 1)
-                menu_frame_select_next(frame->child);
-        }
+            /* next with wraparound */
+            it = g_list_next(it);
+            if (it == NULL) it = frame->entries;
+        } while (it != start);
+
+        if (found) {
+            if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
+                num_found == 1)
+            {
+                menu_frame_select(frame, found, TRUE);
+                usleep(50000);
+                menu_entry_frame_execute(found, state, ev->xkey.time);
+            } else {
+                menu_frame_select(frame, found, TRUE);
+                if (num_found == 1)
+                    menu_frame_select_next(frame->child);
+            }
+        } else
+            ret = FALSE;
     }
+    else
+        ret = FALSE;
+
+    return ret;
 }
 
-static void event_handle_menu(XEvent *ev)
+static gboolean event_handle_menu(XEvent *ev)
 {
     ObMenuFrame *f;
     ObMenuEntryFrame *e;
+    gboolean ret = TRUE;
 
     switch (ev->type) {
     case ButtonRelease:
-        if (menu_can_hide) {
+        if (ev->xbutton.button <= 3 && menu_can_hide) {
             if ((e = menu_entry_frame_under(ev->xbutton.x_root,
                                             ev->xbutton.y_root)))
                 menu_entry_frame_execute(e, ev->xbutton.state,
@@ -1345,40 +1395,10 @@ static void event_handle_menu(XEvent *ev)
             menu_frame_select(e->frame, e, FALSE);
         break;
     case KeyPress:
-        if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
-            if ((f = find_active_or_last_menu()) && f->parent)
-                menu_frame_select(f, NULL, TRUE);
-            else
-                menu_frame_hide_all();
-        else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
-            ObMenuFrame *f;
-            if ((f = find_active_menu())) {
-                if (f->child)
-                    menu_frame_select_next(f->child);
-                else
-                    menu_entry_frame_execute(f->selected, ev->xkey.state,
-                                             ev->xkey.time);
-            }
-        } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
-            ObMenuFrame *f;
-            if ((f = find_active_or_last_menu()))
-                menu_frame_select(f, NULL, TRUE);
-        } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
-            ObMenuFrame *f;
-            if ((f = find_active_menu()) && f->child)
-                menu_frame_select_next(f->child);
-        } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
-            ObMenuFrame *f;
-            if ((f = find_active_or_last_menu()))
-                menu_frame_select_previous(f);
-        } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
-            ObMenuFrame *f;
-            if ((f = find_active_or_last_menu()))
-                menu_frame_select_next(f);
-        } else
-            event_handle_menu_shortcut(ev);
+        ret = event_handle_menu_keyboard(ev);
         break;
     }
+    return ret;
 }
 
 static gboolean menu_hide_delay_func(gpointer data)
index 4c663c3f124eabd30a223489263f1f24b6eb2120..aac6675e3a1fc7ccf18aaf0b64ce27bb822116cd 100644 (file)
@@ -304,13 +304,8 @@ static void popup_cycle(ObClient *c, gboolean show)
         a = screen_physical_area_monitor(0);
         icon_popup_position(focus_cycle_popup, CenterGravity,
                             a->x + a->width / 2, a->y + a->height / 2);
-/*        icon_popup_size(focus_cycle_popup, a->height/2, a->height/16);
-        icon_popup_show(focus_cycle_popup, c->title,
-                        client_icon(c, a->height/16, a->height/16));
-*/
-        /* XXX the size and the font extents need to be related on some level
-         */
-        icon_popup_size(focus_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
+        icon_popup_width(focus_cycle_popup, MAX(a->width/3, POPUP_WIDTH));
+        icon_popup_height(focus_cycle_popup, POPUP_HEIGHT);
 
         /* use the transient's parent's title/icon */
         while (p->transient_for && p->transient_for != OB_TRAN_GROUP)
@@ -323,10 +318,10 @@ static void popup_cycle(ObClient *c, gboolean show)
                                 (p->iconic ? p->icon_title : p->title),
                                 NULL);
             */
-        icon_popup_show(focus_cycle_popup,
-                        (title ? title :
-                         (c->iconic ? c->icon_title : c->title)),
-                        client_icon(p, 48, 48));
+        icon_popup_delay_show(focus_cycle_popup, G_USEC_PER_SEC/12,
+                              (title ? title :
+                               (c->iconic ? c->icon_title : c->title)),
+                              client_icon(p, 48, 48));
         g_free(title);
     }
 }
index e9ecf9d266a515c72bd2b9acbe87a3cfeeb54942..39832e949050c5cbb78ff1e73264945a2dd5108e 100644 (file)
@@ -26,6 +26,7 @@ typedef struct _Point {
 } Point;
 
 #define POINT_SET(pt, nx, ny) (pt).x = (nx), (pt).y = (ny)
+#define POINT_EQUAL(p1, p2) ((p1).x == (p2).x && (p1).y == (p2).y)
 
 typedef struct _Size {
     int width;
index c1151eb392eda2b8bb803c37390a08ae12148d63..ccfe04977c755ec23ef29815a6dde78be06bb9be 100644 (file)
@@ -27,6 +27,7 @@
 #include "client.h"
 #include "action.h"
 #include "prop.h"
+#include "menuframe.h"
 #include "config.h"
 #include "keytree.h"
 #include "keyboard.h"
@@ -75,14 +76,6 @@ static gboolean chain_timeout(gpointer data)
     return FALSE; /* don't repeat */
 }
 
-static gboolean popup_show_timeout(gpointer data)
-{
-    gchar *text = data;
-    popup_show(popup, text);
-
-    return FALSE; /* don't repeat */
-}
-
 static void set_curpos(KeyBindingTree *newpos)
 {
     grab_keys(FALSE);
@@ -103,19 +96,11 @@ static void set_curpos(KeyBindingTree *newpos)
         }
 
         popup_position(popup, NorthWestGravity, 10, 10);
-        if (popup->mapped) {
-            popup_show_timeout(text);
-            g_free(text);
-        } else {
-            ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
-            /* 1 second delay for the popup to show */
-            ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC,
-                                     popup_show_timeout, text,
-                                     g_direct_equal, g_free);
-        }
+        /* 1 second delay for the popup to show */
+        popup_delay_show(popup, G_USEC_PER_SEC, text);
+        g_free(text);
     } else {
         popup_hide(popup);
-        ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
     }
 }
 
@@ -313,6 +298,10 @@ void keyboard_event(ObClient *client, const XEvent *e)
         if (p->key == e->xkey.keycode &&
             p->state == e->xkey.state)
         {
+            /* if we hit a key binding, then close any open menus and run it */
+            if (menu_frame_visible)
+                menu_frame_hide_all();
+
             if (p->first_child != NULL) { /* part of a chain */
                 ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
                 /* 3 second timeout for chains */
@@ -362,7 +351,6 @@ void keyboard_shutdown(gboolean reconfig)
     interactive_states = NULL;
 
     ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
-    ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
 
     keyboard_unbind_all();
     set_curpos(NULL);
index cf9bfcbf5c7cd41c4c72e2d954626f7cca4a7ea0..6f8ecad01149b338a38f61d2ae177aebe5ef95ab 100644 (file)
@@ -221,15 +221,18 @@ static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
 
         /* try to the right of the cursor */
         menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+        self->direction_right = TRUE;
         if (dx != 0) {
             /* try to the left of the cursor */
             myx = *x - self->area.width;
             menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+            self->direction_right = FALSE;
         }
         if (dx != 0) {
             /* if didnt fit on either side so just use what it says */
             myx = *x;
             menu_frame_move_on_screen(self, myx, *y, &dx, &dy);
+            self->direction_right = TRUE;
         }
         *x = myx + dx;
         *y += dy;
@@ -241,29 +244,34 @@ static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y)
 
         /* try to the bottom right of the cursor */
         menu_frame_move_on_screen(self, myx, myy, &dx, &dy);
+        self->direction_right = TRUE;
         if (dx != 0 || dy != 0) {
             /* try to the bottom left of the cursor */
             myx = *x - self->area.width;
             myy = *y;
             menu_frame_move_on_screen(self, myx, myy, &dx, &dy);
+            self->direction_right = FALSE;
         }
         if (dx != 0 || dy != 0) {
             /* try to the top right of the cursor */
             myx = *x;
             myy = *y - self->area.height;
             menu_frame_move_on_screen(self, myx, myy, &dx, &dy);
+            self->direction_right = TRUE;
         }
         if (dx != 0 || dy != 0) {
             /* try to the top left of the cursor */
             myx = *x - self->area.width;
             myy = *y - self->area.height;
             menu_frame_move_on_screen(self, myx, myy, &dx, &dy);
+            self->direction_right = FALSE;
         }
         if (dx != 0 || dy != 0) {
             /* if didnt fit on either side so just use what it says */
             myx = *x;
             myy = *y;
             menu_frame_move_on_screen(self, myx, myy, &dx, &dy);
+            self->direction_right = TRUE;
         }
         *x = myx + dx;
         *y = myy + dy;
@@ -561,7 +569,7 @@ static void menu_frame_render(ObMenuFrame *self)
         gint l, t, r, b;
 
         e->a_text_normal->texture[0].data.text.string = "";
-        RrMinsize(e->a_text_normal, &tw, &th);
+        RrMinSize(e->a_text_normal, &tw, &th);
         tw += 2*PADDING;
         th += 2*PADDING;
         self->item_h = th;
@@ -623,7 +631,7 @@ static void menu_frame_render(ObMenuFrame *self)
         switch (e->entry->type) {
         case OB_MENU_ENTRY_TYPE_NORMAL:
             text_a->texture[0].data.text.string = e->entry->data.normal.label;
-            RrMinsize(text_a, &tw, &th);
+            RrMinSize(text_a, &tw, &th);
             tw = MIN(tw, MAX_MENU_WIDTH);
 
             if (e->entry->data.normal.icon_data ||
@@ -633,7 +641,7 @@ static void menu_frame_render(ObMenuFrame *self)
         case OB_MENU_ENTRY_TYPE_SUBMENU:
             sub = e->entry->data.submenu.submenu;
             text_a->texture[0].data.text.string = sub ? sub->title : "";
-            RrMinsize(text_a, &tw, &th);
+            RrMinSize(text_a, &tw, &th);
             tw = MIN(tw, MAX_MENU_WIDTH);
 
             if (e->entry->data.normal.icon_data ||
@@ -646,7 +654,7 @@ static void menu_frame_render(ObMenuFrame *self)
             if (e->entry->data.separator.label != NULL) {
                 e->a_text_title->texture[0].data.text.string =
                     e->entry->data.separator.label;
-                RrMinsize(e->a_text_title, &tw, &th);
+                RrMinSize(e->a_text_title, &tw, &th);
                 tw = MIN(tw, MAX_MENU_WIDTH);
                 th = ob_rr_theme->menu_title_height +
                     (ob_rr_theme->mbwidth - PADDING) *2;
index b03aed95619c76fd49a691f83b6721940c01b8b4..eba2106692f729b4ed3db445c0a80827dd2c48d7 100644 (file)
@@ -100,7 +100,7 @@ static void get_resize_position(gint *x, gint *y, gboolean cancel)
 
     /* see how much it is actually going to resize */
     {
-        gint cx = x, cy = y;
+        gint cx = *x, cy = *y;
         frame_frame_gravity(moveresize_client->frame, &cx, &cy, w, h);
         client_try_configure(moveresize_client, &cx, &cy, &w, &h,
                              &lw, &lh, TRUE);
@@ -369,9 +369,8 @@ static void do_resize()
        if there are 2 text boxes */
     if (config_resize_popup_show == 2 || /* == "Always" */
             (config_resize_popup_show == 1 && /* == "Nonpixel" */
-                (moveresize_client->size_inc.width > 1 ||
-                 moveresize_client->size_inc.height > 1))
-        )
+             moveresize_client->size_inc.width > 1 &&
+             moveresize_client->size_inc.height > 1))
         popup_coords(moveresize_client, "%d x %d",
                      moveresize_client->logical_size.width,
                      moveresize_client->logical_size.height);
index 9af23be0d88bfe291139cfec9b4bf6794daf338b..a3c94653dd9ed0f98ff02484e67a628ed7a80415 100644 (file)
 #include "stacking.h"
 #include "event.h"
 #include "screen.h"
+#include "mainloop.h"
 #include "render/render.h"
 #include "render/theme.h"
 
+static gboolean popup_show_timeout(gpointer data)
+{
+    ObPopup *self = data;
+    
+    XMapWindow(ob_display, self->bg);
+    stacking_raise(INTERNAL_AS_WINDOW(self));
+    self->mapped = TRUE;
+    self->delay_mapped = FALSE;
+
+    return FALSE; /* don't repeat */
+}
+
 ObPopup *popup_new(gboolean hasicon)
 {
     XSetWindowAttributes attrib;
@@ -75,25 +88,52 @@ void popup_position(ObPopup *self, gint gravity, gint x, gint y)
     self->y = y;
 }
 
-void popup_size(ObPopup *self, gint w, gint h)
+void popup_width(ObPopup *self, gint w)
 {
     self->w = w;
-    self->h = h;
 }
 
-void popup_size_to_string(ObPopup *self, gchar *text)
+void popup_height(ObPopup *self, gint h)
 {
-    gint textw, texth;
-    gint iconw;
+    gint texth;
 
-    self->a_text->texture[0].data.text.string = text;
-    RrMinsize(self->a_text, &textw, &texth);
-    /*XXX textw += ob_rr_theme->bevel * 2;*/
-    texth += ob_rr_theme->paddingy * 2;
+    /* don't let the height be smaller than the text */
+    texth = RrMinHeight(self->a_text) + ob_rr_theme->paddingy * 2;
+    self->h = MAX(h, texth);
+}
 
-    self->h = texth + ob_rr_theme->paddingy * 2;
-    iconw = (self->hasicon ? texth : 0);
+void popup_width_to_string(ObPopup *self, gchar *text, gint max)
+{
+    gint textw, iconw;
+
+    self->a_text->texture[0].data.text.string = text;
+    textw = RrMinWidth(self->a_text);
+    if (self->hasicon) {
+        gint texth = RrMinHeight(self->a_text) + ob_rr_theme->paddingy * 2;
+        iconw = texth;
+    } else
+        iconw = 0;
     self->w = textw + iconw + ob_rr_theme->paddingx * (self->hasicon ? 3 : 2);
+    /* cap it at "max" */
+    if (max > 0)
+        self->w = MIN(self->w, max);
+}
+
+void popup_height_to_string(ObPopup *self, gchar *text)
+{
+    self->h = RrMinHeight(self->a_text) + ob_rr_theme->paddingy * 2;
+}
+
+void popup_width_to_strings(ObPopup *self, gchar **strings, gint max)
+{
+    gint i, maxw;
+
+    maxw = 0;
+    for (i = 0; strings[i] != NULL; ++i) {
+        popup_width_to_string(self, strings[i], max);
+        maxw = MAX(maxw, self->w);
+    }
+    self->w = maxw;
 }
 
 void popup_set_text_align(ObPopup *self, RrJustify align)
@@ -101,7 +141,7 @@ void popup_set_text_align(ObPopup *self, RrJustify align)
     self->a_text->texture[0].data.text.justify = align;
 }
 
-void popup_show(ObPopup *self, gchar *text)
+void popup_delay_show(ObPopup *self, gulong usec, gchar *text)
 {
     gint l, t, r, b;
     gint x, y, w, h;
@@ -122,9 +162,8 @@ void popup_show(ObPopup *self, gchar *text)
     /* set up the textures */
     self->a_text->texture[0].data.text.string = text;
 
-    /* measure the shit out */
-    RrMinsize(self->a_text, &textw, &texth);
-    /*XXX textw += ob_rr_theme->padding * 2;*/
+    /* measure the text out */
+    RrMinSize(self->a_text, &textw, &texth);
     texth += ob_rr_theme->paddingy * 2;
 
     /* set the sizes up and reget the text sizes from the calculated
@@ -204,10 +243,19 @@ void popup_show(ObPopup *self, gchar *text)
                             iconw, texth, self->draw_icon_data);
     }
 
+    /* do the actual showing */
     if (!self->mapped) {
-        XMapWindow(ob_display, self->bg);
-        stacking_raise(INTERNAL_AS_WINDOW(self));
-        self->mapped = TRUE;
+        if (usec) {
+            /* don't kill previous show timers */
+            if (!self->delay_mapped) {
+                ob_main_loop_timeout_add(ob_main_loop, usec,
+                                         popup_show_timeout, self,
+                                         g_direct_equal, NULL);
+                self->delay_mapped = TRUE;
+            }
+        } else {
+            popup_show_timeout(self);
+        }
     }
 }
 
@@ -219,6 +267,9 @@ void popup_hide(ObPopup *self)
 
         /* kill enter events cause by this unmapping */
         event_ignore_queued_enters();
+    } else if (self->delay_mapped) {
+        ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout);
+        self->delay_mapped = FALSE;
     }
 }
 
@@ -262,8 +313,8 @@ void icon_popup_free(ObIconPopup *self)
     }
 }
 
-void icon_popup_show(ObIconPopup *self,
-                     gchar *text, const ObClientIcon *icon)
+void icon_popup_delay_show(ObIconPopup *self, gulong usec,
+                           gchar *text, const ObClientIcon *icon)
 {
     if (icon) {
         self->a_icon->texture[0].type = RR_TEXTURE_RGBA;
@@ -273,7 +324,7 @@ void icon_popup_show(ObIconPopup *self,
     } else
         self->a_icon->texture[0].type = RR_TEXTURE_NONE;
 
-    popup_show(self->popup, text);
+    popup_delay_show(self->popup, usec, text);
 }
 
 static void pager_popup_draw_icon(gint px, gint py, gint w, gint h,
@@ -422,7 +473,8 @@ void pager_popup_free(ObPagerPopup *self)
     }
 }
 
-void pager_popup_show(ObPagerPopup *self, gchar *text, guint desk)
+void pager_popup_delay_show(ObPagerPopup *self, gulong usec,
+                            gchar *text, guint desk)
 {
     guint i;
 
@@ -449,5 +501,5 @@ void pager_popup_show(ObPagerPopup *self, gchar *text, guint desk)
     self->desks = screen_num_desktops;
     self->curdesk = desk;
 
-    popup_show(self->popup, text);
+    popup_delay_show(self->popup, usec, text);
 }
index 609c30286a030741f8748b5b2c480e5636f9fc61..66e0fcab68fdc4738b83d757451261528e8e0db8 100644 (file)
@@ -48,6 +48,7 @@ struct _ObPopup
     gint w;
     gint h;
     gboolean mapped;
+    gboolean delay_mapped;
  
     void (*draw_icon)(gint x, gint y, gint w, gint h, gpointer data);
     gpointer draw_icon_data;
@@ -83,12 +84,16 @@ void popup_free(ObPopup *self);
 void popup_position(ObPopup *self, gint gravity, gint x, gint y);
 /*! Set the sizes for the popup. When set to 0, the size will be based on
   the text size. */
-void popup_size(ObPopup *self, gint w, gint h);
-void popup_size_to_string(ObPopup *self, gchar *text);
+void popup_width(ObPopup *self, gint w);
+void popup_height(ObPopup *self, gint w);
+void popup_width_to_string(ObPopup *self, gchar *text, gint max);
+void popup_height_to_string(ObPopup *self, gchar *text);
+void popup_width_to_strings(ObPopup *self, gchar **strings, gint max);
 
 void popup_set_text_align(ObPopup *self, RrJustify align);
 
-void popup_show(ObPopup *self, gchar *text);
+#define popup_show(s, t) popup_delay_show((s),0,(t))
+void popup_delay_show(ObPopup *self, gulong usec, gchar *text);
 void popup_hide(ObPopup *self);
 
 RrAppearance *popup_icon_appearance(ObPopup *self);
@@ -97,22 +102,33 @@ RrAppearance *popup_icon_appearance(ObPopup *self);
 ObIconPopup *icon_popup_new();
 void icon_popup_free(ObIconPopup *self);
 
-void icon_popup_show(ObIconPopup *self,
-                     gchar *text, const struct _ObClientIcon *icon);
+#define icon_popup_show(s, t, i) icon_popup_delay_show((s),0,(t),(i))
+void icon_popup_delay_show(ObIconPopup *self, gulong usec,
+                           gchar *text, const struct _ObClientIcon *icon);
 #define icon_popup_hide(p) popup_hide((p)->popup)
 #define icon_popup_position(p, g, x, y) popup_position((p)->popup,(g),(x),(y))
-#define icon_popup_size(p, w, h) popup_size((p)->popup,(w),(h))
-#define icon_popup_size_to_string(p, s) popup_size_to_string((p)->popup,(s))
+#define icon_popup_width(p, w) popup_width((p)->popup,(w))
+#define icon_popup_height(p, h) popup_height((p)->popup,(h))
+#define icon_popup_width_to_string(p, s, m) \
+    popup_width_to_string((p)->popup,(s),(m))
+#define icon_popup_width_to_strings(p, s, m) \
+    popup_width_to_strings((p)->popup,(s),(m))
 #define icon_popup_set_text_align(p, j) popup_set_text_align((p)->popup,(j))
 
 ObPagerPopup *pager_popup_new();
 void pager_popup_free(ObPagerPopup *self);
 
-void pager_popup_show(ObPagerPopup *self, gchar *text, guint desk);
+#define pager_popup_show(s, t, d) paper_popup_delay_show((s),0,(t),(d;2D))
+void pager_popup_delay_show(ObPagerPopup *self, gulong usec,
+                            gchar *text, guint desk);
 #define pager_popup_hide(p) popup_hide((p)->popup)
 #define pager_popup_position(p, g, x, y) popup_position((p)->popup,(g),(x),(y))
-#define pager_popup_size(p, w, h) popup_size((p)->popup,(w),(h))
-#define pager_popup_size_to_string(p, s) popup_size_to_string((p)->popup,(s))
+#define pager_popup_width(p, w) popup_width((p)->popup,(w))
+#define pager_popup_height(p, h) popup_height((p)->popup,(h))
+#define pager_popup_width_to_string(p, s, m) \
+    popup_width_to_string((p)->popup,(s),(m))
+#define pager_popup_width_to_strings(p, s, m) \
+    popup_width_to_strings((p)->popup,(s),(m))
 #define pager_popup_set_text_align(p, j) popup_set_text_align((p)->popup,(j))
 
 #endif
index 0773caad9e210b43e042e2cb4345c63486c5397f..25b7a46d0f918d49771e6f78bd0002bd15e44d89 100644 (file)
@@ -598,13 +598,11 @@ void screen_desktop_popup(guint d, gboolean show)
         a = screen_physical_area_monitor(0);
         pager_popup_position(desktop_cycle_popup, CenterGravity,
                              a->x + a->width / 2, a->y + a->height / 2);
-        /* XXX the size and the font extents need to be related on some level
-         */
-        pager_popup_size(desktop_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT);
+        pager_popup_width(desktop_cycle_popup, MAX(a->width/3, POPUP_WIDTH));
+        pager_popup_height(desktop_cycle_popup, POPUP_HEIGHT);
 
-        pager_popup_set_text_align(desktop_cycle_popup, RR_JUSTIFY_CENTER);
-
-        pager_popup_show(desktop_cycle_popup, screen_desktop_names[d], d);
+        pager_popup_delay_show(desktop_cycle_popup, G_USEC_PER_SEC/12,
+                               screen_desktop_names[d], d);
     }
 }
 
index 97066519f4b9f0cf73e53826e77a59e398cf5777..a7cac55721328e0da76eeb14bfc272ccde86172e 100644 (file)
@@ -149,3 +149,19 @@ const gchar *translate_keycode(guint keycode)
         ret = XKeysymToString(sym);
     return g_locale_to_utf8(ret, -1, NULL, NULL, NULL);
 }
+
+gunichar translate_unichar(guint keycode)
+{
+    gunichar unikey = 0;
+
+    const char *key;
+    if ((key = translate_keycode(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;
+    }
+    return unikey;
+}
index 14efe73da6a64688a8904338b25f7e4b6695e916..21cd64984146ce5556693f5240864d011ce4fd8e 100644 (file)
@@ -26,4 +26,8 @@ gboolean translate_key(const gchar *str, guint *state, guint *keycode);
 
 /*! Give the string form of a keycode */
 const gchar *translate_keycode(guint keycode);
+
+/*! Translate a keycode to the unicode character it represents */
+gunichar translate_unichar(guint keycode);
+
 #endif
index 8c39fcd249d0a1e86dcae115a500e2ab2fe97747..2755e6678056f9fd60a9eaa3231715ed35a9cc84 100644 (file)
@@ -344,52 +344,85 @@ void RrMargins (RrAppearance *a, gint *l, gint *t, gint *r, gint *b)
     }
 }
 
-void RrMinsize(RrAppearance *a, gint *w, gint *h)
+void RrMinSize(RrAppearance *a, gint *w, gint *h)
+{
+    *w = RrMinWidth(a);
+    *h = RrMinHeight(a);
+}
+
+gint RrMinWidth(RrAppearance *a)
 {
     gint i;
     RrSize *m;
     gint l, t, r, b;
-    *w = *h = 0;
+    gint w = 0;
 
     for (i = 0; i < a->textures; ++i) {
         switch (a->texture[i].type) {
         case RR_TEXTURE_NONE:
             break;
         case RR_TEXTURE_MASK:
-            *w = MAX(*w, a->texture[i].data.mask.mask->width);
-            *h = MAX(*h, a->texture[i].data.mask.mask->height);
+            w = MAX(w, a->texture[i].data.mask.mask->width);
             break;
         case RR_TEXTURE_TEXT:
             m = RrFontMeasureString(a->texture[i].data.text.font,
                                     a->texture[i].data.text.string, 
                                     a->texture[i].data.text.shadow_offset_x,
                                     a->texture[i].data.text.shadow_offset_y);
-            *w = MAX(*w, m->width + 4);
-            m->height = RrFontHeight(a->texture[i].data.text.font,
-                                     a->texture[i].data.text.shadow_offset_y);
-            *h += MAX(*h, m->height);
+            w = MAX(w, m->width + 4);
             g_free(m);
             break;
         case RR_TEXTURE_RGBA:
-            *w += MAX(*w, a->texture[i].data.rgba.width);
-            *h += MAX(*h, a->texture[i].data.rgba.height);
+            w += MAX(w, a->texture[i].data.rgba.width);
+            break;
+        case RR_TEXTURE_LINE_ART:
+            w += MAX(w, MAX(a->texture[i].data.lineart.x1,
+                            a->texture[i].data.lineart.x2));
+            break;
+        }
+    }
+
+    RrMargins(a, &l, &t, &r, &b);
+
+    w += l + r;
+
+    if (w < 1) w = 1;
+    return w;
+}
+
+gint RrMinHeight(RrAppearance *a)
+{
+    gint i;
+    gint l, t, r, b;
+    gint h = 0;
+
+    for (i = 0; i < a->textures; ++i) {
+        switch (a->texture[i].type) {
+        case RR_TEXTURE_NONE:
+            break;
+        case RR_TEXTURE_MASK:
+            h = MAX(h, a->texture[i].data.mask.mask->height);
+            break;
+        case RR_TEXTURE_TEXT:
+            h += MAX(h, RrFontHeight(a->texture[i].data.text.font,
+                                     a->texture[i].data.text.shadow_offset_y));
+            break;
+        case RR_TEXTURE_RGBA:
+            h += MAX(h, a->texture[i].data.rgba.height);
             break;
         case RR_TEXTURE_LINE_ART:
-            *w += MAX(*w, MAX(a->texture[i].data.lineart.x1,
-                              a->texture[i].data.lineart.x2));
-            *h += MAX(*h, MAX(a->texture[i].data.lineart.y1,
-                              a->texture[i].data.lineart.y2));
+            h += MAX(h, MAX(a->texture[i].data.lineart.y1,
+                            a->texture[i].data.lineart.y2));
             break;
         }
     }
 
     RrMargins(a, &l, &t, &r, &b);
 
-    *w += l + r;
-    *h += t + b;
+    h += t + b;
 
-    if (*w < 1) *w = 1;
-    if (*h < 1) *h = 1;
+    if (h < 1) h = 1;
+    return h;
 }
 
 static void reverse_bits(gchar *c, gint n)
index da2361cc805d7766ce0edec05183cf403e2cc0f8..3b996375b7896023f67564860236b5239b35a189 100644 (file)
@@ -245,7 +245,9 @@ gint    RrFontMaxCharWidth  (const RrFont *f);
    it is non-null. */
 Pixmap RrPaintPixmap (RrAppearance *a, gint w, gint h);
 void   RrPaint       (RrAppearance *a, Window win, gint w, gint h);
-void   RrMinsize     (RrAppearance *a, gint *w, gint *h);
+void   RrMinSize     (RrAppearance *a, gint *w, gint *h);
+gint   RrMinWidth    (RrAppearance *a);
+gint   RrMinHeight   (RrAppearance *a);
 void   RrMargins     (RrAppearance *a, gint *l, gint *t, gint *r, gint *b);
 
 gboolean RrPixmapToRGBA(const RrInstance *inst,