raise menus above clients.

hilight menu entries as the cursor passes over them.
This commit is contained in:
Dana Jansens 2003-04-16 05:36:51 +00:00
parent 59c3cce4f4
commit 79a352a40b
7 changed files with 207 additions and 105 deletions

View file

@ -5,6 +5,7 @@
#include "config.h" #include "config.h"
#include "screen.h" #include "screen.h"
#include "frame.h" #include "frame.h"
#include "menu.h"
#include "framerender.h" #include "framerender.h"
#include "focus.h" #include "focus.h"
#include "stacking.h" #include "stacking.h"
@ -22,6 +23,7 @@
static void event_process(XEvent *e); static void event_process(XEvent *e);
static void event_handle_root(XEvent *e); static void event_handle_root(XEvent *e);
static void event_handle_client(Client *c, XEvent *e); static void event_handle_client(Client *c, XEvent *e);
static void event_handle_menu(Menu *menu, XEvent *e);
Time event_lasttime = 0; Time event_lasttime = 0;
@ -310,16 +312,20 @@ static void event_process(XEvent *e)
{ {
Window window; Window window;
Client *client; Client *client;
Menu *menu = NULL;
window = event_get_window(e); window = event_get_window(e);
client = g_hash_table_lookup(client_map, &window); if (!(client = g_hash_table_lookup(client_map, &window)))
menu = g_hash_table_lookup(menu_map, &window);
event_set_lasttime(e); event_set_lasttime(e);
event_hack_mods(e); event_hack_mods(e);
if (event_ignore(e, client)) if (event_ignore(e, client))
return; return;
/* deal with it in the kernel */ /* deal with it in the kernel */
if (client) if (menu)
event_handle_menu(menu, e);
else if (client)
event_handle_client(client, e); event_handle_client(client, e);
else if (window == ob_root) else if (window == ob_root)
event_handle_root(e); event_handle_root(e);
@ -700,3 +706,20 @@ static void event_handle_client(Client *client, XEvent *e)
#endif #endif
} }
} }
static void event_handle_menu(Menu *menu, XEvent *e)
{
MenuEntry *entry;
switch (e->type) {
case EnterNotify:
case LeaveNotify:
g_message("enter/leave");
entry = menu_find_entry(menu, e->xcrossing.window);
if (entry) {
entry->hilite = e->type == EnterNotify;
menu_entry_render(entry);
}
break;
}
}

View file

@ -9,6 +9,7 @@
#include "dispatch.h" #include "dispatch.h"
#include "focus.h" #include "focus.h"
#include "parse.h" #include "parse.h"
#include "stacking.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <glib.h> #include <glib.h>
@ -35,7 +36,8 @@ void focus_startup()
-100, -100, 1, 1, 0, -100, -100, 1, 1, 0,
CopyFromParent, InputOutput, CopyFromParent, CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect, &attrib); CWOverrideRedirect, &attrib);
XMapRaised(ob_display, focus_backup); XMapWindow(ob_display, focus_backup);
stacking_raise_internal(focus_backup);
/* start with nothing focused */ /* start with nothing focused */
focus_set_client(NULL); focus_set_client(NULL);

View file

