/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
action.c for the Openbox window manager
- Copyright (c) 2003 Ben Jansens
+ Copyright (c) 2006 Mikael Magnusson
+ Copyright (c) 2003-2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "debug.h"
#include "client.h"
#include "focus.h"
+#include "focus_cycle.h"
#include "moveresize.h"
#include "menu.h"
#include "prop.h"
#include "dock.h"
#include "config.h"
#include "mainloop.h"
+#include "startupnotify.h"
+#include "gettext.h"
#include <glib.h>
-inline void client_action_start(union ActionData *data)
+static void client_action_start(union ActionData *data)
{
- if (config_focus_follow)
- if (data->any.context != OB_FRAME_CONTEXT_CLIENT && !data->any.button)
- grab_pointer(TRUE, OB_CURSOR_NONE);
}
-inline void client_action_end(union ActionData *data)
+static void client_action_end(union ActionData *data)
{
if (config_focus_follow)
if (data->any.context != OB_FRAME_CONTEXT_CLIENT) {
- if (!data->any.button) {
- grab_pointer(FALSE, OB_CURSOR_NONE);
- } else {
- ObClient *c;
-
- /* usually this is sorta redundant, but with a press action
- the enter event will come as a GrabNotify which is
- ignored, so this will handle that case */
- if ((c = client_under_pointer()))
- event_enter_client(c);
+ if (!data->any.button && data->any.c)
+ event_ignore_all_queued_enters();
+ else {
+ /* we USED to create a fake enter event here, so that when you
+ used a Press context, and the button was still down,
+ you could still get enter events that weren't
+ NotifyWhileGrabbed.
+
+ only problem with this is that then the resulting focus
+ change events can ALSO be NotifyWhileGrabbed. And that is
+ bad. So, don't create fake enter events anymore. */
}
}
}
/* deal with pointers */
if (a->func == action_execute || a->func == action_restart)
g_free(a->data.execute.path);
+ else if (a->func == action_debug)
+ g_free(a->data.debug.string);
else if (a->func == action_showmenu)
g_free(a->data.showmenu.name);
/* deal with pointers */
if (a->func == action_execute || a->func == action_restart)
a->data.execute.path = g_strdup(a->data.execute.path);
+ else if (a->func == action_debug)
+ a->data.debug.string = g_strdup(a->data.debug.string);
else if (a->func == action_showmenu)
a->data.showmenu.name = g_strdup(a->data.showmenu.name);
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
(*a)->data.interdiraction.dialog = TRUE;
+ (*a)->data.interdiraction.dock_windows = FALSE;
+ (*a)->data.interdiraction.desktop_windows = FALSE;
}
void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
void setup_action_desktop(ObAction **a, ObUserAction uact)
{
+/*
(*a)->data.desktop.inter.any.interactive = FALSE;
+*/
}
void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = TRUE;
(*a)->data.cycle.dialog = TRUE;
+ (*a)->data.cycle.dock_windows = FALSE;
+ (*a)->data.cycle.desktop_windows = FALSE;
+ (*a)->data.cycle.all_desktops = FALSE;
}
void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = FALSE;
(*a)->data.cycle.dialog = TRUE;
+ (*a)->data.cycle.dock_windows = FALSE;
+ (*a)->data.cycle.desktop_windows = FALSE;
+ (*a)->data.cycle.all_desktops = FALSE;
+}
+
+void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
+{
+ (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
+ (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
+ (*a)->data.diraction.hang = TRUE;
+}
+
+void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
+{
+ (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
+ (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
+ (*a)->data.diraction.hang = TRUE;
+}
+
+void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
+{
+ (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
+ (*a)->data.diraction.direction = OB_DIRECTION_EAST;
+ (*a)->data.diraction.hang = TRUE;
+}
+
+void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
+{
+ (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
+ (*a)->data.diraction.direction = OB_DIRECTION_WEST;
+ (*a)->data.diraction.hang = TRUE;
}
void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
{
(*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
(*a)->data.diraction.direction = OB_DIRECTION_NORTH;
+ (*a)->data.diraction.hang = FALSE;
}
void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
{
(*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
(*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
+ (*a)->data.diraction.hang = FALSE;
}
void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
{
(*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
(*a)->data.diraction.direction = OB_DIRECTION_EAST;
+ (*a)->data.diraction.hang = FALSE;
}
void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
{
(*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
(*a)->data.diraction.direction = OB_DIRECTION_WEST;
+ (*a)->data.diraction.hang = FALSE;
}
void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
void setup_action_move(ObAction **a, ObUserAction uact)
{
(*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
- (*a)->data.moveresize.move = TRUE;
(*a)->data.moveresize.keyboard =
(uact == OB_USER_ACTION_NONE ||
uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
+ (*a)->data.moveresize.corner = 0;
}
void setup_action_resize(ObAction **a, ObUserAction uact)
{
(*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
- (*a)->data.moveresize.move = FALSE;
(*a)->data.moveresize.keyboard =
(uact == OB_USER_ACTION_NONE ||
uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
+ (*a)->data.moveresize.corner = 0;
}
void setup_action_showmenu(ObAction **a, ObUserAction uact)
}
}
+void setup_action_focus(ObAction **a, ObUserAction uact)
+{
+ (*a)->data.any.client_action = OB_CLIENT_ACTION_OPTIONAL;
+}
+
void setup_client_action(ObAction **a, ObUserAction uact)
{
(*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
ActionString actionstrings[] =
{
+ {
+ "debug",
+ action_debug,
+ NULL
+ },
{
"execute",
- action_execute,
+ action_execute,
NULL
},
{
{
"activate",
action_activate,
- setup_client_action
+ setup_action_focus
},
{
"focus",
action_focus,
- setup_client_action
+ setup_action_focus
},
{
"unfocus",
},
{
"move",
- action_moveresize,
+ action_move,
setup_action_move
},
{
"resize",
- action_moveresize,
+ action_resize,
setup_action_resize
},
{
action_cycle_windows,
setup_action_cycle_windows_previous
},
+ {
+ "movefromedgenorth",
+ action_movetoedge,
+ setup_action_movefromedge_north
+ },
+ {
+ "movefromedgesouth",
+ action_movetoedge,
+ setup_action_movefromedge_south
+ },
+ {
+ "movefromedgewest",
+ action_movetoedge,
+ setup_action_movefromedge_west
+ },
+ {
+ "movefromedgeeast",
+ action_movetoedge,
+ setup_action_movefromedge_east
+ },
{
"movetoedgenorth",
action_movetoedge,
action_growtoedge,
setup_action_growtoedge_east
},
+ {
+ "breakchroot",
+ action_break_chroot,
+ NULL
+ },
{
NULL,
NULL,
break;
}
if (!exist)
- g_warning("Invalid action '%s' requested. No such action exists.",
+ g_message(_("Invalid action '%s' requested. No such action exists."),
name);
if (!a)
- g_warning("Invalid use of action '%s'. Action will be ignored.", name);
+ g_message(_("Invalid use of action '%s'. Action will be ignored."),
+ name);
return a;
}
act->data.execute.path = parse_expand_tilde(s);
g_free(s);
}
+ if ((n = parse_find_node("startupnotify", node->xmlChildrenNode))) {
+ xmlNodePtr m;
+ if ((m = parse_find_node("enabled", n->xmlChildrenNode)))
+ act->data.execute.startupnotify = parse_bool(doc, m);
+ if ((m = parse_find_node("name", n->xmlChildrenNode)))
+ act->data.execute.name = parse_string(doc, m);
+ if ((m = parse_find_node("icon", n->xmlChildrenNode)))
+ act->data.execute.icon_name = parse_string(doc, m);
+ }
+ } else if (act->func == action_debug) {
+ if ((n = parse_find_node("string", node->xmlChildrenNode)))
+ act->data.debug.string = parse_string(doc, n);
} else if (act->func == action_showmenu) {
if ((n = parse_find_node("menu", node->xmlChildrenNode)))
act->data.showmenu.name = parse_string(doc, n);
if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
act->data.desktop.desk = parse_int(doc, n);
if (act->data.desktop.desk > 0) act->data.desktop.desk--;
+/*
if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
act->data.desktop.inter.any.interactive =
parse_bool(doc, n);
+*/
} else if (act->func == action_send_to_desktop) {
if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
act->data.sendto.desk = parse_int(doc, n);
act->data.cycle.linear = parse_bool(doc, n);
if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
act->data.cycle.dialog = parse_bool(doc, n);
+ if ((n = parse_find_node("panels", node->xmlChildrenNode)))
+ act->data.cycle.dock_windows = parse_bool(doc, n);
+ if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
+ act->data.cycle.desktop_windows = parse_bool(doc, n);
+ if ((n = parse_find_node("allDesktops",
+ node->xmlChildrenNode)))
+ act->data.cycle.all_desktops = parse_bool(doc, n);
} else if (act->func == action_directional_focus) {
if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
- act->data.cycle.dialog = parse_bool(doc, n);
+ act->data.interdiraction.dialog = parse_bool(doc, n);
+ if ((n = parse_find_node("panels", node->xmlChildrenNode)))
+ act->data.interdiraction.dock_windows = parse_bool(doc, n);
+ if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
+ act->data.interdiraction.desktop_windows =
+ parse_bool(doc, n);
+ } else if (act->func == action_resize) {
+ if ((n = parse_find_node("edge", node->xmlChildrenNode))) {
+ gchar *s = parse_string(doc, n);
+ if (!g_ascii_strcasecmp(s, "top"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_top;
+ else if (!g_ascii_strcasecmp(s, "bottom"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_bottom;
+ else if (!g_ascii_strcasecmp(s, "left"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_left;
+ else if (!g_ascii_strcasecmp(s, "right"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_right;
+ else if (!g_ascii_strcasecmp(s, "topleft"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_topleft;
+ else if (!g_ascii_strcasecmp(s, "topright"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_topright;
+ else if (!g_ascii_strcasecmp(s, "bottomleft"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_bottomleft;
+ else if (!g_ascii_strcasecmp(s, "bottomright"))
+ act->data.moveresize.corner =
+ prop_atoms.net_wm_moveresize_size_bottomright;
+ g_free(s);
+ }
} else if (act->func == action_raise ||
act->func == action_lower ||
act->func == action_raiselower ||
act->func == action_shadelower ||
act->func == action_unshaderaise) {
- if ((n = parse_find_node("group", node->xmlChildrenNode)))
- act->data.stacking.group = parse_bool(doc, n);
}
INTERACTIVE_LIMIT(act, uact);
}
}
void action_run_list(GSList *acts, ObClient *c, ObFrameContext context,
- guint state, guint button, gint x, gint y,
+ guint state, guint button, gint x, gint y, Time time,
gboolean cancel, gboolean done)
{
GSList *it;
ObAction *a;
- gboolean inter = FALSE;
if (!acts)
return;
if (x < 0 && y < 0)
screen_pointer_pos(&x, &y);
- if (grab_on_keyboard())
- inter = TRUE;
- else
- for (it = acts; it; it = g_slist_next(it)) {
- a = it->data;
- if (a->data.any.interactive) {
- inter = TRUE;
- break;
- }
- }
-
- if (!inter) {
- /* sometimes when we execute another app as an action,
- it won't work right unless we XUngrabKeyboard first,
- even though we grabbed the key/button Asychronously.
- e.g. "gnome-panel-control --main-menu" */
- XUngrabKeyboard(ob_display, event_lasttime);
- }
-
for (it = acts; it; it = g_slist_next(it)) {
a = it->data;
a->data.any.button = button;
+ a->data.any.time = time;
+
if (a->data.any.interactive) {
a->data.inter.cancel = cancel;
a->data.inter.final = done;
/* XXX UGLY HACK race with motion event starting a move and the
button release gettnig processed first. answer: don't queue
- moveresize starts. UGLY HACK XXX */
- if (a->data.any.interactive || a->func == action_moveresize) {
+ moveresize starts. UGLY HACK XXX
+
+ XXX ALSO don't queue showmenu events, because on button press
+ events we need to know if a mouse grab is going to take place,
+ and set the button to 0, so that later motion events don't think
+ that a drag is going on. since showmenu grabs the pointer..
+ */
+ if (a->data.any.interactive || a->func == action_move ||
+ a->func == action_resize || a->func == action_showmenu)
+ {
/* interactive actions are not queued */
a->func(&a->data);
+ } else if (c &&
+ (context == OB_FRAME_CONTEXT_CLIENT ||
+ (c->type == OB_CLIENT_TYPE_DESKTOP &&
+ context == OB_FRAME_CONTEXT_DESKTOP)) &&
+ (a->func == action_focus ||
+ a->func == action_activate ||
+ a->func == action_showmenu))
+ {
+ /* XXX MORE UGLY HACK
+ actions from clicks on client windows are NOT queued.
+ this solves the mysterious click-and-drag-doesnt-work
+ problem. it was because the window gets focused and stuff
+ after the button event has already been passed through. i
+ dont really know why it should care but it does and it makes
+ a difference.
+
+ however this very bogus ! !
+ we want to send the button press to the window BEFORE
+ we do the action because the action might move the windows
+ (eg change desktops) and then the button press ends up on
+ the completely wrong window !
+ so, this is just for that bug, and it will only NOT queue it
+ if it is a focusing action that can be used with the mouse
+ pointer. ugh.
+
+ also with the menus, there is a race going on. if the
+ desktop wants to pop up a menu, and we do to, we send them
+ the button before we pop up the menu, so they pop up their
+ menu first. but not always. if we pop up our menu before
+ sending them the button press, then the result is
+ deterministic. yay.
+ */
+ a->func(&a->data);
} else
ob_main_loop_queue_action(ob_main_loop, a);
}
}
}
-void action_run_string(const gchar *name, struct _ObClient *c)
+void action_run_string(const gchar *name, struct _ObClient *c, Time time)
{
ObAction *a;
GSList *l;
l = g_slist_append(NULL, a);
- action_run(l, c, 0);
+ action_run(l, c, 0, time);
+}
+
+void action_debug(union ActionData *data)
+{
+ if (data->debug.string)
+ g_print("%s\n", data->debug.string);
}
void action_execute(union ActionData *data)
if (data->execute.path) {
cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
if (cmd) {
+ /* If there is an interactive action going on, then cancel it
+ to release the keyboard, so that the run application
+ can grab the keyboard if it wants to. */
+ if (keyboard_interactively_grabbed())
+ keyboard_interactive_cancel();
+
if (!g_shell_parse_argv (cmd, NULL, &argv, &e)) {
- g_warning("failed to execute '%s': %s",
+ g_message(_("Failed to execute '%s': %s"),
cmd, e->message);
g_error_free(e);
- } else {
+ } else if (data->execute.startupnotify) {
+ gchar *program;
+
+ program = g_path_get_basename(argv[0]);
+ /* sets up the environment */
+ sn_setup_spawn_environment(program,
+ data->execute.name,
+ data->execute.icon_name,
+ /* launch it on the current
+ desktop */
+ screen_desktop,
+ data->execute.any.time);
if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, NULL, &e)) {
- g_warning("failed to execute '%s': %s",
+ g_message(_("Failed to execute '%s': %s"),
+ cmd, e->message);
+ g_error_free(e);
+ sn_spawn_cancel();
+ }
+ unsetenv("DESKTOP_STARTUP_ID");
+ g_free(program);
+ g_strfreev(argv);
+ } else {
+ if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, NULL, &e))
+ {
+ g_message(_("Failed to execute '%s': %s"),
cmd, e->message);
g_error_free(e);
}
}
g_free(cmd);
} else {
- g_warning("failed to convert '%s' from utf8", data->execute.path);
+ g_message(_("Failed to convert the path '%s' from utf8"),
+ data->execute.path);
}
}
}
void action_activate(union ActionData *data)
{
- client_activate(data->activate.any.c, data->activate.here);
+ if (data->client.any.c) {
+ if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
+ (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
+ data->any.context != OB_FRAME_CONTEXT_FRAME))
+ {
+ /* if using focus_delay, stop the timer now so that focus doesn't
+ go moving on us */
+ event_halt_focus_delay();
+
+ client_activate(data->activate.any.c, data->activate.here, TRUE);
+ }
+ } else {
+ /* focus action on something other than a client, make keybindings
+ work for this openbox instance, but don't focus any specific client
+ */
+ focus_nothing();
+ }
}
void action_focus(union ActionData *data)
{
- /* if using focus_delay, stop the timer now so that focus doesn't go moving
- on us */
- event_halt_focus_delay();
+ if (data->client.any.c) {
+ if (!data->any.button || client_mouse_focusable(data->client.any.c) ||
+ (data->any.context != OB_FRAME_CONTEXT_CLIENT &&
+ data->any.context != OB_FRAME_CONTEXT_FRAME))
+ {
+ /* if using focus_delay, stop the timer now so that focus doesn't
+ go moving on us */
+ event_halt_focus_delay();
- client_focus(data->client.any.c);
+ client_focus(data->client.any.c);
+ }
+ } else {
+ /* focus action on something other than a client, make keybindings
+ work for this openbox instance, but don't focus any specific client
+ */
+ focus_nothing();
+ }
}
void action_unfocus (union ActionData *data)
{
- if (data->client.any.c == focus_client);
- focus_fallback(OB_FOCUS_FALLBACK_UNFOCUSING);
+ if (data->client.any.c == focus_client)
+ focus_fallback(FALSE);
}
void action_iconify(union ActionData *data)
{
client_action_start(data);
- client_iconify(data->client.any.c, TRUE, TRUE);
+ client_iconify(data->client.any.c, TRUE, TRUE, FALSE);
client_action_end(data);
}
if (cit == c) break;
if (client_normal(cit) == client_normal(c) &&
- cit->layer == c->layer &&
- cit->frame->visible &&
- !client_search_transient(c, cit))
+ cit->layer == c->layer &&
+ cit->frame->visible &&
+ !client_search_transient(c, cit))
{
if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
raise = TRUE;
void action_raise(union ActionData *data)
{
client_action_start(data);
- stacking_raise(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
+ stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
client_action_end(data);
}
void action_lower(union ActionData *data)
{
client_action_start(data);
- stacking_lower(CLIENT_AS_WINDOW(data->client.any.c), data->stacking.group);
+ stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
client_action_end(data);
}
void action_resize_relative(union ActionData *data)
{
ObClient *c = data->relative.any.c;
+ gint x, y, ow, w, oh, h, lw, lh;
+
client_action_start(data);
- client_move_resize(c,
- c->area.x - data->relative.deltaxl * c->size_inc.width,
- c->area.y - data->relative.deltayu * c->size_inc.height,
- c->area.width + data->relative.deltax * c->size_inc.width
- + data->relative.deltaxl * c->size_inc.width,
- c->area.height + data->relative.deltay * c->size_inc.height
- + data->relative.deltayu * c->size_inc.height);
+
+ x = c->area.x;
+ y = c->area.y;
+ ow = c->area.width;
+ w = ow + data->relative.deltax * c->size_inc.width
+ + data->relative.deltaxl * c->size_inc.width;
+ oh = c->area.height;
+ h = oh + data->relative.deltay * c->size_inc.height
+ + data->relative.deltayu * c->size_inc.height;
+
+ client_try_configure(c, &x, &y, &w, &h, &lw, &lh, TRUE);
+ client_move_resize(c, x + (ow - w), y + (oh - h), w, h);
client_action_end(data);
}
void action_maximize_full(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, TRUE, 0, TRUE);
+ client_maximize(data->client.any.c, TRUE, 0);
client_action_end(data);
}
void action_unmaximize_full(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, FALSE, 0, TRUE);
+ client_maximize(data->client.any.c, FALSE, 0);
client_action_end(data);
}
client_maximize(data->client.any.c,
!(data->client.any.c->max_horz ||
data->client.any.c->max_vert),
- 0, TRUE);
+ 0);
client_action_end(data);
}
void action_maximize_horz(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, TRUE, 1, TRUE);
+ client_maximize(data->client.any.c, TRUE, 1);
client_action_end(data);
}
void action_unmaximize_horz(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, FALSE, 1, TRUE);
+ client_maximize(data->client.any.c, FALSE, 1);
client_action_end(data);
}
{
client_action_start(data);
client_maximize(data->client.any.c,
- !data->client.any.c->max_horz, 1, TRUE);
+ !data->client.any.c->max_horz, 1);
client_action_end(data);
}
void action_maximize_vert(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, TRUE, 2, TRUE);
+ client_maximize(data->client.any.c, TRUE, 2);
client_action_end(data);
}
void action_unmaximize_vert(union ActionData *data)
{
client_action_start(data);
- client_maximize(data->client.any.c, FALSE, 2, TRUE);
+ client_maximize(data->client.any.c, FALSE, 2);
client_action_end(data);
}
{
client_action_start(data);
client_maximize(data->client.any.c,
- !data->client.any.c->max_vert, 2, TRUE);
+ !data->client.any.c->max_vert, 2);
client_action_end(data);
}
void action_toggle_fullscreen(union ActionData *data)
{
client_action_start(data);
- client_fullscreen(data->client.any.c,
- !(data->client.any.c->fullscreen), TRUE);
+ client_fullscreen(data->client.any.c, !(data->client.any.c->fullscreen));
client_action_end(data);
}
if (data->sendto.desk < screen_num_desktops ||
data->sendto.desk == DESKTOP_ALL) {
client_set_desktop(c, data->sendto.desk, data->sendto.follow);
- if (data->sendto.follow)
- screen_set_desktop(data->sendto.desk);
+ if (data->sendto.follow && data->sendto.desk != screen_desktop)
+ screen_set_desktop(data->sendto.desk, TRUE);
}
}
void action_desktop(union ActionData *data)
{
- static guint first = (unsigned) -1;
-
- if (data->inter.any.interactive && first == (unsigned) -1)
- first = screen_desktop;
-
- if (!data->inter.any.interactive ||
- (!data->inter.cancel && !data->inter.final))
+ /* XXX add the interactive/dialog option back again once the dialog
+ has been made to not use grabs */
+ if (data->desktop.desk < screen_num_desktops ||
+ data->desktop.desk == DESKTOP_ALL)
{
- if (data->desktop.desk < screen_num_desktops ||
- data->desktop.desk == DESKTOP_ALL)
- {
- screen_set_desktop(data->desktop.desk);
- if (data->inter.any.interactive)
- screen_desktop_popup(data->desktop.desk, TRUE);
- }
- } else if (data->inter.cancel) {
- screen_set_desktop(first);
- }
-
- if (!data->inter.any.interactive || data->inter.final) {
- screen_desktop_popup(0, FALSE);
- first = (unsigned) -1;
+ screen_set_desktop(data->desktop.desk, TRUE);
+ if (data->inter.any.interactive)
+ screen_desktop_popup(data->desktop.desk, TRUE);
}
}
data->desktopdir.inter.any.interactive,
data->desktopdir.inter.final,
data->desktopdir.inter.cancel);
+ /* only move the desktop when the action is complete. if we switch
+ desktops during the interactive action, focus will move but with
+ NotifyWhileGrabbed and applications don't like that. */
if (!data->sendtodir.inter.any.interactive ||
- !data->sendtodir.inter.final ||
- data->sendtodir.inter.cancel)
+ (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
{
- screen_set_desktop(d);
+ if (d != screen_desktop)
+ screen_set_desktop(d, TRUE);
}
}
data->sendtodir.inter.any.interactive,
data->sendtodir.inter.final,
data->sendtodir.inter.cancel);
+ /* only move the desktop when the action is complete. if we switch
+ desktops during the interactive action, focus will move but with
+ NotifyWhileGrabbed and applications don't like that. */
if (!data->sendtodir.inter.any.interactive ||
- !data->sendtodir.inter.final ||
- data->sendtodir.inter.cancel)
+ (data->sendtodir.inter.final && !data->sendtodir.inter.cancel))
{
client_set_desktop(c, d, data->sendtodir.follow);
- if (data->sendtodir.follow)
- screen_set_desktop(d);
+ if (data->sendtodir.follow && d != screen_desktop)
+ screen_set_desktop(d, TRUE);
}
}
void action_desktop_last(union ActionData *data)
{
- screen_set_desktop(screen_last_desktop);
+ screen_set_desktop(screen_last_desktop, TRUE);
}
void action_toggle_decorations(union ActionData *data)
client_action_end(data);
}
-static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
-{
- if (config_resize_four_corners) {
- if (x - cx > cw / 2) {
- if (y - cy > ch / 2)
- return prop_atoms.net_wm_moveresize_size_bottomright;
- else
- return prop_atoms.net_wm_moveresize_size_topright;
- } else {
- if (y - cy > ch / 2)
- return prop_atoms.net_wm_moveresize_size_bottomleft;
- else
- return prop_atoms.net_wm_moveresize_size_topleft;
- }
- } else {
- if (x - cx > cw * 2 / 3) {
- if (y - cy > ch * 2 / 3)
- return prop_atoms.net_wm_moveresize_size_bottomright;
- else if (y - cy < ch / 3)
- return prop_atoms.net_wm_moveresize_size_topright;
- else
- return prop_atoms.net_wm_moveresize_size_right;
- } else if (x - cx < cw / 3) {
- if (y - cy > ch * 2 / 3)
- return prop_atoms.net_wm_moveresize_size_bottomleft;
- else if (y - cy < ch / 3)
- return prop_atoms.net_wm_moveresize_size_topleft;
- else
- return prop_atoms.net_wm_moveresize_size_left;
- } else
- if (y - cy > ch * 2 / 3)
- return prop_atoms.net_wm_moveresize_size_bottom;
- else if (y - cy < ch / 3)
- return prop_atoms.net_wm_moveresize_size_top;
- else
- return prop_atoms.net_wm_moveresize_move;
+static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch,
+ gboolean shaded)
+{
+ /* 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 */
+
+#define X x*ch/cw
+#define A -4*X + 7*ch/3
+#define B 4*X -15*ch/9
+#define C -X/4 + 2*ch/3
+#define D X/4 + 5*ch/12
+#define E X/4 + ch/3
+#define F -X/4 + 7*ch/12
+#define G 4*X - 4*ch/3
+#define H -4*X + 8*ch/3
+#define a (y > 5*ch/9)
+#define b (x < 4*cw/9)
+#define c (x > 5*cw/9)
+#define d (y < 4*ch/9)
+
+ /*
+ Each of these defines (except X which is just there for fun), represents
+ the equation of a line. The lines they represent are shown in the diagram
+ below. Checking y against these lines, we are able to choose a region
+ of the window as shown.
+
+ +---------------------A-------|-------|-------B---------------------+
+ | |A B| |
+ | |A | | B| |
+ | | A B | |
+ | | A | | B | |
+ | | A B | |
+ | | A | | B | |
+ | northwest | A north B | northeast |
+ | | A | | B | |
+ | | A B | |
+ C---------------------+----A--+-------+--B----+---------------------D
+ |CCCCCCC | A B | DDDDDDD|
+ | CCCCCCCC | A | | B | DDDDDDDD |
+ | CCCCCCC A B DDDDDDD |
+ - - - - - - - - - - - +CCCCCCC+aaaaaaa+DDDDDDD+ - - - - - - - - - - - -
+ | | b c | | sh
+ | west | b move c | east | ad
+ | | b c | | ed
+ - - - - - - - - - - - +EEEEEEE+ddddddd+FFFFFFF+- - - - - - - - - - - -
+ | EEEEEEE G H FFFFFFF |
+ | EEEEEEEE | G | | H | FFFFFFFF |
+ |EEEEEEE | G H | FFFFFFF|
+ E---------------------+----G--+-------+--H----+---------------------F
+ | | G H | |
+ | | G | | H | |
+ | southwest | G south H | southeast |
+ | | G | | H | |
+ | | G H | |
+ | | G | | H | |
+ | | G H | |
+ | |G | | H| |
+ | |G H| |
+ +---------------------G-------|-------|-------H---------------------+
+ */
+
+ if (shaded) {
+ /* for shaded windows, you can only resize west/east and move */
+ if (b)
+ return prop_atoms.net_wm_moveresize_size_left;
+ if (c)
+ return prop_atoms.net_wm_moveresize_size_right;
+ return prop_atoms.net_wm_moveresize_move;
}
+
+ if (y < A && y >= C)
+ return prop_atoms.net_wm_moveresize_size_topleft;
+ else if (y >= A && y >= B && a)
+ return prop_atoms.net_wm_moveresize_size_top;
+ else if (y < B && y >= D)
+ return prop_atoms.net_wm_moveresize_size_topright;
+ else if (y < C && y >= E && b)
+ return prop_atoms.net_wm_moveresize_size_left;
+ else if (y < D && y >= F && c)
+ return prop_atoms.net_wm_moveresize_size_right;
+ else if (y < E && y >= G)
+ return prop_atoms.net_wm_moveresize_size_bottomleft;
+ else if (y < G && y < H && d)
+ return prop_atoms.net_wm_moveresize_size_bottom;
+ else if (y >= H && y < F)
+ return prop_atoms.net_wm_moveresize_size_bottomright;
+ else
+ return prop_atoms.net_wm_moveresize_move;
+
+#undef X
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+#undef a
+#undef b
+#undef c
+#undef d
}
-void action_moveresize(union ActionData *data)
+void action_move(union ActionData *data)
{
ObClient *c = data->moveresize.any.c;
guint32 corner;
- if (!client_normal(c)) return;
+ if (data->moveresize.keyboard)
+ corner = prop_atoms.net_wm_moveresize_move_keyboard;
+ else
+ corner = prop_atoms.net_wm_moveresize_move;
- if (data->moveresize.keyboard) {
- corner = (data->moveresize.move ?
- prop_atoms.net_wm_moveresize_move_keyboard :
- prop_atoms.net_wm_moveresize_size_keyboard);
- } else {
- corner = (data->moveresize.move ?
- prop_atoms.net_wm_moveresize_move :
- pick_corner(data->any.x, data->any.y,
- c->frame->area.x, c->frame->area.y,
- /* use the client size because the frame
- can be differently sized (shaded
- windows) and we want this based on the
- clients size */
- c->area.width + c->frame->size.left +
- c->frame->size.right,
- c->area.height + c->frame->size.top +
- c->frame->size.bottom));
- }
+ moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
+}
+
+void action_resize(union ActionData *data)
+{
+ ObClient *c = data->moveresize.any.c;
+ guint32 corner;
+
+ if (data->moveresize.keyboard)
+ corner = prop_atoms.net_wm_moveresize_size_keyboard;
+ else if (data->moveresize.corner)
+ corner = data->moveresize.corner; /* it was specified in the binding */
+ else
+ corner = pick_corner(data->any.x, data->any.y,
+ c->frame->area.x, c->frame->area.y,
+ /* use the client size because the frame
+ can be differently sized (shaded
+ windows) and we want this based on the
+ clients size */
+ c->area.width + c->frame->size.left +
+ c->frame->size.right,
+ c->area.height + c->frame->size.top +
+ c->frame->size.bottom, c->shaded);
moveresize_start(c, data->any.x, data->any.y, data->any.button, corner);
}
{
if (data->showmenu.name) {
menu_show(data->showmenu.name, data->any.x, data->any.y,
- data->showmenu.any.c);
+ data->any.button, data->showmenu.any.c);
}
}
on us */
event_halt_focus_delay();
- focus_cycle(data->cycle.forward, data->cycle.linear, data->any.interactive,
+ focus_cycle(data->cycle.forward,
+ data->cycle.all_desktops,
+ data->cycle.dock_windows,
+ data->cycle.desktop_windows,
+ data->cycle.linear, data->any.interactive,
data->cycle.dialog,
data->cycle.inter.final, data->cycle.inter.cancel);
}
event_halt_focus_delay();
focus_directional_cycle(data->interdiraction.direction,
+ data->interdiraction.dock_windows,
+ data->interdiraction.desktop_windows,
data->any.interactive,
data->interdiraction.dialog,
data->interdiraction.inter.final,
switch(data->diraction.direction) {
case OB_DIRECTION_NORTH:
- y = client_directional_edge_search(c, OB_DIRECTION_NORTH);
+ y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
+ data->diraction.hang)
+ - (data->diraction.hang ? c->frame->area.height : 0);
break;
case OB_DIRECTION_WEST:
- x = client_directional_edge_search(c, OB_DIRECTION_WEST);
+ x = client_directional_edge_search(c, OB_DIRECTION_WEST,
+ data->diraction.hang)
+ - (data->diraction.hang ? c->frame->area.width : 0);
break;
case OB_DIRECTION_SOUTH:
- y = client_directional_edge_search(c, OB_DIRECTION_SOUTH) -
- c->frame->area.height;
+ y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
+ data->diraction.hang)
+ - (data->diraction.hang ? 0 : c->frame->area.height);
break;
case OB_DIRECTION_EAST:
- x = client_directional_edge_search(c, OB_DIRECTION_EAST) -
- c->frame->area.width;
+ x = client_directional_edge_search(c, OB_DIRECTION_EAST,
+ data->diraction.hang)
+ - (data->diraction.hang ? 0 : c->frame->area.width);
break;
default:
g_assert_not_reached();
}
- frame_frame_gravity(c->frame, &x, &y);
+ frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
client_action_start(data);
client_move(c, x, y);
client_action_end(data);
ObClient *c = data->diraction.any.c;
Rect *a;
- //FIXME growtoedge resizes shaded windows to 0 height
- if (c->shaded)
- return;
-
a = screen_area(c->desktop);
x = c->frame->area.x;
y = c->frame->area.y;
- width = c->frame->area.width;
- height = c->frame->area.height;
+ /* get the unshaded frame's dimensions..if it is shaded */
+ width = c->area.width + c->frame->size.left + c->frame->size.right;
+ height = c->area.height + c->frame->size.top + c->frame->size.bottom;
switch(data->diraction.direction) {
case OB_DIRECTION_NORTH:
- dest = client_directional_edge_search(c, OB_DIRECTION_NORTH);
+ if (c->shaded) break; /* don't allow vertical resize if shaded */
+
+ dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
if (a->y == y)
- height = c->frame->area.height / 2;
+ height = height / 2;
else {
- height = c->frame->area.y + c->frame->area.height - dest;
+ height = c->frame->area.y + height - dest;
y = dest;
}
break;
case OB_DIRECTION_WEST:
- dest = client_directional_edge_search(c, OB_DIRECTION_WEST);
+ dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
if (a->x == x)
- width = c->frame->area.width / 2;
+ width = width / 2;
else {
- width = c->frame->area.x + c->frame->area.width - dest;
+ width = c->frame->area.x + width - dest;
x = dest;
}
break;
case OB_DIRECTION_SOUTH:
- dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH);
+ if (c->shaded) break; /* don't allow vertical resize if shaded */
+
+ dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
if (a->y + a->height == y + c->frame->area.height) {
height = c->frame->area.height / 2;
y = a->y + a->height - height;
height -= (height - c->frame->area.height) % c->size_inc.height;
break;
case OB_DIRECTION_EAST:
- dest = client_directional_edge_search(c, OB_DIRECTION_EAST);
+ dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
if (a->x + a->width == x + c->frame->area.width) {
width = c->frame->area.width / 2;
x = a->x + a->width - width;
default:
g_assert_not_reached();
}
- frame_frame_gravity(c->frame, &x, &y);
width -= c->frame->size.left + c->frame->size.right;
height -= c->frame->size.top + c->frame->size.bottom;
+ frame_frame_gravity(c->frame, &x, &y, width, height);
client_action_start(data);
client_move_resize(c, x, y, width, height);
client_action_end(data);
void action_toggle_show_desktop(union ActionData *data)
{
- screen_show_desktop(!screen_showing_desktop);
+ screen_show_desktop(!screen_showing_desktop, NULL);
}
void action_show_desktop(union ActionData *data)
{
- screen_show_desktop(TRUE);
+ screen_show_desktop(TRUE, NULL);
}
void action_unshow_desktop(union ActionData *data)
{
- screen_show_desktop(FALSE);
+ screen_show_desktop(FALSE, NULL);
+}
+
+void action_break_chroot(union ActionData *data)
+{
+ /* break out of one chroot */
+ keyboard_reset_chains(1);
}