From: Dana Jansens Date: Thu, 26 Apr 2007 05:09:18 +0000 (+0000) Subject: merge r5928-5942 from trunk X-Git-Tag: openbox-3_3_991-RELEASE~213 X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=13f477168b94e0adda97065a4289b8e560df8bfd;p=dana%2Fopenbox.git merge r5928-5942 from trunk --- diff --git a/data/rc.xsd b/data/rc.xsd index 15c426c3..fdb98e7d 100644 --- a/data/rc.xsd +++ b/data/rc.xsd @@ -49,454 +49,422 @@ Removed fourCorners option. Wed Apr 25 14:02:40 UTC 2007 Fixed values for layer to be above/below, not top/bottom. + Add chroot attribute and keybind element to keybind element. + Remove xsd:sequence from everywhere, we don't care about order. --> - - - - all these elements are expected in a openbox config file - - - - - - - - - - - - - - - - - + + + all these elements are expected in a openbox config file + + + + + + + + + + + + + + + - - - defines behaviour of windows when close to each other or the screen edge - - - - - - - - - - defines aspects of window focus - - - - - - - - - - - - defines how new windows are placed - - - - - - - - - - - - - - - - - - - - - - - - - - defines the number and names of desktops - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + defines behaviour of windows when close to each other or the screen edge + + + + + + + + defines aspects of window focus + + + + + + + + + + defines how new windows are placed + + + + + + + + + + + + + + + + + + + + defines the number and names of desktops + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openbox/action.c b/openbox/action.c index 556fc225..80b0a8f1 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -892,6 +892,11 @@ ActionString actionstrings[] = action_growtoedge, setup_action_growtoedge_east }, + { + "breakchroot", + action_break_chroot, + NULL + }, { NULL, NULL, @@ -1727,7 +1732,7 @@ void action_showmenu(union ActionData *data) { if (data->showmenu.name) { menu_show(data->showmenu.name, data->any.x, data->any.y, - data->showmenu.any.c); + data->any.button, data->showmenu.any.c); } } @@ -1899,3 +1904,9 @@ void action_unshow_desktop(union ActionData *data) { screen_show_desktop(FALSE); } + +void action_break_chroot(union ActionData *data) +{ + /* break out of one chroot */ + keyboard_reset_chains(1); +} diff --git a/openbox/action.h b/openbox/action.h index 40391460..c4c06fa8 100644 --- a/openbox/action.h +++ b/openbox/action.h @@ -341,5 +341,7 @@ void action_toggle_show_desktop(union ActionData *data); void action_show_desktop(union ActionData *data); /* Any */ void action_unshow_desktop(union ActionData *data); +/* Any */ +void action_break_chroot(union ActionData *data); #endif diff --git a/openbox/client.c b/openbox/client.c index 4b8e621b..84f739ac 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -483,11 +483,8 @@ void client_unmanage(ObClient *self) /* flush to send the hide to the server quickly */ XFlush(ob_display); - if (focus_client == self) { - /* ignore enter events from the unmap so it doesnt mess with the focus - */ - event_ignore_queued_enters(); - } + /* ignore enter events from the unmap so it doesnt mess with the focus */ + event_ignore_queued_enters(); mouse_grab_for_client(self, FALSE); @@ -1137,7 +1134,8 @@ void client_update_transient_for(ObClient *self) /* remove from old parents */ for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; - if (c != self && !c->transient_for) + if (c != self && (!c->transient_for || + c->transient_for != OB_TRAN_GROUP)) c->transients = g_slist_remove(c->transients, self); } } else if (self->transient_for != NULL) { /* transient of window */ @@ -1152,7 +1150,8 @@ void client_update_transient_for(ObClient *self) /* add to new parents */ for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; - if (c != self && !c->transient_for) + if (c != self && (!c->transient_for || + c->transient_for != OB_TRAN_GROUP)) c->transients = g_slist_append(c->transients, self); } diff --git a/openbox/client_menu.c b/openbox/client_menu.c index be767155..4efef8a8 100644 --- a/openbox/client_menu.c +++ b/openbox/client_menu.c @@ -157,6 +157,69 @@ static void send_to_update(ObMenuFrame *frame, gpointer data) } } +static void client_menu_place(ObMenuFrame *frame, gint *x, gint *y, + gint button, gpointer data) +{ + gint dx, dy; + + if (button == 0 && frame->client) { + *x = frame->client->frame->area.x; + + /* try below the titlebar */ + *y = frame->client->frame->area.y + frame->client->frame->size.top - + frame->client->frame->bwidth; + menu_frame_move_on_screen(frame, *x, *y, &dx, &dy); + if (dy != 0) { + /* try above the titlebar */ + *y = frame->client->frame->area.y + frame->client->frame->bwidth - + frame->area.height; + menu_frame_move_on_screen(frame, *x, *y, &dx, &dy); + } + if (dy != 0) { + /* didnt fit either way, use move on screen's values */ + *y = frame->client->frame->area.y + frame->client->frame->size.top; + menu_frame_move_on_screen(frame, *x, *y, &dx, &dy); + } + + *x += dx; + *y += dy; + } else { + gint myx, myy; + + myx = *x; + myy = *y; + + /* try to the bottom right of the cursor */ + menu_frame_move_on_screen(frame, myx, myy, &dx, &dy); + if (dx != 0 || dy != 0) { + /* try to the bottom left of the cursor */ + myx = *x - frame->area.width; + myy = *y; + menu_frame_move_on_screen(frame, myx, myy, &dx, &dy); + } + if (dx != 0 || dy != 0) { + /* try to the top right of the cursor */ + myx = *x; + myy = *y - frame->area.height; + menu_frame_move_on_screen(frame, myx, myy, &dx, &dy); + } + if (dx != 0 || dy != 0) { + /* try to the top left of the cursor */ + myx = *x - frame->area.width; + myy = *y - frame->area.height; + menu_frame_move_on_screen(frame, myx, myy, &dx, &dy); + } + 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(frame, myx, myy, &dx, &dy); + } + *x = myx + dx; + *y = myy + dy; + } +} + void client_menu_startup() { GSList *acts; @@ -189,6 +252,7 @@ void client_menu_startup() menu = menu_new(CLIENT_MENU_NAME, _("Client menu"), TRUE, NULL); menu_show_all_shortcuts(menu, TRUE); menu_set_update_func(menu, client_update); + menu_set_place_func(menu, client_menu_place); menu_add_submenu(menu, CLIENT_SEND_TO, SEND_TO_MENU_NAME); diff --git a/openbox/config.c b/openbox/config.c index fda9d9f0..f8b3fd95 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -273,47 +273,60 @@ static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, GList *keylist) { gchar *key; - ObAction *action; - xmlNodePtr n, nact; - GList *it; + xmlNodePtr n; + gboolean is_chroot = FALSE; - if ((n = parse_find_node("chainQuitKey", node))) { - key = parse_string(doc, n); - translate_key(key, &config_keyboard_reset_state, - &config_keyboard_reset_keycode); - g_free(key); - } + if (!parse_attr_string("key", node, &key)) + return; - n = parse_find_node("keybind", node); - while (n) { - if (parse_attr_string("key", n, &key)) { - keylist = g_list_append(keylist, key); + parse_attr_bool("chroot", node, &is_chroot); - parse_key(i, doc, n->children, keylist); + keylist = g_list_append(keylist, key); - it = g_list_last(keylist); - g_free(it->data); - keylist = g_list_delete_link(keylist, it); + if ((n = parse_find_node("keybind", node->children))) { + while (n) { + parse_key(i, doc, n, keylist); + n = parse_find_node("keybind", n->next); } - n = parse_find_node("keybind", n->next); } - if (keylist) { - nact = parse_find_node("action", node); - while (nact) { - if ((action = action_parse(i, doc, nact, - OB_USER_ACTION_KEYBOARD_KEY))) + else if ((n = parse_find_node("action", node->children))) { + while (n) { + ObAction *action; + + action = action_parse(i, doc, n, OB_USER_ACTION_KEYBOARD_KEY); + if (action) keyboard_bind(keylist, action); - nact = parse_find_node("action", nact->next); + n = parse_find_node("action", n->next); } } + + if (is_chroot) + keyboard_chroot(keylist); + + g_free(key); + keylist = g_list_delete_link(keylist, g_list_last(keylist)); } static void parse_keyboard(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node, gpointer d) { + xmlNodePtr n; + gchar *key; + keyboard_unbind_all(); - parse_key(i, doc, node->children, NULL); + if ((n = parse_find_node("chainQuitKey", node->children))) { + key = parse_string(doc, n); + translate_key(key, &config_keyboard_reset_state, + &config_keyboard_reset_keycode); + g_free(key); + } + + if ((n = parse_find_node("keybind", node->children))) + while (n) { + parse_key(i, doc, n, NULL); + n = parse_find_node("keybind", n->next); + } } /* diff --git a/openbox/keyboard.c b/openbox/keyboard.c index f9716c30..c1151eb3 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -32,12 +32,11 @@ #include "keyboard.h" #include "translate.h" #include "moveresize.h" +#include "popup.h" #include "gettext.h" #include -KeyBindingTree *keyboard_firstnode; - typedef struct { guint state; ObClient *client; @@ -45,61 +44,112 @@ typedef struct { ObFrameContext context; } ObInteractiveState; +KeyBindingTree *keyboard_firstnode = NULL; +static ObPopup *popup = NULL; static GSList *interactive_states; - static KeyBindingTree *curpos; -static void grab_for_window(Window win, gboolean grab) +static void grab_keys(gboolean grab) { KeyBindingTree *p; - ungrab_all_keys(win); + ungrab_all_keys(RootWindow(ob_display, ob_screen)); if (grab) { p = curpos ? curpos->first_child : keyboard_firstnode; while (p) { - grab_key(p->key, p->state, win, GrabModeAsync); + grab_key(p->key, p->state, RootWindow(ob_display, ob_screen), + GrabModeAsync); p = p->next_sibling; } if (curpos) grab_key(config_keyboard_reset_keycode, config_keyboard_reset_state, - win, GrabModeAsync); + RootWindow(ob_display, ob_screen), GrabModeAsync); } } -static void grab_keys(gboolean grab) +static gboolean chain_timeout(gpointer data) { - GList *it; - - grab_for_window(screen_support_win, grab); - grab_for_window(RootWindow(ob_display, ob_screen), grab); + keyboard_reset_chains(0); + return FALSE; /* don't repeat */ } -static gboolean chain_timeout(gpointer data) +static gboolean popup_show_timeout(gpointer data) { - keyboard_reset_chains(); + gchar *text = data; + popup_show(popup, text); return FALSE; /* don't repeat */ } -void keyboard_reset_chains() +static void set_curpos(KeyBindingTree *newpos) { - ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); + grab_keys(FALSE); + curpos = newpos; + grab_keys(TRUE); + + if (curpos != NULL) { + gchar *text = NULL; + GList *it; + + for (it = curpos->keylist; it; it = g_list_next(it)) { + gchar *oldtext = text; + if (text == NULL) + text = g_strdup(it->data); + else + text = g_strconcat(text, " - ", it->data, NULL); + g_free(oldtext); + } + + 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); + } + } else { + popup_hide(popup); + ob_main_loop_timeout_remove(ob_main_loop, popup_show_timeout); + } +} - if (curpos) { - grab_keys(FALSE); - curpos = NULL; - grab_keys(TRUE); +void keyboard_reset_chains(gint break_chroots) +{ + KeyBindingTree *p; + + for (p = curpos; p; p = p->parent) { + if (p->chroot) { + if (break_chroots == 0) break; /* stop here */ + if (break_chroots > 0) + --break_chroots; + } } + set_curpos(p); } void keyboard_unbind_all() { tree_destroy(keyboard_firstnode); keyboard_firstnode = NULL; - grab_keys(FALSE); - curpos = NULL; +} + +void keyboard_chroot(GList *keylist) +{ + /* try do it in the existing tree. if we can't that means it is an empty + chroot binding. so add it to the tree then. */ + if (!tree_chroot(keyboard_firstnode, keylist)) { + KeyBindingTree *tree; + if (!(tree = tree_build(keylist))) + return; + tree_chroot(tree, keylist); + tree_assimilate(tree); + } } gboolean keyboard_bind(GList *keylist, ObAction *action) @@ -190,7 +240,6 @@ void keyboard_interactive_end(ObInteractiveState *s, if (!interactive_states) { grab_keyboard(FALSE); grab_pointer(FALSE, FALSE, OB_CURSOR_NONE); - keyboard_reset_chains(); } } @@ -251,7 +300,8 @@ void keyboard_event(ObClient *client, const XEvent *e) if (e->xkey.keycode == config_keyboard_reset_keycode && e->xkey.state == config_keyboard_reset_state) { - keyboard_reset_chains(); + ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); + keyboard_reset_chains(-1); return; } @@ -265,16 +315,15 @@ void keyboard_event(ObClient *client, const XEvent *e) { if (p->first_child != NULL) { /* part of a chain */ ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); - /* 5 second timeout for chains */ - ob_main_loop_timeout_add(ob_main_loop, 5 * G_USEC_PER_SEC, + /* 3 second timeout for chains */ + ob_main_loop_timeout_add(ob_main_loop, 3 * G_USEC_PER_SEC, chain_timeout, NULL, g_direct_equal, NULL); - grab_keys(FALSE); - curpos = p; - grab_keys(TRUE); - } else { - - keyboard_reset_chains(); + set_curpos(p); + } else if (p->chroot) /* an empty chroot */ + set_curpos(p); + else { + keyboard_reset_chains(0); action_run_key(p->actions, client, e->xkey.state, e->xkey.x_root, e->xkey.y_root, @@ -294,6 +343,7 @@ gboolean keyboard_interactively_grabbed() void keyboard_startup(gboolean reconfig) { grab_keys(TRUE); + popup = popup_new(FALSE); if (!reconfig) client_add_destructor(keyboard_interactive_end_client, NULL); @@ -312,7 +362,12 @@ 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); + + popup_free(popup); + popup = NULL; } diff --git a/openbox/keyboard.h b/openbox/keyboard.h index 80709fa5..4c6f3bb5 100644 --- a/openbox/keyboard.h +++ b/openbox/keyboard.h @@ -34,11 +34,14 @@ extern KeyBindingTree *keyboard_firstnode; void keyboard_startup(gboolean reconfig); void keyboard_shutdown(gboolean reconfig); +void keyboard_chroot(GList *keylist); gboolean keyboard_bind(GList *keylist, ObAction *action); void keyboard_unbind_all(); void keyboard_event(struct _ObClient *client, const XEvent *e); -void keyboard_reset_chains(); +/*! @param break_chroots how many chroots to break. -1 means to break them ALL! + */ +void keyboard_reset_chains(gint break_chroots); gboolean keyboard_interactive_grab(guint state, struct _ObClient *client, struct _ObAction *action); diff --git a/openbox/keytree.c b/openbox/keytree.c index e86fb4c6..202dd32c 100644 --- a/openbox/keytree.c +++ b/openbox/keytree.c @@ -52,17 +52,16 @@ KeyBindingTree *tree_build(GList *keylist) return NULL; /* nothing in the list.. */ for (it = g_list_last(keylist); it; it = g_list_previous(it)) { + GList *kit; + p = ret; ret = g_new0(KeyBindingTree, 1); - if (p == NULL) { - GList *it; - /* this is the first built node, the bottom node of the tree */ - ret->keylist = g_list_copy(keylist); /* shallow copy */ - for (it = ret->keylist; it; it = g_list_next(it)) /* deep copy */ - it->data = g_strdup(it->data); - } + for (kit = it; kit != NULL; kit = g_list_previous(kit)) + ret->keylist = g_list_prepend(ret->keylist, + g_strdup(kit->data)); /* deep copy */ ret->first_child = p; + if (p != NULL) p->parent = ret; if (!translate_key(it->data, &ret->state, &ret->key)) { tree_destroy(ret); return NULL; @@ -93,10 +92,12 @@ void tree_assimilate(KeyBindingTree *node) a = a->first_child; } } - if (!(last->state == b->state && last->key == b->key)) + if (!(last->state == b->state && last->key == b->key)) { last->next_sibling = b; - else { + b->parent = last->parent; + } else { last->first_child = b->first_child; + last->first_child->parent = last; g_free(b); } } @@ -129,3 +130,20 @@ KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict) } return NULL; /* it just isn't in here */ } + +gboolean tree_chroot(KeyBindingTree *tree, GList *keylist) +{ + guint key, state; + if (translate_key(keylist->data, &state, &key)) { + while (tree != NULL && !(tree->state == state && tree->key == key)) + tree = tree->next_sibling; + if (tree != NULL) { + if (keylist->next == NULL) { + tree->chroot = TRUE; + return TRUE; + } else + return tree_chroot(tree->first_child, keylist->next); + } + } + return FALSE; +} diff --git a/openbox/keytree.h b/openbox/keytree.h index c3be0659..d3544f80 100644 --- a/openbox/keytree.h +++ b/openbox/keytree.h @@ -28,7 +28,10 @@ typedef struct KeyBindingTree { guint key; GList *keylist; GSList *actions; /* list of Action pointers */ + gboolean chroot; + /* the level up in the tree */ + struct KeyBindingTree *parent; /* the next binding in the tree at the same level */ struct KeyBindingTree *next_sibling; /* the first child of this binding (next binding in a chained sequence).*/ @@ -39,5 +42,7 @@ void tree_destroy(KeyBindingTree *tree); KeyBindingTree *tree_build(GList *keylist); void tree_assimilate(KeyBindingTree *node); KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict); +gboolean tree_chroot(KeyBindingTree *tree, GList *keylist); + #endif diff --git a/openbox/menu.c b/openbox/menu.c index 7197868b..9aed40aa 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -360,7 +360,7 @@ void menu_free(ObMenu *menu) g_hash_table_remove(menu_hash, menu->name); } -void menu_show(gchar *name, gint x, gint y, ObClient *client) +void menu_show(gchar *name, gint x, gint y, gint button, ObClient *client) { ObMenu *self; ObMenuFrame *frame; @@ -379,7 +379,7 @@ void menu_show(gchar *name, gint x, gint y, ObClient *client) menu_frame_hide_all(); frame = menu_frame_new(self, client); - if (!menu_frame_show_topmenu(frame, x, y)) + if (!menu_frame_show_topmenu(frame, x, y, button)) menu_frame_free(frame); else if (frame->entries) { ObMenuEntryFrame *e = frame->entries->data; @@ -515,6 +515,11 @@ void menu_set_destroy_func(ObMenu *self, ObMenuDestroyFunc func) self->destroy_func = func; } +void menu_set_place_func(ObMenu *self, ObMenuPlaceFunc func) +{ + self->place_func = func; +} + ObMenuEntry* menu_find_entry_id(ObMenu *self, gint id) { ObMenuEntry *ret = NULL; diff --git a/openbox/menu.h b/openbox/menu.h index 2315351a..fc859a8b 100644 --- a/openbox/menu.h +++ b/openbox/menu.h @@ -41,6 +41,13 @@ typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data); typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry, guint state, gpointer data, Time time); typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data); +/*! @param x is the mouse x coordinate. on return it should be the x coordinate + for the menu + @param y is the mouse y coordinate. on return it should be the y coordinate + for the menu +*/ +typedef void (*ObMenuPlaceFunc)(struct _ObMenuFrame *frame, gint *x, gint *y, + gint button, gpointer data); struct _ObMenu { @@ -70,6 +77,7 @@ struct _ObMenu ObMenuUpdateFunc update_func; ObMenuExecuteFunc execute_func; ObMenuDestroyFunc destroy_func; + ObMenuPlaceFunc place_func; /* Pipe-menu parent, we get destroyed when it is destroyed */ ObMenu *pipe_creator; @@ -144,11 +152,13 @@ void menu_pipe_execute(ObMenu *self); void menu_show_all_shortcuts(ObMenu *self, gboolean show); -void menu_show(gchar *name, gint x, gint y, struct _ObClient *client); +void menu_show(gchar *name, gint x, gint y, gint button, + struct _ObClient *client); void menu_set_update_func(ObMenu *menu, ObMenuUpdateFunc func); void menu_set_execute_func(ObMenu *menu, ObMenuExecuteFunc func); void menu_set_destroy_func(ObMenu *menu, ObMenuDestroyFunc func); +void menu_set_place_func(ObMenu *menu, ObMenuPlaceFunc func); /* functions for building menus */ /*! @param allow_shortcut this should be false when the label is coming from diff --git a/openbox/menuframe.c b/openbox/menuframe.c index 7ca2136c..25131435 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -209,21 +209,69 @@ void menu_frame_move(ObMenuFrame *self, gint x, gint y) XMoveWindow(ob_display, self->window, self->area.x, self->area.y); } -void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y) +static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y) { - if (self->client && x < 0 && y < 0) { - x = self->client->frame->area.x + self->client->frame->size.left; - y = self->client->frame->area.y + self->client->frame->size.top; + gint dx, dy; + + if (config_menu_middle) { + gint myx; + + myx = *x; + *y -= self->area.height / 2; + + /* try to the right of the cursor */ + menu_frame_move_on_screen(self, myx, *y, &dx, &dy); + 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); + } + 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); + } + *x = myx + dx; + *y += dy; } else { - if (config_menu_middle) - y -= self->area.height / 2; + gint myx, myy; + + myx = *x; + myy = *y; + + /* try to the bottom right of the cursor */ + menu_frame_move_on_screen(self, myx, *y, &dx, &dy); + 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, *y, &dx, &dy); + } + 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, *y, &dx, &dy); + } + 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, *y, &dx, &dy); + } + 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, *y, &dx, &dy); + } + *x = myx + dx; + *y = myy + dy; } - menu_frame_move(self, x, y); } -void menu_frame_place_submenu(ObMenuFrame *self) +static void menu_frame_place_submenu(ObMenuFrame *self, gint *x, gint *y) { - gint x, y; gint overlap; gint bwidth; @@ -231,20 +279,20 @@ void menu_frame_place_submenu(ObMenuFrame *self) bwidth = ob_rr_theme->mbwidth; if (self->direction_right) - x = self->parent->area.x + self->parent->area.width - overlap - bwidth; + *x = self->parent->area.x + self->parent->area.width - + overlap - bwidth; else - x = self->parent->area.x - self->area.width + overlap + bwidth; + *x = self->parent->area.x - self->area.width + overlap + bwidth; - y = self->parent->area.y + self->parent_entry->area.y; + *y = self->parent->area.y + self->parent_entry->area.y; if (config_menu_middle) - y -= (self->area.height - (bwidth * 2) - self->item_h) / 2; + *y -= (self->area.height - (bwidth * 2) - self->item_h) / 2; else - y += overlap; - - menu_frame_move(self, x, y); + *y += overlap; } -void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy) +void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, + gint *dx, gint *dy) { Rect *a = NULL; gint pos, half; @@ -259,16 +307,16 @@ void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy) /* if in the bottom half then check this stuff first, will keep the bottom edge of the menu visible */ if (pos > half) { - *dx = MAX(*dx, a->x - self->area.x); - *dy = MAX(*dy, a->y - self->area.y); + *dx = MAX(*dx, a->x - x); + *dy = MAX(*dy, a->y - y); } - *dx = MIN(*dx, (a->x + a->width) - (self->area.x + self->area.width)); - *dy = MIN(*dy, (a->y + a->height) - (self->area.y + self->area.height)); + *dx = MIN(*dx, (a->x + a->width) - (x + self->area.width)); + *dy = MIN(*dy, (a->y + a->height) - (y + self->area.height)); /* if in the top half then check this stuff last, will keep the top edge of the menu visible */ if (pos <= half) { - *dx = MAX(*dx, a->x - self->area.x); - *dy = MAX(*dy, a->y - self->area.y); + *dx = MAX(*dx, a->x - x); + *dy = MAX(*dy, a->y - y); } } @@ -723,9 +771,9 @@ static gboolean menu_frame_show(ObMenuFrame *self) return TRUE; } -gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y) +gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, + gint button) { - gint dx, dy; guint i; if (menu_frame_is_visible(self)) @@ -733,8 +781,6 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y) if (!menu_frame_show(self)) return FALSE; - menu_frame_place_topmenu(self, x, y); - /* find the monitor the menu is on */ for (i = 0; i < screen_num_monitors; ++i) { Rect *a = screen_physical_area_monitor(i); @@ -744,8 +790,12 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y) } } - menu_frame_move_on_screen(self, &dx, &dy); - menu_frame_move(self, self->area.x + dx, self->area.y + dy); + if (self->menu->place_func) + self->menu->place_func(self, &x, &y, button, self->menu->data); + else + menu_frame_place_topmenu(self, &x, &y); + + menu_frame_move(self, x, y); XMapWindow(ob_display, self->window); @@ -756,7 +806,7 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, ObMenuEntryFrame *parent_entry) { ObMenuEntryFrame *e; - gint dx, dy; + gint x, y, dx, dy; if (menu_frame_is_visible(self)) return TRUE; @@ -773,29 +823,16 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, if (!menu_frame_show(self)) return FALSE; - menu_frame_place_submenu(self); - menu_frame_move_on_screen(self, &dx, &dy); - - if (dx == 0) { - menu_frame_move(self, self->area.x, self->area.y + dy); - } else { - gboolean dir; + menu_frame_place_submenu(self, &x, &y); + menu_frame_move_on_screen(self, x, y, &dx, &dy); - /* flip the direction in which we're placing submenus */ - if (dx > 0) - dir = TRUE; - else - dir = FALSE; - - /* if it changed, then replace the menu on the opposite side, - and try keep it on the screen too */ - if (dir != self->direction_right) { - self->direction_right = dir; - menu_frame_place_submenu(self); - menu_frame_move_on_screen(self, &dx, &dy); - menu_frame_move(self, self->area.x + dx, self->area.y + dy); - } + if (dx != 0) { + /*try the other side */ + self->direction_right = !self->direction_right; + menu_frame_place_submenu(self, &x, &y); + menu_frame_move_on_screen(self, x, y, &dx, &dy); } + menu_frame_move(self, x + dx, y + dy); XMapWindow(ob_display, self->window); diff --git a/openbox/menuframe.h b/openbox/menuframe.h index 4cd27d37..5c876832 100644 --- a/openbox/menuframe.h +++ b/openbox/menuframe.h @@ -111,12 +111,11 @@ ObMenuFrame* menu_frame_new(struct _ObMenu *menu, struct _ObClient *client); void menu_frame_free(ObMenuFrame *self); void menu_frame_move(ObMenuFrame *self, gint x, gint y); -void menu_frame_move_on_screen(ObMenuFrame *self, gint *dx, gint *dy); +void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, + gint *dx, gint *dy); -void menu_frame_place_topmenu(ObMenuFrame *self, gint x, gint y); -void menu_frame_place_submenu(ObMenuFrame *self); - -gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y); +gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, + gint button); gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, ObMenuEntryFrame *parent_entry); void menu_frame_hide(ObMenuFrame *self); diff --git a/render/font.c b/render/font.c index 8692a9d1..50b4208f 100644 --- a/render/font.c +++ b/render/font.c @@ -252,19 +252,17 @@ void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area) if (t->shortcut) { const gchar *c = t->string + t->shortcut_pos; - if (g_utf8_validate(c, -1, NULL)) { - t->font->shortcut_underline->start_index = t->shortcut_pos; - t->font->shortcut_underline->end_index = t->shortcut_pos + - (g_utf8_next_char(c) - c); - - /* the attributes are owned by the layout. - re-add the attributes to the layout after changing the - start and end index */ - attrlist = pango_layout_get_attributes(t->font->layout); - pango_attr_list_ref(attrlist); - pango_layout_set_attributes(t->font->layout, attrlist); - pango_attr_list_unref(attrlist); - } + t->font->shortcut_underline->start_index = t->shortcut_pos; + t->font->shortcut_underline->end_index = t->shortcut_pos + + (g_utf8_next_char(c) - c); + + /* the attributes are owned by the layout. + re-add the attributes to the layout after changing the + start and end index */ + attrlist = pango_layout_get_attributes(t->font->layout); + pango_attr_list_ref(attrlist); + pango_layout_set_attributes(t->font->layout, attrlist); + pango_attr_list_unref(attrlist); } /* layout_line() uses y to specify the baseline