1 #include "openbox/action.h"
2 #include "openbox/action_list.h"
3 #include "openbox/action_list_run.h"
4 #include "openbox/action_parser.h"
5 #include "openbox/action_value.h"
6 #include "openbox/client_set.h"
7 #include "openbox/event.h"
8 #include "openbox/stacking.h"
9 #include "openbox/window.h"
10 #include "openbox/focus_cycle.h"
11 #include "openbox/openbox.h"
12 #include "openbox/misc.h"
14 #include "obt/keyboard.h"
19 gboolean dock_windows;
20 gboolean desktop_windows;
21 ObDirection direction;
24 ObActionList *actions;
27 static gboolean cycling = FALSE;
29 static gpointer setup_func(GHashTable *config);
30 static gpointer setup_cycle_func(GHashTable *config,
31 ObActionIPreFunc *pre,
32 ObActionIInputFunc *input,
33 ObActionICancelFunc *cancel,
34 ObActionIPostFunc *post);
35 static gpointer setup_target_func(GHashTable *config);
36 static void free_func(gpointer options);
37 static gboolean run_func(const ObClientSet *set,
38 const ObActionListRun *data, gpointer options);
39 static gboolean i_input_func(guint initial_state,
44 static void i_cancel_func(gpointer options);
46 static void end_cycle(gboolean cancel, guint state, Options *o);
48 void action_directionalwindows_startup(void)
50 action_register_i("DirectionalCycleWindows", OB_ACTION_DEFAULT_FILTER_ALL,
51 setup_cycle_func, free_func, run_func);
52 action_register("DirectionalTargetWindow", OB_ACTION_DEFAULT_FILTER_ALL,
53 setup_target_func, free_func, run_func);
56 static gpointer setup_func(GHashTable *config)
61 o = g_slice_new0(Options);
65 v = g_hash_table_lookup(config, "dialog");
66 if (v && action_value_is_string(v))
67 o->dialog = action_value_bool(v);
68 v = g_hash_table_lookup(config, "bar");
69 if (v && action_value_is_string(v))
70 o->bar = action_value_bool(v);
71 v = g_hash_table_lookup(config, "raise");
72 if (v && action_value_is_string(v))
73 o->raise = action_value_bool(v);
74 v = g_hash_table_lookup(config, "panels");
75 if (v && action_value_is_string(v))
76 o->dock_windows = action_value_bool(v);
77 v = g_hash_table_lookup(config, "desktop");
78 if (v && action_value_is_string(v))
79 o->desktop_windows = action_value_bool(v);
80 v = g_hash_table_lookup(config, "direction");
81 if (v && action_value_is_string(v)) {
82 const gchar *s = action_value_string(v);
83 if (!g_ascii_strcasecmp(s, "north") ||
84 !g_ascii_strcasecmp(s, "up"))
85 o->direction = OB_DIRECTION_NORTH;
86 else if (!g_ascii_strcasecmp(s, "northwest"))
87 o->direction = OB_DIRECTION_NORTHWEST;
88 else if (!g_ascii_strcasecmp(s, "northeast"))
89 o->direction = OB_DIRECTION_NORTHEAST;
90 else if (!g_ascii_strcasecmp(s, "west") ||
91 !g_ascii_strcasecmp(s, "left"))
92 o->direction = OB_DIRECTION_WEST;
93 else if (!g_ascii_strcasecmp(s, "east") ||
94 !g_ascii_strcasecmp(s, "right"))
95 o->direction = OB_DIRECTION_EAST;
96 else if (!g_ascii_strcasecmp(s, "south") ||
97 !g_ascii_strcasecmp(s, "down"))
98 o->direction = OB_DIRECTION_SOUTH;
99 else if (!g_ascii_strcasecmp(s, "southwest"))
100 o->direction = OB_DIRECTION_SOUTHWEST;
101 else if (!g_ascii_strcasecmp(s, "southeast"))
102 o->direction = OB_DIRECTION_SOUTHEAST;
105 v = g_hash_table_lookup(config, "finalactions");
106 if (v && action_value_is_action_list(v)) {
107 o->actions = action_value_action_list(v);
108 action_list_ref(o->actions);
111 ObActionParser *p = action_parser_new();
112 o->actions = action_parser_read_string(p,
116 action_parser_unref(p);
122 static gpointer setup_cycle_func(GHashTable *config,
123 ObActionIPreFunc *pre,
124 ObActionIInputFunc *input,
125 ObActionICancelFunc *cancel,
126 ObActionIPostFunc *post)
128 Options *o = setup_func(config);
129 o->interactive = TRUE;
130 *input = i_input_func;
131 *cancel = i_cancel_func;
135 static gpointer setup_target_func(GHashTable *config)
137 Options *o = setup_func(config);
138 o->interactive = FALSE;
142 static void free_func(gpointer options)
144 Options *o = options;
146 action_list_unref(o->actions);
147 g_slice_free(Options, o);
150 static gboolean run_func(const ObClientSet *set,
151 const ObActionListRun *data, gpointer options)
153 Options *o = options;
155 if (client_set_is_empty(set)) return FALSE;
158 end_cycle(FALSE, data->mod_state, o);
160 struct _ObClient *ft;
162 ft = focus_directional_cycle(o->direction,
173 if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
176 return o->interactive;
179 static gboolean i_input_func(guint initial_state,
185 guint mods, initial_mods;
187 initial_mods = obt_keyboard_only_modmasks(initial_state);
188 mods = obt_keyboard_only_modmasks(e->xkey.state);
189 if (e->type == KeyRelease) {
190 /* remove from the state the mask of the modifier key being
191 released, if it is a modifier key being released that is */
192 mods &= ~obt_keyboard_keyevent_to_modmask(e);
195 if (e->type == KeyPress) {
196 KeySym sym = obt_keyboard_keypress_to_keysym(e);
198 /* Escape cancels no matter what */
199 if (sym == XK_Escape) {
200 end_cycle(TRUE, e->xkey.state, options);
204 /* There were no modifiers and they pressed enter */
205 else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_mods) {
206 end_cycle(FALSE, e->xkey.state, options);
210 /* They released the modifiers */
211 else if (e->type == KeyRelease && initial_mods && !(mods & initial_mods)) {
212 end_cycle(FALSE, e->xkey.state, options);
219 static void i_cancel_func(gpointer options)
221 /* we get cancelled when we move focus, but we're not cycling anymore, so
224 end_cycle(TRUE, 0, options);
227 static void end_cycle(gboolean cancel, guint state, Options *o)
229 struct _ObClient *ft;
231 ft = focus_directional_cycle(o->direction,
242 action_list_run(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
243 state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);