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 */
gint strw, strh;
Rect *a;
- RrMinsize(dock->a_frame, &minw, &minh);
+ RrMinSize(dock->a_frame, &minw, &minh);
dock->w = dock->h = 0;
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);
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);
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);
}
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;
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,
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)
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)
(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);
}
}
} 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;
#include "client.h"
#include "action.h"
#include "prop.h"
+#include "menuframe.h"
#include "config.h"
#include "keytree.h"
#include "keyboard.h"
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);
}
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);
}
}
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 */
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);
/* 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;
/* 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;
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;
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 ||
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 ||
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;
/* 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);
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);
#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;
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)
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;
/* 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
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);
+ }
}
}
/* 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;
}
}
}
}
-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;
} 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,
}
}
-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;
self->desks = screen_num_desktops;
self->curdesk = desk;
- popup_show(self->popup, text);
+ popup_delay_show(self->popup, usec, text);
}
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;
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);
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
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);
}
}
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;
+}
/*! 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
}
}
-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)
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,