diff options
45 files changed, 700 insertions, 293 deletions
diff --git a/common/util.c b/common/util.c index e8a88772..467aa4b5 100644 --- a/common/util.c +++ b/common/util.c | |||
@@ -123,6 +123,22 @@ uint32_t parse_color(const char *color) { | |||
123 | return res; | 123 | return res; |
124 | } | 124 | } |
125 | 125 | ||
126 | bool parse_boolean(const char *boolean, bool current) { | ||
127 | if (strcasecmp(boolean, "1") == 0 | ||
128 | || strcasecmp(boolean, "yes") == 0 | ||
129 | || strcasecmp(boolean, "on") == 0 | ||
130 | || strcasecmp(boolean, "true") == 0 | ||
131 | || strcasecmp(boolean, "enable") == 0 | ||
132 | || strcasecmp(boolean, "enabled") == 0 | ||
133 | || strcasecmp(boolean, "active") == 0) { | ||
134 | return true; | ||
135 | } else if (strcasecmp(boolean, "toggle") == 0) { | ||
136 | return !current; | ||
137 | } | ||
138 | // All other values are false to match i3 | ||
139 | return false; | ||
140 | } | ||
141 | |||
126 | char* resolve_path(const char* path) { | 142 | char* resolve_path(const char* path) { |
127 | struct stat sb; | 143 | struct stat sb; |
128 | ssize_t r; | 144 | ssize_t r; |
@@ -16,7 +16,8 @@ set $right l | |||
16 | # Your preferred terminal emulator | 16 | # Your preferred terminal emulator |
17 | set $term urxvt | 17 | set $term urxvt |
18 | # Your preferred application launcher | 18 | # Your preferred application launcher |
19 | set $menu dmenu_run | 19 | # Note: it's recommended that you pass the final command to sway |
20 | set $menu dmenu_path | dmenu | xargs swaymsg exec | ||
20 | 21 | ||
21 | ### Output configuration | 22 | ### Output configuration |
22 | # | 23 | # |
diff --git a/include/sway/config.h b/include/sway/config.h index b8da29c5..4a6bb780 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -1,6 +1,5 @@ | |||
1 | #ifndef _SWAY_CONFIG_H | 1 | #ifndef _SWAY_CONFIG_H |
2 | #define _SWAY_CONFIG_H | 2 | #define _SWAY_CONFIG_H |
3 | #define PID_WORKSPACE_TIMEOUT 60 | ||
4 | #include <libinput.h> | 3 | #include <libinput.h> |
5 | #include <stdint.h> | 4 | #include <stdint.h> |
6 | #include <string.h> | 5 | #include <string.h> |
@@ -22,14 +21,28 @@ struct sway_variable { | |||
22 | char *value; | 21 | char *value; |
23 | }; | 22 | }; |
24 | 23 | ||
24 | |||
25 | enum binding_input_type { | ||
26 | BINDING_KEYCODE, | ||
27 | BINDING_KEYSYM, | ||
28 | BINDING_MOUSE, | ||
29 | }; | ||
30 | |||
31 | enum binding_flags { | ||
32 | BINDING_RELEASE=1, | ||
33 | BINDING_LOCKED=2, // keyboard only | ||
34 | BINDING_BORDER=4, // mouse only; trigger on container border | ||
35 | BINDING_CONTENTS=8, // mouse only; trigger on container contents | ||
36 | BINDING_TITLEBAR=16 // mouse only; trigger on container titlebar | ||
37 | }; | ||
38 | |||
25 | /** | 39 | /** |
26 | * A key binding and an associated command. | 40 | * A key binding and an associated command. |
27 | */ | 41 | */ |
28 | struct sway_binding { | 42 | struct sway_binding { |
43 | enum binding_input_type type; | ||
29 | int order; | 44 | int order; |
30 | bool release; | 45 | uint32_t flags; |
31 | bool locked; | ||
32 | bool bindcode; | ||
33 | list_t *keys; // sorted in ascending order | 46 | list_t *keys; // sorted in ascending order |
34 | uint32_t modifiers; | 47 | uint32_t modifiers; |
35 | char *command; | 48 | char *command; |
@@ -50,6 +63,7 @@ struct sway_mode { | |||
50 | char *name; | 63 | char *name; |
51 | list_t *keysym_bindings; | 64 | list_t *keysym_bindings; |
52 | list_t *keycode_bindings; | 65 | list_t *keycode_bindings; |
66 | list_t *mouse_bindings; | ||
53 | bool pango; | 67 | bool pango; |
54 | }; | 68 | }; |
55 | 69 | ||
@@ -146,12 +160,6 @@ struct workspace_output { | |||
146 | char *workspace; | 160 | char *workspace; |
147 | }; | 161 | }; |
148 | 162 | ||
149 | struct pid_workspace { | ||
150 | pid_t *pid; | ||
151 | char *workspace; | ||
152 | time_t *time_added; | ||
153 | }; | ||
154 | |||
155 | struct bar_config { | 163 | struct bar_config { |
156 | /** | 164 | /** |
157 | * One of "dock", "hide", "invisible" | 165 | * One of "dock", "hide", "invisible" |
@@ -302,7 +310,6 @@ struct sway_config { | |||
302 | list_t *bars; | 310 | list_t *bars; |
303 | list_t *cmd_queue; | 311 | list_t *cmd_queue; |
304 | list_t *workspace_outputs; | 312 | list_t *workspace_outputs; |
305 | list_t *pid_workspaces; | ||
306 | list_t *output_configs; | 313 | list_t *output_configs; |
307 | list_t *input_configs; | 314 | list_t *input_configs; |
308 | list_t *seat_configs; | 315 | list_t *seat_configs; |
@@ -313,6 +320,7 @@ struct sway_config { | |||
313 | struct bar_config *current_bar; | 320 | struct bar_config *current_bar; |
314 | char *swaybg_command; | 321 | char *swaybg_command; |
315 | uint32_t floating_mod; | 322 | uint32_t floating_mod; |
323 | bool floating_mod_inverse; | ||
316 | uint32_t dragging_key; | 324 | uint32_t dragging_key; |
317 | uint32_t resizing_key; | 325 | uint32_t resizing_key; |
318 | char *floating_scroll_up_cmd; | 326 | char *floating_scroll_up_cmd; |
@@ -388,9 +396,6 @@ struct sway_config { | |||
388 | } handler_context; | 396 | } handler_context; |
389 | }; | 397 | }; |
390 | 398 | ||
391 | void pid_workspace_add(struct pid_workspace *pw); | ||
392 | void free_pid_workspace(struct pid_workspace *pw); | ||
393 | |||
394 | /** | 399 | /** |
395 | * Loads the main config from the given path. is_active should be true when | 400 | * Loads the main config from the given path. is_active should be true when |
396 | * reloading the config. | 401 | * reloading the config. |
@@ -482,6 +487,8 @@ void free_sway_binding(struct sway_binding *sb); | |||
482 | 487 | ||
483 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); | 488 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); |
484 | 489 | ||
490 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | ||
491 | |||
485 | void load_swaybars(); | 492 | void load_swaybars(); |
486 | 493 | ||
487 | void invoke_swaybar(struct bar_config *bar); | 494 | void invoke_swaybar(struct bar_config *bar); |
diff --git a/include/sway/criteria.h b/include/sway/criteria.h index 6a8337c5..b4ff7d49 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _SWAY_CRITERIA_H | 2 | #define _SWAY_CRITERIA_H |
3 | 3 | ||
4 | #include <pcre.h> | 4 | #include <pcre.h> |
5 | #include "config.h" | ||
5 | #include "list.h" | 6 | #include "list.h" |
6 | #include "tree/view.h" | 7 | #include "tree/view.h" |
7 | 8 | ||
@@ -25,7 +26,9 @@ struct criteria { | |||
25 | pcre *instance; | 26 | pcre *instance; |
26 | pcre *con_mark; | 27 | pcre *con_mark; |
27 | uint32_t con_id; // internal ID | 28 | uint32_t con_id; // internal ID |
29 | #ifdef HAVE_XWAYLAND | ||
28 | uint32_t id; // X11 window ID | 30 | uint32_t id; // X11 window ID |
31 | #endif | ||
29 | pcre *window_role; | 32 | pcre *window_role; |
30 | uint32_t window_type; | 33 | uint32_t window_type; |
31 | bool floating; | 34 | bool floating; |
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index b0a3a7c5..7ec45120 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h | |||
@@ -3,6 +3,8 @@ | |||
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | 5 | ||
6 | #define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 | ||
7 | |||
6 | struct sway_cursor { | 8 | struct sway_cursor { |
7 | struct sway_seat *seat; | 9 | struct sway_seat *seat; |
8 | struct wlr_cursor *cursor; | 10 | struct wlr_cursor *cursor; |
@@ -29,6 +31,10 @@ struct sway_cursor { | |||
29 | uint32_t tool_buttons; | 31 | uint32_t tool_buttons; |
30 | 32 | ||
31 | struct wl_listener request_set_cursor; | 33 | struct wl_listener request_set_cursor; |
34 | |||
35 | // Mouse binding state | ||
36 | uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; | ||
37 | size_t pressed_button_count; | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | void sway_cursor_destroy(struct sway_cursor *cursor); | 40 | void sway_cursor_destroy(struct sway_cursor *cursor); |
diff --git a/include/sway/server.h b/include/sway/server.h index 70bde6d4..a3782f91 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -12,7 +12,10 @@ | |||
12 | #include <wlr/render/wlr_renderer.h> | 12 | #include <wlr/render/wlr_renderer.h> |
13 | // TODO WLR: make Xwayland optional | 13 | // TODO WLR: make Xwayland optional |
14 | #include "list.h" | 14 | #include "list.h" |
15 | #include "config.h" | ||
16 | #ifdef HAVE_XWAYLAND | ||
15 | #include "sway/xwayland.h" | 17 | #include "sway/xwayland.h" |
18 | #endif | ||
16 | 19 | ||
17 | struct sway_server { | 20 | struct sway_server { |
18 | struct wl_display *wl_display; | 21 | struct wl_display *wl_display; |
@@ -39,11 +42,11 @@ struct sway_server { | |||
39 | 42 | ||
40 | struct wlr_xdg_shell *xdg_shell; | 43 | struct wlr_xdg_shell *xdg_shell; |
41 | struct wl_listener xdg_shell_surface; | 44 | struct wl_listener xdg_shell_surface; |
42 | 45 | #ifdef HAVE_XWAYLAND | |
43 | struct sway_xwayland xwayland; | 46 | struct sway_xwayland xwayland; |
44 | struct wl_listener xwayland_surface; | 47 | struct wl_listener xwayland_surface; |
45 | struct wl_listener xwayland_ready; | 48 | struct wl_listener xwayland_ready; |
46 | 49 | #endif | |
47 | bool debug_txn_timings; | 50 | bool debug_txn_timings; |
48 | 51 | ||
49 | list_t *transactions; | 52 | list_t *transactions; |
@@ -65,6 +68,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data); | |||
65 | void handle_layer_shell_surface(struct wl_listener *listener, void *data); | 68 | void handle_layer_shell_surface(struct wl_listener *listener, void *data); |
66 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); | 69 | void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); |
67 | void handle_xdg_shell_surface(struct wl_listener *listener, void *data); | 70 | void handle_xdg_shell_surface(struct wl_listener *listener, void *data); |
71 | #ifdef HAVE_XWAYLAND | ||
68 | void handle_xwayland_surface(struct wl_listener *listener, void *data); | 72 | void handle_xwayland_surface(struct wl_listener *listener, void *data); |
69 | 73 | #endif | |
70 | #endif | 74 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 7d7da2d7..a4c31bf6 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <wlr/types/wlr_output_layout.h> | 3 | #include <wlr/types/wlr_output_layout.h> |
4 | #include <wlr/render/wlr_texture.h> | 4 | #include <wlr/render/wlr_texture.h> |
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "config.h" | ||
6 | 7 | ||
7 | enum movement_direction { | 8 | enum movement_direction { |
8 | MOVE_LEFT, | 9 | MOVE_LEFT, |
@@ -27,8 +28,9 @@ struct sway_root { | |||
27 | struct wlr_output_layout *output_layout; | 28 | struct wlr_output_layout *output_layout; |
28 | 29 | ||
29 | struct wl_listener output_layout_change; | 30 | struct wl_listener output_layout_change; |
30 | 31 | #ifdef HAVE_XWAYLAND | |
31 | struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link | 32 | struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link |
33 | #endif | ||
32 | struct wl_list drag_icons; // sway_drag_icon::link | 34 | struct wl_list drag_icons; // sway_drag_icon::link |
33 | 35 | ||
34 | struct wlr_texture *debug_tree; | 36 | struct wlr_texture *debug_tree; |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 3bdfe252..1972447b 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -3,7 +3,10 @@ | |||
3 | #include <wayland-server.h> | 3 | #include <wayland-server.h> |
4 | #include <wlr/types/wlr_surface.h> | 4 | #include <wlr/types/wlr_surface.h> |
5 | #include <wlr/types/wlr_xdg_shell_v6.h> | 5 | #include <wlr/types/wlr_xdg_shell_v6.h> |
6 | #include "config.h" | ||
7 | #ifdef HAVE_XWAYLAND | ||
6 | #include <wlr/xwayland.h> | 8 | #include <wlr/xwayland.h> |
9 | #endif | ||
7 | #include "sway/input/input-manager.h" | 10 | #include "sway/input/input-manager.h" |
8 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
9 | 12 | ||
@@ -12,7 +15,9 @@ struct sway_container; | |||
12 | enum sway_view_type { | 15 | enum sway_view_type { |
13 | SWAY_VIEW_XDG_SHELL_V6, | 16 | SWAY_VIEW_XDG_SHELL_V6, |
14 | SWAY_VIEW_XDG_SHELL, | 17 | SWAY_VIEW_XDG_SHELL, |
18 | #ifdef HAVE_XWAYLAND | ||
15 | SWAY_VIEW_XWAYLAND, | 19 | SWAY_VIEW_XWAYLAND, |
20 | #endif | ||
16 | }; | 21 | }; |
17 | 22 | ||
18 | enum sway_view_prop { | 23 | enum sway_view_prop { |
@@ -22,7 +27,9 @@ enum sway_view_prop { | |||
22 | VIEW_PROP_INSTANCE, | 27 | VIEW_PROP_INSTANCE, |
23 | VIEW_PROP_WINDOW_TYPE, | 28 | VIEW_PROP_WINDOW_TYPE, |
24 | VIEW_PROP_WINDOW_ROLE, | 29 | VIEW_PROP_WINDOW_ROLE, |
30 | #ifdef HAVE_XWAYLAND | ||
25 | VIEW_PROP_X11_WINDOW_ID, | 31 | VIEW_PROP_X11_WINDOW_ID, |
32 | #endif | ||
26 | }; | 33 | }; |
27 | 34 | ||
28 | struct sway_view_impl { | 35 | struct sway_view_impl { |
@@ -90,7 +97,9 @@ struct sway_view { | |||
90 | union { | 97 | union { |
91 | struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; | 98 | struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; |
92 | struct wlr_xdg_surface *wlr_xdg_surface; | 99 | struct wlr_xdg_surface *wlr_xdg_surface; |
100 | #ifdef HAVE_XWAYLAND | ||
93 | struct wlr_xwayland_surface *wlr_xwayland_surface; | 101 | struct wlr_xwayland_surface *wlr_xwayland_surface; |
102 | #endif | ||
94 | struct wlr_wl_shell_surface *wlr_wl_shell_surface; | 103 | struct wlr_wl_shell_surface *wlr_wl_shell_surface; |
95 | }; | 104 | }; |
96 | 105 | ||
@@ -133,7 +142,7 @@ struct sway_xdg_shell_view { | |||
133 | struct wl_listener unmap; | 142 | struct wl_listener unmap; |
134 | struct wl_listener destroy; | 143 | struct wl_listener destroy; |
135 | }; | 144 | }; |
136 | 145 | #ifdef HAVE_XWAYLAND | |
137 | struct sway_xwayland_view { | 146 | struct sway_xwayland_view { |
138 | struct sway_view view; | 147 | struct sway_view view; |
139 | 148 | ||
@@ -165,7 +174,7 @@ struct sway_xwayland_unmanaged { | |||
165 | struct wl_listener unmap; | 174 | struct wl_listener unmap; |
166 | struct wl_listener destroy; | 175 | struct wl_listener destroy; |
167 | }; | 176 | }; |
168 | 177 | #endif | |
169 | struct sway_view_child; | 178 | struct sway_view_child; |
170 | 179 | ||
171 | struct sway_view_child_impl { | 180 | struct sway_view_child_impl { |
@@ -281,9 +290,10 @@ struct sway_view *view_from_wlr_xdg_surface( | |||
281 | struct wlr_xdg_surface *xdg_surface); | 290 | struct wlr_xdg_surface *xdg_surface); |
282 | struct sway_view *view_from_wlr_xdg_surface_v6( | 291 | struct sway_view *view_from_wlr_xdg_surface_v6( |
283 | struct wlr_xdg_surface_v6 *xdg_surface_v6); | 292 | struct wlr_xdg_surface_v6 *xdg_surface_v6); |
293 | #ifdef HAVE_XWAYLAND | ||
284 | struct sway_view *view_from_wlr_xwayland_surface( | 294 | struct sway_view *view_from_wlr_xwayland_surface( |
285 | struct wlr_xwayland_surface *xsurface); | 295 | struct wlr_xwayland_surface *xsurface); |
286 | 296 | #endif | |
287 | struct sway_view *view_from_wlr_surface(struct wlr_surface *surface); | 297 | struct sway_view *view_from_wlr_surface(struct wlr_surface *surface); |
288 | 298 | ||
289 | /** | 299 | /** |
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index bc95317a..ff66da6b 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -44,6 +44,10 @@ void workspace_output_add_priority(struct sway_container *workspace, | |||
44 | struct sway_container *workspace_output_get_highest_available( | 44 | struct sway_container *workspace_output_get_highest_available( |
45 | struct sway_container *ws, struct sway_container *exclude); | 45 | struct sway_container *ws, struct sway_container *exclude); |
46 | 46 | ||
47 | struct sway_container *workspace_for_pid(pid_t pid); | ||
48 | |||
49 | void workspace_record_pid(pid_t pid); | ||
50 | |||
47 | void workspace_detect_urgent(struct sway_container *workspace); | 51 | void workspace_detect_urgent(struct sway_container *workspace); |
48 | 52 | ||
49 | #endif | 53 | #endif |
diff --git a/include/util.h b/include/util.h index f68deae8..bda941ce 100644 --- a/include/util.h +++ b/include/util.h | |||
@@ -51,6 +51,14 @@ pid_t get_parent_pid(pid_t pid); | |||
51 | uint32_t parse_color(const char *color); | 51 | uint32_t parse_color(const char *color); |
52 | 52 | ||
53 | /** | 53 | /** |
54 | * Given a string that represents a boolean, return the boolean value. This | ||
55 | * function also takes in the current boolean value to support toggling. If | ||
56 | * toggling is not desired, pass in true for current so that toggling values | ||
57 | * get parsed as not true. | ||
58 | */ | ||
59 | bool parse_boolean(const char *boolean, bool current); | ||
60 | |||
61 | /** | ||
54 | * Given a path string, recurseively resolves any symlinks to their targets | 62 | * Given a path string, recurseively resolves any symlinks to their targets |
55 | * (which may be a file, directory) and returns the result. | 63 | * (which may be a file, directory) and returns the result. |
56 | * argument is returned. Caller must free the returned buffer. | 64 | * argument is returned. Caller must free the returned buffer. |
diff --git a/meson.build b/meson.build index 1d40581a..06299618 100644 --- a/meson.build +++ b/meson.build | |||
@@ -48,6 +48,12 @@ git = find_program('git', required: false) | |||
48 | 48 | ||
49 | conf_data = configuration_data() | 49 | conf_data = configuration_data() |
50 | 50 | ||
51 | if get_option('enable-xwayland') | ||
52 | conf_data.set('HAVE_XWAYLAND', true) | ||
53 | else | ||
54 | conf_data.set('HAVE_XWAYLAND', false) | ||
55 | endif | ||
56 | |||
51 | if gdk_pixbuf.found() | 57 | if gdk_pixbuf.found() |
52 | conf_data.set('HAVE_GDK_PIXBUF', true) | 58 | conf_data.set('HAVE_GDK_PIXBUF', true) |
53 | endif | 59 | endif |
diff --git a/meson_options.txt b/meson_options.txt index 541ccf13..6c7f241d 100644 --- a/meson_options.txt +++ b/meson_options.txt | |||
@@ -1,3 +1,4 @@ | |||
1 | option('sway_version', type : 'string', description: 'The version string reported in `sway --version`.') | 1 | option('sway_version', type : 'string', description: 'The version string reported in `sway --version`.') |
2 | option('default_wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') | 2 | option('default_wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') |
3 | option('zsh_completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') | 3 | option('zsh_completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') |
4 | option('enable-xwayland', type: 'boolean', value: true, description: 'Enable support for X11 applications') | ||
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 83e9e432..133fd089 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -34,11 +34,14 @@ void free_sway_binding(struct sway_binding *binding) { | |||
34 | */ | 34 | */ |
35 | static bool binding_key_compare(struct sway_binding *binding_a, | 35 | static bool binding_key_compare(struct sway_binding *binding_a, |
36 | struct sway_binding *binding_b) { | 36 | struct sway_binding *binding_b) { |
37 | if (binding_a->release != binding_b->release) { | 37 | if (binding_a->type != binding_b->type) { |
38 | return false; | 38 | return false; |
39 | } | 39 | } |
40 | 40 | ||
41 | if (binding_a->bindcode != binding_b->bindcode) { | 41 | uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER |
42 | | BINDING_CONTENTS | BINDING_TITLEBAR; | ||
43 | if ((binding_a->flags & conflict_generating_flags) != | ||
44 | (binding_b->flags & conflict_generating_flags)) { | ||
42 | return false; | 45 | return false; |
43 | } | 46 | } |
44 | 47 | ||
@@ -69,6 +72,66 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { | |||
69 | return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); | 72 | return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); |
70 | } | 73 | } |
71 | 74 | ||
75 | |||
76 | /** | ||
77 | * From a keycode, bindcode, or bindsym name and the most likely binding type, | ||
78 | * identify the appropriate numeric value corresponding to the key. Return NULL | ||
79 | * and set *key_val if successful, otherwise return a specific error. Change | ||
80 | * the value of *type if the initial type guess was incorrect and if this | ||
81 | * was the first identified key. | ||
82 | */ | ||
83 | static struct cmd_results *identify_key(const char* name, bool first_key, | ||
84 | uint32_t* key_val, enum binding_input_type* type) { | ||
85 | if (*type == BINDING_KEYCODE) { | ||
86 | // check for keycode | ||
87 | xkb_keycode_t keycode = strtol(name, NULL, 10); | ||
88 | if (!xkb_keycode_is_legal_ext(keycode)) { | ||
89 | return cmd_results_new(CMD_INVALID, "bindcode", | ||
90 | "Invalid keycode '%s'", name); | ||
91 | } | ||
92 | *key_val = keycode; | ||
93 | } else { | ||
94 | // check for keysym | ||
95 | xkb_keysym_t keysym = xkb_keysym_from_name(name, | ||
96 | XKB_KEYSYM_CASE_INSENSITIVE); | ||
97 | |||
98 | // Check for mouse binding | ||
99 | uint32_t button = 0; | ||
100 | if (strncasecmp(name, "button", strlen("button")) == 0 && | ||
101 | strlen(name) == strlen("button0")) { | ||
102 | button = name[strlen("button")] - '1' + BTN_LEFT; | ||
103 | } | ||
104 | |||
105 | if (*type == BINDING_KEYSYM) { | ||
106 | if (button) { | ||
107 | if (first_key) { | ||
108 | *type = BINDING_MOUSE; | ||
109 | *key_val = button; | ||
110 | } else { | ||
111 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
112 | "Mixed button '%s' into key sequence", name); | ||
113 | } | ||
114 | } else if (keysym) { | ||
115 | *key_val = keysym; | ||
116 | } else { | ||
117 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
118 | "Unknown key '%s'", name); | ||
119 | } | ||
120 | } else { | ||
121 | if (button) { | ||
122 | *key_val = button; | ||
123 | } else if (keysym) { | ||
124 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
125 | "Mixed keysym '%s' into button sequence", name); | ||
126 | } else { | ||
127 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
128 | "Unknown button '%s'", name); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
72 | static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | 135 | static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, |
73 | bool bindcode) { | 136 | bool bindcode) { |
74 | const char *bindtype = bindcode ? "bindcode" : "bindsym"; | 137 | const char *bindtype = bindcode ? "bindcode" : "bindsym"; |
@@ -85,22 +148,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
85 | } | 148 | } |
86 | binding->keys = create_list(); | 149 | binding->keys = create_list(); |
87 | binding->modifiers = 0; | 150 | binding->modifiers = 0; |
88 | binding->release = false; | 151 | binding->flags = 0; |
89 | binding->locked = false; | 152 | binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM; |
90 | binding->bindcode = bindcode; | 153 | |
154 | bool exclude_titlebar = false; | ||
91 | 155 | ||
92 | // Handle --release and --locked | 156 | // Handle --release and --locked |
93 | while (argc > 0) { | 157 | while (argc > 0) { |
94 | if (strcmp("--release", argv[0]) == 0) { | 158 | if (strcmp("--release", argv[0]) == 0) { |
95 | binding->release = true; | 159 | binding->flags |= BINDING_RELEASE; |
96 | } else if (strcmp("--locked", argv[0]) == 0) { | 160 | } else if (strcmp("--locked", argv[0]) == 0) { |
97 | binding->locked = true; | 161 | binding->flags |= BINDING_LOCKED; |
162 | } else if (strcmp("--whole-window", argv[0]) == 0) { | ||
163 | binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR; | ||
164 | } else if (strcmp("--border", argv[0]) == 0) { | ||
165 | binding->flags |= BINDING_BORDER; | ||
166 | } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { | ||
167 | exclude_titlebar = true; | ||
98 | } else { | 168 | } else { |
99 | break; | 169 | break; |
100 | } | 170 | } |
101 | argv++; | 171 | argv++; |
102 | argc--; | 172 | argc--; |
103 | } | 173 | } |
174 | if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR) | ||
175 | || exclude_titlebar) { | ||
176 | binding->type = BINDING_MOUSE; | ||
177 | } | ||
178 | |||
104 | if (argc < 2) { | 179 | if (argc < 2) { |
105 | free_sway_binding(binding); | 180 | free_sway_binding(binding); |
106 | return cmd_results_new(CMD_FAILURE, bindtype, | 181 | return cmd_results_new(CMD_FAILURE, bindtype, |
@@ -119,64 +194,47 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
119 | continue; | 194 | continue; |
120 | } | 195 | } |
121 | 196 | ||
122 | xkb_keycode_t keycode; | 197 | // Identify the key and possibly change binding->type |
123 | xkb_keysym_t keysym; | 198 | uint32_t key_val = 0; |
124 | if (bindcode) { | 199 | error = identify_key(split->items[i], binding->keys->length == 0, |
125 | // parse keycode | 200 | &key_val, &binding->type); |
126 | keycode = (int)strtol(split->items[i], NULL, 10); | 201 | if (error) { |
127 | if (!xkb_keycode_is_legal_ext(keycode)) { | 202 | free_sway_binding(binding); |
128 | error = | 203 | list_free(split); |
129 | cmd_results_new(CMD_INVALID, "bindcode", | 204 | return error; |
130 | "Invalid keycode '%s'", (char *)split->items[i]); | ||
131 | free_sway_binding(binding); | ||
132 | list_free(split); | ||
133 | return error; | ||
134 | } | ||
135 | } else { | ||
136 | // Check for xkb key | ||
137 | keysym = xkb_keysym_from_name(split->items[i], | ||
138 | XKB_KEYSYM_CASE_INSENSITIVE); | ||
139 | |||
140 | // Check for mouse binding | ||
141 | if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && | ||
142 | strlen(split->items[i]) == strlen("button0")) { | ||
143 | keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; | ||
144 | } | ||
145 | if (!keysym) { | ||
146 | struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", | ||
147 | "Unknown key '%s'", (char *)split->items[i]); | ||
148 | free_sway_binding(binding); | ||
149 | free_flat_list(split); | ||
150 | return ret; | ||
151 | } | ||
152 | } | 205 | } |
206 | |||
153 | uint32_t *key = calloc(1, sizeof(uint32_t)); | 207 | uint32_t *key = calloc(1, sizeof(uint32_t)); |
154 | if (!key) { | 208 | if (!key) { |
155 | free_sway_binding(binding); | 209 | free_sway_binding(binding); |
156 | free_flat_list(split); | 210 | free_flat_list(split); |
157 | return cmd_results_new(CMD_FAILURE, bindtype, | 211 | return cmd_results_new(CMD_FAILURE, bindtype, |
158 | "Unable to allocate binding"); | 212 | "Unable to allocate binding key"); |
159 | } | 213 | } |
160 | 214 | *key = key_val; | |
161 | if (bindcode) { | ||
162 | *key = (uint32_t)keycode; | ||
163 | } else { | ||
164 | *key = (uint32_t)keysym; | ||
165 | } | ||
166 | |||
167 | list_add(binding->keys, key); | 215 | list_add(binding->keys, key); |
168 | } | 216 | } |
169 | free_flat_list(split); | 217 | free_flat_list(split); |
170 | binding->order = binding_order++; | 218 | binding->order = binding_order++; |
171 | 219 | ||
220 | // refine region of interest for mouse binding once we are certain | ||
221 | // that this is one | ||
222 | if (exclude_titlebar) { | ||
223 | binding->flags &= ~BINDING_TITLEBAR; | ||
224 | } else if (binding->type == BINDING_MOUSE) { | ||
225 | binding->flags |= BINDING_TITLEBAR; | ||
226 | } | ||
227 | |||
172 | // sort ascending | 228 | // sort ascending |
173 | list_qsort(binding->keys, key_qsort_cmp); | 229 | list_qsort(binding->keys, key_qsort_cmp); |
174 | 230 | ||
175 | list_t *mode_bindings; | 231 | list_t *mode_bindings; |
176 | if (bindcode) { | 232 | if (binding->type == BINDING_KEYCODE) { |
177 | mode_bindings = config->current_mode->keycode_bindings; | 233 | mode_bindings = config->current_mode->keycode_bindings; |
178 | } else { | 234 | } else if (binding->type == BINDING_KEYSYM) { |
179 | mode_bindings = config->current_mode->keysym_bindings; | 235 | mode_bindings = config->current_mode->keysym_bindings; |
236 | } else { | ||
237 | mode_bindings = config->current_mode->mouse_bindings; | ||
180 | } | 238 | } |
181 | 239 | ||
182 | // overwrite the binding if it already exists | 240 | // overwrite the binding if it already exists |
@@ -209,3 +267,19 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { | |||
209 | struct cmd_results *cmd_bindcode(int argc, char **argv) { | 267 | struct cmd_results *cmd_bindcode(int argc, char **argv) { |
210 | return cmd_bindsym_or_bindcode(argc, argv, true); | 268 | return cmd_bindsym_or_bindcode(argc, argv, true); |
211 | } | 269 | } |
270 | |||
271 | |||
272 | /** | ||
273 | * Execute the command associated to a binding | ||
274 | */ | ||
275 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { | ||
276 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
277 | binding->command); | ||
278 | config->handler_context.seat = seat; | ||
279 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
280 | if (results->status != CMD_SUCCESS) { | ||
281 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
282 | binding->command, results->error); | ||
283 | } | ||
284 | free_cmd_results(results); | ||
285 | } | ||
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index c7727857..9bf2b320 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c | |||
@@ -74,7 +74,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) { | |||
74 | waitpid(pid, NULL, 0); | 74 | waitpid(pid, NULL, 0); |
75 | if (child > 0) { | 75 | if (child > 0) { |
76 | wlr_log(WLR_DEBUG, "Child process created with pid %d", child); | 76 | wlr_log(WLR_DEBUG, "Child process created with pid %d", child); |
77 | // TODO: add PID to active workspace | 77 | workspace_record_pid(child); |
78 | } else { | 78 | } else { |
79 | return cmd_results_new(CMD_FAILURE, "exec_always", | 79 | return cmd_results_new(CMD_FAILURE, "exec_always", |
80 | "Second fork() failed"); | 80 | "Second fork() failed"); |
diff --git a/sway/commands/floating_modifier.c b/sway/commands/floating_modifier.c index 9432c9f1..f5d2b3fe 100644 --- a/sway/commands/floating_modifier.c +++ b/sway/commands/floating_modifier.c | |||
@@ -1,10 +1,11 @@ | |||
1 | #include "strings.h" | ||
1 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
2 | #include "sway/config.h" | 3 | #include "sway/config.h" |
3 | #include "util.h" | 4 | #include "util.h" |
4 | 5 | ||
5 | struct cmd_results *cmd_floating_modifier(int argc, char **argv) { | 6 | struct cmd_results *cmd_floating_modifier(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 7 | struct cmd_results *error = NULL; |
7 | if ((error = checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1))) { | 8 | if ((error = checkarg(argc, "floating_modifier", EXPECTED_AT_LEAST, 1))) { |
8 | return error; | 9 | return error; |
9 | } | 10 | } |
10 | 11 | ||
@@ -14,6 +15,15 @@ struct cmd_results *cmd_floating_modifier(int argc, char **argv) { | |||
14 | "Invalid modifier"); | 15 | "Invalid modifier"); |
15 | } | 16 | } |
16 | 17 | ||
18 | if (argc == 1 || strcasecmp(argv[1], "normal") == 0) { | ||
19 | config->floating_mod_inverse = false; | ||
20 | } else if (strcasecmp(argv[1], "inverse") == 0) { | ||
21 | config->floating_mod_inverse = true; | ||
22 | } else { | ||
23 | return cmd_results_new(CMD_INVALID, "floating_modifier", | ||
24 | "Usage: floating_modifier <mod> [inverse|normal]"); | ||
25 | } | ||
26 | |||
17 | config->floating_mod = mod; | 27 | config->floating_mod = mod; |
18 | 28 | ||
19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 29 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c index 661e7852..0b0e334c 100644 --- a/sway/commands/focus_follows_mouse.c +++ b/sway/commands/focus_follows_mouse.c | |||
@@ -1,12 +1,14 @@ | |||
1 | #include <string.h> | 1 | #include <string.h> |
2 | #include <strings.h> | 2 | #include <strings.h> |
3 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { | 6 | struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 7 | struct cmd_results *error = NULL; |
7 | if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { | 8 | if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { |
8 | return error; | 9 | return error; |
9 | } | 10 | } |
10 | config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); | 11 | config->focus_follows_mouse = |
12 | parse_boolean(argv[0], config->focus_follows_mouse); | ||
11 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 13 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
12 | } | 14 | } |
diff --git a/sway/commands/focus_wrapping.c b/sway/commands/focus_wrapping.c index 0a9e0bf2..562ee4f9 100644 --- a/sway/commands/focus_wrapping.c +++ b/sway/commands/focus_wrapping.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { | 6 | struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 7 | struct cmd_results *error = NULL; |
@@ -8,15 +9,12 @@ struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { | |||
8 | return error; | 9 | return error; |
9 | } | 10 | } |
10 | 11 | ||
11 | if (strcasecmp(argv[0], "no") == 0) { | 12 | if (strcasecmp(argv[0], "force") == 0) { |
12 | config->focus_wrapping = WRAP_NO; | ||
13 | } else if (strcasecmp(argv[0], "yes") == 0) { | ||
14 | config->focus_wrapping = WRAP_YES; | ||
15 | } else if (strcasecmp(argv[0], "force") == 0) { | ||
16 | config->focus_wrapping = WRAP_FORCE; | 13 | config->focus_wrapping = WRAP_FORCE; |
14 | } else if (parse_boolean(argv[0], config->focus_wrapping == WRAP_YES)) { | ||
15 | config->focus_wrapping = WRAP_YES; | ||
17 | } else { | 16 | } else { |
18 | return cmd_results_new(CMD_INVALID, "focus_wrapping", | 17 | config->focus_wrapping = WRAP_NO; |
19 | "Expected 'focus_wrapping yes|no|force'"); | ||
20 | } | 18 | } |
21 | 19 | ||
22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 20 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/force_focus_wrapping.c b/sway/commands/force_focus_wrapping.c index bc1d067f..0892d9e9 100644 --- a/sway/commands/force_focus_wrapping.c +++ b/sway/commands/force_focus_wrapping.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { | 6 | struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { |
6 | struct cmd_results *error = | 7 | struct cmd_results *error = |
@@ -9,13 +10,10 @@ struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { | |||
9 | return error; | 10 | return error; |
10 | } | 11 | } |
11 | 12 | ||
12 | if (strcasecmp(argv[0], "no") == 0) { | 13 | if (parse_boolean(argv[0], config->focus_wrapping == WRAP_FORCE)) { |
13 | config->focus_wrapping = WRAP_YES; | ||
14 | } else if (strcasecmp(argv[0], "yes") == 0) { | ||
15 | config->focus_wrapping = WRAP_FORCE; | 14 | config->focus_wrapping = WRAP_FORCE; |
16 | } else { | 15 | } else { |
17 | return cmd_results_new(CMD_INVALID, "force_focus_wrapping", | 16 | config->focus_wrapping = WRAP_YES; |
18 | "Expected 'force_focus_wrapping yes|no'"); | ||
19 | } | 17 | } |
20 | 18 | ||
21 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 0b5beaa2..b423fd23 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/layout.h" | 7 | #include "sway/tree/layout.h" |
8 | #include "util.h" | ||
8 | 9 | ||
9 | struct cmd_results *cmd_fullscreen(int argc, char **argv) { | 10 | struct cmd_results *cmd_fullscreen(int argc, char **argv) { |
10 | struct cmd_results *error = NULL; | 11 | struct cmd_results *error = NULL; |
@@ -18,17 +19,10 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
18 | "Only views can fullscreen"); | 19 | "Only views can fullscreen"); |
19 | } | 20 | } |
20 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->sway_view; |
21 | bool wants_fullscreen; | 22 | bool wants_fullscreen = !view->is_fullscreen; |
22 | 23 | ||
23 | if (argc == 0 || strcmp(argv[0], "toggle") == 0) { | 24 | if (argc) { |
24 | wants_fullscreen = !view->is_fullscreen; | 25 | wants_fullscreen = parse_boolean(argv[0], view->is_fullscreen); |
25 | } else if (strcmp(argv[0], "enable") == 0) { | ||
26 | wants_fullscreen = true; | ||
27 | } else if (strcmp(argv[0], "disable") == 0) { | ||
28 | wants_fullscreen = false; | ||
29 | } else { | ||
30 | return cmd_results_new(CMD_INVALID, "fullscreen", | ||
31 | "Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'"); | ||
32 | } | 26 | } |
33 | 27 | ||
34 | view_set_fullscreen(view, wants_fullscreen); | 28 | view_set_fullscreen(view, wants_fullscreen); |
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c index 9e32816f..f9ddeef2 100644 --- a/sway/commands/input/drag_lock.c +++ b/sway/commands/input/drag_lock.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; | 23 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; | ||
25 | } else { | 24 | } else { |
26 | free_input_config(new_config); | 25 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; |
27 | return cmd_results_new(CMD_INVALID, "drag_lock", | ||
28 | "Expected 'drag_lock <enabled|disabled>'"); | ||
29 | } | 26 | } |
30 | 27 | ||
31 | apply_input_config(new_config); | 28 | apply_input_config(new_config); |
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c index 73937507..15134268 100644 --- a/sway/commands/input/dwt.c +++ b/sway/commands/input/dwt.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_dwt(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_dwt(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -17,14 +18,10 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) { | |||
17 | struct input_config *new_config = | 18 | struct input_config *new_config = |
18 | new_input_config(current_input_config->identifier); | 19 | new_input_config(current_input_config->identifier); |
19 | 20 | ||
20 | if (strcasecmp(argv[0], "enabled") == 0) { | 21 | if (parse_boolean(argv[0], true)) { |
21 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; | 22 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; |
22 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
23 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; | ||
24 | } else { | 23 | } else { |
25 | free_input_config(new_config); | 24 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; |
26 | return cmd_results_new(CMD_INVALID, "dwt", | ||
27 | "Expected 'dwt <enabled|disabled>'"); | ||
28 | } | 25 | } |
29 | 26 | ||
30 | apply_input_config(new_config); | 27 | apply_input_config(new_config); |
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c index 769ce98c..e770043a 100644 --- a/sway/commands/input/left_handed.c +++ b/sway/commands/input/left_handed.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_left_handed(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_left_handed(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | new_config->left_handed = parse_boolean(argv[0], true); |
22 | new_config->left_handed = 1; | ||
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->left_handed = 0; | ||
25 | } else { | ||
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "left_handed", | ||
28 | "Expected 'left_handed <enabled|disabled>'"); | ||
29 | } | ||
30 | 23 | ||
31 | apply_input_config(new_config); | 24 | apply_input_config(new_config); |
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c index 7ca01629..414d4d2b 100644 --- a/sway/commands/input/middle_emulation.c +++ b/sway/commands/input/middle_emulation.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,11 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; | 23 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | 24 | } else { |
24 | new_config->middle_emulation = | 25 | new_config->middle_emulation = |
25 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; | 26 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; |
26 | } else { | ||
27 | free_input_config(new_config); | ||
28 | return cmd_results_new(CMD_INVALID, "middle_emulation", | ||
29 | "Expected 'middle_emulation <enabled|disabled>'"); | ||
30 | } | 27 | } |
31 | 28 | ||
32 | apply_input_config(new_config); | 29 | apply_input_config(new_config); |
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c index 55236790..77c3ff00 100644 --- a/sway/commands/input/natural_scroll.c +++ b/sway/commands/input/natural_scroll.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | new_config->natural_scroll = parse_boolean(argv[0], true); |
22 | new_config->natural_scroll = 1; | ||
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->natural_scroll = 0; | ||
25 | } else { | ||
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "natural_scroll", | ||
28 | "Expected 'natural_scroll <enabled|disabled>'"); | ||
29 | } | ||
30 | 23 | ||
31 | apply_input_config(new_config); | 24 | apply_input_config(new_config); |
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c index a8d1a10c..ac3b8237 100644 --- a/sway/commands/input/tap.c +++ b/sway/commands/input/tap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "log.h" | 6 | #include "log.h" |
7 | #include "util.h" | ||
7 | 8 | ||
8 | struct cmd_results *input_cmd_tap(int argc, char **argv) { | 9 | struct cmd_results *input_cmd_tap(int argc, char **argv) { |
9 | struct cmd_results *error = NULL; | 10 | struct cmd_results *error = NULL; |
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; | 23 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; | ||
25 | } else { | 24 | } else { |
26 | free_input_config(new_config); | 25 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; |
27 | return cmd_results_new(CMD_INVALID, "tap", | ||
28 | "Expected 'tap <enabled|disabled>'"); | ||
29 | } | 26 | } |
30 | 27 | ||
31 | wlr_log(WLR_DEBUG, "apply-tap for device: %s", | 28 | wlr_log(WLR_DEBUG, "apply-tap for device: %s", |
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c index 0959ea6b..3492061e 100644 --- a/sway/commands/output/dpms.c +++ b/sway/commands/output/dpms.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "sway/commands.h" | 1 | #include "sway/commands.h" |
2 | #include "sway/config.h" | 2 | #include "sway/config.h" |
3 | #include "util.h" | ||
3 | 4 | ||
4 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { | 5 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { |
5 | if (!config->handler_context.output_config) { | 6 | if (!config->handler_context.output_config) { |
@@ -9,13 +10,10 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) { | |||
9 | return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument."); | 10 | return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument."); |
10 | } | 11 | } |
11 | 12 | ||
12 | if (strcmp(*argv, "on") == 0) { | 13 | if (parse_boolean(argv[0], true)) { |
13 | config->handler_context.output_config->dpms_state = DPMS_ON; | 14 | config->handler_context.output_config->dpms_state = DPMS_ON; |
14 | } else if (strcmp(*argv, "off") == 0) { | ||
15 | config->handler_context.output_config->dpms_state = DPMS_OFF; | ||
16 | } else { | 15 | } else { |
17 | return cmd_results_new(CMD_INVALID, "output", | 16 | config->handler_context.output_config->dpms_state = DPMS_OFF; |
18 | "Invalid dpms state, valid states are on/off."); | ||
19 | } | 17 | } |
20 | 18 | ||
21 | config->handler_context.leftovers.argc = argc - 1; | 19 | config->handler_context.leftovers.argc = argc - 1; |
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index c7fdc538..434a0e27 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "list.h" | 7 | #include "list.h" |
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | #include "util.h" | ||
10 | 11 | ||
11 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { | 12 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { |
12 | if (con->type == C_VIEW) { | 13 | if (con->type == C_VIEW) { |
@@ -20,14 +21,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { | |||
20 | return error; | 21 | return error; |
21 | } | 22 | } |
22 | 23 | ||
23 | if (strcmp(*argv, "yes") == 0) { | 24 | config->show_marks = parse_boolean(argv[0], config->show_marks); |
24 | config->show_marks = true; | ||
25 | } else if (strcmp(*argv, "no") == 0) { | ||
26 | config->show_marks = false; | ||
27 | } else { | ||
28 | return cmd_results_new(CMD_INVALID, "show_marks", | ||
29 | "Expected 'show_marks <yes|no>'"); | ||
30 | } | ||
31 | 25 | ||
32 | if (config->show_marks) { | 26 | if (config->show_marks) { |
33 | container_for_each_descendant_dfs(&root_container, | 27 | container_for_each_descendant_dfs(&root_container, |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index 2fc88308..4e3a9cce 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include <wlr/util/log.h> | 2 | #include <wlr/util/log.h> |
3 | #include "config.h" | ||
3 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
4 | #include "sway/tree/arrange.h" | 5 | #include "sway/tree/arrange.h" |
5 | #include "sway/tree/layout.h" | 6 | #include "sway/tree/layout.h" |
@@ -14,10 +15,14 @@ static bool test_con_id(struct sway_container *container, void *con_id) { | |||
14 | } | 15 | } |
15 | 16 | ||
16 | static bool test_id(struct sway_container *container, void *id) { | 17 | static bool test_id(struct sway_container *container, void *id) { |
18 | #ifdef HAVE_XWAYLAND | ||
17 | xcb_window_t *wid = id; | 19 | xcb_window_t *wid = id; |
18 | return (container->type == C_VIEW | 20 | return (container->type == C_VIEW |
19 | && container->sway_view->type == SWAY_VIEW_XWAYLAND | 21 | && container->sway_view->type == SWAY_VIEW_XWAYLAND |
20 | && container->sway_view->wlr_xwayland_surface->window_id == *wid); | 22 | && container->sway_view->wlr_xwayland_surface->window_id == *wid); |
23 | #else | ||
24 | return false; | ||
25 | #endif | ||
21 | } | 26 | } |
22 | 27 | ||
23 | static bool test_mark(struct sway_container *container, void *mark) { | 28 | static bool test_mark(struct sway_container *container, void *mark) { |
@@ -43,8 +48,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
43 | 48 | ||
44 | char *value = join_args(argv + 3, argc - 3); | 49 | char *value = join_args(argv + 3, argc - 3); |
45 | if (strcasecmp(argv[2], "id") == 0) { | 50 | if (strcasecmp(argv[2], "id") == 0) { |
51 | #ifdef HAVE_XWAYLAND | ||
46 | xcb_window_t id = strtol(value, NULL, 0); | 52 | xcb_window_t id = strtol(value, NULL, 0); |
47 | other = container_find(&root_container, test_id, (void *)&id); | 53 | other = container_find(&root_container, test_id, (void *)&id); |
54 | #endif | ||
48 | } else if (strcasecmp(argv[2], "con_id") == 0) { | 55 | } else if (strcasecmp(argv[2], "con_id") == 0) { |
49 | size_t con_id = atoi(value); | 56 | size_t con_id = atoi(value); |
50 | other = container_find(&root_container, test_con_id, (void *)con_id); | 57 | other = container_find(&root_container, test_con_id, (void *)con_id); |
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index d199858a..51c497c4 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/layout.h" | 7 | #include "sway/tree/layout.h" |
8 | #include "util.h" | ||
8 | 9 | ||
9 | struct cmd_results *cmd_urgent(int argc, char **argv) { | 10 | struct cmd_results *cmd_urgent(int argc, char **argv) { |
10 | struct cmd_results *error = NULL; | 11 | struct cmd_results *error = NULL; |
@@ -19,17 +20,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { | |||
19 | } | 20 | } |
20 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->sway_view; |
21 | 22 | ||
22 | if (strcmp(argv[0], "enable") == 0) { | 23 | if (strcmp(argv[0], "allow") == 0) { |
23 | view_set_urgent(view, true); | ||
24 | } else if (strcmp(argv[0], "disable") == 0) { | ||
25 | view_set_urgent(view, false); | ||
26 | } else if (strcmp(argv[0], "allow") == 0) { | ||
27 | view->allow_request_urgent = true; | 24 | view->allow_request_urgent = true; |
28 | } else if (strcmp(argv[0], "deny") == 0) { | 25 | } else if (strcmp(argv[0], "deny") == 0) { |
29 | view->allow_request_urgent = false; | 26 | view->allow_request_urgent = false; |
30 | } else { | 27 | } else { |
31 | return cmd_results_new(CMD_INVALID, "urgent", | 28 | view_set_urgent(view, parse_boolean(argv[0], view_is_urgent(view))); |
32 | "Expected 'urgent <enable|disable|allow|deny>'"); | ||
33 | } | 29 | } |
34 | 30 | ||
35 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/config.c b/sway/config.c index ed624bfa..2afffab1 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -56,6 +56,12 @@ static void free_mode(struct sway_mode *mode) { | |||
56 | } | 56 | } |
57 | list_free(mode->keycode_bindings); | 57 | list_free(mode->keycode_bindings); |
58 | } | 58 | } |
59 | if (mode->mouse_bindings) { | ||
60 | for (i = 0; i < mode->mouse_bindings->length; i++) { | ||
61 | free_sway_binding(mode->mouse_bindings->items[i]); | ||
62 | } | ||
63 | list_free(mode->mouse_bindings); | ||
64 | } | ||
59 | free(mode); | 65 | free(mode); |
60 | } | 66 | } |
61 | 67 | ||
@@ -87,7 +93,6 @@ void free_config(struct sway_config *config) { | |||
87 | } | 93 | } |
88 | list_free(config->cmd_queue); | 94 | list_free(config->cmd_queue); |
89 | list_free(config->workspace_outputs); | 95 | list_free(config->workspace_outputs); |
90 | list_free(config->pid_workspaces); | ||
91 | if (config->output_configs) { | 96 | if (config->output_configs) { |
92 | for (int i = 0; i < config->output_configs->length; i++) { | 97 | for (int i = 0; i < config->output_configs->length; i++) { |
93 | free_output_config(config->output_configs->items[i]); | 98 | free_output_config(config->output_configs->items[i]); |
@@ -157,7 +162,6 @@ static void config_defaults(struct sway_config *config) { | |||
157 | if (!(config->modes = create_list())) goto cleanup; | 162 | if (!(config->modes = create_list())) goto cleanup; |
158 | if (!(config->bars = create_list())) goto cleanup; | 163 | if (!(config->bars = create_list())) goto cleanup; |
159 | if (!(config->workspace_outputs = create_list())) goto cleanup; | 164 | if (!(config->workspace_outputs = create_list())) goto cleanup; |
160 | if (!(config->pid_workspaces = create_list())) goto cleanup; | ||
161 | if (!(config->criteria = create_list())) goto cleanup; | 165 | if (!(config->criteria = create_list())) goto cleanup; |
162 | if (!(config->no_focus = create_list())) goto cleanup; | 166 | if (!(config->no_focus = create_list())) goto cleanup; |
163 | if (!(config->input_configs = create_list())) goto cleanup; | 167 | if (!(config->input_configs = create_list())) goto cleanup; |
@@ -172,9 +176,11 @@ static void config_defaults(struct sway_config *config) { | |||
172 | strcpy(config->current_mode->name, "default"); | 176 | strcpy(config->current_mode->name, "default"); |
173 | if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup; | 177 | if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup; |
174 | if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; | 178 | if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; |
179 | if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup; | ||
175 | list_add(config->modes, config->current_mode); | 180 | list_add(config->modes, config->current_mode); |
176 | 181 | ||
177 | config->floating_mod = 0; | 182 | config->floating_mod = 0; |
183 | config->floating_mod_inverse = false; | ||
178 | config->dragging_key = BTN_LEFT; | 184 | config->dragging_key = BTN_LEFT; |
179 | config->resizing_key = BTN_RIGHT; | 185 | config->resizing_key = BTN_RIGHT; |
180 | 186 | ||
diff --git a/sway/criteria.c b/sway/criteria.c index c2e9c07e..39d300ea 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "stringop.h" | 10 | #include "stringop.h" |
11 | #include "list.h" | 11 | #include "list.h" |
12 | #include "log.h" | 12 | #include "log.h" |
13 | #include "config.h" | ||
13 | 14 | ||
14 | bool criteria_is_empty(struct criteria *criteria) { | 15 | bool criteria_is_empty(struct criteria *criteria) { |
15 | return !criteria->title | 16 | return !criteria->title |
@@ -19,7 +20,9 @@ bool criteria_is_empty(struct criteria *criteria) { | |||
19 | && !criteria->instance | 20 | && !criteria->instance |
20 | && !criteria->con_mark | 21 | && !criteria->con_mark |
21 | && !criteria->con_id | 22 | && !criteria->con_id |
23 | #ifdef HAVE_XWAYLAND | ||
22 | && !criteria->id | 24 | && !criteria->id |
25 | #endif | ||
23 | && !criteria->window_role | 26 | && !criteria->window_role |
24 | && !criteria->window_type | 27 | && !criteria->window_type |
25 | && !criteria->floating | 28 | && !criteria->floating |
@@ -127,12 +130,14 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
127 | } | 130 | } |
128 | } | 131 | } |
129 | 132 | ||
133 | #ifdef HAVE_XWAYLAND | ||
130 | if (criteria->id) { // X11 window ID | 134 | if (criteria->id) { // X11 window ID |
131 | uint32_t x11_window_id = view_get_x11_window_id(view); | 135 | uint32_t x11_window_id = view_get_x11_window_id(view); |
132 | if (!x11_window_id || x11_window_id != criteria->id) { | 136 | if (!x11_window_id || x11_window_id != criteria->id) { |
133 | return false; | 137 | return false; |
134 | } | 138 | } |
135 | } | 139 | } |
140 | #endif | ||
136 | 141 | ||
137 | if (criteria->window_role) { | 142 | if (criteria->window_role) { |
138 | // TODO | 143 | // TODO |
@@ -265,7 +270,9 @@ enum criteria_token { | |||
265 | T_CON_ID, | 270 | T_CON_ID, |
266 | T_CON_MARK, | 271 | T_CON_MARK, |
267 | T_FLOATING, | 272 | T_FLOATING, |
273 | #ifdef HAVE_XWAYLAND | ||
268 | T_ID, | 274 | T_ID, |
275 | #endif | ||
269 | T_INSTANCE, | 276 | T_INSTANCE, |
270 | T_SHELL, | 277 | T_SHELL, |
271 | T_TILING, | 278 | T_TILING, |
@@ -287,8 +294,10 @@ static enum criteria_token token_from_name(char *name) { | |||
287 | return T_CON_ID; | 294 | return T_CON_ID; |
288 | } else if (strcmp(name, "con_mark") == 0) { | 295 | } else if (strcmp(name, "con_mark") == 0) { |
289 | return T_CON_MARK; | 296 | return T_CON_MARK; |
297 | #ifdef HAVE_XWAYLAND | ||
290 | } else if (strcmp(name, "id") == 0) { | 298 | } else if (strcmp(name, "id") == 0) { |
291 | return T_ID; | 299 | return T_ID; |
300 | #endif | ||
292 | } else if (strcmp(name, "instance") == 0) { | 301 | } else if (strcmp(name, "instance") == 0) { |
293 | return T_INSTANCE; | 302 | return T_INSTANCE; |
294 | } else if (strcmp(name, "shell") == 0) { | 303 | } else if (strcmp(name, "shell") == 0) { |
@@ -355,7 +364,9 @@ static char *get_focused_prop(enum criteria_token token) { | |||
355 | case T_CON_ID: // These do not support __focused__ | 364 | case T_CON_ID: // These do not support __focused__ |
356 | case T_CON_MARK: | 365 | case T_CON_MARK: |
357 | case T_FLOATING: | 366 | case T_FLOATING: |
367 | #ifdef HAVE_XWAYLAND | ||
358 | case T_ID: | 368 | case T_ID: |
369 | #endif | ||
359 | case T_TILING: | 370 | case T_TILING: |
360 | case T_URGENT: | 371 | case T_URGENT: |
361 | case T_WINDOW_TYPE: | 372 | case T_WINDOW_TYPE: |
@@ -426,12 +437,14 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
426 | case T_WINDOW_TYPE: | 437 | case T_WINDOW_TYPE: |
427 | // TODO: This is a string but will be stored as an enum or integer | 438 | // TODO: This is a string but will be stored as an enum or integer |
428 | break; | 439 | break; |
440 | #ifdef HAVE_XWAYLAND | ||
429 | case T_ID: | 441 | case T_ID: |
430 | criteria->id = strtoul(effective_value, &endptr, 10); | 442 | criteria->id = strtoul(effective_value, &endptr, 10); |
431 | if (*endptr != 0) { | 443 | if (*endptr != 0) { |
432 | error = strdup("The value for 'id' should be numeric"); | 444 | error = strdup("The value for 'id' should be numeric"); |
433 | } | 445 | } |
434 | break; | 446 | break; |
447 | #endif | ||
435 | case T_FLOATING: | 448 | case T_FLOATING: |
436 | criteria->floating = true; | 449 | criteria->floating = true; |
437 | break; | 450 | break; |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index cbd6ef86..1764b4e3 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <wlr/types/wlr_surface.h> | 14 | #include <wlr/types/wlr_surface.h> |
15 | #include <wlr/util/region.h> | 15 | #include <wlr/util/region.h> |
16 | #include "log.h" | 16 | #include "log.h" |
17 | #include "config.h" | ||
17 | #include "sway/config.h" | 18 | #include "sway/config.h" |
18 | #include "sway/input/input-manager.h" | 19 | #include "sway/input/input-manager.h" |
19 | #include "sway/input/seat.h" | 20 | #include "sway/input/seat.h" |
@@ -128,7 +129,7 @@ void output_layer_for_each_surface(struct wl_list *layer_surfaces, | |||
128 | user_data); | 129 | user_data); |
129 | } | 130 | } |
130 | } | 131 | } |
131 | 132 | #ifdef HAVE_XWAYLAND | |
132 | void output_unmanaged_for_each_surface(struct wl_list *unmanaged, | 133 | void output_unmanaged_for_each_surface(struct wl_list *unmanaged, |
133 | struct sway_output *output, struct root_geometry *geo, | 134 | struct sway_output *output, struct root_geometry *geo, |
134 | wlr_surface_iterator_func_t iterator, void *user_data) { | 135 | wlr_surface_iterator_func_t iterator, void *user_data) { |
@@ -143,7 +144,7 @@ void output_unmanaged_for_each_surface(struct wl_list *unmanaged, | |||
143 | iterator, user_data); | 144 | iterator, user_data); |
144 | } | 145 | } |
145 | } | 146 | } |
146 | 147 | #endif | |
147 | void output_drag_icons_for_each_surface(struct wl_list *drag_icons, | 148 | void output_drag_icons_for_each_surface(struct wl_list *drag_icons, |
148 | struct sway_output *output, struct root_geometry *geo, | 149 | struct sway_output *output, struct root_geometry *geo, |
149 | wlr_surface_iterator_func_t iterator, void *user_data) { | 150 | wlr_surface_iterator_func_t iterator, void *user_data) { |
@@ -232,13 +233,13 @@ static void send_frame_done_layer(struct send_frame_done_data *data, | |||
232 | output_layer_for_each_surface(layer_surfaces, &data->root_geo, | 233 | output_layer_for_each_surface(layer_surfaces, &data->root_geo, |
233 | send_frame_done_iterator, data); | 234 | send_frame_done_iterator, data); |
234 | } | 235 | } |
235 | 236 | #ifdef HAVE_XWAYLAND | |
236 | static void send_frame_done_unmanaged(struct send_frame_done_data *data, | 237 | static void send_frame_done_unmanaged(struct send_frame_done_data *data, |
237 | struct wl_list *unmanaged) { | 238 | struct wl_list *unmanaged) { |
238 | output_unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo, | 239 | output_unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo, |
239 | send_frame_done_iterator, data); | 240 | send_frame_done_iterator, data); |
240 | } | 241 | } |
241 | 242 | #endif | |
242 | static void send_frame_done_drag_icons(struct send_frame_done_data *data, | 243 | static void send_frame_done_drag_icons(struct send_frame_done_data *data, |
243 | struct wl_list *drag_icons) { | 244 | struct wl_list *drag_icons) { |
244 | output_drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo, | 245 | output_drag_icons_for_each_surface(drag_icons, data->output, &data->root_geo, |
@@ -280,11 +281,12 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
280 | if (workspace->current.ws_fullscreen) { | 281 | if (workspace->current.ws_fullscreen) { |
281 | send_frame_done_container_iterator( | 282 | send_frame_done_container_iterator( |
282 | workspace->current.ws_fullscreen->swayc, &data); | 283 | workspace->current.ws_fullscreen->swayc, &data); |
283 | 284 | #ifdef HAVE_XWAYLAND | |
284 | if (workspace->current.ws_fullscreen->type == SWAY_VIEW_XWAYLAND) { | 285 | if (workspace->current.ws_fullscreen->type == SWAY_VIEW_XWAYLAND) { |
285 | send_frame_done_unmanaged(&data, | 286 | send_frame_done_unmanaged(&data, |
286 | &root_container.sway_root->xwayland_unmanaged); | 287 | &root_container.sway_root->xwayland_unmanaged); |
287 | } | 288 | } |
289 | #endif | ||
288 | } else { | 290 | } else { |
289 | send_frame_done_layer(&data, | 291 | send_frame_done_layer(&data, |
290 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); | 292 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); |
@@ -294,8 +296,10 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
294 | send_frame_done_container(&data, workspace); | 296 | send_frame_done_container(&data, workspace); |
295 | send_frame_done_container(&data, workspace->sway_workspace->floating); | 297 | send_frame_done_container(&data, workspace->sway_workspace->floating); |
296 | 298 | ||
299 | #ifdef HAVE_XWAYLAND | ||
297 | send_frame_done_unmanaged(&data, | 300 | send_frame_done_unmanaged(&data, |
298 | &root_container.sway_root->xwayland_unmanaged); | 301 | &root_container.sway_root->xwayland_unmanaged); |
302 | #endif | ||
299 | send_frame_done_layer(&data, | 303 | send_frame_done_layer(&data, |
300 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 304 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
301 | } | 305 | } |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d6c3fa8c..15c5b94c 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <wlr/types/wlr_surface.h> | 14 | #include <wlr/types/wlr_surface.h> |
15 | #include <wlr/util/region.h> | 15 | #include <wlr/util/region.h> |
16 | #include "log.h" | 16 | #include "log.h" |
17 | #include "config.h" | ||
17 | #include "sway/config.h" | 18 | #include "sway/config.h" |
18 | #include "sway/debug.h" | 19 | #include "sway/debug.h" |
19 | #include "sway/input/input-manager.h" | 20 | #include "sway/input/input-manager.h" |
@@ -132,7 +133,7 @@ static void render_layer(struct sway_output *output, | |||
132 | output_layer_for_each_surface(layer_surfaces, &data.root_geo, | 133 | output_layer_for_each_surface(layer_surfaces, &data.root_geo, |
133 | render_surface_iterator, &data); | 134 | render_surface_iterator, &data); |
134 | } | 135 | } |
135 | 136 | #ifdef HAVE_XWAYLAND | |
136 | static void render_unmanaged(struct sway_output *output, | 137 | static void render_unmanaged(struct sway_output *output, |
137 | pixman_region32_t *damage, struct wl_list *unmanaged) { | 138 | pixman_region32_t *damage, struct wl_list *unmanaged) { |
138 | struct render_data data = { | 139 | struct render_data data = { |
@@ -143,7 +144,7 @@ static void render_unmanaged(struct sway_output *output, | |||
143 | output_unmanaged_for_each_surface(unmanaged, output, &data.root_geo, | 144 | output_unmanaged_for_each_surface(unmanaged, output, &data.root_geo, |
144 | render_surface_iterator, &data); | 145 | render_surface_iterator, &data); |
145 | } | 146 | } |
146 | 147 | #endif | |
147 | static void render_drag_icons(struct sway_output *output, | 148 | static void render_drag_icons(struct sway_output *output, |
148 | pixman_region32_t *damage, struct wl_list *drag_icons) { | 149 | pixman_region32_t *damage, struct wl_list *drag_icons) { |
149 | struct render_data data = { | 150 | struct render_data data = { |
@@ -857,11 +858,12 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
857 | } else { | 858 | } else { |
858 | render_view_surfaces(fullscreen_view, output, damage, 1.0f); | 859 | render_view_surfaces(fullscreen_view, output, damage, 1.0f); |
859 | } | 860 | } |
860 | 861 | #ifdef HAVE_XWAYLAND | |
861 | if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { | 862 | if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { |
862 | render_unmanaged(output, damage, | 863 | render_unmanaged(output, damage, |
863 | &root_container.sway_root->xwayland_unmanaged); | 864 | &root_container.sway_root->xwayland_unmanaged); |
864 | } | 865 | } |
866 | #endif | ||
865 | } else { | 867 | } else { |
866 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | 868 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; |
867 | 869 | ||
@@ -879,9 +881,10 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
879 | 881 | ||
880 | render_container(output, damage, workspace, workspace->current.focused); | 882 | render_container(output, damage, workspace, workspace->current.focused); |
881 | render_floating(output, damage); | 883 | render_floating(output, damage); |
882 | 884 | #ifdef HAVE_XWAYLAND | |
883 | render_unmanaged(output, damage, | 885 | render_unmanaged(output, damage, |
884 | &root_container.sway_root->xwayland_unmanaged); | 886 | &root_container.sway_root->xwayland_unmanaged); |
887 | #endif | ||
885 | render_layer(output, damage, | 888 | render_layer(output, damage, |
886 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 889 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
887 | } | 890 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 62c3abc8..f3e4fef8 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -418,9 +418,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { | |||
418 | view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); | 418 | view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl); |
419 | xdg_shell_view->view.wlr_xdg_surface = xdg_surface; | 419 | xdg_shell_view->view.wlr_xdg_surface = xdg_surface; |
420 | 420 | ||
421 | // TODO: | ||
422 | // - Look up pid and open on appropriate workspace | ||
423 | |||
424 | xdg_shell_view->map.notify = handle_map; | 421 | xdg_shell_view->map.notify = handle_map; |
425 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); | 422 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); |
426 | 423 | ||
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 7fb85410..46fd4769 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -409,9 +409,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
409 | view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl); | 409 | view_init(&xdg_shell_v6_view->view, SWAY_VIEW_XDG_SHELL_V6, &view_impl); |
410 | xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface; | 410 | xdg_shell_v6_view->view.wlr_xdg_surface_v6 = xdg_surface; |
411 | 411 | ||
412 | // TODO: | ||
413 | // - Look up pid and open on appropriate workspace | ||
414 | |||
415 | xdg_shell_v6_view->map.notify = handle_map; | 412 | xdg_shell_v6_view->map.notify = handle_map; |
416 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); | 413 | wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); |
417 | 414 | ||
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 2546168b..65d4fcd4 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -514,9 +514,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
514 | view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl); | 514 | view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl); |
515 | xwayland_view->view.wlr_xwayland_surface = xsurface; | 515 | xwayland_view->view.wlr_xwayland_surface = xsurface; |
516 | 516 | ||
517 | // TODO: | ||
518 | // - Look up pid and open on appropriate workspace | ||
519 | |||
520 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); | 517 | wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy); |
521 | xwayland_view->destroy.notify = handle_destroy; | 518 | xwayland_view->destroy.notify = handle_destroy; |
522 | 519 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 65d04cac..02bd2239 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <wlr/types/wlr_idle.h> | 11 | #include <wlr/types/wlr_idle.h> |
12 | #include "list.h" | 12 | #include "list.h" |
13 | #include "log.h" | 13 | #include "log.h" |
14 | #include "config.h" | ||
14 | #include "sway/desktop.h" | 15 | #include "sway/desktop.h" |
15 | #include "sway/desktop/transaction.h" | 16 | #include "sway/desktop/transaction.h" |
16 | #include "sway/input/cursor.h" | 17 | #include "sway/input/cursor.h" |
@@ -54,6 +55,7 @@ static struct sway_container *container_at_coords( | |||
54 | struct sway_seat *seat, double lx, double ly, | 55 | struct sway_seat *seat, double lx, double ly, |
55 | struct wlr_surface **surface, double *sx, double *sy) { | 56 | struct wlr_surface **surface, double *sx, double *sy) { |
56 | // check for unmanaged views first | 57 | // check for unmanaged views first |
58 | #ifdef HAVE_XWAYLAND | ||
57 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; | 59 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; |
58 | struct sway_xwayland_unmanaged *unmanaged_surface; | 60 | struct sway_xwayland_unmanaged *unmanaged_surface; |
59 | wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { | 61 | wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { |
@@ -69,7 +71,7 @@ static struct sway_container *container_at_coords( | |||
69 | return NULL; | 71 | return NULL; |
70 | } | 72 | } |
71 | } | 73 | } |
72 | 74 | #endif | |
73 | // find the output the cursor is on | 75 | // find the output the cursor is on |
74 | struct wlr_output_layout *output_layout = | 76 | struct wlr_output_layout *output_layout = |
75 | root_container.sway_root->output_layout; | 77 | root_container.sway_root->output_layout; |
@@ -449,17 +451,25 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
449 | bool over_title = edge == WLR_EDGE_NONE && !surface; | 451 | bool over_title = edge == WLR_EDGE_NONE && !surface; |
450 | 452 | ||
451 | // Check for beginning move | 453 | // Check for beginning move |
452 | if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED && | 454 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
455 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | ||
453 | (mod_pressed || over_title)) { | 456 | (mod_pressed || over_title)) { |
454 | seat_begin_move(seat, cont, BTN_LEFT); | 457 | seat_begin_move(seat, cont, button); |
455 | return; | 458 | return; |
456 | } | 459 | } |
457 | 460 | ||
458 | // Check for beginning resize | 461 | // Check for beginning resize |
459 | bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE; | 462 | bool resizing_via_border = button == BTN_LEFT && edge != WLR_EDGE_NONE; |
460 | bool resizing_via_mod = button == BTN_RIGHT && mod_pressed; | 463 | uint32_t btn_resize = config->floating_mod_inverse ? BTN_LEFT : BTN_RIGHT; |
464 | bool resizing_via_mod = button == btn_resize && mod_pressed; | ||
461 | if ((resizing_via_border || resizing_via_mod) && | 465 | if ((resizing_via_border || resizing_via_mod) && |
462 | state == WLR_BUTTON_PRESSED) { | 466 | state == WLR_BUTTON_PRESSED) { |
467 | if (edge == WLR_EDGE_NONE) { | ||
468 | edge |= cursor->cursor->x > cont->x + cont->width / 2 ? | ||
469 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | ||
470 | edge |= cursor->cursor->y > cont->y + cont->height / 2 ? | ||
471 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | ||
472 | } | ||
463 | seat_begin_resize(seat, cont, button, edge); | 473 | seat_begin_resize(seat, cont, button, edge); |
464 | return; | 474 | return; |
465 | } | 475 | } |
@@ -469,6 +479,83 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
469 | seat_pointer_notify_button(seat, time_msec, button, state); | 479 | seat_pointer_notify_button(seat, time_msec, button, state); |
470 | } | 480 | } |
471 | 481 | ||
482 | /** | ||
483 | * Remove a button (and duplicates) to the sorted list of currently pressed buttons | ||
484 | */ | ||
485 | static void state_erase_button(struct sway_cursor *cursor, uint32_t button) { | ||
486 | size_t j = 0; | ||
487 | for (size_t i = 0; i < cursor->pressed_button_count; ++i) { | ||
488 | if (i > j) { | ||
489 | cursor->pressed_buttons[j] = cursor->pressed_buttons[i]; | ||
490 | } | ||
491 | if (cursor->pressed_buttons[i] != button) { | ||
492 | ++j; | ||
493 | } | ||
494 | } | ||
495 | while (cursor->pressed_button_count > j) { | ||
496 | --cursor->pressed_button_count; | ||
497 | cursor->pressed_buttons[cursor->pressed_button_count] = 0; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * Add a button to the sorted list of currently pressed buttons, if there | ||
503 | * is space. | ||
504 | */ | ||
505 | static void state_add_button(struct sway_cursor *cursor, uint32_t button) { | ||
506 | if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { | ||
507 | return; | ||
508 | } | ||
509 | size_t i = 0; | ||
510 | while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) { | ||
511 | ++i; | ||
512 | } | ||
513 | size_t j = cursor->pressed_button_count; | ||
514 | while (j > i) { | ||
515 | cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1]; | ||
516 | --j; | ||
517 | } | ||
518 | cursor->pressed_buttons[i] = button; | ||
519 | cursor->pressed_button_count++; | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | * Return the mouse binding which matches modifier, click location, release, | ||
524 | * and pressed button state, otherwise return null. | ||
525 | */ | ||
526 | static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor, | ||
527 | list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, | ||
528 | bool on_border, bool on_content) { | ||
529 | uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | | ||
530 | (on_border ? BINDING_BORDER : 0) | | ||
531 | (on_content ? BINDING_CONTENTS : 0); | ||
532 | |||
533 | for (int i = 0; i < bindings->length; ++i) { | ||
534 | struct sway_binding *binding = bindings->items[i]; | ||
535 | if (modifiers ^ binding->modifiers || | ||
536 | cursor->pressed_button_count != (size_t)binding->keys->length || | ||
537 | release != (binding->flags & BINDING_RELEASE) || | ||
538 | !(click_region & binding->flags)) { | ||
539 | continue; | ||
540 | } | ||
541 | |||
542 | bool match = true; | ||
543 | for (size_t j = 0; j < cursor->pressed_button_count; j++) { | ||
544 | uint32_t key = *(uint32_t *)binding->keys->items[j]; | ||
545 | if (key != cursor->pressed_buttons[j]) { | ||
546 | match = false; | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | if (!match) { | ||
551 | continue; | ||
552 | } | ||
553 | |||
554 | return binding; | ||
555 | } | ||
556 | return NULL; | ||
557 | } | ||
558 | |||
472 | void dispatch_cursor_button(struct sway_cursor *cursor, | 559 | void dispatch_cursor_button(struct sway_cursor *cursor, |
473 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { | 560 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { |
474 | if (cursor->seat->operation != OP_NONE && | 561 | if (cursor->seat->operation != OP_NONE && |
@@ -485,6 +572,31 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
485 | double sx, sy; | 572 | double sx, sy; |
486 | struct sway_container *cont = container_at_coords(cursor->seat, | 573 | struct sway_container *cont = container_at_coords(cursor->seat, |
487 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 574 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
575 | |||
576 | // Handle mouse bindings | ||
577 | bool on_border = cont && (find_resize_edge(cont, cursor) != WLR_EDGE_NONE); | ||
578 | bool on_contents = !on_border && surface; | ||
579 | bool on_titlebar = !on_border && !surface; | ||
580 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); | ||
581 | uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; | ||
582 | |||
583 | struct sway_binding *binding = NULL; | ||
584 | if (state == WLR_BUTTON_PRESSED) { | ||
585 | state_add_button(cursor, button); | ||
586 | binding = get_active_mouse_binding(cursor, | ||
587 | config->current_mode->mouse_bindings, modifiers, false, | ||
588 | on_titlebar, on_border, on_contents); | ||
589 | } else { | ||
590 | binding = get_active_mouse_binding(cursor, | ||
591 | config->current_mode->mouse_bindings, modifiers, true, | ||
592 | on_titlebar, on_border, on_contents); | ||
593 | state_erase_button(cursor, button); | ||
594 | } | ||
595 | if (binding) { | ||
596 | seat_execute_command(cursor->seat, binding); | ||
597 | // TODO: do we want to pass on the event? | ||
598 | } | ||
599 | |||
488 | if (surface && wlr_surface_is_layer_surface(surface)) { | 600 | if (surface && wlr_surface_is_layer_surface(surface)) { |
489 | struct wlr_layer_surface *layer = | 601 | struct wlr_layer_surface *layer = |
490 | wlr_layer_surface_from_wlr_surface(surface); | 602 | wlr_layer_surface_from_wlr_surface(surface); |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ede38519..49241db8 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -3,11 +3,11 @@ | |||
3 | #include <wlr/backend/multi.h> | 3 | #include <wlr/backend/multi.h> |
4 | #include <wlr/backend/session.h> | 4 | #include <wlr/backend/session.h> |
5 | #include <wlr/types/wlr_idle.h> | 5 | #include <wlr/types/wlr_idle.h> |
6 | #include "sway/commands.h" | ||
6 | #include "sway/desktop/transaction.h" | 7 | #include "sway/desktop/transaction.h" |
7 | #include "sway/input/seat.h" | ||
8 | #include "sway/input/keyboard.h" | ||
9 | #include "sway/input/input-manager.h" | 8 | #include "sway/input/input-manager.h" |
10 | #include "sway/commands.h" | 9 | #include "sway/input/keyboard.h" |
10 | #include "sway/input/seat.h" | ||
11 | #include "log.h" | 11 | #include "log.h" |
12 | 12 | ||
13 | /** | 13 | /** |
@@ -88,11 +88,13 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
88 | uint32_t modifiers, bool release, bool locked) { | 88 | uint32_t modifiers, bool release, bool locked) { |
89 | for (int i = 0; i < bindings->length; ++i) { | 89 | for (int i = 0; i < bindings->length; ++i) { |
90 | struct sway_binding *binding = bindings->items[i]; | 90 | struct sway_binding *binding = bindings->items[i]; |
91 | bool binding_locked = binding->flags & BINDING_LOCKED; | ||
92 | bool binding_release = binding->flags & BINDING_RELEASE; | ||
91 | 93 | ||
92 | if (modifiers ^ binding->modifiers || | 94 | if (modifiers ^ binding->modifiers || |
93 | state->npressed != (size_t)binding->keys->length || | 95 | state->npressed != (size_t)binding->keys->length || |
94 | locked > binding->locked || | 96 | release != binding_release || |
95 | release != binding->release) { | 97 | locked > binding_locked) { |
96 | continue; | 98 | continue; |
97 | } | 99 | } |
98 | 100 | ||
@@ -119,23 +121,6 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
119 | } | 121 | } |
120 | 122 | ||
121 | /** | 123 | /** |
122 | * Execute the command associated to a binding | ||
123 | */ | ||
124 | static void keyboard_execute_command(struct sway_keyboard *keyboard, | ||
125 | struct sway_binding *binding) { | ||
126 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
127 | binding->command); | ||
128 | config->handler_context.seat = keyboard->seat_device->sway_seat; | ||
129 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
130 | transaction_commit_dirty(); | ||
131 | if (results->status != CMD_SUCCESS) { | ||
132 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
133 | binding->command, results->error); | ||
134 | } | ||
135 | free_cmd_results(results); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Execute a built-in, hardcoded compositor binding. These are triggered from a | 124 | * Execute a built-in, hardcoded compositor binding. These are triggered from a |
140 | * single keysym. | 125 | * single keysym. |
141 | * | 126 | * |
@@ -211,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, | |||
211 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { | 196 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { |
212 | struct sway_keyboard *keyboard = | 197 | struct sway_keyboard *keyboard = |
213 | wl_container_of(listener, keyboard, keyboard_key); | 198 | wl_container_of(listener, keyboard, keyboard_key); |
214 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | 199 | struct sway_seat* seat = keyboard->seat_device->sway_seat; |
200 | struct wlr_seat *wlr_seat = seat->wlr_seat; | ||
215 | struct wlr_input_device *wlr_device = | 201 | struct wlr_input_device *wlr_device = |
216 | keyboard->seat_device->input_device->wlr_device; | 202 | keyboard->seat_device->input_device->wlr_device; |
217 | wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat); | 203 | wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); |
218 | struct wlr_event_keyboard_key *event = data; | 204 | struct wlr_event_keyboard_key *event = data; |
219 | bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; | 205 | bool input_inhibited = seat->exclusive_client != NULL; |
220 | 206 | ||
221 | // Identify new keycode, raw keysym(s), and translated keysym(s) | 207 | // Identify new keycode, raw keysym(s), and translated keysym(s) |
222 | xkb_keycode_t keycode = event->keycode + 8; | 208 | xkb_keycode_t keycode = event->keycode + 8; |
@@ -266,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
266 | // Execute stored release binding once no longer active | 252 | // Execute stored release binding once no longer active |
267 | if (keyboard->held_binding && binding_released != keyboard->held_binding && | 253 | if (keyboard->held_binding && binding_released != keyboard->held_binding && |
268 | event->state == WLR_KEY_RELEASED) { | 254 | event->state == WLR_KEY_RELEASED) { |
269 | keyboard_execute_command(keyboard, keyboard->held_binding); | 255 | seat_execute_command(seat, keyboard->held_binding); |
270 | handled = true; | 256 | handled = true; |
271 | } | 257 | } |
272 | if (binding_released != keyboard->held_binding) { | 258 | if (binding_released != keyboard->held_binding) { |
@@ -290,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
290 | raw_modifiers, false, input_inhibited); | 276 | raw_modifiers, false, input_inhibited); |
291 | 277 | ||
292 | if (binding_pressed) { | 278 | if (binding_pressed) { |
293 | keyboard_execute_command(keyboard, binding_pressed); | 279 | seat_execute_command(seat, binding_pressed); |
294 | handled = true; | 280 | handled = true; |
295 | } | 281 | } |
296 | } | 282 | } |
@@ -312,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
312 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 298 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
313 | event->keycode, event->state); | 299 | event->keycode, event->state); |
314 | } | 300 | } |
301 | |||
302 | transaction_commit_dirty(); | ||
315 | } | 303 | } |
316 | 304 | ||
317 | static void handle_keyboard_modifiers(struct wl_listener *listener, | 305 | static void handle_keyboard_modifiers(struct wl_listener *listener, |
diff --git a/sway/input/seat.c b/sway/input/seat.c index fc9e54b6..8698d69e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <wlr/types/wlr_output_layout.h> | 12 | #include <wlr/types/wlr_output_layout.h> |
13 | #include <wlr/types/wlr_xcursor_manager.h> | 13 | #include <wlr/types/wlr_xcursor_manager.h> |
14 | #include "log.h" | 14 | #include "log.h" |
15 | #include "config.h" | ||
15 | #include "sway/debug.h" | 16 | #include "sway/debug.h" |
16 | #include "sway/desktop.h" | 17 | #include "sway/desktop.h" |
17 | #include "sway/input/cursor.h" | 18 | #include "sway/input/cursor.h" |
@@ -103,11 +104,13 @@ static void seat_send_focus(struct sway_container *con, | |||
103 | 104 | ||
104 | if (con->type == C_VIEW | 105 | if (con->type == C_VIEW |
105 | && seat_is_input_allowed(seat, con->sway_view->surface)) { | 106 | && seat_is_input_allowed(seat, con->sway_view->surface)) { |
107 | #ifdef HAVE_XWAYLAND | ||
106 | if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { | 108 | if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { |
107 | struct wlr_xwayland *xwayland = | 109 | struct wlr_xwayland *xwayland = |
108 | seat->input->server->xwayland.wlr_xwayland; | 110 | seat->input->server->xwayland.wlr_xwayland; |
109 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 111 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
110 | } | 112 | } |
113 | #endif | ||
111 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | 114 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
112 | if (keyboard) { | 115 | if (keyboard) { |
113 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | 116 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, |
@@ -181,6 +184,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener, | |||
181 | bool set_focus = | 184 | bool set_focus = |
182 | focus != NULL && | 185 | focus != NULL && |
183 | (focus == con || container_has_child(con, focus)) && | 186 | (focus == con || container_has_child(con, focus)) && |
187 | con->parent && con->parent->children->length > 1 && | ||
184 | con->type != C_WORKSPACE; | 188 | con->type != C_WORKSPACE; |
185 | 189 | ||
186 | seat_container_destroy(seat_con); | 190 | seat_container_destroy(seat_con); |
diff --git a/sway/meson.build b/sway/meson.build index 30c848e2..649a3ac2 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -18,7 +18,6 @@ sway_sources = files( | |||
18 | 'desktop/transaction.c', | 18 | 'desktop/transaction.c', |
19 | 'desktop/xdg_shell_v6.c', | 19 | 'desktop/xdg_shell_v6.c', |
20 | 'desktop/xdg_shell.c', | 20 | 'desktop/xdg_shell.c', |
21 | 'desktop/xwayland.c', | ||
22 | 21 | ||
23 | 'input/input-manager.c', | 22 | 'input/input-manager.c', |
24 | 'input/seat.c', | 23 | 'input/seat.c', |
@@ -152,6 +151,10 @@ sway_sources = files( | |||
152 | 'tree/output.c', | 151 | 'tree/output.c', |
153 | ) | 152 | ) |
154 | 153 | ||
154 | if get_option('enable-xwayland') | ||
155 | sway_sources += 'desktop/xwayland.c' | ||
156 | endif | ||
157 | |||
155 | sway_deps = [ | 158 | sway_deps = [ |
156 | cairo, | 159 | cairo, |
157 | gdk_pixbuf, | 160 | gdk_pixbuf, |
diff --git a/sway/server.c b/sway/server.c index 89dfbf8c..10ca9614 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -25,7 +25,10 @@ | |||
25 | #include "sway/input/input-manager.h" | 25 | #include "sway/input/input-manager.h" |
26 | #include "sway/server.h" | 26 | #include "sway/server.h" |
27 | #include "sway/tree/layout.h" | 27 | #include "sway/tree/layout.h" |
28 | #include "config.h" | ||
29 | #ifdef HAVE_XWAYLAND | ||
28 | #include "sway/xwayland.h" | 30 | #include "sway/xwayland.h" |
31 | #endif | ||
29 | 32 | ||
30 | bool server_privileged_prepare(struct sway_server *server) { | 33 | bool server_privileged_prepare(struct sway_server *server) { |
31 | wlr_log(WLR_DEBUG, "Preparing Wayland server initialization"); | 34 | wlr_log(WLR_DEBUG, "Preparing Wayland server initialization"); |
@@ -81,6 +84,7 @@ bool server_init(struct sway_server *server) { | |||
81 | server->xdg_shell_surface.notify = handle_xdg_shell_surface; | 84 | server->xdg_shell_surface.notify = handle_xdg_shell_surface; |
82 | 85 | ||
83 | // TODO make xwayland optional | 86 | // TODO make xwayland optional |
87 | #ifdef HAVE_XWAYLAND | ||
84 | server->xwayland.wlr_xwayland = | 88 | server->xwayland.wlr_xwayland = |
85 | wlr_xwayland_create(server->wl_display, server->compositor, true); | 89 | wlr_xwayland_create(server->wl_display, server->compositor, true); |
86 | wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface, | 90 | wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface, |
@@ -101,6 +105,7 @@ bool server_init(struct sway_server *server) { | |||
101 | image->width * 4, image->width, image->height, image->hotspot_x, | 105 | image->width * 4, image->width, image->height, image->hotspot_x, |
102 | image->hotspot_y); | 106 | image->hotspot_y); |
103 | } | 107 | } |
108 | #endif | ||
104 | 109 | ||
105 | // TODO: Integration with sway borders | 110 | // TODO: Integration with sway borders |
106 | struct wlr_server_decoration_manager *deco_manager = | 111 | struct wlr_server_decoration_manager *deco_manager = |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 4f743c40..b56b4e87 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -527,10 +527,12 @@ static struct sway_container *container_at_view(struct sway_container *swayc, | |||
527 | double _sx, _sy; | 527 | double _sx, _sy; |
528 | struct wlr_surface *_surface = NULL; | 528 | struct wlr_surface *_surface = NULL; |
529 | switch (sview->type) { | 529 | switch (sview->type) { |
530 | #ifdef HAVE_XWAYLAND | ||
530 | case SWAY_VIEW_XWAYLAND: | 531 | case SWAY_VIEW_XWAYLAND: |
531 | _surface = wlr_surface_surface_at(sview->surface, | 532 | _surface = wlr_surface_surface_at(sview->surface, |
532 | view_sx, view_sy, &_sx, &_sy); | 533 | view_sx, view_sy, &_sx, &_sy); |
533 | break; | 534 | break; |
535 | #endif | ||
534 | case SWAY_VIEW_XDG_SHELL_V6: | 536 | case SWAY_VIEW_XDG_SHELL_V6: |
535 | _surface = wlr_xdg_surface_v6_surface_at( | 537 | _surface = wlr_xdg_surface_v6_surface_at( |
536 | sview->wlr_xdg_surface_v6, | 538 | sview->wlr_xdg_surface_v6, |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index a2be0ef3..2b3263f8 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
8 | #include <wlr/types/wlr_output_layout.h> | 8 | #include <wlr/types/wlr_output_layout.h> |
9 | #include "config.h" | ||
9 | #include "sway/debug.h" | 10 | #include "sway/debug.h" |
10 | #include "sway/tree/arrange.h" | 11 | #include "sway/tree/arrange.h" |
11 | #include "sway/tree/container.h" | 12 | #include "sway/tree/container.h" |
@@ -39,7 +40,9 @@ void layout_init(void) { | |||
39 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); | 40 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); |
40 | root_container.sway_root->output_layout = wlr_output_layout_create(); | 41 | root_container.sway_root->output_layout = wlr_output_layout_create(); |
41 | wl_list_init(&root_container.sway_root->outputs); | 42 | wl_list_init(&root_container.sway_root->outputs); |
43 | #ifdef HAVE_XWAYLAND | ||
42 | wl_list_init(&root_container.sway_root->xwayland_unmanaged); | 44 | wl_list_init(&root_container.sway_root->xwayland_unmanaged); |
45 | #endif | ||
43 | wl_list_init(&root_container.sway_root->drag_icons); | 46 | wl_list_init(&root_container.sway_root->drag_icons); |
44 | wl_signal_init(&root_container.sway_root->events.new_container); | 47 | wl_signal_init(&root_container.sway_root->events.new_container); |
45 | root_container.sway_root->scratchpad = create_list(); | 48 | root_container.sway_root->scratchpad = create_list(); |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 9d88d7aa..beeb8144 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -3,6 +3,10 @@ | |||
3 | #include <wayland-server.h> | 3 | #include <wayland-server.h> |
4 | #include <wlr/render/wlr_renderer.h> | 4 | #include <wlr/render/wlr_renderer.h> |
5 | #include <wlr/types/wlr_output_layout.h> | 5 | #include <wlr/types/wlr_output_layout.h> |
6 | #include "config.h" | ||
7 | #ifdef HAVE_XWAYLAND | ||
8 | #include <wlr/xwayland.h> | ||
9 | #endif | ||
6 | #include "list.h" | 10 | #include "list.h" |
7 | #include "log.h" | 11 | #include "log.h" |
8 | #include "sway/criteria.h" | 12 | #include "sway/criteria.h" |
@@ -107,14 +111,14 @@ const char *view_get_instance(struct sway_view *view) { | |||
107 | } | 111 | } |
108 | return NULL; | 112 | return NULL; |
109 | } | 113 | } |
110 | 114 | #ifdef HAVE_XWAYLAND | |
111 | uint32_t view_get_x11_window_id(struct sway_view *view) { | 115 | uint32_t view_get_x11_window_id(struct sway_view *view) { |
112 | if (view->impl->get_int_prop) { | 116 | if (view->impl->get_int_prop) { |
113 | return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); | 117 | return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); |
114 | } | 118 | } |
115 | return 0; | 119 | return 0; |
116 | } | 120 | } |
117 | 121 | #endif | |
118 | const char *view_get_window_role(struct sway_view *view) { | 122 | const char *view_get_window_role(struct sway_view *view) { |
119 | if (view->impl->get_string_prop) { | 123 | if (view->impl->get_string_prop) { |
120 | return view->impl->get_string_prop(view, VIEW_PROP_WINDOW_ROLE); | 124 | return view->impl->get_string_prop(view, VIEW_PROP_WINDOW_ROLE); |
@@ -135,8 +139,10 @@ const char *view_get_shell(struct sway_view *view) { | |||
135 | return "xdg_shell_v6"; | 139 | return "xdg_shell_v6"; |
136 | case SWAY_VIEW_XDG_SHELL: | 140 | case SWAY_VIEW_XDG_SHELL: |
137 | return "xdg_shell"; | 141 | return "xdg_shell"; |
142 | #ifdef HAVE_XWAYLAND | ||
138 | case SWAY_VIEW_XWAYLAND: | 143 | case SWAY_VIEW_XWAYLAND: |
139 | return "xwayland"; | 144 | return "xwayland"; |
145 | #endif | ||
140 | } | 146 | } |
141 | return "unknown"; | 147 | return "unknown"; |
142 | } | 148 | } |
@@ -561,9 +567,27 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
561 | return; | 567 | return; |
562 | } | 568 | } |
563 | 569 | ||
570 | pid_t pid; | ||
571 | #ifdef HAVE_XWAYLAND | ||
572 | if (view->type == SWAY_VIEW_XWAYLAND) { | ||
573 | struct wlr_xwayland_surface *surf = | ||
574 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); | ||
575 | pid = surf->pid; | ||
576 | } else { | ||
577 | struct wl_client *client = | ||
578 | wl_resource_get_client(wlr_surface->resource); | ||
579 | wl_client_get_credentials(client, &pid, NULL, NULL); | ||
580 | } | ||
581 | #else | ||
582 | struct wl_client *client = | ||
583 | wl_resource_get_client(wlr_surface->resource); | ||
584 | wl_client_get_credentials(client, &pid, NULL, NULL); | ||
585 | #endif | ||
586 | |||
564 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 587 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
565 | struct sway_container *focus = | 588 | struct sway_container *target_sibling = |
566 | seat_get_focus_inactive(seat, &root_container); | 589 | seat_get_focus_inactive(seat, &root_container); |
590 | struct sway_container *prev_focus = target_sibling; | ||
567 | struct sway_container *cont = NULL; | 591 | struct sway_container *cont = NULL; |
568 | 592 | ||
569 | // Check if there's any `assign` criteria for the view | 593 | // Check if there's any `assign` criteria for the view |
@@ -577,22 +601,35 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
577 | if (!workspace) { | 601 | if (!workspace) { |
578 | workspace = workspace_create(NULL, criteria->target); | 602 | workspace = workspace_create(NULL, criteria->target); |
579 | } | 603 | } |
580 | focus = seat_get_focus_inactive(seat, workspace); | 604 | prev_focus = target_sibling; |
605 | target_sibling = seat_get_focus_inactive(seat, workspace); | ||
581 | } else { | 606 | } else { |
582 | // CT_ASSIGN_OUTPUT | 607 | // CT_ASSIGN_OUTPUT |
583 | struct sway_container *output = output_by_name(criteria->target); | 608 | struct sway_container *output = output_by_name(criteria->target); |
584 | if (output) { | 609 | if (output) { |
585 | focus = seat_get_focus_inactive(seat, output); | 610 | prev_focus = seat_get_focus_inactive(seat, output); |
586 | } | 611 | } |
587 | } | 612 | } |
588 | } | 613 | } |
614 | list_free(criterias); | ||
615 | |||
616 | if (!workspace) { | ||
617 | workspace = workspace_for_pid(pid); | ||
618 | if (workspace) { | ||
619 | prev_focus = target_sibling; | ||
620 | target_sibling = seat_get_focus_inactive(seat, workspace); | ||
621 | } | ||
622 | } | ||
589 | // If we're about to launch the view into the floating container, then | 623 | // If we're about to launch the view into the floating container, then |
590 | // launch it as a tiled view in the root of the workspace instead. | 624 | // launch it as a tiled view in the root of the workspace instead. |
591 | if (container_is_floating(focus)) { | 625 | if (container_is_floating(target_sibling)) { |
592 | focus = focus->parent->parent; | 626 | if (prev_focus == target_sibling) { |
627 | prev_focus = target_sibling->parent->parent; | ||
628 | } | ||
629 | target_sibling = target_sibling->parent->parent; | ||
593 | } | 630 | } |
594 | list_free(criterias); | 631 | |
595 | cont = container_view_create(focus, view); | 632 | cont = container_view_create(target_sibling, view); |
596 | 633 | ||
597 | view->surface = wlr_surface; | 634 | view->surface = wlr_surface; |
598 | view->swayc = cont; | 635 | view->swayc = cont; |
@@ -615,7 +652,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
615 | view_set_tiled(view, true); | 652 | view_set_tiled(view, true); |
616 | } | 653 | } |
617 | 654 | ||
618 | if (should_focus(view)) { | 655 | if (should_focus(view) && prev_focus == target_sibling) { |
619 | input_manager_set_focus(input_manager, cont); | 656 | input_manager_set_focus(input_manager, cont); |
620 | if (workspace) { | 657 | if (workspace) { |
621 | workspace_switch(workspace); | 658 | workspace_switch(workspace); |
@@ -799,11 +836,13 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { | |||
799 | wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); | 836 | wlr_xdg_surface_v6_from_wlr_surface(wlr_surface); |
800 | return view_from_wlr_xdg_surface_v6(xdg_surface_v6); | 837 | return view_from_wlr_xdg_surface_v6(xdg_surface_v6); |
801 | } | 838 | } |
839 | #ifdef HAVE_XWAYLAND | ||
802 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { | 840 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { |
803 | struct wlr_xwayland_surface *xsurface = | 841 | struct wlr_xwayland_surface *xsurface = |
804 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); | 842 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); |
805 | return view_from_wlr_xwayland_surface(xsurface); | 843 | return view_from_wlr_xwayland_surface(xsurface); |
806 | } | 844 | } |
845 | #endif | ||
807 | if (wlr_surface_is_subsurface(wlr_surface)) { | 846 | if (wlr_surface_is_subsurface(wlr_surface)) { |
808 | struct wlr_subsurface *subsurface = | 847 | struct wlr_subsurface *subsurface = |
809 | wlr_subsurface_from_wlr_surface(wlr_surface); | 848 | wlr_subsurface_from_wlr_surface(wlr_surface); |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 622f01ec..62974cd7 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "sway/input/input-manager.h" | 9 | #include "sway/input/input-manager.h" |
10 | #include "sway/input/seat.h" | 10 | #include "sway/input/seat.h" |
11 | #include "sway/ipc-server.h" | 11 | #include "sway/ipc-server.h" |
12 | #include "sway/output.h" | ||
12 | #include "sway/tree/arrange.h" | 13 | #include "sway/tree/arrange.h" |
13 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
14 | #include "sway/tree/view.h" | 15 | #include "sway/tree/view.h" |
@@ -107,96 +108,103 @@ static bool workspace_valid_on_output(const char *output_name, | |||
107 | return true; | 108 | return true; |
108 | } | 109 | } |
109 | 110 | ||
110 | char *workspace_next_name(const char *output_name) { | 111 | static void workspace_name_from_binding(const struct sway_binding * binding, |
111 | wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", | 112 | const char* output_name, int *min_order, char **earliest_name) { |
112 | output_name); | 113 | char *cmdlist = strdup(binding->command); |
113 | // Scan all workspace bindings to find the next available workspace name, | 114 | char *dup = cmdlist; |
114 | // if none are found/available then default to a number | 115 | char *name = NULL; |
115 | struct sway_mode *mode = config->current_mode; | ||
116 | 116 | ||
117 | // TODO: iterate over keycode bindings too | 117 | // workspace n |
118 | int order = INT_MAX; | 118 | char *cmd = argsep(&cmdlist, " "); |
119 | char *target = NULL; | 119 | if (cmdlist) { |
120 | for (int i = 0; i < mode->keysym_bindings->length; ++i) { | 120 | name = argsep(&cmdlist, ",;"); |
121 | struct sway_binding *binding = mode->keysym_bindings->items[i]; | 121 | } |
122 | char *cmdlist = strdup(binding->command); | ||
123 | char *dup = cmdlist; | ||
124 | char *name = NULL; | ||
125 | |||
126 | // workspace n | ||
127 | char *cmd = argsep(&cmdlist, " "); | ||
128 | if (cmdlist) { | ||
129 | name = argsep(&cmdlist, ",;"); | ||
130 | } | ||
131 | 122 | ||
132 | if (strcmp("workspace", cmd) == 0 && name) { | 123 | if (strcmp("workspace", cmd) == 0 && name) { |
133 | char *_target = strdup(name); | 124 | char *_target = strdup(name); |
134 | _target = do_var_replacement(_target); | 125 | _target = do_var_replacement(_target); |
135 | strip_quotes(_target); | 126 | strip_quotes(_target); |
136 | while (isspace(*_target)) { | 127 | while (isspace(*_target)) { |
137 | memmove(_target, _target+1, strlen(_target+1)); | 128 | memmove(_target, _target+1, strlen(_target+1)); |
138 | } | 129 | } |
139 | wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", | 130 | wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", |
140 | _target); | 131 | _target); |
141 | 132 | ||
142 | // Make sure that the command references an actual workspace | 133 | // Make sure that the command references an actual workspace |
143 | // not a command about workspaces | 134 | // not a command about workspaces |
144 | if (strcmp(_target, "next") == 0 || | 135 | if (strcmp(_target, "next") == 0 || |
145 | strcmp(_target, "prev") == 0 || | 136 | strcmp(_target, "prev") == 0 || |
146 | strcmp(_target, "next_on_output") == 0 || | 137 | strcmp(_target, "next_on_output") == 0 || |
147 | strcmp(_target, "prev_on_output") == 0 || | 138 | strcmp(_target, "prev_on_output") == 0 || |
148 | strcmp(_target, "number") == 0 || | 139 | strcmp(_target, "number") == 0 || |
149 | strcmp(_target, "back_and_forth") == 0 || | 140 | strcmp(_target, "back_and_forth") == 0 || |
150 | strcmp(_target, "current") == 0) | 141 | strcmp(_target, "current") == 0) { |
151 | { | 142 | free(_target); |
152 | free(_target); | 143 | free(dup); |
153 | free(dup); | 144 | return; |
154 | continue; | 145 | } |
155 | } | ||
156 | |||
157 | // If the command is workspace number <name>, isolate the name | ||
158 | if (strncmp(_target, "number ", strlen("number ")) == 0) { | ||
159 | size_t length = strlen(_target) - strlen("number ") + 1; | ||
160 | char *temp = malloc(length); | ||
161 | strncpy(temp, _target + strlen("number "), length - 1); | ||
162 | temp[length - 1] = '\0'; | ||
163 | free(_target); | ||
164 | _target = temp; | ||
165 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); | ||
166 | |||
167 | // Make sure the workspace number doesn't already exist | ||
168 | if (workspace_by_number(_target)) { | ||
169 | free(_target); | ||
170 | free(dup); | ||
171 | continue; | ||
172 | } | ||
173 | } | ||
174 | 146 | ||
175 | // Make sure that the workspace doesn't already exist | 147 | // If the command is workspace number <name>, isolate the name |
176 | if (workspace_by_name(_target)) { | 148 | if (strncmp(_target, "number ", strlen("number ")) == 0) { |
149 | size_t length = strlen(_target) - strlen("number ") + 1; | ||
150 | char *temp = malloc(length); | ||
151 | strncpy(temp, _target + strlen("number "), length - 1); | ||
152 | temp[length - 1] = '\0'; | ||
153 | free(_target); | ||
154 | _target = temp; | ||
155 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); | ||
156 | |||
157 | // Make sure the workspace number doesn't already exist | ||
158 | if (workspace_by_number(_target)) { | ||
177 | free(_target); | 159 | free(_target); |
178 | free(dup); | 160 | free(dup); |
179 | continue; | 161 | return; |
180 | } | 162 | } |
163 | } | ||
181 | 164 | ||
182 | // make sure that the workspace can appear on the given | 165 | // Make sure that the workspace doesn't already exist |
183 | // output | 166 | if (workspace_by_name(_target)) { |
184 | if (!workspace_valid_on_output(output_name, _target)) { | 167 | free(_target); |
185 | free(_target); | 168 | free(dup); |
186 | free(dup); | 169 | return; |
187 | continue; | 170 | } |
188 | } | ||
189 | 171 | ||
190 | if (binding->order < order) { | 172 | // make sure that the workspace can appear on the given |
191 | order = binding->order; | 173 | // output |
192 | free(target); | 174 | if (!workspace_valid_on_output(output_name, _target)) { |
193 | target = _target; | 175 | free(_target); |
194 | wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); | 176 | free(dup); |
195 | } else { | 177 | return; |
196 | free(_target); | 178 | } |
197 | } | 179 | |
180 | if (binding->order < *min_order) { | ||
181 | *min_order = binding->order; | ||
182 | free(*earliest_name); | ||
183 | *earliest_name = _target; | ||
184 | wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); | ||
185 | } else { | ||
186 | free(_target); | ||
198 | } | 187 | } |
199 | free(dup); | 188 | } |
189 | free(dup); | ||
190 | } | ||
191 | |||
192 | char *workspace_next_name(const char *output_name) { | ||
193 | wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", | ||
194 | output_name); | ||
195 | // Scan all workspace bindings to find the next available workspace name, | ||
196 | // if none are found/available then default to a number | ||
197 | struct sway_mode *mode = config->current_mode; | ||
198 | |||
199 | int order = INT_MAX; | ||
200 | char *target = NULL; | ||
201 | for (int i = 0; i < mode->keysym_bindings->length; ++i) { | ||
202 | workspace_name_from_binding(mode->keysym_bindings->items[i], | ||
203 | output_name, &order, &target); | ||
204 | } | ||
205 | for (int i = 0; i < mode->keycode_bindings->length; ++i) { | ||
206 | workspace_name_from_binding(mode->keycode_bindings->items[i], | ||
207 | output_name, &order, &target); | ||
200 | } | 208 | } |
201 | if (target != NULL) { | 209 | if (target != NULL) { |
202 | return target; | 210 | return target; |
@@ -529,3 +537,116 @@ void workspace_detect_urgent(struct sway_container *workspace) { | |||
529 | container_damage_whole(workspace); | 537 | container_damage_whole(workspace); |
530 | } | 538 | } |
531 | } | 539 | } |
540 | |||
541 | struct pid_workspace { | ||
542 | pid_t pid; | ||
543 | char *workspace; | ||
544 | struct timespec time_added; | ||
545 | |||
546 | struct sway_container *output; | ||
547 | struct wl_listener output_destroy; | ||
548 | |||
549 | struct wl_list link; | ||
550 | }; | ||
551 | |||
552 | static struct wl_list pid_workspaces; | ||
553 | |||
554 | struct sway_container *workspace_for_pid(pid_t pid) { | ||
555 | if (!pid_workspaces.prev && !pid_workspaces.next) { | ||
556 | wl_list_init(&pid_workspaces); | ||
557 | return NULL; | ||
558 | } | ||
559 | |||
560 | struct sway_container *ws = NULL; | ||
561 | struct pid_workspace *pw = NULL; | ||
562 | |||
563 | wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); | ||
564 | |||
565 | do { | ||
566 | struct pid_workspace *_pw = NULL; | ||
567 | wl_list_for_each(_pw, &pid_workspaces, link) { | ||
568 | if (pid == _pw->pid) { | ||
569 | pw = _pw; | ||
570 | wlr_log(WLR_DEBUG, | ||
571 | "found pid_workspace for pid %d, workspace %s", | ||
572 | pid, pw->workspace); | ||
573 | goto found; | ||
574 | } | ||
575 | } | ||
576 | pid = get_parent_pid(pid); | ||
577 | } while (pid > 1); | ||
578 | found: | ||
579 | |||
580 | if (pw && pw->workspace) { | ||
581 | ws = workspace_by_name(pw->workspace); | ||
582 | |||
583 | if (!ws) { | ||
584 | wlr_log(WLR_DEBUG, | ||
585 | "Creating workspace %s for pid %d because it disappeared", | ||
586 | pw->workspace, pid); | ||
587 | ws = workspace_create(pw->output, pw->workspace); | ||
588 | } | ||
589 | |||
590 | wl_list_remove(&pw->output_destroy.link); | ||
591 | wl_list_remove(&pw->link); | ||
592 | free(pw->workspace); | ||
593 | free(pw); | ||
594 | } | ||
595 | |||
596 | return ws; | ||
597 | } | ||
598 | |||
599 | static void pw_handle_output_destroy(struct wl_listener *listener, void *data) { | ||
600 | struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy); | ||
601 | pw->output = NULL; | ||
602 | wl_list_remove(&pw->output_destroy.link); | ||
603 | wl_list_init(&pw->output_destroy.link); | ||
604 | } | ||
605 | |||
606 | void workspace_record_pid(pid_t pid) { | ||
607 | wlr_log(WLR_DEBUG, "Recording workspace for process %d", pid); | ||
608 | if (!pid_workspaces.prev && !pid_workspaces.next) { | ||
609 | wl_list_init(&pid_workspaces); | ||
610 | } | ||
611 | |||
612 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
613 | struct sway_container *ws = | ||
614 | seat_get_focus_inactive(seat, &root_container); | ||
615 | if (ws && ws->type != C_WORKSPACE) { | ||
616 | ws = container_parent(ws, C_WORKSPACE); | ||
617 | } | ||
618 | if (!ws) { | ||
619 | wlr_log(WLR_DEBUG, "Bailing out, no workspace"); | ||
620 | return; | ||
621 | } | ||
622 | struct sway_container *output = ws->parent; | ||
623 | if (!output) { | ||
624 | wlr_log(WLR_DEBUG, "Bailing out, no output"); | ||
625 | return; | ||
626 | } | ||
627 | |||
628 | struct timespec now; | ||
629 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
630 | |||
631 | // Remove expired entries | ||
632 | static const int timeout = 60; | ||
633 | struct pid_workspace *old, *_old; | ||
634 | wl_list_for_each_safe(old, _old, &pid_workspaces, link) { | ||
635 | if (now.tv_sec - old->time_added.tv_sec >= timeout) { | ||
636 | wl_list_remove(&old->output_destroy.link); | ||
637 | wl_list_remove(&old->link); | ||
638 | free(old->workspace); | ||
639 | free(old); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace)); | ||
644 | pw->workspace = strdup(ws->name); | ||
645 | pw->output = output; | ||
646 | pw->pid = pid; | ||
647 | memcpy(&pw->time_added, &now, sizeof(struct timespec)); | ||
648 | pw->output_destroy.notify = pw_handle_output_destroy; | ||
649 | wl_signal_add(&output->sway_output->wlr_output->events.destroy, | ||
650 | &pw->output_destroy); | ||
651 | wl_list_insert(&pid_workspaces, &pw->link); | ||
652 | } | ||