little bit of an actions overhaul, added action_run* so that duplicated code can all be in the same place now woot.

allow actions to specify when they can be used (ShowMenu cant in the OB_USER_ACTION_MENU_SELECTION case)
remove KeyboardMove ad KeyboardResize. Instead, just use Move and Resize and determine if it should be a keyboard move/resize in the code
This commit is contained in:
Dana Jansens 2003-09-07 19:03:20 +00:00
parent b23594d88d
commit 78282959f9
15 changed files with 402 additions and 459 deletions

View file

@ -96,10 +96,10 @@
<action name="PreviousWindow"/> <action name="PreviousWindow"/>
</keybind> </keybind>
<keybind key="A-F7"> <keybind key="A-F7">
<action name="KeyboardMove"/> <action name="Move"/>
</keybind> </keybind>
<keybind key="A-F8"> <keybind key="A-F8">
<action name="KeyboardResize"/> <action name="Resize"/>
</keybind> </keybind>
<keybind key="A-F9"> <keybind key="A-F9">
<action name="Iconify"/> <action name="Iconify"/>

View file

@ -5,21 +5,22 @@
#include "menu.h" #include "menu.h"
#include "prop.h" #include "prop.h"
#include "stacking.h" #include "stacking.h"
#include "frame.h"
#include "screen.h" #include "screen.h"
#include "action.h" #include "action.h"
#include "openbox.h" #include "openbox.h"
#include "grab.h" #include "grab.h"
#include "keyboard.h"
#include <glib.h> #include <glib.h>
typedef struct ActionString { typedef struct ActionString {
char *name; char *name;
void (*func)(union ActionData *); void (*func)(union ActionData *);
void (*setup)(ObAction *); void (*setup)(ObAction **, ObUserAction uact);
} ActionString; } ActionString;
ObAction *action_new(void (*func)(union ActionData *data)) static ObAction *action_new(void (*func)(union ActionData *data),
ObUserAction uact)
{ {
ObAction *a = g_new0(ObAction, 1); ObAction *a = g_new0(ObAction, 1);
a->func = func; a->func = func;
@ -40,262 +41,255 @@ void action_free(ObAction *a)
g_free(a); g_free(a);
} }
void setup_action_directional_focus_north(ObAction *a) void setup_action_directional_focus_north(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_NORTH; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTH;
} }
void setup_action_directional_focus_east(ObAction *a) void setup_action_directional_focus_east(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_EAST; (*a)->data.interdiraction.direction = OB_DIRECTION_EAST;
} }
void setup_action_directional_focus_south(ObAction *a) void setup_action_directional_focus_south(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_SOUTH; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTH;
} }
void setup_action_directional_focus_west(ObAction *a) void setup_action_directional_focus_west(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_WEST; (*a)->data.interdiraction.direction = OB_DIRECTION_WEST;
} }
void setup_action_directional_focus_northeast(ObAction *a) void setup_action_directional_focus_northeast(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_NORTHEAST; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHEAST;
} }
void setup_action_directional_focus_southeast(ObAction *a) void setup_action_directional_focus_southeast(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHEAST;
} }
void setup_action_directional_focus_southwest(ObAction *a) void setup_action_directional_focus_southwest(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST; (*a)->data.interdiraction.direction = OB_DIRECTION_SOUTHWEST;
} }
void setup_action_directional_focus_northwest(ObAction *a) void setup_action_directional_focus_northwest(ObAction **a, ObUserAction uact)
{ {
a->data.interdiraction.inter.any.interactive = TRUE; (*a)->data.interdiraction.inter.any.interactive = TRUE;
a->data.interdiraction.direction = OB_DIRECTION_NORTHWEST; (*a)->data.interdiraction.direction = OB_DIRECTION_NORTHWEST;
} }
void setup_action_send_to_desktop(ObAction *a) void setup_action_send_to_desktop(ObAction **a, ObUserAction uact)
{ {
a->data.sendto.follow = TRUE; (*a)->data.sendto.follow = TRUE;
} }
void setup_action_send_to_desktop_prev(ObAction *a) void setup_action_send_to_desktop_prev(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_WEST; (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
a->data.sendtodir.linear = TRUE; (*a)->data.sendtodir.linear = TRUE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_send_to_desktop_next(ObAction *a) void setup_action_send_to_desktop_next(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_EAST; (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
a->data.sendtodir.linear = TRUE; (*a)->data.sendtodir.linear = TRUE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_send_to_desktop_left(ObAction *a) void setup_action_send_to_desktop_left(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_WEST; (*a)->data.sendtodir.dir = OB_DIRECTION_WEST;
a->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.linear = FALSE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_send_to_desktop_right(ObAction *a) void setup_action_send_to_desktop_right(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_EAST; (*a)->data.sendtodir.dir = OB_DIRECTION_EAST;
a->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.linear = FALSE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_send_to_desktop_up(ObAction *a) void setup_action_send_to_desktop_up(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_NORTH; (*a)->data.sendtodir.dir = OB_DIRECTION_NORTH;
a->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.linear = FALSE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_send_to_desktop_down(ObAction *a) void setup_action_send_to_desktop_down(ObAction **a, ObUserAction uact)
{ {
a->data.sendtodir.inter.any.interactive = TRUE; (*a)->data.sendtodir.inter.any.interactive = TRUE;
a->data.sendtodir.dir = OB_DIRECTION_SOUTH; (*a)->data.sendtodir.dir = OB_DIRECTION_SOUTH;
a->data.sendtodir.linear = FALSE; (*a)->data.sendtodir.linear = FALSE;
a->data.sendtodir.wrap = TRUE; (*a)->data.sendtodir.wrap = TRUE;
a->data.sendtodir.follow = TRUE; (*a)->data.sendtodir.follow = TRUE;
} }
void setup_action_desktop_prev(ObAction *a) void setup_action_desktop_prev(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_WEST; (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
a->data.desktopdir.linear = TRUE; (*a)->data.desktopdir.linear = TRUE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_desktop_next(ObAction *a) void setup_action_desktop_next(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_EAST; (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
a->data.desktopdir.linear = TRUE; (*a)->data.desktopdir.linear = TRUE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_desktop_left(ObAction *a) void setup_action_desktop_left(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_WEST; (*a)->data.desktopdir.dir = OB_DIRECTION_WEST;
a->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.linear = FALSE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_desktop_right(ObAction *a) void setup_action_desktop_right(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_EAST; (*a)->data.desktopdir.dir = OB_DIRECTION_EAST;
a->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.linear = FALSE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_desktop_up(ObAction *a) void setup_action_desktop_up(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_NORTH; (*a)->data.desktopdir.dir = OB_DIRECTION_NORTH;
a->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.linear = FALSE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_desktop_down(ObAction *a) void setup_action_desktop_down(ObAction **a, ObUserAction uact)
{ {
a->data.desktopdir.inter.any.interactive = TRUE; (*a)->data.desktopdir.inter.any.interactive = TRUE;
a->data.desktopdir.dir = OB_DIRECTION_SOUTH; (*a)->data.desktopdir.dir = OB_DIRECTION_SOUTH;
a->data.desktopdir.linear = FALSE; (*a)->data.desktopdir.linear = FALSE;
a->data.desktopdir.wrap = TRUE; (*a)->data.desktopdir.wrap = TRUE;
} }
void setup_action_move_keyboard(ObAction *a) void setup_action_cycle_windows_next(ObAction **a, ObUserAction uact)
{ {
a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move_keyboard; (*a)->data.cycle.inter.any.interactive = TRUE;
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = TRUE;
} }
void setup_action_move(ObAction *a) void setup_action_cycle_windows_previous(ObAction **a, ObUserAction uact)
{ {
a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move; (*a)->data.cycle.inter.any.interactive = TRUE;
(*a)->data.cycle.linear = FALSE;
(*a)->data.cycle.forward = FALSE;
} }
void setup_action_resize(ObAction *a) void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
{ {
a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft; (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
} }
void setup_action_resize_keyboard(ObAction *a) void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
{ {
a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_keyboard; (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
} }
void setup_action_cycle_windows_linear_next(ObAction *a) void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
{ {
a->data.cycle.inter.any.interactive = TRUE; (*a)->data.diraction.direction = OB_DIRECTION_EAST;
a->data.cycle.linear = TRUE;
a->data.cycle.forward = TRUE;
} }
void setup_action_cycle_windows_linear_previous(ObAction *a) void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
{ {
a->data.cycle.inter.any.interactive = TRUE; (*a)->data.diraction.direction = OB_DIRECTION_WEST;
a->data.cycle.linear = TRUE;
a->data.cycle.forward = FALSE;
} }
void setup_action_cycle_windows_next(ObAction *a) void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
{ {
a->data.cycle.inter.any.interactive = TRUE; (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
a->data.cycle.linear = FALSE;
a->data.cycle.forward = TRUE;
} }
void setup_action_cycle_windows_previous(ObAction *a) void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
{ {
a->data.cycle.inter.any.interactive = TRUE; (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
a->data.cycle.linear = FALSE;
a->data.cycle.forward = FALSE;
} }
void setup_action_movetoedge_north(ObAction *a) void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_NORTH; (*a)->data.diraction.direction = OB_DIRECTION_EAST;
} }
void setup_action_movetoedge_south(ObAction *a) void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_SOUTH; (*a)->data.diraction.direction = OB_DIRECTION_WEST;
} }
void setup_action_movetoedge_east(ObAction *a) void setup_action_top_layer(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_EAST; (*a)->data.layer.layer = 1;
} }
void setup_action_movetoedge_west(ObAction *a) void setup_action_normal_layer(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_WEST; (*a)->data.layer.layer = 0;
} }
void setup_action_growtoedge_north(ObAction *a) void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_NORTH; (*a)->data.layer.layer = -1;
} }
void setup_action_growtoedge_south(ObAction *a) void setup_action_move(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_SOUTH; (*a)->data.moveresize.move = TRUE;
(*a)->data.moveresize.keyboard =
(uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
} }
void setup_action_growtoedge_east(ObAction *a) void setup_action_resize(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_EAST; (*a)->data.moveresize.move = FALSE;
(*a)->data.moveresize.keyboard =
(uact == OB_USER_ACTION_KEYBOARD_KEY ||
uact == OB_USER_ACTION_MENU_SELECTION);
} }
void setup_action_growtoedge_west(ObAction *a) void setup_action_showmenu(ObAction **a, ObUserAction uact)
{ {
a->data.diraction.direction = OB_DIRECTION_WEST; /* you cannot call ShowMenu from inside a menu, cuz the menu code makes
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;
} }
void setup_action_top_layer(ObAction *a)
{
a->data.layer.layer = 1;
}
void setup_action_normal_layer(ObAction *a)
{
a->data.layer.layer = 0;
}
void setup_action_bottom_layer(ObAction *a)
{
a->data.layer.layer = -1;
} }
ActionString actionstrings[] = ActionString actionstrings[] =
@ -348,12 +342,12 @@ ActionString actionstrings[] =
{ {
"activate", "activate",
action_activate, action_activate,
NULL, NULL
}, },
{ {
"focus", "focus",
action_focus, action_focus,
NULL, NULL
}, },
{ {
"unfocus", "unfocus",
@ -560,11 +554,6 @@ ActionString actionstrings[] =
action_toggle_decorations, action_toggle_decorations,
NULL NULL
}, },
{
"keyboardmove",
action_moveresize,
setup_action_move_keyboard
},
{ {
"move", "move",
action_moveresize, action_moveresize,
@ -575,11 +564,6 @@ ActionString actionstrings[] =
action_moveresize, action_moveresize,
setup_action_resize setup_action_resize
}, },
{
"keyboardresize",
action_moveresize,
setup_action_resize_keyboard
},
{ {
"toggleshowdesktop", "toggleshowdesktop",
action_toggle_show_desktop, action_toggle_show_desktop,
@ -618,7 +602,7 @@ ActionString actionstrings[] =
{ {
"showmenu", "showmenu",
action_showmenu, action_showmenu,
NULL setup_action_showmenu
}, },
{ {
"sendtotoplayer", "sendtotoplayer",
@ -645,16 +629,6 @@ ActionString actionstrings[] =
action_toggle_layer, action_toggle_layer,
setup_action_bottom_layer setup_action_bottom_layer
}, },
{
"nextwindowlinear",
action_cycle_windows,
setup_action_cycle_windows_linear_next
},
{
"previouswindowlinear",
action_cycle_windows,
setup_action_cycle_windows_linear_previous
},
{ {
"nextwindow", "nextwindow",
action_cycle_windows, action_cycle_windows,
@ -712,32 +686,37 @@ ActionString actionstrings[] =
} }
}; };
ObAction *action_from_string(char *name) ObAction *action_from_string(char *name, ObUserAction uact)
{ {
ObAction *a = NULL; ObAction *a = NULL;
gboolean exist = FALSE;
int i; int i;
for (i = 0; actionstrings[i].name; i++) for (i = 0; actionstrings[i].name; i++)
if (!g_ascii_strcasecmp(name, actionstrings[i].name)) { if (!g_ascii_strcasecmp(name, actionstrings[i].name)) {
a = action_new(actionstrings[i].func); exist = TRUE;
a = action_new(actionstrings[i].func, uact);
if (actionstrings[i].setup) if (actionstrings[i].setup)
actionstrings[i].setup(a); actionstrings[i].setup(&a, uact);
break; break;
} }
if (!a) if (!exist)
g_warning("Invalid action '%s' requested. No such action exists.", g_warning("Invalid action '%s' requested. No such action exists.",
name); name);
if (!a)
g_warning("Invalid use of action '%s'. Action will be ignored.", name);
return a; return a;
} }
ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node) ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
ObUserAction uact)
{ {
char *actname; char *actname;
ObAction *act = NULL; ObAction *act = NULL;
xmlNodePtr n; xmlNodePtr n;
if (parse_attr_string("name", node, &actname)) { if (parse_attr_string("name", node, &actname)) {
if ((act = action_from_string(actname))) { if ((act = action_from_string(actname, uact))) {
if (act->func == action_execute || act->func == action_restart) { if (act->func == action_execute || act->func == action_restart) {
if ((n = parse_find_node("execute", node->xmlChildrenNode))) { if ((n = parse_find_node("execute", node->xmlChildrenNode))) {
gchar *s = parse_string(doc, n); gchar *s = parse_string(doc, n);
@ -747,6 +726,12 @@ ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
} else if (act->func == action_showmenu) { } else if (act->func == action_showmenu) {
if ((n = parse_find_node("menu", node->xmlChildrenNode))) if ((n = parse_find_node("menu", node->xmlChildrenNode)))
act->data.showmenu.name = parse_string(doc, n); act->data.showmenu.name = parse_string(doc, n);
} else if (act->func == action_move_relative_horz ||
act->func == action_move_relative_vert ||
act->func == action_resize_relative_horz ||
act->func == action_resize_relative_vert) {
if ((n = parse_find_node("delta", node->xmlChildrenNode)))
act->data.relative.delta = parse_int(doc, n);
} else if (act->func == action_desktop) { } else if (act->func == action_desktop) {
if ((n = parse_find_node("desktop", node->xmlChildrenNode))) if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
act->data.desktop.desk = parse_int(doc, n); act->data.desktop.desk = parse_int(doc, n);
@ -755,18 +740,11 @@ ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
if ((n = parse_find_node("desktop", node->xmlChildrenNode))) if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
act->data.sendto.desk = parse_int(doc, n); act->data.sendto.desk = parse_int(doc, n);
if (act->data.sendto.desk > 0) act->data.sendto.desk--; if (act->data.sendto.desk > 0) act->data.sendto.desk--;
} else if (act->func == action_move_relative_horz || if ((n = parse_find_node("follow", node->xmlChildrenNode)))
act->func == action_move_relative_vert || act->data.sendto.follow = parse_bool(doc, n);
act->func == action_resize_relative_horz ||
act->func == action_resize_relative_vert) {
if ((n = parse_find_node("delta", node->xmlChildrenNode)))
act->data.relative.delta = parse_int(doc, n);
} else if (act->func == action_desktop_dir) { } else if (act->func == action_desktop_dir) {
if ((n = parse_find_node("wrap", node->xmlChildrenNode))) if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
act->data.desktopdir.wrap = parse_bool(doc, n); act->data.desktopdir.wrap = parse_bool(doc, n);
} else if (act->func == action_send_to_desktop) {
if ((n = parse_find_node("follow", node->xmlChildrenNode)))
act->data.sendto.follow = parse_bool(doc, n);
} else if (act->func == action_send_to_desktop_dir) { } else if (act->func == action_send_to_desktop_dir) {
if ((n = parse_find_node("wrap", node->xmlChildrenNode))) if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
act->data.sendtodir.wrap = parse_bool(doc, n); act->data.sendtodir.wrap = parse_bool(doc, n);
@ -775,6 +753,9 @@ ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
} else if (act->func == action_activate) { } else if (act->func == action_activate) {
if ((n = parse_find_node("here", node->xmlChildrenNode))) if ((n = parse_find_node("here", node->xmlChildrenNode)))
act->data.activate.here = parse_bool(doc, n); 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);
} }
} }
g_free(actname); g_free(actname);
@ -782,6 +763,30 @@ ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
return act; return act;
} }
void action_run_full(ObAction *a, struct _ObClient *c,
ObFrameContext context,
guint state, guint button, gint x, gint y,
gboolean cancel, gboolean done)
{
if (x < 0 && y < 0)
screen_pointer_pos(&x, &y);
a->data.any.c = c;
a->data.any.x = x;
a->data.any.y = y;
a->data.any.button = button;
if (a->data.any.interactive) {
a->data.inter.cancel = cancel;
a->data.inter.final = done;
if (!(cancel || done))
keyboard_interactive_grab(state, c, context, a);
}
a->func(&a->data);
}
void action_execute(union ActionData *data) void action_execute(union ActionData *data)
{ {
GError *e = NULL; GError *e = NULL;
@ -1089,14 +1094,48 @@ void action_toggle_decorations(union ActionData *data)
client_setup_decor_and_functions(c); client_setup_decor_and_functions(c);
} }
static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch)
{
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;
}
}
void action_moveresize(union ActionData *data) void action_moveresize(union ActionData *data)
{ {
ObClient *c = data->moveresize.any.c; ObClient *c = data->moveresize.any.c;
guint32 corner;
if (!c || !client_normal(c)) return; if (!c || !client_normal(c)) return;
moveresize_start(c, data->moveresize.x, data->moveresize.y, if (data->moveresize.keyboard) {
data->moveresize.button, data->moveresize.corner); 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_reconfigure(union ActionData *data) void action_reconfigure(union ActionData *data)
@ -1117,7 +1156,7 @@ void action_exit(union ActionData *data)
void action_showmenu(union ActionData *data) void action_showmenu(union ActionData *data)
{ {
if (data->showmenu.name) { if (data->showmenu.name) {
menu_show(data->showmenu.name, data->showmenu.x, data->showmenu.y, menu_show(data->showmenu.name, data->any.x, data->any.y,
data->showmenu.any.c); data->showmenu.any.c);
} }
} }

View file

@ -2,8 +2,11 @@
#define __action_h #define __action_h
#include "misc.h" #include "misc.h"
#include "frame.h"
#include "parser/parse.h" #include "parser/parse.h"
struct _ObClient;
typedef struct _ObAction ObAction; typedef struct _ObAction ObAction;
/* These have to all have a Client* at the top even if they don't use it, so /* These have to all have a Client* at the top even if they don't use it, so
@ -14,6 +17,9 @@ typedef struct _ObAction ObAction;
struct AnyAction { struct AnyAction {
struct _ObClient *c; struct _ObClient *c;
gboolean interactive; gboolean interactive;
gint x;
gint y;
gint button;
}; };
struct InteractiveAction { struct InteractiveAction {
@ -84,17 +90,13 @@ struct DesktopDirection {
struct MoveResize { struct MoveResize {
struct AnyAction any; struct AnyAction any;
int x; gboolean move;
int y; gboolean keyboard;
guint32 corner; /* prop_atoms.net_wm_moveresize_* */
guint button;
}; };
struct ShowMenu { struct ShowMenu {
struct AnyAction any; struct AnyAction any;
char *name; char *name;
int x;
int y;
}; };
struct CycleWindows { struct CycleWindows {
@ -123,6 +125,7 @@ union ActionData {
}; };
struct _ObAction { struct _ObAction {
ObUserAction act;
/* The func member acts like an enum to tell which one of the structs in /* The func member acts like an enum to tell which one of the structs in
the data union are valid. the data union are valid.
*/ */
@ -130,24 +133,53 @@ struct _ObAction {
union ActionData data; union ActionData data;
}; };
ObAction *action_new(void (*func)(union ActionData *data));
/* Creates a new Action from the name of the action /* Creates a new Action from the name of the action
A few action types need data set after making this call still. Check if A few action types need data set after making this call still. Check if
the returned action's "func" is one of these. the returned action's "func" is one of these.
action_execute - the path needs to be set action_execute - the path needs to be set
action_restart - the path can optionally be set action_restart - the path can optionally be set
action_desktop - the destination desktop needs to be set action_desktop - the destination desktop needs to be set
action_send_to_desktop - the destination desktop needs to be set
action_move_relative_horz - the delta action_move_relative_horz - the delta
action_move_relative_vert - the delta action_move_relative_vert - the delta
action_resize_relative_horz - the delta action_resize_relative_horz - the delta
action_resize_relative_vert - the delta action_resize_relative_vert - the delta
*/ */
ObAction *action_from_string(char *name); ObAction *action_from_string(char *name, ObUserAction uact);
ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node); ObAction *action_parse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
ObUserAction uact);
void action_free(ObAction *a); void action_free(ObAction *a);
/*! Executes an action.
@param c The client associated with the action. Can be NULL.
@param context The context in which the user action occured.
@param state The keyboard modifiers state at the time the user action occured
@param button The mouse button used to execute the action.
@param x The x coord at which the user action occured.
@param y The y coord at which the user action occured.
@param cancel If the action is cancelling an interactive action. This only
affects interactive actions, but should generally always be FALSE.
@param done If the action is completing an interactive action. This only
affects interactive actions, but should generally always be FALSE.
*/
void action_run_full(ObAction *a, struct _ObClient *c,
ObFrameContext context,
guint state, guint button, gint x, gint y,
gboolean cancel, gboolean done);
#define action_run_mouse(a, c, t, s, b, x, y) \
action_run_full(a, c, t, s, b, x, y, FALSE, FALSE)
#define action_run_interactive(a, c, s, n, d) \
action_run_full(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, n, d)
#define action_run_key(a, c, s, x, y) \
action_run_full(a, c, OB_FRAME_CONTEXT_NONE, s, 0, x, y, FALSE,FALSE)
#define action_run(a, c, s) \
action_run_full(a, c, OB_FRAME_CONTEXT_NONE, s, 0, -1, -1, FALSE,FALSE)
/* Execute */ /* Execute */
void action_execute(union ActionData *data); void action_execute(union ActionData *data);
/* ActivateAction */ /* ActivateAction */

View file

@ -40,7 +40,8 @@ static void desk_menu_update(ObMenuFrame *frame, gpointer data)
menu_add_separator(menu, -1); menu_add_separator(menu, -1);
} }
act = action_from_string("activate"); act = action_from_string("Activate",
OB_USER_ACTION_MENU_SELECTION);
act->data.activate.any.c = c; act->data.activate.any.c = c;
acts = g_slist_prepend(NULL, act); acts = g_slist_prepend(NULL, act);
e = menu_add_normal(menu, i, e = menu_add_normal(menu, i,
@ -56,16 +57,16 @@ static void desk_menu_update(ObMenuFrame *frame, gpointer data)
} }
/* executes it without changing the client in the actions, since we set that /* executes it using the client in the actions, since we set that
when we make the actions! */ when we make the actions! */
static void desk_menu_execute(ObMenuEntry *self, gpointer data) static void desk_menu_execute(ObMenuEntry *self, guint state, gpointer data)
{ {
GSList *it; GSList *it;
for (it = self->data.normal.actions; it; it = g_slist_next(it)) for (it = self->data.normal.actions; it; it = g_slist_next(it))
{ {
ObAction *act = it->data; ObAction *act = it->data;
act->func(&act->data); action_run(it->data, act->data.any.c, state);
} }
} }

View file

@ -120,7 +120,8 @@ static void send_to_update(ObMenuFrame *frame, gpointer data)
name = screen_desktop_names[i]; name = screen_desktop_names[i];
} }
act = action_from_string("SendToDesktop"); act = action_from_string("SendToDesktop",
OB_USER_ACTION_MENU_SELECTION);
act->data.sendto.desk = desk; act->data.sendto.desk = desk;
act->data.sendto.follow = FALSE; act->data.sendto.follow = FALSE;
acts = g_slist_prepend(NULL, act); acts = g_slist_prepend(NULL, act);
@ -143,13 +144,18 @@ void client_menu_startup()
menu = menu_new(LAYER_MENU_NAME, _("Layer"), NULL); menu = menu_new(LAYER_MENU_NAME, _("Layer"), NULL);
menu_set_update_func(menu, layer_update); menu_set_update_func(menu, layer_update);
acts = g_slist_prepend(NULL, action_from_string("SendToTopLayer")); acts = g_slist_prepend(NULL, action_from_string
("SendToTopLayer", OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, LAYER_TOP, _("Always on top"), acts); menu_add_normal(menu, LAYER_TOP, _("Always on top"), acts);
acts = g_slist_prepend(NULL, action_from_string("SendToNormalLayer")); acts = g_slist_prepend(NULL, action_from_string
("SendToNormalLayer",
OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, LAYER_NORMAL, _("Normal"), acts); menu_add_normal(menu, LAYER_NORMAL, _("Normal"), acts);
acts = g_slist_prepend(NULL, action_from_string("SendToBottomLayer")); acts = g_slist_prepend(NULL, action_from_string
("SendToBottomLayer",
OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, LAYER_BOTTOM, _("Always on bottom"),acts); menu_add_normal(menu, LAYER_BOTTOM, _("Always on bottom"),acts);
@ -168,47 +174,58 @@ void client_menu_startup()
menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME); menu_add_submenu(menu, CLIENT_LAYER, LAYER_MENU_NAME);
acts = g_slist_prepend(NULL, action_from_string("Iconify")); acts = g_slist_prepend(NULL, action_from_string
("Iconify", OB_USER_ACTION_MENU_SELECTION));
e = menu_add_normal(menu, CLIENT_ICONIFY, _("Iconify"), acts); e = menu_add_normal(menu, CLIENT_ICONIFY, _("Iconify"), acts);
e->data.normal.mask = ob_rr_theme->iconify_mask; e->data.normal.mask = ob_rr_theme->iconify_mask;
e->data.normal.mask_normal_color = ob_rr_theme->menu_color; e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color; e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color; e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
acts = g_slist_prepend(NULL, action_from_string("ToggleMaximizeFull")); acts = g_slist_prepend(NULL, action_from_string
("ToggleMaximizeFull",
OB_USER_ACTION_MENU_SELECTION));
e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Maximize"), acts); e = menu_add_normal(menu, CLIENT_MAXIMIZE, _("Maximize"), acts);
e->data.normal.mask = ob_rr_theme->max_mask; e->data.normal.mask = ob_rr_theme->max_mask;
e->data.normal.mask_normal_color = ob_rr_theme->menu_color; e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color; e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color; e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
acts = g_slist_prepend(NULL, action_from_string("Raise")); acts = g_slist_prepend(NULL, action_from_string
("Raise", OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, CLIENT_RAISE, _("Raise to top"), acts); menu_add_normal(menu, CLIENT_RAISE, _("Raise to top"), acts);
acts = g_slist_prepend(NULL, action_from_string("Lower")); acts = g_slist_prepend(NULL, action_from_string
("Lower", OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, CLIENT_LOWER, _("Lower to bottom"),acts); menu_add_normal(menu, CLIENT_LOWER, _("Lower to bottom"),acts);
acts = g_slist_prepend(NULL, action_from_string("ToggleShade")); acts = g_slist_prepend(NULL, action_from_string
("ToggleShade", OB_USER_ACTION_MENU_SELECTION));
e = menu_add_normal(menu, CLIENT_SHADE, _("Roll up/down"), acts); e = menu_add_normal(menu, CLIENT_SHADE, _("Roll up/down"), acts);
e->data.normal.mask = ob_rr_theme->shade_mask; e->data.normal.mask = ob_rr_theme->shade_mask;
e->data.normal.mask_normal_color = ob_rr_theme->menu_color; e->data.normal.mask_normal_color = ob_rr_theme->menu_color;
e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color; e->data.normal.mask_disabled_color = ob_rr_theme->menu_disabled_color;
e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color; e->data.normal.mask_selected_color = ob_rr_theme->menu_selected_color;
acts = g_slist_prepend(NULL, action_from_string("ToggleDecorations")); acts = g_slist_prepend(NULL, action_from_string
("ToggleDecorations",
OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, CLIENT_DECORATE, _("Decorate"), acts); menu_add_normal(menu, CLIENT_DECORATE, _("Decorate"), acts);
menu_add_separator(menu, -1); menu_add_separator(menu, -1);
acts = g_slist_prepend(NULL, action_from_string("KeyboardMove")); acts = g_slist_prepend(NULL, action_from_string
("Move", OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, CLIENT_MOVE, _("Move"), acts); menu_add_normal(menu, CLIENT_MOVE, _("Move"), acts);
acts = g_slist_prepend(NULL, action_from_string("KeyboardResize")); acts = g_slist_prepend(NULL, action_from_string
("Resize", OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(menu, CLIENT_RESIZE, _("Resize"), acts); menu_add_normal(menu, CLIENT_RESIZE, _("Resize"), acts);
menu_add_separator(menu, -1); menu_add_separator(menu, -1);
acts = g_slist_prepend(NULL, action_from_string("Close")); acts = g_slist_prepend(NULL, action_from_string
("Close", OB_USER_ACTION_MENU_SELECTION));
e = menu_add_normal(menu, CLIENT_CLOSE, _("Close"), acts); e = menu_add_normal(menu, CLIENT_CLOSE, _("Close"), acts);
e->data.normal.mask = ob_rr_theme->close_mask; e->data.normal.mask = ob_rr_theme->close_mask;
e->data.normal.mask_normal_color = ob_rr_theme->menu_color; e->data.normal.mask_normal_color = ob_rr_theme->menu_color;

View file

@ -82,20 +82,9 @@ static void parse_key(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
if (keylist) { if (keylist) {
nact = parse_find_node("action", node); nact = parse_find_node("action", node);
while (nact) { while (nact) {
if ((action = action_parse(i, doc, nact))) { if ((action = action_parse(i, doc, nact,
/* validate that its okay for a key binding */ OB_USER_ACTION_KEYBOARD_KEY)))
if (action->func == action_moveresize &&
action->data.moveresize.corner !=
prop_atoms.net_wm_moveresize_move_keyboard &&
action->data.moveresize.corner !=
prop_atoms.net_wm_moveresize_size_keyboard) {
action_free(action);
action = NULL;
}
if (action)
keyboard_bind(keylist, action); keyboard_bind(keylist, action);
}
nact = parse_find_node("action", nact->next); nact = parse_find_node("action", nact->next);
} }
} }
@ -123,6 +112,7 @@ static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
xmlNodePtr n, nbut, nact; xmlNodePtr n, nbut, nact;
char *buttonstr; char *buttonstr;
char *contextstr; char *contextstr;
ObUserAction uact;
ObMouseAction mact; ObMouseAction mact;
ObAction *action; ObAction *action;
@ -141,44 +131,27 @@ static void parse_mouse(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
while (nbut) { while (nbut) {
if (!parse_attr_string("button", nbut, &buttonstr)) if (!parse_attr_string("button", nbut, &buttonstr))
goto next_nbut; goto next_nbut;
if (parse_attr_contains("press", nbut, "action")) if (parse_attr_contains("press", nbut, "action")) {
uact = OB_USER_ACTION_MOUSE_PRESS;
mact = OB_MOUSE_ACTION_PRESS; mact = OB_MOUSE_ACTION_PRESS;
else if (parse_attr_contains("release", nbut, "action")) } else if (parse_attr_contains("release", nbut, "action")) {
uact = OB_USER_ACTION_MOUSE_RELEASE;
mact = OB_MOUSE_ACTION_RELEASE; mact = OB_MOUSE_ACTION_RELEASE;
else if (parse_attr_contains("click", nbut, "action")) } else if (parse_attr_contains("click", nbut, "action")) {
uact = OB_USER_ACTION_MOUSE_CLICK;
mact = OB_MOUSE_ACTION_CLICK; mact = OB_MOUSE_ACTION_CLICK;
else if (parse_attr_contains("doubleclick", nbut,"action")) } else if (parse_attr_contains("doubleclick", nbut,"action")) {
uact = OB_USER_ACTION_MOUSE_DOUBLE_CLICK;
mact = OB_MOUSE_ACTION_DOUBLE_CLICK; mact = OB_MOUSE_ACTION_DOUBLE_CLICK;
else if (parse_attr_contains("drag", nbut, "action")) } else if (parse_attr_contains("drag", nbut, "action")) {
uact = OB_USER_ACTION_MOUSE_MOTION;
mact = OB_MOUSE_ACTION_MOTION; mact = OB_MOUSE_ACTION_MOTION;
else } else
goto next_nbut; goto next_nbut;
nact = parse_find_node("action", nbut->xmlChildrenNode); nact = parse_find_node("action", nbut->xmlChildrenNode);
while (nact) { while (nact) {
if ((action = action_parse(i, doc, nact))) { if ((action = action_parse(i, doc, nact, uact)))
/* validate that its okay for a mouse binding*/
if (mact == OB_MOUSE_ACTION_MOTION) {
if (action->func != action_moveresize ||
action->data.moveresize.corner ==
prop_atoms.net_wm_moveresize_move_keyboard ||
action->data.moveresize.corner ==
prop_atoms.net_wm_moveresize_size_keyboard) {
action_free(action);
action = NULL;
}
} else {
if (action->func == action_moveresize &&
action->data.moveresize.corner !=
prop_atoms.net_wm_moveresize_move_keyboard &&
action->data.moveresize.corner !=
prop_atoms.net_wm_moveresize_size_keyboard) {
action_free(action);
action = NULL;
}
}
if (action)
mouse_bind(buttonstr, contextstr, mact, action); mouse_bind(buttonstr, contextstr, mact, action);
}
nact = parse_find_node("action", nact->next); nact = parse_find_node("action", nact->next);
} }
g_free(buttonstr); g_free(buttonstr);

View file

@ -1126,8 +1126,7 @@ static void event_handle_menu(XEvent *ev)
else { else {
if ((e = menu_entry_frame_under(ev->xbutton.x_root, if ((e = menu_entry_frame_under(ev->xbutton.x_root,
ev->xbutton.y_root))) ev->xbutton.y_root)))
menu_entry_frame_execute(e, menu_entry_frame_execute(e, ev->xbutton.state);
!(ev->xbutton.state & ControlMask));
} }
break; break;
case MotionNotify: case MotionNotify:
@ -1145,8 +1144,7 @@ static void event_handle_menu(XEvent *ev)
else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) { else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
ObMenuFrame *f; ObMenuFrame *f;
if ((f = find_active_menu())) if ((f = find_active_menu()))
menu_entry_frame_execute(f->selected, menu_entry_frame_execute(f->selected, ev->xkey.state);
!(ev->xkey.state & ControlMask));
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) { } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
ObMenuFrame *f; ObMenuFrame *f;
if ((f = find_active_menu()) && f->parent) if ((f = find_active_menu()) && f->parent)

View file

@ -133,6 +133,8 @@ void keyboard_interactive_grab(guint state, ObClient *client,
{ {
ObInteractiveState *s; ObInteractiveState *s;
g_assert(action->data.any.interactive);
if (!interactive_states) { if (!interactive_states) {
if (!grab_keyboard(TRUE)) if (!grab_keyboard(TRUE))
return; return;
@ -179,12 +181,8 @@ gboolean keyboard_process_interactive_grab(const XEvent *e,
cancel = done = TRUE; cancel = done = TRUE;
} }
if (done) { if (done) {
g_assert(s->action->data.any.interactive); action_run_interactive(s->action, s->client,
e->xkey.state, cancel, TRUE);
s->action->data.inter.cancel = cancel;
s->action->data.inter.final = TRUE;
s->action->func(&s->action->data);
g_free(s); g_free(s);
@ -221,7 +219,8 @@ void keyboard_event(ObClient *client, const XEvent *e)
p = curpos->first_child; p = curpos->first_child;
while (p) { while (p) {
if (p->key == e->xkey.keycode && if (p->key == e->xkey.keycode &&
p->state == e->xkey.state) { p->state == e->xkey.state)
{
if (p->first_child != NULL) { /* part of a chain */ if (p->first_child != NULL) { /* part of a chain */
ob_main_loop_timeout_remove(ob_main_loop, chain_timeout); ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
/* 5 second timeout for chains */ /* 5 second timeout for chains */
@ -232,32 +231,10 @@ void keyboard_event(ObClient *client, const XEvent *e)
grab_keys(TRUE); grab_keys(TRUE);
} else { } else {
GSList *it; GSList *it;
for (it = p->actions; it; it = it->next) {
ObAction *act = it->data;
if (act->func != NULL) {
act->data.any.c = client;
if (act->func == action_moveresize) { for (it = p->actions; it; it = it->next)
screen_pointer_pos(&act->data.moveresize.x, action_run_key(it->data, client, e->xkey.state,
&act->data.moveresize.y); e->xkey.x_root, e->xkey.y_root);
}
if (act->data.any.interactive) {
act->data.inter.cancel = FALSE;
act->data.inter.final = FALSE;
keyboard_interactive_grab(e->xkey.state, client,
0, act);
}
if (act->func == action_showmenu) {
act->data.showmenu.x = e->xkey.x_root;
act->data.showmenu.y = e->xkey.y_root;
}
act->data.any.c = client;
act->func(&act->data);
}
}
keyboard_reset_chains(); keyboard_reset_chains();
} }

View file

@ -180,7 +180,9 @@ static void parse_menu_item(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node,
for (node = node->xmlChildrenNode; node; node = node->next) for (node = node->xmlChildrenNode; node; node = node->next)
if (!xmlStrcasecmp(node->name, (const xmlChar*) "action")) if (!xmlStrcasecmp(node->name, (const xmlChar*) "action"))
acts = g_slist_append(acts, action_parse(i, doc, node)); acts = g_slist_append(acts, action_parse
(i, doc, node,
OB_USER_ACTION_MENU_SELECTION));
menu_add_normal(state->parent, -1, label, acts); menu_add_normal(state->parent, -1, label, acts);
g_free(label); g_free(label);
} }

View file

@ -20,7 +20,8 @@ typedef struct _ObSubmenuMenuEntry ObSubmenuMenuEntry;
typedef struct _ObSeparatorMenuEntry ObSeparatorMenuEntry; typedef struct _ObSeparatorMenuEntry ObSeparatorMenuEntry;
typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data); typedef void (*ObMenuUpdateFunc)(struct _ObMenuFrame *frame, gpointer data);
typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry, gpointer data); typedef void (*ObMenuExecuteFunc)(struct _ObMenuEntry *entry,
guint state, gpointer data);
typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data); typedef void (*ObMenuDestroyFunc)(struct _ObMenu *menu, gpointer data);
struct _ObMenu struct _ObMenu

View file

@ -711,7 +711,7 @@ void menu_entry_frame_show_submenu(ObMenuEntryFrame *self)
menu_frame_show(f, self->frame); menu_frame_show(f, self->frame);
} }
void menu_entry_frame_execute(ObMenuEntryFrame *self, gboolean hide) void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state)
{ {
if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && if (self->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
self->entry->data.normal.enabled) self->entry->data.normal.enabled)
@ -725,31 +725,16 @@ void menu_entry_frame_execute(ObMenuEntryFrame *self, gboolean hide)
ObClient *client = self->frame->client; ObClient *client = self->frame->client;
/* release grabs before executing the shit */ /* release grabs before executing the shit */
if (hide) if (!(state & ControlMask))
menu_frame_hide_all(); menu_frame_hide_all();
if (func) if (func)
func(entry, data); func(entry, state, data);
else { else {
GSList *it; GSList *it;
for (it = acts; it; it = g_slist_next(it)) for (it = acts; it; it = g_slist_next(it))
{ action_run(it->data, client, state);
ObAction *act = it->data;
act->data.any.c = client;
if (act->func == action_moveresize)
screen_pointer_pos(&act->data.moveresize.x,
&act->data.moveresize.y);
if (!(act->func == action_cycle_windows ||
act->func == action_desktop_dir ||
act->func == action_send_to_desktop_dir ||
act->func == action_showmenu))
{
act->func(&act->data);
}
}
} }
} }
} }

View file

@ -100,6 +100,6 @@ ObMenuEntryFrame* menu_entry_frame_under(gint x, gint y);
void menu_entry_frame_show_submenu(ObMenuEntryFrame *self); void menu_entry_frame_show_submenu(ObMenuEntryFrame *self);
void menu_entry_frame_execute(ObMenuEntryFrame *self, gboolean hide); void menu_entry_frame_execute(ObMenuEntryFrame *self, guint state);
#endif #endif

View file

@ -62,4 +62,24 @@ typedef enum
OB_CORNER_BOTTOMRIGHT OB_CORNER_BOTTOMRIGHT
} ObCorner; } ObCorner;
typedef enum {
OB_MOUSE_ACTION_PRESS,
OB_MOUSE_ACTION_RELEASE,
OB_MOUSE_ACTION_CLICK,
OB_MOUSE_ACTION_DOUBLE_CLICK,
OB_MOUSE_ACTION_MOTION,
OB_NUM_MOUSE_ACTIONS
} ObMouseAction;
typedef enum {
OB_USER_ACTION_KEYBOARD_KEY,
OB_USER_ACTION_MOUSE_PRESS,
OB_USER_ACTION_MOUSE_RELEASE,
OB_USER_ACTION_MOUSE_CLICK,
OB_USER_ACTION_MOUSE_DOUBLE_CLICK,
OB_USER_ACTION_MOUSE_MOTION,
OB_USER_ACTION_MENU_SELECTION,
OB_NUM_USER_ACTIONS
} ObUserAction;
#endif #endif

View file

@ -9,13 +9,12 @@
#include "frame.h" #include "frame.h"
#include "translate.h" #include "translate.h"
#include "mouse.h" #include "mouse.h"
#include "keyboard.h"
#include <glib.h> #include <glib.h>
typedef struct { typedef struct {
guint state; guint state;
guint button; guint button;
GSList *actions[OB_MOUSE_NUM_ACTIONS]; /* lists of Action pointers */ GSList *actions[OB_NUM_MOUSE_ACTIONS]; /* lists of Action pointers */
} ObMouseBinding; } ObMouseBinding;
#define FRAME_CONTEXT(co, cl) ((cl && cl->type != OB_CLIENT_TYPE_DESKTOP) ? \ #define FRAME_CONTEXT(co, cl) ((cl && cl->type != OB_CLIENT_TYPE_DESKTOP) ? \
@ -33,7 +32,7 @@ void mouse_grab_for_client(ObClient *client, gboolean grab)
GSList *it; GSList *it;
for (i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) for (i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i)
for (it = bound_contexts[i]; it != NULL; it = it->next) { for (it = bound_contexts[i]; it != NULL; it = g_slist_next(it)) {
/* grab/ungrab the button */ /* grab/ungrab the button */
ObMouseBinding *b = it->data; ObMouseBinding *b = it->data;
Window win; Window win;
@ -75,14 +74,14 @@ static void clearall()
for(i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) { for(i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) {
for (it = bound_contexts[i]; it != NULL; it = it->next) { for (it = bound_contexts[i]; it != NULL; it = it->next) {
ObMouseBinding *b = it->data;
int j; int j;
ObMouseBinding *b = it->data; for (j = 0; j < OB_NUM_MOUSE_ACTIONS; ++j) {
for (j = 0; j < OB_MOUSE_NUM_ACTIONS; ++j) {
GSList *it; GSList *it;
for (it = b->actions[j]; it; it = it->next) {
for (it = b->actions[j]; it; it = it->next)
action_free(it->data); action_free(it->data);
}
g_slist_free(b->actions[j]); g_slist_free(b->actions[j]);
} }
g_free(b); g_free(b);
@ -92,7 +91,7 @@ static void clearall()
} }
} }
static gboolean fire_button(ObMouseAction a, ObFrameContext context, static gboolean fire_binding(ObMouseAction a, ObFrameContext context,
ObClient *c, guint state, ObClient *c, guint state,
guint button, int x, int y) guint button, int x, int y)
{ {
@ -107,85 +106,11 @@ static gboolean fire_button(ObMouseAction a, ObFrameContext context,
/* if not bound, then nothing to do! */ /* if not bound, then nothing to do! */
if (it == NULL) return FALSE; if (it == NULL) return FALSE;
for (it = b->actions[a]; it; it = it->next) { for (it = b->actions[a]; it; it = it->next)
ObAction *act = it->data; action_run_mouse(it->data, c, context, state, button, x, y);
if (act->func != NULL) {
act->data.any.c = c;
g_assert(act->func != action_moveresize);
if (act->func == action_showmenu) {
act->data.showmenu.x = x;
act->data.showmenu.y = y;
}
if (act->data.any.interactive) {
act->data.inter.cancel = FALSE;
act->data.inter.final = FALSE;
keyboard_interactive_grab(state, c, context, act);
}
act->func(&act->data);
}
}
return TRUE; return TRUE;
} }
static gboolean fire_motion(ObMouseAction a, ObFrameContext context,
ObClient *c, guint state, guint button,
int x_root, int y_root, guint32 corner)
{
GSList *it;
ObMouseBinding *b;
for (it = bound_contexts[context]; it != NULL; it = it->next) {
b = it->data;
if (b->state == state && b->button == button)
break;
}
/* if not bound, then nothing to do! */
if (it == NULL) return FALSE;
for (it = b->actions[a]; it; it = it->next) {
ObAction *act = it->data;
if (act->func != NULL) {
act->data.any.c = c;
if (act->func == action_moveresize) {
act->data.moveresize.x = x_root;
act->data.moveresize.y = y_root;
act->data.moveresize.button = button;
if (!(act->data.moveresize.corner ==
prop_atoms.net_wm_moveresize_move ||
act->data.moveresize.corner ==
prop_atoms.net_wm_moveresize_move_keyboard ||
act->data.moveresize.corner ==
prop_atoms.net_wm_moveresize_size_keyboard))
act->data.moveresize.corner = corner;
} else
g_assert_not_reached();
act->func(&act->data);
}
}
return TRUE;
}
static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch)
{
if (x - cx < cw / 2) {
if (y - cy < ch / 2)
return prop_atoms.net_wm_moveresize_size_topleft;
else
return prop_atoms.net_wm_moveresize_size_bottomleft;
} else {
if (y - cy < ch / 2)
return prop_atoms.net_wm_moveresize_size_topright;
else
return prop_atoms.net_wm_moveresize_size_bottomright;
}
}
void mouse_event(ObClient *client, ObFrameContext context, XEvent *e) void mouse_event(ObClient *client, ObFrameContext context, XEvent *e)
{ {
static Time ltime; static Time ltime;
@ -203,7 +128,7 @@ void mouse_event(ObClient *client, ObFrameContext context, XEvent *e)
button = e->xbutton.button; button = e->xbutton.button;
state = e->xbutton.state; state = e->xbutton.state;
fire_button(OB_MOUSE_ACTION_PRESS, context, fire_binding(OB_MOUSE_ACTION_PRESS, context,
client, e->xbutton.state, client, e->xbutton.state,
e->xbutton.button, e->xbutton.button,
e->xbutton.x_root, e->xbutton.y_root); e->xbutton.x_root, e->xbutton.y_root);
@ -252,18 +177,18 @@ void mouse_event(ObClient *client, ObFrameContext context, XEvent *e)
state = 0; state = 0;
ltime = e->xbutton.time; ltime = e->xbutton.time;
} }
fire_button(OB_MOUSE_ACTION_RELEASE, context, fire_binding(OB_MOUSE_ACTION_RELEASE, context,
client, e->xbutton.state, client, e->xbutton.state,
e->xbutton.button, e->xbutton.button,
e->xbutton.x_root, e->xbutton.y_root); e->xbutton.x_root, e->xbutton.y_root);
if (click) if (click)
fire_button(OB_MOUSE_ACTION_CLICK, context, fire_binding(OB_MOUSE_ACTION_CLICK, context,
client, e->xbutton.state, client, e->xbutton.state,
e->xbutton.button, e->xbutton.button,
e->xbutton.x_root, e->xbutton.x_root,
e->xbutton.y_root); e->xbutton.y_root);
if (dclick) if (dclick)
fire_button(OB_MOUSE_ACTION_DOUBLE_CLICK, context, fire_binding(OB_MOUSE_ACTION_DOUBLE_CLICK, context,
client, e->xbutton.state, client, e->xbutton.state,
e->xbutton.button, e->xbutton.button,
e->xbutton.x_root, e->xbutton.x_root,
@ -276,7 +201,6 @@ void mouse_event(ObClient *client, ObFrameContext context, XEvent *e)
config_mouse_threshold || config_mouse_threshold ||
ABS(e->xmotion.y_root - py) >= ABS(e->xmotion.y_root - py) >=
config_mouse_threshold) { config_mouse_threshold) {
guint32 corner;
/* You can't drag on buttons */ /* You can't drag on buttons */
if (context == OB_FRAME_CONTEXT_MAXIMIZE || if (context == OB_FRAME_CONTEXT_MAXIMIZE ||
@ -287,26 +211,8 @@ void mouse_event(ObClient *client, ObFrameContext context, XEvent *e)
context == OB_FRAME_CONTEXT_CLOSE) context == OB_FRAME_CONTEXT_CLOSE)
break; break;
if (!client) fire_binding(OB_MOUSE_ACTION_MOTION, context,
corner = prop_atoms.net_wm_moveresize_size_bottomright; client, state, button, px, py);
else
corner =
pick_corner(e->xmotion.x_root,
e->xmotion.y_root,
client->frame->area.x,
client->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 */
client->area.width +
client->frame->size.left +
client->frame->size.right,
client->area.height +
client->frame->size.top +
client->frame->size.bottom);
fire_motion(OB_MOUSE_ACTION_MOTION, context,
client, state, button, px, py, corner);
button = 0; button = 0;
state = 0; state = 0;
} }

View file

@ -3,18 +3,10 @@
#include "action.h" #include "action.h"
#include "frame.h" #include "frame.h"
#include "misc.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
typedef enum {
OB_MOUSE_ACTION_PRESS,
OB_MOUSE_ACTION_RELEASE,
OB_MOUSE_ACTION_CLICK,
OB_MOUSE_ACTION_DOUBLE_CLICK,
OB_MOUSE_ACTION_MOTION,
OB_MOUSE_NUM_ACTIONS
} ObMouseAction;
void mouse_startup(gboolean reconfig); void mouse_startup(gboolean reconfig);
void mouse_shutdown(gboolean reconfig); void mouse_shutdown(gboolean reconfig);