1 #include "openbox/action.h"
2 #include "openbox/action_list.h"
3 #include "openbox/action_parser.h"
4 #include "openbox/action_value.h"
5 #include "openbox/event.h"
6 #include "openbox/stacking.h"
7 #include "openbox/window.h"
8 #include "openbox/focus_cycle.h"
9 #include "openbox/openbox.h"
10 #include "openbox/misc.h"
12 #include "obt/keyboard.h"
17 gboolean dock_windows;
18 gboolean desktop_windows;
19 ObDirection direction;
22 ObActionList *actions;
25 static gboolean cycling = FALSE;
27 static gpointer setup_func(GHashTable *config);
28 static gpointer setup_cycle_func(GHashTable *config,
29 ObActionIPreFunc *pre,
30 ObActionIInputFunc *input,
31 ObActionICancelFunc *cancel,
32 ObActionIPostFunc *post);
33 static gpointer setup_target_func(GHashTable *config);
34 static void free_func(gpointer options);
35 static gboolean run_func(ObActionData *data, gpointer options);
36 static gboolean i_input_func(guint initial_state,
41 static void i_cancel_func(gpointer options);
43 static void end_cycle(gboolean cancel, guint state, Options *o);
45 void action_directionalwindows_startup(void)
47 action_register_i("DirectionalCycleWindows", setup_cycle_func, free_func,
49 action_register("DirectionalTargetWindow", setup_target_func, free_func,
53 static gpointer setup_func(GHashTable *config)
58 o = g_slice_new0(Options);
62 v = g_hash_table_lookup(config, "dialog");
63 if (v && action_value_is_string(v))
64 o->dialog = action_value_bool(v);
65 v = g_hash_table_lookup(config, "bar");
66 if (v && action_value_is_string(v))
67 o->bar = action_value_bool(v);
68 v = g_hash_table_lookup(config, "raise");
69 if (v && action_value_is_string(v))
70 o->raise = action_value_bool(v);
71 v = g_hash_table_lookup(config, "panels");
72 if (v && action_value_is_string(v))
73 o->dock_windows = action_value_bool(v);
74 v = g_hash_table_lookup(config, "desktop");
75 if (v && action_value_is_string(v))
76 o->desktop_windows = action_value_bool(v);
77 v = g_hash_table_lookup(config, "direction");
78 if (v && action_value_is_string(v)) {
79 const gchar *s = action_value_string(v);
80 if (!g_ascii_strcasecmp(s, "north") ||
81 !g_ascii_strcasecmp(s, "up"))
82 o->direction = OB_DIRECTION_NORTH;
83 else if (!g_ascii_strcasecmp(s, "northwest"))
84 o->direction = OB_DIRECTION_NORTHWEST;
85 else if (!g_ascii_strcasecmp(s, "northeast"))
86 o->direction = OB_DIRECTION_NORTHEAST;
87 else if (!g_ascii_strcasecmp(s, "west") ||
88 !g_ascii_strcasecmp(s, "left"))
89 o->direction = OB_DIRECTION_WEST;
90 else if (!g_ascii_strcasecmp(s, "east") ||
91 !g_ascii_strcasecmp(s, "right"))
92 o->direction = OB_DIRECTION_EAST;
93 else if (!g_ascii_strcasecmp(s, "south") ||
94 !g_ascii_strcasecmp(s, "down"))
95 o->direction = OB_DIRECTION_SOUTH;
96 else if (!g_ascii_strcasecmp(s, "southwest"))
97 o->direction = OB_DIRECTION_SOUTHWEST;
98 else if (!g_ascii_strcasecmp(s, "southeast"))
99 o->direction = OB_DIRECTION_SOUTHEAST;
102 v = g_hash_table_lookup(config, "finalactions");
103 if (v && action_value_is_action_list(v)) {
104 o->actions = action_value_action_list(v);
105 action_list_ref(o->actions);
108 ObActionParser *p = action_parser_new();
109 o->actions = action_parser_read_string(p,
113 action_parser_unref(p);
119 static gpointer setup_cycle_func(GHashTable *config,
120 ObActionIPreFunc *pre,
121 ObActionIInputFunc *input,
122 ObActionICancelFunc *cancel,
123 ObActionIPostFunc *post)
125 Options *o = setup_func(config);
126 o->interactive = TRUE;
127 *input = i_input_func;
128 *cancel = i_cancel_func;
132 static gpointer setup_target_func(GHashTable *config)
134 Options *o = setup_func(config);
135 o->interactive = FALSE;
139 static void free_func(gpointer options)
141 Options *o = options;
143 action_list_unref(o->actions);
144 g_slice_free(Options, o);
147 static gboolean run_func(ObActionData *data, gpointer options)
149 Options *o = options;
152 end_cycle(FALSE, data->state, o);
154 struct _ObClient *ft;
156 ft = focus_directional_cycle(o->direction,
166 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
169 return o->interactive;
172 static gboolean i_input_func(guint initial_state,
178 guint mods, initial_mods;
180 initial_mods = obt_keyboard_only_modmasks(initial_state);
181 mods = obt_keyboard_only_modmasks(e->xkey.state);
182 if (e->type == KeyRelease) {
183 /* remove from the state the mask of the modifier key being
184 released, if it is a modifier key being released that is */
185 mods &= ~obt_keyboard_keyevent_to_modmask(e);
188 if (e->type == KeyPress) {
189 KeySym sym = obt_keyboard_keypress_to_keysym(e);
191 /* Escape cancels no matter what */
192 if (sym == XK_Escape) {
193 end_cycle(TRUE, e->xkey.state, options);
197 /* There were no modifiers and they pressed enter */
198 else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_mods) {
199 end_cycle(FALSE, e->xkey.state, options);
203 /* They released the modifiers */
204 else if (e->type == KeyRelease && initial_mods && !(mods & initial_mods)) {
205 end_cycle(FALSE, e->xkey.state, options);
212 static void i_cancel_func(gpointer options)
214 /* we get cancelled when we move focus, but we're not cycling anymore, so
217 end_cycle(TRUE, 0, options);
220 static void end_cycle(gboolean cancel, guint state, Options *o)
222 struct _ObClient *ft;
224 ft = focus_directional_cycle(o->direction,
234 action_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
235 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);