X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fmenuframe.c;h=3252bb3c76a2ae115e55728000eaaed5c01ffd5c;hb=HEAD;hp=b235f5eb459d93c5bef80d4d5a53abc22cb99215;hpb=3bd4397b6ec5212bfe53a36892746962dc45dbeb;p=chaz%2Fopenbox diff --git a/openbox/menuframe.c b/openbox/menuframe.c index b235f5eb..3252bb3c 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -27,6 +27,7 @@ #include "openbox.h" #include "config.h" #include "obt/prop.h" +#include "obt/keyboard.h" #include "obrender/theme.h" #define PADDING 2 @@ -37,12 +38,15 @@ #define FRAME_EVENTMASK (ButtonPressMask |ButtonMotionMask | EnterWindowMask |\ LeaveWindowMask) #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \ - ButtonPressMask | ButtonReleaseMask) + ButtonPressMask | ButtonReleaseMask | \ + PointerMotionMask) GList *menu_frame_visible; GHashTable *menu_frame_map; static RrAppearance *a_sep; +static guint submenu_show_timer = 0; +static guint submenu_hide_timer = 0; static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, ObMenuFrame *frame); @@ -61,6 +65,19 @@ static Window createWindow(Window parent, gulong mask, RrVisual(ob_rr_inst), mask, attrib); } +static void client_dest(ObClient *client, gpointer data) +{ + GList *it; + + /* menus can be associated with a client, so null those refs since + we are disappearing now */ + for (it = menu_frame_visible; it; it = g_list_next(it)) { + ObMenuFrame *f = it->data; + if (f->client == client) + f->client = NULL; + } +} + void menu_frame_startup(gboolean reconfig) { gint i; @@ -75,6 +92,7 @@ void menu_frame_startup(gboolean reconfig) if (reconfig) return; + client_add_destroy_notify(client_dest, NULL); menu_frame_map = g_hash_table_new(g_int_hash, g_int_equal); } @@ -84,6 +102,7 @@ void menu_frame_shutdown(gboolean reconfig) if (reconfig) return; + client_remove_destroy_notify(client_dest); g_hash_table_destroy(menu_frame_map); } @@ -92,7 +111,7 @@ ObMenuFrame* menu_frame_new(ObMenu *menu, guint show_from, ObClient *client) ObMenuFrame *self; XSetWindowAttributes attr; - self = g_new0(ObMenuFrame, 1); + self = g_slice_new0(ObMenuFrame); self->obwin.type = OB_WINDOW_CLASS_MENUFRAME; self->menu = menu; self->selected = NULL; @@ -135,17 +154,24 @@ void menu_frame_free(ObMenuFrame *self) XDestroyWindow(obt_display, self->window); - g_free(self); + g_slice_free(ObMenuFrame, self); } } +ObtIC* menu_frame_ic(ObMenuFrame *self) +{ + /* menus are always used through a grab right now, so they can always use + the grab input context */ + return grab_input_context(); +} + static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, ObMenuFrame *frame) { ObMenuEntryFrame *self; XSetWindowAttributes attr; - self = g_new0(ObMenuEntryFrame, 1); + self = g_slice_new0(ObMenuEntryFrame); self->entry = entry; self->frame = frame; @@ -156,7 +182,8 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, self->text = createWindow(self->window, 0, NULL); g_hash_table_insert(menu_frame_map, &self->window, self); g_hash_table_insert(menu_frame_map, &self->text, self); - if (entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { + if ((entry->type == OB_MENU_ENTRY_TYPE_NORMAL) || + (entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) { self->icon = createWindow(self->window, 0, NULL); g_hash_table_insert(menu_frame_map, &self->icon, self); } @@ -184,7 +211,8 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) XDestroyWindow(obt_display, self->window); g_hash_table_remove(menu_frame_map, &self->text); g_hash_table_remove(menu_frame_map, &self->window); - if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) { + if ((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) || + (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) { XDestroyWindow(obt_display, self->icon); g_hash_table_remove(menu_frame_map, &self->icon); } @@ -193,7 +221,7 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) g_hash_table_remove(menu_frame_map, &self->bullet); } - g_free(self); + g_slice_free(ObMenuEntryFrame, self); } } @@ -298,12 +326,19 @@ static void menu_frame_place_submenu(ObMenuFrame *self, gint *x, gint *y) void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, gint *dx, gint *dy) { - Rect *a = NULL; - gint pos, half; + const Rect *a = NULL; + Rect search = self->area; + gint pos, half, monitor; *dx = *dy = 0; + RECT_SET_POINT(search, x, y); - a = screen_physical_area_monitor(screen_find_monitor_point(x, y)); + if (self->parent) + monitor = self->parent->monitor; + else + monitor = screen_find_monitor(&search); + + a = screen_physical_area_monitor(monitor); half = g_list_length(self->entries) / 2; pos = g_list_index(self->entries, self->selected); @@ -322,8 +357,6 @@ void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, *dx = MAX(*dx, a->x - x); *dy = MAX(*dy, a->y - y); } - - g_free(a); } static void menu_entry_frame_render(ObMenuEntryFrame *self) @@ -492,7 +525,8 @@ static void menu_entry_frame_render(ObMenuEntryFrame *self) g_assert_not_reached(); } - if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && + if (((self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL) || + (self->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)) && self->entry->data.normal.icon) { RrAppearance *clear; @@ -810,7 +844,7 @@ void menu_frame_render(ObMenuFrame *self) static void menu_frame_update(ObMenuFrame *self) { GList *mit, *fit; - Rect *a; + const Rect *a; gint h; menu_pipe_execute(self->menu); @@ -908,8 +942,6 @@ static void menu_frame_update(ObMenuFrame *self) } } - g_free(a); - menu_frame_render(self); } @@ -990,8 +1022,8 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, */ static void remove_submenu_hide_timeout(ObMenuFrame *child) { - obt_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout, - child, FALSE); + if (submenu_hide_timer) g_source_remove(submenu_hide_timer); + submenu_hide_timer = 0; } gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, @@ -1015,8 +1047,11 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, parent->child_entry = parent_entry; } - if (!menu_frame_show(self)) + if (!menu_frame_show(self)) { + parent->child = NULL; + parent->child_entry = NULL; return FALSE; + } menu_frame_place_submenu(self, &x, &y); menu_frame_move_on_screen(self, x, y, &dx, &dy); @@ -1042,14 +1077,15 @@ gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, static void menu_frame_hide(ObMenuFrame *self) { + ObMenu *const menu = self->menu; GList *it = g_list_find(menu_frame_visible, self); gulong ignore_start; if (!it) return; - if (self->menu->hide_func) - self->menu->hide_func(self, self->menu->data); + if (menu->hide_func) + menu->hide_func(self, menu->data); if (self->child) menu_frame_hide(self->child); @@ -1076,6 +1112,9 @@ static void menu_frame_hide(ObMenuFrame *self) event_end_ignore_all_enters(ignore_start); menu_frame_free(self); + + if (menu->cleanup_func) + menu->cleanup_func(menu, menu->data); } void menu_frame_hide_all(void) @@ -1084,28 +1123,13 @@ void menu_frame_hide_all(void) if (config_submenu_show_delay) { /* remove any submenu open requests */ - obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout); + if (submenu_show_timer) g_source_remove(submenu_show_timer); + submenu_show_timer = 0; } if ((it = g_list_last(menu_frame_visible))) menu_frame_hide(it->data); } -void menu_frame_hide_all_client(ObClient *client) -{ - GList *it = g_list_last(menu_frame_visible); - if (it) { - ObMenuFrame *f = it->data; - if (f->client == client) { - if (config_submenu_show_delay) { - /* remove any submenu open requests */ - obt_main_loop_timeout_remove(ob_main_loop, - submenu_show_timeout); - } - menu_frame_hide(f); - } - } -} - ObMenuFrame* menu_frame_under(gint x, gint y) { ObMenuFrame *ret = NULL; @@ -1181,7 +1205,8 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, if (config_submenu_show_delay) { /* remove any submenu open requests */ - obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout); + if (submenu_show_timer) g_source_remove(submenu_show_timer); + submenu_show_timer = 0; } self->selected = entry; @@ -1201,12 +1226,13 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, submenu */ if (immediate || config_submenu_hide_delay == 0) menu_frame_hide(oldchild); - else if (config_submenu_hide_delay > 0) - obt_main_loop_timeout_add(ob_main_loop, - config_submenu_hide_delay * 1000, - submenu_hide_timeout, - oldchild, g_direct_equal, - NULL); + else if (config_submenu_hide_delay > 0) { + if (submenu_hide_timer) g_source_remove(submenu_hide_timer); + submenu_hide_timer = + g_timeout_add_full(G_PRIORITY_DEFAULT, + config_submenu_hide_delay, + submenu_hide_timeout, oldchild, NULL); + } } } @@ -1216,14 +1242,17 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, if (self->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) { /* only show if the submenu isn't already showing */ if (oldchild_entry != self->selected) { - if (immediate || config_submenu_hide_delay == 0) + if (immediate || config_submenu_show_delay == 0) menu_entry_frame_show_submenu(self->selected); - else if (config_submenu_hide_delay > 0) - obt_main_loop_timeout_add(ob_main_loop, - config_submenu_show_delay * 1000, - submenu_show_timeout, - self->selected, g_direct_equal, - NULL); + else if (config_submenu_show_delay > 0) { + if (submenu_show_timer) + g_source_remove(submenu_show_timer); + submenu_show_timer = + g_timeout_add_full(G_PRIORITY_DEFAULT, + config_submenu_show_delay, + submenu_show_timeout, + self->selected, NULL); + } } /* hide the grandchildren of this menu. and move the cursor to the current menu */ @@ -1247,7 +1276,8 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self) /* pass our direction on to our child */ f->direction_right = self->frame->direction_right; - menu_frame_show_submenu(f, self->frame, self); + if (!menu_frame_show_submenu(f, self->frame, self)) + menu_frame_free(f); } void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state) @@ -1263,10 +1293,11 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state) GSList *acts = self->entry->data.normal.actions; ObClient *client = self->frame->client; ObMenuFrame *frame = self->frame; + guint mods = obt_keyboard_only_modmasks(state); /* release grabs before executing the shit */ - if (!(state & ControlMask)) { - menu_frame_hide_all(); + if (!(mods & ControlMask)) { + event_cancel_all_key_grabs(); frame = NULL; }