From 961e1215474e95de0828d52456fd5918f60bbdf7 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 2 May 2007 03:11:35 +0000 Subject: [PATCH] merge r5968-5975 from trunk --- openbox/client.c | 104 +++++++++++++-------- openbox/dock.c | 2 +- openbox/event.c | 210 +++++++++++++++++++++++-------------------- openbox/focus.c | 17 ++-- openbox/geom.h | 1 + openbox/keyboard.c | 28 ++---- openbox/menuframe.c | 16 +++- openbox/moveresize.c | 7 +- openbox/popup.c | 98 +++++++++++++++----- openbox/popup.h | 36 +++++--- openbox/screen.c | 10 +-- openbox/translate.c | 16 ++++ openbox/translate.h | 4 + render/render.c | 69 ++++++++++---- render/render.h | 4 +- 15 files changed, 391 insertions(+), 231 deletions(-) diff --git a/openbox/client.c b/openbox/client.c index 33967962..5e1a7851 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -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 */ diff --git a/openbox/dock.c b/openbox/dock.c index 2e191f1c..5e61f00f 100644 --- a/openbox/dock.c +++ b/openbox/dock.c @@ -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; diff --git a/openbox/event.c b/openbox/event.c index 78768a62..a36e9223 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -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) diff --git a/openbox/focus.c b/openbox/focus.c index 4c663c3f..aac6675e 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -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); } } diff --git a/openbox/geom.h b/openbox/geom.h index e9ecf9d2..39832e94 100644 --- a/openbox/geom.h +++ b/openbox/geom.h @@ -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; diff --git a/openbox/keyboard.c b/openbox/keyboard.c index c1151eb3..ccfe0497 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -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); diff --git a/openbox/menuframe.c b/openbox/menuframe.c index cf9bfcbf..6f8ecad0 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -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; diff --git a/openbox/moveresize.c b/openbox/moveresize.c index b03aed95..eba21066 100644 --- a/openbox/moveresize.c +++ b/openbox/moveresize.c @@ -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); diff --git a/openbox/popup.c b/openbox/popup.c index 9af23be0..a3c94653 100644 --- a/openbox/popup.c +++ b/openbox/popup.c @@ -25,9 +25,22 @@ #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); } diff --git a/openbox/popup.h b/openbox/popup.h index 609c3028..66e0fcab 100644 --- a/openbox/popup.h +++ b/openbox/popup.h @@ -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 diff --git a/openbox/screen.c b/openbox/screen.c index 0773caad..25b7a46d 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -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); } } diff --git a/openbox/translate.c b/openbox/translate.c index 97066519..a7cac557 100644 --- a/openbox/translate.c +++ b/openbox/translate.c @@ -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; +} diff --git a/openbox/translate.h b/openbox/translate.h index 14efe73d..21cd6498 100644 --- a/openbox/translate.h +++ b/openbox/translate.h @@ -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 diff --git a/render/render.c b/render/render.c index 8c39fcd2..2755e667 100644 --- a/render/render.c +++ b/render/render.c @@ -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) diff --git a/render/render.h b/render/render.h index da2361cc..3b996375 100644 --- a/render/render.h +++ b/render/render.h @@ -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, -- 2.34.1