#include "openbox.h"
#include "config.h"
#include "obt/prop.h"
+#include "obt/keyboard.h"
#include "obrender/theme.h"
#define PADDING 2
#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);
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;
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;
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);
}
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);
}
g_hash_table_remove(menu_frame_map, &self->bullet);
}
- g_free(self);
+ g_slice_free(ObMenuEntryFrame, self);
}
}
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);
*dx = MAX(*dx, a->x - x);
*dy = MAX(*dy, a->y - y);
}
-
- g_free(a);
}
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;
static void menu_frame_update(ObMenuFrame *self)
{
GList *mit, *fit;
- Rect *a;
+ const Rect *a;
gint h;
menu_pipe_execute(self->menu);
}
}
- g_free(a);
-
menu_frame_render(self);
}
*/
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,
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);
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);
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)
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);
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;
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);
+ }
}
}
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 */
/* 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)
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)) {
+ if (!(mods & ControlMask)) {
event_cancel_all_key_grabs();
frame = NULL;
}