diff options
Diffstat (limited to 'openbox')
| -rw-r--r-- | openbox/actions/desktop.c | 349 | ||||
| -rw-r--r-- | openbox/actions/growtoedge.c | 146 | ||||
| -rw-r--r-- | openbox/actions/if.c | 22 | ||||
| -rw-r--r-- | openbox/actions/resize.c | 7 | ||||
| -rw-r--r-- | openbox/actions/showdesktop.c | 39 | ||||
| -rw-r--r-- | openbox/actions/showmenu.c | 84 | ||||
| -rw-r--r-- | openbox/client.c | 80 | ||||
| -rw-r--r-- | openbox/client.h | 13 | ||||
| -rw-r--r-- | openbox/client_menu.c | 12 | ||||
| -rw-r--r-- | openbox/config.c | 81 | ||||
| -rw-r--r-- | openbox/config.h | 2 | ||||
| -rw-r--r-- | openbox/dock.c | 16 | ||||
| -rw-r--r-- | openbox/event.c | 48 | ||||
| -rw-r--r-- | openbox/frame.c | 19 | ||||
| -rw-r--r-- | openbox/frame.h | 2 | ||||
| -rw-r--r-- | openbox/framerender.c | 76 | ||||
| -rw-r--r-- | openbox/keyboard.c | 2 | ||||
| -rw-r--r-- | openbox/menu.c | 14 | ||||
| -rw-r--r-- | openbox/menu.h | 4 | ||||
| -rw-r--r-- | openbox/menuframe.c | 56 | ||||
| -rw-r--r-- | openbox/menuframe.h | 5 | ||||
| -rw-r--r-- | openbox/mouse.c | 2 | ||||
| -rw-r--r-- | openbox/moveresize.c | 9 | ||||
| -rw-r--r-- | openbox/openbox.c | 8 | ||||
| -rw-r--r-- | openbox/place.c | 89 | ||||
| -rw-r--r-- | openbox/place.h | 3 | ||||
| -rw-r--r-- | openbox/place_overlap.c | 46 | ||||
| -rw-r--r-- | openbox/screen.c | 98 | ||||
| -rw-r--r-- | openbox/screen.h | 19 | ||||
| -rw-r--r-- | openbox/stacking.c | 64 | ||||
| -rw-r--r-- | openbox/stacking.h | 4 |
31 files changed, 846 insertions, 573 deletions
diff --git a/openbox/actions/desktop.c b/openbox/actions/desktop.c index 8dadf550..c2f73c6b 100644 --- a/openbox/actions/desktop.c +++ b/openbox/actions/desktop.c @@ -26,131 +26,62 @@ typedef struct { } u; gboolean send; gboolean follow; - gboolean interactive; } Options; -static gpointer setup_go_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); +static gpointer setup_func(xmlNodePtr node); +static gpointer setup_send_func(xmlNodePtr node); static void free_func(gpointer o); static gboolean run_func(ObActionsData *data, gpointer options); -static gboolean i_pre_func(guint state, gpointer options); -static gboolean i_input_func(guint initial_state, - XEvent *e, - ObtIC *ic, - gpointer options, - gboolean *used); -static void i_post_func(gpointer options); - /* 3.4-compatibility */ static gpointer setup_go_last_func(xmlNodePtr node); static gpointer setup_send_last_func(xmlNodePtr node); static gpointer setup_go_abs_func(xmlNodePtr node); -static gpointer setup_go_next_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_next_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_go_prev_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_prev_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_go_left_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_left_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_go_right_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_right_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_go_up_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_up_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_go_down_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); -static gpointer setup_send_down_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post); +static gpointer setup_go_next_func(xmlNodePtr node); +static gpointer setup_send_next_func(xmlNodePtr node); +static gpointer setup_go_prev_func(xmlNodePtr node); +static gpointer setup_send_prev_func(xmlNodePtr node); +static gpointer setup_go_left_func(xmlNodePtr node); +static gpointer setup_send_left_func(xmlNodePtr node); +static gpointer setup_go_right_func(xmlNodePtr node); +static gpointer setup_send_right_func(xmlNodePtr node); +static gpointer setup_go_up_func(xmlNodePtr node); +static gpointer setup_send_up_func(xmlNodePtr node); +static gpointer setup_go_down_func(xmlNodePtr node); +static gpointer setup_send_down_func(xmlNodePtr node); void action_desktop_startup(void) { - actions_register_i("GoToDesktop", setup_go_func, free_func, run_func); - actions_register_i("SendToDesktop", setup_send_func, free_func, run_func); + actions_register("GoToDesktop", setup_func, free_func, run_func); + actions_register("SendToDesktop", setup_send_func, free_func, run_func); /* 3.4-compatibility */ actions_register("DesktopLast", setup_go_last_func, free_func, run_func); actions_register("SendToDesktopLast", setup_send_last_func, free_func, run_func); actions_register("Desktop", setup_go_abs_func, free_func, run_func); - actions_register_i("DesktopNext", setup_go_next_func, free_func, run_func); - actions_register_i("SendToDesktopNext", setup_send_next_func, - free_func, run_func); - actions_register_i("DesktopPrevious", setup_go_prev_func, - free_func, run_func); - actions_register_i("SendToDesktopPrevious", setup_send_prev_func, - free_func, run_func); - actions_register_i("DesktopLeft", setup_go_left_func, free_func, run_func); - actions_register_i("SendToDesktopLeft", setup_send_left_func, - free_func, run_func); - actions_register_i("DesktopRight", setup_go_right_func, - free_func, run_func); - actions_register_i("SendToDesktopRight", setup_send_right_func, - free_func, run_func); - actions_register_i("DesktopUp", setup_go_up_func, free_func, run_func); - actions_register_i("SendToDesktopUp", setup_send_up_func, - free_func, run_func); - actions_register_i("DesktopDown", setup_go_down_func, free_func, run_func); - actions_register_i("SendToDesktopDown", setup_send_down_func, - free_func, run_func); + actions_register("DesktopNext", setup_go_next_func, free_func, run_func); + actions_register("SendToDesktopNext", setup_send_next_func, + free_func, run_func); + actions_register("DesktopPrevious", setup_go_prev_func, + free_func, run_func); + actions_register("SendToDesktopPrevious", setup_send_prev_func, + free_func, run_func); + actions_register("DesktopLeft", setup_go_left_func, free_func, run_func); + actions_register("SendToDesktopLeft", setup_send_left_func, + free_func, run_func); + actions_register("DesktopRight", setup_go_right_func, + free_func, run_func); + actions_register("SendToDesktopRight", setup_send_right_func, + free_func, run_func); + actions_register("DesktopUp", setup_go_up_func, free_func, run_func); + actions_register("SendToDesktopUp", setup_send_up_func, + free_func, run_func); + actions_register("DesktopDown", setup_go_down_func, free_func, run_func); + actions_register("SendToDesktopDown", setup_send_down_func, + free_func, run_func); } -static gpointer setup_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_func(xmlNodePtr node) { xmlNodePtr n; Options *o; @@ -211,36 +142,12 @@ static gpointer setup_func(xmlNodePtr node, return o; } - -static gpointer setup_go_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) -{ - Options *o; - - o = setup_func(node, pre, input, cancel, post); - if (o->type == RELATIVE) { - o->interactive = TRUE; - *pre = i_pre_func; - *input = i_input_func; - *post = i_post_func; - } - - return o; -} - -static gpointer setup_send_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_func(xmlNodePtr node) { xmlNodePtr n; Options *o; - o = setup_func(node, pre, input, cancel, post); + o = setup_func(node); if ((n = obt_xml_find_node(node, "desktop"))) { /* 3.4 compatibility */ o->u.abs.desktop = obt_xml_node_int(n) - 1; @@ -252,13 +159,6 @@ static gpointer setup_send_func(xmlNodePtr node, if ((n = obt_xml_find_node(node, "follow"))) o->follow = obt_xml_node_bool(n); - if (o->type == RELATIVE && o->follow) { - o->interactive = TRUE; - *pre = i_pre_func; - *input = i_input_func; - *post = i_post_func; - } - return o; } @@ -310,62 +210,7 @@ static gboolean run_func(ObActionsData *data, gpointer options) actions_client_move(data, FALSE); } - return o->interactive; -} - -static gboolean i_input_func(guint initial_state, - XEvent *e, - ObtIC *ic, - gpointer options, - gboolean *used) -{ - guint mods, initial_mods; - - initial_mods = obt_keyboard_only_modmasks(initial_state); - mods = obt_keyboard_only_modmasks(e->xkey.state); - if (e->type == KeyRelease) { - /* remove from the state the mask of the modifier key being - released, if it is a modifier key being released that is */ - mods &= ~obt_keyboard_keyevent_to_modmask(e); - } - - if (e->type == KeyPress) { - KeySym sym = obt_keyboard_keypress_to_keysym(e); - - /* Escape cancels no matter what */ - if (sym == XK_Escape) - return FALSE; - - /* There were no modifiers and they pressed enter */ - else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_mods) - return FALSE; - } - /* They released the modifiers */ - else if (e->type == KeyRelease && initial_mods && !(mods & initial_mods)) - { - return FALSE; - } - - return TRUE; -} - -static gboolean i_pre_func(guint initial_state, gpointer options) -{ - guint initial_mods = obt_keyboard_only_modmasks(initial_state); - if (!initial_mods) { - Options *o = options; - o->interactive = FALSE; - return FALSE; - } - else { - screen_show_desktop_popup(screen_desktop, TRUE); - return TRUE; - } -} - -static void i_post_func(gpointer options) -{ - screen_hide_desktop_popup(); + return FALSE; } /* 3.4-compatilibity */ @@ -407,10 +252,7 @@ static gpointer setup_go_abs_func(xmlNodePtr node) } static void setup_rel(Options *o, xmlNodePtr node, gboolean lin, - ObDirection dir, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsIPostFunc *post) + ObDirection dir) { xmlNodePtr n; @@ -421,149 +263,88 @@ static void setup_rel(Options *o, xmlNodePtr node, gboolean lin, if ((n = obt_xml_find_node(node, "wrap"))) o->u.rel.wrap = obt_xml_node_bool(n); - - if (input) { - o->interactive = TRUE; - *pre = i_pre_func; - *input = i_input_func; - *post = i_post_func; - } } -static gpointer setup_go_next_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_next_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post); + setup_rel(o, node, TRUE, OB_DIRECTION_EAST); return o; } -static gpointer setup_send_next_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_next_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, TRUE, OB_DIRECTION_EAST, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, TRUE, OB_DIRECTION_EAST); return o; } -static gpointer setup_go_prev_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_prev_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post); + setup_rel(o, node, TRUE, OB_DIRECTION_WEST); return o; } -static gpointer setup_send_prev_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_prev_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, TRUE, OB_DIRECTION_WEST, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, TRUE, OB_DIRECTION_WEST); return o; } -static gpointer setup_go_left_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_left_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post); + setup_rel(o, node, FALSE, OB_DIRECTION_WEST); return o; } -static gpointer setup_send_left_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_left_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, FALSE, OB_DIRECTION_WEST, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, FALSE, OB_DIRECTION_WEST); return o; } -static gpointer setup_go_right_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_right_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post); + setup_rel(o, node, FALSE, OB_DIRECTION_EAST); return o; } -static gpointer setup_send_right_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_right_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, FALSE, OB_DIRECTION_EAST, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, FALSE, OB_DIRECTION_EAST); return o; } -static gpointer setup_go_up_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_up_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post); + setup_rel(o, node, FALSE, OB_DIRECTION_NORTH); return o; } -static gpointer setup_send_up_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_up_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, FALSE, OB_DIRECTION_NORTH); return o; } -static gpointer setup_go_down_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_go_down_func(xmlNodePtr node) { Options *o = g_slice_new0(Options); - setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post); + setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH); return o; } -static gpointer setup_send_down_func(xmlNodePtr node, - ObActionsIPreFunc *pre, - ObActionsIInputFunc *input, - ObActionsICancelFunc *cancel, - ObActionsIPostFunc *post) +static gpointer setup_send_down_func(xmlNodePtr node) { Options *o = setup_follow(node); - setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, - pre, (o->follow ? input : NULL), post); + setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH); return o; } diff --git a/openbox/actions/growtoedge.c b/openbox/actions/growtoedge.c index d5a7bfdd..acfbcfab 100644 --- a/openbox/actions/growtoedge.c +++ b/openbox/actions/growtoedge.c @@ -8,9 +8,11 @@ typedef struct { ObDirection dir; gboolean shrink; + gboolean fill; } Options; -static gpointer setup_func(xmlNodePtr node); +static gpointer setup_grow_func(xmlNodePtr node); +static gpointer setup_fill_func(xmlNodePtr node); static gpointer setup_shrink_func(xmlNodePtr node); static void free_func(gpointer o); static gboolean run_func(ObActionsData *data, gpointer options); @@ -22,7 +24,9 @@ static gpointer setup_west_func(xmlNodePtr node); void action_growtoedge_startup(void) { - actions_register("GrowToEdge", setup_func, + actions_register("GrowToEdge", setup_grow_func, + free_func, run_func); + actions_register("GrowToFill", setup_fill_func, free_func, run_func); actions_register("ShrinkToEdge", setup_shrink_func, free_func, run_func); @@ -40,7 +44,6 @@ static gpointer setup_func(xmlNodePtr node) o = g_slice_new0(Options); o->dir = OB_DIRECTION_NORTH; - o->shrink = FALSE; if ((n = obt_xml_find_node(node, "direction"))) { gchar *s = obt_xml_node_string(n); @@ -62,12 +65,35 @@ static gpointer setup_func(xmlNodePtr node) return o; } +static gpointer setup_grow_func(xmlNodePtr node) +{ + Options *o; + + o = setup_func(node); + o->shrink = FALSE; + o->fill = FALSE; + + return o; +} + +static gpointer setup_fill_func(xmlNodePtr node) +{ + Options *o; + + o = setup_func(node); + o->shrink = FALSE; + o->fill = TRUE; + + return o; +} + static gpointer setup_shrink_func(xmlNodePtr node) { Options *o; o = setup_func(node); o->shrink = TRUE; + o->fill = FALSE; return o; } @@ -97,6 +123,58 @@ static gboolean do_grow(ObActionsData *data, gint x, gint y, gint w, gint h) return FALSE; } +static gboolean do_grow_all_edges(ObActionsData* data, + ObClientDirectionalResizeType resize_type) +{ + gint x, y, w, h; + gint temp_x, temp_y, temp_w, temp_h; + + client_find_resize_directional(data->client, + OB_DIRECTION_NORTH, + resize_type, + &temp_x, &temp_y, &temp_w, &temp_h); + y = temp_y; + h = temp_h; + + client_find_resize_directional(data->client, + OB_DIRECTION_SOUTH, + resize_type, + &temp_x, &temp_y, &temp_w, &temp_h); + h += temp_h - data->client->area.height; + + + client_find_resize_directional(data->client, + OB_DIRECTION_WEST, + resize_type, + &temp_x, &temp_y, &temp_w, &temp_h); + x = temp_x; + w = temp_w; + + client_find_resize_directional(data->client, + OB_DIRECTION_EAST, + resize_type, + &temp_x, &temp_y, &temp_w, &temp_h); + w += temp_w - data->client->area.width; + + /* When filling, we allow the window to move to an arbitrary x/y + position, since we'll be growing the other edge as well. */ + int lw, lh; + client_try_configure(data->client, &x, &y, &w, &h, &lw, &lh, TRUE); + + if (x == data->client->area.x && + y == data->client->area.y && + w == data->client->area.width && + h == data->client->area.height) + { + return FALSE; + } + + actions_client_move(data, TRUE); + client_move_resize(data->client, x, y, w, h); + actions_client_move(data, FALSE); + return TRUE; +} + static void free_func(gpointer o) { g_slice_free(Options, o); @@ -106,34 +184,62 @@ static void free_func(gpointer o) static gboolean run_func(ObActionsData *data, gpointer options) { Options *o = options; - gint x, y, w, h; - ObDirection opp; - gint half; - if (!data->client || - /* don't allow vertical resize if shaded */ - ((o->dir == OB_DIRECTION_NORTH || o->dir == OB_DIRECTION_SOUTH) && - data->client->shaded)) - { + if (!data->client) + return FALSE; + + gboolean doing_vertical_resize = + o->dir == OB_DIRECTION_NORTH || + o->dir == OB_DIRECTION_SOUTH || + o->fill; + if (data->client->shaded && doing_vertical_resize) + return FALSE; + + if (o->fill) { + if (o->shrink) { + /* We don't have any implementation of shrinking for the FillToGrow + action. */ + return FALSE; + } + + if (do_grow_all_edges(data, CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE)) + return FALSE; + + /* If all the edges are blocked, then allow them to jump past their + current block points. */ + do_grow_all_edges(data, CLIENT_RESIZE_GROW); return FALSE; } if (!o->shrink) { - /* try grow */ - client_find_resize_directional(data->client, o->dir, TRUE, + gint x, y, w, h; + + /* Try grow. */ + client_find_resize_directional(data->client, + o->dir, + CLIENT_RESIZE_GROW, &x, &y, &w, &h); + if (do_grow(data, x, y, w, h)) return FALSE; } - /* we couldn't grow, so try shrink! */ - opp = (o->dir == OB_DIRECTION_NORTH ? OB_DIRECTION_SOUTH : - (o->dir == OB_DIRECTION_SOUTH ? OB_DIRECTION_NORTH : - (o->dir == OB_DIRECTION_EAST ? OB_DIRECTION_WEST : - OB_DIRECTION_EAST))); - client_find_resize_directional(data->client, opp, FALSE, + /* We couldn't grow, so try shrink! */ + ObDirection opposite = + (o->dir == OB_DIRECTION_NORTH ? OB_DIRECTION_SOUTH : + (o->dir == OB_DIRECTION_SOUTH ? OB_DIRECTION_NORTH : + (o->dir == OB_DIRECTION_EAST ? OB_DIRECTION_WEST : + OB_DIRECTION_EAST))); + + gint x, y, w, h; + gint half; + + client_find_resize_directional(data->client, + opposite, + CLIENT_RESIZE_SHRINK, &x, &y, &w, &h); - switch (opp) { + + switch (opposite) { case OB_DIRECTION_NORTH: half = data->client->area.y + data->client->area.height / 2; if (y > half) { diff --git a/openbox/actions/if.c b/openbox/actions/if.c index a083d485..a9c4094b 100644 --- a/openbox/actions/if.c +++ b/openbox/actions/if.c @@ -79,10 +79,9 @@ typedef struct { } Query; typedef struct { - GArray* queries; + GArray *queries; GSList *thenacts; GSList *elseacts; - gboolean stop; } Options; static gpointer setup_func(xmlNodePtr node); @@ -91,6 +90,8 @@ static gboolean run_func_if(ObActionsData *data, gpointer options); static gboolean run_func_stop(ObActionsData *data, gpointer options); static gboolean run_func_foreach(ObActionsData *data, gpointer options); +static gboolean foreach_stop; + void action_if_startup(void) { actions_register("If", setup_func, free_func, run_func_if); @@ -313,7 +314,7 @@ static gboolean run_func_if(ObActionsData *data, gpointer options) gboolean is_true = TRUE; guint i; - for (i = 0; i < o->queries->len; ++i) { + for (i = 0; is_true && i < o->queries->len; ++i) { Query *q = g_array_index(o->queries, Query*, i); ObClient *query_target = NULL; @@ -327,7 +328,10 @@ static gboolean run_func_if(ObActionsData *data, gpointer options) } /* If there's no client to query, then false. */ - is_true &= query_target != NULL; + if (!query_target) { + is_true = FALSE; + break; + } if (q->shaded_on) is_true &= query_target->shaded; @@ -427,14 +431,14 @@ static gboolean run_func_if(ObActionsData *data, gpointer options) static gboolean run_func_foreach(ObActionsData *data, gpointer options) { GList *it; - Options *o = options; - o->stop = FALSE; + foreach_stop = FALSE; for (it = client_list; it; it = g_list_next(it)) { data->client = it->data; run_func_if(data, options); - if (o->stop) { + if (foreach_stop) { + foreach_stop = FALSE; break; } } @@ -444,11 +448,9 @@ static gboolean run_func_foreach(ObActionsData *data, gpointer options) static gboolean run_func_stop(ObActionsData *data, gpointer options) { - Options *o = options; - /* This stops the loop above so we don't invoke actions on any more clients */ - o->stop = TRUE; + foreach_stop = TRUE; /* TRUE causes actions_run_acts to not run further actions on the current client */ diff --git a/openbox/actions/resize.c b/openbox/actions/resize.c index f6858d2d..fc85c0b7 100644 --- a/openbox/actions/resize.c +++ b/openbox/actions/resize.c @@ -2,6 +2,7 @@ #include "openbox/moveresize.h" #include "openbox/client.h" #include "openbox/frame.h" +#include "openbox/screen.h" #include "obt/prop.h" typedef struct { @@ -95,6 +96,12 @@ static gboolean run_func(ObActionsData *data, gpointer options) static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch, gboolean shaded) { + const Rect *full = screen_physical_area_all_monitors(); + if (cx < full->x) { cw = cw + cx - full->x; cx = full->x; } + if (cy < full->y) { ch = ch + cy - full->y; cy = full->y; } + if (cx + cw > full->x + full->width) cw = full->x + full->width - cx; + if (cy + ch > full->y + full->height) ch = full->y + full->height - cy; + /* let's make x and y client relative instead of screen relative */ x = x - cx; y = ch - (y - cy); /* y is inverted, 0 is at the bottom of the window */ diff --git a/openbox/actions/showdesktop.c b/openbox/actions/showdesktop.c index 6dc77d5e..3c3b2d10 100644 --- a/openbox/actions/showdesktop.c +++ b/openbox/actions/showdesktop.c @@ -1,17 +1,52 @@ #include "openbox/actions.h" #include "openbox/screen.h" +typedef struct { + /* If true, windows are unable to be shown while in the showing-desktop + state. */ + gboolean strict; +} Options; + +static gpointer setup_func(xmlNodePtr node); +static void free_func(gpointer o); static gboolean run_func(ObActionsData *data, gpointer options); void action_showdesktop_startup(void) { - actions_register("ToggleShowDesktop", NULL, NULL, run_func); + actions_register("ToggleShowDesktop", setup_func, free_func, run_func); +} + +static gpointer setup_func(xmlNodePtr node) +{ + xmlNodePtr n; + Options *o = g_slice_new0(Options); + o->strict = FALSE; + + if ((n = obt_xml_find_node(node, "strict"))) + o->strict = obt_xml_node_bool(n); + + return o; +} + +static void free_func(gpointer o) +{ + g_slice_free(Options, o); } /* Always return FALSE because its not interactive */ static gboolean run_func(ObActionsData *data, gpointer options) { - screen_show_desktop(!screen_showing_desktop, NULL); + Options *o = options; + + ObScreenShowDestopMode show_mode; + if (screen_showing_desktop()) + show_mode = SCREEN_SHOW_DESKTOP_NO; + else if (!o->strict) + show_mode = SCREEN_SHOW_DESKTOP_UNTIL_WINDOW; + else + show_mode = SCREEN_SHOW_DESKTOP_UNTIL_TOGGLE; + + screen_show_desktop(show_mode, NULL); return FALSE; } diff --git a/openbox/actions/showmenu.c b/openbox/actions/showmenu.c index 485a31d5..7411e981 100644 --- a/openbox/actions/showmenu.c +++ b/openbox/actions/showmenu.c @@ -1,9 +1,17 @@ #include "openbox/actions.h" #include "openbox/menu.h" +#include "openbox/place.h" +#include "openbox/geom.h" +#include "openbox/screen.h" +#include "openbox/config.h" #include <glib.h> typedef struct { - gchar *name; + gchar *name; + GravityPoint position; + ObPlaceMonitor monitor_type; + gint monitor; + gboolean use_position; } Options; static gpointer setup_func(xmlNodePtr node); @@ -17,13 +25,50 @@ void action_showmenu_startup(void) static gpointer setup_func(xmlNodePtr node) { - xmlNodePtr n; + xmlNodePtr n, c; Options *o; + gboolean x_pos_given = FALSE; o = g_slice_new0(Options); + o->monitor = -1; if ((n = obt_xml_find_node(node, "menu"))) o->name = obt_xml_node_string(n); + + if ((n = obt_xml_find_node(node, "position"))) { + if ((c = obt_xml_find_node(n->children, "x"))) { + if (!obt_xml_node_contains(c, "default")) { + config_parse_gravity_coord(c, &o->position.x); + x_pos_given = TRUE; + } + } + + if (x_pos_given && (c = obt_xml_find_node(n->children, "y"))) { + if (!obt_xml_node_contains(c, "default")) { + config_parse_gravity_coord(c, &o->position.y); + o->use_position = TRUE; + } + } + + /* unlike client placement, x/y is needed to specify a monitor, + * either it's under the mouse or it's in an exact actual position */ + if (o->use_position && (c = obt_xml_find_node(n->children, "monitor"))) { + if (!obt_xml_node_contains(c, "default")) { + gchar *s = obt_xml_node_string(c); + if (!g_ascii_strcasecmp(s, "mouse")) + o->monitor_type = OB_PLACE_MONITOR_MOUSE; + else if (!g_ascii_strcasecmp(s, "active")) + o->monitor_type = OB_PLACE_MONITOR_ACTIVE; + else if (!g_ascii_strcasecmp(s, "primary")) + o->monitor_type = OB_PLACE_MONITOR_PRIMARY; + else if (!g_ascii_strcasecmp(s, "all")) + o->monitor_type = OB_PLACE_MONITOR_ALL; + else + o->monitor = obt_xml_node_int(c) - 1; + g_free(s); + } + } + } return o; } @@ -38,10 +83,43 @@ static void free_func(gpointer options) static gboolean run_func(ObActionsData *data, gpointer options) { Options *o = options; + GravityPoint position = { { 0, }, }; + gint monitor = -1; + + if (o->use_position) { + if (o->monitor >= 0) + monitor = o->monitor; + else switch (o->monitor_type) { + case OB_PLACE_MONITOR_ANY: + case OB_PLACE_MONITOR_PRIMARY: + monitor = screen_monitor_primary(FALSE); + break; + case OB_PLACE_MONITOR_MOUSE: + monitor = screen_monitor_pointer(); + break; + case OB_PLACE_MONITOR_ACTIVE: + monitor = screen_monitor_active(); + break; + case OB_PLACE_MONITOR_ALL: + monitor = screen_num_monitors; + break; + default: + g_assert_not_reached(); + } + + position = o->position; + } else { + const Rect *allmon; + monitor = screen_num_monitors; + allmon = screen_physical_area_monitor(monitor); + position.x.pos = data->x - allmon->x; + position.y.pos = data->y - allmon->y; + } /* you cannot call ShowMenu from inside a menu */ if (data->uact != OB_USER_ACTION_MENU_SELECTION && o->name) - menu_show(o->name, data->x, data->y, data->button != 0, data->client); + menu_show(o->name, &position, monitor, + data->button != 0, o->use_position, data->client); return FALSE; } diff --git a/openbox/client.c b/openbox/client.c index c97abd5a..3ff278ae 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -2734,7 +2734,7 @@ gboolean client_should_show(ObClient *self) { if (self->iconic) return FALSE; - if (client_normal(self) && screen_showing_desktop) + if (client_normal(self) && screen_showing_desktop()) return FALSE; if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL) return TRUE; @@ -4080,7 +4080,7 @@ gboolean client_focus(ObClient *self) static void client_present(ObClient *self, gboolean here, gboolean raise, gboolean unshade) { - if (client_normal(self) && screen_showing_desktop) + if (client_normal(self) && screen_showing_desktop()) screen_show_desktop(FALSE, self); if (self->iconic) client_iconify(self, FALSE, here, FALSE); @@ -4535,8 +4535,9 @@ void client_find_move_directional(ObClient *self, ObDirection dir, frame_frame_gravity(self->frame, x, y); } -void client_find_resize_directional(ObClient *self, ObDirection side, - gboolean grow, +void client_find_resize_directional(ObClient *self, + ObDirection side, + ObClientDirectionalResizeType resize_type, gint *x, gint *y, gint *w, gint *h) { gint head; @@ -4544,31 +4545,84 @@ void client_find_resize_directional(ObClient *self, ObDirection side, gboolean near; ObDirection dir; + gboolean grow; + switch (resize_type) { + case CLIENT_RESIZE_GROW: + grow = TRUE; + break; + case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE: + grow = TRUE; + break; + case CLIENT_RESIZE_SHRINK: + grow = FALSE; + break; + } + switch (side) { case OB_DIRECTION_EAST: - head = RECT_RIGHT(self->frame->area) + - (self->size_inc.width - 1) * (grow ? 1 : 0); + head = RECT_RIGHT(self->frame->area); + switch (resize_type) { + case CLIENT_RESIZE_GROW: + head += self->size_inc.width - 1; + break; + case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE: + head -= 1; + break; + case CLIENT_RESIZE_SHRINK: + break; + } + e_start = RECT_TOP(self->frame->area); e_size = self->frame->area.height; dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST; break; case OB_DIRECTION_WEST: - head = RECT_LEFT(self->frame->area) - - (self->size_inc.width - 1) * (grow ? 1 : 0); + head = RECT_LEFT(self->frame->area); + switch (resize_type) { + case CLIENT_RESIZE_GROW: + head -= self->size_inc.width - 1; + break; + case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE: + head += 1; + break; + case CLIENT_RESIZE_SHRINK: + break; + } + e_start = RECT_TOP(self->frame->area); e_size = self->frame->area.height; dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST; break; case OB_DIRECTION_NORTH: - head = RECT_TOP(self->frame->area) - - (self->size_inc.height - 1) * (grow ? 1 : 0); + head = RECT_TOP(self->frame->area); + switch (resize_type) { + case CLIENT_RESIZE_GROW: + head -= self->size_inc.height - 1; + break; + case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE: + head += 1; + break; + case CLIENT_RESIZE_SHRINK: + break; + } + e_start = RECT_LEFT(self->frame->area); e_size = self->frame->area.width; dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH; break; case OB_DIRECTION_SOUTH: - head = RECT_BOTTOM(self->frame->area) + - (self->size_inc.height - 1) * (grow ? 1 : 0); + head = RECT_BOTTOM(self->frame->area); + switch (resize_type) { + case CLIENT_RESIZE_GROW: + head += self->size_inc.height - 1; + break; + case CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE: + head -= 1; + break; + case CLIENT_RESIZE_SHRINK: + break; + } + e_start = RECT_LEFT(self->frame->area); e_size = self->frame->area.width; dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH; @@ -4607,7 +4661,7 @@ void client_find_resize_directional(ObClient *self, ObDirection side, if (grow == near) --e; delta = e - RECT_BOTTOM(self->frame->area); *h += delta; - break; + break; default: g_assert_not_reached(); } diff --git a/openbox/client.h b/openbox/client.h index 5ae2d3d2..11a01400 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -489,8 +489,17 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, gint *dest, gboolean *near_edge); void client_find_move_directional(ObClient *self, ObDirection dir, gint *x, gint *y); -void client_find_resize_directional(ObClient *self, ObDirection side, - gboolean grow, + +typedef enum { + CLIENT_RESIZE_GROW, + CLIENT_RESIZE_GROW_IF_NOT_ON_EDGE, + CLIENT_RESIZE_SHRINK, +} ObClientDirectionalResizeType; + +/*! Moves the client area passed in to grow/shrink the given edge. */ +void client_find_resize_directional(ObClient *self, + ObDirection side, + ObClientDirectionalResizeType resize_type, gint *x, gint *y, gint *w, gint *h); /*! Fullscreen's or unfullscreen's the client window diff --git a/openbox/client_menu.c b/openbox/client_menu.c index c6cdd635..4a3b286f 100644 --- a/openbox/client_menu.c +++ b/openbox/client_menu.c @@ -276,7 +276,7 @@ static gboolean send_to_menu_update(ObMenuFrame *frame, gpointer data) if ((desk == DESKTOP_ALL && c->desktop != DESKTOP_ALL) || (c->desktop == DESKTOP_ALL && desk == screen_desktop)) { - e->data.normal.mask = ob_rr_theme->btn_desk->mask; + e->data.normal.mask = ob_rr_theme->btn_desk->unpressed_mask; set_icon_color(e); } else e->data.normal.mask = NULL; @@ -392,7 +392,7 @@ void client_menu_startup(void) menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME); e = menu_add_normal(menu, CLIENT_RESTORE, _("R_estore"), NULL, TRUE); - e->data.normal.mask = ob_rr_theme->btn_max->toggled_mask; + e->data.normal.mask = ob_rr_theme->btn_max->unpressed_toggled_mask; set_icon_color(e); menu_add_normal(menu, CLIENT_MOVE, _("_Move"), NULL, TRUE); @@ -400,15 +400,15 @@ void client_menu_startup(void) menu_add_normal(menu, CLIENT_RESIZE, _("Resi_ze"), NULL, TRUE); e = menu_add_normal(menu, CLIENT_ICONIFY, _("Ico_nify"), NULL, TRUE); - e->data.normal.mask = ob_rr_theme->btn_iconify->mask; + e->data.normal.mask = ob_rr_theme->btn_iconify->unpressed_mask; set_icon_color(e); e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Ma_ximize"), NULL, TRUE); - e->data.normal.mask = ob_rr_theme->btn_max->mask; + e->data.normal.mask = ob_rr_theme->btn_max->unpressed_mask; set_icon_color(e); e = menu_add_normal(menu, CLIENT_SHADE, _("_Roll up/down"), NULL, TRUE); - e->data.normal.mask = ob_rr_theme->btn_shade->mask; + e->data.normal.mask = ob_rr_theme->btn_shade->unpressed_mask; set_icon_color(e); menu_add_normal(menu, CLIENT_DECORATE, _("Un/_Decorate"), NULL, TRUE); @@ -416,6 +416,6 @@ void client_menu_startup(void) menu_add_separator(menu, -1, NULL); e = menu_add_normal(menu, CLIENT_CLOSE, _("_Close"), NULL, TRUE); - e->data.normal.mask = ob_rr_theme->btn_close->mask; + e->data.normal.mask = ob_rr_theme->btn_close->unpressed_mask; set_icon_color(e); } diff --git a/openbox/config.c b/openbox/config.c index 76f48569..dad5d1bf 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -83,8 +83,9 @@ guint config_dock_show_delay; guint config_dock_app_move_button; guint config_dock_app_move_modifiers; -guint config_keyboard_reset_keycode; -guint config_keyboard_reset_state; +guint config_keyboard_reset_keycode; +guint config_keyboard_reset_state; +gboolean config_keyboard_rebind_on_mapping_notify; gint config_mouse_threshold; gint config_mouse_dclicktime; @@ -503,6 +504,9 @@ static void parse_keyboard(xmlNodePtr node, gpointer d) parse_key(n, NULL); n = obt_xml_find_node(n->next, "keybind"); } + + if ((n = obt_xml_find_node(node->children, "rebindOnMappingNotify"))) + config_keyboard_rebind_on_mapping_notify = obt_xml_node_bool(n); } /* @@ -540,13 +544,15 @@ static void parse_mouse(xmlNodePtr node, gpointer d) if ((n = obt_xml_find_node(node, "screenEdgeWarpMouse"))) config_mouse_screenedgewarp = obt_xml_node_bool(n); - n = obt_xml_find_node(node, "context"); - while (n) { + for (n = obt_xml_find_node(node, "context"); + n; + n = obt_xml_find_node(n->next, "context")) + { gchar *modcxstr; ObFrameContext cx; if (!obt_xml_attr_string(n, "name", &cxstr)) - goto next_n; + continue; modcxstr = g_strdup(cxstr); /* make a copy to mutilate */ while (frame_next_context_from_string(modcxstr, &cx)) { @@ -561,10 +567,15 @@ static void parse_mouse(xmlNodePtr node, gpointer d) continue; } - nbut = obt_xml_find_node(n->children, "mousebind"); - while (nbut) { + for (nbut = obt_xml_find_node(n->children, "mousebind"); + nbut; + nbut = obt_xml_find_node(nbut->next, "mousebind")) + { + + gchar **button, **buttons; + if (!obt_xml_attr_string(nbut, "button", &buttonstr)) - goto next_nbut; + continue; if (obt_xml_attr_contains(nbut, "action", "press")) mact = OB_MOUSE_ACTION_PRESS; else if (obt_xml_attr_contains(nbut, "action", "release")) @@ -576,25 +587,31 @@ static void parse_mouse(xmlNodePtr node, gpointer d) else if (obt_xml_attr_contains(nbut, "action", "drag")) mact = OB_MOUSE_ACTION_MOTION; else - goto next_nbut; + continue; - nact = obt_xml_find_node(nbut->children, "action"); - while (nact) { + buttons = g_strsplit(buttonstr, " ", 0); + for (nact = obt_xml_find_node(nbut->children, "action"); + nact; + nact = obt_xml_find_node(nact->next, "action")) + { ObActionsAct *action; - if ((action = actions_parse(nact))) - mouse_bind(buttonstr, cx, mact, action); - nact = obt_xml_find_node(nact->next, "action"); + /* actions_parse() creates one ref to the action, but we need + * exactly one ref per binding we use it for. */ + if ((action = actions_parse(nact))) { + for (button = buttons; *button; ++button) { + actions_act_ref(action); + mouse_bind(*button, cx, mact, action); + } + actions_act_unref(action); + } } - g_free(buttonstr); - next_nbut: - nbut = obt_xml_find_node(nbut->next, "mousebind"); + g_strfreev(buttons); + g_free(buttonstr); } } g_free(modcxstr); g_free(cxstr); - next_n: - n = obt_xml_find_node(n->next, "context"); } } @@ -703,8 +720,10 @@ static void parse_theme(xmlNodePtr node, gpointer d) config_theme_window_list_icon_size = 96; } - n = obt_xml_find_node(node, "font"); - while (n) { + for (n = obt_xml_find_node(node, "font"); + n; + n = obt_xml_find_node(n->next, "font")) + { xmlNodePtr fnode; RrFont **font; gchar *name = g_strdup(RrDefaultFontFamily); @@ -727,7 +746,7 @@ static void parse_theme(xmlNodePtr node, gpointer d) else if (obt_xml_attr_contains(n, "place","InactiveOnScreenDisplay")) font = &config_font_inactiveosd; else - goto next_font; + continue; if ((fnode = obt_xml_find_node(n->children, "name"))) { g_free(name); @@ -754,8 +773,6 @@ static void parse_theme(xmlNodePtr node, gpointer d) *font = RrFontOpen(ob_rr_inst, name, size, weight, slant); g_free(name); - next_font: - n = obt_xml_find_node(n->next, "font"); } } @@ -784,12 +801,13 @@ static void parse_desktops(xmlNodePtr node, gpointer d) g_slist_free(config_desktops_names); config_desktops_names = NULL; - nname = obt_xml_find_node(n->children, "name"); - while (nname) { + for (nname = obt_xml_find_node(n->children, "name"); + nname; + nname = obt_xml_find_node(nname->next, "name")) + { config_desktops_names = g_slist_append(config_desktops_names, obt_xml_node_string(nname)); - nname = obt_xml_find_node(nname->next, "name"); } } if ((n = obt_xml_find_node(node, "popupTime"))) @@ -905,7 +923,7 @@ static void parse_dock(xmlNodePtr node, gpointer d) config_dock_show_delay = obt_xml_node_int(n); if ((n = obt_xml_find_node(node, "moveButton"))) { gchar *str = obt_xml_node_string(n); - guint b, s; + guint b = 0, s = 0; if (translate_button(str, &s, &b)) { config_dock_app_move_button = b; config_dock_app_move_modifiers = s; @@ -939,12 +957,14 @@ static void parse_menu(xmlNodePtr node, gpointer d) #endif } - while ((node = obt_xml_find_node(node, "file"))) { + for (node = obt_xml_find_node(node, "file"); + node; + node = obt_xml_find_node(node->next, "file")) + { gchar *c = obt_xml_node_string(node); config_menu_files = g_slist_append(config_menu_files, obt_paths_expand_tilde(c)); g_free(c); - node = node->next; } } @@ -1120,6 +1140,7 @@ void config_startup(ObtXmlInst *i) translate_key("C-g", &config_keyboard_reset_state, &config_keyboard_reset_keycode); + config_keyboard_rebind_on_mapping_notify = TRUE; bind_default_keyboard(); diff --git a/openbox/config.h b/openbox/config.h index fc1d217e..96a66cf1 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -179,6 +179,8 @@ extern guint config_desktop_popup_time; extern guint config_keyboard_reset_keycode; /*! The modifiers of the key combo which resets the keybaord chains */ extern guint config_keyboard_reset_state; +/*! Reload the keyboard bindings when the mapping changes */ +extern gboolean config_keyboard_rebind_on_mapping_notify; /*! Number of pixels a drag must go before being considered a drag */ extern gint config_mouse_threshold; diff --git a/openbox/dock.c b/openbox/dock.c index f18683d6..ea9b7f49 100644 --- a/openbox/dock.c +++ b/openbox/dock.c @@ -632,8 +632,6 @@ static gboolean hide_timeout(gpointer data) dock->hidden = TRUE; dock_configure(); - hide_timeout_id = 0; - return FALSE; /* don't repeat */ } @@ -643,30 +641,32 @@ static gboolean show_timeout(gpointer data) dock->hidden = FALSE; dock_configure(); - show_timeout_id = 0; - return FALSE; /* don't repeat */ } +static void destroy_timeout(gpointer data) +{ + gint *id = data; + *id = 0; +} + void dock_hide(gboolean hide) { if (!hide) { if (dock->hidden && config_dock_hide) { show_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, config_dock_show_delay, - show_timeout, NULL, NULL); + show_timeout, &show_timeout_id, destroy_timeout); } else if (!dock->hidden && config_dock_hide && hide_timeout_id) { if (hide_timeout_id) g_source_remove(hide_timeout_id); - hide_timeout_id = 0; } } else { if (!dock->hidden && config_dock_hide) { hide_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, config_dock_hide_delay, - hide_timeout, NULL, NULL); + hide_timeout, &hide_timeout_id, destroy_timeout); } else if (dock->hidden && config_dock_hide && show_timeout_id) { if (show_timeout_id) g_source_remove(show_timeout_id); - show_timeout_id = 0; } } } diff --git a/openbox/event.c b/openbox/event.c index 1b3a0e46..5774f67d 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -206,6 +206,7 @@ static Window event_get_window(XEvent *e) switch (((XkbAnyEvent*)e)->xkb_type) { case XkbBellNotify: window = ((XkbBellNotifyEvent*)e)->window; + break; default: window = None; } @@ -636,11 +637,13 @@ static void event_process(const XEvent *ec, gpointer data) else if (e->type == MappingNotify) { /* keyboard layout changes for modifier mapping changes. reload the modifier map, and rebind all the key bindings as appropriate */ - ob_debug("Keyboard map changed. Reloading keyboard bindings."); - ob_set_state(OB_STATE_RECONFIGURING); - obt_keyboard_reload(); - keyboard_rebind(); - ob_set_state(OB_STATE_RUNNING); + if (config_keyboard_rebind_on_mapping_notify) { + ob_debug("Keyboard map changed. Reloading keyboard bindings."); + ob_set_state(OB_STATE_RECONFIGURING); + obt_keyboard_reload(); + keyboard_rebind(); + ob_set_state(OB_STATE_RUNNING); + } } else if (e->type == ClientMessage) { /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for @@ -772,7 +775,12 @@ static void event_handle_root(XEvent *e) if (d > 0 && d <= 1000) screen_set_num_desktops(d); } else if (msgtype == OBT_PROP_ATOM(NET_SHOWING_DESKTOP)) { - screen_show_desktop(e->xclient.data.l[0] != 0, NULL); + ObScreenShowDestopMode show_mode; + if (e->xclient.data.l[0] != 0) + show_mode = SCREEN_SHOW_DESKTOP_UNTIL_WINDOW; + else + show_mode = SCREEN_SHOW_DESKTOP_NO; + screen_show_desktop(show_mode, NULL); } else if (msgtype == OBT_PROP_ATOM(OB_CONTROL)) { ob_debug("OB_CONTROL: %d", e->xclient.data.l[0]); if (e->xclient.data.l[0] == 1) @@ -1190,7 +1198,7 @@ static void event_handle_client(ObClient *client, XEvent *e) } if (e->xconfigurerequest.value_mask & CWStackMode) { - ObClient *sibling = NULL; + ObWindow *sibling = NULL; gulong ignore_start; gboolean ok = TRUE; @@ -1201,7 +1209,11 @@ static void event_handle_client(ObClient *client, XEvent *e) if (win && WINDOW_IS_CLIENT(win) && WINDOW_AS_CLIENT(win) != client) { - sibling = WINDOW_AS_CLIENT(win); + sibling = win; + } + else if (win && WINDOW_IS_DOCK(win)) + { + sibling = win; } else /* an invalid sibling was specified so don't restack at @@ -1552,13 +1564,17 @@ static void event_handle_client(ObClient *client, XEvent *e) "invalid source indication %ld", client->title, e->xclient.data.l[0]); } else { - ObClient *sibling = NULL; + ObWindow *sibling = NULL; if (e->xclient.data.l[1]) { ObWindow *win = window_find(e->xclient.data.l[1]); if (WINDOW_IS_CLIENT(win) && WINDOW_AS_CLIENT(win) != client) { - sibling = WINDOW_AS_CLIENT(win); + sibling = win; + } + if (WINDOW_IS_DOCK(win)) + { + sibling = win; } if (sibling == NULL) ob_debug_type(OB_DEBUG_APP_BUGS, @@ -1820,8 +1836,14 @@ static gboolean event_handle_menu_input(XEvent *ev) if ((e = menu_entry_frame_under(ev->xbutton.x_root, ev->xbutton.y_root))) { - if (ev->type == ButtonPress && e->frame->child) - menu_frame_select(e->frame->child, NULL, TRUE); + if (ev->type == ButtonPress) { + /* We know this is a new press, so we don't have to + * block release events anymore */ + menu_hide_delay_reset(); + + if (e->frame->child) + menu_frame_select(e->frame->child, NULL, TRUE); + } menu_frame_select(e->frame, e, TRUE); if (ev->type == ButtonRelease) menu_entry_frame_execute(e, ev->xbutton.state); @@ -2106,6 +2128,7 @@ static gboolean focus_delay_func(gpointer data) if (client_focus(d->client) && config_focus_raise) stacking_raise(CLIENT_AS_WINDOW(d->client)); event_curtime = old; + return FALSE; /* no repeat */ } @@ -2118,6 +2141,7 @@ static gboolean unfocus_delay_func(gpointer data) event_curserial = d->serial; focus_nothing(); event_curtime = old; + return FALSE; /* no repeat */ } diff --git a/openbox/frame.c b/openbox/frame.c index 3dbcf126..89669726 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -1664,8 +1664,7 @@ static void flash_done(gpointer data) { ObFrame *self = data; - if (self->focused != self->flash_on) - frame_adjust_focus(self, self->focused); + self->flash_timer = 0; } static gboolean flash_timeout(gpointer data) @@ -1679,8 +1678,12 @@ static gboolean flash_timeout(gpointer data) now.tv_usec >= self->flash_end.tv_usec)) self->flashing = FALSE; - if (!self->flashing) + if (!self->flashing) { + if (self->focused != self->flash_on) + frame_adjust_focus(self, self->focused); + return FALSE; /* we are done */ + } self->flash_on = !self->flash_on; if (!self->focused) { @@ -1787,14 +1790,12 @@ static gboolean frame_animate_iconify(gpointer p) XMoveResizeWindow(obt_display, self->window, x, y, w, h); XFlush(obt_display); - if (time == 0) - frame_end_iconify_animation(self); - return time > 0; /* repeat until we're out of time */ } -void frame_end_iconify_animation(ObFrame *self) +void frame_end_iconify_animation(gpointer data) { + ObFrame *self = data; /* see if there is an animation going */ if (self->iconify_animation_going == 0) return; @@ -1811,6 +1812,7 @@ void frame_end_iconify_animation(ObFrame *self) /* we're not animating any more ! */ self->iconify_animation_going = 0; + self->iconify_animation_timer = 0; XMoveResizeWindow(obt_display, self->window, self->area.x, self->area.y, @@ -1861,7 +1863,8 @@ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying) self->iconify_animation_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, FRAME_ANIMATE_ICONIFY_STEP_TIME, - frame_animate_iconify, self, NULL); + frame_animate_iconify, self, + frame_end_iconify_animation); /* do the first step */ diff --git a/openbox/frame.h b/openbox/frame.h index 915c08db..ae29c3b1 100644 --- a/openbox/frame.h +++ b/openbox/frame.h @@ -265,7 +265,7 @@ void frame_flash_stop(ObFrame *self); will be called when the animation finishes. But if another animation is started in the meantime, the callback will never get called. */ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying); -void frame_end_iconify_animation(ObFrame *self); +void frame_end_iconify_animation(gpointer data); #define frame_iconify_animating(f) (f->iconify_animation_going != 0) diff --git a/openbox/framerender.c b/openbox/framerender.c index 041e6d17..094d5962 100644 --- a/openbox/framerender.c +++ b/openbox/framerender.c @@ -131,115 +131,115 @@ void framerender_frame(ObFrame *self) t = ob_rr_theme->a_focused_title; l = ob_rr_theme->a_focused_label; m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? - ob_rr_theme->btn_max->a_disabled_focused : + ob_rr_theme->btn_max->a_focused_disabled : (self->client->max_vert || self->client->max_horz ? (self->max_press ? - ob_rr_theme->btn_max->a_toggled_focused_pressed : + ob_rr_theme->btn_max->a_focused_pressed_toggled : (self->max_hover ? - ob_rr_theme->btn_max->a_toggled_hover_focused : - ob_rr_theme->btn_max->a_toggled_focused_unpressed)) : + ob_rr_theme->btn_max->a_focused_hover_toggled : + ob_rr_theme->btn_max->a_focused_unpressed_toggled)) : (self->max_press ? ob_rr_theme->btn_max->a_focused_pressed : (self->max_hover ? - ob_rr_theme->btn_max->a_hover_focused : + ob_rr_theme->btn_max->a_focused_hover : ob_rr_theme->btn_max->a_focused_unpressed)))); n = ob_rr_theme->a_icon; i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? - ob_rr_theme->btn_iconify->a_disabled_focused : + ob_rr_theme->btn_iconify->a_focused_disabled : (self->iconify_press ? ob_rr_theme->btn_iconify->a_focused_pressed : (self->iconify_hover ? - ob_rr_theme->btn_iconify->a_hover_focused : + ob_rr_theme->btn_iconify->a_focused_hover : ob_rr_theme->btn_iconify->a_focused_unpressed))); d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? - ob_rr_theme->btn_desk->a_disabled_focused : + ob_rr_theme->btn_desk->a_focused_disabled : (self->client->desktop == DESKTOP_ALL ? (self->desk_press ? - ob_rr_theme->btn_desk->a_toggled_focused_pressed : + ob_rr_theme->btn_desk->a_focused_pressed_toggled : (self->desk_hover ? - ob_rr_theme->btn_desk->a_toggled_hover_focused : - ob_rr_theme->btn_desk->a_toggled_focused_unpressed)) : + ob_rr_theme->btn_desk->a_focused_hover_toggled : + ob_rr_theme->btn_desk->a_focused_unpressed_toggled)) : (self->desk_press ? ob_rr_theme->btn_desk->a_focused_pressed : (self->desk_hover ? - ob_rr_theme->btn_desk->a_hover_focused : + ob_rr_theme->btn_desk->a_focused_hover : ob_rr_theme->btn_desk->a_focused_unpressed)))); s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? - ob_rr_theme->btn_shade->a_disabled_focused : + ob_rr_theme->btn_shade->a_focused_disabled : (self->client->shaded ? (self->shade_press ? - ob_rr_theme->btn_shade->a_toggled_focused_pressed : + ob_rr_theme->btn_shade->a_focused_pressed_toggled : (self->shade_hover ? - ob_rr_theme->btn_shade->a_toggled_hover_focused : - ob_rr_theme->btn_shade->a_toggled_focused_unpressed)) : + ob_rr_theme->btn_shade->a_focused_hover_toggled : + ob_rr_theme->btn_shade->a_focused_unpressed_toggled)) : (self->shade_press ? ob_rr_theme->btn_shade->a_focused_pressed : (self->shade_hover ? - ob_rr_theme->btn_shade->a_hover_focused : + ob_rr_theme->btn_shade->a_focused_hover : ob_rr_theme->btn_shade->a_focused_unpressed)))); c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? - ob_rr_theme->btn_close->a_disabled_focused : + ob_rr_theme->btn_close->a_focused_disabled : (self->close_press ? ob_rr_theme->btn_close->a_focused_pressed : (self->close_hover ? - ob_rr_theme->btn_close->a_hover_focused : + ob_rr_theme->btn_close->a_focused_hover : ob_rr_theme->btn_close->a_focused_unpressed))); } else { t = ob_rr_theme->a_unfocused_title; l = ob_rr_theme->a_unfocused_label; m = (!(self->decorations & OB_FRAME_DECOR_MAXIMIZE) ? - ob_rr_theme->btn_max->a_disabled_unfocused : + ob_rr_theme->btn_max->a_unfocused_disabled : (self->client->max_vert || self->client->max_horz ? (self->max_press ? - ob_rr_theme->btn_max->a_toggled_unfocused_pressed : + ob_rr_theme->btn_max->a_unfocused_pressed_toggled : (self->max_hover ? - ob_rr_theme->btn_max->a_toggled_hover_unfocused : - ob_rr_theme->btn_max->a_toggled_unfocused_unpressed)) : + ob_rr_theme->btn_max->a_unfocused_hover_toggled : + ob_rr_theme->btn_max->a_unfocused_unpressed_toggled)) : (self->max_press ? ob_rr_theme->btn_max->a_unfocused_pressed : (self->max_hover ? - ob_rr_theme->btn_max->a_hover_unfocused : + ob_rr_theme->btn_max->a_unfocused_hover : ob_rr_theme->btn_max->a_unfocused_unpressed)))); n = ob_rr_theme->a_icon; i = (!(self->decorations & OB_FRAME_DECOR_ICONIFY) ? - ob_rr_theme->btn_iconify->a_disabled_unfocused : + ob_rr_theme->btn_iconify->a_unfocused_disabled : (self->iconify_press ? ob_rr_theme->btn_iconify->a_unfocused_pressed : (self->iconify_hover ? - ob_rr_theme->btn_iconify->a_hover_unfocused : + ob_rr_theme->btn_iconify->a_unfocused_hover : ob_rr_theme->btn_iconify->a_unfocused_unpressed))); d = (!(self->decorations & OB_FRAME_DECOR_ALLDESKTOPS) ? - ob_rr_theme->btn_desk->a_disabled_unfocused : + ob_rr_theme->btn_desk->a_unfocused_disabled : (self->client->desktop == DESKTOP_ALL ? (self->desk_press ? - ob_rr_theme->btn_desk->a_toggled_unfocused_pressed : + ob_rr_theme->btn_desk->a_unfocused_pressed_toggled : (self->desk_hover ? - ob_rr_theme->btn_desk->a_toggled_hover_unfocused : - ob_rr_theme->btn_desk->a_toggled_unfocused_unpressed)) : + ob_rr_theme->btn_desk->a_unfocused_hover_toggled : + ob_rr_theme->btn_desk->a_unfocused_unpressed_toggled)) : (self->desk_press ? ob_rr_theme->btn_desk->a_unfocused_pressed : (self->desk_hover ? - ob_rr_theme->btn_desk->a_hover_unfocused : + ob_rr_theme->btn_desk->a_unfocused_hover : ob_rr_theme->btn_desk->a_unfocused_unpressed)))); s = (!(self->decorations & OB_FRAME_DECOR_SHADE) ? - ob_rr_theme->btn_shade->a_disabled_unfocused : + ob_rr_theme->btn_shade->a_unfocused_disabled : (self->client->shaded ? (self->shade_press ? - ob_rr_theme->btn_shade->a_toggled_unfocused_pressed : + ob_rr_theme->btn_shade->a_unfocused_pressed_toggled : (self->shade_hover ? - ob_rr_theme->btn_shade->a_toggled_hover_unfocused : - ob_rr_theme->btn_shade->a_toggled_unfocused_unpressed)) : + ob_rr_theme->btn_shade->a_unfocused_hover_toggled : + ob_rr_theme->btn_shade->a_unfocused_unpressed_toggled)) : (self->shade_press ? ob_rr_theme->btn_shade->a_unfocused_pressed : (self->shade_hover ? - ob_rr_theme->btn_shade->a_hover_unfocused : + ob_rr_theme->btn_shade->a_unfocused_hover : ob_rr_theme->btn_shade->a_unfocused_unpressed)))); c = (!(self->decorations & OB_FRAME_DECOR_CLOSE) ? - ob_rr_theme->btn_close->a_disabled_unfocused : + ob_rr_theme->btn_close->a_unfocused_disabled : (self->close_press ? ob_rr_theme->btn_close->a_unfocused_pressed : (self->close_hover ? - ob_rr_theme->btn_close->a_hover_unfocused : + ob_rr_theme->btn_close->a_unfocused_hover : ob_rr_theme->btn_close->a_unfocused_unpressed))); } clear = ob_rr_theme->a_clear; diff --git a/openbox/keyboard.c b/openbox/keyboard.c index 8f4424ea..29abca82 100644 --- a/openbox/keyboard.c +++ b/openbox/keyboard.c @@ -270,8 +270,8 @@ gboolean keyboard_event(ObClient *client, const XEvent *e) e->xkey.state, e->xkey.x_root, e->xkey.y_root, 0, OB_FRAME_CONTEXT_NONE, client); } - break; used = TRUE; + break; } p = p->next_sibling; } diff --git a/openbox/menu.c b/openbox/menu.c index 7c49cedb..8804e128 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -277,7 +277,7 @@ static gunichar parse_shortcut(const gchar *label, gboolean allow_shortcut, return shortcut; } -static void parse_menu_item(xmlNodePtr node, gpointer data) +static void parse_menu_item(xmlNodePtr node, gpointer data) { ObMenuParseState *state = data; gchar *label; @@ -454,10 +454,12 @@ static gboolean menu_hide_delay_func(gpointer data) { menu_can_hide = TRUE; menu_timeout_id = 0; + return FALSE; /* no repeat */ } -void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client) +void menu_show(gchar *name, const GravityPoint *pos, gint monitor, + gboolean mouse, gboolean user_positioned, ObClient *client) { ObMenu *self; ObMenuFrame *frame; @@ -479,7 +481,7 @@ void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client) menu_clear_pipe_caches(); frame = menu_frame_new(self, 0, client); - if (!menu_frame_show_topmenu(frame, x, y, mouse)) + if (!menu_frame_show_topmenu(frame, pos, monitor, mouse, user_positioned)) menu_frame_free(frame); else { if (!mouse) { @@ -517,6 +519,12 @@ gboolean menu_hide_delay_reached(void) return menu_can_hide; } +void menu_hide_delay_reset(void) +{ + if (menu_timeout_id) g_source_remove(menu_timeout_id); + menu_hide_delay_func(NULL); +} + static ObMenuEntry* menu_entry_new(ObMenu *menu, ObMenuEntryType type, gint id) { ObMenuEntry *self; diff --git a/openbox/menu.h b/openbox/menu.h index 7d719729..8c2ecd77 100644 --- a/openbox/menu.h +++ b/openbox/menu.h @@ -181,9 +181,11 @@ void menu_clear_pipe_caches(void); void menu_show_all_shortcuts(ObMenu *self, gboolean show); -void menu_show(gchar *name, gint x, gint y, gboolean mouse, +void menu_show(gchar *name, const GravityPoint *pos, gint monitor, + gboolean mouse, gboolean user_positioned, struct _ObClient *client); gboolean menu_hide_delay_reached(void); +void menu_hide_delay_reset(void); /*! The show function is called right after a menu is shown */ void menu_set_show_func(ObMenu *menu, ObMenuShowFunc func); diff --git a/openbox/menuframe.c b/openbox/menuframe.c index 3252bb3c..c37fdcc5 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -203,8 +203,6 @@ static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry, static void menu_entry_frame_free(ObMenuEntryFrame *self) { if (self) { - menu_entry_unref(self->entry); - window_remove(self->window); XDestroyWindow(obt_display, self->text); @@ -221,6 +219,7 @@ static void menu_entry_frame_free(ObMenuEntryFrame *self) g_hash_table_remove(menu_frame_map, &self->bullet); } + menu_entry_unref(self->entry); g_slice_free(ObMenuEntryFrame, self); } } @@ -232,10 +231,18 @@ void menu_frame_move(ObMenuFrame *self, gint x, gint y) XMoveWindow(obt_display, self->window, self->area.x, self->area.y); } -static void menu_frame_place_topmenu(ObMenuFrame *self, gint *x, gint *y) +static void menu_frame_place_topmenu(ObMenuFrame *self, const GravityPoint *pos, + gint *x, gint *y, gint monitor, + gboolean user_positioned) { gint dx, dy; + screen_apply_gravity_point(x, y, self->area.width, self->area.height, + pos, screen_physical_area_monitor(monitor)); + + if (user_positioned) + return; + if (config_menu_middle) { gint myx; @@ -989,20 +996,26 @@ static gboolean menu_frame_show(ObMenuFrame *self) return TRUE; } -gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, - gboolean mouse) +gboolean menu_frame_show_topmenu(ObMenuFrame *self, const GravityPoint *pos, + gint monitor, gboolean mouse, + gboolean user_positioned) { gint px, py; + gint x, y; if (menu_frame_is_visible(self)) return TRUE; if (!menu_frame_show(self)) return FALSE; - if (self->menu->place_func) + if (self->menu->place_func) { + x = pos->x.pos; + y = pos->y.pos; self->menu->place_func(self, &x, &y, mouse, self->menu->data); - else - menu_frame_place_topmenu(self, &x, &y); + } else { + menu_frame_place_topmenu(self, pos, &x, &y, monitor, + user_positioned); + } menu_frame_move(self, x, y); @@ -1023,7 +1036,6 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, static void remove_submenu_hide_timeout(ObMenuFrame *child) { if (submenu_hide_timer) g_source_remove(submenu_hide_timer); - submenu_hide_timer = 0; } gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, @@ -1121,11 +1133,9 @@ void menu_frame_hide_all(void) { GList *it; - if (config_submenu_show_delay) { + if (config_submenu_show_delay && submenu_show_timer) /* remove any submenu open requests */ - if (submenu_show_timer) g_source_remove(submenu_show_timer); - submenu_show_timer = 0; - } + g_source_remove(submenu_show_timer); if ((it = g_list_last(menu_frame_visible))) menu_frame_hide(it->data); } @@ -1175,6 +1185,11 @@ static gboolean submenu_show_timeout(gpointer data) return FALSE; } +static void submenu_show_dest(gpointer data) +{ + submenu_show_timer = 0; +} + static gboolean submenu_hide_timeout(gpointer data) { g_assert(menu_frame_visible); @@ -1182,6 +1197,11 @@ static gboolean submenu_hide_timeout(gpointer data) return FALSE; } +static void submenu_hide_dest(gpointer data) +{ + submenu_hide_timer = 0; +} + void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, gboolean immediate) { @@ -1203,11 +1223,9 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, if (!entry && oldchild_entry) entry = oldchild_entry; - if (config_submenu_show_delay) { + if (config_submenu_show_delay && submenu_show_timer) /* remove any submenu open requests */ - if (submenu_show_timer) g_source_remove(submenu_show_timer); - submenu_show_timer = 0; - } + g_source_remove(submenu_show_timer); self->selected = entry; @@ -1231,7 +1249,7 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, submenu_hide_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, config_submenu_hide_delay, - submenu_hide_timeout, oldchild, NULL); + submenu_hide_timeout, oldchild, submenu_hide_dest); } } } @@ -1251,7 +1269,7 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry, g_timeout_add_full(G_PRIORITY_DEFAULT, config_submenu_show_delay, submenu_show_timeout, - self->selected, NULL); + self->selected, submenu_show_dest); } } /* hide the grandchildren of this menu. and move the cursor to diff --git a/openbox/menuframe.h b/openbox/menuframe.h index 2d7a2ae0..7b295b6f 100644 --- a/openbox/menuframe.h +++ b/openbox/menuframe.h @@ -120,8 +120,9 @@ void menu_frame_move(ObMenuFrame *self, gint x, gint y); void menu_frame_move_on_screen(ObMenuFrame *self, gint x, gint y, gint *dx, gint *dy); -gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y, - gboolean mouse); +gboolean menu_frame_show_topmenu(ObMenuFrame *self, const GravityPoint *pos, + gint monitor, gboolean mouse, + gboolean user_positioned); gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent, ObMenuEntryFrame *parent_entry); diff --git a/openbox/mouse.c b/openbox/mouse.c index 2f0c8f59..4da22f3c 100644 --- a/openbox/mouse.c +++ b/openbox/mouse.c @@ -372,7 +372,7 @@ gboolean mouse_event(ObClient *client, XEvent *e) gboolean mouse_bind(const gchar *buttonstr, ObFrameContext context, ObMouseAction mact, ObActionsAct *action) { - guint state, button; + guint state = 0, button = 0; ObMouseBinding *b; GSList *it; diff --git a/openbox/moveresize.c b/openbox/moveresize.c index 333a1bea..d12a64de 100644 --- a/openbox/moveresize.c +++ b/openbox/moveresize.c @@ -795,8 +795,13 @@ static void resize_with_keys(KeySym sym, guint state) else /* if (sym == XK_Up)) */ dir = OB_DIRECTION_NORTH; - client_find_resize_directional(moveresize_client, key_resize_edge, - key_resize_edge == dir, + ObClientDirectionalResizeType resize_type = + key_resize_edge == dir ? CLIENT_RESIZE_GROW + : CLIENT_RESIZE_SHRINK; + + client_find_resize_directional(moveresize_client, + key_resize_edge, + resize_type, &x, &y, &w, &h); dw = w - moveresize_client->area.width; dh = h - moveresize_client->area.height; diff --git a/openbox/openbox.c b/openbox/openbox.c index cba04995..1671a0d3 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -329,11 +329,11 @@ gint main(gint argc, gchar **argv) menu_startup(reconfigure); prompt_startup(reconfigure); - /* do this after everything is started so no events will get - missed */ - xqueue_listen(); - if (!reconfigure) { + /* do this after everything is started so no events will get + missed */ + xqueue_listen(); + guint32 xid; ObWindow *w; diff --git a/openbox/place.c b/openbox/place.c index 7d5c8694..de2c7dc9 100644 --- a/openbox/place.c +++ b/openbox/place.c @@ -257,13 +257,13 @@ static Rect* choose_monitor(ObClient *c, gboolean client_to_be_foregrounded, static gboolean place_under_mouse(ObClient *client, gint *x, gint *y, Size frame_size) { - if (config_place_policy != OB_PLACE_POLICY_MOUSE) - return FALSE; - gint l, r, t, b; gint px, py; Rect *area; + if (config_place_policy != OB_PLACE_POLICY_MOUSE) + return FALSE; + ob_debug("placing under mouse"); if (!screen_pointer_pos(&px, &py)) @@ -295,25 +295,8 @@ static gboolean place_per_app_setting_position(ObClient *client, Rect *screen, ob_debug("placing by per-app settings"); - if (settings->position.x.center) - *x = screen->x + screen->width / 2 - client->area.width / 2; - else if (settings->position.x.opposite) - *x = screen->x + screen->width - frame_size.width - - settings->position.x.pos; - else - *x = screen->x + settings->position.x.pos; - if (settings->position.x.denom) - *x = (*x * screen->width) / settings->position.x.denom; - - if (settings->position.y.center) - *y = screen->y + screen->height / 2 - client->area.height / 2; - else if (settings->position.y.opposite) - *y = screen->y + screen->height - frame_size.height - - settings->position.y.pos; - else - *y = screen->y + settings->position.y.pos; - if (settings->position.y.denom) - *y = (*y * screen->height) / settings->position.y.denom; + screen_apply_gravity_point(x, y, frame_size.width, frame_size.height, + &settings->position, screen); return TRUE; } @@ -377,11 +360,11 @@ static gboolean place_transient_splash(ObClient *client, Rect *area, b = MAX(b, RECT_BOTTOM(m->frame->area)); } } - if (!first) { - *x = ((r + 1 - l) - frame_size.width) / 2 + l; - *y = ((b + 1 - t) - frame_size.height) / 2 + t; - return TRUE; - } + } + if (!first) { + *x = ((r + 1 - l) - frame_size.width) / 2 + l; + *y = ((b + 1 - t) - frame_size.height) / 2 + t; + return TRUE; } } @@ -406,8 +389,19 @@ static gboolean place_least_overlap(ObClient *c, Rect *head, int *x, int *y, GSList* potential_overlap_clients = NULL; gint n_client_rects = config_dock_hide ? 0 : 1; - /* if we're "showing desktop", ignore all existing windows */ - if (!screen_showing_desktop) { + /* If we're "showing desktop", and going to allow this window to + be shown now, then ignore all existing windows */ + gboolean ignore_windows = FALSE; + switch (screen_show_desktop_mode) { + case SCREEN_SHOW_DESKTOP_NO: + case SCREEN_SHOW_DESKTOP_UNTIL_WINDOW: + break; + case SCREEN_SHOW_DESKTOP_UNTIL_TOGGLE: + ignore_windows = TRUE; + break; + } + + if (!ignore_windows) { GList* it; for (it = client_list; it != NULL; it = g_list_next(it)) { ObClient* maybe_client = (ObClient*)it->data; @@ -432,24 +426,27 @@ static gboolean place_least_overlap(ObClient *c, Rect *head, int *x, int *y, n_client_rects += 1; } } - Rect client_rects[n_client_rects]; - - GSList* it; - guint i = 0; - if (!config_dock_hide) - dock_get_area(&client_rects[i++]); - for (it = potential_overlap_clients; it != NULL; it = g_slist_next(it)) { - ObClient* potential_overlap_client = (ObClient*)it->data; - client_rects[i] = potential_overlap_client->frame->area; - i += 1; - } - g_slist_free(potential_overlap_clients); - Point result; - place_overlap_find_least_placement(client_rects, n_client_rects, head, - &frame_size, &result); - *x = result.x; - *y = result.y; + if (n_client_rects) { + Rect client_rects[n_client_rects]; + GSList* it; + Point result; + guint i = 0; + + if (!config_dock_hide) + dock_get_area(&client_rects[i++]); + for (it = potential_overlap_clients; it != NULL; it = g_slist_next(it)) { + ObClient* potential_overlap_client = (ObClient*)it->data; + client_rects[i] = potential_overlap_client->frame->area; + i += 1; + } + g_slist_free(potential_overlap_clients); + + place_overlap_find_least_placement(client_rects, n_client_rects, head, + &frame_size, &result); + *x = result.x; + *y = result.y; + } return TRUE; } diff --git a/openbox/place.h b/openbox/place.h index 3bc679e0..792fc387 100644 --- a/openbox/place.h +++ b/openbox/place.h @@ -38,7 +38,8 @@ typedef enum OB_PLACE_MONITOR_ANY, OB_PLACE_MONITOR_ACTIVE, OB_PLACE_MONITOR_MOUSE, - OB_PLACE_MONITOR_PRIMARY + OB_PLACE_MONITOR_PRIMARY, + OB_PLACE_MONITOR_ALL } ObPlaceMonitor; /*! Return TRUE if openbox chose the position for the window, and FALSE if diff --git a/openbox/place_overlap.c b/openbox/place_overlap.c index ac7255bf..ed7ff6c0 100644 --- a/openbox/place_overlap.c +++ b/openbox/place_overlap.c @@ -19,7 +19,9 @@ #include "config.h" #include "geom.h" #include "place_overlap.h" +#include "obt/bsearch.h" +#include <glib.h> #include <stdlib.h> static void make_grid(const Rect* client_rects, @@ -170,29 +172,23 @@ static int total_overlap(const Rect* client_rects, return overlap; } -/* Unfortunately, the libc bsearch() function cannot be used to find the - position of a value that is not in the array, and glib doesn't - provide a binary search function at all. So, tricky as it is, if we - want to avoid linear scan of the edge array, we have to roll our - own. */ -static int grid_position(int value, - const int* edges, - int max_edges) +static int find_first_grid_position_greater_or_equal(int search_value, + const int* edges, + int max_edges) { - int low = 0; - int high = max_edges - 1; - int mid = low + (high - low) / 2; - while (low != mid) { - if (value < edges[mid]) - high = mid; - else if (value > edges[mid]) - low = mid; - else /* value == edges[mid] */ - return mid; - mid = low + (high - low) / 2; - } - /* we get here when low == mid. can have low == high or low == high - 1 */ - return (value <= edges[low] ? low : high); + g_assert(max_edges >= 2); + g_assert(search_value >= edges[0]); + g_assert(search_value <= edges[max_edges - 1]); + + BSEARCH_SETUP(); + BSEARCH(int, edges, 0, max_edges, search_value); + + if (BSEARCH_FOUND()) + return BSEARCH_AT(); + + g_assert(BSEARCH_FOUND_NEAREST_SMALLER()); + /* Get the nearest larger instead. */ + return BSEARCH_AT() + 1; } static void expand_width(Rect* r, int by) @@ -263,9 +259,11 @@ static void center_in_field(Point* top_left, { /* Find minimal rectangle. */ int orig_right_edge_index = - grid_position(top_left->x + req_size->width, x_edges, max_edges); + find_first_grid_position_greater_or_equal( + top_left->x + req_size->width, x_edges, max_edges); int orig_bottom_edge_index = - grid_position(top_left->y + req_size->height, y_edges, max_edges); + find_first_grid_position_greater_or_equal( + top_left->y + req_size->height, y_edges, max_edges); ExpandInfo i = { .top_left = top_left, .orig_width = x_edges[orig_right_edge_index] - top_left->x, diff --git a/openbox/screen.c b/openbox/screen.c index 9295194e..e758ada1 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -57,15 +57,15 @@ static gboolean replace_wm(void); static void screen_tell_ksplash(void); static void screen_fallback_focus(void); -guint screen_num_desktops; -guint screen_num_monitors; -guint screen_desktop; -guint screen_last_desktop; -gboolean screen_showing_desktop; -ObDesktopLayout screen_desktop_layout; -gchar **screen_desktop_names; -Window screen_support_win; -Time screen_desktop_user_time = CurrentTime; +guint screen_num_desktops; +guint screen_num_monitors; +guint screen_desktop; +guint screen_last_desktop; +ObScreenShowDestopMode screen_show_desktop_mode; +ObDesktopLayout screen_desktop_layout; +gchar **screen_desktop_names; +Window screen_support_win; +Time screen_desktop_user_time = CurrentTime; static Size screen_physical_size; static guint screen_old_desktop; @@ -445,9 +445,9 @@ void screen_startup(gboolean reconfig) screen_last_desktop = screen_desktop; /* don't start in showing-desktop mode */ - screen_showing_desktop = FALSE; + screen_show_desktop_mode = SCREEN_SHOW_DESKTOP_NO; OBT_PROP_SET32(obt_root(ob_screen), - NET_SHOWING_DESKTOP, CARDINAL, screen_showing_desktop); + NET_SHOWING_DESKTOP, CARDINAL, screen_showing_desktop()); if (session_desktop_layout_present && screen_validate_layout(&session_desktop_layout)) @@ -1218,15 +1218,33 @@ void screen_update_desktop_names(void) screen_num_desktops); } -void screen_show_desktop(gboolean show, ObClient *show_only) +void screen_show_desktop(ObScreenShowDestopMode show_mode, ObClient *show_only) { GList *it; - if (show == screen_showing_desktop) return; /* no change */ + ObScreenShowDestopMode before_mode = screen_show_desktop_mode; - screen_showing_desktop = show; + gboolean showing_before = screen_showing_desktop(); + screen_show_desktop_mode = show_mode; + gboolean showing_after = screen_showing_desktop(); - if (show) { + if (showing_before == showing_after) { + /* No change. */ + screen_show_desktop_mode = before_mode; + return; + } + + if (screen_show_desktop_mode == SCREEN_SHOW_DESKTOP_UNTIL_TOGGLE && + show_only != NULL) + { + /* If we're showing the desktop until the show-mode is toggled, we + don't allow breaking out of showing-desktop mode unless we're + showing all the windows again. */ + screen_show_desktop_mode = before_mode; + return; + } + + if (showing_after) { /* hide windows bottom to top */ for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) { if (WINDOW_IS_CLIENT(it->data)) { @@ -1250,7 +1268,7 @@ void screen_show_desktop(gboolean show, ObClient *show_only) } } - if (show) { + if (showing_after) { /* focus the desktop */ for (it = focus_order; it; it = g_list_next(it)) { ObClient *c = it->data; @@ -1275,8 +1293,23 @@ void screen_show_desktop(gboolean show, ObClient *show_only) } } - show = !!show; /* make it boolean */ - OBT_PROP_SET32(obt_root(ob_screen), NET_SHOWING_DESKTOP, CARDINAL, show); + OBT_PROP_SET32(obt_root(ob_screen), + NET_SHOWING_DESKTOP, + CARDINAL, + !!showing_after); +} + +gboolean screen_showing_desktop() +{ + switch (screen_show_desktop_mode) { + case SCREEN_SHOW_DESKTOP_NO: + return FALSE; + case SCREEN_SHOW_DESKTOP_UNTIL_WINDOW: + case SCREEN_SHOW_DESKTOP_UNTIL_TOGGLE: + return TRUE; + } + g_assert_not_reached(); + return FALSE; } void screen_install_colormap(ObClient *client, gboolean install) @@ -1648,7 +1681,7 @@ guint screen_find_monitor(const Rect *search) { guint i; guint mostpx_index = screen_num_monitors; - guint mostpx = 0; + glong mostpx = 0; guint closest_distance_index = screen_num_monitors; guint closest_distance = G_MAXUINT; GSList *counted = NULL; @@ -1895,3 +1928,30 @@ gboolean screen_compare_desktops(guint a, guint b) b = screen_desktop; return a == b; } + +void screen_apply_gravity_point(gint *x, gint *y, gint width, gint height, + const GravityPoint *position, const Rect *area) +{ + if (position->x.center) + *x = area->width / 2 - width / 2; + else { + *x = position->x.pos; + if (position->x.denom) + *x = (*x * area->width) / position->x.denom; + if (position->x.opposite) + *x = area->width - width - *x; + } + + if (position->y.center) + *y = area->height / 2 - height / 2; + else { + *y = position->y.pos; + if (position->y.denom) + *y = (*y * area->height) / position->y.denom; + if (position->y.opposite) + *y = area->height - height - *y; + } + + *x += area->x; + *y += area->y; +} diff --git a/openbox/screen.h b/openbox/screen.h index a6a3995b..6c26ce89 100644 --- a/openbox/screen.h +++ b/openbox/screen.h @@ -26,6 +26,12 @@ struct _ObClient; #define DESKTOP_ALL (0xffffffff) +typedef enum { + SCREEN_SHOW_DESKTOP_NO, + SCREEN_SHOW_DESKTOP_UNTIL_WINDOW, + SCREEN_SHOW_DESKTOP_UNTIL_TOGGLE +} ObScreenShowDestopMode; + /*! The number of available desktops */ extern guint screen_num_desktops; /*! The number of virtual "xinerama" screens/heads */ @@ -35,7 +41,7 @@ extern guint screen_desktop; /*! The desktop which was last visible */ extern guint screen_last_desktop; /*! Are we in showing-desktop mode? */ -extern gboolean screen_showing_desktop; +extern ObScreenShowDestopMode screen_show_desktop_mode; /*! The support window also used for focus and stacking */ extern Window screen_support_win; /*! The last time at which the user changed desktops */ @@ -90,7 +96,11 @@ void screen_hide_desktop_popup(void); show is FALSE (restoring from show-desktop mode), and the rest are iconified. */ -void screen_show_desktop(gboolean show, struct _ObClient *show_only); +void screen_show_desktop(ObScreenShowDestopMode show_mode, + struct _ObClient *show_only); + +/*! Returns true if showing desktop mode is enabled. */ +gboolean screen_showing_desktop(); /*! Updates the desktop layout from the root property if available */ void screen_update_layout(void); @@ -172,4 +182,9 @@ guint screen_monitor_pointer(void); */ gboolean screen_compare_desktops(guint a, guint b); +/*! Resolve a gravity point into absolute coordinates. + * width and height are the size of the object being placed, used for + * aligning to right/bottom edges of the area. */ +void screen_apply_gravity_point(gint *x, gint *y, gint width, gint height, + const GravityPoint *position, const Rect *area); #endif diff --git a/openbox/stacking.c b/openbox/stacking.c index 58551b5d..0ef900aa 100644 --- a/openbox/stacking.c +++ b/openbox/stacking.c @@ -26,6 +26,8 @@ #include "window.h" #include "event.h" #include "debug.h" +#include "dock.h" +#include "config.h" #include "obt/prop.h" GList *stacking_list = NULL; @@ -567,14 +569,18 @@ void stacking_add_nonintrusive(ObWindow *win) /*! Returns TRUE if client is occluded by the sibling. If sibling is NULL it tries against all other clients. */ -static gboolean stacking_occluded(ObClient *client, ObClient *sibling) +static gboolean stacking_occluded(ObClient *client, ObWindow *sibling_win) { GList *it; gboolean occluded = FALSE; + ObClient *sibling = NULL; + + if (sibling_win && WINDOW_IS_CLIENT(sibling_win)) + sibling = WINDOW_AS_CLIENT(sibling_win); /* no need for any looping in this case */ if (sibling && client->layer != sibling->layer) - return occluded; + return FALSE; for (it = g_list_previous(g_list_find(stacking_list, client)); it; it = g_list_previous(it)) @@ -601,6 +607,21 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling) break; /* we past its layer */ } } + } else if (WINDOW_IS_DOCK(it->data)) { + ObDock *dock = it->data; + if (RECT_INTERSECTS_RECT(dock->area, client->frame->area)) + { + if (sibling_win != NULL) { + if (DOCK_AS_WINDOW(dock) == sibling_win) { + occluded = TRUE; + break; + } + } + else if (config_dock_layer == client->layer) { + occluded = TRUE; + break; + } + } } return occluded; } @@ -608,14 +629,18 @@ static gboolean stacking_occluded(ObClient *client, ObClient *sibling) /*! Returns TRUE if client occludes the sibling. If sibling is NULL it tries against all other clients. */ -static gboolean stacking_occludes(ObClient *client, ObClient *sibling) +static gboolean stacking_occludes(ObClient *client, ObWindow *sibling_win) { GList *it; gboolean occludes = FALSE; + ObClient *sibling = NULL; + + if (sibling_win && WINDOW_IS_CLIENT(sibling_win)) + sibling = WINDOW_AS_CLIENT(sibling_win); /* no need for any looping in this case */ if (sibling && client->layer != sibling->layer) - return occludes; + return FALSE; for (it = g_list_next(g_list_find(stacking_list, client)); it; it = g_list_next(it)) @@ -643,14 +668,35 @@ static gboolean stacking_occludes(ObClient *client, ObClient *sibling) } } } + else if (WINDOW_IS_DOCK(it->data)) { + ObDock *dock = it->data; + if (RECT_INTERSECTS_RECT(dock->area, client->frame->area)) + { + if (sibling_win != NULL) { + if (DOCK_AS_WINDOW(dock) == sibling_win) { + occludes = TRUE; + break; + } + } + else if (config_dock_layer == client->layer) { + occludes = TRUE; + break; + } + } + } return occludes; } -gboolean stacking_restack_request(ObClient *client, ObClient *sibling, +gboolean stacking_restack_request(ObClient *client, ObWindow *sibling_win, gint detail) { gboolean ret = FALSE; + ObClient *sibling = NULL; + + if (sibling_win && WINDOW_IS_CLIENT(sibling_win)) + sibling = WINDOW_AS_CLIENT(sibling_win); + if (sibling && ((client->desktop != sibling->desktop && client->desktop != DESKTOP_ALL && sibling->desktop != DESKTOP_ALL) || @@ -674,7 +720,7 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling, client->title, sibling ? sibling->title : "(all)"); /* if this client occludes sibling (or anything if NULL), then lower it to the bottom */ - if (stacking_occludes(client, sibling)) { + if (stacking_occludes(client, sibling_win)) { stacking_lower(CLIENT_AS_WINDOW(client)); ret = TRUE; } @@ -688,7 +734,7 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling, case TopIf: ob_debug("Restack request TopIf for client %s sibling %s", client->title, sibling ? sibling->title : "(all)"); - if (stacking_occluded(client, sibling)) { + if (stacking_occluded(client, sibling_win)) { stacking_raise(CLIENT_AS_WINDOW(client)); ret = TRUE; } @@ -696,11 +742,11 @@ gboolean stacking_restack_request(ObClient *client, ObClient *sibling, case Opposite: ob_debug("Restack request Opposite for client %s sibling %s", client->title, sibling ? sibling->title : "(all)"); - if (stacking_occluded(client, sibling)) { + if (stacking_occluded(client, sibling_win)) { stacking_raise(CLIENT_AS_WINDOW(client)); ret = TRUE; } - else if (stacking_occludes(client, sibling)) { + else if (stacking_occludes(client, sibling_win)) { stacking_lower(CLIENT_AS_WINDOW(client)); ret = TRUE; } diff --git a/openbox/stacking.h b/openbox/stacking.h index c14aa2ed..ebfa1755 100644 --- a/openbox/stacking.h +++ b/openbox/stacking.h @@ -71,7 +71,7 @@ void stacking_below(struct _ObWindow *window, struct _ObWindow *below); /*! Restack a window based upon a sibling (or all windows) in various ways. @param client The client to be restacked - @param sibling Another client to compare to, or NULL to compare to all + @param sibling A window to compare to, or NULL to compare to all windows @param detail One of Above, Below, TopIf, BottomIf, Opposite @return TRUE if the client was restacked @@ -79,7 +79,7 @@ void stacking_below(struct _ObWindow *window, struct _ObWindow *below); how each detail works with and without a sibling. */ gboolean stacking_restack_request(struct _ObClient *client, - struct _ObClient *sibling, + struct _ObWindow *sibling_win, gint detail); #endif |
