#include "keyboard.h"
#include "event.h"
#include "config.h"
+#include "mainloop.h"
#include <glib.h>
void (*setup)(ObAction **, ObUserAction uact);
} ActionString;
-static ObAction *action_new(void (*func)(union ActionData *data),
- ObUserAction uact)
+static ObAction *action_new(void (*func)(union ActionData *data))
{
ObAction *a = g_new0(ObAction, 1);
+ a->ref = 1;
a->func = func;
return a;
}
-void action_free(ObAction *a)
+void action_ref(ObAction *a)
+{
+ ++a->ref;
+}
+
+void action_unref(ObAction *a)
{
if (a == NULL) return;
+ if (--a->ref > 0) return;
+
/* deal with pointers */
if (a->func == action_execute || a->func == action_restart)
g_free(a->data.execute.path);
g_free(a);
}
+ObAction* action_copy(const ObAction *src)
+{
+ ObAction *a = action_new(src->func);
+
+ a->data = src->data;
+
+ /* 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_showmenu)
+ a->data.showmenu.name = g_strdup(a->data.showmenu.name);
+
+ return a;
+}
+
void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
{
(*a)->data.interdiraction.inter.any.interactive = TRUE;
(*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
+ (*a)->data.interdiraction.dialog = TRUE;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
(*a)->data.sendtodir.follow = TRUE;
}
+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.desktopdir.inter.any.interactive = TRUE;
(*a)->data.cycle.inter.any.interactive = TRUE;
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = TRUE;
+ (*a)->data.cycle.dialog = TRUE;
}
void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
(*a)->data.cycle.inter.any.interactive = TRUE;
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = FALSE;
+ (*a)->data.cycle.dialog = TRUE;
}
void setup_action_movetoedge_north(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_KEYBOARD_KEY ||
+ (uact == OB_USER_ACTION_NONE ||
+ uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
}
(*a)->data.moveresize.any.client_action = OB_CLIENT_ACTION_ALWAYS;
(*a)->data.moveresize.move = FALSE;
(*a)->data.moveresize.keyboard =
- (uact == OB_USER_ACTION_KEYBOARD_KEY ||
+ (uact == OB_USER_ACTION_NONE ||
+ uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
}
assumptions that there is only one menu (and submenus) open at
a time! */
if (uact == OB_USER_ACTION_MENU_SELECTION) {
- action_free(*a);
- a = NULL;
+ action_unref(*a);
+ *a = NULL;
}
}
{
"desktop",
action_desktop,
- NULL
+ setup_action_desktop
},
{
"desktopnext",
}
};
+/* only key bindings can be interactive. thus saith the xor.
+ because of how the mouse is grabbed, mouse events dont even get
+ read during interactive events, so no dice! >:) */
+#define INTERACTIVE_LIMIT(a, uact) \
+ if (uact != OB_USER_ACTION_KEYBOARD_KEY) \
+ a->data.any.interactive = FALSE;
+
ObAction *action_from_string(const gchar *name, ObUserAction uact)
{
ObAction *a = NULL;
gboolean exist = FALSE;
- int i;
+ gint i;
for (i = 0; actionstrings[i].name; i++)
if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
exist = TRUE;
- a = action_new(actionstrings[i].func, uact);
+ a = action_new(actionstrings[i].func);
if (actionstrings[i].setup)
actionstrings[i].setup(&a, uact);
- /* only key bindings can be interactive. thus saith the xor. */
- if (uact != OB_USER_ACTION_KEYBOARD_KEY)
- a->data.any.interactive = FALSE;
+ if (a)
+ INTERACTIVE_LIMIT(a, uact);
break;
}
if (!exist)
ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
ObUserAction uact)
{
- char *actname;
+ gchar *actname;
ObAction *act = NULL;
xmlNodePtr 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);
} else if (act->func == action_desktop_dir) {
if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
act->data.desktopdir.wrap = parse_bool(doc, n);
+ if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
+ act->data.desktopdir.inter.any.interactive =
+ parse_bool(doc, n);
} else if (act->func == action_send_to_desktop_dir) {
if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
act->data.sendtodir.wrap = parse_bool(doc, n);
if ((n = parse_find_node("follow", node->xmlChildrenNode)))
act->data.sendtodir.follow = parse_bool(doc, n);
+ if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
+ act->data.sendtodir.inter.any.interactive =
+ parse_bool(doc, n);
} else if (act->func == action_activate) {
if ((n = parse_find_node("here", node->xmlChildrenNode)))
act->data.activate.here = parse_bool(doc, n);
} else if (act->func == action_cycle_windows) {
if ((n = parse_find_node("linear", node->xmlChildrenNode)))
act->data.cycle.linear = parse_bool(doc, n);
+ if ((n = parse_find_node("dialog", node->xmlChildrenNode)))
+ act->data.cycle.dialog = 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);
}
+ INTERACTIVE_LIMIT(act, uact);
}
g_free(actname);
}
a->data.inter.cancel = cancel;
a->data.inter.final = done;
if (!(cancel || done))
- keyboard_interactive_grab(state, a->data.any.c, a);
+ if (!keyboard_interactive_grab(state, a->data.any.c, a))
+ continue;
}
- a->func(&a->data);
+ /* 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) {
+ /* interactive actions are not queued */
+ a->func(&a->data);
+ } else
+ ob_main_loop_queue_action(ob_main_loop, a);
}
}
}
+void action_run_string(const gchar *name, struct _ObClient *c)
+{
+ ObAction *a;
+ GSList *l;
+
+ a = action_from_string(name, OB_USER_ACTION_NONE);
+ g_assert(a);
+
+ l = g_slist_append(NULL, a);
+
+ action_run(l, c, 0);
+}
+
void action_execute(union ActionData *data)
{
GError *e = NULL;
- char *cmd;
+ gchar *cmd, **argv = 0;
if (data->execute.path) {
cmd = g_filename_from_utf8(data->execute.path, -1, NULL, NULL, NULL);
if (cmd) {
- if (!g_spawn_command_line_async(cmd, &e)) {
+ if (!g_shell_parse_argv (cmd, NULL, &argv, &e)) {
g_warning("failed to execute '%s': %s",
cmd, e->message);
+ g_error_free(e);
+ } else {
+ 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",
+ cmd, e->message);
+ g_error_free(e);
+ }
+ g_strfreev(argv);
}
g_free(cmd);
} else {
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();
+
client_focus(data->client.any.c);
}
if (cit == c) break;
if (client_normal(cit) == client_normal(c) &&
cit->layer == c->layer &&
- cit->frame->visible)
+ cit->frame->visible &&
+ !client_search_transient(c, cit))
{
if (RECT_INTERSECTS_RECT(cit->frame->area, c->frame->area)) {
raise = TRUE;
}
}
- if (raise) {
- client_action_start(data);
- stacking_raise(CLIENT_AS_WINDOW(c));
- client_action_end(data);
- } else {
- client_action_start(data);
- stacking_lower(CLIENT_AS_WINDOW(c));
- client_action_end(data);
- }
+ if (raise)
+ action_raise(data);
+ else
+ action_lower(data);
}
void action_raise(union ActionData *data)
void action_unshaderaise(union ActionData *data)
{
- if (data->client.any.c->shaded) {
- client_action_start(data);
- client_shade(data->client.any.c, FALSE);
- client_action_end(data);
- } else {
- client_action_start(data);
- stacking_raise(CLIENT_AS_WINDOW(data->client.any.c));
- client_action_end(data);
- }
+ if (data->client.any.c->shaded)
+ action_unshade(data);
+ else
+ action_raise(data);
}
void action_shadelower(union ActionData *data)
{
if (data->client.any.c->shaded)
- stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
- else {
- client_action_start(data);
- client_shade(data->client.any.c, TRUE);
- client_action_end(data);
- }
+ action_lower(data);
+ else
+ action_shade(data);
}
void action_lower(union ActionData *data)
client_action_start(data);
stacking_lower(CLIENT_AS_WINDOW(data->client.any.c));
client_action_end(data);
+
+ focus_order_to_bottom(data->client.any.c);
}
void action_close(union ActionData *data)
void action_desktop(union ActionData *data)
{
- if (data->desktop.desk < screen_num_desktops ||
- data->desktop.desk == DESKTOP_ALL)
- screen_set_desktop(data->desktop.desk);
+ 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))
+ {
+ 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;
+ }
}
void action_desktop_dir(union ActionData *data)
d = screen_cycle_desktop(data->desktopdir.dir,
data->desktopdir.wrap,
- data->sendtodir.linear,
+ data->desktopdir.linear,
data->desktopdir.inter.any.interactive,
data->desktopdir.inter.final,
data->desktopdir.inter.cancel);
if (!data->sendtodir.inter.any.interactive ||
- !data->sendtodir.inter.final)
+ !data->sendtodir.inter.final ||
+ data->sendtodir.inter.cancel)
{
screen_set_desktop(d);
}
data->sendtodir.inter.final,
data->sendtodir.inter.cancel);
if (!data->sendtodir.inter.any.interactive ||
- !data->sendtodir.inter.final)
+ !data->sendtodir.inter.final ||
+ data->sendtodir.inter.cancel)
{
client_set_desktop(c, d, data->sendtodir.follow);
if (data->sendtodir.follow)
ObClient *c = data->client.any.c;
client_action_start(data);
- c->decorate = !c->decorate;
- client_setup_decor_and_functions(c);
+ client_set_undecorated(c, !c->undecorated);
client_action_end(data);
}
-static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch)
+static guint32 pick_corner(gint x, gint y, gint cx, gint cy, gint cw, gint ch)
{
- if (x - cx > cw / 2) {
- if (y - cy > ch / 2)
+ if ((cw / 3 < 1) || (x - cx > cw / 3 * 2)) {
+ if ((ch / 3 < 1) || (y - cy > ch / 3 * 2))
return prop_atoms.net_wm_moveresize_size_bottomright;
- else
+ 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 / 3 * 2)
+ 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)
- return prop_atoms.net_wm_moveresize_size_bottomleft;
+ return prop_atoms.net_wm_moveresize_size_bottom;
else
- return prop_atoms.net_wm_moveresize_size_topleft;
+ return prop_atoms.net_wm_moveresize_size_top;
}
}
void action_cycle_windows(union ActionData *data)
{
+ /* if using focus_delay, stop the timer now so that focus doesn't go moving
+ on us */
+ event_halt_focus_delay();
+
focus_cycle(data->cycle.forward, data->cycle.linear,
- data->cycle.inter.any.interactive,
+ data->cycle.dialog,
data->cycle.inter.final, data->cycle.inter.cancel);
}
void action_directional_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();
+
focus_directional_cycle(data->interdiraction.direction,
- data->interdiraction.inter.any.interactive,
+ data->interdiraction.dialog,
data->interdiraction.inter.final,
data->interdiraction.inter.cancel);
}
void action_movetoedge(union ActionData *data)
{
- int x, y;
+ gint x, y;
ObClient *c = data->diraction.any.c;
x = c->frame->area.x;
void action_growtoedge(union ActionData *data)
{
- int x, y, width, height, dest;
+ gint x, y, width, height, dest;
ObClient *c = data->diraction.any.c;
Rect *a;