@ -1,11 +1,12 @@
#include "menu.h" #include "menu.h"
#include "openbox.h" #include "openbox.h"
#include "stacking.h"
#include "render/theme.h" #include "render/theme.h"
static GHashTable *menu_hash = NULL; static GHashTable *menu_hash = NULL;
GHashTable *menu_map = NULL; GHashTable *menu_map = NULL;
#define TITLE_EVENTMASK (ButtonMotionMask) #define TITLE_EVENTMASK (ButtonPressMask | ButtonMotionMask)
#define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \ #define ENTRY_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
ButtonPressMask | ButtonReleaseMask) ButtonPressMask | ButtonReleaseMask)
@ -17,7 +18,6 @@ void menu_destroy_hash_key(gpointer data)
void menu_destroy_hash_value(Menu *self) void menu_destroy_hash_value(Menu *self)
{ {
GList *it; GList *it;
MenuRenderData *data = self->render_data;
for (it = self->entries; it; it = it->next) for (it = self->entries; it; it = it->next)
menu_entry_free(it->data); menu_entry_free(it->data);
@ -26,30 +26,29 @@ void menu_destroy_hash_value(Menu *self)
g_free(self->label); g_free(self->label);
g_free(self->name); g_free(self->name);
g_hash_table_remove(menu_map, &data->title); g_hash_table_remove(menu_map, &self->title);
g_hash_table_remove(menu_map, &data->frame); g_hash_table_remove(menu_map, &self->frame);
g_hash_table_remove(menu_map, &data->items); g_hash_table_remove(menu_map, &self->items);
appearance_free(data->a_title); appearance_free(self->a_title);
XDestroyWindow(ob_display, data->title); XDestroyWindow(ob_display, self->title);
XDestroyWindow(ob_display, data->frame); XDestroyWindow(ob_display, self->frame);
XDestroyWindow(ob_display, data->items); XDestroyWindow(ob_display, self->items);
g_free(self); g_free(self);
} }
void menu_entry_free(MenuEntry *self) void menu_entry_free(MenuEntry *self)
{ {
MenuEntryRenderData *data = self->render_data;
g_free(self->label); g_free(self->label);
g_free(self->render_data);
action_free(self->action); action_free(self->action);
g_hash_table_remove(menu_map, &data->item); g_hash_table_remove(menu_map, &self->item);
appearance_free(data->a_item); appearance_free(self->a_item);
XDestroyWindow(ob_display, data->item); appearance_free(self->a_disabled);
appearance_free(self->a_hilite);
XDestroyWindow(ob_display, self->item);
g_free(self); g_free(self);
} }
@ -93,7 +92,6 @@ Menu *menu_new(char *label, char *name, Menu *parent)
{ {
XSetWindowAttributes attrib; XSetWindowAttributes attrib;
Menu *self; Menu *self;
MenuRenderData *data;
self = g_new0(Menu, 1); self = g_new0(Menu, 1);
self->label = g_strdup(label); self->label = g_strdup(label);
@ -105,30 +103,26 @@ Menu *menu_new(char *label, char *name, Menu *parent)
self->invalid = FALSE; self->invalid = FALSE;
/* default controllers? */ /* default controllers? */
data = g_new(MenuRenderData, 1);
attrib.override_redirect = TRUE; attrib.override_redirect = TRUE;
data->frame = createWindow(ob_root, CWOverrideRedirect, &attrib); self->frame = createWindow(ob_root, CWOverrideRedirect, &attrib);
attrib.event_mask = TITLE_EVENTMASK; attrib.event_mask = TITLE_EVENTMASK;
data->title = createWindow(data->frame, CWEventMask, &attrib); self->title = createWindow(self->frame, CWEventMask, &attrib);
data->items = createWindow(data->frame, 0, &attrib); self->items = createWindow(self->frame, 0, &attrib);
XSetWindowBorderWidth(ob_display, data->frame, theme_bwidth); XSetWindowBorderWidth(ob_display, self->frame, theme_bwidth);
XSetWindowBorderWidth(ob_display, data->title, theme_bwidth); XSetWindowBorderWidth(ob_display, self->title, theme_bwidth);
XSetWindowBorder(ob_display, data->frame, theme_b_color->pixel); XSetWindowBorder(ob_display, self->frame, theme_b_color->pixel);
XSetWindowBorder(ob_display, data->title, theme_b_color->pixel); XSetWindowBorder(ob_display, self->title, theme_b_color->pixel);
XMapWindow(ob_display, data->title); XMapWindow(ob_display, self->title);
XMapWindow(ob_display, data->items); XMapWindow(ob_display, self->items);
data->a_title = appearance_copy(theme_a_menu_title); self->a_title = appearance_copy(theme_a_menu_title);
data->a_items = appearance_copy(theme_a_menu); self->a_items = appearance_copy(theme_a_menu);
self->render_data = data; g_hash_table_insert(menu_map, &self->frame, self);
g_hash_table_insert(menu_map, &self->title, self);
g_hash_table_insert(menu_map, &data->frame, self); g_hash_table_insert(menu_map, &self->items, self);
g_hash_table_insert(menu_map, &data->title, self);
g_hash_table_insert(menu_map, &data->items, self);
g_hash_table_insert(menu_hash, g_strdup(name), self); g_hash_table_insert(menu_hash, g_strdup(name), self);
return self; return self;
} }
@ -142,13 +136,15 @@ MenuEntry *menu_entry_new_full(char *label, Action *action,
MenuEntryRenderType render_type, MenuEntryRenderType render_type,
gpointer submenu) gpointer submenu)
{ {
MenuEntry *menu_entry = g_new(MenuEntry, 1); MenuEntry *menu_entry = g_new0(MenuEntry, 1);
menu_entry->label = g_strdup(label); menu_entry->label = g_strdup(label);
menu_entry->render_type = render_type; menu_entry->render_type = render_type;
menu_entry->action = action; menu_entry->action = action;
menu_entry->render_data = NULL; menu_entry->hilite = FALSE;
menu_entry->enabled = TRUE;
menu_entry->submenu = submenu; menu_entry->submenu = submenu;
return menu_entry; return menu_entry;
@ -166,37 +162,32 @@ void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu)
void menu_add_entry(Menu *menu, MenuEntry *entry) void menu_add_entry(Menu *menu, MenuEntry *entry)
{ {
MenuEntryRenderData *data;
XSetWindowAttributes attrib; XSetWindowAttributes attrib;
g_assert(menu != NULL && entry != NULL && entry->render_data == NULL); g_assert(menu != NULL && entry != NULL && entry->item == None);
menu->entries = g_list_append(menu->entries, entry); menu->entries = g_list_append(menu->entries, entry);
entry->parent = menu; entry->parent = menu;
data = g_new(MenuEntryRenderData, 1); attrib.event_mask = ENTRY_EVENTMASK;
data->item = createWindow(((MenuRenderData*)menu->render_data)->items, entry->item = createWindow(menu->items, CWEventMask, &attrib);
0, &attrib); XMapWindow(ob_display, entry->item);
XMapWindow(ob_display, data->item); entry->a_item = appearance_copy(theme_a_menu_item);
data->a_item = appearance_copy(theme_a_menu_item); entry->a_disabled = appearance_copy(theme_a_menu_disabled);
entry->a_hilite = appearance_copy(theme_a_menu_hilite);
entry->render_data = data;
menu->invalid = TRUE; menu->invalid = TRUE;
g_hash_table_insert(menu_map, &data->item, menu); g_hash_table_insert(menu_map, &entry->item, menu);
} }
void menu_show(char *name, int x, int y, Client *client) void menu_show(char *name, int x, int y, Client *client)
{ {
Menu *self; Menu *self;
MenuRenderData *data;
GList *it; GList *it;
int w = 1;
int items_h; int items_h;
int item_h = 0, nitems = 0; /* each item, only one is used */ int nitems = 0; /* each item, only one is used */
int item_y; int item_y;
int bullet_w;
self = g_hash_table_lookup(menu_hash, name); self = g_hash_table_lookup(menu_hash, name);
if (!self) { if (!self) {
@ -205,58 +196,99 @@ void menu_show(char *name, int x, int y, Client *client)
return; return;
} }
data = self->render_data; self->width = 1;
self->item_h = 0;
/* set texture data and size them mofos out */ /* set texture data and size them mofos out */
data->a_title->texture[0].data.text.string = self->label; self->a_title->texture[0].data.text.string = self->label;
appearance_minsize(data->a_title, &data->title_min_w, &data->title_h); appearance_minsize(self->a_title, &self->title_min_w, &self->title_h);
data->title_min_w += theme_bevel * 2; self->title_min_w += theme_bevel * 2;
data->title_h += theme_bevel * 2; self->title_h += theme_bevel * 2;
w = MAX(w, data->title_min_w); self->width = MAX(self->width, self->title_min_w);
for (it = self->entries; it; it = it->next) { for (it = self->entries; it; it = it->next) {
MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data; MenuEntry *e = it->data;
int h;
r->a_item->texture[0].data.text.string = ((MenuEntry*)it->data)->label; e->a_item->texture[0].data.text.string = e->label;
appearance_minsize(r->a_item, &r->min_w, &item_h); appearance_minsize(e->a_item, &e->min_w, &self->item_h);
r->min_w += theme_bevel * 2; self->width = MAX(self->width, e->min_w);
item_h += theme_bevel * 2;
w = MAX(w, r->min_w); e->a_disabled->texture[0].data.text.string = e->label;
appearance_minsize(e->a_disabled, &e->min_w, &h);
self->item_h = MAX(self->item_h, h);
self->width = MAX(self->width, e->min_w);
e->a_hilite->texture[0].data.text.string = e->label;
appearance_minsize(e->a_hilite, &e->min_w, &h);
self->item_h = MAX(self->item_h, h);
self->width = MAX(self->width, e->min_w);
e->min_w += theme_bevel * 2;
++nitems; ++nitems;
} }
bullet_w = item_h + theme_bevel; self->bullet_w = self->item_h + theme_bevel;
w += 2 * bullet_w; self->width += 2 * self->bullet_w;
items_h = item_h * nitems; self->item_h += theme_bevel * 2;
items_h = self->item_h * nitems;
/* size appearances */ RECT_SET(self->a_title->area, 0, 0, self->width, self->title_h);
RECT_SET(data->a_title->area, 0, 0, w, data->title_h); RECT_SET(self->a_title->texture[0].position, 0, 0, self->width,
RECT_SET(data->a_title->texture[0].position, 0, 0, w, data->title_h); self->title_h);
RECT_SET(data->a_items->area, 0, 0, w, items_h); RECT_SET(self->a_items->area, 0, 0, self->width, items_h);
XMoveResizeWindow(ob_display, self->frame, x, y, self->width,
self->title_h + items_h);
XMoveResizeWindow(ob_display, self->title, -theme_bwidth, -theme_bwidth,
self->width, self->title_h);
XMoveResizeWindow(ob_display, self->items, 0, self->title_h + theme_bwidth,
self->width, items_h);
paint(self->title, self->a_title);
paint(self->items, self->a_items);
item_y = 0;
for (it = self->entries; it; it = it->next) { for (it = self->entries; it; it = it->next) {
MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data; ((MenuEntry*)it->data)->y = item_y;
RECT_SET(r->a_item->area, 0, 0, w, item_h); menu_entry_render(it->data);
RECT_SET(r->a_item->texture[0].position, bullet_w, 0, item_y += self->item_h;
w - 2 * bullet_w, item_h);
} }
/* size windows and paint the suckers */ stacking_raise_internal(self->frame);
XMoveResizeWindow(ob_display, data->frame, x, y, w, XMapWindow(ob_display, self->frame);
data->title_h + items_h); }
XMoveResizeWindow(ob_display, data->title, -theme_bwidth, -theme_bwidth,
w, data->title_h); MenuEntry *menu_find_entry(Menu *menu, Window win)
paint(data->title, data->a_title); {
XMoveResizeWindow(ob_display, data->items, 0, data->title_h + theme_bwidth, GList *it;
w, items_h);
paint(data->items, data->a_items); for (it = menu->entries; it; it = it->next) {
for (item_y = 0, it = self->entries; it; item_y += item_h, it = it->next) { MenuEntry *entry = it->data;
MenuEntryRenderData *r = ((MenuEntry*)it->data)->render_data; if (entry->item == win)
XMoveResizeWindow(ob_display, r->item, 0, item_y, w, item_h); return entry;
r->a_item->surface.data.planar.parent = data->a_items; }
r->a_item->surface.data.planar.parentx = 0; return NULL;
r->a_item->surface.data.planar.parenty = item_y; }
paint(r->item, r->a_item);
} void menu_entry_render(MenuEntry *self)
{
Menu *menu = self->parent;
XMapWindow(ob_display, data->frame); Appearance *a;
a = !self->enabled ? self->a_disabled :
(self->hilite ? self->a_hilite : self->a_item);
RECT_SET(a->area, 0, 0, menu->width,
menu->item_h);
RECT_SET(a->texture[0].position, menu->bullet_w,
0, menu->width - 2 * menu->bullet_w,
menu->item_h);
XMoveResizeWindow(ob_display, self->item, 0, self->y,
menu->width, menu->item_h);
a->surface.data.planar.parent = menu->a_items;
a->surface.data.planar.parentx = 0;
a->surface.data.planar.parenty = self->y;
paint(self->item, a);
} }

View file

@ -18,7 +18,6 @@ typedef struct Menu {
/* ? */ /* ? */
gboolean shown; gboolean shown;
gboolean invalid; gboolean invalid;
gpointer render_data; /* where the engine can store anything it likes */
struct Menu *parent; struct Menu *parent;
@ -28,17 +27,19 @@ typedef struct Menu {
void (*update)( /* some bummu */); void (*update)( /* some bummu */);
void (*mouseover)( /* some bummu */); void (*mouseover)( /* some bummu */);
void (*selected)( /* some bummu */); void (*selected)( /* some bummu */);
} Menu;
typedef struct MenuRenderData {
/* render stuff */
Window frame; Window frame;
Window title; Window title;
Appearance *a_title; Appearance *a_title;
int title_min_w, title_h; int title_min_w, title_h;
Window items; Window items;
Appearance *a_items; Appearance *a_items;
int bullet_w;
int item_h; int item_h;
} MenuRenderData; int width;
} Menu;
typedef enum MenuEntryRenderType { typedef enum MenuEntryRenderType {
MenuEntryRenderType_None = 0, MenuEntryRenderType_None = 0,
@ -56,18 +57,20 @@ typedef struct {
Action *action; Action *action;
MenuEntryRenderType render_type; MenuEntryRenderType render_type;
gboolean hilite;
gboolean enabled; gboolean enabled;
gboolean boolean_value; gboolean boolean_value;
gpointer render_data; /* where the engine can store anything it likes */
Menu *submenu; Menu *submenu;
} MenuEntry;
typedef struct MenuEntryRenderData { /* render stuff */
Window item; Window item;
Appearance *a_item; Appearance *a_item;
Appearance *a_disabled;
Appearance *a_hilite;
int y;
int min_w; int min_w;
} MenuEntryRenderData; } MenuEntry;
void menu_startup(); void menu_startup();
void menu_shutdown(); void menu_shutdown();
@ -89,4 +92,9 @@ void menu_entry_free(MenuEntry *entry);
void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu); void menu_entry_set_submenu(MenuEntry *entry, Menu *submenu);
void menu_add_entry(Menu *menu, MenuEntry *entry); void menu_add_entry(Menu *menu, MenuEntry *entry);
MenuEntry *menu_find_entry(Menu *menu, Window win);
void menu_entry_render(MenuEntry *self);
#endif #endif

View file

@ -181,6 +181,7 @@ int main(int argc, char **argv)
menu_startup(); menu_startup();
frame_startup(); frame_startup();
stacking_startup();
focus_startup(); focus_startup();
screen_startup(); screen_startup();
group_startup(); group_startup();
@ -204,6 +205,7 @@ int main(int argc, char **argv)
group_shutdown(); group_shutdown();
screen_shutdown(); screen_shutdown();
focus_shutdown(); focus_shutdown();
stacking_shutdown();
frame_shutdown(); frame_shutdown();
menu_shutdown(); menu_shutdown();
grab_shutdown(); grab_shutdown();

View file

@ -8,6 +8,24 @@
GList *stacking_list = NULL; GList *stacking_list = NULL;
static Window top_window = None;
void stacking_startup()
{
XSetWindowAttributes attrib;
attrib.override_redirect = TRUE;
top_window = XCreateWindow(ob_display, ob_root,
-100, -100, 1, 1, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect, &attrib);
XMapWindow(ob_display, top_window);
}
void stacking_shutdown()
{
XDestroyWindow(ob_display, top_window);
}
void stacking_set_list() void stacking_set_list()
{ {
Window *windows, *win_it; Window *windows, *win_it;
@ -30,7 +48,8 @@ void stacking_set_list()
} else } else
windows = NULL; windows = NULL;
PROP_SETA32(ob_root, net_client_list_stacking, window, windows, size); PROP_SETA32(ob_root, net_client_list_stacking, window,
(guint32*)windows, size);
if (windows) if (windows)
g_free(windows); g_free(windows);
@ -183,3 +202,12 @@ void stacking_lower(Client *client)
stacking_set_list(); stacking_set_list();
} }
void stacking_raise_internal(Window win)
{
Window wins[2]; /* only ever restack 2 windows. */
wins[0] = top_window;
wins[1] = win;
XRestackWindows(ob_display, wins, 2);
}

View file

@ -2,6 +2,7 @@
#define __stacking_h #define __stacking_h
#include <glib.h> #include <glib.h>
#include <X11/Xlib.h>
struct Client; struct Client;
@ -20,6 +21,9 @@ typedef enum {
/* list of Client*s in stacking order from highest to lowest */ /* list of Client*s in stacking order from highest to lowest */
extern GList *stacking_list; extern GList *stacking_list;
void stacking_startup();
void stacking_shutdown();
/*! Sets the client stacking list on the root window from the /*! Sets the client stacking list on the root window from the
stacking_clientlist */ stacking_clientlist */
void stacking_set_list(); void stacking_set_list();
@ -36,4 +40,7 @@ void stacking_raise(struct Client *client);
/*! Lowers a client window below all others in its stacking layer */ /*! Lowers a client window below all others in its stacking layer */
void stacking_lower(struct Client *client); void stacking_lower(struct Client *client);
/*! Raises an internal window (e.g. menus) */
void stacking_raise_internal(Window win);
#endif #endif