From 88cc7e31781a0d42bdd4f9eee646c02ff03857c4 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 30 Nov 2017 03:39:27 -0500 Subject: use meson subdirectories --- sway/meson.build | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 sway/meson.build (limited to 'sway/meson.build') diff --git a/sway/meson.build b/sway/meson.build new file mode 100644 index 00000000..1f17ed31 --- /dev/null +++ b/sway/meson.build @@ -0,0 +1,29 @@ +sway_sources = sway_common + files( + 'main.c', + 'server.c', + 'commands.c', + 'commands/exit.c', + 'ipc-json.c', + 'ipc-server.c', + 'desktop/output.c', + 'desktop/xdg_shell_v6.c', + 'tree/container.c', + 'tree/layout.c', + 'tree/workspace.c', +) + +sway_deps = [ + pixman, + wayland_server, + jsonc, + wlroots, + libcap, + math, +] + +executable( + 'sway', + sway_sources, + include_directories: [sway_inc], + dependencies: sway_deps +) -- cgit v1.2.3 From cc310cffb0bf4cd2333be26a2ae16848655a306b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 30 Nov 2017 06:25:13 -0500 Subject: meson: common static library --- common/meson.build | 17 ++++++++++------- sway/meson.build | 5 +++-- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'sway/meson.build') diff --git a/common/meson.build b/common/meson.build index ca1f1752..3a4282ad 100644 --- a/common/meson.build +++ b/common/meson.build @@ -1,8 +1,11 @@ -sway_common = files( - 'log.c', - 'list.c', - 'util.c', - 'stringop.c', - 'readline.c', - 'ipc-client.c' +lib_sway_common = static_library('sway-common', + files( + 'log.c', + 'list.c', + 'util.c', + 'stringop.c', + 'readline.c', + 'ipc-client.c' + ), + include_directories: sway_inc ) diff --git a/sway/meson.build b/sway/meson.build index 1f17ed31..b02506c8 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -1,4 +1,4 @@ -sway_sources = sway_common + files( +sway_sources = files( 'main.c', 'server.c', 'commands.c', @@ -25,5 +25,6 @@ executable( 'sway', sway_sources, include_directories: [sway_inc], - dependencies: sway_deps + dependencies: sway_deps, + link_with: [lib_sway_common] ) -- cgit v1.2.3 From 2f3633433e2f1d840f3a98ca777d79d658a66e3f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 30 Nov 2017 08:31:13 -0500 Subject: add meson install files --- config.in | 4 ++-- meson.build | 54 ++++++++++++++++++++++++++++++++++++++++++++++- meson_options.txt | 3 ++- security.d/00-defaults.in | 18 ++++++++-------- sway/meson.build | 3 ++- 5 files changed, 68 insertions(+), 14 deletions(-) (limited to 'sway/meson.build') diff --git a/config.in b/config.in index b39a39aa..086b66dc 100644 --- a/config.in +++ b/config.in @@ -21,7 +21,7 @@ set $menu dmenu_run ### Output configuration # # Default wallpaper (more resolutions are available in __DATADIR__/backgrounds/sway/) -output * bg __DATADIR__/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill +output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # # Example configuration: # @@ -194,4 +194,4 @@ bar { } } -include __SYSCONFDIR__/sway/config.d/* +include @sysconfdir@/sway/config.d/* diff --git a/meson.build b/meson.build index ac161987..494f2866 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,11 @@ project( cc = meson.get_compiler('c') +is_freebsd = host_machine.system().startswith('freebsd') +datadir = get_option('datadir') +sysconfdir = get_option('sysconfdir') +prefix = get_option('prefix') + jsonc = dependency('json-c', version: '>=0.12.1') pcre = dependency('libpcre') wlroots = dependency('wlroots') @@ -37,7 +42,6 @@ else git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch) endif - add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') sway_inc = include_directories('include') @@ -45,3 +49,51 @@ sway_inc = include_directories('include') subdir('common') subdir('sway') +config = configuration_data() +config.set('sysconfdir', join_paths(prefix, sysconfdir)) +config.set('datadir', join_paths(prefix, datadir)) +config.set('prefix', prefix) + +configure_file( + configuration: config, + input: 'config.in', + output: '@BASENAME@', + install_dir: sysconfdir + '/sway' +) + +if is_freebsd + configure_file( + configuration: config, + input: 'security.d/10-freebsd.in', + output: '@BASENAME@', + install_dir: sysconfdir + '/sway/security.d' + ) +else + configure_file( + configuration: config, + input: 'security.d/00-defaults.in', + output: '@BASENAME@', + install_dir: sysconfdir + '/sway/security.d' + ) +endif + +install_data( + 'sway.desktop', + install_dir: datadir + '/wayland-sessions' +) + +if (get_option('default_wallpaper')) + wallpaper_files = files( + 'assets/Sway_Wallpaper_Blue_768x1024.png', + 'assets/Sway_Wallpaper_Blue_768x1024_Portrait.png', + 'assets/Sway_Wallpaper_Blue_1136x640.png', + 'assets/Sway_Wallpaper_Blue_1136x640_Portrait.png', + 'assets/Sway_Wallpaper_Blue_1366x768.png', + 'assets/Sway_Wallpaper_Blue_1920x1080.png', + 'assets/Sway_Wallpaper_Blue_2048x1536.png', + 'assets/Sway_Wallpaper_Blue_2048x1536_Portrait.png', + ) + wallpaper_install_dir = datadir + '/backgrounds/sway' + + install_data(wallpaper_files, install_dir: wallpaper_install_dir) +endif diff --git a/meson_options.txt b/meson_options.txt index 5015a986..03bc1986 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ -option('sway_version', type : 'string', description : 'The version string reported in `sway --version`.') +option('sway_version', type : 'string', description: 'The version string reported in `sway --version`.') +option('default_wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') diff --git a/security.d/00-defaults.in b/security.d/00-defaults.in index 05098dea..e4626477 100644 --- a/security.d/00-defaults.in +++ b/security.d/00-defaults.in @@ -6,17 +6,17 @@ # installation. # # DO NOT CHANGE THIS FILE. Override these defaults by writing new files in -# __SYSCONFDIR__/sway/security.d/* +# @sysconfdir@/sway/security.d/* # Configures enabled compositor features for specific programs permit * fullscreen keyboard mouse -permit __PREFIX__/bin/swaylock lock -permit __PREFIX__/bin/swaybg background -permit __PREFIX__/bin/swaygrab screenshot -permit __PREFIX__/bin/swaybar panel +permit @prefix@/bin/swaylock lock +permit @prefix@/bin/swaybg background +permit @prefix@/bin/swaygrab screenshot +permit @prefix@/bin/swaybar panel # Configures enabled IPC features for specific programs -ipc __PREFIX__/bin/swaymsg { +ipc @prefix@/bin/swaymsg { * enabled events { @@ -24,7 +24,7 @@ ipc __PREFIX__/bin/swaymsg { } } -ipc __PREFIX__/bin/swaybar { +ipc @prefix@/bin/swaybar { bar-config enabled outputs enabled workspaces enabled @@ -36,12 +36,12 @@ ipc __PREFIX__/bin/swaybar { } } -ipc __PREFIX__/bin/swaygrab { +ipc @prefix@/bin/swaygrab { outputs enabled tree enabled } -ipc __PREFIX__/bin/swaylock { +ipc @prefix@/bin/swaylock { outputs enabled } diff --git a/sway/meson.build b/sway/meson.build index b02506c8..cf2aa913 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -26,5 +26,6 @@ executable( sway_sources, include_directories: [sway_inc], dependencies: sway_deps, - link_with: [lib_sway_common] + link_with: [lib_sway_common], + install: true ) -- cgit v1.2.3 From 8239067da42545a59dbb43b941f69470d501f544 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 3 Dec 2017 14:21:26 -0500 Subject: basic wl-shell --- include/sway/server.h | 3 ++ include/sway/view.h | 12 +++++++ sway/desktop/wl_shell.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + sway/server.c | 6 ++++ 5 files changed, 107 insertions(+) (limited to 'sway/meson.build') diff --git a/include/sway/server.h b/include/sway/server.h index 1901e39f..bfdb7b8a 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -30,6 +30,9 @@ struct sway_server { struct wlr_xdg_shell_v6 *xdg_shell_v6; struct wl_listener xdg_shell_v6_surface; + + struct wlr_wl_shell *wl_shell; + struct wl_listener wl_shell_surface; }; struct sway_server server; diff --git a/include/sway/view.h b/include/sway/view.h index 77d451e5..22f5ccf9 100644 --- a/include/sway/view.h +++ b/include/sway/view.h @@ -19,6 +19,18 @@ struct sway_xdg_surface_v6 { int pending_width, pending_height; }; +struct sway_wl_shell_surface { + struct sway_view *view; + + struct wl_listener commit; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener destroy; + + int pending_width, pending_height; +}; + enum sway_view_type { SWAY_WL_SHELL_VIEW, SWAY_XDG_SHELL_V6_VIEW, diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 8bfa605e..3a349425 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -28,3 +28,88 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { } } +static void set_dimensions(struct sway_view *view, int width, int height) { + if (!assert_wl_shell(view)) { + return; + } + view->sway_wl_shell_surface->pending_width = width; + view->sway_wl_shell_surface->pending_height = height; + wlr_wl_shell_surface_configure(view->wlr_wl_shell_surface, 0, width, height); +} + +static void handle_commit(struct wl_listener *listener, void *data) { + struct sway_wl_shell_surface *sway_surface = + wl_container_of(listener, sway_surface, commit); + struct sway_view *view = sway_surface->view; + sway_log(L_DEBUG, "wl_shell surface commit %dx%d", + sway_surface->pending_width, sway_surface->pending_height); + // NOTE: We intentionally discard the view's desired width here + // TODO: Let floating views do whatever + view->width = sway_surface->pending_width; + view->height = sway_surface->pending_height; +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct sway_wl_shell_surface *sway_surface = + wl_container_of(listener, sway_surface, destroy); + wl_list_remove(&sway_surface->commit.link); + wl_list_remove(&sway_surface->destroy.link); + swayc_t *parent = destroy_view(sway_surface->view->swayc); + free(sway_surface->view); + free(sway_surface); + arrange_windows(parent, -1, -1); +} + +void handle_wl_shell_surface(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of( + listener, server, wl_shell_surface); + struct wlr_wl_shell_surface *shell_surface = data; + + if (shell_surface->state != WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL) { + // TODO: transient and popups should be floating + return; + } + + sway_log(L_DEBUG, "New wl_shell toplevel title='%s' app_id='%s'", + shell_surface->title, shell_surface->class); + wlr_wl_shell_surface_ping(shell_surface); + + struct sway_wl_shell_surface *sway_surface = + calloc(1, sizeof(struct sway_wl_shell_surface)); + if (!sway_assert(sway_surface, "Failed to allocate surface!")) { + return; + } + + struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); + if (!sway_assert(sway_view, "Failed to allocate view!")) { + return; + } + sway_view->type = SWAY_WL_SHELL_VIEW; + sway_view->iface.get_prop = get_prop; + sway_view->iface.set_dimensions = set_dimensions; + sway_view->wlr_wl_shell_surface = shell_surface; + sway_view->sway_wl_shell_surface = sway_surface; + sway_view->surface = shell_surface->surface; + sway_surface->view = sway_view; + + // TODO: + // - Wire up listeners + // - Handle popups + // - Look up pid and open on appropriate workspace + // - Set new view to maximized so it behaves nicely + // - Criteria + + sway_surface->commit.notify = handle_commit; + wl_signal_add(&shell_surface->events.commit, &sway_surface->commit); + sway_surface->destroy.notify = handle_destroy; + wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy); + + // TODO: actual focus semantics + swayc_t *parent = root_container.children->items[0]; + parent = parent->children->items[0]; // workspace + + swayc_t *cont = new_view(parent, sway_view); + sway_view->swayc = cont; + + arrange_windows(cont->parent, -1, -1); +} diff --git a/sway/meson.build b/sway/meson.build index cf2aa913..dd3570bf 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -6,6 +6,7 @@ sway_sources = files( 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', + 'desktop/wl_shell.c', 'desktop/xdg_shell_v6.c', 'tree/container.c', 'tree/layout.c', diff --git a/sway/server.c b/sway/server.c index 6e66bc3c..bf5c37eb 100644 --- a/sway/server.c +++ b/sway/server.c @@ -7,6 +7,7 @@ #include #include #include +#include // TODO WLR: make Xwayland optional #include #include "sway/server.h" @@ -40,6 +41,11 @@ bool server_init(struct sway_server *server) { &server->xdg_shell_v6_surface); server->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + server->wl_shell = wlr_wl_shell_create(server->wl_display); + wl_signal_add(&server->wl_shell->events.new_surface, + &server->wl_shell_surface); + server->wl_shell_surface.notify = handle_wl_shell_surface; + server->socket = wl_display_add_socket_auto(server->wl_display); if (!sway_assert(server->socket, "Unable to open wayland socket")) { wlr_backend_destroy(server->backend); -- cgit v1.2.3 From 1870f116ba355fd02c8cc235fe262ccb0a03976b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 4 Dec 2017 06:19:36 -0500 Subject: xwayland shell --- include/sway/server.h | 4 ++ include/sway/view.h | 16 ++++++ sway/desktop/xwayland.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + sway/server.c | 7 +++ 5 files changed, 162 insertions(+) create mode 100644 sway/desktop/xwayland.c (limited to 'sway/meson.build') diff --git a/include/sway/server.h b/include/sway/server.h index b0684d15..30b15e75 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -30,6 +30,9 @@ struct sway_server { struct wlr_xdg_shell_v6 *xdg_shell_v6; struct wl_listener xdg_shell_v6_surface; + + struct wlr_xwayland *xwayland; + struct wl_listener xwayland_surface; }; struct sway_server server; @@ -42,5 +45,6 @@ void output_add_notify(struct wl_listener *listener, void *data); void output_remove_notify(struct wl_listener *listener, void *data); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); +void handle_xwayland_surface(struct wl_listener *listener, void *data); #endif diff --git a/include/sway/view.h b/include/sway/view.h index cf2e6f66..2d9b4ef5 100644 --- a/include/sway/view.h +++ b/include/sway/view.h @@ -3,6 +3,7 @@ #include #include #include +#include struct sway_container; struct sway_view; @@ -19,6 +20,19 @@ struct sway_xdg_surface_v6 { int pending_width, pending_height; }; +struct sway_xwayland_surface { + struct sway_view *view; + + struct wl_listener commit; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_configure; + struct wl_listener destroy; + + int pending_width, pending_height; +}; + enum sway_view_type { SWAY_WL_SHELL_VIEW, SWAY_XDG_SHELL_V6_VIEW, @@ -46,10 +60,12 @@ struct sway_view { union { struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; + struct wlr_xwayland_surface *wlr_xwayland_surface; }; union { struct sway_xdg_surface_v6 *sway_xdg_surface_v6; + struct sway_xwayland_surface *sway_xwayland_surface; }; struct { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c new file mode 100644 index 00000000..04ec118d --- /dev/null +++ b/sway/desktop/xwayland.c @@ -0,0 +1,134 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include "sway/container.h" +#include "sway/layout.h" +#include "sway/server.h" +#include "sway/view.h" +#include "log.h" + + static bool assert_xwayland(struct sway_view *view) { + return sway_assert(view->type == SWAY_XWAYLAND_VIEW, + "Expected xwayland view!"); + } + +static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { + if (!assert_xwayland(view)) { + return NULL; + } + switch (prop) { + case VIEW_PROP_TITLE: + return view->wlr_xwayland_surface->title; + case VIEW_PROP_CLASS: + return view->wlr_xwayland_surface->class; + default: + return NULL; + } +} + +static void set_size(struct sway_view *view, int width, int height) { + if (!assert_xwayland(view)) { + return; + } + view->sway_xwayland_surface->pending_width = width; + view->sway_xwayland_surface->pending_height = height; + + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + wlr_xwayland_surface_configure(xsurface, view->swayc->x, view->swayc->y, + width, height); +} + +static void handle_commit(struct wl_listener *listener, void *data) { + struct sway_xwayland_surface *sway_surface = + wl_container_of(listener, sway_surface, commit); + struct sway_view *view = sway_surface->view; + sway_log(L_DEBUG, "xwayland surface commit %dx%d", + sway_surface->pending_width, sway_surface->pending_height); + // NOTE: We intentionally discard the view's desired width here + // TODO: Let floating views do whatever + view->width = sway_surface->pending_width; + view->height = sway_surface->pending_height; +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xwayland_surface *sway_surface = + wl_container_of(listener, sway_surface, destroy); + wl_list_remove(&sway_surface->commit.link); + wl_list_remove(&sway_surface->destroy.link); + wl_list_remove(&sway_surface->request_configure.link); + swayc_t *parent = destroy_view(sway_surface->view->swayc); + free(sway_surface->view); + free(sway_surface); + arrange_windows(parent, -1, -1); +} + +static void handle_configure_request(struct wl_listener *listener, void *data) { + struct sway_xwayland_surface *sway_surface = + wl_container_of(listener, sway_surface, request_configure); + struct wlr_xwayland_surface_configure_event *ev = data; + struct sway_view *view = sway_surface->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + // TODO: floating windows are allowed to move around like this, but make + // sure tiling windows always stay in place. + wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, + ev->width, ev->height); +} + +void handle_xwayland_surface(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of( + listener, server, xwayland_surface); + struct wlr_xwayland_surface *xsurface = data; + + if (xsurface->override_redirect) { + // TODO: floating popups + return; + } + + sway_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", + xsurface->title, xsurface->class); + + struct sway_xwayland_surface *sway_surface = + calloc(1, sizeof(struct sway_xwayland_surface)); + if (!sway_assert(sway_surface, "Failed to allocate surface!")) { + return; + } + + struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); + if (!sway_assert(sway_view, "Failed to allocate view!")) { + return; + } + sway_view->type = SWAY_XWAYLAND_VIEW; + sway_view->iface.get_prop = get_prop; + sway_view->iface.set_size = set_size; + sway_view->wlr_xwayland_surface = xsurface; + sway_view->sway_xwayland_surface = sway_surface; + // TODO remove from the tree when the surface goes away (unmapped) + sway_view->surface = xsurface->surface; + sway_surface->view = sway_view; + + // TODO: + // - Wire up listeners + // - Handle popups + // - Look up pid and open on appropriate workspace + // - Set new view to maximized so it behaves nicely + // - Criteria + + sway_surface->commit.notify = handle_commit; + wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit); + sway_surface->destroy.notify = handle_destroy; + wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy); + sway_surface->request_configure.notify = handle_configure_request; + wl_signal_add(&xsurface->events.request_configure, + &sway_surface->request_configure); + + // TODO: actual focus semantics + swayc_t *parent = root_container.children->items[0]; + parent = parent->children->items[0]; // workspace + + swayc_t *cont = new_view(parent, sway_view); + sway_view->swayc = cont; + + arrange_windows(cont->parent, -1, -1); +} diff --git a/sway/meson.build b/sway/meson.build index cf2aa913..e8e9013f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -7,6 +7,7 @@ sway_sources = files( 'ipc-server.c', 'desktop/output.c', 'desktop/xdg_shell_v6.c', + 'desktop/xwayland.c', 'tree/container.c', 'tree/layout.c', 'tree/workspace.c', diff --git a/sway/server.c b/sway/server.c index 6e66bc3c..2694cea0 100644 --- a/sway/server.c +++ b/sway/server.c @@ -40,6 +40,13 @@ bool server_init(struct sway_server *server) { &server->xdg_shell_v6_surface); server->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; + // TODO make xwayland optional + server->xwayland = + wlr_xwayland_create(server->wl_display, server->compositor); + wl_signal_add(&server->xwayland->events.new_surface, + &server->xwayland_surface); + server->xwayland_surface.notify = handle_xwayland_surface; + server->socket = wl_display_add_socket_auto(server->wl_display); if (!sway_assert(server->socket, "Unable to open wayland socket")) { wlr_backend_destroy(server->backend); -- cgit v1.2.3 From 514c819ff98d72880c5b7e0beb7bd9ca866bc1ad Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 4 Dec 2017 22:43:49 +0100 Subject: Add exec and exec_always commands --- sway/commands.c | 2 ++ sway/commands/exec.c | 16 +++++++++ sway/commands/exec_always.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 2 ++ 4 files changed, 105 insertions(+) create mode 100644 sway/commands/exec.c create mode 100644 sway/commands/exec_always.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index 94a45253..5fdcdbb6 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -90,6 +90,8 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color) /* Keep alphabetized */ static struct cmd_handler handlers[] = { + { "exec", cmd_exec }, + { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, }; diff --git a/sway/commands/exec.c b/sway/commands/exec.c new file mode 100644 index 00000000..dd71500a --- /dev/null +++ b/sway/commands/exec.c @@ -0,0 +1,16 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_exec(int argc, char **argv) { + // TODO: config + /*if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); + if (config->reloading) { + char *args = join_args(argv, argc); + sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); + free(args); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + }*/ + return cmd_exec_always(argc, argv); +} diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c new file mode 100644 index 00000000..0a252e7b --- /dev/null +++ b/sway/commands/exec_always.c @@ -0,0 +1,85 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/workspace.h" +#include "sway/container.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_exec_always(int argc, char **argv) { + struct cmd_results *error = NULL; + // TODO: config + //if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); + if ((error = checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0))) { + return error; + } + + char *tmp = NULL; + if (strcmp((char*)*argv, "--no-startup-id") == 0) { + sway_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored."); + if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) { + return error; + } + + tmp = join_args(argv + 1, argc - 1); + } else { + tmp = join_args(argv, argc); + } + + // Put argument into cmd array + char cmd[4096]; + strncpy(cmd, tmp, sizeof(cmd)); + cmd[sizeof(cmd) - 1] = 0; + free(tmp); + sway_log(L_DEBUG, "Executing %s", cmd); + + int fd[2]; + if (pipe(fd) != 0) { + sway_log(L_ERROR, "Unable to create pipe for fork"); + } + + pid_t pid; + pid_t *child = malloc(sizeof(pid_t)); // malloc'd so that Linux can avoid copying the process space + if (!child) { + return cmd_results_new(CMD_FAILURE, "exec_always", "Unable to allocate child pid"); + } + // Fork process + if ((pid = fork()) == 0) { + // Fork child process again + setsid(); + if ((*child = fork()) == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); + // Not reached + } + close(fd[0]); + ssize_t s = 0; + while ((size_t)s < sizeof(pid_t)) { + s += write(fd[1], ((uint8_t *)child) + s, sizeof(pid_t) - s); + } + close(fd[1]); + _exit(0); // Close child process + } else if (pid < 0) { + free(child); + return cmd_results_new(CMD_FAILURE, "exec_always", "fork() failed"); + } + close(fd[1]); // close write + ssize_t s = 0; + while ((size_t)s < sizeof(pid_t)) { + s += read(fd[0], ((uint8_t *)child) + s, sizeof(pid_t) - s); + } + close(fd[0]); + // cleanup child process + wait(0); + if (*child > 0) { + sway_log(L_DEBUG, "Child process created with pid %d", *child); + // TODO: add PID to active workspace + } else { + free(child); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 9f92f5d1..b224f15f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -3,6 +3,8 @@ sway_sources = files( 'server.c', 'commands.c', 'commands/exit.c', + 'commands/exec.c', + 'commands/exec_always.c', 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', -- cgit v1.2.3 From 90f7f1a0e61fa20ed1b74b9df057aa70abc791ed Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 5 Dec 2017 10:40:55 +0100 Subject: Add minimal config subsystem --- include/sway/commands.h | 10 + include/sway/config.h | 405 +++++++++++++++++++++++++++++++++++ meson.build | 2 + sway/commands.c | 132 ++++++++++++ sway/commands/exec.c | 6 +- sway/commands/exec_always.c | 6 +- sway/commands/exit.c | 4 +- sway/config.c | 504 ++++++++++++++++++++++++++++++++++++++++++++ sway/main.c | 21 +- sway/meson.build | 2 + sway/security.c | 18 ++ 11 files changed, 1091 insertions(+), 19 deletions(-) create mode 100644 include/sway/config.h create mode 100644 sway/config.c create mode 100644 sway/security.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index df5c6859..b1f0423d 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -46,6 +46,16 @@ struct cmd_results *checkarg(int argc, const char *name, * Parse and handles a command. */ struct cmd_results *handle_command(char *command); +/** + * Parse and handles a command during config file loading. + * + * Do not use this under normal conditions. + */ +struct cmd_results *config_command(char *command, enum cmd_status block); +/* + * Parses a command policy rule. + */ +struct cmd_results *config_commands_command(char *exec); /** * Allocates a cmd_results object. */ diff --git a/include/sway/config.h b/include/sway/config.h new file mode 100644 index 00000000..56b4e637 --- /dev/null +++ b/include/sway/config.h @@ -0,0 +1,405 @@ +#ifndef _SWAY_CONFIG_H +#define _SWAY_CONFIG_H + +#define PID_WORKSPACE_TIMEOUT 60 + +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "layout.h" +#include "container.h" + +/** + * Describes a variable created via the `set` command. + */ +struct sway_variable { + char *name; + char *value; +}; + +/** + * A key binding and an associated command. + */ +struct sway_binding { + int order; + bool release; + bool bindcode; + list_t *keys; + uint32_t modifiers; + char *command; +}; + +/** + * A mouse binding and an associated command. + */ +struct sway_mouse_binding { + uint32_t button; + char *command; +}; + +/** + * A "mode" of keybindings created via the `mode` command. + */ +struct sway_mode { + char *name; + list_t *bindings; +}; + +/** + * libinput options for input devices + */ +struct input_config { + char *identifier; + + int accel_profile; + int click_method; + int drag_lock; + int dwt; + int left_handed; + int middle_emulation; + int natural_scroll; + float pointer_accel; + int scroll_method; + int send_events; + int tap; + + bool capturable; + struct wlc_geometry region; +}; + +/** + * Size and position configuration for a particular output. + * + * This is set via the `output` command. + */ +struct output_config { + char *name; + int enabled; + int width, height; + int x, y; + int scale; + char *background; + char *background_option; +}; + +/** + * Maps a workspace name to an output name. + * + * Set via `workspace output ` + */ +struct workspace_output { + char *output; + char *workspace; +}; + +struct pid_workspace { + pid_t *pid; + char *workspace; + time_t *time_added; +}; + +struct bar_config { + /** + * One of "dock", "hide", "invisible" + * + * Always visible in dock mode. Visible only when modifier key is held in hide mode. + * Never visible in invisible mode. + */ + char *mode; + /** + * One of "show" or "hide". + * + * In "show" mode, it will always be shown on top of the active workspace. + */ + char *hidden_state; + /** + * Id name used to identify the bar through IPC. + * + * Defaults to bar-x, where x corresponds to the position of the + * embedding bar block in the config file (bar-0, bar-1, ...). + */ + char *id; + uint32_t modifier; + list_t *outputs; + //enum desktop_shell_panel_position position; // TODO + list_t *bindings; + char *status_command; + bool pango_markup; + char *swaybar_command; + char *font; + int height; // -1 not defined + +#ifdef ENABLE_TRAY + // Tray + char *tray_output; + char *icon_theme; + uint32_t tray_padding; + uint32_t activate_button; + uint32_t context_button; + uint32_t secondary_button; +#endif + + bool workspace_buttons; + bool wrap_scroll; + char *separator_symbol; + bool strip_workspace_numbers; + bool binding_mode_indicator; + bool verbose; + pid_t pid; + struct { + char *background; + char *statusline; + char *separator; + char *focused_background; + char *focused_statusline; + char *focused_separator; + char *focused_workspace_border; + char *focused_workspace_bg; + char *focused_workspace_text; + char *active_workspace_border; + char *active_workspace_bg; + char *active_workspace_text; + char *inactive_workspace_border; + char *inactive_workspace_bg; + char *inactive_workspace_text; + char *urgent_workspace_border; + char *urgent_workspace_bg; + char *urgent_workspace_text; + char *binding_mode_border; + char *binding_mode_bg; + char *binding_mode_text; + } colors; +}; + +struct border_colors { + uint32_t border; + uint32_t background; + uint32_t text; + uint32_t indicator; + uint32_t child_border; +}; + +enum edge_border_types { + E_NONE, /**< Don't hide edge borders */ + E_VERTICAL, /**< hide vertical edge borders */ + E_HORIZONTAL, /**< hide horizontal edge borders */ + E_BOTH, /**< hide vertical and horizontal edge borders */ + E_SMART /**< hide both if precisely one window is present in workspace */ +}; + +enum command_context { + CONTEXT_CONFIG = 1, + CONTEXT_BINDING = 2, + CONTEXT_IPC = 4, + CONTEXT_CRITERIA = 8, + CONTEXT_ALL = 0xFFFFFFFF, +}; + +struct command_policy { + char *command; + uint32_t context; +}; + +enum secure_feature { + FEATURE_LOCK = 1, + FEATURE_PANEL = 2, + FEATURE_BACKGROUND = 4, + FEATURE_SCREENSHOT = 8, + FEATURE_FULLSCREEN = 16, + FEATURE_KEYBOARD = 32, + FEATURE_MOUSE = 64, +}; + +struct feature_policy { + char *program; + uint32_t features; +}; + +enum ipc_feature { + IPC_FEATURE_COMMAND = 1, + IPC_FEATURE_GET_WORKSPACES = 2, + IPC_FEATURE_GET_OUTPUTS = 4, + IPC_FEATURE_GET_TREE = 8, + IPC_FEATURE_GET_MARKS = 16, + IPC_FEATURE_GET_BAR_CONFIG = 32, + IPC_FEATURE_GET_VERSION = 64, + IPC_FEATURE_GET_INPUTS = 128, + IPC_FEATURE_EVENT_WORKSPACE = 256, + IPC_FEATURE_EVENT_OUTPUT = 512, + IPC_FEATURE_EVENT_MODE = 1024, + IPC_FEATURE_EVENT_WINDOW = 2048, + IPC_FEATURE_EVENT_BINDING = 4096, + IPC_FEATURE_EVENT_INPUT = 8192, + IPC_FEATURE_GET_CLIPBOARD = 16384, + + IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, + IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, + + IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, +}; + +struct ipc_policy { + char *program; + uint32_t features; +}; + +/** + * The configuration struct. The result of loading a config file. + */ +struct sway_config { + list_t *symbols; + list_t *modes; + list_t *bars; + list_t *cmd_queue; + list_t *workspace_outputs; + list_t *pid_workspaces; + list_t *output_configs; + list_t *input_configs; + list_t *criteria; + list_t *no_focus; + list_t *active_bar_modifiers; + struct sway_mode *current_mode; + struct bar_config *current_bar; + uint32_t floating_mod; + uint32_t dragging_key; + uint32_t resizing_key; + char *floating_scroll_up_cmd; + char *floating_scroll_down_cmd; + char *floating_scroll_left_cmd; + char *floating_scroll_right_cmd; + enum swayc_layouts default_orientation; + enum swayc_layouts default_layout; + char *font; + int font_height; + + // Flags + bool focus_follows_mouse; + bool mouse_warping; + bool force_focus_wrapping; + bool active; + bool failed; + bool reloading; + bool reading; + bool auto_back_and_forth; + bool seamless_mouse; + bool show_marks; + + bool edge_gaps; + bool smart_gaps; + int gaps_inner; + int gaps_outer; + + list_t *config_chain; + const char *current_config; + + enum swayc_border_types border; + enum swayc_border_types floating_border; + int border_thickness; + int floating_border_thickness; + enum edge_border_types hide_edge_borders; + + // border colors + struct { + struct border_colors focused; + struct border_colors focused_inactive; + struct border_colors unfocused; + struct border_colors urgent; + struct border_colors placeholder; + uint32_t background; + } border_colors; + + // floating view + int32_t floating_maximum_width; + int32_t floating_maximum_height; + int32_t floating_minimum_width; + int32_t floating_minimum_height; + + // Security + list_t *command_policies; + list_t *feature_policies; + list_t *ipc_policies; +}; + +void pid_workspace_add(struct pid_workspace *pw); +void free_pid_workspace(struct pid_workspace *pw); + +/** + * Loads the main config from the given path. is_active should be true when + * reloading the config. + */ +bool load_main_config(const char *path, bool is_active); + +/** + * Loads an included config. Can only be used after load_main_config. + */ +bool load_include_configs(const char *path, struct sway_config *config); + +/** + * Reads the config from the given FILE. + */ +bool read_config(FILE *file, struct sway_config *config); + +/** + * Free config struct + */ +void free_config(struct sway_config *config); +/** + * Does variable replacement for a string based on the config's currently loaded variables. + */ +char *do_var_replacement(char *str); + +struct cmd_results *check_security_config(); + +int input_identifier_cmp(const void *item, const void *data); +void merge_input_config(struct input_config *dst, struct input_config *src); +void apply_input_config(struct input_config *ic, struct libinput_device *dev); +void free_input_config(struct input_config *ic); + +int output_name_cmp(const void *item, const void *data); +void merge_output_config(struct output_config *dst, struct output_config *src); +/** Sets up a WLC output handle based on a given output_config. + */ +void apply_output_config(struct output_config *oc, swayc_t *output); +void free_output_config(struct output_config *oc); + +/** + * Updates the list of active bar modifiers + */ +void update_active_bar_modifiers(void); + +int workspace_output_cmp_workspace(const void *a, const void *b); + +int sway_binding_cmp(const void *a, const void *b); +int sway_binding_cmp_qsort(const void *a, const void *b); +int sway_binding_cmp_keys(const void *a, const void *b); +void free_sway_binding(struct sway_binding *sb); +struct sway_binding *sway_binding_dup(struct sway_binding *sb); + +int sway_mouse_binding_cmp(const void *a, const void *b); +int sway_mouse_binding_cmp_qsort(const void *a, const void *b); +int sway_mouse_binding_cmp_buttons(const void *a, const void *b); +void free_sway_mouse_binding(struct sway_mouse_binding *smb); + +void load_swaybars(); +void terminate_swaybg(pid_t pid); + +/** + * Allocate and initialize default bar configuration. + */ +struct bar_config *default_bar_config(void); + +/** + * Global config singleton. + */ +extern struct sway_config *config; + +/** + * Config file currently being read. + */ +extern const char *current_config_path; + +#endif diff --git a/meson.build b/meson.build index 695e237e..8e7b98ed 100644 --- a/meson.build +++ b/meson.build @@ -65,6 +65,8 @@ if a2x.found() endforeach endif +add_project_arguments('-DSYSCONFDIR="/@0@"'.format(sysconfdir), language : 'c') + version = get_option('sway_version') if version != '' version = '"@0@"'.format(version) diff --git a/sway/commands.c b/sway/commands.c index 5fdcdbb6..17638129 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -7,6 +7,8 @@ #include #include #include "sway/commands.h" +#include "sway/config.h" +#include "sway/security.h" #include "stringop.h" #include "log.h" @@ -200,6 +202,136 @@ cleanup: return results; } +// this is like handle_command above, except: +// 1) it ignores empty commands (empty lines) +// 2) it does variable substitution +// 3) it doesn't split commands (because the multiple commands are supposed to +// be chained together) +// 4) handle_command handles all state internally while config_command has some +// state handled outside (notably the block mode, in read_config) +struct cmd_results *config_command(char *exec, enum cmd_status block) { + struct cmd_results *results = NULL; + int argc; + char **argv = split_args(exec, &argc); + if (!argc) { + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + goto cleanup; + } + + sway_log(L_INFO, "handling config command '%s'", exec); + // Endblock + if (**argv == '}') { + results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); + goto cleanup; + } + struct cmd_handler *handler = find_handler(argv[0], block); + if (!handler) { + char *input = argv[0] ? argv[0] : "(empty)"; + results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); + goto cleanup; + } + int i; + // Var replacement, for all but first argument of set + // TODO commands + for (i = /*handler->handle == cmd_set ? 2 :*/ 1; i < argc; ++i) { + argv[i] = do_var_replacement(argv[i]); + unescape_string(argv[i]); + } + /* Strip quotes for first argument. + * TODO This part needs to be handled much better */ + if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { + strip_quotes(argv[1]); + } + if (handler->handle) { + results = handler->handle(argc-1, argv+1); + } else { + results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented"); + } + +cleanup: + free_argv(argc, argv); + return results; +} + +struct cmd_results *config_commands_command(char *exec) { + struct cmd_results *results = NULL; + int argc; + char **argv = split_args(exec, &argc); + if (!argc) { + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + goto cleanup; + } + + // Find handler for the command this is setting a policy for + char *cmd = argv[0]; + + if (strcmp(cmd, "}") == 0) { + results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); + goto cleanup; + } + + struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); + if (!handler && strcmp(cmd, "*") != 0) { + char *input = cmd ? cmd : "(empty)"; + results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); + goto cleanup; + } + + enum command_context context = 0; + + struct { + char *name; + enum command_context context; + } context_names[] = { + { "config", CONTEXT_CONFIG }, + { "binding", CONTEXT_BINDING }, + { "ipc", CONTEXT_IPC }, + { "criteria", CONTEXT_CRITERIA }, + { "all", CONTEXT_ALL }, + }; + + for (int i = 1; i < argc; ++i) { + size_t j; + for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { + if (strcmp(context_names[j].name, argv[i]) == 0) { + break; + } + } + if (j == sizeof(context_names) / sizeof(context_names[0])) { + results = cmd_results_new(CMD_INVALID, cmd, + "Invalid command context %s", argv[i]); + goto cleanup; + } + context |= context_names[j].context; + } + + struct command_policy *policy = NULL; + for (int i = 0; i < config->command_policies->length; ++i) { + struct command_policy *p = config->command_policies->items[i]; + if (strcmp(p->command, cmd) == 0) { + policy = p; + break; + } + } + if (!policy) { + policy = alloc_command_policy(cmd); + sway_assert(policy, "Unable to allocate security policy"); + if (policy) { + list_add(config->command_policies, policy); + } + } + policy->context = context; + + sway_log(L_INFO, "Set command policy for %s to %d", + policy->command, policy->context); + + results = cmd_results_new(CMD_SUCCESS, NULL, NULL); + +cleanup: + free_argv(argc, argv); + return results; +} + struct cmd_results *cmd_results_new(enum cmd_status status, const char *input, const char *format, ...) { struct cmd_results *results = malloc(sizeof(struct cmd_results)); diff --git a/sway/commands/exec.c b/sway/commands/exec.c index dd71500a..fbbc4941 100644 --- a/sway/commands/exec.c +++ b/sway/commands/exec.c @@ -1,16 +1,16 @@ #include #include "sway/commands.h" +#include "sway/config.h" #include "log.h" #include "stringop.h" struct cmd_results *cmd_exec(int argc, char **argv) { - // TODO: config - /*if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); + if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); if (config->reloading) { char *args = join_args(argv, argc); sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); free(args); return cmd_results_new(CMD_SUCCESS, NULL, NULL); - }*/ + } return cmd_exec_always(argc, argv); } diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 0a252e7b..9527a487 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -5,15 +5,15 @@ #include #include #include "sway/commands.h" -#include "sway/workspace.h" +#include "sway/config.h" #include "sway/container.h" +#include "sway/workspace.h" #include "log.h" #include "stringop.h" struct cmd_results *cmd_exec_always(int argc, char **argv) { struct cmd_results *error = NULL; - // TODO: config - //if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); + if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); if ((error = checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0))) { return error; } diff --git a/sway/commands/exit.c b/sway/commands/exit.c index d294e344..4bb6a97b 100644 --- a/sway/commands/exit.c +++ b/sway/commands/exit.c @@ -1,19 +1,17 @@ #include #include "sway/commands.h" +#include "sway/config.h" void sway_terminate(int exit_code); struct cmd_results *cmd_exit(int argc, char **argv) { struct cmd_results *error = NULL; - /* TODO if (config->reading) { return cmd_results_new(CMD_FAILURE, "exit", "Can't be used in config file."); } - */ if ((error = checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0))) { return error; } sway_terminate(0); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } - diff --git a/sway/config.c b/sway/config.c new file mode 100644 index 00000000..475e8b04 --- /dev/null +++ b/sway/config.c @@ -0,0 +1,504 @@ +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/layout.h" +#include "readline.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +struct sway_config *config = NULL; + +void free_config(struct sway_config *config) { + // TODO +} + +static void config_defaults(struct sway_config *config) { + if (!(config->symbols = create_list())) goto cleanup; + if (!(config->modes = create_list())) goto cleanup; + if (!(config->bars = create_list())) goto cleanup; + if (!(config->workspace_outputs = create_list())) goto cleanup; + if (!(config->pid_workspaces = create_list())) goto cleanup; + if (!(config->criteria = create_list())) goto cleanup; + if (!(config->no_focus = create_list())) goto cleanup; + if (!(config->input_configs = create_list())) goto cleanup; + if (!(config->output_configs = create_list())) goto cleanup; + + if (!(config->cmd_queue = create_list())) goto cleanup; + + if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; + if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; + strcpy(config->current_mode->name, "default"); + if (!(config->current_mode->bindings = create_list())) goto cleanup; + list_add(config->modes, config->current_mode); + + config->floating_mod = 0; + config->dragging_key = BTN_LEFT; + config->resizing_key = BTN_RIGHT; + if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; + if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; + config->default_layout = L_NONE; + config->default_orientation = L_NONE; + if (!(config->font = strdup("monospace 10"))) goto cleanup; + // TODO: border + //config->font_height = get_font_text_height(config->font); + + // floating view + config->floating_maximum_width = 0; + config->floating_maximum_height = 0; + config->floating_minimum_width = 75; + config->floating_minimum_height = 50; + + // Flags + config->focus_follows_mouse = true; + config->mouse_warping = true; + config->reloading = false; + config->active = false; + config->failed = false; + config->auto_back_and_forth = false; + config->seamless_mouse = true; + config->reading = false; + config->show_marks = true; + + config->edge_gaps = true; + config->smart_gaps = false; + config->gaps_inner = 0; + config->gaps_outer = 0; + + if (!(config->active_bar_modifiers = create_list())) goto cleanup; + + if (!(config->config_chain = create_list())) goto cleanup; + config->current_config = NULL; + + // borders + config->border = B_NORMAL; + config->floating_border = B_NORMAL; + config->border_thickness = 2; + config->floating_border_thickness = 2; + config->hide_edge_borders = E_NONE; + + // border colors + config->border_colors.focused.border = 0x4C7899FF; + config->border_colors.focused.background = 0x285577FF; + config->border_colors.focused.text = 0xFFFFFFFF; + config->border_colors.focused.indicator = 0x2E9EF4FF; + config->border_colors.focused.child_border = 0x285577FF; + + config->border_colors.focused_inactive.border = 0x333333FF; + config->border_colors.focused_inactive.background = 0x5F676AFF; + config->border_colors.focused_inactive.text = 0xFFFFFFFF; + config->border_colors.focused_inactive.indicator = 0x484E50FF; + config->border_colors.focused_inactive.child_border = 0x5F676AFF; + + config->border_colors.unfocused.border = 0x333333FF; + config->border_colors.unfocused.background = 0x222222FF; + config->border_colors.unfocused.text = 0x888888FF; + config->border_colors.unfocused.indicator = 0x292D2EFF; + config->border_colors.unfocused.child_border = 0x222222FF; + + config->border_colors.urgent.border = 0x2F343AFF; + config->border_colors.urgent.background = 0x900000FF; + config->border_colors.urgent.text = 0xFFFFFFFF; + config->border_colors.urgent.indicator = 0x900000FF; + config->border_colors.urgent.child_border = 0x900000FF; + + config->border_colors.placeholder.border = 0x000000FF; + config->border_colors.placeholder.background = 0x0C0C0CFF; + config->border_colors.placeholder.text = 0xFFFFFFFF; + config->border_colors.placeholder.indicator = 0x000000FF; + config->border_colors.placeholder.child_border = 0x0C0C0CFF; + + config->border_colors.background = 0xFFFFFFFF; + + // Security + if (!(config->command_policies = create_list())) goto cleanup; + if (!(config->feature_policies = create_list())) goto cleanup; + if (!(config->ipc_policies = create_list())) goto cleanup; + + return; +cleanup: + sway_abort("Unable to allocate config structures"); +} + +static bool file_exists(const char *path) { + return path && access(path, R_OK) != -1; +} + +static char *get_config_path(void) { + static const char *config_paths[] = { + "$HOME/.sway/config", + "$XDG_CONFIG_HOME/sway/config", + "$HOME/.i3/config", + "$XDG_CONFIG_HOME/i3/config", + SYSCONFDIR "/sway/config", + SYSCONFDIR "/i3/config", + }; + + if (!getenv("XDG_CONFIG_HOME")) { + char *home = getenv("HOME"); + char *config_home = malloc(strlen(home) + strlen("/.config") + 1); + if (!config_home) { + sway_log(L_ERROR, "Unable to allocate $HOME/.config"); + } else { + strcpy(config_home, home); + strcat(config_home, "/.config"); + setenv("XDG_CONFIG_HOME", config_home, 1); + sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); + free(config_home); + } + } + + wordexp_t p; + char *path; + + int i; + for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { + if (wordexp(config_paths[i], &p, 0) == 0) { + path = strdup(p.we_wordv[0]); + wordfree(&p); + if (file_exists(path)) { + return path; + } + } + } + + return NULL; // Not reached +} + +const char *current_config_path; + +static bool load_config(const char *path, struct sway_config *config) { + sway_log(L_INFO, "Loading config from %s", path); + current_config_path = path; + + struct stat sb; + if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { + return false; + } + + if (path == NULL) { + sway_log(L_ERROR, "Unable to find a config file!"); + return false; + } + + FILE *f = fopen(path, "r"); + if (!f) { + sway_log(L_ERROR, "Unable to open %s for reading", path); + return false; + } + + bool config_load_success = read_config(f, config); + fclose(f); + + if (!config_load_success) { + sway_log(L_ERROR, "Error(s) loading config!"); + } + + current_config_path = NULL; + return true; +} + +static int qstrcmp(const void* a, const void* b) { + return strcmp(*((char**) a), *((char**) b)); +} + +bool load_main_config(const char *file, bool is_active) { + char *path; + if (file != NULL) { + path = strdup(file); + } else { + path = get_config_path(); + } + + struct sway_config *old_config = config; + config = calloc(1, sizeof(struct sway_config)); + if (!config) { + sway_abort("Unable to allocate config"); + } + + config_defaults(config); + if (is_active) { + sway_log(L_DEBUG, "Performing configuration file reload"); + config->reloading = true; + config->active = true; + } + + config->current_config = path; + list_add(config->config_chain, path); + + config->reading = true; + + // Read security configs + bool success = true; + DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); + if (!dir) { + sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" + " and will probably be broken", SYSCONFDIR "/sway/security.d"); + } else { + list_t *secconfigs = create_list(); + char *base = SYSCONFDIR "/sway/security.d/"; + struct dirent *ent = readdir(dir); + struct stat s; + while (ent != NULL) { + char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); + strcpy(_path, base); + strcat(_path, ent->d_name); + lstat(_path, &s); + if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { + list_add(secconfigs, _path); + } + else { + free(_path); + } + ent = readdir(dir); + } + closedir(dir); + + list_qsort(secconfigs, qstrcmp); + for (int i = 0; i < secconfigs->length; ++i) { + char *_path = secconfigs->items[i]; + if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { + sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); + success = false; + } else { + success = success && load_config(_path, config); + } + } + + free_flat_list(secconfigs); + } + + success = success && load_config(path, config); + + if (is_active) { + config->reloading = false; + } + + if (old_config) { + free_config(old_config); + } + config->reading = false; + + if (success) { + // TODO: bar + //update_active_bar_modifiers(); + } + + return success; +} + +bool read_config(FILE *file, struct sway_config *config) { + bool success = true; + enum cmd_status block = CMD_BLOCK_END; + + int line_number = 0; + char *line; + while (!feof(file)) { + line = read_line(file); + if (!line) { + continue; + } + line_number++; + line = strip_whitespace(line); + if (line[0] == '#') { + free(line); + continue; + } + struct cmd_results *res; + if (block == CMD_BLOCK_COMMANDS) { + // Special case + res = config_commands_command(line); + } else { + res = config_command(line, block); + } + switch(res->status) { + case CMD_FAILURE: + case CMD_INVALID: + sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, + res->error, config->current_config); + success = false; + break; + + case CMD_DEFER: + sway_log(L_DEBUG, "Defferring command `%s'", line); + list_add(config->cmd_queue, strdup(line)); + break; + + case CMD_BLOCK_MODE: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_MODE; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_INPUT: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_INPUT; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_BAR: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_BAR; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_BAR_COLORS: + if (block == CMD_BLOCK_BAR) { + block = CMD_BLOCK_BAR_COLORS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_COMMANDS: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_COMMANDS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_IPC: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_IPC; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_IPC_EVENTS: + if (block == CMD_BLOCK_IPC) { + block = CMD_BLOCK_IPC_EVENTS; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + + case CMD_BLOCK_END: + switch(block) { + case CMD_BLOCK_MODE: + sway_log(L_DEBUG, "End of mode block"); + config->current_mode = config->modes->items[0]; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_INPUT: + sway_log(L_DEBUG, "End of input block"); + // TODO: input + //current_input_config = NULL; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_BAR: + sway_log(L_DEBUG, "End of bar block"); + config->current_bar = NULL; + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_BAR_COLORS: + sway_log(L_DEBUG, "End of bar colors block"); + block = CMD_BLOCK_BAR; + break; + + case CMD_BLOCK_COMMANDS: + sway_log(L_DEBUG, "End of commands block"); + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_IPC: + sway_log(L_DEBUG, "End of IPC block"); + block = CMD_BLOCK_END; + break; + + case CMD_BLOCK_IPC_EVENTS: + sway_log(L_DEBUG, "End of IPC events block"); + block = CMD_BLOCK_IPC; + break; + + case CMD_BLOCK_END: + sway_log(L_ERROR, "Unmatched }"); + break; + + default:; + } + default:; + } + free(line); + free_cmd_results(res); + } + + return success; +} + +char *do_var_replacement(char *str) { + int i; + char *find = str; + while ((find = strchr(find, '$'))) { + // Skip if escaped. + if (find > str && find[-1] == '\\') { + if (find == str + 1 || !(find > str + 1 && find[-2] == '\\')) { + ++find; + continue; + } + } + // Find matching variable + for (i = 0; i < config->symbols->length; ++i) { + struct sway_variable *var = config->symbols->items[i]; + int vnlen = strlen(var->name); + if (strncmp(find, var->name, vnlen) == 0) { + int vvlen = strlen(var->value); + char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); + if (!newstr) { + sway_log(L_ERROR, + "Unable to allocate replacement during variable expansion"); + break; + } + char *newptr = newstr; + int offset = find - str; + strncpy(newptr, str, offset); + newptr += offset; + strncpy(newptr, var->value, vvlen); + newptr += vvlen; + strcpy(newptr, find + vnlen); + free(str); + str = newstr; + find = str + offset + vvlen; + break; + } + } + if (i == config->symbols->length) { + ++find; + } + } + return str; +} diff --git a/sway/main.c b/sway/main.c index bc107309..bc843591 100644 --- a/sway/main.c +++ b/sway/main.c @@ -15,6 +15,7 @@ #include #include #endif +#include "sway/config.h" #include "sway/server.h" #include "sway/layout.h" #include "sway/ipc-server.h" @@ -388,14 +389,14 @@ int main(int argc, char **argv) { ipc_init(&server); log_env(); - //if (validate) { - // bool valid = load_main_config(config_path, false); - // return valid ? 0 : 1; - //} + if (validate) { + bool valid = load_main_config(config_path, false); + return valid ? 0 : 1; + } - //if (!load_main_config(config_path, false)) { - // sway_terminate(EXIT_FAILURE); - //} + if (!load_main_config(config_path, false)) { + sway_terminate(EXIT_FAILURE); + } if (config_path) { free(config_path); @@ -411,9 +412,9 @@ int main(int argc, char **argv) { ipc_terminate(); - //if (config) { - // free_config(config); - //} + if (config) { + free_config(config); + } return exit_value; } diff --git a/sway/meson.build b/sway/meson.build index b224f15f..84f48137 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -5,12 +5,14 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'config.c', 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', 'desktop/wl_shell.c', 'desktop/xdg_shell_v6.c', 'desktop/xwayland.c', + 'security.c', 'tree/container.c', 'tree/layout.c', 'tree/workspace.c', diff --git a/sway/security.c b/sway/security.c new file mode 100644 index 00000000..cc0d3f66 --- /dev/null +++ b/sway/security.c @@ -0,0 +1,18 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include "sway/security.h" + +struct command_policy *alloc_command_policy(const char *command) { + struct command_policy *policy = malloc(sizeof(struct command_policy)); + if (!policy) { + return NULL; + } + policy->command = strdup(command); + if (!policy->command) { + free(policy); + return NULL; + } + policy->context = 0; + return policy; +} -- cgit v1.2.3 From 9aeda824779d3174db01b6445fa349def031a035 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 5 Dec 2017 18:47:57 +0100 Subject: Add include command --- sway/commands.c | 1 + sway/commands/include.c | 15 +++++++++ sway/config.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + 4 files changed, 106 insertions(+) create mode 100644 sway/commands/include.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index 17638129..05a66a7f 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -95,6 +95,7 @@ static struct cmd_handler handlers[] = { { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, + { "include", cmd_include }, }; static int handler_compare(const void *_a, const void *_b) { diff --git a/sway/commands/include.c b/sway/commands/include.c new file mode 100644 index 00000000..1ba9a10d --- /dev/null +++ b/sway/commands/include.c @@ -0,0 +1,15 @@ +#include "sway/commands.h" +#include "sway/config.h" + +struct cmd_results *cmd_include(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!load_include_configs(argv[0], config)) { + return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 475e8b04..61131845 100644 --- a/sway/config.c +++ b/sway/config.c @@ -311,6 +311,95 @@ bool load_main_config(const char *file, bool is_active) { return success; } +static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { + // save parent config + const char *parent_config = config->current_config; + + char *full_path = strdup(path); + int len = strlen(path); + if (len >= 1 && path[0] != '/') { + len = len + strlen(parent_dir) + 2; + full_path = malloc(len * sizeof(char)); + if (!full_path) { + sway_log(L_ERROR, "Unable to allocate full path to included config"); + return false; + } + snprintf(full_path, len, "%s/%s", parent_dir, path); + } + + char *real_path = realpath(full_path, NULL); + free(full_path); + + if (real_path == NULL) { + sway_log(L_DEBUG, "%s not found.", path); + return false; + } + + // check if config has already been included + int j; + for (j = 0; j < config->config_chain->length; ++j) { + char *old_path = config->config_chain->items[j]; + if (strcmp(real_path, old_path) == 0) { + sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); + free(real_path); + return false; + } + } + + config->current_config = real_path; + list_add(config->config_chain, real_path); + int index = config->config_chain->length - 1; + + if (!load_config(real_path, config)) { + free(real_path); + config->current_config = parent_config; + list_del(config->config_chain, index); + return false; + } + + // restore current_config + config->current_config = parent_config; + return true; +} + +bool load_include_configs(const char *path, struct sway_config *config) { + char *wd = getcwd(NULL, 0); + char *parent_path = strdup(config->current_config); + const char *parent_dir = dirname(parent_path); + + if (chdir(parent_dir) < 0) { + free(parent_path); + free(wd); + return false; + } + + wordexp_t p; + + if (wordexp(path, &p, 0) < 0) { + free(parent_path); + free(wd); + return false; + } + + char **w = p.we_wordv; + size_t i; + for (i = 0; i < p.we_wordc; ++i) { + load_include_config(w[i], parent_dir, config); + } + free(parent_path); + wordfree(&p); + + // restore wd + if (chdir(wd) < 0) { + free(wd); + sway_log(L_ERROR, "failed to restore working directory"); + return false; + } + + free(wd); + return true; +} + bool read_config(FILE *file, struct sway_config *config) { bool success = true; enum cmd_status block = CMD_BLOCK_END; diff --git a/sway/meson.build b/sway/meson.build index 84f48137..ab863e87 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -5,6 +5,7 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/include.c', 'config.c', 'ipc-json.c', 'ipc-server.c', -- cgit v1.2.3 From aaae59026ff3751190b93277ac6d7566e373c892 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 6 Dec 2017 12:36:06 +0100 Subject: Add output config --- include/sway/config.h | 4 + include/sway/container.h | 1 + sway/commands.c | 1 + sway/commands/output.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++ sway/config/output.c | 166 +++++++++++++++++++++++++++++++ sway/main.c | 4 + sway/meson.build | 2 + sway/tree/container.c | 83 +++++++++++++++- 8 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 sway/commands/output.c create mode 100644 sway/config/output.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index 7de85ab7..1b49c5c9 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -80,8 +81,11 @@ struct output_config { char *name; int enabled; int width, height; + float refresh_rate; int x, y; int scale; + enum wl_output_transform transform; + char *background; char *background_option; }; diff --git a/include/sway/container.h b/include/sway/container.h index 08a98ed9..e3f84fc6 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -132,6 +132,7 @@ swayc_t *new_output(struct sway_output *sway_output); swayc_t *new_workspace(swayc_t *output, const char *name); swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view); +swayc_t *destroy_output(swayc_t *output); swayc_t *destroy_view(swayc_t *view); swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); diff --git a/sway/commands.c b/sway/commands.c index 17638129..961cb867 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -95,6 +95,7 @@ static struct cmd_handler handlers[] = { { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, + { "output", cmd_output }, }; static int handler_compare(const void *_a, const void *_b) { diff --git a/sway/commands/output.c b/sway/commands/output.c new file mode 100644 index 00000000..c964bef7 --- /dev/null +++ b/sway/commands/output.c @@ -0,0 +1,253 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +static char *bg_options[] = { + "stretch", + "center", + "fill", + "fit", + "tile", +}; + +struct cmd_results *cmd_output(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { + return error; + } + const char *name = argv[0]; + + struct output_config *output = calloc(1, sizeof(struct output_config)); + if (!output) { + return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate output config"); + } + output->x = output->y = output->width = output->height = -1; + output->name = strdup(name); + output->enabled = -1; + output->scale = 1; + + // TODO: atoi doesn't handle invalid numbers + + int i; + for (i = 1; i < argc; ++i) { + const char *command = argv[i]; + + if (strcasecmp(command, "disable") == 0) { + output->enabled = 0; + } else if (strcasecmp(command, "resolution") == 0 || strcasecmp(command, "res") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument."); + goto fail; + } + char *res = argv[i]; + char *x = strchr(res, 'x'); + int width = -1, height = -1; + if (x != NULL) { + // Format is 1234x4321 + *x = '\0'; + width = atoi(res); + height = atoi(x + 1); + *x = 'x'; + } else { + // Format is 1234 4321 + width = atoi(res); + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing resolution argument (height)."); + goto fail; + } + res = argv[i]; + height = atoi(res); + } + output->width = width; + output->height = height; + } else if (strcasecmp(command, "refresh_rate") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing refresh_rate argument."); + goto fail; + } + output->refresh_rate = atof(argv[i]); + } else if (strcasecmp(command, "position") == 0 || strcasecmp(command, "pos") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing position argument."); + goto fail; + } + char *res = argv[i]; + char *c = strchr(res, ','); + int x = -1, y = -1; + if (c != NULL) { + // Format is 1234,4321 + *c = '\0'; + x = atoi(res); + y = atoi(c + 1); + *c = ','; + } else { + // Format is 1234 4321 + x = atoi(res); + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing position argument (y)."); + goto fail; + } + res = argv[i]; + y = atoi(res); + } + output->x = x; + output->y = y; + } else if (strcasecmp(command, "scale") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing scale parameter."); + goto fail; + } + output->scale = atoi(argv[i]); + } else if (strcasecmp(command, "transform") == 0) { + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing transform parameter."); + goto fail; + } + char *value = argv[i]; + if (strcmp(value, "normal") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_NORMAL; + } else if (strcmp(value, "90") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_90; + } else if (strcmp(value, "180") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_180; + } else if (strcmp(value, "270") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_270; + } else if (strcmp(value, "flipped") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_FLIPPED; + } else if (strcmp(value, "flipped-90") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90; + } else if (strcmp(value, "flipped-180") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; + } else if (strcmp(value, "flipped-270") == 0) { + output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270; + } else { + error = cmd_results_new(CMD_INVALID, "output", "Invalid output transform."); + goto fail; + } + } else if (strcasecmp(command, "background") == 0 || strcasecmp(command, "bg") == 0) { + wordexp_t p; + if (++i >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background file or color specification."); + goto fail; + } + if (i + 1 >= argc) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode or `solid_color`."); + goto fail; + } + if (strcasecmp(argv[i + 1], "solid_color") == 0) { + output->background = strdup(argv[argc - 2]); + output->background_option = strdup("solid_color"); + } else { + // argv[i+j]=bg_option + bool valid = false; + char *mode; + size_t j; + for (j = 0; j < (size_t) (argc - i); ++j) { + mode = argv[i + j]; + for (size_t k = 0; k < sizeof(bg_options) / sizeof(char *); ++k) { + if (strcasecmp(mode, bg_options[k]) == 0) { + valid = true; + break; + } + } + if (valid) { + break; + } + } + if (!valid) { + error = cmd_results_new(CMD_INVALID, "output", "Missing background scaling mode."); + goto fail; + } + + char *src = join_args(argv + i, j); + if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { + error = cmd_results_new(CMD_INVALID, "output", "Invalid syntax (%s)", src); + goto fail; + } + free(src); + src = p.we_wordv[0]; + if (config->reading && *src != '/') { + char *conf = strdup(config->current_config); + if (conf) { + char *conf_path = dirname(conf); + src = malloc(strlen(conf_path) + strlen(src) + 2); + if (src) { + sprintf(src, "%s/%s", conf_path, p.we_wordv[0]); + } else { + sway_log(L_ERROR, "Unable to allocate background source"); + } + free(conf); + } else { + sway_log(L_ERROR, "Unable to allocate background source"); + } + } + if (!src || access(src, F_OK) == -1) { + error = cmd_results_new(CMD_INVALID, "output", "Background file unreadable (%s)", src); + wordfree(&p); + goto fail; + } + + output->background = strdup(src); + output->background_option = strdup(mode); + if (src != p.we_wordv[0]) { + free(src); + } + wordfree(&p); + + i += j; + } + } + } + + i = list_seq_find(config->output_configs, output_name_cmp, name); + if (i >= 0) { + // merge existing config + struct output_config *oc = config->output_configs->items[i]; + merge_output_config(oc, output); + free_output_config(output); + output = oc; + } else { + list_add(config->output_configs, output); + } + + sway_log(L_DEBUG, "Config stored for output %s (enabled:%d) (%d x %d @ " + "%d, %d scale %d transform %d refresh_rate %f) (bg %s %s)", + output->name, output->enabled, output->width, + output->height, output->x, output->y, output->scale, + output->transform, output->refresh_rate, + output->background, output->background_option); + + if (output->name) { + // Try to find the output container and apply configuration now. If + // this is during startup then there will be no container and config + // will be applied during normal "new output" event from wlc. + swayc_t *cont = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + cont = root_container.children->items[i]; + if (cont->name && ((strcmp(cont->name, output->name) == 0) || (strcmp(output->name, "*") == 0))) { + apply_output_config(output, cont); + + if (strcmp(output->name, "*") != 0) { + // stop looking if the output config isn't applicable to all outputs + break; + } + } + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + +fail: + free_output_config(output); + return error; +} diff --git a/sway/config/output.c b/sway/config/output.c new file mode 100644 index 00000000..02e18e59 --- /dev/null +++ b/sway/config/output.c @@ -0,0 +1,166 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include "sway/config.h" +#include "sway/output.h" +#include "log.h" + +int output_name_cmp(const void *item, const void *data) { + const struct output_config *output = item; + const char *name = data; + + return strcmp(output->name, name); +} + +void merge_output_config(struct output_config *dst, struct output_config *src) { + if (src->name) { + if (dst->name) { + free(dst->name); + } + dst->name = strdup(src->name); + } + if (src->enabled != -1) { + dst->enabled = src->enabled; + } + if (src->width != -1) { + dst->width = src->width; + } + if (src->height != -1) { + dst->height = src->height; + } + if (src->x != -1) { + dst->x = src->x; + } + if (src->y != -1) { + dst->y = src->y; + } + if (src->scale != -1) { + dst->scale = src->scale; + } + if (src->background) { + if (dst->background) { + free(dst->background); + } + dst->background = strdup(src->background); + } + if (src->background_option) { + if (dst->background_option) { + free(dst->background_option); + } + dst->background_option = strdup(src->background_option); + } +} + +static void set_mode(struct wlr_output *output, int width, int height, + float refresh_rate) { + struct wlr_output_mode *mode, *best = NULL; + int mhz = (int)(refresh_rate * 1000); + wl_list_for_each(mode, &output->modes, link) { + if (mode->width == width && mode->height == height) { + if (mode->refresh == mhz) { + best = mode; + break; + } + best = mode; + } + } + if (!best) { + sway_log(L_ERROR, "Configured mode for %s not available", output->name); + } else { + sway_log(L_DEBUG, "Assigning configured mode to %s", output->name); + wlr_output_set_mode(output, best); + } +} + +void apply_output_config(struct output_config *oc, swayc_t *output) { + assert(output->type == C_OUTPUT); + + if (oc && oc->enabled == 0) { + destroy_output(output); + return; + } + + struct wlr_output *wlr_output = output->sway_output->wlr_output; + if (oc && oc->width > 0 && oc->height > 0) { + set_mode(wlr_output, oc->width, oc->height, oc->refresh_rate); + } + if (oc && oc->scale > 0) { + wlr_output->scale = oc->scale; + } + if (oc && oc->transform != WL_OUTPUT_TRANSFORM_NORMAL) { + wlr_output_transform(wlr_output, oc->transform); + } + + // Find position for it + if (oc && oc->x != -1 && oc->y != -1) { + sway_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); + output->x = oc->x; + output->y = oc->y; + } else { + int x = 0; + for (int i = 0; i < root_container.children->length; ++i) { + swayc_t *c = root_container.children->items[i]; + if (c->type == C_OUTPUT) { + if (c->width + c->x > x) { + x = c->width + c->x; + } + } + } + output->x = x; + } + + if (!oc || !oc->background) { + // Look for a * config for background + int i = list_seq_find(config->output_configs, output_name_cmp, "*"); + if (i >= 0) { + oc = config->output_configs->items[i]; + } else { + oc = NULL; + } + } + + int output_i; + for (output_i = 0; output_i < root_container.children->length; ++output_i) { + if (root_container.children->items[output_i] == output) { + break; + } + } + + if (oc && oc->background) { + // TODO: swaybg + /*if (output->bg_pid != 0) { + terminate_swaybg(output->bg_pid); + } + + sway_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background); + + size_t bufsize = 12; + char output_id[bufsize]; + snprintf(output_id, bufsize, "%d", output_i); + output_id[bufsize-1] = 0; + + char *const cmd[] = { + "swaybg", + output_id, + oc->background, + oc->background_option, + NULL, + }; + + output->bg_pid = fork(); + if (output->bg_pid == 0) { + execvp(cmd[0], cmd); + }*/ + } +} + +void free_output_config(struct output_config *oc) { + if (!oc) { + return; + } + free(oc->name); + free(oc->background); + free(oc->background_option); + free(oc); +} diff --git a/sway/main.c b/sway/main.c index bc843591..8952f997 100644 --- a/sway/main.c +++ b/sway/main.c @@ -404,6 +404,10 @@ int main(int argc, char **argv) { security_sanity_check(); + // TODO: wait for server to be ready + // TODO: consume config->cmd_queue + config->active = true; + if (!terminate_request) { server_run(&server); } diff --git a/sway/meson.build b/sway/meson.build index 84f48137..5ae7fbb3 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -5,7 +5,9 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/output.c', 'config.c', + 'config/output.c', 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index e205fbcf..7720718f 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include "sway/config.h" #include "sway/container.h" #include "sway/layout.h" #include "sway/output.h" @@ -23,6 +25,30 @@ void swayc_descendants_of_type(swayc_t *root, enum swayc_types type, } } +static void update_root_geometry() { + int width = 0; + int height = 0; + swayc_t *child; + int child_width; + int child_height; + + for (int i = 0; i < root_container.children->length; ++i) { + child = root_container.children->items[i]; + child_width = child->width + child->x; + child_height = child->height + child->y; + if (child_width > width) { + width = child_width; + } + + if (child_height > height) { + height = child_height; + } + } + + root_container.width = width; + root_container.height = height; +} + static swayc_t *new_swayc(enum swayc_types type) { // next id starts at 1 because 0 is assigned to root_container in layout.c static size_t next_id = 1; @@ -44,10 +70,33 @@ static swayc_t *new_swayc(enum swayc_types type) { swayc_t *new_output(struct sway_output *sway_output) { struct wlr_box size; - wlr_output_effective_resolution( - sway_output->wlr_output, &size.width, &size.height); + wlr_output_effective_resolution(sway_output->wlr_output, &size.width, + &size.height); const char *name = sway_output->wlr_output->name; + struct output_config *oc = NULL, *all = NULL; + for (int i = 0; i < config->output_configs->length; ++i) { + struct output_config *cur = config->output_configs->items[i]; + if (strcasecmp(name, cur->name) == 0) { + sway_log(L_DEBUG, "Matched output config for %s", name); + oc = cur; + } + if (strcasecmp("*", cur->name) == 0) { + sway_log(L_DEBUG, "Matched wildcard output config for %s", name); + all = cur; + } + + if (oc && all) { + break; + } + } + if (!oc) { + oc = all; + } + if (oc && !oc->enabled) { + return NULL; + } + swayc_t *output = new_swayc(C_OUTPUT); output->sway_output = sway_output; output->name = name ? strdup(name) : NULL; @@ -58,6 +107,8 @@ swayc_t *new_output(struct sway_output *sway_output) { wlr_output_layout_add_auto(root_container.output_layout, sway_output->wlr_output); + apply_output_config(oc, output); + add_child(&root_container, output); // Create workspace @@ -139,6 +190,34 @@ static void free_swayc(swayc_t *cont) { free(cont); } +swayc_t *destroy_output(swayc_t *output) { + if (!sway_assert(output, "null output passed to destroy_output")) { + return NULL; + } + if (output->children->length > 0) { + // TODO save workspaces when there are no outputs. + // TODO also check if there will ever be no outputs except for exiting + // program + if (root_container.children->length > 1) { + int p = root_container.children->items[0] == output; + // Move workspace from this output to another output + while (output->children->length) { + swayc_t *child = output->children->items[0]; + remove_child(child); + add_child(root_container.children->items[p], child); + } + sort_workspaces(root_container.children->items[p]); + // TODO WLR: is this needed anymore? + //update_visibility(root_container.children->items[p]); + arrange_windows(root_container.children->items[p], -1, -1); + } + } + sway_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); + free_swayc(output); + update_root_geometry(); + return &root_container; +} + swayc_t *destroy_view(swayc_t *view) { if (!sway_assert(view, "null view passed to destroy_view")) { return NULL; -- cgit v1.2.3 From 338a0399f8d7c0ebe9cbb989945d8fd646d8d407 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 6 Dec 2017 08:28:46 -0500 Subject: input skeleton --- include/sway/input.h | 18 ++++++++++++++++++ meson.build | 1 + sway/meson.build | 2 ++ sway/server.c | 4 ++++ 4 files changed, 25 insertions(+) create mode 100644 include/sway/input.h (limited to 'sway/meson.build') diff --git a/include/sway/input.h b/include/sway/input.h new file mode 100644 index 00000000..21ed61c5 --- /dev/null +++ b/include/sway/input.h @@ -0,0 +1,18 @@ +#ifndef _SWAY_INPUT_H +#define _SWAY_INPUT_H +#include +#include "sway/server.h" +#include "config.h" +#include "list.h" + +struct sway_input { + list_t *input_devices; +}; + +struct input_config *new_input_config(const char* identifier); + +char* libinput_dev_unique_id(struct libinput_device *dev); + +struct sway_input *sway_input_create(struct sway_server *server); + +#endif diff --git a/meson.build b/meson.build index 8e7b98ed..029aea46 100644 --- a/meson.build +++ b/meson.build @@ -29,6 +29,7 @@ xkbcommon = dependency('xkbcommon') pango = dependency('pango') pixman = dependency('pixman-1') libcap = dependency('libcap') +libinput = dependency('libinput') math = cc.find_library('m') git = find_program('git', required: false) a2x = find_program('a2x', required: false) diff --git a/sway/meson.build b/sway/meson.build index 84f48137..8631b9c3 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -2,6 +2,7 @@ sway_sources = files( 'main.c', 'server.c', 'commands.c', + 'input/input.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', @@ -25,6 +26,7 @@ sway_deps = [ wlroots, libcap, math, + libinput, ] executable( diff --git a/sway/server.c b/sway/server.c index 024d8429..3873e625 100644 --- a/sway/server.c +++ b/sway/server.c @@ -11,6 +11,7 @@ // TODO WLR: make Xwayland optional #include #include "sway/server.h" +#include "sway/input.h" #include "log.h" bool server_init(struct sway_server *server) { @@ -58,6 +59,9 @@ bool server_init(struct sway_server *server) { wlr_backend_destroy(server->backend); return false; } + + server->input = sway_input_create(server); + return true; } -- cgit v1.2.3 From 21ce20885a6a6e9e7178778513b09fea9354c603 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 7 Dec 2017 07:31:49 -0500 Subject: rename input to input-manager --- include/sway/input-manager.h | 19 +++++++++++ include/sway/input.h | 18 ---------- include/sway/server.h | 2 +- sway/input/input-manager.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ sway/input/input.c | 77 ------------------------------------------ sway/meson.build | 2 +- sway/server.c | 4 +-- 7 files changed, 102 insertions(+), 99 deletions(-) create mode 100644 include/sway/input-manager.h delete mode 100644 include/sway/input.h create mode 100644 sway/input/input-manager.c delete mode 100644 sway/input/input.c (limited to 'sway/meson.build') diff --git a/include/sway/input-manager.h b/include/sway/input-manager.h new file mode 100644 index 00000000..a3662f7b --- /dev/null +++ b/include/sway/input-manager.h @@ -0,0 +1,19 @@ +#ifndef _SWAY_INPUT_H +#define _SWAY_INPUT_H +#include +#include "sway/server.h" +#include "config.h" +#include "list.h" + +struct sway_input_manager { + list_t *input_devices; +}; + +struct input_config *new_input_config(const char* identifier); + +char* libinput_dev_unique_id(struct libinput_device *dev); + +struct sway_input_manager *sway_input_manager_create( + struct sway_server *server); + +#endif diff --git a/include/sway/input.h b/include/sway/input.h deleted file mode 100644 index 21ed61c5..00000000 --- a/include/sway/input.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _SWAY_INPUT_H -#define _SWAY_INPUT_H -#include -#include "sway/server.h" -#include "config.h" -#include "list.h" - -struct sway_input { - list_t *input_devices; -}; - -struct input_config *new_input_config(const char* identifier); - -char* libinput_dev_unique_id(struct libinput_device *dev); - -struct sway_input *sway_input_create(struct sway_server *server); - -#endif diff --git a/include/sway/server.h b/include/sway/server.h index 3fa72e84..76a05476 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -22,7 +22,7 @@ struct sway_server { struct wlr_compositor *compositor; struct wlr_data_device_manager *data_device_manager; - struct sway_input *input; + struct sway_input_manager *input; struct wl_listener output_add; struct wl_listener output_remove; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c new file mode 100644 index 00000000..285a68b8 --- /dev/null +++ b/sway/input/input-manager.c @@ -0,0 +1,79 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include "sway/config.h" +#include "sway/input-manager.h" +#include "sway/server.h" +#include "list.h" +#include "log.h" + +struct input_config *current_input_config = NULL; + +struct sway_input_manager *sway_input_manager_create( + struct sway_server *server) { + struct sway_input_manager *input = + calloc(1, sizeof(struct sway_input_manager)); + if (!input) { + return NULL; + } + return input; +} + +struct input_config *new_input_config(const char* identifier) { + struct input_config *input = calloc(1, sizeof(struct input_config)); + if (!input) { + sway_log(L_DEBUG, "Unable to allocate input config"); + return NULL; + } + sway_log(L_DEBUG, "new_input_config(%s)", identifier); + if (!(input->identifier = strdup(identifier))) { + free(input); + sway_log(L_DEBUG, "Unable to allocate input config"); + return NULL; + } + + input->tap = INT_MIN; + input->drag_lock = INT_MIN; + input->dwt = INT_MIN; + input->send_events = INT_MIN; + input->click_method = INT_MIN; + input->middle_emulation = INT_MIN; + input->natural_scroll = INT_MIN; + input->accel_profile = INT_MIN; + input->pointer_accel = FLT_MIN; + input->scroll_method = INT_MIN; + input->left_handed = INT_MIN; + + return input; +} + +char *libinput_dev_unique_id(struct libinput_device *device) { + int vendor = libinput_device_get_id_vendor(device); + int product = libinput_device_get_id_product(device); + char *name = strdup(libinput_device_get_name(device)); + + char *p = name; + for (; *p; ++p) { + if (*p == ' ') { + *p = '_'; + } + } + + sway_log(L_DEBUG, "rewritten name %s", name); + + int len = strlen(name) + sizeof(char) * 6; + char *identifier = malloc(len); + if (!identifier) { + sway_log(L_ERROR, "Unable to allocate unique input device name"); + return NULL; + } + + const char *fmt = "%d:%d:%s"; + snprintf(identifier, len, fmt, vendor, product, name); + free(name); + return identifier; +} diff --git a/sway/input/input.c b/sway/input/input.c deleted file mode 100644 index 02b4995e..00000000 --- a/sway/input/input.c +++ /dev/null @@ -1,77 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include "sway/config.h" -#include "sway/input.h" -#include "sway/server.h" -#include "list.h" -#include "log.h" - -struct input_config *current_input_config = NULL; - -struct sway_input *sway_input_create(struct sway_server *server) { - struct sway_input *input = calloc(1, sizeof(struct sway_input)); - if (!input) { - return NULL; - } - return input; -} - -struct input_config *new_input_config(const char* identifier) { - struct input_config *input = calloc(1, sizeof(struct input_config)); - if (!input) { - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - sway_log(L_DEBUG, "new_input_config(%s)", identifier); - if (!(input->identifier = strdup(identifier))) { - free(input); - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - - input->tap = INT_MIN; - input->drag_lock = INT_MIN; - input->dwt = INT_MIN; - input->send_events = INT_MIN; - input->click_method = INT_MIN; - input->middle_emulation = INT_MIN; - input->natural_scroll = INT_MIN; - input->accel_profile = INT_MIN; - input->pointer_accel = FLT_MIN; - input->scroll_method = INT_MIN; - input->left_handed = INT_MIN; - - return input; -} - -char *libinput_dev_unique_id(struct libinput_device *device) { - int vendor = libinput_device_get_id_vendor(device); - int product = libinput_device_get_id_product(device); - char *name = strdup(libinput_device_get_name(device)); - - char *p = name; - for (; *p; ++p) { - if (*p == ' ') { - *p = '_'; - } - } - - sway_log(L_DEBUG, "rewritten name %s", name); - - int len = strlen(name) + sizeof(char) * 6; - char *identifier = malloc(len); - if (!identifier) { - sway_log(L_ERROR, "Unable to allocate unique input device name"); - return NULL; - } - - const char *fmt = "%d:%d:%s"; - snprintf(identifier, len, fmt, vendor, product, name); - free(name); - return identifier; -} diff --git a/sway/meson.build b/sway/meson.build index 8631b9c3..b5cdbbf2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -2,7 +2,7 @@ sway_sources = files( 'main.c', 'server.c', 'commands.c', - 'input/input.c', + 'input/input-manager.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', diff --git a/sway/server.c b/sway/server.c index 3873e625..174beac6 100644 --- a/sway/server.c +++ b/sway/server.c @@ -11,7 +11,7 @@ // TODO WLR: make Xwayland optional #include #include "sway/server.h" -#include "sway/input.h" +#include "sway/input-manager.h" #include "log.h" bool server_init(struct sway_server *server) { @@ -60,7 +60,7 @@ bool server_init(struct sway_server *server) { return false; } - server->input = sway_input_create(server); + server->input = sway_input_manager_create(server); return true; } -- cgit v1.2.3 From f6f63f60d6c7f9602dd1c07b45eb45a97e5b6f5a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 7 Dec 2017 09:58:32 -0500 Subject: basic input manager and seat --- include/sway/input-manager.h | 9 +++++--- include/sway/seat.h | 20 ++++++++++++++++ sway/input/input-manager.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ sway/input/seat.c | 24 ++++++++++++++++++++ sway/meson.build | 1 + 5 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 include/sway/seat.h create mode 100644 sway/input/seat.c (limited to 'sway/meson.build') diff --git a/include/sway/input-manager.h b/include/sway/input-manager.h index a3662f7b..4c01a043 100644 --- a/include/sway/input-manager.h +++ b/include/sway/input-manager.h @@ -1,12 +1,15 @@ -#ifndef _SWAY_INPUT_H -#define _SWAY_INPUT_H +#ifndef _SWAY_INPUT_MANAGER_H +#define _SWAY_INPUT_MANAGER_H #include #include "sway/server.h" #include "config.h" #include "list.h" struct sway_input_manager { - list_t *input_devices; + struct wl_listener input_add; + struct wl_listener input_remove; + struct sway_server *server; + list_t *seats; }; struct input_config *new_input_config(const char* identifier); diff --git a/include/sway/seat.h b/include/sway/seat.h new file mode 100644 index 00000000..a2b8fe51 --- /dev/null +++ b/include/sway/seat.h @@ -0,0 +1,20 @@ +#ifndef _SWAY_SEAT_H +#define _SWAY_SEAT_H + +#include +#include "sway/input-manager.h" + +struct sway_seat { + struct wlr_seat *seat; +}; + +struct sway_seat *sway_seat_create(struct wl_display *display, + const char *seat_name); + +void sway_seat_add_device(struct sway_seat *seat, + struct wlr_input_device *device); + +void sway_seat_remove_device(struct sway_seat *seat, + struct wlr_input_device *device); + +#endif diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 285a68b8..b5ab8cc1 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -7,12 +7,52 @@ #include #include "sway/config.h" #include "sway/input-manager.h" +#include "sway/seat.h" #include "sway/server.h" #include "list.h" #include "log.h" +static const char *default_seat = "seat0"; + struct input_config *current_input_config = NULL; +static struct sway_seat *input_manager_get_seat( + struct sway_input_manager *input, const char *seat_name) { + struct sway_seat *seat = NULL; + + for (int i = 0; i < input->seats->length; ++i) { + seat = input->seats->items[i]; + if (strcmp(seat->seat->name, seat_name) == 0) { + return seat; + } + } + + seat = sway_seat_create(input->server->wl_display, seat_name); + list_add(input->seats, seat); + + return seat; +} + +static void input_add_notify(struct wl_listener *listener, void *data) { + struct sway_input_manager *input = + wl_container_of(listener, input, input_add); + struct wlr_input_device *device = data; + + // TODO device configuration + struct sway_seat *seat = input_manager_get_seat(input, default_seat); + sway_seat_add_device(seat, device); +} + +static void input_remove_notify(struct wl_listener *listener, void *data) { + struct sway_input_manager *input = + wl_container_of(listener, input, input_remove); + struct wlr_input_device *device = data; + + // TODO device configuration + struct sway_seat *seat = input_manager_get_seat(input, default_seat); + sway_seat_remove_device(seat, device); +} + struct sway_input_manager *sway_input_manager_create( struct sway_server *server) { struct sway_input_manager *input = @@ -20,6 +60,20 @@ struct sway_input_manager *sway_input_manager_create( if (!input) { return NULL; } + // XXX probably don't need the full server + input->server = server; + + input->seats = create_list(); + + // create the default seat + input_manager_get_seat(input, default_seat); + + input->input_add.notify = input_add_notify; + wl_signal_add(&server->backend->events.input_add, &input->input_add); + + input->input_remove.notify = input_remove_notify; + wl_signal_add(&server->backend->events.input_remove, &input->input_remove); + return input; } diff --git a/sway/input/seat.c b/sway/input/seat.c new file mode 100644 index 00000000..f41b6dba --- /dev/null +++ b/sway/input/seat.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/seat.h" +#include "sway/input-manager.h" +#include "log.h" + +struct sway_seat *sway_seat_create(struct wl_display *display, + const char *seat_name) { + struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); + if (!seat) { + return NULL; + } + seat->seat = wlr_seat_create(display, seat_name); + return seat; +} + +void sway_seat_add_device(struct sway_seat *seat, + struct wlr_input_device *device) { + sway_log(L_DEBUG, "input add: %s", device->name); +} + +void sway_seat_remove_device(struct sway_seat *seat, + struct wlr_input_device *device) { + sway_log(L_DEBUG, "input remove: %s", device->name); +} diff --git a/sway/meson.build b/sway/meson.build index b5cdbbf2..cea565d6 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -3,6 +3,7 @@ sway_sources = files( 'server.c', 'commands.c', 'input/input-manager.c', + 'input/seat.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', -- cgit v1.2.3 From ec7fc42a00db8c230ca1a050f0a1f7badc697fa5 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 8 Dec 2017 07:22:26 -0500 Subject: sway cursor --- include/sway/cursor.h | 26 ++++++++++ include/sway/seat.h | 1 + sway/input/cursor.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++ sway/input/seat.c | 52 ++++++++++++++++++++ sway/meson.build | 1 + 5 files changed, 208 insertions(+) create mode 100644 include/sway/cursor.h create mode 100644 sway/input/cursor.c (limited to 'sway/meson.build') diff --git a/include/sway/cursor.h b/include/sway/cursor.h new file mode 100644 index 00000000..647bc8f1 --- /dev/null +++ b/include/sway/cursor.h @@ -0,0 +1,26 @@ +#ifndef _SWAY_CURSOR_H +#define _SWAY_CURSOR_H + +#include "sway/seat.h" + +struct sway_cursor { + struct wlr_cursor *cursor; + + struct wl_listener motion; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener axis; + + struct wl_listener touch_down; + struct wl_listener touch_up; + struct wl_listener touch_motion; + + struct wl_listener tool_axis; + struct wl_listener tool_tip; + + struct wl_listener request_set_cursor; +}; + +struct sway_cursor *sway_cursor_create(struct sway_seat *seat); + +#endif diff --git a/include/sway/seat.h b/include/sway/seat.h index a2b8fe51..2f8ca72e 100644 --- a/include/sway/seat.h +++ b/include/sway/seat.h @@ -6,6 +6,7 @@ struct sway_seat { struct wlr_seat *seat; + struct sway_cursor *cursor; }; struct sway_seat *sway_seat_create(struct wl_display *display, diff --git a/sway/input/cursor.c b/sway/input/cursor.c new file mode 100644 index 00000000..819007d5 --- /dev/null +++ b/sway/input/cursor.c @@ -0,0 +1,128 @@ +#define _XOPEN_SOURCE 700 +#include +#include "sway/cursor.h" +#include "log.h" + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, motion); + struct wlr_event_pointer_motion *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, button); + struct wlr_event_pointer_button *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, axis); + struct wlr_event_pointer_axis *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_down); + struct wlr_event_touch_down *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_up); + struct wlr_event_touch_up *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, touch_motion); + struct wlr_event_touch_motion *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_tool_axis(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_tool_tip(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, tool_tip); + struct wlr_event_tablet_tool_tip *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +static void handle_request_set_cursor(struct wl_listener *listener, + void *data) { + struct sway_cursor *cursor = + wl_container_of(listener, cursor, request_set_cursor); + struct wlr_seat_pointer_request_set_cursor_event *event = data; + sway_log(L_DEBUG, "TODO: handle event: %p", event); +} + +struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { + struct sway_cursor *cursor = calloc(1, sizeof(struct sway_cursor)); + if (!sway_assert(cursor, "could not allocate sway cursor")) { + return NULL; + } + + struct wlr_cursor *wlr_cursor = wlr_cursor_create(); + if (!sway_assert(wlr_cursor, "could not allocate wlr cursor")) { + free(cursor); + return NULL; + } + + // input events + wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); + cursor->motion.notify = handle_cursor_motion; + + wl_signal_add(&wlr_cursor->events.motion_absolute, + &cursor->motion_absolute); + cursor->motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&wlr_cursor->events.button, &cursor->button); + cursor->button.notify = handle_cursor_button; + + wl_signal_add(&wlr_cursor->events.axis, &cursor->axis); + cursor->axis.notify = handle_cursor_axis; + + wl_signal_add(&wlr_cursor->events.touch_down, &cursor->touch_down); + cursor->touch_down.notify = handle_touch_down; + + wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up); + cursor->touch_up.notify = handle_touch_up; + + wl_signal_add(&wlr_cursor->events.touch_motion, + &cursor->touch_motion); + cursor->touch_motion.notify = handle_touch_motion; + + wl_signal_add(&wlr_cursor->events.tablet_tool_axis, + &cursor->tool_axis); + cursor->tool_axis.notify = handle_tool_axis; + + wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); + cursor->tool_tip.notify = handle_tool_tip; + + wl_signal_add(&seat->seat->events.request_set_cursor, + &cursor->request_set_cursor); + cursor->request_set_cursor.notify = handle_request_set_cursor; + + cursor->cursor = wlr_cursor; + + return cursor; +} diff --git a/sway/input/seat.c b/sway/input/seat.c index f41b6dba..459b2ee2 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,5 +1,7 @@ #define _XOPEN_SOURCE 700 +#include #include "sway/seat.h" +#include "sway/cursor.h" #include "sway/input-manager.h" #include "log.h" @@ -9,16 +11,66 @@ struct sway_seat *sway_seat_create(struct wl_display *display, if (!seat) { return NULL; } + seat->seat = wlr_seat_create(display, seat_name); + if (!sway_assert(seat->seat, "could not allocate seat")) { + return NULL; + } + + seat->cursor = sway_cursor_create(seat); + if (!seat->cursor) { + wlr_seat_destroy(seat->seat); + free(seat); + return NULL; + } + + wlr_seat_set_capabilities(seat->seat, + WL_SEAT_CAPABILITY_KEYBOARD | + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_TOUCH); + return seat; } +static void seat_add_pointer(struct sway_seat *seat, + struct wlr_input_device *device) { + // TODO pointer configuration + wlr_cursor_attach_input_device(seat->cursor->cursor, device); +} + void sway_seat_add_device(struct sway_seat *seat, struct wlr_input_device *device) { sway_log(L_DEBUG, "input add: %s", device->name); + switch (device->type) { + case WLR_INPUT_DEVICE_POINTER: + seat_add_pointer(seat, device); + break; + case WLR_INPUT_DEVICE_KEYBOARD: + case WLR_INPUT_DEVICE_TOUCH: + case WLR_INPUT_DEVICE_TABLET_PAD: + case WLR_INPUT_DEVICE_TABLET_TOOL: + sway_log(L_DEBUG, "TODO: add other devices"); + break; + } +} + +static void seat_remove_pointer(struct sway_seat *seat, + struct wlr_input_device *device) { + // TODO } void sway_seat_remove_device(struct sway_seat *seat, struct wlr_input_device *device) { sway_log(L_DEBUG, "input remove: %s", device->name); + switch (device->type) { + case WLR_INPUT_DEVICE_POINTER: + seat_remove_pointer(seat, device); + break; + case WLR_INPUT_DEVICE_KEYBOARD: + case WLR_INPUT_DEVICE_TOUCH: + case WLR_INPUT_DEVICE_TABLET_PAD: + case WLR_INPUT_DEVICE_TABLET_TOOL: + sway_log(L_DEBUG, "TODO: remove other devices"); + break; + } } diff --git a/sway/meson.build b/sway/meson.build index cea565d6..059204b2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -4,6 +4,7 @@ sway_sources = files( 'commands.c', 'input/input-manager.c', 'input/seat.c', + 'input/cursor.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', -- cgit v1.2.3 From 609f63934ab3eb925741450aa7f78db1c11bdd37 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 10 Dec 2017 13:59:04 -0500 Subject: basic keyboard --- include/sway/input/keyboard.h | 13 ++++++++++ include/sway/input/seat.h | 2 ++ sway/input/keyboard.c | 57 +++++++++++++++++++++++++++++++++++++++++++ sway/input/seat.c | 14 ++++++++++- sway/meson.build | 2 ++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 include/sway/input/keyboard.h create mode 100644 sway/input/keyboard.c (limited to 'sway/meson.build') diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h new file mode 100644 index 00000000..2e04065c --- /dev/null +++ b/include/sway/input/keyboard.h @@ -0,0 +1,13 @@ +#include "sway/input/seat.h" + +struct sway_keyboard { + struct sway_seat *seat; + struct wlr_input_device *device; + struct wl_list link; // sway_seat::keyboards + + struct wl_listener keyboard_key; + struct wl_listener keyboard_modifiers; +}; + +struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, + struct wlr_input_device *device); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 964c0f7b..a0c6ab07 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -10,6 +10,8 @@ struct sway_seat { struct sway_input_manager *input; swayc_t *focus; + struct wl_list keyboards; + struct wl_listener focus_destroy; }; diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c new file mode 100644 index 00000000..59f81e62 --- /dev/null +++ b/sway/input/keyboard.c @@ -0,0 +1,57 @@ +#include "sway/input/seat.h" +#include "sway/input/keyboard.h" +#include "log.h" + +static void handle_keyboard_key(struct wl_listener *listener, void *data) { + struct sway_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_key); + struct wlr_event_keyboard_key *event = data; + wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); + wlr_seat_keyboard_notify_key(keyboard->seat->seat, event->time_msec, + event->keycode, event->state); +} + +static void handle_keyboard_modifiers(struct wl_listener *listener, + void *data) { + struct sway_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_modifiers); + wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); + wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat); +} + +struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, + struct wlr_input_device *device) { + struct sway_keyboard *keyboard = + calloc(1, sizeof(struct sway_keyboard)); + if (!sway_assert(keyboard, "could not allocate sway keyboard")) { + return NULL; + } + + keyboard->device = device; + keyboard->seat = seat; + + // TODO keyboard config + struct xkb_rule_names rules; + memset(&rules, 0, sizeof(rules)); + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!sway_assert(context, "cannot create XKB context")) { + return NULL; + } + + wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, + &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + xkb_context_unref(context); + + wl_signal_add(&device->keyboard->events.key, &keyboard->keyboard_key); + keyboard->keyboard_key.notify = handle_keyboard_key; + + wl_signal_add(&device->keyboard->events.modifiers, &keyboard->keyboard_modifiers); + keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; + + return keyboard; +} diff --git a/sway/input/seat.c b/sway/input/seat.c index b3d36681..0a5329c8 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -4,6 +4,7 @@ #include "sway/input/seat.h" #include "sway/input/cursor.h" #include "sway/input/input-manager.h" +#include "sway/input/keyboard.h" #include "sway/output.h" #include "sway/view.h" #include "log.h" @@ -36,6 +37,8 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, sway_seat_configure_xcursor(seat); + wl_list_init(&seat->keyboards); + return seat; } @@ -45,6 +48,13 @@ static void seat_add_pointer(struct sway_seat *seat, wlr_cursor_attach_input_device(seat->cursor->cursor, device); } +static void seat_add_keyboard(struct sway_seat *seat, + struct wlr_input_device *device) { + struct sway_keyboard *keyboard = sway_keyboard_create(seat, device); + wl_list_insert(&seat->keyboards, &keyboard->link); + wlr_seat_set_keyboard(seat->seat, device); +} + void sway_seat_add_device(struct sway_seat *seat, struct wlr_input_device *device) { sway_log(L_DEBUG, "input add: %s", device->name); @@ -53,6 +63,8 @@ void sway_seat_add_device(struct sway_seat *seat, seat_add_pointer(seat, device); break; case WLR_INPUT_DEVICE_KEYBOARD: + seat_add_keyboard(seat, device); + break; case WLR_INPUT_DEVICE_TOUCH: case WLR_INPUT_DEVICE_TABLET_PAD: case WLR_INPUT_DEVICE_TABLET_TOOL: @@ -138,7 +150,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { view->iface.set_activated(view, true); wl_signal_add(&container->events.destroy, &seat->focus_destroy); seat->focus_destroy.notify = handle_focus_destroy; - // TODO give keyboard focus + wlr_seat_keyboard_notify_enter(seat->seat, view->surface); } seat->focus = container; diff --git a/sway/meson.build b/sway/meson.build index 18955693..79201f3a 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -5,6 +5,7 @@ sway_sources = files( 'input/input-manager.c', 'input/seat.c', 'input/cursor.c', + 'input/keyboard.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', @@ -30,6 +31,7 @@ sway_deps = [ libcap, math, libinput, + xkbcommon, ] executable( -- cgit v1.2.3 From 462a451328a1d6f0b17d34b431d6bf3dec87c1ba Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 11 Dec 2017 04:17:14 -0500 Subject: input config --- include/sway/commands.h | 4 ++ include/sway/input/input-manager.h | 2 + sway/commands.c | 90 ++++++++++++++++++++++++---------- sway/commands/input.c | 55 +++++++++++++++++++++ sway/commands/input/accel_profile.c | 27 ++++++++++ sway/commands/input/click_method.c | 30 ++++++++++++ sway/commands/input/drag_lock.c | 26 ++++++++++ sway/commands/input/dwt.c | 26 ++++++++++ sway/commands/input/events.c | 30 ++++++++++++ sway/commands/input/left_handed.c | 26 ++++++++++ sway/commands/input/middle_emulation.c | 26 ++++++++++ sway/commands/input/natural_scroll.c | 26 ++++++++++ sway/commands/input/pointer_accel.c | 24 +++++++++ sway/commands/input/scroll_method.c | 30 ++++++++++++ sway/commands/input/tap.c | 29 +++++++++++ sway/config.c | 53 ++++++++++++++++++++ sway/meson.build | 12 +++++ 17 files changed, 490 insertions(+), 26 deletions(-) create mode 100644 sway/commands/input.c create mode 100644 sway/commands/input/accel_profile.c create mode 100644 sway/commands/input/click_method.c create mode 100644 sway/commands/input/drag_lock.c create mode 100644 sway/commands/input/dwt.c create mode 100644 sway/commands/input/events.c create mode 100644 sway/commands/input/left_handed.c create mode 100644 sway/commands/input/middle_emulation.c create mode 100644 sway/commands/input/natural_scroll.c create mode 100644 sway/commands/input/pointer_accel.c create mode 100644 sway/commands/input/scroll_method.c create mode 100644 sway/commands/input/tap.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index b1f0423d..138e3c29 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -1,6 +1,8 @@ #ifndef _SWAY_COMMANDS_H #define _SWAY_COMMANDS_H +#include "config.h" + /** * Indicates the result of a command's execution. */ @@ -39,6 +41,8 @@ enum expected_args { EXPECTED_EQUAL_TO }; +void input_cmd_apply(struct input_config *input); + struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 9548c170..78bc161f 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -5,6 +5,8 @@ #include "sway/config.h" #include "list.h" +extern struct input_config *current_input_config; + struct sway_input_manager { struct wl_listener input_add; struct wl_listener input_remove; diff --git a/sway/commands.c b/sway/commands.c index 05a66a7f..7710c6ab 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -9,6 +9,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/security.h" +#include "sway/input/input-manager.h" #include "stringop.h" #include "log.h" @@ -56,6 +57,44 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type return error; } +void input_cmd_apply(struct input_config *input) { + int i; + i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); + if (i >= 0) { + // merge existing config + struct input_config *ic = config->input_configs->items[i]; + merge_input_config(ic, input); + free_input_config(input); + input = ic; + } else { + list_add(config->input_configs, input); + } + + current_input_config = input; + + if (input->identifier) { + // Try to find the input device and apply configuration now. If + // this is during startup then there will be no container and config + // will be applied during normal "new input" event from wlc. + /* TODO WLR + struct libinput_device *device = NULL; + for (int i = 0; i < input_devices->length; ++i) { + device = input_devices->items[i]; + char* dev_identifier = libinput_dev_unique_id(device); + if (!dev_identifier) { + break; + } + int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0; + free(dev_identifier); + if (match) { + apply_input_config(input, device); + break; + } + } + */ + } +} + /** * Check and add color to buffer. * @@ -96,6 +135,7 @@ static struct cmd_handler handlers[] = { { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, { "include", cmd_include }, + { "input", cmd_input }, }; static int handler_compare(const void *_a, const void *_b) { @@ -104,37 +144,35 @@ static int handler_compare(const void *_a, const void *_b) { return strcasecmp(a->command, b->command); } +static struct cmd_handler input_handlers[] = { + { "accel_profile", input_cmd_accel_profile }, + { "click_method", input_cmd_click_method }, + { "drag_lock", input_cmd_drag_lock }, + { "dwt", input_cmd_dwt }, + { "events", input_cmd_events }, + { "left_handed", input_cmd_left_handed }, + { "middle_emulation", input_cmd_middle_emulation }, + { "natural_scroll", input_cmd_natural_scroll }, + { "pointer_accel", input_cmd_pointer_accel }, + { "scroll_method", input_cmd_scroll_method }, + { "tap", input_cmd_tap }, +}; + static struct cmd_handler *find_handler(char *line, enum cmd_status block) { struct cmd_handler d = { .command=line }; struct cmd_handler *res = NULL; sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); - /* TODO - if (block == CMD_BLOCK_BAR) { - res = bsearch(&d, bar_handlers, - sizeof(bar_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_BAR_COLORS){ - res = bsearch(&d, bar_colors_handlers, - sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_INPUT) { + + if (block == CMD_BLOCK_INPUT) { res = bsearch(&d, input_handlers, - sizeof(input_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_IPC) { - res = bsearch(&d, ipc_handlers, - sizeof(ipc_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_IPC_EVENTS) { - res = bsearch(&d, ipc_event_handlers, - sizeof(ipc_event_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); + sizeof(input_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); } else { - */ res = bsearch(&d, handlers, - sizeof(handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - //} + sizeof(handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } + return res; } @@ -238,8 +276,8 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) { argv[i] = do_var_replacement(argv[i]); unescape_string(argv[i]); } - /* Strip quotes for first argument. - * TODO This part needs to be handled much better */ + // Strip quotes for first argument. + // TODO This part needs to be handled much better if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { strip_quotes(argv[1]); } diff --git a/sway/commands/input.c b/sway/commands/input.c new file mode 100644 index 00000000..5ca9c2e6 --- /dev/null +++ b/sway/commands/input.c @@ -0,0 +1,55 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *cmd_input(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (config->reading && strcmp("{", argv[1]) == 0) { + current_input_config = new_input_config(argv[0]); + sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier); + return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); + } + + if (argc > 2) { + int argc_new = argc-2; + char **argv_new = argv+2; + + struct cmd_results *res; + current_input_config = new_input_config(argv[0]); + if (strcasecmp("accel_profile", argv[1]) == 0) { + res = input_cmd_accel_profile(argc_new, argv_new); + } else if (strcasecmp("click_method", argv[1]) == 0) { + res = input_cmd_click_method(argc_new, argv_new); + } else if (strcasecmp("drag_lock", argv[1]) == 0) { + res = input_cmd_drag_lock(argc_new, argv_new); + } else if (strcasecmp("dwt", argv[1]) == 0) { + res = input_cmd_dwt(argc_new, argv_new); + } else if (strcasecmp("events", argv[1]) == 0) { + res = input_cmd_events(argc_new, argv_new); + } else if (strcasecmp("left_handed", argv[1]) == 0) { + res = input_cmd_left_handed(argc_new, argv_new); + } else if (strcasecmp("middle_emulation", argv[1]) == 0) { + res = input_cmd_middle_emulation(argc_new, argv_new); + } else if (strcasecmp("natural_scroll", argv[1]) == 0) { + res = input_cmd_natural_scroll(argc_new, argv_new); + } else if (strcasecmp("pointer_accel", argv[1]) == 0) { + res = input_cmd_pointer_accel(argc_new, argv_new); + } else if (strcasecmp("scroll_method", argv[1]) == 0) { + res = input_cmd_scroll_method(argc_new, argv_new); + } else if (strcasecmp("tap", argv[1]) == 0) { + res = input_cmd_tap(argc_new, argv_new); + } else { + res = cmd_results_new(CMD_INVALID, "input ", "Unknown command %s", argv[1]); + } + current_input_config = NULL; + return res; + } + + return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); +} diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c new file mode 100644 index 00000000..13ded431 --- /dev/null +++ b/sway/commands/input/accel_profile.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_accel_profile(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "accel_profile", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "adaptive") == 0) { + new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; + } else if (strcasecmp(argv[0], "flat") == 0) { + new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; + } else { + return cmd_results_new(CMD_INVALID, "accel_profile", + "Expected 'accel_profile '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c new file mode 100644 index 00000000..40f075ce --- /dev/null +++ b/sway/commands/input/click_method.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_click_method(int argc, char **argv) { + sway_log(L_DEBUG, "click_method for device: %d %s", current_input_config==NULL, current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "click_method", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "none") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; + } else if (strcasecmp(argv[0], "button_areas") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + } else if (strcasecmp(argv[0], "clickfinger") == 0) { + new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + } else { + return cmd_results_new(CMD_INVALID, "click_method", "Expected 'click_method +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "drag_lock", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "drag_lock", "Expected 'drag_lock '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c new file mode 100644 index 00000000..f3cbf252 --- /dev/null +++ b/sway/commands/input/dwt.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_dwt(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "dwt", "Expected 'dwt '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c new file mode 100644 index 00000000..4b2fdff5 --- /dev/null +++ b/sway/commands/input/events.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_events(int argc, char **argv) { + sway_log(L_DEBUG, "events for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "events", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; + } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { + new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; + } else { + return cmd_results_new(CMD_INVALID, "events", "Expected 'events '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c new file mode 100644 index 00000000..715df2a1 --- /dev/null +++ b/sway/commands/input/left_handed.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_left_handed(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "left_handed", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->left_handed = 1; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->left_handed = 0; + } else { + return cmd_results_new(CMD_INVALID, "left_handed", "Expected 'left_handed '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c new file mode 100644 index 00000000..d31ce950 --- /dev/null +++ b/sway/commands/input/middle_emulation.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "middle_emulation", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "middle_emulation", "Expected 'middle_emulation '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c new file mode 100644 index 00000000..9d1dc506 --- /dev/null +++ b/sway/commands/input/natural_scroll.c @@ -0,0 +1,26 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "natural_scoll", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->natural_scroll = 1; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->natural_scroll = 0; + } else { + return cmd_results_new(CMD_INVALID, "natural_scroll", "Expected 'natural_scroll '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c new file mode 100644 index 00000000..87fb5cff --- /dev/null +++ b/sway/commands/input/pointer_accel.c @@ -0,0 +1,24 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "pointer_accel", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + float pointer_accel = atof(argv[0]); + if (pointer_accel < -1 || pointer_accel > 1) { + return cmd_results_new(CMD_INVALID, "pointer_accel", "Input out of range [-1, 1]"); + } + new_config->pointer_accel = pointer_accel; + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c new file mode 100644 index 00000000..98873938 --- /dev/null +++ b/sway/commands/input/scroll_method.c @@ -0,0 +1,30 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_scroll_method(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "scroll_method", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "none") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; + } else if (strcasecmp(argv[0], "two_finger") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; + } else if (strcasecmp(argv[0], "edge") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; + } else if (strcasecmp(argv[0], "on_button_down") == 0) { + new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; + } else { + return cmd_results_new(CMD_INVALID, "scroll_method", "Expected 'scroll_method '"); + } + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c new file mode 100644 index 00000000..1109466f --- /dev/null +++ b/sway/commands/input/tap.c @@ -0,0 +1,29 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_tap(int argc, char **argv) { + sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); + } + struct input_config *new_config = new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "enabled") == 0) { + new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; + } else if (strcasecmp(argv[0], "disabled") == 0) { + new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; + } else { + return cmd_results_new(CMD_INVALID, "tap", "Expected 'tap '"); + } + + sway_log(L_DEBUG, "apply-tap for device: %s", current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 61131845..ec8e89b4 100644 --- a/sway/config.c +++ b/sway/config.c @@ -226,6 +226,59 @@ static int qstrcmp(const void* a, const void* b) { return strcmp(*((char**) a), *((char**) b)); } +void merge_input_config(struct input_config *dst, struct input_config *src) { + if (src->identifier) { + if (dst->identifier) { + free(dst->identifier); + } + dst->identifier = strdup(src->identifier); + } + if (src->accel_profile != INT_MIN) { + dst->accel_profile = src->accel_profile; + } + if (src->click_method != INT_MIN) { + dst->click_method = src->click_method; + } + if (src->drag_lock != INT_MIN) { + dst->drag_lock = src->drag_lock; + } + if (src->dwt != INT_MIN) { + dst->dwt = src->dwt; + } + if (src->middle_emulation != INT_MIN) { + dst->middle_emulation = src->middle_emulation; + } + if (src->natural_scroll != INT_MIN) { + dst->natural_scroll = src->natural_scroll; + } + if (src->pointer_accel != FLT_MIN) { + dst->pointer_accel = src->pointer_accel; + } + if (src->scroll_method != INT_MIN) { + dst->scroll_method = src->scroll_method; + } + if (src->send_events != INT_MIN) { + dst->send_events = src->send_events; + } + if (src->tap != INT_MIN) { + dst->tap = src->tap; + } +} + +void free_input_config(struct input_config *ic) { + if (!ic) { + return; + } + free(ic->identifier); + free(ic); +} + +int input_identifier_cmp(const void *item, const void *data) { + const struct input_config *ic = item; + const char *identifier = data; + return strcmp(ic->identifier, identifier); +} + bool load_main_config(const char *file, bool is_active) { char *path; if (file != NULL) { diff --git a/sway/meson.build b/sway/meson.build index 79201f3a..aa3dd2a7 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -10,6 +10,18 @@ sway_sources = files( 'commands/exec.c', 'commands/exec_always.c', 'commands/include.c', + 'commands/input.c', + 'commands/input/accel_profile.c', + 'commands/input/click_method.c', + 'commands/input/drag_lock.c', + 'commands/input/dwt.c', + 'commands/input/events.c', + 'commands/input/left_handed.c', + 'commands/input/middle_emulation.c', + 'commands/input/natural_scroll.c', + 'commands/input/pointer_accel.c', + 'commands/input/scroll_method.c', + 'commands/input/tap.c', 'config.c', 'ipc-json.c', 'ipc-server.c', -- cgit v1.2.3 From c173d30b9203520c274f34eb72fc787aa33ca211 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 12 Dec 2017 10:55:20 -0500 Subject: seat configuration --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands.c | 2 ++ sway/commands/input/seat.c | 28 ++++++++++++++++++++++++++++ sway/config.c | 1 + sway/input/input-manager.c | 11 +++++++---- sway/meson.build | 1 + 7 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 sway/commands/input/seat.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 138e3c29..75340e03 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -180,6 +180,7 @@ sway_cmd bar_colors_cmd_statusline; sway_cmd bar_colors_cmd_focused_statusline; sway_cmd bar_colors_cmd_urgent_workspace; +sway_cmd input_cmd_seat; sway_cmd input_cmd_accel_profile; sway_cmd input_cmd_click_method; sway_cmd input_cmd_drag_lock; diff --git a/include/sway/config.h b/include/sway/config.h index d80f5a39..9fcecfd6 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -69,6 +69,7 @@ struct input_config { bool capturable; struct wlr_box region; + char *seat; }; /** diff --git a/sway/commands.c b/sway/commands.c index 57f76ea9..6645436a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -123,6 +123,7 @@ static int handler_compare(const void *_a, const void *_b) { return strcasecmp(a->command, b->command); } +// must be in order for the bsearch static struct cmd_handler input_handlers[] = { { "accel_profile", input_cmd_accel_profile }, { "click_method", input_cmd_click_method }, @@ -134,6 +135,7 @@ static struct cmd_handler input_handlers[] = { { "natural_scroll", input_cmd_natural_scroll }, { "pointer_accel", input_cmd_pointer_accel }, { "scroll_method", input_cmd_scroll_method }, + { "seat", input_cmd_seat }, { "tap", input_cmd_tap }, }; diff --git a/sway/commands/input/seat.c b/sway/commands/input/seat.c new file mode 100644 index 00000000..9d86ac0e --- /dev/null +++ b/sway/commands/input/seat.c @@ -0,0 +1,28 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_seat(int argc, char **argv) { + sway_log(L_DEBUG, "seat for device: %d %s", + current_input_config==NULL, current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "seat", + "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + // TODO validate seat name + free(new_config->seat); + new_config->seat = strdup(argv[0]); + + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 4bc74ee0..b77b8b4b 100644 --- a/sway/config.c +++ b/sway/config.c @@ -300,6 +300,7 @@ void free_input_config(struct input_config *ic) { return; } free(ic->identifier); + free(ic->seat); free(ic); } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index b7f5615c..b07a733e 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -104,7 +104,9 @@ static void input_add_notify(struct wl_listener *listener, void *data) { } } - struct sway_seat *seat = input_manager_get_seat(input, default_seat); + const char *seat_name = + (sway_device->config ? sway_device->config->seat : default_seat); + struct sway_seat *seat = input_manager_get_seat(input, seat_name); sway_seat_add_device(seat, sway_device); } @@ -176,9 +178,9 @@ void sway_input_manager_set_focus(struct sway_input_manager *input, } void sway_input_manager_apply_config(struct sway_input_manager *input, - struct input_config *config) { + struct input_config *input_config) { struct sway_input_device *sway_device = - input_sway_device_from_config(input, config); + input_sway_device_from_config(input, input_config); if (!sway_device) { return; } @@ -188,7 +190,8 @@ void sway_input_manager_apply_config(struct sway_input_manager *input, sway_seat_remove_device(seat, sway_device); } - seat = input_manager_get_seat(input, default_seat); + const char *seat_name = (input_config->seat ? input_config->seat : default_seat); + seat = input_manager_get_seat(input, seat_name); sway_seat_add_device(seat, sway_device); } diff --git a/sway/meson.build b/sway/meson.build index aa3dd2a7..fad1f88c 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -11,6 +11,7 @@ sway_sources = files( 'commands/exec_always.c', 'commands/include.c', 'commands/input.c', + 'commands/input/seat.c', 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', -- cgit v1.2.3 From 92fef27eaa0b52c9d37bdabff14ae21cd6660f46 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 14 Dec 2017 11:11:56 -0500 Subject: basic configuration --- include/sway/commands.h | 5 ++ include/sway/config.h | 27 +++++- include/sway/input/input-manager.h | 9 +- include/sway/input/keyboard.h | 9 +- include/sway/input/seat.h | 20 ++++- sway/commands.c | 32 +++++++- sway/commands/input/seat.c | 28 ------- sway/commands/seat.c | 35 ++++++++ sway/commands/seat/attach.c | 26 ++++++ sway/config.c | 144 ++++++++++++++++++++++++++++++-- sway/input/cursor.c | 8 +- sway/input/input-manager.c | 139 ++++++++++++++++++++++--------- sway/input/keyboard.c | 51 ++++++++---- sway/input/seat.c | 163 +++++++++++++++++++++++-------------- sway/meson.build | 3 +- 15 files changed, 534 insertions(+), 165 deletions(-) delete mode 100644 sway/commands/input/seat.c create mode 100644 sway/commands/seat.c create mode 100644 sway/commands/seat/attach.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 75340e03..ce74e1ed 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -17,6 +17,7 @@ enum cmd_status { CMD_BLOCK_BAR, CMD_BLOCK_BAR_COLORS, CMD_BLOCK_INPUT, + CMD_BLOCK_SEAT, CMD_BLOCK_COMMANDS, CMD_BLOCK_IPC, CMD_BLOCK_IPC_EVENTS, @@ -42,6 +43,7 @@ enum expected_args { }; void input_cmd_apply(struct input_config *input); +void seat_cmd_apply(struct seat_config *seat); struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); @@ -111,6 +113,7 @@ sway_cmd cmd_gaps; sway_cmd cmd_hide_edge_borders; sway_cmd cmd_include; sway_cmd cmd_input; +sway_cmd cmd_seat; sway_cmd cmd_ipc; sway_cmd cmd_kill; sway_cmd cmd_layout; @@ -193,6 +196,8 @@ sway_cmd input_cmd_pointer_accel; sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; +sway_cmd seat_cmd_attach; + sway_cmd cmd_ipc_cmd; sway_cmd cmd_ipc_events; sway_cmd cmd_ipc_event_cmd; diff --git a/include/sway/config.h b/include/sway/config.h index 9fcecfd6..5df5d61e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -69,7 +69,22 @@ struct input_config { bool capturable; struct wlr_box region; - char *seat; +}; + +/** + * Options for misc device configurations that happen in the seat block + */ +struct seat_attachment_config { + char *identifier; + // TODO other things are configured here for some reason +}; + +/** + * Options for multiseat and other misc device configurations + */ +struct seat_config { + char *name; + list_t *attachments; // list of seat_attachment configs }; /** @@ -260,6 +275,7 @@ struct sway_config { list_t *pid_workspaces; list_t *output_configs; list_t *input_configs; + list_t *seat_configs; list_t *criteria; list_t *no_focus; list_t *active_bar_modifiers; @@ -358,9 +374,16 @@ struct cmd_results *check_security_config(); int input_identifier_cmp(const void *item, const void *data); struct input_config *new_input_config(const char* identifier); void merge_input_config(struct input_config *dst, struct input_config *src); -void apply_input_config(struct input_config *ic, struct libinput_device *dev); void free_input_config(struct input_config *ic); +int seat_name_cmp(const void *item, const void *data); +struct seat_config *new_seat_config(const char* name); +void merge_seat_config(struct seat_config *dst, struct seat_config *src); +void free_seat_config(struct seat_config *ic); +struct seat_attachment_config *seat_attachment_config_new(); +struct seat_attachment_config *seat_config_get_attachment( + struct seat_config *seat_config, char *identifier); + int output_name_cmp(const void *item, const void *data); void merge_output_config(struct output_config *dst, struct output_config *src); /** Sets up a WLC output handle based on a given output_config. diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 7d7c463f..cdcffab6 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -6,6 +6,7 @@ #include "list.h" extern struct input_config *current_input_config; +extern struct seat_config *current_seat_config; /** * The global singleton input manager @@ -17,7 +18,6 @@ struct sway_input_device { char *identifier; struct wlr_input_device *wlr_device; struct input_config *config; - struct sway_keyboard *keyboard; // managed by the seat struct wl_list link; }; @@ -40,7 +40,10 @@ void sway_input_manager_set_focus(struct sway_input_manager *input, void sway_input_manager_configure_xcursor(struct sway_input_manager *input); -void sway_input_manager_apply_config(struct sway_input_manager *input, - struct input_config *config); +void sway_input_manager_apply_input_config(struct sway_input_manager *input, + struct input_config *input_config); + +void sway_input_manager_apply_seat_config(struct sway_input_manager *input, + struct seat_config *seat_config); #endif diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 881805b4..89cde3fa 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -1,15 +1,18 @@ #include "sway/input/seat.h" struct sway_keyboard { - struct sway_seat *seat; - struct sway_input_device *device; + struct sway_seat_device *seat_device; struct wl_list link; // sway_seat::keyboards + struct xkb_keymap *keymap; + struct wl_listener keyboard_key; struct wl_listener keyboard_modifiers; }; struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, - struct sway_input_device *device); + struct sway_seat_device *device); + +void sway_keyboard_configure(struct sway_keyboard *keyboard); void sway_keyboard_destroy(struct sway_keyboard *keyboard); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index bd94a357..db69f83e 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -4,16 +4,25 @@ #include #include "sway/input/input-manager.h" +struct sway_seat_device { + struct sway_seat *sway_seat; + struct sway_input_device *input_device; + struct sway_keyboard *keyboard; + struct seat_attachment_config *attachment_config; + struct wl_list link; // sway_seat::devices +}; + struct sway_seat { - struct wlr_seat *seat; + struct wlr_seat *wlr_seat; + struct seat_config *config; struct sway_cursor *cursor; struct sway_input_manager *input; swayc_t *focus; - list_t *devices; - struct wl_listener focus_destroy; + struct wl_list devices; // sway_seat_device::link + struct wl_list link; // input_manager::seats }; @@ -23,6 +32,9 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, void sway_seat_add_device(struct sway_seat *seat, struct sway_input_device *device); +void sway_seat_configure_device(struct sway_seat *seat, + struct sway_input_device *device); + void sway_seat_remove_device(struct sway_seat *seat, struct sway_input_device *device); @@ -30,4 +42,6 @@ void sway_seat_configure_xcursor(struct sway_seat *seat); void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container); +void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); + #endif diff --git a/sway/commands.c b/sway/commands.c index 6645436a..e003e06d 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -71,7 +71,24 @@ void input_cmd_apply(struct input_config *input) { } current_input_config = input; - sway_input_manager_apply_config(input_manager, input); + sway_input_manager_apply_input_config(input_manager, input); +} + +void seat_cmd_apply(struct seat_config *seat) { + int i; + i = list_seq_find(config->seat_configs, seat_name_cmp, seat->name); + if (i >= 0) { + // merge existing config + struct seat_config *sc = config->seat_configs->items[i]; + merge_seat_config(sc, seat); + free_seat_config(seat); + seat = sc; + } else { + list_add(config->seat_configs, seat); + } + + current_seat_config = seat; + sway_input_manager_apply_seat_config(input_manager, seat); } /** @@ -115,6 +132,7 @@ static struct cmd_handler handlers[] = { { "exit", cmd_exit }, { "include", cmd_include }, { "input", cmd_input }, + { "seat", cmd_seat }, }; static int handler_compare(const void *_a, const void *_b) { @@ -135,19 +153,27 @@ static struct cmd_handler input_handlers[] = { { "natural_scroll", input_cmd_natural_scroll }, { "pointer_accel", input_cmd_pointer_accel }, { "scroll_method", input_cmd_scroll_method }, - { "seat", input_cmd_seat }, { "tap", input_cmd_tap }, }; +// must be in order for the bsearch +static struct cmd_handler seat_handlers[] = { + { "attach", seat_cmd_attach }, +}; + static struct cmd_handler *find_handler(char *line, enum cmd_status block) { struct cmd_handler d = { .command=line }; struct cmd_handler *res = NULL; - sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); + sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); if (block == CMD_BLOCK_INPUT) { res = bsearch(&d, input_handlers, sizeof(input_handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_SEAT) { + res = bsearch(&d, seat_handlers, + sizeof(seat_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); } else { res = bsearch(&d, handlers, sizeof(handlers) / sizeof(struct cmd_handler), diff --git a/sway/commands/input/seat.c b/sway/commands/input/seat.c deleted file mode 100644 index 9d86ac0e..00000000 --- a/sway/commands/input/seat.c +++ /dev/null @@ -1,28 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include "sway/commands.h" -#include "sway/input/input-manager.h" -#include "log.h" - -struct cmd_results *input_cmd_seat(int argc, char **argv) { - sway_log(L_DEBUG, "seat for device: %d %s", - current_input_config==NULL, current_input_config->identifier); - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 1))) { - return error; - } - if (!current_input_config) { - return cmd_results_new(CMD_FAILURE, "seat", - "No input device defined."); - } - struct input_config *new_config = - new_input_config(current_input_config->identifier); - - // TODO validate seat name - free(new_config->seat); - new_config->seat = strdup(argv[0]); - - input_cmd_apply(new_config); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); -} diff --git a/sway/commands/seat.c b/sway/commands/seat.c new file mode 100644 index 00000000..4f9e259b --- /dev/null +++ b/sway/commands/seat.c @@ -0,0 +1,35 @@ +#include +#include +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *cmd_seat(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (config->reading && strcmp("{", argv[1]) == 0) { + current_seat_config = new_seat_config(argv[0]); + sway_log(L_DEBUG, "entering seat block: %s", current_seat_config->name); + return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); + } + + if (argc > 2) { + int argc_new = argc-2; + char **argv_new = argv+2; + + struct cmd_results *res; + current_seat_config = new_seat_config(argv[0]); + if (strcasecmp("attach", argv[1]) == 0) { + res = seat_cmd_attach(argc_new, argv_new); + } else { + res = cmd_results_new(CMD_INVALID, "seat ", "Unknown command %s", argv[1]); + } + current_seat_config = NULL; + return res; + } + + return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); +} diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c new file mode 100644 index 00000000..996c1bda --- /dev/null +++ b/sway/commands/seat/attach.c @@ -0,0 +1,26 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include "sway/input/input-manager.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *seat_cmd_attach(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_seat_config) { + return cmd_results_new(CMD_FAILURE, "attach", "No seat defined"); + } + + struct seat_config *new_config = new_seat_config(current_seat_config->name); + struct seat_attachment_config *new_attachment = seat_attachment_config_new(); + new_attachment->identifier = strdup(argv[0]); + list_add(new_config->attachments, new_attachment); + + seat_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index b77b8b4b..52633ad8 100644 --- a/sway/config.c +++ b/sway/config.c @@ -45,6 +45,7 @@ static void config_defaults(struct sway_config *config) { if (!(config->criteria = create_list())) goto cleanup; if (!(config->no_focus = create_list())) goto cleanup; if (!(config->input_configs = create_list())) goto cleanup; + if (!(config->seat_configs = create_list())) goto cleanup; if (!(config->output_configs = create_list())) goto cleanup; if (!(config->cmd_queue = create_list())) goto cleanup; @@ -258,9 +259,7 @@ struct input_config *new_input_config(const char* identifier) { void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->identifier) { - if (dst->identifier) { - free(dst->identifier); - } + free(dst->identifier); dst->identifier = strdup(src->identifier); } if (src->accel_profile != INT_MIN) { @@ -300,7 +299,6 @@ void free_input_config(struct input_config *ic) { return; } free(ic->identifier); - free(ic->seat); free(ic); } @@ -310,6 +308,128 @@ int input_identifier_cmp(const void *item, const void *data) { return strcmp(ic->identifier, identifier); } +struct seat_config *new_seat_config(const char* name) { + struct seat_config *seat = calloc(1, sizeof(struct seat_config)); + if (!seat) { + sway_log(L_DEBUG, "Unable to allocate seat config"); + return NULL; + } + + sway_log(L_DEBUG, "new_seat_config(%s)", name); + seat->name = strdup(name); + if (!sway_assert(seat->name, "could not allocate name for seat")) { + return NULL; + } + + seat->attachments = create_list(); + if (!sway_assert(seat->attachments, + "could not allocate seat attachments list")) { + return NULL; + } + + return seat; +} + +struct seat_attachment_config *seat_attachment_config_new() { + struct seat_attachment_config *attachment = + calloc(1, sizeof(struct seat_attachment_config)); + if (!attachment) { + sway_log(L_DEBUG, "cannot allocate attachment config"); + return NULL; + } + return attachment; +} + +static void seat_attachment_config_free( + struct seat_attachment_config *attachment) { + free(attachment->identifier); + free(attachment); + return; +} + +static struct seat_attachment_config *seat_attachment_config_copy( + struct seat_attachment_config *attachment) { + struct seat_attachment_config *copy = seat_attachment_config_new(); + if (!copy) { + return NULL; + } + + copy->identifier = strdup(attachment->identifier); + + return copy; +} + +static void merge_seat_attachment_config(struct seat_attachment_config *dest, + struct seat_attachment_config *source) { + // nothing to merge yet, but there will be some day +} + +void merge_seat_config(struct seat_config *dest, struct seat_config *source) { + if (source->name) { + free(dest->name); + dest->name = strdup(source->name); + } + + for (int i = 0; i < source->attachments->length; ++i) { + struct seat_attachment_config *source_attachment = + source->attachments->items[i]; + bool found = false; + for (int j = 0; j < dest->attachments->length; ++j) { + struct seat_attachment_config *dest_attachment = + dest->attachments->items[j]; + if (strcmp(source_attachment->identifier, + dest_attachment->identifier) == 0) { + merge_seat_attachment_config(dest_attachment, + source_attachment); + found = true; + } + } + + if (!found) { + struct seat_attachment_config *copy = + seat_attachment_config_copy(source_attachment); + if (copy) { + list_add(dest->attachments, copy); + } + } + } +} + +void free_seat_config(struct seat_config *seat) { + if (!seat) { + return; + } + + free(seat->name); + for (int i = 0; i < seat->attachments->length; ++i) { + struct seat_attachment_config *attachment = + seat->attachments->items[i]; + seat_attachment_config_free(attachment); + } + + list_free(seat->attachments); + free(seat); +} + +int seat_name_cmp(const void *item, const void *data) { + const struct seat_config *sc = item; + const char *name = data; + return strcmp(sc->name, name); +} + +struct seat_attachment_config *seat_config_get_attachment( + struct seat_config *seat_config, char *identifier) { + for (int i = 0; i < seat_config->attachments->length; ++i) { + struct seat_attachment_config *attachment = + seat_config->attachments->items[i]; + if (strcmp(attachment->identifier, identifier) == 0) { + return attachment; + } + } + + return NULL; +} + bool load_main_config(const char *file, bool is_active) { char *path; if (file != NULL) { @@ -368,7 +488,7 @@ bool load_main_config(const char *file, bool is_active) { char *_path = secconfigs->items[i]; if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && - (s.st_mode & 0777) != 0444)) { + (s.st_mode & 0777) != 0444)) { sway_log(L_ERROR, "Refusing to load %s - it must be owned by root " "and mode 644 or 444", _path); @@ -547,6 +667,14 @@ bool read_config(FILE *file, struct sway_config *config) { } break; + case CMD_BLOCK_SEAT: + if (block == CMD_BLOCK_END) { + block = CMD_BLOCK_SEAT; + } else { + sway_log(L_ERROR, "Invalid block '%s'", line); + } + break; + case CMD_BLOCK_BAR: if (block == CMD_BLOCK_END) { block = CMD_BLOCK_BAR; @@ -601,6 +729,12 @@ bool read_config(FILE *file, struct sway_config *config) { block = CMD_BLOCK_END; break; + case CMD_BLOCK_SEAT: + sway_log(L_DEBUG, "End of seat block"); + current_seat_config = NULL; + block = CMD_BLOCK_END; + break; + case CMD_BLOCK_BAR: sway_log(L_DEBUG, "End of bar block"); config->current_bar = NULL; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 217c2ddb..3aa2d1bc 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -24,7 +24,7 @@ static void cursor_update_position(struct sway_cursor *cursor) { static void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time) { - struct wlr_seat *seat = cursor->seat->seat; + struct wlr_seat *seat = cursor->seat->wlr_seat; struct wlr_surface *surface = NULL; double sx, sy; swayc_t *swayc = @@ -72,7 +72,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { sway_seat_set_focus(cursor->seat, swayc); } - wlr_seat_pointer_notify_button(cursor->seat->seat, event->time_msec, + wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, event->button, event->state); } @@ -80,7 +80,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, axis); struct wlr_event_pointer_axis *event = data; - wlr_seat_pointer_notify_axis(cursor->seat->seat, event->time_msec, + wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, event->orientation, event->delta); } @@ -173,7 +173,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &cursor->tool_tip); cursor->tool_tip.notify = handle_tool_tip; - wl_signal_add(&seat->seat->events.request_set_cursor, + wl_signal_add(&seat->wlr_seat->events.request_set_cursor, &cursor->request_set_cursor); cursor->request_set_cursor.notify = handle_request_set_cursor; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index b07a733e..1950b6d9 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -18,12 +18,13 @@ static const char *default_seat = "seat0"; struct sway_input_manager *input_manager; struct input_config *current_input_config = NULL; +struct seat_config *current_seat_config = NULL; static struct sway_seat *input_manager_get_seat( struct sway_input_manager *input, const char *seat_name) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - if (strcmp(seat->seat->name, seat_name) == 0) { + if (strcmp(seat->wlr_seat->name, seat_name) == 0) { return seat; } } @@ -58,56 +59,88 @@ static char *get_device_identifier(struct wlr_input_device *device) { return identifier; } -static struct sway_input_device *input_sway_device_from_wlr(struct sway_input_manager *input, - struct wlr_input_device *device) { - struct sway_input_device *sway_device = NULL; - wl_list_for_each(sway_device, &input->devices, link) { - if (sway_device->wlr_device == device) { - return sway_device; +static struct sway_input_device *input_sway_device_from_wlr( + struct sway_input_manager *input, struct wlr_input_device *device) { + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + if (input_device->wlr_device == device) { + return input_device; } } return NULL; } -static struct sway_input_device *input_sway_device_from_config(struct sway_input_manager *input, - struct input_config *config) { - struct sway_input_device *sway_device = NULL; - wl_list_for_each(sway_device, &input->devices, link) { - if (strcmp(sway_device->identifier, config->identifier) == 0) { - return sway_device; +static struct sway_input_device *input_sway_device_from_config( + struct sway_input_manager *input, struct input_config *config) { + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + if (strcmp(input_device->identifier, config->identifier) == 0) { + return input_device; } } return NULL; } +static struct sway_input_device *input_sway_device_from_identifier( + struct sway_input_manager *input, char *identifier) { + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + if (strcmp(input_device->identifier, identifier) == 0) { + return input_device; + } + } + return NULL; +} + +static bool input_has_seat_configuration(struct sway_input_manager *input) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (seat->config) { + return true; + } + } + + return false; +} + static void input_add_notify(struct wl_listener *listener, void *data) { struct sway_input_manager *input = wl_container_of(listener, input, input_add); struct wlr_input_device *device = data; - struct sway_input_device *sway_device = + struct sway_input_device *input_device = calloc(1, sizeof(struct sway_input_device)); - if (!sway_assert(sway_device, "could not allocate input device")) { + if (!sway_assert(input_device, "could not allocate input device")) { return; } - sway_device->wlr_device = device; - sway_device->identifier = get_device_identifier(device); - wl_list_insert(&input->devices, &sway_device->link); + input_device->wlr_device = device; + input_device->identifier = get_device_identifier(device); + wl_list_insert(&input->devices, &input_device->link); // find config for (int i = 0; i < config->input_configs->length; ++i) { struct input_config *input_config = config->input_configs->items[i]; - if (strcmp(input_config->identifier, sway_device->identifier) == 0) { - sway_device->config = input_config; + if (strcmp(input_config->identifier, input_device->identifier) == 0) { + input_device->config = input_config; break; } } - const char *seat_name = - (sway_device->config ? sway_device->config->seat : default_seat); - struct sway_seat *seat = input_manager_get_seat(input, seat_name); - sway_seat_add_device(seat, sway_device); + struct sway_seat *seat = NULL; + if (!input_has_seat_configuration(input)) { + seat = input_manager_get_seat(input, default_seat); + sway_seat_add_device(seat, input_device); + return; + } + + wl_list_for_each(seat, &input->seats, link) { + if (seat->config && + (seat_config_get_attachment(seat->config, input_device->identifier) || + seat_config_get_attachment(seat->config, "*"))) { + sway_seat_add_device(seat, input_device); + } + } } static void input_remove_notify(struct wl_listener *listener, void *data) { @@ -115,21 +148,21 @@ static void input_remove_notify(struct wl_listener *listener, void *data) { wl_container_of(listener, input, input_remove); struct wlr_input_device *device = data; - struct sway_input_device *sway_device = + struct sway_input_device *input_device = input_sway_device_from_wlr(input, device); - if (!sway_assert(sway_device, "could not find sway device")) { + if (!sway_assert(input_device, "could not find sway device")) { return; } struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - sway_seat_remove_device(seat, sway_device); + sway_seat_remove_device(seat, input_device); } - wl_list_remove(&sway_device->link); - free(sway_device->identifier); - free(sway_device); + wl_list_remove(&input_device->link); + free(input_device->identifier); + free(input_device); } struct sway_input_manager *sway_input_manager_create( @@ -139,7 +172,6 @@ struct sway_input_manager *sway_input_manager_create( if (!input) { return NULL; } - // XXX probably don't need the full server input->server = server; wl_list_init(&input->devices); @@ -177,22 +209,53 @@ void sway_input_manager_set_focus(struct sway_input_manager *input, } } -void sway_input_manager_apply_config(struct sway_input_manager *input, +void sway_input_manager_apply_input_config(struct sway_input_manager *input, struct input_config *input_config) { - struct sway_input_device *sway_device = + struct sway_input_device *input_device = input_sway_device_from_config(input, input_config); - if (!sway_device) { + if (!input_device) { return; } + input_device->config = input_config; struct sway_seat *seat = NULL; wl_list_for_each(seat, &input->seats, link) { - sway_seat_remove_device(seat, sway_device); + sway_seat_configure_device(seat, input_device); + } +} + +void sway_input_manager_apply_seat_config(struct sway_input_manager *input, + struct seat_config *seat_config) { + struct sway_seat *seat = input_manager_get_seat(input, seat_config->name); + // the old config is invalid so clear it + sway_seat_set_config(seat, NULL); + + // clear devices + struct sway_input_device *input_device = NULL; + wl_list_for_each(input_device, &input->devices, link) { + sway_seat_remove_device(seat, input_device); + } + + if (seat_config_get_attachment(seat_config, "*")) { + wl_list_for_each(input_device, &input->devices, link) { + sway_seat_add_device(seat, input_device); + } + } else { + for (int i = 0; i < seat_config->attachments->length; ++i) { + struct seat_attachment_config *attachment = + seat_config->attachments->items[i]; + + struct sway_input_device *device = + input_sway_device_from_identifier(input, + attachment->identifier); + + if (device) { + sway_seat_add_device(seat, device); + } + } } - const char *seat_name = (input_config->seat ? input_config->seat : default_seat); - seat = input_manager_get_seat(input, seat_name); - sway_seat_add_device(seat, sway_device); + sway_seat_set_config(seat, seat_config); } void sway_input_manager_configure_xcursor(struct sway_input_manager *input) { diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 6a792c65..53db3270 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -5,32 +5,46 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_key); + struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct wlr_input_device *wlr_device = + keyboard->seat_device->input_device->wlr_device; struct wlr_event_keyboard_key *event = data; - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device->wlr_device); - wlr_seat_keyboard_notify_key(keyboard->seat->seat, event->time_msec, - event->keycode, event->state); + wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,event->keycode, + event->state); } static void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_modifiers); - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device->wlr_device); - wlr_seat_keyboard_notify_modifiers(keyboard->seat->seat); + struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct wlr_input_device *wlr_device = + keyboard->seat_device->input_device->wlr_device; + wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); + wlr_seat_set_keyboard(wlr_seat, wlr_device); + wlr_seat_keyboard_notify_modifiers(wlr_seat); } struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, - struct sway_input_device *device) { + struct sway_seat_device *device) { struct sway_keyboard *keyboard = calloc(1, sizeof(struct sway_keyboard)); if (!sway_assert(keyboard, "could not allocate sway keyboard")) { return NULL; } - keyboard->device = device; - keyboard->seat = seat; + keyboard->seat_device = device; + device->keyboard = keyboard; - // TODO keyboard config + wl_list_init(&keyboard->keyboard_key.link); + wl_list_init(&keyboard->keyboard_modifiers.link); + + return keyboard; +} + +void sway_keyboard_configure(struct sway_keyboard *keyboard) { struct xkb_rule_names rules; memset(&rules, 0, sizeof(rules)); rules.rules = getenv("XKB_DEFAULT_RULES"); @@ -38,27 +52,32 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, rules.layout = getenv("XKB_DEFAULT_LAYOUT"); rules.variant = getenv("XKB_DEFAULT_VARIANT"); rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!sway_assert(context, "cannot create XKB context")) { - return NULL; + return; } - wlr_keyboard_set_keymap(device->wlr_device->keyboard, - xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + keyboard->keymap = + xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + wlr_keyboard_set_keymap(keyboard->seat_device->input_device->wlr_device->keyboard, keyboard->keymap); xkb_context_unref(context); - wl_signal_add(&device->wlr_device->keyboard->events.key, + wl_list_remove(&keyboard->keyboard_key.link); + wl_signal_add( + &keyboard->seat_device->input_device->wlr_device->keyboard->events.key, &keyboard->keyboard_key); keyboard->keyboard_key.notify = handle_keyboard_key; - wl_signal_add(&device->wlr_device->keyboard->events.modifiers, + wl_list_remove(&keyboard->keyboard_modifiers.link); + wl_signal_add( + &keyboard->seat_device->input_device->wlr_device->keyboard->events.modifiers, &keyboard->keyboard_modifiers); keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; - - return keyboard; } void sway_keyboard_destroy(struct sway_keyboard *keyboard) { + xkb_keymap_unref(keyboard->keymap); wl_list_remove(&keyboard->keyboard_key.link); wl_list_remove(&keyboard->keyboard_modifiers.link); wl_list_remove(&keyboard->link); diff --git a/sway/input/seat.c b/sway/input/seat.c index 80c6424f..1b25419b 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -9,6 +9,18 @@ #include "sway/view.h" #include "log.h" +static void seat_device_destroy(struct sway_seat_device *seat_device) { + if (!seat_device) { + return; + } + + sway_keyboard_destroy(seat_device->keyboard); + wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor, + seat_device->input_device->wlr_device); + wl_list_remove(&seat_device->link); + free(seat_device); +} + struct sway_seat *sway_seat_create(struct sway_input_manager *input, const char *seat_name) { struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); @@ -16,22 +28,22 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, return NULL; } - seat->seat = wlr_seat_create(input->server->wl_display, seat_name); - if (!sway_assert(seat->seat, "could not allocate seat")) { + seat->wlr_seat = wlr_seat_create(input->server->wl_display, seat_name); + if (!sway_assert(seat->wlr_seat, "could not allocate seat")) { return NULL; } seat->cursor = sway_cursor_create(seat); if (!seat->cursor) { - wlr_seat_destroy(seat->seat); + wlr_seat_destroy(seat->wlr_seat); free(seat); return NULL; } seat->input = input; - seat->devices = create_list(); + wl_list_init(&seat->devices); - wlr_seat_set_capabilities(seat->seat, + wlr_seat_set_capabilities(seat->wlr_seat, WL_SEAT_CAPABILITY_KEYBOARD | WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); @@ -43,88 +55,94 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, return seat; } -static void seat_add_pointer(struct sway_seat *seat, - struct sway_input_device *sway_device) { +static void seat_configure_pointer(struct sway_seat *seat, + struct sway_seat_device *sway_device) { // TODO pointer configuration wlr_cursor_attach_input_device(seat->cursor->cursor, - sway_device->wlr_device); + sway_device->input_device->wlr_device); } -static void seat_add_keyboard(struct sway_seat *seat, - struct sway_input_device *device) { - // TODO keyboard configuration - sway_keyboard_create(seat, device); - wlr_seat_set_keyboard(seat->seat, device->wlr_device); +static void seat_configure_keyboard(struct sway_seat *seat, + struct sway_seat_device *seat_device) { + if (!seat_device->keyboard) { + sway_keyboard_create(seat, seat_device); + } + sway_keyboard_configure(seat_device->keyboard); } -bool sway_seat_has_device(struct sway_seat *seat, - struct sway_input_device *device) { - return false; +static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + struct sway_seat_device *seat_device = NULL; + wl_list_for_each(seat_device, &seat->devices, link) { + if (seat_device->input_device == input_device) { + return seat_device; + } + } + + return NULL; } -void sway_seat_add_device(struct sway_seat *seat, - struct sway_input_device *device) { - if (sway_seat_has_device(seat, device)) { +void sway_seat_configure_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + struct sway_seat_device *seat_device = + sway_seat_get_device(seat, input_device); + if (!seat_device) { return; } - sway_log(L_DEBUG, "input add: %s", device->identifier); - switch (device->wlr_device->type) { + if (seat->config) { + seat_device->attachment_config = + seat_config_get_attachment(seat->config, input_device->identifier); + } + + switch (input_device->wlr_device->type) { case WLR_INPUT_DEVICE_POINTER: - seat_add_pointer(seat, device); + seat_configure_pointer(seat, seat_device); break; case WLR_INPUT_DEVICE_KEYBOARD: - seat_add_keyboard(seat, device); + seat_configure_keyboard(seat, seat_device); + wlr_seat_set_keyboard(seat->wlr_seat, + seat_device->input_device->wlr_device); break; case WLR_INPUT_DEVICE_TOUCH: case WLR_INPUT_DEVICE_TABLET_PAD: case WLR_INPUT_DEVICE_TABLET_TOOL: - sway_log(L_DEBUG, "TODO: add other devices"); + sway_log(L_DEBUG, "TODO: configure other devices"); break; } - - list_add(seat->devices, device); } -static void seat_remove_keyboard(struct sway_seat *seat, - struct sway_input_device *device) { - if (device && device->keyboard) { - sway_keyboard_destroy(device->keyboard); +void sway_seat_add_device(struct sway_seat *seat, + struct sway_input_device *input_device) { + if (sway_seat_get_device(seat, input_device)) { + return; } -} -static void seat_remove_pointer(struct sway_seat *seat, - struct sway_input_device *device) { - wlr_cursor_detach_input_device(seat->cursor->cursor, device->wlr_device); + struct sway_seat_device *seat_device = + calloc(1, sizeof(struct sway_seat_device)); + if (!seat_device) { + sway_log(L_DEBUG, "could not allocate seat device"); + return; + } + + seat_device->sway_seat = seat; + seat_device->input_device = input_device; + wl_list_insert(&seat->devices, &seat_device->link); + + sway_seat_configure_device(seat, input_device); } void sway_seat_remove_device(struct sway_seat *seat, - struct sway_input_device *device) { - sway_log(L_DEBUG, "input remove: %s", device->identifier); - if (!sway_seat_has_device(seat, device)) { - return; - } + struct sway_input_device *input_device) { + sway_log(L_DEBUG, "input remove: %s", input_device->identifier); + struct sway_seat_device *seat_device = + sway_seat_get_device(seat, input_device); - switch (device->wlr_device->type) { - case WLR_INPUT_DEVICE_POINTER: - seat_remove_pointer(seat, device); - break; - case WLR_INPUT_DEVICE_KEYBOARD: - seat_remove_keyboard(seat, device); - break; - case WLR_INPUT_DEVICE_TOUCH: - case WLR_INPUT_DEVICE_TABLET_PAD: - case WLR_INPUT_DEVICE_TABLET_TOOL: - sway_log(L_DEBUG, "TODO: remove other devices"); - break; + if (!seat_device) { + return; } - for (int i = 0; i < seat->devices->length; ++i) { - if (seat->devices->items[i] == device) { - list_del(seat->devices, i); - break; - } - } + seat_device_destroy(seat_device); } void sway_seat_configure_xcursor(struct sway_seat *seat) { @@ -135,7 +153,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { seat->cursor->xcursor_manager = wlr_xcursor_manager_create("default", 24); if (sway_assert(seat->cursor->xcursor_manager, - "Cannot create XCursor manager for theme %s", cursor_theme)) { + "Cannot create XCursor manager for theme %s", + cursor_theme)) { return; } } @@ -183,7 +202,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { view->iface.set_activated(view, true); wl_signal_add(&container->events.destroy, &seat->focus_destroy); seat->focus_destroy.notify = handle_focus_destroy; - wlr_seat_keyboard_notify_enter(seat->seat, view->surface); + wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface); } seat->focus = container; @@ -195,3 +214,29 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { } } + +void sway_seat_set_config(struct sway_seat *seat, + struct seat_config *seat_config) { + // clear configs + seat->config = NULL; + + struct sway_seat_device *seat_device = NULL; + wl_list_for_each(seat_device, &seat->devices, link) { + seat_device->attachment_config = NULL; + } + + if (!seat_config) { + return; + } + + // add configs + seat->config = seat_config; + + wl_list_for_each(seat_device, &seat->devices, link) { + seat_device->attachment_config = + seat_config_get_attachment(seat_config, + seat_device->input_device->identifier); + sway_seat_configure_device(seat, seat_device->input_device); + } + +} diff --git a/sway/meson.build b/sway/meson.build index fad1f88c..ad8160eb 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -11,7 +11,8 @@ sway_sources = files( 'commands/exec_always.c', 'commands/include.c', 'commands/input.c', - 'commands/input/seat.c', + 'commands/seat.c', + 'commands/seat/attach.c', 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', -- cgit v1.2.3 From 9eecbb5d8a988a0dded57ead1982dd0121071454 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 15 Dec 2017 05:22:51 -0500 Subject: xkb config --- include/sway/commands.h | 5 +++++ include/sway/config.h | 6 ++++++ sway/commands.c | 5 +++++ sway/commands/input/xkb_layout.c | 24 ++++++++++++++++++++++++ sway/commands/input/xkb_model.c | 24 ++++++++++++++++++++++++ sway/commands/input/xkb_options.c | 24 ++++++++++++++++++++++++ sway/commands/input/xkb_rules.c | 24 ++++++++++++++++++++++++ sway/commands/input/xkb_variant.c | 24 ++++++++++++++++++++++++ sway/config.c | 20 ++++++++++++++++++++ sway/input/keyboard.c | 38 +++++++++++++++++++++++++++++++++----- sway/main.c | 1 + sway/meson.build | 5 +++++ 12 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 sway/commands/input/xkb_layout.c create mode 100644 sway/commands/input/xkb_model.c create mode 100644 sway/commands/input/xkb_options.c create mode 100644 sway/commands/input/xkb_rules.c create mode 100644 sway/commands/input/xkb_variant.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index ce74e1ed..61950d0d 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -195,6 +195,11 @@ sway_cmd input_cmd_natural_scroll; sway_cmd input_cmd_pointer_accel; sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; +sway_cmd input_cmd_xkb_layout; +sway_cmd input_cmd_xkb_model; +sway_cmd input_cmd_xkb_options; +sway_cmd input_cmd_xkb_rules; +sway_cmd input_cmd_xkb_variant; sway_cmd seat_cmd_attach; diff --git a/include/sway/config.h b/include/sway/config.h index 5df5d61e..9bfda259 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -67,6 +67,12 @@ struct input_config { int send_events; int tap; + char *xkb_layout; + char *xkb_model; + char *xkb_options; + char *xkb_rules; + char *xkb_variant; + bool capturable; struct wlr_box region; }; diff --git a/sway/commands.c b/sway/commands.c index e003e06d..b8948fb7 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -154,6 +154,11 @@ static struct cmd_handler input_handlers[] = { { "pointer_accel", input_cmd_pointer_accel }, { "scroll_method", input_cmd_scroll_method }, { "tap", input_cmd_tap }, + { "xkb_layout", input_cmd_xkb_layout }, + { "xkb_model", input_cmd_xkb_model }, + { "xkb_options", input_cmd_xkb_options }, + { "xkb_rules", input_cmd_xkb_rules }, + { "xkb_variant", input_cmd_xkb_variant }, }; // must be in order for the bsearch diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c new file mode 100644 index 00000000..9a9ce044 --- /dev/null +++ b/sway/commands/input/xkb_layout.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { + sway_log(L_DEBUG, "xkb layout for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_layout", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->xkb_layout = strdup(argv[0]); + + sway_log(L_DEBUG, "apply-xkb_layout for device: %s", + current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c new file mode 100644 index 00000000..14a50ffb --- /dev/null +++ b/sway/commands/input/xkb_model.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { + sway_log(L_DEBUG, "xkb model for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_model", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->xkb_model = strdup(argv[0]); + + sway_log(L_DEBUG, "apply-xkb_model for device: %s", + current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c new file mode 100644 index 00000000..67eb5342 --- /dev/null +++ b/sway/commands/input/xkb_options.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { + sway_log(L_DEBUG, "xkb options for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_options", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->xkb_options = strdup(argv[0]); + + sway_log(L_DEBUG, "apply-xkb_options for device: %s", + current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c new file mode 100644 index 00000000..3eda0bdd --- /dev/null +++ b/sway/commands/input/xkb_rules.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { + sway_log(L_DEBUG, "xkb rules for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_rules", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->xkb_rules = strdup(argv[0]); + + sway_log(L_DEBUG, "apply-xkb_rules for device: %s", + current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c new file mode 100644 index 00000000..c7f93ad4 --- /dev/null +++ b/sway/commands/input/xkb_variant.c @@ -0,0 +1,24 @@ +#define _XOPEN_SOURCE 700 +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { + sway_log(L_DEBUG, "xkb variant for device: %s", current_input_config->identifier); + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_variant", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->xkb_variant = strdup(argv[0]); + + sway_log(L_DEBUG, "apply-xkb_variant for device: %s", + current_input_config->identifier); + input_cmd_apply(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 52633ad8..4e34aa8c 100644 --- a/sway/config.c +++ b/sway/config.c @@ -292,6 +292,26 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->tap != INT_MIN) { dst->tap = src->tap; } + if (src->xkb_layout) { + free(dst->xkb_layout); + dst->xkb_layout = strdup(src->xkb_layout); + } + if (src->xkb_model) { + free(dst->xkb_model); + dst->xkb_model = strdup(src->xkb_model); + } + if (src->xkb_options) { + free(dst->xkb_options); + dst->xkb_options = strdup(src->xkb_options); + } + if (src->xkb_rules) { + free(dst->xkb_rules); + dst->xkb_rules = strdup(src->xkb_rules); + } + if (src->xkb_variant) { + free(dst->xkb_variant); + dst->xkb_variant = strdup(src->xkb_variant); + } } void free_input_config(struct input_config *ic) { diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 53db3270..2ab0206a 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -1,5 +1,6 @@ #include "sway/input/seat.h" #include "sway/input/keyboard.h" +#include "sway/input/input-manager.h" #include "log.h" static void handle_keyboard_key(struct wl_listener *listener, void *data) { @@ -47,17 +48,44 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, void sway_keyboard_configure(struct sway_keyboard *keyboard) { struct xkb_rule_names rules; memset(&rules, 0, sizeof(rules)); - rules.rules = getenv("XKB_DEFAULT_RULES"); - rules.model = getenv("XKB_DEFAULT_MODEL"); - rules.layout = getenv("XKB_DEFAULT_LAYOUT"); - rules.variant = getenv("XKB_DEFAULT_VARIANT"); - rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct input_config *input_config = + keyboard->seat_device->input_device->config; + + if (input_config && input_config->xkb_layout) { + rules.layout = input_config->xkb_layout; + } else { + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + } + if (input_config && input_config->xkb_model) { + rules.model = input_config->xkb_model; + } else { + rules.model = getenv("XKB_DEFAULT_MODEL"); + } + + if (input_config && input_config->xkb_options) { + rules.options = input_config->xkb_options; + } else { + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + } + + if (input_config && input_config->xkb_rules) { + rules.rules = input_config->xkb_rules; + } else { + rules.rules = getenv("XKB_DEFAULT_RULES"); + } + + if (input_config && input_config->xkb_variant) { + rules.variant = input_config->xkb_variant; + } else { + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + } struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!sway_assert(context, "cannot create XKB context")) { return; } + xkb_keymap_unref(keyboard->keymap); keyboard->keymap = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); wlr_keyboard_set_keymap(keyboard->seat_device->input_device->wlr_device->keyboard, keyboard->keymap); diff --git a/sway/main.c b/sway/main.c index 363f4d96..25032aa0 100644 --- a/sway/main.c +++ b/sway/main.c @@ -158,6 +158,7 @@ static void log_distro() { } static void log_kernel() { + return; FILE *f = popen("uname -a", "r"); if (!f) { sway_log(L_INFO, "Unable to determine kernel version"); diff --git a/sway/meson.build b/sway/meson.build index ad8160eb..c81e1c2c 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -24,6 +24,11 @@ sway_sources = files( 'commands/input/pointer_accel.c', 'commands/input/scroll_method.c', 'commands/input/tap.c', + 'commands/input/xkb_layout.c', + 'commands/input/xkb_model.c', + 'commands/input/xkb_options.c', + 'commands/input/xkb_rules.c', + 'commands/input/xkb_variant.c', 'config.c', 'ipc-json.c', 'ipc-server.c', -- cgit v1.2.3 From f4a5a0ead4c8b155985c242db1fa5de5fa4807a0 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Dec 2017 11:25:59 -0500 Subject: put seat and input config in their own files --- sway/config.c | 222 ---------------------------------------------------- sway/config/input.c | 105 +++++++++++++++++++++++++ sway/config/seat.c | 127 ++++++++++++++++++++++++++++++ sway/meson.build | 2 + 4 files changed, 234 insertions(+), 222 deletions(-) create mode 100644 sway/config/input.c create mode 100644 sway/config/seat.c (limited to 'sway/meson.build') diff --git a/sway/config.c b/sway/config.c index 4e34aa8c..b591ae9e 100644 --- a/sway/config.c +++ b/sway/config.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #ifdef __linux__ @@ -229,227 +228,6 @@ static int qstrcmp(const void* a, const void* b) { return strcmp(*((char**) a), *((char**) b)); } -struct input_config *new_input_config(const char* identifier) { - struct input_config *input = calloc(1, sizeof(struct input_config)); - if (!input) { - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - sway_log(L_DEBUG, "new_input_config(%s)", identifier); - if (!(input->identifier = strdup(identifier))) { - free(input); - sway_log(L_DEBUG, "Unable to allocate input config"); - return NULL; - } - - input->tap = INT_MIN; - input->drag_lock = INT_MIN; - input->dwt = INT_MIN; - input->send_events = INT_MIN; - input->click_method = INT_MIN; - input->middle_emulation = INT_MIN; - input->natural_scroll = INT_MIN; - input->accel_profile = INT_MIN; - input->pointer_accel = FLT_MIN; - input->scroll_method = INT_MIN; - input->left_handed = INT_MIN; - - return input; -} - -void merge_input_config(struct input_config *dst, struct input_config *src) { - if (src->identifier) { - free(dst->identifier); - dst->identifier = strdup(src->identifier); - } - if (src->accel_profile != INT_MIN) { - dst->accel_profile = src->accel_profile; - } - if (src->click_method != INT_MIN) { - dst->click_method = src->click_method; - } - if (src->drag_lock != INT_MIN) { - dst->drag_lock = src->drag_lock; - } - if (src->dwt != INT_MIN) { - dst->dwt = src->dwt; - } - if (src->middle_emulation != INT_MIN) { - dst->middle_emulation = src->middle_emulation; - } - if (src->natural_scroll != INT_MIN) { - dst->natural_scroll = src->natural_scroll; - } - if (src->pointer_accel != FLT_MIN) { - dst->pointer_accel = src->pointer_accel; - } - if (src->scroll_method != INT_MIN) { - dst->scroll_method = src->scroll_method; - } - if (src->send_events != INT_MIN) { - dst->send_events = src->send_events; - } - if (src->tap != INT_MIN) { - dst->tap = src->tap; - } - if (src->xkb_layout) { - free(dst->xkb_layout); - dst->xkb_layout = strdup(src->xkb_layout); - } - if (src->xkb_model) { - free(dst->xkb_model); - dst->xkb_model = strdup(src->xkb_model); - } - if (src->xkb_options) { - free(dst->xkb_options); - dst->xkb_options = strdup(src->xkb_options); - } - if (src->xkb_rules) { - free(dst->xkb_rules); - dst->xkb_rules = strdup(src->xkb_rules); - } - if (src->xkb_variant) { - free(dst->xkb_variant); - dst->xkb_variant = strdup(src->xkb_variant); - } -} - -void free_input_config(struct input_config *ic) { - if (!ic) { - return; - } - free(ic->identifier); - free(ic); -} - -int input_identifier_cmp(const void *item, const void *data) { - const struct input_config *ic = item; - const char *identifier = data; - return strcmp(ic->identifier, identifier); -} - -struct seat_config *new_seat_config(const char* name) { - struct seat_config *seat = calloc(1, sizeof(struct seat_config)); - if (!seat) { - sway_log(L_DEBUG, "Unable to allocate seat config"); - return NULL; - } - - sway_log(L_DEBUG, "new_seat_config(%s)", name); - seat->name = strdup(name); - if (!sway_assert(seat->name, "could not allocate name for seat")) { - return NULL; - } - - seat->attachments = create_list(); - if (!sway_assert(seat->attachments, - "could not allocate seat attachments list")) { - return NULL; - } - - return seat; -} - -struct seat_attachment_config *seat_attachment_config_new() { - struct seat_attachment_config *attachment = - calloc(1, sizeof(struct seat_attachment_config)); - if (!attachment) { - sway_log(L_DEBUG, "cannot allocate attachment config"); - return NULL; - } - return attachment; -} - -static void seat_attachment_config_free( - struct seat_attachment_config *attachment) { - free(attachment->identifier); - free(attachment); - return; -} - -static struct seat_attachment_config *seat_attachment_config_copy( - struct seat_attachment_config *attachment) { - struct seat_attachment_config *copy = seat_attachment_config_new(); - if (!copy) { - return NULL; - } - - copy->identifier = strdup(attachment->identifier); - - return copy; -} - -static void merge_seat_attachment_config(struct seat_attachment_config *dest, - struct seat_attachment_config *source) { - // nothing to merge yet, but there will be some day -} - -void merge_seat_config(struct seat_config *dest, struct seat_config *source) { - if (source->name) { - free(dest->name); - dest->name = strdup(source->name); - } - - for (int i = 0; i < source->attachments->length; ++i) { - struct seat_attachment_config *source_attachment = - source->attachments->items[i]; - bool found = false; - for (int j = 0; j < dest->attachments->length; ++j) { - struct seat_attachment_config *dest_attachment = - dest->attachments->items[j]; - if (strcmp(source_attachment->identifier, - dest_attachment->identifier) == 0) { - merge_seat_attachment_config(dest_attachment, - source_attachment); - found = true; - } - } - - if (!found) { - struct seat_attachment_config *copy = - seat_attachment_config_copy(source_attachment); - if (copy) { - list_add(dest->attachments, copy); - } - } - } -} - -void free_seat_config(struct seat_config *seat) { - if (!seat) { - return; - } - - free(seat->name); - for (int i = 0; i < seat->attachments->length; ++i) { - struct seat_attachment_config *attachment = - seat->attachments->items[i]; - seat_attachment_config_free(attachment); - } - - list_free(seat->attachments); - free(seat); -} - -int seat_name_cmp(const void *item, const void *data) { - const struct seat_config *sc = item; - const char *name = data; - return strcmp(sc->name, name); -} - -struct seat_attachment_config *seat_config_get_attachment( - struct seat_config *seat_config, char *identifier) { - for (int i = 0; i < seat_config->attachments->length; ++i) { - struct seat_attachment_config *attachment = - seat_config->attachments->items[i]; - if (strcmp(attachment->identifier, identifier) == 0) { - return attachment; - } - } - - return NULL; -} - bool load_main_config(const char *file, bool is_active) { char *path; if (file != NULL) { diff --git a/sway/config/input.c b/sway/config/input.c new file mode 100644 index 00000000..6f8d31f7 --- /dev/null +++ b/sway/config/input.c @@ -0,0 +1,105 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include "sway/config.h" +#include "log.h" + +struct input_config *new_input_config(const char* identifier) { + struct input_config *input = calloc(1, sizeof(struct input_config)); + if (!input) { + sway_log(L_DEBUG, "Unable to allocate input config"); + return NULL; + } + sway_log(L_DEBUG, "new_input_config(%s)", identifier); + if (!(input->identifier = strdup(identifier))) { + free(input); + sway_log(L_DEBUG, "Unable to allocate input config"); + return NULL; + } + + input->tap = INT_MIN; + input->drag_lock = INT_MIN; + input->dwt = INT_MIN; + input->send_events = INT_MIN; + input->click_method = INT_MIN; + input->middle_emulation = INT_MIN; + input->natural_scroll = INT_MIN; + input->accel_profile = INT_MIN; + input->pointer_accel = FLT_MIN; + input->scroll_method = INT_MIN; + input->left_handed = INT_MIN; + + return input; +} + +void merge_input_config(struct input_config *dst, struct input_config *src) { + if (src->identifier) { + free(dst->identifier); + dst->identifier = strdup(src->identifier); + } + if (src->accel_profile != INT_MIN) { + dst->accel_profile = src->accel_profile; + } + if (src->click_method != INT_MIN) { + dst->click_method = src->click_method; + } + if (src->drag_lock != INT_MIN) { + dst->drag_lock = src->drag_lock; + } + if (src->dwt != INT_MIN) { + dst->dwt = src->dwt; + } + if (src->middle_emulation != INT_MIN) { + dst->middle_emulation = src->middle_emulation; + } + if (src->natural_scroll != INT_MIN) { + dst->natural_scroll = src->natural_scroll; + } + if (src->pointer_accel != FLT_MIN) { + dst->pointer_accel = src->pointer_accel; + } + if (src->scroll_method != INT_MIN) { + dst->scroll_method = src->scroll_method; + } + if (src->send_events != INT_MIN) { + dst->send_events = src->send_events; + } + if (src->tap != INT_MIN) { + dst->tap = src->tap; + } + if (src->xkb_layout) { + free(dst->xkb_layout); + dst->xkb_layout = strdup(src->xkb_layout); + } + if (src->xkb_model) { + free(dst->xkb_model); + dst->xkb_model = strdup(src->xkb_model); + } + if (src->xkb_options) { + free(dst->xkb_options); + dst->xkb_options = strdup(src->xkb_options); + } + if (src->xkb_rules) { + free(dst->xkb_rules); + dst->xkb_rules = strdup(src->xkb_rules); + } + if (src->xkb_variant) { + free(dst->xkb_variant); + dst->xkb_variant = strdup(src->xkb_variant); + } +} + +void free_input_config(struct input_config *ic) { + if (!ic) { + return; + } + free(ic->identifier); + free(ic); +} + +int input_identifier_cmp(const void *item, const void *data) { + const struct input_config *ic = item; + const char *identifier = data; + return strcmp(ic->identifier, identifier); +} diff --git a/sway/config/seat.c b/sway/config/seat.c new file mode 100644 index 00000000..3a2fdaa6 --- /dev/null +++ b/sway/config/seat.c @@ -0,0 +1,127 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include "sway/config.h" +#include "log.h" + +struct seat_config *new_seat_config(const char* name) { + struct seat_config *seat = calloc(1, sizeof(struct seat_config)); + if (!seat) { + sway_log(L_DEBUG, "Unable to allocate seat config"); + return NULL; + } + + sway_log(L_DEBUG, "new_seat_config(%s)", name); + seat->name = strdup(name); + if (!sway_assert(seat->name, "could not allocate name for seat")) { + return NULL; + } + + seat->attachments = create_list(); + if (!sway_assert(seat->attachments, + "could not allocate seat attachments list")) { + return NULL; + } + + return seat; +} + +struct seat_attachment_config *seat_attachment_config_new() { + struct seat_attachment_config *attachment = + calloc(1, sizeof(struct seat_attachment_config)); + if (!attachment) { + sway_log(L_DEBUG, "cannot allocate attachment config"); + return NULL; + } + return attachment; +} + +static void seat_attachment_config_free( + struct seat_attachment_config *attachment) { + free(attachment->identifier); + free(attachment); + return; +} + +static struct seat_attachment_config *seat_attachment_config_copy( + struct seat_attachment_config *attachment) { + struct seat_attachment_config *copy = seat_attachment_config_new(); + if (!copy) { + return NULL; + } + + copy->identifier = strdup(attachment->identifier); + + return copy; +} + +static void merge_seat_attachment_config(struct seat_attachment_config *dest, + struct seat_attachment_config *source) { + // nothing to merge yet, but there will be some day +} + +void merge_seat_config(struct seat_config *dest, struct seat_config *source) { + if (source->name) { + free(dest->name); + dest->name = strdup(source->name); + } + + for (int i = 0; i < source->attachments->length; ++i) { + struct seat_attachment_config *source_attachment = + source->attachments->items[i]; + bool found = false; + for (int j = 0; j < dest->attachments->length; ++j) { + struct seat_attachment_config *dest_attachment = + dest->attachments->items[j]; + if (strcmp(source_attachment->identifier, + dest_attachment->identifier) == 0) { + merge_seat_attachment_config(dest_attachment, + source_attachment); + found = true; + } + } + + if (!found) { + struct seat_attachment_config *copy = + seat_attachment_config_copy(source_attachment); + if (copy) { + list_add(dest->attachments, copy); + } + } + } +} + +void free_seat_config(struct seat_config *seat) { + if (!seat) { + return; + } + + free(seat->name); + for (int i = 0; i < seat->attachments->length; ++i) { + struct seat_attachment_config *attachment = + seat->attachments->items[i]; + seat_attachment_config_free(attachment); + } + + list_free(seat->attachments); + free(seat); +} + +int seat_name_cmp(const void *item, const void *data) { + const struct seat_config *sc = item; + const char *name = data; + return strcmp(sc->name, name); +} + +struct seat_attachment_config *seat_config_get_attachment( + struct seat_config *seat_config, char *identifier) { + for (int i = 0; i < seat_config->attachments->length; ++i) { + struct seat_attachment_config *attachment = + seat_config->attachments->items[i]; + if (strcmp(attachment->identifier, identifier) == 0) { + return attachment; + } + } + + return NULL; +} diff --git a/sway/meson.build b/sway/meson.build index c1f75b13..3d38c7c9 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -32,6 +32,8 @@ sway_sources = files( 'commands/output.c', 'config.c', 'config/output.c', + 'config/seat.c', + 'config/input.c', 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', -- cgit v1.2.3 From 88bcd43ebf59cfa03a9e9a158c6f7a258c1f7db2 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 17 Dec 2017 10:39:22 -0500 Subject: seat fallback config --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands.c | 1 + sway/commands/seat.c | 2 ++ sway/commands/seat/fallback.c | 29 +++++++++++++++ sway/config/seat.c | 5 +++ sway/input/input-manager.c | 83 ++++++++++++++++++++++++++++++------------- sway/input/seat.c | 3 +- sway/meson.build | 1 + 9 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 sway/commands/seat/fallback.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 5008831d..4ee7af2a 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -198,6 +198,7 @@ sway_cmd input_cmd_xkb_options; sway_cmd input_cmd_xkb_rules; sway_cmd input_cmd_xkb_variant; +sway_cmd seat_cmd_fallback; sway_cmd seat_cmd_attach; sway_cmd cmd_ipc_cmd; diff --git a/include/sway/config.h b/include/sway/config.h index eb642dc2..fdfbbedb 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -90,6 +90,7 @@ struct seat_attachment_config { */ struct seat_config { char *name; + int fallback; // -1 means not set list_t *attachments; // list of seat_attachment configs }; diff --git a/sway/commands.c b/sway/commands.c index 3fb1842d..34afb6a0 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -165,6 +165,7 @@ static struct cmd_handler input_handlers[] = { // must be in order for the bsearch static struct cmd_handler seat_handlers[] = { { "attach", seat_cmd_attach }, + { "fallback", seat_cmd_fallback }, }; static struct cmd_handler *find_handler(char *line, enum cmd_status block) { diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 4f9e259b..0149762a 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -24,6 +24,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) { current_seat_config = new_seat_config(argv[0]); if (strcasecmp("attach", argv[1]) == 0) { res = seat_cmd_attach(argc_new, argv_new); + } else if (strcasecmp("fallback", argv[1]) == 0) { + res = seat_cmd_fallback(argc_new, argv_new); } else { res = cmd_results_new(CMD_INVALID, "seat ", "Unknown command %s", argv[1]); } diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c new file mode 100644 index 00000000..7c129aae --- /dev/null +++ b/sway/commands/seat/fallback.c @@ -0,0 +1,29 @@ +#include +#include +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *seat_cmd_fallback(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) { + return error; + } + if (!current_seat_config) { + return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined"); + } + struct seat_config *new_config = + new_seat_config(current_seat_config->name); + + if (strcasecmp(argv[0], "true") == 0) { + new_config->fallback = 1; + } else if (strcasecmp(argv[0], "false") == 0) { + new_config->fallback = 0; + } else { + return cmd_results_new(CMD_INVALID, "fallback", + "Expected 'fallback '"); + } + + apply_seat_config(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config/seat.c b/sway/config/seat.c index 3a2fdaa6..4c9e8d0d 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c @@ -17,6 +17,7 @@ struct seat_config *new_seat_config(const char* name) { return NULL; } + seat->fallback = -1; seat->attachments = create_list(); if (!sway_assert(seat->attachments, "could not allocate seat attachments list")) { @@ -66,6 +67,10 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) { dest->name = strdup(source->name); } + if (source->fallback != -1) { + dest->fallback = source->fallback; + } + for (int i = 0; i < source->attachments->length; ++i) { struct seat_attachment_config *source_attachment = source->attachments->items[i]; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index fa8e4b49..16301489 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -56,9 +56,9 @@ static char *get_device_identifier(struct wlr_input_device *device) { int len = (strlen(name) + - strlen_num(device->vendor) + - strlen_num(device->product) + - 3) * sizeof(char); + strlen_num(device->vendor) + + strlen_num(device->product) + + 3) * sizeof(char); char *identifier = malloc(len); if (!identifier) { @@ -151,13 +151,30 @@ static void input_add_notify(struct wl_listener *listener, void *data) { return; } + bool added = false; wl_list_for_each(seat, &input->seats, link) { if (seat->config && (seat_config_get_attachment(seat->config, input_device->identifier) || seat_config_get_attachment(seat->config, "*"))) { sway_seat_add_device(seat, input_device); + added = true; } } + + if (!added) { + wl_list_for_each(seat, &input->seats, link) { + if (seat->config && seat->config->fallback == 1) { + sway_seat_add_device(seat, input_device); + added = true; + } + } + } + + if (!added) { + sway_log(L_DEBUG, + "device '%s' is not configured on any seats", + input_device->identifier); + } } static void input_remove_notify(struct wl_listener *listener, void *data) { @@ -248,35 +265,53 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input, struct seat_config *seat_config) { sway_log(L_DEBUG, "applying new seat config for seat %s", seat_config->name); struct sway_seat *seat = input_manager_get_seat(input, seat_config->name); - // the old config is invalid so clear it - sway_seat_set_config(seat, NULL); + if (!seat) { + return; + } + + sway_seat_set_config(seat, seat_config); - // clear devices + // for every device, try to add it to a seat and if no seat has it + // attached, add it to the fallback seats. struct sway_input_device *input_device = NULL; wl_list_for_each(input_device, &input->devices, link) { - sway_seat_remove_device(seat, input_device); - } - - if (seat_config_get_attachment(seat_config, "*")) { - wl_list_for_each(input_device, &input->devices, link) { - sway_seat_add_device(seat, input_device); + list_t *seat_list = create_list(); + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (!seat->config) { + continue; + } + if (seat_config_get_attachment(seat->config, "*") || + seat_config_get_attachment(seat->config, input_device->identifier)) { + list_add(seat_list, seat); + } } - } else { - for (int i = 0; i < seat_config->attachments->length; ++i) { - struct seat_attachment_config *attachment = - seat_config->attachments->items[i]; - - struct sway_input_device *device = - input_sway_device_from_identifier(input, - attachment->identifier); - if (device) { - sway_seat_add_device(seat, device); + if (seat_list->length) { + wl_list_for_each(seat, &input->seats, link) { + bool attached = false; + for (int i = 0; i < seat_list->length; ++i) { + if (seat == seat_list->items[i]) { + attached = true; + break; + } + } + if (attached) { + sway_seat_add_device(seat, input_device); + } else { + sway_seat_remove_device(seat, input_device); + } + } + } else { + wl_list_for_each(seat, &input->seats, link) { + if (seat->config && seat->config->fallback == 1) { + sway_seat_add_device(seat, input_device); + } else { + sway_seat_remove_device(seat, input_device); + } } } } - - sway_seat_set_config(seat, seat_config); } void sway_input_manager_configure_xcursor(struct sway_input_manager *input) { diff --git a/sway/input/seat.c b/sway/input/seat.c index 8fe82b46..94503687 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -120,6 +120,7 @@ void sway_seat_configure_device(struct sway_seat *seat, void sway_seat_add_device(struct sway_seat *seat, struct sway_input_device *input_device) { if (sway_seat_get_device(seat, input_device)) { + sway_seat_configure_device(seat, input_device); return; } @@ -246,7 +247,5 @@ void sway_seat_set_config(struct sway_seat *seat, seat_device->attachment_config = seat_config_get_attachment(seat_config, seat_device->input_device->identifier); - sway_seat_configure_device(seat, seat_device->input_device); } - } diff --git a/sway/meson.build b/sway/meson.build index 3d38c7c9..fee2ddd2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -13,6 +13,7 @@ sway_sources = files( 'commands/input.c', 'commands/seat.c', 'commands/seat/attach.c', + 'commands/seat/fallback.c', 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', -- cgit v1.2.3 From ba69f06695c24f98a05d138a53ba130108ebce6f Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 27 Dec 2017 10:08:18 -0500 Subject: binding config --- include/sway/config.h | 3 +- sway/commands.c | 2 + sway/commands/bind.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++ sway/config.c | 3 +- sway/meson.build | 1 + 5 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 sway/commands/bind.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index 83ded720..7146623e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -46,7 +46,8 @@ struct sway_mouse_binding { */ struct sway_mode { char *name; - list_t *bindings; + list_t *keysym_bindings; + list_t *keycode_bindings; }; /** diff --git a/sway/commands.c b/sway/commands.c index 34afb6a0..b0078a46 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -127,6 +127,8 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color) /* Keep alphabetized */ static struct cmd_handler handlers[] = { + { "bindcode", cmd_bindcode }, + { "bindsym", cmd_bindsym }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, diff --git a/sway/commands/bind.c b/sway/commands/bind.c new file mode 100644 index 00000000..62aa535a --- /dev/null +++ b/sway/commands/bind.c @@ -0,0 +1,173 @@ +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include "util.h" + +int binding_order = 0; + +void free_sway_binding(struct sway_binding *binding) { + if (binding->keys) { + for (int i = 0; i < binding->keys->length; i++) { + free(binding->keys->items[i]); + } + list_free(binding->keys); + } + if (binding->command) { + free(binding->command); + } + free(binding); +} + +struct cmd_results *cmd_bindsym(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { + return error; + } + + struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + binding->keys = create_list(); + binding->modifiers = 0; + binding->release = false; + binding->bindcode = false; + + // Handle --release + if (strcmp("--release", argv[0]) == 0) { + if (argc >= 3) { + binding->release = true; + argv++; + argc--; + } else { + free_sway_binding(binding); + return cmd_results_new(CMD_FAILURE, "bindsym", + "Invalid bindsym command " + "(expected more than 2 arguments, got %d)", argc); + } + } + + binding->command = join_args(argv + 1, argc - 1); + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + // Check for a modifier key + uint32_t mod; + if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { + binding->modifiers |= mod; + continue; + } + // Check for xkb key + xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], + XKB_KEYSYM_CASE_INSENSITIVE); + + // Check for mouse binding + if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && + strlen(split->items[i]) == strlen("button0")) { + sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; + } + if (!sym) { + struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", + "Unknown key '%s'", (char *)split->items[i]); + free_sway_binding(binding); + free_flat_list(split); + return ret; + } + xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); + if (!key) { + free_sway_binding(binding); + free_flat_list(split); + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + *key = sym; + list_add(binding->keys, key); + } + free_flat_list(split); + + struct sway_mode *mode = config->current_mode; + // TODO overwrite the binding if it already exists + binding->order = binding_order++; + list_add(mode->keysym_bindings, binding); + + sway_log(L_DEBUG, "bindsym - Bound %s to command %s", + argv[0], binding->command); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_bindcode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) { + return error; + } + + struct sway_binding *binding = malloc(sizeof(struct sway_binding)); + if (!binding) { + return cmd_results_new(CMD_FAILURE, "bindsym", + "Unable to allocate binding"); + } + binding->keys = create_list(); + binding->modifiers = 0; + binding->release = false; + binding->bindcode = true; + + // Handle --release + if (strcmp("--release", argv[0]) == 0) { + if (argc >= 3) { + binding->release = true; + argv++; + argc--; + } else { + free_sway_binding(binding); + return cmd_results_new(CMD_FAILURE, "bindcode", + "Invalid bindcode command " + "(expected more than 2 arguments, got %d)", argc); + } + } + + binding->command = join_args(argv + 1, argc - 1); + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + // Check for a modifier key + uint32_t mod; + if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { + binding->modifiers |= mod; + continue; + } + // parse keycode + xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); + if (!xkb_keycode_is_legal_ext(keycode)) { + error = + cmd_results_new(CMD_INVALID, "bindcode", + "Invalid keycode '%s'", (char *)split->items[i]); + free_sway_binding(binding); + list_free(split); + return error; + } + xkb_keycode_t *key = malloc(sizeof(xkb_keycode_t)); + *key = keycode - 8; + list_add(binding->keys, key); + } + free_flat_list(split); + + struct sway_mode *mode = config->current_mode; + // TODO overwrite binding if it already exists + binding->order = binding_order++; + list_add(mode->keycode_bindings, binding); + + sway_log(L_DEBUG, "bindcode - Bound %s to command %s", + argv[0], binding->command); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index b591ae9e..312e0779 100644 --- a/sway/config.c +++ b/sway/config.c @@ -53,7 +53,8 @@ static void config_defaults(struct sway_config *config) { goto cleanup; if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; strcpy(config->current_mode->name, "default"); - if (!(config->current_mode->bindings = create_list())) goto cleanup; + if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup; + if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; list_add(config->modes, config->current_mode); config->floating_mod = 0; diff --git a/sway/meson.build b/sway/meson.build index fee2ddd2..01d5ef36 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -6,6 +6,7 @@ sway_sources = files( 'input/seat.c', 'input/cursor.c', 'input/keyboard.c', + 'commands/bind.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', -- cgit v1.2.3 From c83900593daace2ef85174163edf2748179e28f2 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Fri, 29 Dec 2017 15:31:04 +0100 Subject: config: add 'set' command --- include/sway/config.h | 1 + sway/commands.c | 3 ++- sway/commands/set.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ sway/config.c | 7 ++++- sway/meson.build | 1 + 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 sway/commands/set.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index 405092e3..0a9c4595 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -375,6 +375,7 @@ bool read_config(FILE *file, struct sway_config *config); * Free config struct */ void free_config(struct sway_config *config); +void free_sway_variable(struct sway_variable *var); /** * Does variable replacement for a string based on the config's currently loaded variables. */ diff --git a/sway/commands.c b/sway/commands.c index c1c6dc5d..f01329db 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -138,6 +138,7 @@ static struct cmd_handler handlers[] = { { "input", cmd_input }, { "output", cmd_output }, { "seat", cmd_seat }, + { "set", cmd_set }, }; static int handler_compare(const void *_a, const void *_b) { @@ -290,7 +291,7 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) { int i; // Var replacement, for all but first argument of set // TODO commands - for (i = /*handler->handle == cmd_set ? 2 :*/ 1; i < argc; ++i) { + for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { argv[i] = do_var_replacement(argv[i]); unescape_string(argv[i]); } diff --git a/sway/commands/set.c b/sway/commands/set.c new file mode 100644 index 00000000..dcd928ba --- /dev/null +++ b/sway/commands/set.c @@ -0,0 +1,71 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +// sort in order of longest->shortest +static int compare_set_qsort(const void *_l, const void *_r) { + struct sway_variable const *l = *(void **)_l; + struct sway_variable const *r = *(void **)_r; + return strlen(r->name) - strlen(l->name); +} + +void free_sway_variable(struct sway_variable *var) { + if (!var) { + return; + } + free(var->name); + free(var->value); + free(var); +} + +struct cmd_results *cmd_set(int argc, char **argv) { + char *tmp; + struct cmd_results *error = NULL; + if (!config->reading) return cmd_results_new(CMD_FAILURE, "set", "Can only be used in config file."); + if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (argv[0][0] != '$') { + sway_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); + + size_t size = snprintf(NULL, 0, "$%s", argv[0]); + tmp = malloc(size + 1); + if (!tmp) { + return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); + } + snprintf(tmp, size+1, "$%s", argv[0]); + + argv[0] = tmp; + } + + struct sway_variable *var = NULL; + // Find old variable if it exists + int i; + for (i = 0; i < config->symbols->length; ++i) { + var = config->symbols->items[i]; + if (strcmp(var->name, argv[0]) == 0) { + break; + } + var = NULL; + } + if (var) { + free(var->value); + } else { + var = malloc(sizeof(struct sway_variable)); + if (!var) { + return cmd_results_new(CMD_FAILURE, "set", "Unable to allocate variable"); + } + var->name = strdup(argv[0]); + list_add(config->symbols, var); + list_qsort(config->symbols, compare_set_qsort); + } + var->value = join_args(argv + 1, argc - 1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 627ed94f..e0a93e19 100644 --- a/sway/config.c +++ b/sway/config.c @@ -61,7 +61,12 @@ void free_config(struct sway_config *config) { } // TODO: handle all currently unhandled lists as we add implementations - list_free(config->symbols); + if (config->symbols) { + for (i = 0; i < config->symbols->length; i++) { + free_sway_variable(config->symbols->items[i]); + } + list_free(config->symbols); + } if (config->modes) { for (i = 0; i < config->modes->length; i++) { free_mode(config->modes->items[i]); diff --git a/sway/meson.build b/sway/meson.build index 01d5ef36..30ec166b 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -15,6 +15,7 @@ sway_sources = files( 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', + 'commands/set.c', 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', -- cgit v1.2.3 From c353e01c85049cfbc09510657e453b6aa5fd9c2d Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 20 Jan 2018 14:10:11 -0500 Subject: add kill command --- include/sway/config.h | 1 + include/sway/input/input-manager.h | 3 +++ include/sway/view.h | 1 + sway/commands.c | 1 + sway/commands/kill.c | 25 +++++++++++++++++++++++++ sway/desktop/wl_shell.c | 9 +++++++++ sway/desktop/xdg_shell_v6.c | 11 +++++++++++ sway/desktop/xwayland.c | 8 ++++++++ sway/input/input-manager.c | 11 +++++++++++ sway/input/keyboard.c | 9 ++++++--- sway/meson.build | 1 + 11 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 sway/commands/kill.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index 27fae0c6..be29082e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -355,6 +355,7 @@ struct sway_config { struct { struct input_config *input_config; struct seat_config *seat_config; + struct sway_seat *seat; } handler_context; }; diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 58a93fe3..2bf297ce 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -43,4 +43,7 @@ void sway_input_manager_apply_input_config(struct sway_input_manager *input, void sway_input_manager_apply_seat_config(struct sway_input_manager *input, struct seat_config *seat_config); +struct sway_seat *sway_input_manager_get_default_seat( + struct sway_input_manager *input); + #endif diff --git a/include/sway/view.h b/include/sway/view.h index 08c5480b..240ffaa5 100644 --- a/include/sway/view.h +++ b/include/sway/view.h @@ -92,6 +92,7 @@ struct sway_view { void (*set_position)(struct sway_view *view, double ox, double oy); void (*set_activated)(struct sway_view *view, bool activated); + void (*close)(struct sway_view *view); } iface; // only used for unmanaged views (shell specific) diff --git a/sway/commands.c b/sway/commands.c index 414ef809..28943963 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = { { "exit", cmd_exit }, { "include", cmd_include }, { "input", cmd_input }, + { "kill", cmd_kill }, { "output", cmd_output }, { "seat", cmd_seat }, { "set", cmd_set }, diff --git a/sway/commands/kill.c b/sway/commands/kill.c new file mode 100644 index 00000000..4bbf94e5 --- /dev/null +++ b/sway/commands/kill.c @@ -0,0 +1,25 @@ +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/view.h" +#include "sway/commands.h" + +struct cmd_results *cmd_kill(int argc, char **argv) { + struct sway_seat *seat = config->handler_context.seat; + if (!seat) { + seat = sway_input_manager_get_default_seat(input_manager); + } + + // TODO context for arbitrary sway containers (when we get criteria + // working) will make seat context not explicitly required + if (!seat) { + return cmd_results_new(CMD_FAILURE, NULL, "no seat context given"); + } + + struct sway_view *view = seat->focus->sway_view; + + if (view->iface.close) { + view->iface.close(view); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index e34f5160..0cde6583 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -51,6 +51,14 @@ static void set_activated(struct sway_view *view, bool activated) { // no way to activate wl_shell } +static void close(struct sway_view *view) { + if (!assert_wl_shell(view)) { + return; + } + + wl_client_destroy(view->wlr_wl_shell_surface->client); +} + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_wl_shell_surface *sway_surface = wl_container_of(listener, sway_surface, commit); @@ -103,6 +111,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { sway_view->iface.set_size = set_size; sway_view->iface.set_position = set_position; sway_view->iface.set_activated = set_activated; + sway_view->iface.close = close; sway_view->wlr_wl_shell_surface = shell_surface; sway_view->sway_wl_shell_surface = sway_surface; sway_view->surface = shell_surface->surface; diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index df48345c..4b50093f 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -57,6 +57,16 @@ static void set_activated(struct sway_view *view, bool activated) { } } +static void close(struct sway_view *view) { + if (!assert_xdg(view)) { + return; + } + struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6; + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_v6_send_close(surface); + } +} + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_xdg_surface_v6 *sway_surface = wl_container_of(listener, sway_surface, commit); @@ -107,6 +117,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { sway_view->iface.set_size = set_size; sway_view->iface.set_position = set_position; sway_view->iface.set_activated = set_activated; + sway_view->iface.close = close; sway_view->wlr_xdg_surface_v6 = xdg_surface; sway_view->sway_xdg_surface_v6 = sway_surface; sway_view->surface = xdg_surface->surface; diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index a4d9687d..7603d3ca 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -80,6 +80,13 @@ static void set_activated(struct sway_view *view, bool activated) { wlr_xwayland_surface_activate(surface, activated); } +static void close(struct sway_view *view) { + if (!assert_xwayland(view)) { + return; + } + wlr_xwayland_surface_close(view->wlr_xwayland_surface); +} + static void handle_commit(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, commit); @@ -192,6 +199,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { sway_view->iface.set_size = set_size; sway_view->iface.set_position = set_position; sway_view->iface.set_activated = set_activated; + sway_view->iface.close = close; sway_view->wlr_xwayland_surface = xsurface; sway_view->sway_xwayland_surface = sway_surface; sway_view->surface = xsurface->surface; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 26cf5035..7b19991b 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -369,3 +369,14 @@ void sway_input_manager_configure_xcursor(struct sway_input_manager *input) { sway_seat_configure_xcursor(seat); } } + +struct sway_seat *sway_input_manager_get_default_seat( + struct sway_input_manager *input) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (strcmp(seat->wlr_seat->name, "seat0") == 0) { + return seat; + } + } + return seat; +} diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 5827a1ca..6dc57d46 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -89,9 +89,12 @@ static bool binding_matches_key_state(struct sway_binding *binding, return false; } -static void binding_execute_command(struct sway_binding *binding) { +static void keyboard_execute_command(struct sway_keyboard *keyboard, + struct sway_binding *binding) { wlr_log(L_DEBUG, "running command for binding: %s", binding->command); + config_clear_handler_context(config); + config->handler_context.seat = keyboard->seat_device->sway_seat; struct cmd_results *results = handle_command(binding->command); if (results->status != CMD_SUCCESS) { wlr_log(L_DEBUG, "could not run command for binding: %s", @@ -160,7 +163,7 @@ static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard, } if (match) { - binding_execute_command(binding); + keyboard_execute_command(keyboard, binding); return true; } } @@ -267,7 +270,7 @@ static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard, for (int i = 0; i < keycode_bindings->length; ++i) { struct sway_binding *binding = keycode_bindings->items[i]; if (binding_matches_keycodes(wlr_keyboard, binding, event)) { - binding_execute_command(binding); + keyboard_execute_command(keyboard, binding); return true; } } diff --git a/sway/meson.build b/sway/meson.build index 30ec166b..d5dead42 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -10,6 +10,7 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/kill.c', 'commands/include.c', 'commands/input.c', 'commands/seat.c', -- cgit v1.2.3 From 6a1d71b8b8f33bdea3fb41bcd0de9439c0452682 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 20 Jan 2018 16:21:45 -0500 Subject: basic command criteria --- include/sway/config.h | 1 + include/sway/container.h | 2 + include/sway/criteria.h | 42 +++++ sway/commands.c | 68 +++++++- sway/commands/kill.c | 8 +- sway/criteria.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 2 + sway/tree/container.c | 22 +++ 8 files changed, 549 insertions(+), 9 deletions(-) create mode 100644 include/sway/criteria.h create mode 100644 sway/criteria.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index be29082e..d07a71df 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -356,6 +356,7 @@ struct sway_config { struct input_config *input_config; struct seat_config *seat_config; struct sway_seat *seat; + swayc_t *current_container; } handler_context; }; diff --git a/include/sway/container.h b/include/sway/container.h index 9a5e312b..a99e2694 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -145,4 +145,6 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); swayc_t *swayc_at(swayc_t *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); +void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data); + #endif diff --git a/include/sway/criteria.h b/include/sway/criteria.h new file mode 100644 index 00000000..c5ed9857 --- /dev/null +++ b/include/sway/criteria.h @@ -0,0 +1,42 @@ +#ifndef _SWAY_CRITERIA_H +#define _SWAY_CRITERIA_H + +#include "container.h" +#include "list.h" + +/** + * Maps criteria (as a list of criteria tokens) to a command list. + * + * A list of tokens together represent a single criteria string (e.g. + * '[class="abc" title="xyz"]' becomes two criteria tokens). + * + * for_window: Views matching all criteria will have the bound command list + * executed on them. + * + * Set via `for_window `. + */ +struct criteria { + list_t *tokens; // struct crit_token, contains compiled regex. + char *crit_raw; // entire criteria string (for logging) + + char *cmdlist; +}; + +int criteria_cmp(const void *item, const void *data); +void free_criteria(struct criteria *crit); + +// Pouplate list with crit_tokens extracted from criteria string, returns error +// string or NULL if successful. +char *extract_crit_tokens(list_t *tokens, const char *criteria); + +// Returns list of criteria that match given container. These criteria have +// been set with `for_window` commands and have an associated cmdlist. +list_t *criteria_for(swayc_t *cont); + +// Returns a list of all containers that match the given list of tokens. +list_t *container_for(list_t *tokens); + +// Returns true if any criteria in the given list matches this container +bool criteria_any(swayc_t *cont, list_t *criteria); + +#endif diff --git a/sway/commands.c b/sway/commands.c index 28943963..c1e25c5f 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -8,6 +8,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/criteria.h" #include "sway/security.h" #include "sway/input/input-manager.h" #include "stringop.h" @@ -201,9 +202,41 @@ struct cmd_results *handle_command(char *_exec) { char *head = exec; char *cmdlist; char *cmd; + list_t *containers = NULL; head = exec; do { + // Extract criteria (valid for this command list only). + bool has_criteria = false; + if (*head == '[') { + has_criteria = true; + ++head; + char *criteria_string = argsep(&head, "]"); + if (head) { + ++head; + list_t *tokens = create_list(); + char *error; + + if ((error = extract_crit_tokens(tokens, criteria_string))) { + wlr_log(L_DEBUG, "criteria string parse error: %s", error); + results = cmd_results_new(CMD_INVALID, criteria_string, + "Can't parse criteria string: %s", error); + free(error); + free(tokens); + goto cleanup; + } + containers = container_for(tokens); + + free(tokens); + } else { + if (!results) { + results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched ["); + } + goto cleanup; + } + // Skip leading whitespace + head += strspn(head, whitespace); + } // Split command list cmdlist = argsep(&head, ";"); cmdlist += strspn(cmdlist, whitespace); @@ -236,16 +269,35 @@ struct cmd_results *handle_command(char *_exec) { free_argv(argc, argv); goto cleanup; } - struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status != CMD_SUCCESS) { - free_argv(argc, argv); - if (results) { - free_cmd_results(results); + + if (!has_criteria) { + config->handler_context.current_container = NULL; + struct cmd_results *res = handler->handle(argc-1, argv+1); + if (res->status != CMD_SUCCESS) { + free_argv(argc, argv); + if (results) { + free_cmd_results(results); + } + results = res; + goto cleanup; + } + free_cmd_results(res); + } else { + wlr_log(L_DEBUG, "@@ running command on containers"); + for (int i = 0; i < containers->length; ++i) { + config->handler_context.current_container = containers->items[i]; + struct cmd_results *res = handler->handle(argc-1, argv+1); + if (res->status != CMD_SUCCESS) { + free_argv(argc, argv); + if (results) { + free_cmd_results(results); + } + results = res; + goto cleanup; + } + free_cmd_results(res); } - results = res; - goto cleanup; } - free_cmd_results(res); free_argv(argc, argv); } while(cmdlist); } while(head); diff --git a/sway/commands/kill.c b/sway/commands/kill.c index 4bbf94e5..f0e3722a 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -15,7 +15,13 @@ struct cmd_results *cmd_kill(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, NULL, "no seat context given"); } - struct sway_view *view = seat->focus->sway_view; + struct sway_view *view = NULL; + + if (config->handler_context.current_container) { + view = config->handler_context.current_container->sway_view; + } else { + view = seat->focus->sway_view; + } if (view->iface.close) { view->iface.close(view); diff --git a/sway/criteria.c b/sway/criteria.c new file mode 100644 index 00000000..c15f6354 --- /dev/null +++ b/sway/criteria.c @@ -0,0 +1,413 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include "sway/criteria.h" +#include "sway/container.h" +#include "sway/config.h" +#include "sway/view.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +enum criteria_type { // *must* keep in sync with criteria_strings[] + CRIT_APP_ID, + CRIT_CLASS, + CRIT_CON_ID, + CRIT_CON_MARK, + CRIT_FLOATING, + CRIT_ID, + CRIT_INSTANCE, + CRIT_TILING, + CRIT_TITLE, + CRIT_URGENT, + CRIT_WINDOW_ROLE, + CRIT_WINDOW_TYPE, + CRIT_WORKSPACE, + CRIT_LAST +}; + +static const char * const criteria_strings[CRIT_LAST] = { + [CRIT_APP_ID] = "app_id", + [CRIT_CLASS] = "class", + [CRIT_CON_ID] = "con_id", + [CRIT_CON_MARK] = "con_mark", + [CRIT_FLOATING] = "floating", + [CRIT_ID] = "id", + [CRIT_INSTANCE] = "instance", + [CRIT_TILING] = "tiling", + [CRIT_TITLE] = "title", + [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... + [CRIT_WINDOW_ROLE] = "window_role", + [CRIT_WINDOW_TYPE] = "window_type", + [CRIT_WORKSPACE] = "workspace" +}; + +/** + * A single criteria token (ie. value/regex pair), + * e.g. 'class="some class regex"'. + */ +struct crit_token { + enum criteria_type type; + pcre *regex; + char *raw; +}; + +static void free_crit_token(struct crit_token *crit) { + pcre_free(crit->regex); + free(crit->raw); + free(crit); +} + +static void free_crit_tokens(list_t *crit_tokens) { + for (int i = 0; i < crit_tokens->length; i++) { + free_crit_token(crit_tokens->items[i]); + } + list_free(crit_tokens); +} + +// Extracts criteria string from its brackets. Returns new (duplicate) +// substring. +static char *criteria_from(const char *arg) { + char *criteria = NULL; + if (*arg == '[') { + criteria = strdup(arg + 1); + } else { + criteria = strdup(arg); + } + + int last = strlen(criteria) - 1; + if (criteria[last] == ']') { + criteria[last] = '\0'; + } + return criteria; +} + +// Return instances of c found in str. +static int countchr(char *str, char c) { + int found = 0; + for (int i = 0; str[i]; i++) { + if (str[i] == c) { + ++found; + } + } + return found; +} + +// criteria_str is e.g. '[class="some class regex" instance="instance name"]'. +// +// Will create array of pointers in buf, where first is duplicate of given +// string (must be freed) and the rest are pointers to names and values in the +// base string (every other, naturally). argc will be populated with the length +// of buf. +// +// Returns error string or NULL if successful. +static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str) { + wlr_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); + char *base = criteria_from(criteria_str); + char *head = base; + char *namep = head; // start of criteria name + char *valp = NULL; // start of value + + // We're going to place EOS markers where we need to and fill up an array + // of pointers to the start of each token (either name or value). + int pairs = countchr(base, '='); + int max_tokens = pairs * 2 + 1; // this gives us at least enough slots + + char **argv = *buf = calloc(max_tokens, sizeof(char*)); + argv[0] = base; // this needs to be freed by caller + bool quoted = true; + + *argc = 1; // uneven = name, even = value + while (*head && *argc < max_tokens) { + if (namep != head && *(head - 1) == '\\') { + // escaped character: don't try to parse this + } else if (*head == '=' && namep != head) { + if (*argc % 2 != 1) { + // we're not expecting a name + return strdup("Unable to parse criteria: " + "Found out of place equal sign"); + } else { + // name ends here + char *end = head; // don't want to rewind the head + while (*(end - 1) == ' ') { + --end; + } + *end = '\0'; + if (*(namep) == ' ') { + namep = strrchr(namep, ' ') + 1; + } + argv[*argc] = namep; + *argc += 1; + } + } else if (*head == '"') { + if (*argc % 2 != 0) { + // we're not expecting a value + return strdup("Unable to parse criteria: " + "Found quoted value where it was not expected"); + } else if (!valp) { // value starts here + valp = head + 1; + quoted = true; + } else { + // value ends here + argv[*argc] = valp; + *argc += 1; + *head = '\0'; + valp = NULL; + namep = head + 1; + } + } else if (*argc % 2 == 0 && *head != ' ') { + // parse unquoted values + if (!valp) { + quoted = false; + valp = head; // value starts here + } + } else if (valp && !quoted && *head == ' ') { + // value ends here + argv[*argc] = valp; + *argc += 1; + *head = '\0'; + valp = NULL; + namep = head + 1; + } + head++; + } + + // catch last unquoted value if needed + if (valp && !quoted && !*head) { + argv[*argc] = valp; + *argc += 1; + } + + return NULL; +} + +// Returns error string on failure or NULL otherwise. +static char *parse_criteria_name(enum criteria_type *type, char *name) { + *type = CRIT_LAST; + for (int i = 0; i < CRIT_LAST; i++) { + if (strcmp(criteria_strings[i], name) == 0) { + *type = (enum criteria_type) i; + break; + } + } + if (*type == CRIT_LAST) { + const char *fmt = "Criteria type '%s' is invalid or unsupported."; + int len = strlen(name) + strlen(fmt) - 1; + char *error = malloc(len); + snprintf(error, len, fmt, name); + return error; + } else if (*type == CRIT_URGENT || *type == CRIT_WINDOW_ROLE || + *type == CRIT_WINDOW_TYPE) { + // (we're just being helpful here) + const char *fmt = "\"%s\" criteria currently unsupported, " + "no window will match this"; + int len = strlen(fmt) + strlen(name) - 1; + char *error = malloc(len); + snprintf(error, len, fmt, name); + return error; + } + return NULL; +} + +// Returns error string on failure or NULL otherwise. +static char *generate_regex(pcre **regex, char *value) { + const char *reg_err; + int offset; + + *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); + + if (!*regex) { + const char *fmt = "Regex compilation (for '%s') failed: %s"; + int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; + char *error = malloc(len); + snprintf(error, len, fmt, value, reg_err); + return error; + } + return NULL; +} + +// Test whether the criterion corresponds to the currently focused window +static bool crit_is_focused(const char *value) { + return !strcmp(value, "focused") || !strcmp(value, "__focused__"); +} + +// Populate list with crit_tokens extracted from criteria string, returns error +// string or NULL if successful. +char *extract_crit_tokens(list_t *tokens, const char * const criteria) { + int argc; + char **argv = NULL, *error = NULL; + if ((error = crit_tokens(&argc, &argv, criteria))) { + goto ect_cleanup; + } + for (int i = 1; i + 1 < argc; i += 2) { + char* name = argv[i], *value = argv[i + 1]; + struct crit_token *token = calloc(1, sizeof(struct crit_token)); + token->raw = strdup(value); + + if ((error = parse_criteria_name(&token->type, name))) { + free_crit_token(token); + goto ect_cleanup; + } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { + wlr_log(L_DEBUG, "%s -> \"%s\"", name, value); + list_add(tokens, token); + } else if((error = generate_regex(&token->regex, value))) { + free_crit_token(token); + goto ect_cleanup; + } else { + wlr_log(L_DEBUG, "%s -> /%s/", name, value); + list_add(tokens, token); + } + } +ect_cleanup: + free(argv[0]); // base string + free(argv); + return error; +} + +static int regex_cmp(const char *item, const pcre *regex) { + return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); +} + +// test a single view if it matches list of criteria tokens (all of them). +static bool criteria_test(swayc_t *cont, list_t *tokens) { + if (cont->type != C_VIEW) { + return false; + } + struct sway_view *view = cont->sway_view; + + int matches = 0; + for (int i = 0; i < tokens->length; i++) { + struct crit_token *crit = tokens->items[i]; + switch (crit->type) { + case CRIT_CLASS: // TODO + break; + case CRIT_CON_ID: { + char *endptr; + size_t crit_id = strtoul(crit->raw, &endptr, 10); + + if (*endptr == 0 && cont->id == crit_id) { + ++matches; + } + break; + } + case CRIT_CON_MARK: // TODO + break; + case CRIT_FLOATING: // TODO + break; + case CRIT_ID: // TODO + break; + case CRIT_APP_ID: + if (!view->iface.get_prop) { + break; + } + + const char *app_id = + cont->sway_view->iface.get_prop(view, VIEW_PROP_APP_ID); + + if (!app_id) { + break; + } + + if (crit->regex && regex_cmp(app_id, crit->regex) == 0) { + matches++; + } + break; + case CRIT_INSTANCE: // TODO + break; + case CRIT_TILING: // TODO + break; + case CRIT_TITLE: + if (!cont->name) { + // ignore + } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { + matches++; + } + break; + case CRIT_URGENT: // "latest" or "oldest" + break; + case CRIT_WINDOW_ROLE: + break; + case CRIT_WINDOW_TYPE: + break; + case CRIT_WORKSPACE: // TODO + break; + default: + sway_abort("Invalid criteria type (%i)", crit->type); + break; + } + } + return matches == tokens->length; +} + +int criteria_cmp(const void *a, const void *b) { + if (a == b) { + return 0; + } else if (!a) { + return -1; + } else if (!b) { + return 1; + } + const struct criteria *crit_a = a, *crit_b = b; + int cmp = lenient_strcmp(crit_a->cmdlist, crit_b->cmdlist); + if (cmp != 0) { + return cmp; + } + return lenient_strcmp(crit_a->crit_raw, crit_b->crit_raw); +} + +void free_criteria(struct criteria *crit) { + if (crit->tokens) { + free_crit_tokens(crit->tokens); + } + if (crit->cmdlist) { + free(crit->cmdlist); + } + if (crit->crit_raw) { + free(crit->crit_raw); + } + free(crit); +} + +bool criteria_any(swayc_t *cont, list_t *criteria) { + for (int i = 0; i < criteria->length; i++) { + struct criteria *bc = criteria->items[i]; + if (criteria_test(cont, bc->tokens)) { + return true; + } + } + return false; +} + +list_t *criteria_for(swayc_t *cont) { + list_t *criteria = config->criteria, *matches = create_list(); + for (int i = 0; i < criteria->length; i++) { + struct criteria *bc = criteria->items[i]; + if (criteria_test(cont, bc->tokens)) { + list_add(matches, bc); + } + } + return matches; +} + +struct list_tokens { + list_t *list; + list_t *tokens; +}; + +static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { + if (criteria_test(container, list_tokens->tokens)) { + list_add(list_tokens->list, container); + } +} + +list_t *container_for(list_t *tokens) { + struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; + + container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); + + // TODO look in the scratchpad + + return list_tokens.list; +} diff --git a/sway/meson.build b/sway/meson.build index d5dead42..46d79d44 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -38,6 +38,7 @@ sway_sources = files( 'config/output.c', 'config/seat.c', 'config/input.c', + 'criteria.c', 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', @@ -51,6 +52,7 @@ sway_sources = files( ) sway_deps = [ + pcre, pixman, wayland_server, jsonc, diff --git a/sway/tree/container.c b/sway/tree/container.c index d241f69a..e224539f 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -321,3 +321,25 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, return NULL; } + +void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) { + if (container) { + int i; + if (container->children) { + for (i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + container_map(child, f, data); + } + } + // TODO + /* + if (container->floating) { + for (i = 0; i < container->floating->length; ++i) { + swayc_t *child = container->floating->items[i]; + container_map(child, f, data); + } + } + */ + f(container, data); + } +} -- cgit v1.2.3 From 0e3eae4baa7717321ec87cf2c46f6798e89e3ded Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 21 Jan 2018 09:09:53 -0500 Subject: view interface --- include/sway/view.h | 16 ++++++++++++++++ sway/commands/kill.c | 4 ++-- sway/criteria.c | 20 ++++++++----------- sway/input/seat.c | 5 ++--- sway/meson.build | 1 + sway/tree/container.c | 2 +- sway/tree/layout.c | 8 ++++---- sway/tree/view.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 87 insertions(+), 22 deletions(-) create mode 100644 sway/tree/view.c (limited to 'sway/meson.build') diff --git a/include/sway/view.h b/include/sway/view.h index 240ffaa5..ac33e11a 100644 --- a/include/sway/view.h +++ b/include/sway/view.h @@ -99,4 +99,20 @@ struct sway_view { struct wl_list unmanaged_view_link; // sway_root::unmanaged views }; +const char *view_get_title(struct sway_view *view); + +const char *view_get_app_id(struct sway_view *view); + +const char *view_get_class(struct sway_view *view); + +const char *view_get_instance(struct sway_view *view); + +void view_set_size(struct sway_view *view, int width, int height); + +void view_set_position(struct sway_view *view, double ox, double oy); + +void view_set_activated(struct sway_view *view, bool activated); + +void view_close(struct sway_view *view); + #endif diff --git a/sway/commands/kill.c b/sway/commands/kill.c index a04c21f3..62a3a514 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -15,8 +15,8 @@ struct cmd_results *cmd_kill(int argc, char **argv) { struct sway_view *view = config->handler_context.current_container->sway_view; - if (view && view->iface.close) { - view->iface.close(view); + if (view) { + view_close(view); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/criteria.c b/sway/criteria.c index c15f6354..21278a94 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -299,21 +299,17 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { case CRIT_ID: // TODO break; case CRIT_APP_ID: - if (!view->iface.get_prop) { - break; - } - - const char *app_id = - cont->sway_view->iface.get_prop(view, VIEW_PROP_APP_ID); + { + const char *app_id = view_get_app_id(cont->sway_view); + if (!app_id) { + break; + } - if (!app_id) { + if (crit->regex && regex_cmp(app_id, crit->regex) == 0) { + matches++; + } break; } - - if (crit->regex && regex_cmp(app_id, crit->regex) == 0) { - matches++; - } - break; case CRIT_INSTANCE: // TODO break; case CRIT_TILING: // TODO diff --git a/sway/input/seat.c b/sway/input/seat.c index d24a6c7a..ae6dc7c4 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -214,7 +214,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { if (container) { struct sway_view *view = container->sway_view; - view->iface.set_activated(view, true); + view_set_activated(view, true); wl_signal_add(&container->events.destroy, &seat->focus_destroy); seat->focus_destroy.notify = handle_focus_destroy; @@ -234,8 +234,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { if (last_focus && !sway_input_manager_has_focus(seat->input, last_focus)) { struct sway_view *view = last_focus->sway_view; - view->iface.set_activated(view, false); - + view_set_activated(view, false); } } diff --git a/sway/meson.build b/sway/meson.build index 46d79d44..80ccc01d 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -48,6 +48,7 @@ sway_sources = files( 'security.c', 'tree/container.c', 'tree/layout.c', + 'tree/view.c', 'tree/workspace.c', ) diff --git a/sway/tree/container.c b/sway/tree/container.c index e224539f..b7b9bc68 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -157,7 +157,7 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) { if (!sway_assert(sibling, "new_view called with NULL sibling/parent")) { return NULL; } - const char *title = sway_view->iface.get_prop(sway_view, VIEW_PROP_TITLE); + const char *title = view_get_title(sway_view); swayc_t *swayc = new_swayc(C_VIEW); wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d", swayc, title, sibling, sibling ? sibling->type : 0); diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 01535f2d..41ff81b2 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -191,8 +191,8 @@ void arrange_windows(swayc_t *container, double width, double height) { { container->width = width; container->height = height; - container->sway_view->iface.set_size(container->sway_view, - container->width, container->height); + view_set_size(container->sway_view, + container->width, container->height); wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", container->width, container->height, container->x, container->y); @@ -251,7 +251,7 @@ static void apply_horiz_layout(swayc_t *container, wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); - child->sway_view->iface.set_position(child->sway_view, child_x, y); + view_set_position(child->sway_view, child_x, y); if (i == end - 1) { double remaining_width = x + width - child_x; @@ -301,7 +301,7 @@ void apply_vert_layout(swayc_t *container, wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); - child->sway_view->iface.set_position(child->sway_view, x, child_y); + view_set_position(child->sway_view, x, child_y); if (i == end - 1) { double remaining_height = y + height - child_y; diff --git a/sway/tree/view.c b/sway/tree/view.c new file mode 100644 index 00000000..b46c3b17 --- /dev/null +++ b/sway/tree/view.c @@ -0,0 +1,53 @@ +#include "sway/view.h" + +const char *view_get_title(struct sway_view *view) { + if (view->iface.get_prop) { + return view->iface.get_prop(view, VIEW_PROP_TITLE); + } + return NULL; +} + +const char *view_get_app_id(struct sway_view *view) { + if (view->iface.get_prop) { + return view->iface.get_prop(view, VIEW_PROP_APP_ID); + } + return NULL; +} + +const char *view_get_class(struct sway_view *view) { + if (view->iface.get_prop) { + return view->iface.get_prop(view, VIEW_PROP_CLASS); + } + return NULL; +} + +const char *view_get_instance(struct sway_view *view) { + if (view->iface.get_prop) { + return view->iface.get_prop(view, VIEW_PROP_INSTANCE); + } + return NULL; +} + +void view_set_size(struct sway_view *view, int width, int height) { + if (view->iface.set_size) { + view->iface.set_size(view, width, height); + } +} + +void view_set_position(struct sway_view *view, double ox, double oy) { + if (view->iface.set_position) { + view->iface.set_position(view, ox, oy); + } +} + +void view_set_activated(struct sway_view *view, bool activated) { + if (view->iface.set_activated) { + view->iface.set_activated(view, activated); + } +} + +void view_close(struct sway_view *view) { + if (view->iface.close) { + view->iface.close(view); + } +} -- cgit v1.2.3 From 869be4378d44e08c686b550a86a5e4fa60915edb Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Fri, 5 Jan 2018 22:05:48 +0100 Subject: commands: add 'reload' command --- sway/commands.c | 1 + sway/commands/reload.c | 21 +++++++++++++++++++++ sway/config.c | 4 ++++ sway/meson.build | 1 + 4 files changed, 27 insertions(+) create mode 100644 sway/commands/reload.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index a77ff791..d4262c08 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -136,6 +136,7 @@ static struct cmd_handler handlers[] = { { "input", cmd_input }, { "kill", cmd_kill }, { "output", cmd_output }, + { "reload", cmd_reload }, { "seat", cmd_seat }, { "set", cmd_set }, }; diff --git a/sway/commands/reload.c b/sway/commands/reload.c new file mode 100644 index 00000000..2b553845 --- /dev/null +++ b/sway/commands/reload.c @@ -0,0 +1,21 @@ +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/layout.h" + +struct cmd_results *cmd_reload(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "reload", "Can't be used in config file."); + } + if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { + return error; + } + if (!load_main_config(config->current_config, true)) { + return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); + } + + load_swaybars(); + + arrange_windows(&root_container, -1, -1); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 1fd123b7..cb22f664 100644 --- a/sway/config.c +++ b/sway/config.c @@ -698,3 +698,7 @@ char *do_var_replacement(char *str) { } return str; } + +void load_swaybars() { + /* stub function for reload commnd, to fill when we restore swaybars */ +} diff --git a/sway/meson.build b/sway/meson.build index 80ccc01d..51e9e4db 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -34,6 +34,7 @@ sway_sources = files( 'commands/input/xkb_rules.c', 'commands/input/xkb_variant.c', 'commands/output.c', + 'commands/reload.c', 'config.c', 'config/output.c', 'config/seat.c', -- cgit v1.2.3 From b28602aa7425cf435150e6008624429737e037d3 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 30 Jan 2018 23:09:21 -0500 Subject: Implement workspaces --- include/sway/container.h | 19 +++- include/sway/input/input-manager.h | 4 + include/sway/workspace.h | 14 +++ sway/commands.c | 1 + sway/commands/kill.c | 7 +- sway/commands/workspace.c | 101 ++++++++++++++++++ sway/config.c | 15 ++- sway/desktop/output.c | 4 +- sway/desktop/xdg_shell_v6.c | 9 +- sway/input/input-manager.c | 8 ++ sway/input/seat.c | 15 ++- sway/meson.build | 1 + sway/tree/container.c | 41 ++++++- sway/tree/workspace.c | 211 +++++++++++++++++++++++++++++++++++++ 14 files changed, 420 insertions(+), 30 deletions(-) create mode 100644 sway/commands/workspace.c (limited to 'sway/meson.build') diff --git a/include/sway/container.h b/include/sway/container.h index a99e2694..0c66932d 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -11,6 +11,7 @@ typedef struct sway_container swayc_t; extern swayc_t root_container; struct sway_view; +struct sway_seat; /** * Different kinds of containers. @@ -140,11 +141,25 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view); swayc_t *destroy_output(swayc_t *output); swayc_t *destroy_view(swayc_t *view); +swayc_t *next_view_sibling(struct sway_seat *seat); + +/** + * Finds a container based on test criteria. Returns the first container that + * passes the test. + */ +swayc_t *swayc_by_test(swayc_t *container, + bool (*test)(swayc_t *view, void *data), void *data); +/** + * Finds a parent container with the given swayc_type. + */ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); +/** + * Maps a container's children over a function. + */ +void container_map(swayc_t *container, + void (*f)(swayc_t *view, void *data), void *data); swayc_t *swayc_at(swayc_t *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); -void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data); - #endif diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 63806b8e..66ace262 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -48,4 +48,8 @@ struct sway_seat *sway_input_manager_get_default_seat( struct sway_seat *input_manager_get_seat(struct sway_input_manager *input, const char *seat_name); + +/** Gets the last seat the user interacted with */ +struct sway_seat *input_manager_current_seat(struct sway_input_manager *input); + #endif diff --git a/include/sway/workspace.h b/include/sway/workspace.h index 04b2ea4e..30bbdaa8 100644 --- a/include/sway/workspace.h +++ b/include/sway/workspace.h @@ -1,6 +1,20 @@ #ifndef _SWAY_WORKSPACE_H #define _SWAY_WORKSPACE_H +struct sway_container; + +extern char *prev_workspace_name; + char *workspace_next_name(const char *output_name); +swayc_t *workspace_create(const char *name); +bool workspace_switch(swayc_t *workspace); + +struct sway_container *workspace_by_number(const char* name); +swayc_t *workspace_by_name(const char*); + +struct sway_container *workspace_output_next(struct sway_container *current); +struct sway_container *workspace_next(struct sway_container *current); +struct sway_container *workspace_output_prev(struct sway_container *current); +struct sway_container *workspace_prev(struct sway_container *current); #endif diff --git a/sway/commands.c b/sway/commands.c index d4262c08..0d4aa104 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -139,6 +139,7 @@ static struct cmd_handler handlers[] = { { "reload", cmd_reload }, { "seat", cmd_seat }, { "set", cmd_set }, + { "workspace", cmd_workspace }, }; static int handler_compare(const void *_a, const void *_b) { diff --git a/sway/commands/kill.c b/sway/commands/kill.c index 3804f0b0..cebf7f3c 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -10,11 +10,10 @@ struct cmd_results *cmd_kill(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, "kill", "Command 'kill' cannot be used in the config file"); } - if (!sway_assert(config->handler_context.current_container, - "cmd_kill called without container context")) { + enum swayc_types type = config->handler_context.current_container->type; + if (type != C_VIEW || type != C_CONTAINER) { return cmd_results_new(CMD_INVALID, NULL, - "cmd_kill called without container context " - "(this is a bug in sway)"); + "Can only kill views and containers with this command"); } // TODO close arbitrary containers without a view struct sway_view *view = diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c new file mode 100644 index 00000000..12984ed4 --- /dev/null +++ b/sway/commands/workspace.c @@ -0,0 +1,101 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/input/seat.h" +#include "sway/workspace.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_workspace(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { + return error; + } + + int output_location = -1; + + swayc_t *current_container = config->handler_context.current_container; + swayc_t *old_workspace = NULL, *old_output = NULL; + if (current_container) { + if (current_container->type == C_WORKSPACE) { + old_workspace = current_container; + } else { + old_workspace = swayc_parent_by_type(current_container, C_WORKSPACE); + } + old_output = swayc_parent_by_type(current_container, C_OUTPUT); + } + + for (int i = 0; i < argc; ++i) { + if (strcasecmp(argv[i], "output") == 0) { + output_location = i; + break; + } + } + if (output_location >= 0) { + if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { + return error; + } + struct workspace_output *wso = calloc(1, sizeof(struct workspace_output)); + if (!wso) { + return cmd_results_new(CMD_FAILURE, "workspace output", + "Unable to allocate workspace output"); + } + wso->workspace = join_args(argv, argc - 2); + wso->output = strdup(argv[output_location + 1]); + int i = -1; + if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) { + struct workspace_output *old = config->workspace_outputs->items[i]; + free(old); // workspaces can only be assigned to a single output + list_del(config->workspace_outputs, i); + } + wlr_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); + list_add(config->workspace_outputs, wso); + } else { + if (config->reading || !config->active) { + return cmd_results_new(CMD_DEFER, "workspace", NULL); + } + swayc_t *ws = NULL; + if (strcasecmp(argv[0], "number") == 0) { + if (!(ws = workspace_by_number(argv[1]))) { + char *name = join_args(argv + 1, argc - 1); + ws = workspace_create(name); + free(name); + } + } else if (strcasecmp(argv[0], "next") == 0) { + ws = workspace_next(old_workspace); + } else if (strcasecmp(argv[0], "prev") == 0) { + ws = workspace_prev(old_workspace); + } else if (strcasecmp(argv[0], "next_on_output") == 0) { + ws = workspace_output_next(old_output); + } else if (strcasecmp(argv[0], "prev_on_output") == 0) { + ws = workspace_output_prev(old_output); + } else if (strcasecmp(argv[0], "back_and_forth") == 0) { + // if auto_back_and_forth is enabled, workspace_switch will swap + // the workspaces. If we created prev_workspace here, workspace_switch + // would put us back on original workspace. + if (config->auto_back_and_forth) { + ws = old_workspace; + } else if (prev_workspace_name + && !(ws = workspace_by_name(prev_workspace_name))) { + ws = workspace_create(prev_workspace_name); + } + } else { + char *name = join_args(argv, argc); + if (!(ws = workspace_by_name(name))) { + ws = workspace_create(name); + } + free(name); + } + workspace_switch(ws); + current_container = config->handler_context.seat->focus; + swayc_t *new_output = swayc_parent_by_type(current_container, C_OUTPUT); + + if (config->mouse_warping && old_output != new_output) { + // TODO: Warp mouse + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index a67322d1..213e7680 100644 --- a/sway/config.c +++ b/sway/config.c @@ -318,10 +318,6 @@ static bool load_config(const char *path, struct sway_config *config) { return true; } -static int qstrcmp(const void* a, const void* b) { - return strcmp(*((char**) a), *((char**) b)); -} - bool load_main_config(const char *file, bool is_active) { char *path; if (file != NULL) { @@ -349,7 +345,9 @@ bool load_main_config(const char *file, bool is_active) { config->reading = true; // Read security configs + // TODO: Security bool success = true; + /* DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); if (!dir) { wlr_log(L_ERROR, @@ -392,6 +390,7 @@ bool load_main_config(const char *file, bool is_active) { free_flat_list(secconfigs); } + */ success = success && load_config(path, config); @@ -717,3 +716,11 @@ char *do_var_replacement(char *str) { } return str; } + +// the naming is intentional (albeit long): a workspace_output_cmp function +// would compare two structs in full, while this method only compares the +// workspace. +int workspace_output_cmp_workspace(const void *a, const void *b) { + const struct workspace_output *wsa = a, *wsb = b; + return lenient_strcmp(wsa->workspace, wsb->workspace); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0f00222b..a650665f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -219,8 +219,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_output_make_current(wlr_output); wlr_renderer_begin(server->renderer, wlr_output); - swayc_descendants_of_type( - &root_container, C_VIEW, output_frame_view, soutput); + swayc_t *workspace = soutput->swayc->focused; + swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); // render unmanaged views on top struct sway_view *view; diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 4b50093f..ca56a9c0 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -124,8 +124,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { sway_surface->view = sway_view; // TODO: - // - Wire up listeners - // - Handle popups // - Look up pid and open on appropriate workspace // - Set new view to maximized so it behaves nicely // - Criteria @@ -136,11 +134,8 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { sway_surface->destroy.notify = handle_destroy; wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); - // TODO: actual focus semantics - swayc_t *parent = root_container.children->items[0]; - parent = parent->children->items[0]; // workspace - - swayc_t *cont = new_view(parent, sway_view); + struct sway_seat *seat = input_manager_current_seat(input_manager); + swayc_t *cont = new_view(seat->focus, sway_view); sway_view->swayc = cont; arrange_windows(cont->parent, -1, -1); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 12b3a430..d789c7eb 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -23,6 +23,14 @@ struct sway_input_manager *input_manager; struct input_config *current_input_config = NULL; struct seat_config *current_seat_config = NULL; +struct sway_seat *input_manager_current_seat(struct sway_input_manager *input) { + struct sway_seat *seat = config->handler_context.seat; + if (!seat) { + seat = sway_input_manager_get_default_seat(input_manager); + } + return seat; +} + struct sway_seat *input_manager_get_seat( struct sway_input_manager *input, const char *seat_name) { struct sway_seat *seat = NULL; diff --git a/sway/input/seat.c b/sway/input/seat.c index 9ea08eec..5e87986d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,6 +1,7 @@ #define _XOPEN_SOURCE 700 #include #include +#include "sway/container.h" #include "sway/input/seat.h" #include "sway/input/cursor.h" #include "sway/input/input-manager.h" @@ -81,7 +82,7 @@ static void seat_configure_keyboard(struct sway_seat *seat, sway_keyboard_configure(seat_device->keyboard); wlr_seat_set_keyboard(seat->wlr_seat, seat_device->input_device->wlr_device); - if (seat->focus) { + if (seat->focus && seat->focus->type == C_VIEW) { // force notify reenter to pick up the new configuration wlr_seat_keyboard_clear_focus(seat->wlr_seat); wlr_seat_keyboard_notify_enter(seat->wlr_seat, @@ -205,10 +206,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { static void handle_focus_destroy(struct wl_listener *listener, void *data) { struct sway_seat *seat = wl_container_of(listener, seat, focus_destroy); - //swayc_t *container = data; - - // TODO set new focus based on the state of the tree - sway_seat_set_focus(seat, NULL); + swayc_t *container = data; + sway_seat_set_focus(seat, container->parent); } void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { @@ -218,11 +217,11 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { return; } - if (last_focus) { + if (last_focus && last_focus->type == C_VIEW) { wl_list_remove(&seat->focus_destroy.link); } - if (container) { + if (container && container->type == C_VIEW) { struct sway_view *view = container->sway_view; view_set_activated(view, true); wl_signal_add(&container->events.destroy, &seat->focus_destroy); @@ -241,7 +240,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) { seat->focus = container; - if (last_focus && + if (last_focus && last_focus->type == C_VIEW && !sway_input_manager_has_focus(seat->input, last_focus)) { struct sway_view *view = last_focus->sway_view; view_set_activated(view, false); diff --git a/sway/meson.build b/sway/meson.build index 51e9e4db..271d4a99 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -35,6 +35,7 @@ sway_sources = files( 'commands/input/xkb_variant.c', 'commands/output.c', 'commands/reload.c', + 'commands/workspace.c', 'config.c', 'config/output.c', 'config/seat.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index b7b9bc68..48aabd86 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -3,10 +3,13 @@ #include #include #include +#include #include #include #include "sway/config.h" #include "sway/container.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" #include "sway/layout.h" #include "sway/output.h" #include "sway/server.h" @@ -14,6 +17,26 @@ #include "sway/workspace.h" #include "log.h" +swayc_t *swayc_by_test(swayc_t *container, + bool (*test)(swayc_t *view, void *data), void *data) { + if (!container->children) { + return NULL; + } + // TODO: floating windows + for (int i = 0; i < container->children->length; ++i) { + swayc_t *child = container->children->items[i]; + if (test(child, data)) { + return child; + } else { + swayc_t *res = swayc_by_test(child, test, data); + if (res) { + return res; + } + } + } + return NULL; +} + void swayc_descendants_of_type(swayc_t *root, enum swayc_types type, void (*func)(swayc_t *item, void *data), void *data) { for (int i = 0; i < root->children->length; ++i) { @@ -127,7 +150,19 @@ swayc_t *new_output(struct sway_output *sway_output) { // Create workspace char *ws_name = workspace_next_name(output->name); wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); - new_workspace(output, ws_name); + swayc_t *ws = new_workspace(output, ws_name); + output->focused = ws; + // Set each seat's focus if not already set + // TODO FOCUS: this is probably stupid, we shouldn't define focus in two + // places. We should probably put the active workspace on the sway_output + // struct instead of trying to do focus semantics like this + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input_manager->seats, link) { + if (!seat->focus) { + seat->focus = ws; + } + } + free(ws_name); return output; } @@ -159,8 +194,8 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) { } const char *title = view_get_title(sway_view); swayc_t *swayc = new_swayc(C_VIEW); - wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d", - swayc, title, sibling, sibling ? sibling->type : 0); + wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d %s", + swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); // Setup values swayc->sway_view = sway_view; swayc->name = title ? strdup(title) : NULL; diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index c37a873c..23c630b6 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -2,8 +2,20 @@ #include #include #include +#include #include "sway/container.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/workspace.h" #include "log.h" +#include "util.h" + +char *prev_workspace_name = NULL; +struct workspace_by_number_data { + int len; + const char *cset; + const char *name; +}; void next_name_map(swayc_t *ws, void *data) { int *count = data; @@ -24,3 +36,202 @@ char *workspace_next_name(const char *output_name) { snprintf(name, len + 1, "%d", count); return name; } + +static bool _workspace_by_number(swayc_t *view, void *data) { + if (view->type != C_WORKSPACE) { + return false; + } + struct workspace_by_number_data *wbnd = data; + int a = strspn(view->name, wbnd->cset); + return a == wbnd->len && strncmp(view->name, wbnd->name, a) == 0; +} + +swayc_t *workspace_by_number(const char* name) { + struct workspace_by_number_data wbnd = {0, "1234567890", name}; + wbnd.len = strspn(name, wbnd.cset); + if (wbnd.len <= 0) { + return NULL; + } + return swayc_by_test(&root_container, _workspace_by_number, (void *) &wbnd); +} + +static bool _workspace_by_name(swayc_t *view, void *data) { + return (view->type == C_WORKSPACE) && + (strcasecmp(view->name, (char *) data) == 0); +} + +swayc_t *workspace_by_name(const char *name) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + swayc_t *current_workspace = NULL, *current_output = NULL; + if (seat->focus) { + current_workspace = swayc_parent_by_type(seat->focus, C_WORKSPACE); + current_output = swayc_parent_by_type(seat->focus, C_OUTPUT); + } + if (strcmp(name, "prev") == 0) { + return workspace_prev(current_workspace); + } else if (strcmp(name, "prev_on_output") == 0) { + return workspace_output_prev(current_output); + } else if (strcmp(name, "next") == 0) { + return workspace_next(current_workspace); + } else if (strcmp(name, "next_on_output") == 0) { + return workspace_output_next(current_output); + } else if (strcmp(name, "current") == 0) { + return current_workspace; + } else { + return swayc_by_test(&root_container, _workspace_by_name, (void *) name); + } +} + +swayc_t *workspace_create(const char *name) { + swayc_t *parent; + // Search for workspace<->output pair + int i, e = config->workspace_outputs->length; + for (i = 0; i < e; ++i) { + struct workspace_output *wso = config->workspace_outputs->items[i]; + if (strcasecmp(wso->workspace, name) == 0) { + // Find output to use if it exists + e = root_container.children->length; + for (i = 0; i < e; ++i) { + parent = root_container.children->items[i]; + if (strcmp(parent->name, wso->output) == 0) { + return new_workspace(parent, name); + } + } + break; + } + } + // Otherwise create a new one + struct sway_seat *seat = input_manager_current_seat(input_manager); + parent = seat->focus; + parent = swayc_parent_by_type(parent, C_OUTPUT); + return new_workspace(parent, name); +} + +/** + * Get the previous or next workspace on the specified output. Wraps around at + * the end and beginning. If next is false, the previous workspace is returned, + * otherwise the next one is returned. + */ +swayc_t *workspace_output_prev_next_impl(swayc_t *output, bool next) { + if (!sway_assert(output->type == C_OUTPUT, + "Argument must be an output, is %d", output->type)) { + return NULL; + } + + int i; + for (i = 0; i < output->children->length; i++) { + if (output->children->items[i] == output->focused) { + return output->children->items[ + wrap(i + (next ? 1 : -1), output->children->length)]; + } + } + + // Doesn't happen, at worst the for loop returns the previously active workspace + return NULL; +} + +/** + * Get the previous or next workspace. If the first/last workspace on an output + * is active, proceed to the previous/next output's previous/next workspace. If + * next is false, the previous workspace is returned, otherwise the next one is + * returned. + */ +swayc_t *workspace_prev_next_impl(swayc_t *workspace, bool next) { + if (!sway_assert(workspace->type == C_WORKSPACE, + "Argument must be a workspace, is %d", workspace->type)) { + return NULL; + } + + swayc_t *current_output = workspace->parent; + int offset = next ? 1 : -1; + int start = next ? 0 : 1; + int end; + if (next) { + end = current_output->children->length - 1; + } else { + end = current_output->children->length; + } + int i; + for (i = start; i < end; i++) { + if (current_output->children->items[i] == workspace) { + return current_output->children->items[i + offset]; + } + } + + // Given workspace is the first/last on the output, jump to the previous/next output + int num_outputs = root_container.children->length; + for (i = 0; i < num_outputs; i++) { + if (root_container.children->items[i] == current_output) { + swayc_t *next_output = root_container.children->items[ + wrap(i + offset, num_outputs)]; + return workspace_output_prev_next_impl(next_output, next); + } + } + + // Doesn't happen, at worst the for loop returns the previously active workspace on the active output + return NULL; +} + +swayc_t *workspace_output_next(swayc_t *current) { + return workspace_output_prev_next_impl(current, true); +} + +swayc_t *workspace_next(swayc_t *current) { + return workspace_prev_next_impl(current, true); +} + +swayc_t *workspace_output_prev(swayc_t *current) { + return workspace_output_prev_next_impl(current, false); +} + +swayc_t *workspace_prev(swayc_t *current) { + return workspace_prev_next_impl(current, false); +} + +bool workspace_switch(swayc_t *workspace) { + if (!workspace) { + return false; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (!seat || !seat->focus) { + return false; + } + swayc_t *active_ws = seat->focus; + if (active_ws->type != C_WORKSPACE) { + swayc_parent_by_type(seat->focus, C_WORKSPACE); + } + + if (config->auto_back_and_forth + && active_ws == workspace + && prev_workspace_name) { + swayc_t *new_ws = workspace_by_name(prev_workspace_name); + workspace = new_ws ? new_ws : workspace_create(prev_workspace_name); + } + + if (!prev_workspace_name || (strcmp(prev_workspace_name, active_ws->name) + && active_ws != workspace)) { + free(prev_workspace_name); + prev_workspace_name = malloc(strlen(active_ws->name) + 1); + if (!prev_workspace_name) { + wlr_log(L_ERROR, "Unable to allocate previous workspace name"); + return false; + } + strcpy(prev_workspace_name, active_ws->name); + } + + // TODO: Deal with sticky containers + + wlr_log(L_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); + // TODO FOCUS: Focus the last view this seat had focused on this workspace + if (workspace->children->length) { + // TODO FOCUS: This is really fucking stupid + sway_seat_set_focus(seat, workspace->children->items[0]); + } else { + sway_seat_set_focus(seat, workspace); + } + swayc_t *output = swayc_parent_by_type(workspace, C_OUTPUT); + // TODO FOCUS: take a look at this + output->focused = workspace; + arrange_windows(output, -1, -1); + return true; +} -- cgit v1.2.3 From 52670c636cf5115560ce6d20e2aaab1d55c49d0b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 14 Feb 2018 16:47:23 -0500 Subject: basic focus (without direction) --- sway/commands.c | 1 + sway/commands/focus.c | 32 ++++++++++++++++++++++++++++++++ sway/ipc-server.c | 1 + sway/meson.build | 1 + 4 files changed, 35 insertions(+) create mode 100644 sway/commands/focus.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index d8d29a1c..bc2a85d7 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -132,6 +132,7 @@ static struct cmd_handler handlers[] = { { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, { "exit", cmd_exit }, + { "focus", cmd_focus }, { "include", cmd_include }, { "input", cmd_input }, { "kill", cmd_kill }, diff --git a/sway/commands/focus.c b/sway/commands/focus.c new file mode 100644 index 00000000..5286851f --- /dev/null +++ b/sway/commands/focus.c @@ -0,0 +1,32 @@ +#include +#include "log.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/view.h" +#include "sway/commands.h" + +struct cmd_results *cmd_focus(int argc, char **argv) { + swayc_t *con = config->handler_context.current_container; + struct sway_seat *seat = config->handler_context.seat; + + if (!sway_assert(seat, "'focus' command called without seat context")) { + return cmd_results_new(CMD_FAILURE, "focus", + "Command 'focus' called without seat context (this is a bug in sway)"); + } + + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "focus", + "Command 'focus' cannot be used in the config file"); + } + if (con == NULL) { + wlr_log(L_DEBUG, "no container to focus"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + if (argc == 0) { + sway_seat_set_focus(seat, con); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index a16a2b80..ee259c99 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -336,6 +336,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_COMMAND: { config_clear_handler_context(config); + config->handler_context.seat = input_manager_current_seat(input_manager); struct cmd_results *results = handle_command(buf); const char *json = cmd_results_to_json(results); char reply[256]; diff --git a/sway/meson.build b/sway/meson.build index 271d4a99..8d5a97d2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -10,6 +10,7 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/focus.c', 'commands/kill.c', 'commands/include.c', 'commands/input.c', -- cgit v1.2.3 From 66d1e0b313c6bbee142bb08e4af07ce6f15cffca Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 22 Feb 2018 18:03:46 -0500 Subject: basic layout command --- include/sway/container.h | 2 ++ sway/commands.c | 1 + sway/commands/layout.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + sway/tree/container.c | 12 +++++++++ 5 files changed, 81 insertions(+) create mode 100644 sway/commands/layout.c (limited to 'sway/meson.build') diff --git a/include/sway/container.h b/include/sway/container.h index 48363be6..f200a1a2 100644 --- a/include/sway/container.h +++ b/include/sway/container.h @@ -164,4 +164,6 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly, void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), void *data); +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout); + #endif diff --git a/sway/commands.c b/sway/commands.c index bc2a85d7..a7eb6b4a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -136,6 +136,7 @@ static struct cmd_handler handlers[] = { { "include", cmd_include }, { "input", cmd_input }, { "kill", cmd_kill }, + { "layout", cmd_layout }, { "output", cmd_output }, { "reload", cmd_reload }, { "seat", cmd_seat }, diff --git a/sway/commands/layout.c b/sway/commands/layout.c new file mode 100644 index 00000000..d953abc8 --- /dev/null +++ b/sway/commands/layout.c @@ -0,0 +1,65 @@ +#include +#include +#include "sway/commands.h" +#include "sway/container.h" +#include "sway/layout.h" +#include "log.h" + +struct cmd_results *cmd_layout(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); + } + if (!config->active) { + return cmd_results_new(CMD_FAILURE, "layout", "Can only be used when sway is running."); + } + if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { + return error; + } + swayc_t *parent = config->handler_context.current_container; + if (!sway_assert(parent != NULL, "command called without container context")) { + return NULL; + } + + // TODO: floating + /* + if (parent->is_floating) { + return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); + } + */ + + while (parent->type == C_VIEW) { + parent = parent->parent; + } + + // TODO: stacks and tabs + + if (strcasecmp(argv[0], "default") == 0) { + swayc_change_layout(parent, parent->prev_layout); + if (parent->layout == L_NONE) { + swayc_t *output = swayc_parent_by_type(parent, C_OUTPUT); + swayc_change_layout(parent, default_layout(output)); + } + } else { + if (parent->layout != L_TABBED && parent->layout != L_STACKED) { + parent->prev_layout = parent->layout; + } + + if (strcasecmp(argv[0], "splith") == 0) { + swayc_change_layout(parent, L_HORIZ); + } else if (strcasecmp(argv[0], "splitv") == 0) { + swayc_change_layout(parent, L_VERT); + } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { + if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE + || parent->workspace_layout == L_HORIZ)) { + swayc_change_layout(parent, L_VERT); + } else { + swayc_change_layout(parent, L_HORIZ); + } + } + } + + arrange_windows(parent, parent->width, parent->height); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 8d5a97d2..26e56ad2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -14,6 +14,7 @@ sway_sources = files( 'commands/kill.c', 'commands/include.c', 'commands/input.c', + 'commands/layout.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 84e14ba6..b56e72e1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -400,3 +400,15 @@ void container_for_each_bfs(swayc_t *con, void (*f)(swayc_t *con, void *data), list_free(queue); } + +swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) { + if (container->type == C_WORKSPACE) { + container->workspace_layout = layout; + if (layout == L_HORIZ || layout == L_VERT) { + container->layout = layout; + } + } else { + container->layout = layout; + } + return container; +} -- cgit v1.2.3 From 0c8a64942e087038806b353949c900e03fd764a8 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 28 Mar 2018 15:47:22 -0400 Subject: Add initial layer shell skeleton --- include/sway/layers.h | 24 ++++++++++++ include/sway/output.h | 4 ++ include/sway/server.h | 5 +++ protocols/meson.build | 55 ++++++++++++++++++++------ sway/desktop/layer_shell.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 6 +++ sway/meson.build | 10 +++-- sway/server.c | 6 +++ swaybg/meson.build | 2 +- 9 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 include/sway/layers.h create mode 100644 sway/desktop/layer_shell.c (limited to 'sway/meson.build') diff --git a/include/sway/layers.h b/include/sway/layers.h new file mode 100644 index 00000000..73fb7cb8 --- /dev/null +++ b/include/sway/layers.h @@ -0,0 +1,24 @@ +#ifndef _SWAY_LAYERS_H +#define _SWAY_LAYERS_H +#include +#include +#include +#include + +struct sway_layer_surface { + struct wlr_layer_surface *layer_surface; + struct wl_list link; + + struct wl_listener destroy; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener surface_commit; + struct wl_listener output_destroy; + struct wl_listener output_mode; + struct wl_listener output_transform; + + bool configured; + struct wlr_box geo; +}; + +#endif diff --git a/include/sway/output.h b/include/sway/output.h index 95d64705..769d44d0 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -2,6 +2,7 @@ #define _SWAY_OUTPUT_H #include #include +#include #include struct sway_server; @@ -13,6 +14,9 @@ struct sway_output { struct sway_server *server; struct timespec last_frame; + struct wl_list layers[4]; // sway_layer_surface::link + struct wlr_box usable_area; + struct wl_listener frame; struct wl_listener output_destroy; }; diff --git a/include/sway/server.h b/include/sway/server.h index eb7fa2ff..25eb64fe 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include // TODO WLR: make Xwayland optional @@ -27,6 +28,9 @@ struct sway_server { struct wl_listener new_output; struct wl_listener output_frame; + struct wlr_layer_shell *layer_shell; + struct wl_listener layer_shell_surface; + struct wlr_xdg_shell_v6 *xdg_shell_v6; struct wl_listener xdg_shell_v6_surface; @@ -46,6 +50,7 @@ void server_run(struct sway_server *server); void handle_new_output(struct wl_listener *listener, void *data); +void handle_layer_shell_surface(struct wl_listener *listener, void *data); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xwayland_surface(struct wl_listener *listener, void *data); void handle_wl_shell_surface(struct wl_listener *listener, void *data); diff --git a/protocols/meson.build b/protocols/meson.build index 1fda600e..3f79e719 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -14,24 +14,57 @@ wayland_scanner_client = generator( arguments: ['client-header', '@INPUT@', '@OUTPUT@'], ) -protocols = [ +wayland_scanner_server = generator( + wayland_scanner, + output: '@BASENAME@-protocol.h', + arguments: ['server-header', '@INPUT@', '@OUTPUT@'], +) + +client_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], ['wlr-layer-shell-unstable-v1.xml'] ] -wl_protos_src = [] -wl_protos_headers = [] +server_protocols = [ + ['wlr-layer-shell-unstable-v1.xml'] +] + +client_protos_src = [] +client_protos_headers = [] + +server_protos_src = [] +server_protos_headers = [] -foreach p : protocols +foreach p : client_protocols xml = join_paths(p) - wl_protos_src += wayland_scanner_code.process(xml) - wl_protos_headers += wayland_scanner_client.process(xml) + client_protos_src += wayland_scanner_code.process(xml) + client_protos_headers += wayland_scanner_client.process(xml) endforeach -lib_wl_protos = static_library('wl_protos', wl_protos_src + wl_protos_headers, - dependencies: [wayland_client]) # for the include directory +foreach p : server_protocols + xml = join_paths(p) + server_protos_src += wayland_scanner_code.process(xml) + server_protos_headers += wayland_scanner_server.process(xml) +endforeach + +lib_client_protos = static_library( + 'client_protos', + client_protos_src + client_protos_headers, + dependencies: [wayland_client] +) # for the include directory + +client_protos = declare_dependency( + link_with: lib_client_protos, + sources: client_protos_headers, +) + +lib_server_protos = static_library( + 'server_protos', + server_protos_src + server_protos_headers, + dependencies: [wayland_client] +) # for the include directory -sway_protos = declare_dependency( - link_with: lib_wl_protos, - sources: wl_protos_headers, +server_protos = declare_dependency( + link_with: lib_server_protos, + sources: server_protos_headers, ) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c new file mode 100644 index 00000000..3cf171bd --- /dev/null +++ b/sway/desktop/layer_shell.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include "sway/layers.h" +#include "sway/output.h" +#include "sway/server.h" + +static void arrange_layers(struct sway_output *output) { + // TODO +} + +static void handle_output_destroy(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_output_mode(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_output_transform(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_surface_commit(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_destroy(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_map(struct wl_listener *listener, void *data) { + // TODO +} + +static void handle_unmap(struct wl_listener *listener, void *data) { + // TODO +} + +void handle_layer_shell_surface(struct wl_listener *listener, void *data) { + struct wlr_layer_surface *layer_surface = data; + struct sway_server *server = + wl_container_of(listener, server, layer_shell_surface); + wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d " + "size %dx%d margin %d,%d,%d,%d", + layer_surface->namespace, layer_surface->layer, layer_surface->layer, + layer_surface->client_pending.desired_width, + layer_surface->client_pending.desired_height, + layer_surface->client_pending.margin.top, + layer_surface->client_pending.margin.right, + layer_surface->client_pending.margin.bottom, + layer_surface->client_pending.margin.left); + + struct sway_layer_surface *sway_layer = + calloc(1, sizeof(struct sway_layer_surface)); + if (!sway_layer) { + return; + } + + sway_layer->surface_commit.notify = handle_surface_commit; + wl_signal_add(&layer_surface->surface->events.commit, + &sway_layer->surface_commit); + + sway_layer->output_destroy.notify = handle_output_destroy; + wl_signal_add(&layer_surface->output->events.destroy, + &sway_layer->output_destroy); + + sway_layer->output_mode.notify = handle_output_mode; + wl_signal_add(&layer_surface->output->events.mode, + &sway_layer->output_mode); + + sway_layer->output_transform.notify = handle_output_transform; + wl_signal_add(&layer_surface->output->events.transform, + &sway_layer->output_transform); + + sway_layer->destroy.notify = handle_destroy; + wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); + sway_layer->map.notify = handle_map; + wl_signal_add(&layer_surface->events.map, &sway_layer->map); + sway_layer->unmap.notify = handle_unmap; + wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); + // TODO: Listen for subsurfaces + + sway_layer->layer_surface = layer_surface; + layer_surface->data = sway_layer; + + struct sway_output *output = layer_surface->output->data; + wl_list_insert(&output->layers[layer_surface->layer], &sway_layer->link); + + // Temporarily set the layer's current state to client_pending + // So that we can easily arrange it + struct wlr_layer_surface_state old_state = layer_surface->current; + layer_surface->current = layer_surface->client_pending; + arrange_layers(output); + layer_surface->current = old_state; +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6c990c47..a9aa47a6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -236,6 +236,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { return; } output->wlr_output = wlr_output; + wlr_output->data = output; output->server = server; if (!wl_list_empty(&wlr_output->modes)) { @@ -250,6 +251,11 @@ void handle_new_output(struct wl_listener *listener, void *data) { return; } + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len; ++i) { + wl_list_init(&output->layers[i]); + } + sway_input_manager_configure_xcursor(input_manager); wl_signal_add(&wlr_output->events.frame, &output->frame); diff --git a/sway/meson.build b/sway/meson.build index 26e56ad2..8bddb11b 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -46,6 +46,7 @@ sway_sources = files( 'ipc-json.c', 'ipc-server.c', 'desktop/output.c', + 'desktop/layer_shell.c', 'desktop/wl_shell.c', 'desktop/xdg_shell_v6.c', 'desktop/xwayland.c', @@ -57,14 +58,15 @@ sway_sources = files( ) sway_deps = [ + jsonc, + libcap, + libinput, + math, pcre, pixman, + server_protos, wayland_server, - jsonc, wlroots, - libcap, - math, - libinput, xkbcommon, ] diff --git a/sway/server.c b/sway/server.c index ca08d7fb..92f72f13 100644 --- a/sway/server.c +++ b/sway/server.c @@ -7,6 +7,7 @@ #include #include #include +#include #include // TODO WLR: make Xwayland optional #include @@ -51,6 +52,11 @@ bool server_init(struct sway_server *server) { server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); + server->layer_shell = wlr_layer_shell_create(server->wl_display); + wl_signal_add(&server->layer_shell->events.new_surface, + &server->layer_shell_surface); + server->layer_shell_surface.notify = handle_layer_shell_surface; + server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); wl_signal_add(&server->xdg_shell_v6->events.new_surface, &server->xdg_shell_v6_surface); diff --git a/swaybg/meson.build b/swaybg/meson.build index 5e10f3c7..8704de6d 100644 --- a/swaybg/meson.build +++ b/swaybg/meson.build @@ -4,12 +4,12 @@ executable( include_directories: [sway_inc], dependencies: [ cairo, + client_protos, gdk_pixbuf, jsonc, math, pango, pangocairo, - sway_protos, wayland_client, wlroots, ], -- cgit v1.2.3 From bf7a4cd0ebd465a0597e9eec0142fad222b396de Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 29 Mar 2018 17:20:03 -0400 Subject: Add bar configuration commands --- include/sway/commands.h | 3 + include/sway/ipc-server.h | 1 + sway/commands.c | 135 ++++++++++++++++++---------- sway/commands/bar.c | 57 ++++++++++++ sway/commands/bar/activate_button.c | 9 ++ sway/commands/bar/binding_mode_indicator.c | 27 ++++++ sway/commands/bar/bindsym.c | 11 +++ sway/commands/bar/colors.c | 129 ++++++++++++++++++++++++++ sway/commands/bar/context_button.c | 9 ++ sway/commands/bar/font.c | 26 ++++++ sway/commands/bar/height.c | 21 +++++ sway/commands/bar/hidden_state.c | 78 ++++++++++++++++ sway/commands/bar/icon_theme.c | 9 ++ sway/commands/bar/id.c | 33 +++++++ sway/commands/bar/mode.c | 78 ++++++++++++++++ sway/commands/bar/modifier.c | 35 ++++++++ sway/commands/bar/output.c | 50 +++++++++++ sway/commands/bar/pango_markup.c | 27 ++++++ sway/commands/bar/position.c | 29 ++++++ sway/commands/bar/secondary_button.c | 9 ++ sway/commands/bar/separator_symbol.c | 21 +++++ sway/commands/bar/status_command.c | 21 +++++ sway/commands/bar/strip_workspace_numbers.c | 27 ++++++ sway/commands/bar/swaybar_command.c | 21 +++++ sway/commands/bar/tray_output.c | 9 ++ sway/commands/bar/tray_padding.c | 10 +++ sway/commands/bar/workspace_buttons.c | 27 ++++++ sway/commands/bar/wrap_scroll.c | 27 ++++++ sway/config.c | 127 ++++++++++++++++++++++++++ sway/ipc-server.c | 10 ++- sway/meson.build | 25 ++++++ 31 files changed, 1051 insertions(+), 50 deletions(-) create mode 100644 sway/commands/bar.c create mode 100644 sway/commands/bar/activate_button.c create mode 100644 sway/commands/bar/binding_mode_indicator.c create mode 100644 sway/commands/bar/bindsym.c create mode 100644 sway/commands/bar/colors.c create mode 100644 sway/commands/bar/context_button.c create mode 100644 sway/commands/bar/font.c create mode 100644 sway/commands/bar/height.c create mode 100644 sway/commands/bar/hidden_state.c create mode 100644 sway/commands/bar/icon_theme.c create mode 100644 sway/commands/bar/id.c create mode 100644 sway/commands/bar/mode.c create mode 100644 sway/commands/bar/modifier.c create mode 100644 sway/commands/bar/output.c create mode 100644 sway/commands/bar/pango_markup.c create mode 100644 sway/commands/bar/position.c create mode 100644 sway/commands/bar/secondary_button.c create mode 100644 sway/commands/bar/separator_symbol.c create mode 100644 sway/commands/bar/status_command.c create mode 100644 sway/commands/bar/strip_workspace_numbers.c create mode 100644 sway/commands/bar/swaybar_command.c create mode 100644 sway/commands/bar/tray_output.c create mode 100644 sway/commands/bar/tray_padding.c create mode 100644 sway/commands/bar/workspace_buttons.c create mode 100644 sway/commands/bar/wrap_scroll.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 9ff18823..dda286a2 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -74,6 +74,9 @@ void free_cmd_results(struct cmd_results *results); */ const char *cmd_results_to_json(struct cmd_results *results); +struct cmd_results *add_color(const char *name, + char *buffer, const char *color); + typedef struct cmd_results *sway_cmd(int argc, char **argv); sway_cmd cmd_assign; diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 6b7404e5..1f6fffff 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -12,5 +12,6 @@ struct sockaddr_un *ipc_user_sockaddr(void); void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); void ipc_event_window(swayc_t *window, const char *change); +void ipc_event_barconfig_update(struct bar_config *bar); #endif diff --git a/sway/commands.c b/sway/commands.c index b52eb200..8d8b643b 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -91,45 +91,9 @@ void apply_seat_config(struct seat_config *seat) { sway_input_manager_apply_seat_config(input_manager, seat); } -/** - * Check and add color to buffer. - * - * return error object, or NULL if color is valid. - */ -struct cmd_results *add_color(const char *name, char *buffer, const char *color) { - int len = strlen(color); - if (len != 7 && len != 9) { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - - if (color[0] != '#') { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - - int i; - for (i = 1; i < len; ++i) { - if (!isxdigit(color[i])) { - return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); - } - } - - // copy color to buffer - strncpy(buffer, color, len); - // add default alpha channel if color was defined without it - if (len == 7) { - buffer[7] = 'f'; - buffer[8] = 'f'; - } - buffer[9] = '\0'; - - return NULL; -} - -/** - * handlers that can run in either config or command context - * Keep alphabetized - */ +/* Keep alphabetized */ static struct cmd_handler handlers[] = { + { "bar", cmd_bar }, { "bindcode", cmd_bindcode }, { "bindsym", cmd_bindsym }, { "exec", cmd_exec }, @@ -141,18 +105,53 @@ static struct cmd_handler handlers[] = { { "workspace", cmd_workspace }, }; -/** - * Commands that can *only* run in the config loading context - * Keep alphabetized - */ +static struct cmd_handler bar_handlers[] = { + { "activate_button", bar_cmd_activate_button }, + { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, + { "bindsym", bar_cmd_bindsym }, + { "colors", bar_cmd_colors }, + { "context_button", bar_cmd_context_button }, + { "font", bar_cmd_font }, + { "height", bar_cmd_height }, + { "hidden_state", bar_cmd_hidden_state }, + { "icon_theme", bar_cmd_icon_theme }, + { "id", bar_cmd_id }, + { "mode", bar_cmd_mode }, + { "modifier", bar_cmd_modifier }, + { "output", bar_cmd_output }, + { "pango_markup", bar_cmd_pango_markup }, + { "position", bar_cmd_position }, + { "secondary_button", bar_cmd_secondary_button }, + { "separator_symbol", bar_cmd_separator_symbol }, + { "status_command", bar_cmd_status_command }, + { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, + { "swaybar_command", bar_cmd_swaybar_command }, + { "tray_output", bar_cmd_tray_output }, + { "tray_padding", bar_cmd_tray_padding }, + { "workspace_buttons", bar_cmd_workspace_buttons }, + { "wrap_scroll", bar_cmd_wrap_scroll }, +}; + +static struct cmd_handler bar_colors_handlers[] = { + { "active_workspace", bar_colors_cmd_active_workspace }, + { "background", bar_colors_cmd_background }, + { "binding_mode", bar_colors_cmd_binding_mode }, + { "focused_background", bar_colors_cmd_focused_background }, + { "focused_separator", bar_colors_cmd_focused_separator }, + { "focused_statusline", bar_colors_cmd_focused_statusline }, + { "focused_workspace", bar_colors_cmd_focused_workspace }, + { "inactive_workspace", bar_colors_cmd_inactive_workspace }, + { "separator", bar_colors_cmd_separator }, + { "statusline", bar_colors_cmd_statusline }, + { "urgent_workspace", bar_colors_cmd_urgent_workspace }, +}; + +/* Config-time only commands. Keep alphabetized */ static struct cmd_handler config_handlers[] = { { "set", cmd_set }, }; -/** - * Commands that can *not* run in the config loading context - * Keep alphabetized - */ +/* Runtime-only commands. Keep alphabetized */ static struct cmd_handler command_handlers[] = { { "exit", cmd_exit }, { "focus", cmd_focus }, @@ -200,13 +199,19 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { bool config_loading = config->reading || !config->active; - if (block == CMD_BLOCK_INPUT) { - // input commands can run in either context + if (block == CMD_BLOCK_BAR) { + return bsearch(&d, bar_handlers, + sizeof(bar_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_BAR_COLORS) { + return bsearch(&d, bar_colors_handlers, + sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), + sizeof(struct cmd_handler), handler_compare); + } else if (block == CMD_BLOCK_INPUT) { return bsearch(&d, input_handlers, sizeof(input_handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); } else if (block == CMD_BLOCK_SEAT) { - // seat commands can run in either context return bsearch(&d, seat_handlers, sizeof(seat_handlers) / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); @@ -558,3 +563,35 @@ const char *cmd_results_to_json(struct cmd_results *results) { free(root); return json; } + +/** + * Check and add color to buffer. + * + * return error object, or NULL if color is valid. + */ +struct cmd_results *add_color(const char *name, + char *buffer, const char *color) { + int len = strlen(color); + if (len != 7 && len != 9) { + return cmd_results_new(CMD_INVALID, name, + "Invalid color definition %s", color); + } + if (color[0] != '#') { + return cmd_results_new(CMD_INVALID, name, + "Invalid color definition %s", color); + } + for (int i = 1; i < len; ++i) { + if (!isxdigit(color[i])) { + return cmd_results_new(CMD_INVALID, name, + "Invalid color definition %s", color); + } + } + strncpy(buffer, color, len); + // add default alpha channel if color was defined without it + if (len == 7) { + buffer[7] = 'f'; + buffer[8] = 'f'; + } + buffer[9] = '\0'; + return NULL; +} diff --git a/sway/commands/bar.c b/sway/commands/bar.c new file mode 100644 index 00000000..548106b3 --- /dev/null +++ b/sway/commands/bar.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "util.h" + +struct cmd_results *cmd_bar(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (config->reading && strcmp("{", argv[0]) != 0) { + return cmd_results_new(CMD_INVALID, "bar", + "Expected '{' at start of bar config definition."); + } + + if (!config->reading) { + if (argc > 1) { + if (strcasecmp("mode", argv[0]) == 0) { + return bar_cmd_mode(argc-1, argv + 1); + } + + if (strcasecmp("hidden_state", argv[0]) == 0) { + return bar_cmd_hidden_state(argc-1, argv + 1); + } + } + return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); + } + + // Create new bar with default values + struct bar_config *bar = default_bar_config(); + if (!bar) { + return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state"); + } + + // set bar id + int i; + for (i = 0; i < config->bars->length; ++i) { + if (bar == config->bars->items[i]) { + const int len = 5 + numlen(i); // "bar-" + i + \0 + bar->id = malloc(len * sizeof(char)); + if (bar->id) { + snprintf(bar->id, len, "bar-%d", i); + } else { + return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar ID"); + } + break; + } + } + + // Set current bar + config->current_bar = bar; + wlr_log(L_DEBUG, "Configuring bar %s", bar->id); + return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL); +} diff --git a/sway/commands/bar/activate_button.c b/sway/commands/bar/activate_button.c new file mode 100644 index 00000000..0665d2a6 --- /dev/null +++ b/sway/commands/bar/activate_button.c @@ -0,0 +1,9 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_activate_button(int argc, char **argv) { + const char *cmd_name = "activate_button"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c new file mode 100644 index 00000000..e11e1033 --- /dev/null +++ b/sway/commands/bar/binding_mode_indicator.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "binding_mode_indicator", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "binding_mode_indicator", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->binding_mode_indicator = true; + wlr_log(L_DEBUG, "Enabling binding mode indicator on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->binding_mode_indicator = false; + wlr_log(L_DEBUG, "Disabling binding mode indicator on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "binding_mode_indicator", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/bindsym.c b/sway/commands/bar/bindsym.c new file mode 100644 index 00000000..ac09a03f --- /dev/null +++ b/sway/commands/bar/bindsym.c @@ -0,0 +1,11 @@ +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "list.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_bindsym(int argc, char **argv) { + return cmd_results_new(CMD_FAILURE, "bindsym", "TODO"); // TODO +} diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c new file mode 100644 index 00000000..8b3b0aac --- /dev/null +++ b/sway/commands/bar/colors.c @@ -0,0 +1,129 @@ +#include +#include "sway/commands.h" + +static struct cmd_results *parse_single_color(char **color, const char *cmd_name, int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!*color) { + *color = malloc(10); + if (!*color) { + return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); + } + } + + error = add_color(cmd_name, *color, argv[0]); + if (error) { + return error; + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *parse_three_colors(char ***colors, const char *cmd_name, int argc, char **argv) { + struct cmd_results *error = NULL; + if (argc != 3) { + return cmd_results_new(CMD_INVALID, cmd_name, "Requires exactly three color values"); + } + + int i; + for (i = 0; i < 3; i++) { + if (!*colors[i]) { + *(colors[i]) = malloc(10); + if (!*(colors[i])) { + return cmd_results_new(CMD_FAILURE, cmd_name, "Unable to allocate color"); + } + } + error = add_color(cmd_name, *(colors[i]), argv[i]); + if (error) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_colors(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcmp("{", argv[0]) != 0) { + return cmd_results_new(CMD_INVALID, "colors", + "Expected '{' at the start of colors config definition."); + } + + return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL); +} + +struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.active_workspace_border), + &(config->current_bar->colors.active_workspace_bg), + &(config->current_bar->colors.active_workspace_text) + }; + return parse_three_colors(colors, "active_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_background(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.background), "background", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_background(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_background), "focused_background", argc, argv); +} + +struct cmd_results *bar_colors_cmd_binding_mode(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.binding_mode_border), + &(config->current_bar->colors.binding_mode_bg), + &(config->current_bar->colors.binding_mode_text) + }; + return parse_three_colors(colors, "binding_mode", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.focused_workspace_border), + &(config->current_bar->colors.focused_workspace_bg), + &(config->current_bar->colors.focused_workspace_text) + }; + return parse_three_colors(colors, "focused_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_inactive_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.inactive_workspace_border), + &(config->current_bar->colors.inactive_workspace_bg), + &(config->current_bar->colors.inactive_workspace_text) + }; + return parse_three_colors(colors, "inactive_workspace", argc, argv); +} + +struct cmd_results *bar_colors_cmd_separator(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.separator), "separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_separator(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.statusline), "statusline", argc, argv); +} + +struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) { + return parse_single_color(&(config->current_bar->colors.focused_separator), "focused_separator", argc, argv); +} + +struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) { + char **colors[3] = { + &(config->current_bar->colors.urgent_workspace_border), + &(config->current_bar->colors.urgent_workspace_bg), + &(config->current_bar->colors.urgent_workspace_text) + }; + return parse_three_colors(colors, "urgent_workspace", argc, argv); +} diff --git a/sway/commands/bar/context_button.c b/sway/commands/bar/context_button.c new file mode 100644 index 00000000..e6d17f10 --- /dev/null +++ b/sway/commands/bar/context_button.c @@ -0,0 +1,9 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_context_button(int argc, char **argv) { + const char *cmd_name = "context_button"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c new file mode 100644 index 00000000..6d7c533a --- /dev/null +++ b/sway/commands/bar/font.c @@ -0,0 +1,26 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_font(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "font", "No bar defined."); + } + + char *font = join_args(argv, argc); + free(config->current_bar->font); + if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { + config->current_bar->font = font; + } else { + config->current_bar->font = font; + } + + wlr_log(L_DEBUG, "Settings font '%s' for bar: %s", config->current_bar->font, config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/height.c b/sway/commands/bar/height.c new file mode 100644 index 00000000..ae0c7834 --- /dev/null +++ b/sway/commands/bar/height.c @@ -0,0 +1,21 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_height(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "height", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + int height = atoi(argv[0]); + if (height < 0) { + return cmd_results_new(CMD_INVALID, "height", + "Invalid height value: %s", argv[0]); + } + + config->current_bar->height = height; + wlr_log(L_DEBUG, "Setting bar height to %d on bar: %s", height, config->current_bar->id); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c new file mode 100644 index 00000000..245d0858 --- /dev/null +++ b/sway/commands/bar/hidden_state.c @@ -0,0 +1,78 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "log.h" + +static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, + const char *hidden_state) { + char *old_state = bar->hidden_state; + if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) { + if (strcasecmp("hide", bar->hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else if (strcasecmp("show", bar->hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } + } else if (strcasecmp("hide", hidden_state) == 0) { + bar->hidden_state = strdup("hide"); + } else if (strcasecmp("show", hidden_state) == 0) { + bar->hidden_state = strdup("show"); + } else { + return cmd_results_new(CMD_INVALID, "hidden_state", + "Invalid value %s", hidden_state); + } + + if (strcmp(old_state, bar->hidden_state) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + } + wlr_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", + bar->hidden_state, bar->id); + } + + // free old mode + free(old_state); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) { + return error; + } + + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "hidden_state", + "Unexpected value %s in config mode", argv[1]); + } + + const char *state = argv[0]; + + if (config->reading) { + return bar_set_hidden_state(config->current_bar, state); + } + + const char *id = NULL; + if (argc == 2) { + id = argv[1]; + } + + struct bar_config *bar; + for (int i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_hidden_state(bar, state); + } + + error = bar_set_hidden_state(bar, state); + if (error) { + return error; + } + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c new file mode 100644 index 00000000..c6090b81 --- /dev/null +++ b/sway/commands/bar/icon_theme.c @@ -0,0 +1,9 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" + +struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) { + const char *cmd_name = "tray_output"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c new file mode 100644 index 00000000..d9e7f8df --- /dev/null +++ b/sway/commands/bar/id.c @@ -0,0 +1,33 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_id(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "id", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + const char *name = argv[0]; + const char *oldname = config->current_bar->id; + + // check if id is used by a previously defined bar + int i; + for (i = 0; i < config->bars->length; ++i) { + struct bar_config *find = config->bars->items[i]; + if (strcmp(name, find->id) == 0 && config->current_bar != find) { + return cmd_results_new(CMD_FAILURE, "id", + "Id '%s' already defined for another bar. Id unchanged (%s).", + name, oldname); + } + } + + wlr_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name); + + // free old bar id + free(config->current_bar->id); + + config->current_bar->id = strdup(name); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c new file mode 100644 index 00000000..7d346956 --- /dev/null +++ b/sway/commands/bar/mode.c @@ -0,0 +1,78 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "log.h" + +static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) { + char *old_mode = bar->mode; + if (strcasecmp("toggle", mode) == 0 && !config->reading) { + if (strcasecmp("dock", bar->mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("hide", bar->mode) == 0) { + bar->mode = strdup("dock"); + } + } else if (strcasecmp("dock", mode) == 0) { + bar->mode = strdup("dock"); + } else if (strcasecmp("hide", mode) == 0) { + bar->mode = strdup("hide"); + } else if (strcasecmp("invisible", mode) == 0) { + bar->mode = strdup("invisible"); + } else { + return cmd_results_new(CMD_INVALID, "mode", "Invalid value %s", mode); + } + + if (strcmp(old_mode, bar->mode) != 0) { + if (!config->reading) { + ipc_event_barconfig_update(bar); + } + wlr_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); + } + + // free old mode + free(old_mode); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *bar_cmd_mode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { + return error; + } + if ((error = checkarg(argc, "mode", EXPECTED_LESS_THAN, 3))) { + return error; + } + + if (config->reading && argc > 1) { + return cmd_results_new(CMD_INVALID, "mode", "Unexpected value %s in config mode", argv[1]); + } + + const char *mode = argv[0]; + + if (config->reading) { + return bar_set_mode(config->current_bar, mode); + } + + const char *id = NULL; + if (argc == 2) { + id = argv[1]; + } + + int i; + struct bar_config *bar; + for (i = 0; i < config->bars->length; ++i) { + bar = config->bars->items[i]; + if (id && strcmp(id, bar->id) == 0) { + return bar_set_mode(bar, mode); + } + + error = bar_set_mode(bar, mode); + if (error) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c new file mode 100644 index 00000000..9a1f8b01 --- /dev/null +++ b/sway/commands/bar/modifier.c @@ -0,0 +1,35 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" +#include "util.h" + +struct cmd_results *bar_cmd_modifier(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "modifier", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "modifier", "No bar defined."); + } + + uint32_t mod = 0; + + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + uint32_t tmp_mod; + if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { + mod |= tmp_mod; + continue; + } else { + free_flat_list(split); + return cmd_results_new(CMD_INVALID, "modifier", "Unknown modifier '%s'", split->items[i]); + } + } + free_flat_list(split); + + config->current_bar->modifier = mod; + wlr_log(L_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c new file mode 100644 index 00000000..034d9ca4 --- /dev/null +++ b/sway/commands/bar/output.c @@ -0,0 +1,50 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "list.h" +#include "log.h" + +struct cmd_results *bar_cmd_output(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "output", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "output", "No bar defined."); + } + + const char *output = argv[0]; + list_t *outputs = config->current_bar->outputs; + if (!outputs) { + outputs = create_list(); + config->current_bar->outputs = outputs; + } + + int i; + int add_output = 1; + if (strcmp("*", output) == 0) { + // remove all previous defined outputs and replace with '*' + for (i = 0; i < outputs->length; ++i) { + free(outputs->items[i]); + list_del(outputs, i); + } + } else { + // only add output if not already defined with either the same + // name or as '*' + for (i = 0; i < outputs->length; ++i) { + const char *find = outputs->items[i]; + if (strcmp("*", find) == 0 || strcmp(output, find) == 0) { + add_output = 0; + break; + } + } + } + + if (add_output) { + list_add(outputs, strdup(output)); + wlr_log(L_DEBUG, "Adding bar: '%s' to output '%s'", config->current_bar->id, output); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/pango_markup.c b/sway/commands/bar/pango_markup.c new file mode 100644 index 00000000..34b85e98 --- /dev/null +++ b/sway/commands/bar/pango_markup.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "pango_markup", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "pango_markup", "No bar defined."); + } + + if (strcasecmp("enabled", argv[0]) == 0) { + config->current_bar->pango_markup = true; + wlr_log(L_DEBUG, "Enabling pango markup for bar: %s", config->current_bar->id); + } else if (strcasecmp("disabled", argv[0]) == 0) { + config->current_bar->pango_markup = false; + wlr_log(L_DEBUG, "Disabling pango markup for bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "pango_markup", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c new file mode 100644 index 00000000..efa8c0bc --- /dev/null +++ b/sway/commands/bar/position.c @@ -0,0 +1,29 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_position(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "position", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "position", "No bar defined."); + } + + char *valid[] = { "top", "bottom", "left", "right" }; + for (size_t i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) { + if (strcasecmp(valid[i], argv[0]) == 0) { + wlr_log(L_DEBUG, "Setting bar position '%s' for bar: %s", + argv[0], config->current_bar->id); + config->current_bar->position = strdup(argv[0]); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + } + + error = cmd_results_new(CMD_INVALID, "position", "Invalid value %s", argv[0]); + return error; +} diff --git a/sway/commands/bar/secondary_button.c b/sway/commands/bar/secondary_button.c new file mode 100644 index 00000000..46d53e3f --- /dev/null +++ b/sway/commands/bar/secondary_button.c @@ -0,0 +1,9 @@ +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) { + const char *cmd_name = "secondary_button"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c new file mode 100644 index 00000000..7dc0956b --- /dev/null +++ b/sway/commands/bar/separator_symbol.c @@ -0,0 +1,21 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "separator_symbol", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "separator_symbol", "No bar defined."); + } + + free(config->current_bar->separator_symbol); + config->current_bar->separator_symbol = strdup(argv[0]); + wlr_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s", config->current_bar->separator_symbol, config->current_bar->id); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c new file mode 100644 index 00000000..05377fcc --- /dev/null +++ b/sway/commands/bar/status_command.c @@ -0,0 +1,21 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_status_command(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "status_command", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "status_command", "No bar defined."); + } + + free(config->current_bar->status_command); + config->current_bar->status_command = join_args(argv, argc); + wlr_log(L_DEBUG, "Feeding bar with status command: %s", config->current_bar->status_command); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c new file mode 100644 index 00000000..0558db8f --- /dev/null +++ b/sway/commands/bar/strip_workspace_numbers.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "strip_workspace_numbers", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "strip_workspace_numbers", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->strip_workspace_numbers = true; + wlr_log(L_DEBUG, "Stripping workspace numbers on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->strip_workspace_numbers = false; + wlr_log(L_DEBUG, "Enabling workspace numbers on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "strip_workspace_numbers", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c new file mode 100644 index 00000000..63d4f29a --- /dev/null +++ b/sway/commands/bar/swaybar_command.c @@ -0,0 +1,21 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "swaybar_command", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "swaybar_command", "No bar defined."); + } + + free(config->current_bar->swaybar_command); + config->current_bar->swaybar_command = join_args(argv, argc); + wlr_log(L_DEBUG, "Using custom swaybar command: %s", config->current_bar->swaybar_command); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c new file mode 100644 index 00000000..2d822146 --- /dev/null +++ b/sway/commands/bar/tray_output.c @@ -0,0 +1,9 @@ +#define _XOPEN_SOURCE 500 +#include +#include "sway/commands.h" + +struct cmd_results *bar_cmd_tray_output(int argc, char **argv) { + const char *cmd_name = "tray_output"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/tray_padding.c b/sway/commands/bar/tray_padding.c new file mode 100644 index 00000000..95b8ad3b --- /dev/null +++ b/sway/commands/bar/tray_padding.c @@ -0,0 +1,10 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) { + const char *cmd_name = "tray_padding"; + // TODO TRAY + return cmd_results_new(CMD_INVALID, cmd_name, "TODO TRAY"); +} diff --git a/sway/commands/bar/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c new file mode 100644 index 00000000..1a617eb8 --- /dev/null +++ b/sway/commands/bar/workspace_buttons.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace_buttons", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "workspace_buttons", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->workspace_buttons = true; + wlr_log(L_DEBUG, "Enabling workspace buttons on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->workspace_buttons = false; + wlr_log(L_DEBUG, "Disabling workspace buttons on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "workspace_buttons", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c new file mode 100644 index 00000000..c89dff5f --- /dev/null +++ b/sway/commands/bar/wrap_scroll.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/commands.h" +#include "log.h" + +struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "wrap_scroll", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (!config->current_bar) { + return cmd_results_new(CMD_FAILURE, "wrap_scroll", "No bar defined."); + } + + if (strcasecmp("yes", argv[0]) == 0) { + config->current_bar->wrap_scroll = true; + wlr_log(L_DEBUG, "Enabling wrap scroll on bar: %s", config->current_bar->id); + } else if (strcasecmp("no", argv[0]) == 0) { + config->current_bar->wrap_scroll = false; + wlr_log(L_DEBUG, "Disabling wrap scroll on bar: %s", config->current_bar->id); + } else { + error = cmd_results_new(CMD_INVALID, "wrap_scroll", "Invalid value %s", argv[0]); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index 0422fdd9..a0e408de 100644 --- a/sway/config.c +++ b/sway/config.c @@ -110,6 +110,48 @@ void free_config(struct sway_config *config) { free(config); } +static void free_bar(struct bar_config *bar) { + if (!bar) { + return; + } + free(bar->mode); + free(bar->position); + free(bar->hidden_state); + free(bar->status_command); + free(bar->font); + free(bar->separator_symbol); + // TODO: Free mouse bindings + list_free(bar->bindings); + if (bar->outputs) { + free_flat_list(bar->outputs); + } + if (bar->pid != 0) { + // TODO terminate_swaybar(bar->pid); + } + free(bar->colors.background); + free(bar->colors.statusline); + free(bar->colors.separator); + free(bar->colors.focused_background); + free(bar->colors.focused_statusline); + free(bar->colors.focused_separator); + free(bar->colors.focused_workspace_border); + free(bar->colors.focused_workspace_bg); + free(bar->colors.focused_workspace_text); + free(bar->colors.active_workspace_border); + free(bar->colors.active_workspace_bg); + free(bar->colors.active_workspace_text); + free(bar->colors.inactive_workspace_border); + free(bar->colors.inactive_workspace_bg); + free(bar->colors.inactive_workspace_text); + free(bar->colors.urgent_workspace_border); + free(bar->colors.urgent_workspace_bg); + free(bar->colors.urgent_workspace_text); + free(bar->colors.binding_mode_border); + free(bar->colors.binding_mode_bg); + free(bar->colors.binding_mode_text); + free(bar); +} + static void destroy_removed_seats(struct sway_config *old_config, struct sway_config *new_config) { struct seat_config *seat_config; @@ -239,6 +281,91 @@ cleanup: sway_abort("Unable to allocate config structures"); } +struct bar_config *default_bar_config(void) { + struct bar_config *bar = NULL; + bar = malloc(sizeof(struct bar_config)); + if (!bar) { + return NULL; + } + if (!(bar->mode = strdup("dock"))) goto cleanup; + if (!(bar->hidden_state = strdup("hide"))) goto cleanup; + bar->outputs = NULL; + bar->position = strdup("bottom"); + if (!(bar->bindings = create_list())) goto cleanup; + if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; + bar->pango_markup = false; + bar->swaybar_command = NULL; + bar->font = NULL; + bar->height = -1; + bar->workspace_buttons = true; + bar->wrap_scroll = false; + bar->separator_symbol = NULL; + bar->strip_workspace_numbers = false; + bar->binding_mode_indicator = true; + bar->verbose = false; + bar->pid = 0; + // set default colors + if (!(bar->colors.background = strndup("#000000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.statusline = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.separator = strndup("#666666ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + // if the following colors stay undefined, they fall back to background, + // statusline, separator and urgent_workspace_*. + bar->colors.focused_background = NULL; + bar->colors.focused_statusline = NULL; + bar->colors.focused_separator = NULL; + bar->colors.binding_mode_border = NULL; + bar->colors.binding_mode_bg = NULL; + bar->colors.binding_mode_text = NULL; + + list_add(config->bars, bar); + return bar; +cleanup: + free_bar(bar); + return NULL; +} + static bool file_exists(const char *path) { return path && access(path, R_OK) != -1; } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 408ed432..59fc05f9 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -313,10 +313,18 @@ void ipc_event_window(swayc_t *window, const char *change) { const char *json_string = json_object_to_json_string(obj); ipc_send_event(json_string, IPC_EVENT_WINDOW); - json_object_put(obj); // free } +void ipc_event_barconfig_update(struct bar_config *bar) { + wlr_log(L_DEBUG, "Sending barconfig_update event"); + json_object *json = ipc_json_describe_bar_config(bar); + + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE); + json_object_put(json); // free +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; diff --git a/sway/meson.build b/sway/meson.build index 8bddb11b..8fcb0dbf 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -6,6 +6,7 @@ sway_sources = files( 'input/seat.c', 'input/cursor.c', 'input/keyboard.c', + 'commands/bar.c', 'commands/bind.c', 'commands/exit.c', 'commands/exec.c', @@ -19,6 +20,30 @@ sway_sources = files( 'commands/seat/attach.c', 'commands/seat/fallback.c', 'commands/set.c', + 'commands/bar/activate_button.c', + 'commands/bar/binding_mode_indicator.c', + 'commands/bar/bindsym.c', + 'commands/bar/colors.c', + 'commands/bar/context_button.c', + 'commands/bar/font.c', + 'commands/bar/height.c', + 'commands/bar/hidden_state.c', + 'commands/bar/icon_theme.c', + 'commands/bar/id.c', + 'commands/bar/mode.c', + 'commands/bar/modifier.c', + 'commands/bar/output.c', + 'commands/bar/pango_markup.c', + 'commands/bar/position.c', + 'commands/bar/secondary_button.c', + 'commands/bar/separator_symbol.c', + 'commands/bar/status_command.c', + 'commands/bar/strip_workspace_numbers.c', + 'commands/bar/swaybar_command.c', + 'commands/bar/tray_output.c', + 'commands/bar/tray_padding.c', + 'commands/bar/workspace_buttons.c', + 'commands/bar/wrap_scroll.c', 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', -- cgit v1.2.3 From 569b2bfd5daae5b3be49772bdca4a3f224e20629 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 29 Mar 2018 17:41:02 -0400 Subject: Move bar config into its own file --- include/sway/config.h | 26 +++------ sway/config.c | 127 -------------------------------------------- sway/config/bar.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ sway/config/output.c | 2 +- sway/meson.build | 1 + 5 files changed, 151 insertions(+), 148 deletions(-) create mode 100644 sway/config/bar.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index f9ab6778..dbcfc91e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -12,6 +12,8 @@ #include "container.h" #include "wlr-layer-shell-unstable-v1-protocol.h" +// TODO: Refactor this shit + /** * Describes a variable created via the `set` command. */ @@ -407,11 +409,6 @@ void merge_output_config(struct output_config *dst, struct output_config *src); void apply_output_config(struct output_config *oc, swayc_t *output); void free_output_config(struct output_config *oc); -/** - * Updates the list of active bar modifiers - */ -void update_active_bar_modifiers(void); - int workspace_output_cmp_workspace(const void *a, const void *b); int sway_binding_cmp(const void *a, const void *b); @@ -420,27 +417,16 @@ int sway_binding_cmp_keys(const void *a, const void *b); void free_sway_binding(struct sway_binding *sb); struct sway_binding *sway_binding_dup(struct sway_binding *sb); -int sway_mouse_binding_cmp(const void *a, const void *b); -int sway_mouse_binding_cmp_qsort(const void *a, const void *b); -int sway_mouse_binding_cmp_buttons(const void *a, const void *b); -void free_sway_mouse_binding(struct sway_mouse_binding *smb); - +/* Bar stuff */ void load_swaybars(); void terminate_swaybg(pid_t pid); - -/** - * Allocate and initialize default bar configuration. - */ struct bar_config *default_bar_config(void); +void free_bar_config(struct bar_config *bar); -/** - * Global config singleton. - */ +/* Global config singleton. */ extern struct sway_config *config; -/** - * Config file currently being read. - */ +/* Config file currently being read */ extern const char *current_config_path; #endif diff --git a/sway/config.c b/sway/config.c index a0e408de..0422fdd9 100644 --- a/sway/config.c +++ b/sway/config.c @@ -110,48 +110,6 @@ void free_config(struct sway_config *config) { free(config); } -static void free_bar(struct bar_config *bar) { - if (!bar) { - return; - } - free(bar->mode); - free(bar->position); - free(bar->hidden_state); - free(bar->status_command); - free(bar->font); - free(bar->separator_symbol); - // TODO: Free mouse bindings - list_free(bar->bindings); - if (bar->outputs) { - free_flat_list(bar->outputs); - } - if (bar->pid != 0) { - // TODO terminate_swaybar(bar->pid); - } - free(bar->colors.background); - free(bar->colors.statusline); - free(bar->colors.separator); - free(bar->colors.focused_background); - free(bar->colors.focused_statusline); - free(bar->colors.focused_separator); - free(bar->colors.focused_workspace_border); - free(bar->colors.focused_workspace_bg); - free(bar->colors.focused_workspace_text); - free(bar->colors.active_workspace_border); - free(bar->colors.active_workspace_bg); - free(bar->colors.active_workspace_text); - free(bar->colors.inactive_workspace_border); - free(bar->colors.inactive_workspace_bg); - free(bar->colors.inactive_workspace_text); - free(bar->colors.urgent_workspace_border); - free(bar->colors.urgent_workspace_bg); - free(bar->colors.urgent_workspace_text); - free(bar->colors.binding_mode_border); - free(bar->colors.binding_mode_bg); - free(bar->colors.binding_mode_text); - free(bar); -} - static void destroy_removed_seats(struct sway_config *old_config, struct sway_config *new_config) { struct seat_config *seat_config; @@ -281,91 +239,6 @@ cleanup: sway_abort("Unable to allocate config structures"); } -struct bar_config *default_bar_config(void) { - struct bar_config *bar = NULL; - bar = malloc(sizeof(struct bar_config)); - if (!bar) { - return NULL; - } - if (!(bar->mode = strdup("dock"))) goto cleanup; - if (!(bar->hidden_state = strdup("hide"))) goto cleanup; - bar->outputs = NULL; - bar->position = strdup("bottom"); - if (!(bar->bindings = create_list())) goto cleanup; - if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; - bar->pango_markup = false; - bar->swaybar_command = NULL; - bar->font = NULL; - bar->height = -1; - bar->workspace_buttons = true; - bar->wrap_scroll = false; - bar->separator_symbol = NULL; - bar->strip_workspace_numbers = false; - bar->binding_mode_indicator = true; - bar->verbose = false; - bar->pid = 0; - // set default colors - if (!(bar->colors.background = strndup("#000000ff", 9))) { - goto cleanup; - } - if (!(bar->colors.statusline = strndup("#ffffffff", 9))) { - goto cleanup; - } - if (!(bar->colors.separator = strndup("#666666ff", 9))) { - goto cleanup; - } - if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) { - goto cleanup; - } - if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) { - goto cleanup; - } - if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) { - goto cleanup; - } - if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) { - goto cleanup; - } - if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) { - goto cleanup; - } - if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) { - goto cleanup; - } - if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) { - goto cleanup; - } - if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) { - goto cleanup; - } - if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) { - goto cleanup; - } - if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) { - goto cleanup; - } - if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) { - goto cleanup; - } - if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) { - goto cleanup; - } - // if the following colors stay undefined, they fall back to background, - // statusline, separator and urgent_workspace_*. - bar->colors.focused_background = NULL; - bar->colors.focused_statusline = NULL; - bar->colors.focused_separator = NULL; - bar->colors.binding_mode_border = NULL; - bar->colors.binding_mode_bg = NULL; - bar->colors.binding_mode_text = NULL; - - list_add(config->bars, bar); - return bar; -cleanup: - free_bar(bar); - return NULL; -} - static bool file_exists(const char *path) { return path && access(path, R_OK) != -1; } diff --git a/sway/config/bar.c b/sway/config/bar.c new file mode 100644 index 00000000..ecc357d0 --- /dev/null +++ b/sway/config/bar.c @@ -0,0 +1,143 @@ +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sway/config.h" +#include "stringop.h" +#include "list.h" +#include "log.h" + +void free_bar_config(struct bar_config *bar) { + if (!bar) { + return; + } + free(bar->mode); + free(bar->position); + free(bar->hidden_state); + free(bar->status_command); + free(bar->font); + free(bar->separator_symbol); + // TODO: Free mouse bindings + list_free(bar->bindings); + if (bar->outputs) { + free_flat_list(bar->outputs); + } + if (bar->pid != 0) { + // TODO terminate_swaybar(bar->pid); + } + free(bar->colors.background); + free(bar->colors.statusline); + free(bar->colors.separator); + free(bar->colors.focused_background); + free(bar->colors.focused_statusline); + free(bar->colors.focused_separator); + free(bar->colors.focused_workspace_border); + free(bar->colors.focused_workspace_bg); + free(bar->colors.focused_workspace_text); + free(bar->colors.active_workspace_border); + free(bar->colors.active_workspace_bg); + free(bar->colors.active_workspace_text); + free(bar->colors.inactive_workspace_border); + free(bar->colors.inactive_workspace_bg); + free(bar->colors.inactive_workspace_text); + free(bar->colors.urgent_workspace_border); + free(bar->colors.urgent_workspace_bg); + free(bar->colors.urgent_workspace_text); + free(bar->colors.binding_mode_border); + free(bar->colors.binding_mode_bg); + free(bar->colors.binding_mode_text); + free(bar); +} + +struct bar_config *default_bar_config(void) { + struct bar_config *bar = NULL; + bar = malloc(sizeof(struct bar_config)); + if (!bar) { + return NULL; + } + if (!(bar->mode = strdup("dock"))) goto cleanup; + if (!(bar->hidden_state = strdup("hide"))) goto cleanup; + bar->outputs = NULL; + bar->position = strdup("bottom"); + if (!(bar->bindings = create_list())) goto cleanup; + if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; + bar->pango_markup = false; + bar->swaybar_command = NULL; + bar->font = NULL; + bar->height = -1; + bar->workspace_buttons = true; + bar->wrap_scroll = false; + bar->separator_symbol = NULL; + bar->strip_workspace_numbers = false; + bar->binding_mode_indicator = true; + bar->verbose = false; + bar->pid = 0; + // set default colors + if (!(bar->colors.background = strndup("#000000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.statusline = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.separator = strndup("#666666ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) { + goto cleanup; + } + if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) { + goto cleanup; + } + if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) { + goto cleanup; + } + if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) { + goto cleanup; + } + if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) { + goto cleanup; + } + // if the following colors stay undefined, they fall back to background, + // statusline, separator and urgent_workspace_*. + bar->colors.focused_background = NULL; + bar->colors.focused_statusline = NULL; + bar->colors.focused_separator = NULL; + bar->colors.binding_mode_border = NULL; + bar->colors.binding_mode_bg = NULL; + bar->colors.binding_mode_text = NULL; + + list_add(config->bars, bar); + return bar; +cleanup: + free_bar_config(bar); + return NULL; +} diff --git a/sway/config/output.c b/sway/config/output.c index 9e211861..24b4a18e 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -186,7 +186,7 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { output_id[bufsize-1] = 0; char *const cmd[] = { - "./swaybg/swaybg", + "swaybg", output_id, oc->background, oc->background_option, diff --git a/sway/meson.build b/sway/meson.build index 8fcb0dbf..ac65d05e 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -64,6 +64,7 @@ sway_sources = files( 'commands/reload.c', 'commands/workspace.c', 'config.c', + 'config/bar.c', 'config/output.c', 'config/seat.c', 'config/input.c', -- cgit v1.2.3 From 5c9cdbcdd2a07e2ced7b60d629a3e20bd7c8bf68 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 29 Mar 2018 17:49:44 -0400 Subject: Add swaybg_command --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands.c | 1 + sway/commands/swaybg_command.c | 20 ++++++++++++++++++++ sway/config/output.c | 25 +++++++++++++------------ sway/meson.build | 1 + sway/sway.5.txt | 3 +++ 7 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 sway/commands/swaybg_command.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index dda286a2..1291d5fb 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -141,6 +141,7 @@ sway_cmd cmd_splith; sway_cmd cmd_splitt; sway_cmd cmd_splitv; sway_cmd cmd_sticky; +sway_cmd cmd_swaybg_command; sway_cmd cmd_unmark; sway_cmd cmd_workspace; sway_cmd cmd_ws_auto_back_and_forth; diff --git a/include/sway/config.h b/include/sway/config.h index dbcfc91e..4a7fee0f 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -282,6 +282,7 @@ struct sway_config { list_t *active_bar_modifiers; struct sway_mode *current_mode; struct bar_config *current_bar; + char *swaybg_command; uint32_t floating_mod; uint32_t dragging_key; uint32_t resizing_key; diff --git a/sway/commands.c b/sway/commands.c index 8d8b643b..38e2f764 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -149,6 +149,7 @@ static struct cmd_handler bar_colors_handlers[] = { /* Config-time only commands. Keep alphabetized */ static struct cmd_handler config_handlers[] = { { "set", cmd_set }, + { "swaybg_command", cmd_swaybg_command }, }; /* Runtime-only commands. Keep alphabetized */ diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c new file mode 100644 index 00000000..770d4821 --- /dev/null +++ b/sway/commands/swaybg_command.c @@ -0,0 +1,20 @@ +#include +#include "sway/commands.h" +#include "log.h" +#include "stringop.h" + +struct cmd_results *cmd_swaybg_command(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "swaybg_command", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (config->swaybg_command) { + free(config->swaybg_command); + } + config->swaybg_command = join_args(argv, argc); + wlr_log(L_DEBUG, "Using custom swaybg command: %s", + config->swaybg_command); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config/output.c b/sway/config/output.c index 24b4a18e..c3ec61b7 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -180,19 +180,20 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { wlr_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background); - size_t bufsize = 12; - char output_id[bufsize]; - snprintf(output_id, bufsize, "%d", output_i); - output_id[bufsize-1] = 0; - - char *const cmd[] = { - "swaybg", - output_id, - oc->background, - oc->background_option, - NULL, - }; + size_t len = snprintf(NULL, 0, "%s %d %s %s", + config->swaybg_command ? config->swaybg_command : "swaybg", + output_i, oc->background, oc->background_option); + char *command = malloc(len + 1); + if (!command) { + wlr_log(L_DEBUG, "Unable to allocate swaybg command"); + return; + } + snprintf(command, len + 1, "%s %d %s %s", + config->swaybg_command ? config->swaybg_command : "swaybg", + output_i, oc->background, oc->background_option); + wlr_log(L_DEBUG, "-> %s", command); + char *const cmd[] = { "sh", "-c", command, NULL }; output->sway_output->bg_pid = fork(); if (output->sway_output->bg_pid == 0) { execvp(cmd[0], cmd); diff --git a/sway/meson.build b/sway/meson.build index ac65d05e..54c03061 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -20,6 +20,7 @@ sway_sources = files( 'commands/seat/attach.c', 'commands/seat/fallback.c', 'commands/set.c', + 'commands/swaybg_command.c', 'commands/bar/activate_button.c', 'commands/bar/binding_mode_indicator.c', 'commands/bar/bindsym.c', diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 6c9bce7a..900e499a 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -43,6 +43,9 @@ The following commands may only be used in the configuration file. Sets variable $name to _value_. You can use the new variable in the arguments of future commands. +**swaybg_command** :: + Executes custom bg command, default is _swaybg_. + The following commands cannot be used directly in the configuration file. They are expected to be used with **bindsym** or at runtime through **swaymsg**(1). -- cgit v1.2.3 From 8efee109ad2ab4861f25e54e9f6d1ceb06203791 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 29 Mar 2018 22:10:33 -0400 Subject: Implement modes --- include/sway/ipc-server.h | 1 + sway/commands.c | 1 + sway/commands/mode.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ sway/ipc-server.c | 14 +++++++++-- sway/meson.build | 1 + 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 sway/commands/mode.c (limited to 'sway/meson.build') diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 1f6fffff..b4db75c3 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -13,5 +13,6 @@ struct sockaddr_un *ipc_user_sockaddr(void); void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change); void ipc_event_window(swayc_t *window, const char *change); void ipc_event_barconfig_update(struct bar_config *bar); +void ipc_event_mode(const char *mode); #endif diff --git a/sway/commands.c b/sway/commands.c index 38e2f764..bcc777ed 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -100,6 +100,7 @@ static struct cmd_handler handlers[] = { { "exec_always", cmd_exec_always }, { "include", cmd_include }, { "input", cmd_input }, + { "mode", cmd_mode }, { "output", cmd_output }, { "seat", cmd_seat }, { "workspace", cmd_workspace }, diff --git a/sway/commands/mode.c b/sway/commands/mode.c new file mode 100644 index 00000000..c30a8bac --- /dev/null +++ b/sway/commands/mode.c @@ -0,0 +1,59 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/ipc-server.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_mode(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) { + return error; + } + + const char *mode_name = argv[0]; + bool new_mode = (argc == 2 && strcmp(argv[1], "{") == 0); + if (new_mode && !config->reading) { + return cmd_results_new(CMD_FAILURE, + "mode", "Can only be used in config file."); + } + struct sway_mode *mode = NULL; + // Find mode + for (int i = 0; i < config->modes->length; ++i) { + struct sway_mode *test = config->modes->items[i]; + if (strcasecmp(test->name, mode_name) == 0) { + mode = test; + break; + } + } + // Create mode if it doesn't exist + if (!mode && new_mode) { + mode = calloc(1, sizeof(struct sway_mode)); + if (!mode) { + return cmd_results_new(CMD_FAILURE, + "mode", "Unable to allocate mode"); + } + mode->name = strdup(mode_name); + mode->keysym_bindings = create_list(); + mode->keycode_bindings = create_list(); + list_add(config->modes, mode); + } + if (!mode) { + error = cmd_results_new(CMD_INVALID, + "mode", "Unknown mode `%s'", mode_name); + return error; + } + if ((config->reading && new_mode) || (!config->reading && !new_mode)) { + wlr_log(L_DEBUG, "Switching to mode `%s'",mode->name); + } + // Set current mode + config->current_mode = mode; + if (!new_mode) { + // trigger IPC mode event + ipc_event_mode(config->current_mode->name); + } + return cmd_results_new(new_mode ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 8250b3a0..c3b589a6 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -290,7 +290,7 @@ void ipc_event_window(swayc_t *window, const char *change) { const char *json_string = json_object_to_json_string(obj); ipc_send_event(json_string, IPC_EVENT_WINDOW); - json_object_put(obj); // free + json_object_put(obj); } void ipc_event_barconfig_update(struct bar_config *bar) { @@ -299,7 +299,17 @@ void ipc_event_barconfig_update(struct bar_config *bar) { const char *json_string = json_object_to_json_string(json); ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE); - json_object_put(json); // free + json_object_put(json); +} + +void ipc_event_mode(const char *mode) { + wlr_log(L_DEBUG, "Sending mode::%s event", mode); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(mode)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_MODE); + json_object_put(obj); } int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { diff --git a/sway/meson.build b/sway/meson.build index 54c03061..1e7ee7ae 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -16,6 +16,7 @@ sway_sources = files( 'commands/include.c', 'commands/input.c', 'commands/layout.c', + 'commands/mode.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', -- cgit v1.2.3 From 69eb021767d8cf57b08699c7e330fe8c52ca2764 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 30 Mar 2018 10:43:55 -0400 Subject: Add default_orientation command --- include/sway/commands.h | 2 +- sway/commands.c | 1 + sway/commands/default_orientation.c | 21 +++++++++++++++++++++ sway/meson.build | 1 + sway/tree/layout.c | 5 ++--- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 sway/commands/default_orientation.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 1291d5fb..66f097ea 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -95,6 +95,7 @@ sway_cmd cmd_commands; sway_cmd cmd_debuglog; sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; +sway_cmd cmd_default_orientation; sway_cmd cmd_exec; sway_cmd cmd_exec_always; sway_cmd cmd_exit; @@ -125,7 +126,6 @@ sway_cmd cmd_move; sway_cmd cmd_new_float; sway_cmd cmd_new_window; sway_cmd cmd_no_focus; -sway_cmd cmd_orientation; sway_cmd cmd_output; sway_cmd cmd_permit; sway_cmd cmd_reject; diff --git a/sway/commands.c b/sway/commands.c index bcc777ed..eee7f254 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -149,6 +149,7 @@ static struct cmd_handler bar_colors_handlers[] = { /* Config-time only commands. Keep alphabetized */ static struct cmd_handler config_handlers[] = { + { "default_orientation", cmd_default_orientation }, { "set", cmd_set }, { "swaybg_command", cmd_swaybg_command }, }; diff --git a/sway/commands/default_orientation.c b/sway/commands/default_orientation.c new file mode 100644 index 00000000..a5347ce2 --- /dev/null +++ b/sway/commands/default_orientation.c @@ -0,0 +1,21 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_default_orientation(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_orientation", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "horizontal") == 0) { + config->default_orientation = L_HORIZ; + } else if (strcasecmp(argv[0], "vertical") == 0) { + config->default_orientation = L_VERT; + } else if (strcasecmp(argv[0], "auto") == 0) { + // Do nothing + } else { + return cmd_results_new(CMD_INVALID, "default_orientation", + "Expected 'orientation '"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 1e7ee7ae..9c5e4a00 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -8,6 +8,7 @@ sway_sources = files( 'input/keyboard.c', 'commands/bar.c', 'commands/bind.c', + 'commands/default_orientation.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', diff --git a/sway/tree/layout.c b/sway/tree/layout.c index dc0ee5b4..c7cf16e6 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -123,12 +123,11 @@ struct sway_container *container_remove_child(struct sway_container *child) { enum sway_container_layout container_get_default_layout( struct sway_container *output) { - /* TODO WLR if (config->default_layout != L_NONE) { - //return config->default_layout; + return config->default_layout; } else if (config->default_orientation != L_NONE) { return config->default_orientation; - } else */if (output->width >= output->height) { + } else if (output->width >= output->height) { return L_HORIZ; } else { return L_VERT; -- cgit v1.2.3 From 49379dd0fc0758f89d7f4fa4fb5b08c7f4c26ae6 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 30 Mar 2018 11:58:17 -0400 Subject: Fix workspace deletion edge cases --- include/sway/tree/container.h | 2 +- include/sway/tree/layout.h | 2 + include/sway/tree/workspace.h | 2 + sway/desktop/xdg_shell_v6.c | 3 +- sway/desktop/xwayland.c | 20 ++------- sway/meson.build | 1 + sway/tree/container.c | 101 +++--------------------------------------- sway/tree/layout.c | 58 +++++++++++------------- sway/tree/output.c | 36 +++++++++++++++ sway/tree/view.c | 11 +++++ sway/tree/workspace.c | 56 ++++++++++++++++++++++- 11 files changed, 145 insertions(+), 147 deletions(-) create mode 100644 sway/tree/output.c (limited to 'sway/meson.build') diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 24e8468e..6aa66da0 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -104,7 +104,7 @@ struct sway_container *container_workspace_destroy( struct sway_container *container_view_destroy(struct sway_container *view); -void container_destroy(struct sway_container *cont); +struct sway_container *container_destroy(struct sway_container *cont); struct sway_container *container_set_layout(struct sway_container *container, enum sway_container_layout layout); diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 8239366b..0a904c4b 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -39,6 +39,8 @@ struct sway_container *container_add_sibling(struct sway_container *parent, struct sway_container *container_remove_child(struct sway_container *child); +struct sway_container *container_reap_empty(struct sway_container *container); + void container_move_to(struct sway_container* container, struct sway_container* destination); diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index d73b29c1..4e4c3450 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -23,4 +23,6 @@ struct sway_container *workspace_output_prev(struct sway_container *current); struct sway_container *workspace_prev(struct sway_container *current); +bool workspace_is_visible(struct sway_container *ws); + #endif diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 25c0cbca..01f38d16 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -83,10 +83,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, sway_xdg_surface, destroy); wl_list_remove(&sway_xdg_surface->commit.link); wl_list_remove(&sway_xdg_surface->destroy.link); - struct sway_container *parent = container_view_destroy(sway_xdg_surface->view->swayc); + container_view_destroy(sway_xdg_surface->view->swayc); free(sway_xdg_surface->view); free(sway_xdg_surface); - arrange_windows(parent, -1, -1); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 3e08b20e..357c8883 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -109,29 +109,17 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&sway_surface->destroy.link); wl_list_remove(&sway_surface->request_configure.link); wl_list_remove(&sway_surface->view->unmanaged_view_link); - - struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); - if (parent) { - arrange_windows(parent, -1, -1); - } - - free(sway_surface->view); - free(sway_surface); + container_view_destroy(sway_surface->view->swayc); + sway_surface->view->swayc = NULL; + sway_surface->view->surface = NULL; } static void handle_unmap_notify(struct wl_listener *listener, void *data) { struct sway_xwayland_surface *sway_surface = wl_container_of(listener, sway_surface, unmap_notify); - wl_list_remove(&sway_surface->view->unmanaged_view_link); wl_list_init(&sway_surface->view->unmanaged_view_link); - - // take it out of the tree - struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); - if (parent) { - arrange_windows(parent, -1, -1); - } - + container_view_destroy(sway_surface->view->swayc); sway_surface->view->swayc = NULL; sway_surface->view->surface = NULL; } diff --git a/sway/meson.build b/sway/meson.build index 9c5e4a00..e8a192f0 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -82,6 +82,7 @@ sway_sources = files( 'security.c', 'tree/container.c', 'tree/layout.c', + 'tree/output.c', 'tree/view.c', 'tree/workspace.c', ) diff --git a/sway/tree/container.c b/sway/tree/container.c index ed39a154..778108b4 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -10,12 +10,12 @@ #include "sway/tree/container.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" -#include "sway/tree/layout.h" +#include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" -#include "sway/ipc-server.h" #include "log.h" static list_t *bfs_queue; @@ -58,13 +58,14 @@ static struct sway_container *container_create(enum sway_container_type type) { return c; } -void container_destroy(struct sway_container *cont) { +struct sway_container *container_destroy(struct sway_container *cont) { if (cont == NULL) { - return; + return NULL; } wl_signal_emit(&cont->events.destroy, cont); + struct sway_container *parent = cont->parent; if (cont->children) { // remove children until there are no more, container_destroy calls // container_remove_child, which removes child from this container @@ -77,13 +78,14 @@ void container_destroy(struct sway_container *cont) { list_foreach(cont->marks, free); list_free(cont->marks); } - if (cont->parent) { + if (parent) { container_remove_child(cont); } if (cont->name) { free(cont->name); } free(cont); + return parent; } struct sway_container *container_output_create( @@ -202,95 +204,6 @@ struct sway_container *container_view_create(struct sway_container *sibling, return swayc; } -struct sway_container *container_output_destroy(struct sway_container *output) { - if (!sway_assert(output, "cannot destroy null output")) { - return NULL; - } - - if (output->children->length > 0) { - // TODO save workspaces when there are no outputs. - // TODO also check if there will ever be no outputs except for exiting - // program - if (root_container.children->length > 1) { - int p = root_container.children->items[0] == output; - // Move workspace from this output to another output - while (output->children->length) { - struct sway_container *child = output->children->items[0]; - container_remove_child(child); - container_add_child(root_container.children->items[p], child); - } - container_sort_workspaces(root_container.children->items[p]); - arrange_windows(root_container.children->items[p], - -1, -1); - } - } - - wl_list_remove(&output->sway_output->frame.link); - wl_list_remove(&output->sway_output->destroy.link); - wl_list_remove(&output->sway_output->mode.link); - - wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); - container_destroy(output); - - return &root_container; -} - -struct sway_container *container_workspace_destroy( - struct sway_container *workspace) { - if (!sway_assert(workspace, "cannot destroy null workspace")) { - return NULL; - } - - // Do not destroy this if it's the last workspace on this output - struct sway_container *output = container_parent(workspace, C_OUTPUT); - if (output && output->children->length == 1) { - return NULL; - } - - struct sway_container *parent = workspace->parent; - if (workspace->children->length == 0) { - // destroy the WS if there are no children (TODO check for floating) - wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); - ipc_event_workspace(workspace, NULL, "empty"); - } else { - // Move children to a different workspace on this output - struct sway_container *new_workspace = NULL; - // TODO move floating - for (int i = 0; i < output->children->length; i++) { - if (output->children->items[i] != workspace) { - new_workspace = output->children->items[i]; - break; - } - } - - wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", - workspace->name, new_workspace->name); - for (int i = 0; i < workspace->children->length; i++) { - container_move_to(workspace->children->items[i], new_workspace); - } - } - - container_destroy(workspace); - return parent; -} - -struct sway_container *container_view_destroy(struct sway_container *view) { - if (!view) { - return NULL; - } - wlr_log(L_DEBUG, "Destroying view '%s'", view->name); - struct sway_container *parent = view->parent; - container_destroy(view); - - // TODO WLR: Destroy empty containers - /* - if (parent && parent->type == C_CONTAINER) { - return destroy_container(parent); - } - */ - return parent; -} - struct sway_container *container_set_layout(struct sway_container *container, enum sway_container_layout layout) { if (container->type == C_WORKSPACE) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 73c4849b..32e6a77c 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -9,6 +9,7 @@ #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/output.h" +#include "sway/tree/workspace.h" #include "sway/tree/view.h" #include "sway/input/seat.h" #include "sway/ipc-server.h" @@ -99,40 +100,40 @@ void container_add_child(struct sway_container *parent, parent, parent->type, parent->width, parent->height); list_add(parent->children, child); child->parent = parent; - // set focus for this container - /* TODO WLR - if (parent->type == C_WORKSPACE && child->type == C_VIEW && - (parent->workspace_layout == L_TABBED || parent->workspace_layout == - L_STACKED)) { - child = new_container(child, parent->workspace_layout); +} + +struct sway_container *container_reap_empty(struct sway_container *container) { + if (!sway_assert(container, "reaping null container")) { + return NULL; } - */ + wlr_log(L_DEBUG, "reaping %p %s", container, container->name); + while (container->children->length == 0) { + if (container->type == C_WORKSPACE) { + if (!workspace_is_visible(container)) { + container_workspace_destroy(container); + } + break; + } else if (container->type == C_CONTAINER) { + struct sway_container *parent = container->parent; + container_destroy(container); + container = parent; + } else { + container = container->parent; + } + } + return container; } struct sway_container *container_remove_child(struct sway_container *child) { - int i; struct sway_container *parent = child->parent; - for (i = 0; i < parent->children->length; ++i) { + for (int i = 0; i < parent->children->length; ++i) { if (parent->children->items[i] == child) { list_del(parent->children, i); break; } } child->parent = NULL; - return parent; -} - -struct sway_container *container_reap_empty(struct sway_container *container) { - if (!sway_assert(container, "reaping null container")) { - return NULL; - } - while (container->children->length == 0 && container->type == C_CONTAINER) { - wlr_log(L_DEBUG, "Container: Destroying container '%p'", container); - struct sway_container *parent = container->parent; - container_destroy(container); - container = parent; - } - return container; + return container_reap_empty(parent); } void container_move_to(struct sway_container* container, @@ -145,16 +146,9 @@ void container_move_to(struct sway_container* container, container->width = container->height = 0; struct sway_container *new_parent = container_add_sibling(destination, container); - if (destination->type == C_WORKSPACE) { - // If the workspace only has one child after adding one, it - // means that the workspace was just initialized. - // TODO: Consider floating views in this test - if (destination->children->length == 1) { - ipc_event_workspace(NULL, destination, "init"); - } + if (old_parent) { + arrange_windows(old_parent, -1, -1); } - old_parent = container_reap_empty(old_parent); - arrange_windows(old_parent, -1, -1); arrange_windows(new_parent, -1, -1); } diff --git a/sway/tree/output.c b/sway/tree/output.c new file mode 100644 index 00000000..2246cb11 --- /dev/null +++ b/sway/tree/output.c @@ -0,0 +1,36 @@ +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/output.h" +#include "log.h" + +struct sway_container *container_output_destroy(struct sway_container *output) { + if (!sway_assert(output, "cannot destroy null output")) { + return NULL; + } + + if (output->children->length > 0) { + // TODO save workspaces when there are no outputs. + // TODO also check if there will ever be no outputs except for exiting + // program + if (root_container.children->length > 1) { + int p = root_container.children->items[0] == output; + // Move workspace from this output to another output + while (output->children->length) { + struct sway_container *child = output->children->items[0]; + container_remove_child(child); + container_add_child(root_container.children->items[p], child); + } + container_sort_workspaces(root_container.children->items[p]); + arrange_windows(root_container.children->items[p], + -1, -1); + } + } + + wl_list_remove(&output->sway_output->frame.link); + wl_list_remove(&output->sway_output->destroy.link); + wl_list_remove(&output->sway_output->mode.link); + + wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); + container_destroy(output); + return &root_container; +} diff --git a/sway/tree/view.c b/sway/tree/view.c index d5325c31..480ff693 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -3,6 +3,7 @@ #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" +#include "log.h" const char *view_get_title(struct sway_view *view) { if (view->iface.get_prop) { @@ -94,3 +95,13 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { } } } + +struct sway_container *container_view_destroy(struct sway_container *view) { + if (!view) { + return NULL; + } + wlr_log(L_DEBUG, "Destroying view '%s'", view->name); + struct sway_container *parent = container_destroy(view); + arrange_windows(parent, -1, -1); + return parent; +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 5800ea09..c629f1f1 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -6,9 +6,10 @@ #include #include #include "stringop.h" -#include "sway/tree/container.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/ipc-server.h" +#include "sway/tree/container.h" #include "sway/tree/workspace.h" #include "log.h" #include "util.h" @@ -202,7 +203,48 @@ struct sway_container *workspace_create(const char *name) { sway_seat_get_focus_inactive(seat, &root_container); parent = focus; parent = container_parent(parent, C_OUTPUT); - return container_workspace_create(parent, name); + struct sway_container *new_ws = container_workspace_create(parent, name); + ipc_event_workspace(NULL, new_ws, "init"); + return new_ws; +} + +struct sway_container *container_workspace_destroy( + struct sway_container *workspace) { + if (!sway_assert(workspace, "cannot destroy null workspace")) { + return NULL; + } + + // Do not destroy this if it's the last workspace on this output + struct sway_container *output = container_parent(workspace, C_OUTPUT); + if (output && output->children->length == 1) { + return NULL; + } + + struct sway_container *parent = workspace->parent; + if (workspace->children->length == 0) { + // destroy the WS if there are no children (TODO check for floating) + wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); + ipc_event_workspace(workspace, NULL, "empty"); + } else { + // Move children to a different workspace on this output + struct sway_container *new_workspace = NULL; + // TODO move floating + for (int i = 0; i < output->children->length; i++) { + if (output->children->items[i] != workspace) { + new_workspace = output->children->items[i]; + break; + } + } + + wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", + workspace->name, new_workspace->name); + for (int i = 0; i < workspace->children->length; i++) { + container_move_to(workspace->children->items[i], new_workspace); + } + } + + container_destroy(workspace); + return parent; } /** @@ -343,3 +385,13 @@ bool workspace_switch(struct sway_container *workspace) { arrange_windows(output, -1, -1); return true; } + +bool workspace_is_visible(struct sway_container *ws) { + struct sway_container *output = container_parent(ws, C_OUTPUT); + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = sway_seat_get_focus_inactive(seat, output); + if (focus->type != C_WORKSPACE) { + focus = container_parent(focus, C_WORKSPACE); + } + return focus == ws; +} -- cgit v1.2.3 From ae6d459000865f0a3a54a1d0429ee28b282a7954 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 10:49:52 -0400 Subject: Implement mouse warping --- sway/commands.c | 1 + sway/commands/mouse_warping.c | 19 +++++++++++++++++++ sway/input/cursor.c | 4 ++-- sway/input/seat.c | 18 ++++++++++++++++-- sway/meson.build | 1 + 5 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 sway/commands/mouse_warping.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index eee7f254..d983dcbb 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -101,6 +101,7 @@ static struct cmd_handler handlers[] = { { "include", cmd_include }, { "input", cmd_input }, { "mode", cmd_mode }, + { "mouse_warping", cmd_mouse_warping }, { "output", cmd_output }, { "seat", cmd_seat }, { "workspace", cmd_workspace }, diff --git a/sway/commands/mouse_warping.c b/sway/commands/mouse_warping.c new file mode 100644 index 00000000..eef32ce7 --- /dev/null +++ b/sway/commands/mouse_warping.c @@ -0,0 +1,19 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_mouse_warping(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "mouse_warping", EXPECTED_EQUAL_TO, 1))) { + return error; + } else if (strcasecmp(argv[0], "output") == 0) { + config->mouse_warping = true; + } else if (strcasecmp(argv[0], "none") == 0) { + config->mouse_warping = false; + } else { + return cmd_results_new(CMD_FAILURE, "mouse_warping", + "Expected 'mouse_warping output|none'"); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 74af6426..9cdd66d8 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -156,8 +156,8 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { cursor_send_pointer_motion(cursor, event->time_msec); } -static void handle_cursor_motion_absolute(struct wl_listener *listener, - void *data) { +static void handle_cursor_motion_absolute( + struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; diff --git a/sway/input/seat.c b/sway/input/seat.c index 8d592872..eab5cf40 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -333,15 +333,29 @@ void sway_seat_set_focus(struct sway_seat *seat, if (last_focus) { struct sway_container *last_ws = last_focus; if (last_ws && last_ws->type != C_WORKSPACE) { - last_ws = container_parent(last_focus, C_WORKSPACE); + last_ws = container_parent(last_ws, C_WORKSPACE); } if (last_ws) { - wlr_log(L_DEBUG, "sending workspace event"); ipc_event_workspace(last_ws, container, "focus"); if (last_ws->children->length == 0) { container_workspace_destroy(last_ws); } } + struct sway_container *last_output = last_focus; + if (last_output && last_output->type != C_OUTPUT) { + last_output = container_parent(last_output, C_OUTPUT); + } + struct sway_container *new_output = container; + if (new_output && new_output->type != C_OUTPUT) { + new_output = container_parent(new_output, C_OUTPUT); + } + if (new_output != last_output && config->mouse_warping) { + struct wlr_output *output = new_output->sway_output->wlr_output; + // TODO: Change container coords to layout coords + double x = container->x + output->lx + container->width / 2.0; + double y = container->y + output->ly + container->height / 2.0; + wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); + } } if (last_focus && last_focus->type == C_VIEW && diff --git a/sway/meson.build b/sway/meson.build index e8a192f0..5bc57964 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -63,6 +63,7 @@ sway_sources = files( 'commands/input/xkb_options.c', 'commands/input/xkb_rules.c', 'commands/input/xkb_variant.c', + 'commands/mouse_warping.c', 'commands/output.c', 'commands/reload.c', 'commands/workspace.c', -- cgit v1.2.3 From 9b38ef950fcf293ba11f54c14d8b3a87f050b154 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 10:11:15 -0400 Subject: Implement focus_follows_mouse Also contains two other small changes: - Clicking any button will focus the container clicked (not just left) - Remove seamless_mouse (doesn't make sense on wlroots) --- include/sway/config.h | 1 - sway/commands.c | 1 + sway/commands/focus_follows_mouse.c | 12 +++++++++ sway/config.c | 1 - sway/input/cursor.c | 53 +++++++++++++++++++------------------ sway/meson.build | 1 + 6 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 sway/commands/focus_follows_mouse.c (limited to 'sway/meson.build') diff --git a/include/sway/config.h b/include/sway/config.h index ac1105b4..03b51948 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -304,7 +304,6 @@ struct sway_config { bool reloading; bool reading; bool auto_back_and_forth; - bool seamless_mouse; bool show_marks; bool edge_gaps; diff --git a/sway/commands.c b/sway/commands.c index d983dcbb..90544220 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -98,6 +98,7 @@ static struct cmd_handler handlers[] = { { "bindsym", cmd_bindsym }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, + { "focus_follows_mouse", cmd_focus_follows_mouse }, { "include", cmd_include }, { "input", cmd_input }, { "mode", cmd_mode }, diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c new file mode 100644 index 00000000..661e7852 --- /dev/null +++ b/sway/commands/focus_follows_mouse.c @@ -0,0 +1,12 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { + return error; + } + config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index e9e7057d..0eecf7f6 100644 --- a/sway/config.c +++ b/sway/config.c @@ -178,7 +178,6 @@ static void config_defaults(struct sway_config *config) { config->active = false; config->failed = false; config->auto_back_and_forth = false; - config->seamless_mouse = true; config->reading = false; config->show_marks = true; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 9cdd66d8..35dd5dc8 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -125,7 +125,10 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor, struct wlr_seat *seat = cursor->seat->wlr_seat; struct wlr_surface *surface = NULL; double sx, sy; - container_at_cursor(cursor, &surface, &sx, &sy); + struct sway_container *c = container_at_cursor(cursor, &surface, &sx, &sy); + if (c && config->focus_follows_mouse) { + sway_seat_set_focus(cursor->seat, c); + } // reset cursor if switching between clients struct wl_client *client = NULL; @@ -170,33 +173,31 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, button); struct wlr_event_pointer_button *event = data; - if (event->button == BTN_LEFT) { - struct wlr_surface *surface = NULL; - double sx, sy; - struct sway_container *cont = - container_at_cursor(cursor, &surface, &sx, &sy); - // Avoid moving keyboard focus from a surface that accepts it to one - // that does not unless the change would move us to a new workspace. - // - // This prevents, for example, losing focus when clicking on swaybar. - // - // TODO: Replace this condition with something like - // !surface_accepts_keyboard_input - if (surface && cont && cont->type != C_VIEW) { - struct sway_container *new_ws = cont; - if (new_ws && new_ws->type != C_WORKSPACE) { - new_ws = container_parent(new_ws, C_WORKSPACE); - } - struct sway_container *old_ws = sway_seat_get_focus(cursor->seat); - if (old_ws && old_ws->type != C_WORKSPACE) { - old_ws = container_parent(old_ws, C_WORKSPACE); - } - if (new_ws != old_ws) { - sway_seat_set_focus(cursor->seat, cont); - } - } else { + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_container *cont = + container_at_cursor(cursor, &surface, &sx, &sy); + // Avoid moving keyboard focus from a surface that accepts it to one + // that does not unless the change would move us to a new workspace. + // + // This prevents, for example, losing focus when clicking on swaybar. + // + // TODO: Replace this condition with something like + // !surface_accepts_keyboard_input + if (surface && cont && cont->type != C_VIEW) { + struct sway_container *new_ws = cont; + if (new_ws && new_ws->type != C_WORKSPACE) { + new_ws = container_parent(new_ws, C_WORKSPACE); + } + struct sway_container *old_ws = sway_seat_get_focus(cursor->seat); + if (old_ws && old_ws->type != C_WORKSPACE) { + old_ws = container_parent(old_ws, C_WORKSPACE); + } + if (new_ws != old_ws) { sway_seat_set_focus(cursor->seat, cont); } + } else { + sway_seat_set_focus(cursor->seat, cont); } wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, diff --git a/sway/meson.build b/sway/meson.build index 5bc57964..0cc620ea 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -13,6 +13,7 @@ sway_sources = files( 'commands/exec.c', 'commands/exec_always.c', 'commands/focus.c', + 'commands/focus_follows_mouse.c', 'commands/kill.c', 'commands/include.c', 'commands/input.c', -- cgit v1.2.3 From 7706d83160267be61accb1b6f7bdc2f43299cae7 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 31 Mar 2018 00:44:17 -0400 Subject: basic split containers --- include/sway/input/seat.h | 2 +- include/sway/tree/container.h | 2 + include/sway/tree/layout.h | 3 ++ sway/commands.c | 4 ++ sway/commands/kill.c | 29 ++++++++---- sway/commands/split.c | 107 ++++++++++++++++++++++++++++++++++++++++++ sway/input/seat.c | 32 ++++++------- sway/meson.build | 1 + sway/tree/container.c | 7 +-- sway/tree/layout.c | 99 ++++++++++++++++++++++++++++++++------ 10 files changed, 240 insertions(+), 46 deletions(-) create mode 100644 sway/commands/split.c (limited to 'sway/meson.build') diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 31210a5a..38795e14 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -74,7 +74,7 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container); struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, - enum sway_container_type type); + struct sway_container *container, enum sway_container_type type); void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 6aa66da0..46f1c5ab 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -87,6 +87,8 @@ struct sway_container { } events; }; +struct sway_container *container_create(enum sway_container_type type); + // TODO only one container create function and pass the type? struct sway_container *container_output_create( struct sway_output *sway_output); diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 0a904c4b..79c14eda 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -54,4 +54,7 @@ void arrange_windows(struct sway_container *container, struct sway_container *container_get_in_direction(struct sway_container *container, struct sway_seat *seat, enum movement_direction dir); +struct sway_container *container_split(struct sway_container *child, + enum sway_container_layout layout); + #endif diff --git a/sway/commands.c b/sway/commands.c index 90544220..c85ddf7a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -163,6 +163,10 @@ static struct cmd_handler command_handlers[] = { { "kill", cmd_kill }, { "layout", cmd_layout }, { "reload", cmd_reload }, + { "split", cmd_split }, + { "splith", cmd_splith }, + { "splitt", cmd_splitt }, + { "splitv", cmd_splitv }, }; static int handler_compare(const void *_a, const void *_b) { diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f6774767..80120832 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c @@ -3,21 +3,30 @@ #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/tree/view.h" +#include "sway/tree/container.h" #include "sway/commands.h" struct cmd_results *cmd_kill(int argc, char **argv) { - enum sway_container_type type = config->handler_context.current_container->type; - if (type != C_VIEW && type != C_CONTAINER) { + struct sway_container *con = + config->handler_context.current_container; + + switch (con->type) { + case C_ROOT: + case C_OUTPUT: + case C_WORKSPACE: return cmd_results_new(CMD_INVALID, NULL, "Can only kill views and containers with this command"); - } - - // TODO close arbitrary containers without a view - struct sway_view *view = - config->handler_context.current_container->sway_view; - - if (view) { - view_close(view); + break; + case C_CONTAINER: + con = container_destroy(con); + con = container_reap_empty(con); + arrange_windows(con, -1, -1); + break; + case C_VIEW: + view_close(con->sway_view); + break; + default: + break; } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/split.c b/sway/commands/split.c new file mode 100644 index 00000000..6df20e88 --- /dev/null +++ b/sway/commands/split.c @@ -0,0 +1,107 @@ +#include +#include +#include "sway/commands.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/view.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "log.h" + +static struct cmd_results *_do_split(int argc, char **argv, int layout) { + char *name = layout == L_VERT ? "splitv" : + layout == L_HORIZ ? "splith" : "split"; + struct cmd_results *error = NULL; + if (config->reading) { + return cmd_results_new(CMD_FAILURE, name, + "Can't be used in config file."); + } + if (!config->active) { + return cmd_results_new(CMD_FAILURE, name, + "Can only be used when sway is running."); + } + if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { + return error; + } + + struct sway_container *focused = config->handler_context.current_container; + + // TODO floating: dont split + + /* Case that focus is on an workspace with 0/1 children.change its layout */ + if (focused->type == C_WORKSPACE && focused->children->length <= 1) { + wlr_log(L_DEBUG, "changing workspace layout"); + container_set_layout(focused, layout); + } else if (focused->type != C_WORKSPACE && + focused->parent->children->length == 1) { + /* Case of no siblings. change parent layout */ + wlr_log(L_DEBUG, "changing container layout"); + container_set_layout(focused->parent, layout); + } else { + // regular case where new split container is build around focused + // container or in case of workspace, container inherits its children + wlr_log(L_DEBUG, + "Adding new container around current focused container"); + wlr_log(L_INFO, "FOCUSED SIZE: %.f %.f", + focused->width, focused->height); + + struct sway_container *parent = container_split(focused, layout); + arrange_windows(parent, -1, -1); + } + + // TODO borders: update borders + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_split(int argc, char **argv) { + struct cmd_results *error = NULL; + if (config->reading) { + return cmd_results_new(CMD_FAILURE, "split", + "Can't be used in config file."); + } + if (!config->active) { + return cmd_results_new(CMD_FAILURE, "split", + "Can only be used when sway is running."); + } + if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { + return error; + } + if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { + _do_split(argc - 1, argv + 1, L_VERT); + } else if (strcasecmp(argv[0], "h") == 0 || + strcasecmp(argv[0], "horizontal") == 0) { + _do_split(argc - 1, argv + 1, L_HORIZ); + } else if (strcasecmp(argv[0], "t") == 0 || + strcasecmp(argv[0], "toggle") == 0) { + struct sway_container *focused = + config->handler_context.current_container; + if (focused->parent->layout == L_VERT) { + _do_split(argc - 1, argv + 1, L_HORIZ); + } else { + _do_split(argc - 1, argv + 1, L_VERT); + } + } else { + error = cmd_results_new(CMD_FAILURE, "split", + "Invalid split command (expected either horizontal or vertical)."); + return error; + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_splitv(int argc, char **argv) { + return _do_split(argc, argv, L_VERT); +} + +struct cmd_results *cmd_splith(int argc, char **argv) { + return _do_split(argc, argv, L_HORIZ); +} + +struct cmd_results *cmd_splitt(int argc, char **argv) { + struct sway_container *focused = config->handler_context.current_container; + if (focused->parent->layout == L_VERT) { + return _do_split(argc, argv, L_HORIZ); + } else { + return _do_split(argc, argv, L_VERT); + } +} diff --git a/sway/input/seat.c b/sway/input/seat.c index 9aa34aca..e0fd314a 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,4 +1,5 @@ #define _XOPEN_SOURCE 700 +#include #include #include #include @@ -378,6 +379,18 @@ void sway_seat_set_focus(struct sway_seat *seat, } struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) { + return sway_seat_get_focus_by_type(seat, container, C_TYPES); +} + +struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { + if (!seat->has_focus) { + return NULL; + } + return sway_seat_get_focus_inactive(seat, &root_container); +} + +struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, + struct sway_container *container, enum sway_container_type type) { struct sway_seat_container *current = NULL; struct sway_container *parent = NULL; wl_list_for_each(current, &seat->focus_stack, link) { @@ -388,7 +401,7 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, stru } while (parent) { - if (parent == container) { + if (parent == container && (type == C_TYPES || current->container->type == type)) { return current->container; } parent = parent->parent; @@ -398,23 +411,6 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, stru return NULL; } -struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { - if (!seat->has_focus) { - return NULL; - } - return sway_seat_get_focus_inactive(seat, &root_container); -} - -struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, - enum sway_container_type type) { - struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); - if (focus->type == type) { - return focus; - } - - return container_parent(focus, type); -} - void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config) { // clear configs diff --git a/sway/meson.build b/sway/meson.build index 0cc620ea..b4775d58 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -19,6 +19,7 @@ sway_sources = files( 'commands/input.c', 'commands/layout.c', 'commands/mode.c', + 'commands/split.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 746dbf1f..7b88cccb 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -38,7 +38,7 @@ static void notify_new_container(struct sway_container *container) { ipc_event_window(container, "new"); } -static struct sway_container *container_create(enum sway_container_type type) { +struct sway_container *container_create(enum sway_container_type type) { // next id starts at 1 because 0 is assigned to root_container in layout.c static size_t next_id = 1; struct sway_container *c = calloc(1, sizeof(struct sway_container)); @@ -66,13 +66,14 @@ struct sway_container *container_destroy(struct sway_container *cont) { wl_signal_emit(&cont->events.destroy, cont); struct sway_container *parent = cont->parent; - if (cont->children) { + if (cont->children != NULL) { // remove children until there are no more, container_destroy calls // container_remove_child, which removes child from this container - while (cont->children->length) { + while (cont->children->length != 0) { container_destroy(cont->children->items[0]); } list_free(cont->children); + cont->children = NULL; } if (cont->marks) { list_foreach(cont->marks, free); diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ce0682dc..62df19e9 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -100,6 +101,8 @@ void container_add_child(struct sway_container *parent, parent, parent->type, parent->width, parent->height); list_add(parent->children, child); child->parent = parent; + // TODO: set focus for this container? + sway_input_manager_set_focus(input_manager, child); } struct sway_container *container_reap_empty(struct sway_container *container) { @@ -135,7 +138,7 @@ struct sway_container *container_remove_child(struct sway_container *child) { } } child->parent = NULL; - return container_reap_empty(parent); + return parent; } void container_move_to(struct sway_container* container, @@ -322,7 +325,12 @@ static void apply_horiz_layout(struct sway_container *container, wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); - view_set_position(child->sway_view, child_x, y); + if (child->type == C_VIEW) { + view_set_position(child->sway_view, child_x, y); + } else { + child->x = child_x; + child->y = y; + } if (i == end - 1) { double remaining_width = x + width - child_x; @@ -505,9 +513,9 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { return NULL; } -static struct sway_container *get_swayc_in_direction_under( - struct sway_container *container, enum movement_direction dir, - struct sway_seat *seat, struct sway_container *limit) { +struct sway_container *container_get_in_direction( + struct sway_container *container, struct sway_seat *seat, + enum movement_direction dir) { if (dir == MOVE_CHILD) { return sway_seat_get_focus_inactive(seat, container); } @@ -559,7 +567,6 @@ static struct sway_container *get_swayc_in_direction_under( struct sway_container *wrap_candidate = NULL; while (true) { - // Test if we can even make a difference here bool can_move = false; int desired; int idx = index_child(container); @@ -589,7 +596,7 @@ static struct sway_container *get_swayc_in_direction_under( } if (next->children && next->children->length) { // TODO consider floating children as well - return sway_seat_get_focus_inactive(seat, next); + return sway_seat_get_focus_by_type(seat, next, C_VIEW); } else { return next; } @@ -619,21 +626,22 @@ static struct sway_container *get_swayc_in_direction_under( wrap_candidate = parent->children->items[0]; } if (config->force_focus_wrapping) { - return wrap_candidate; + return sway_seat_get_focus_by_type(seat, wrap_candidate, C_VIEW); } } } else { wlr_log(L_DEBUG, "cont %d-%p dir %i sibling %d: %p", idx, container, dir, desired, parent->children->items[desired]); - return parent->children->items[desired]; + return sway_seat_get_focus_by_type(seat, + parent->children->items[desired], C_VIEW); } } if (!can_move) { container = parent; parent = parent->parent; - if (!parent || container == limit) { + if (!parent) { // wrapping is the last chance return wrap_candidate; } @@ -641,8 +649,71 @@ static struct sway_container *get_swayc_in_direction_under( } } -struct sway_container *container_get_in_direction( - struct sway_container *container, struct sway_seat *seat, - enum movement_direction dir) { - return get_swayc_in_direction_under(container, dir, seat, NULL); +struct sway_container *container_replace_child(struct sway_container *child, + struct sway_container *new_child) { + struct sway_container *parent = child->parent; + if (parent == NULL) { + return NULL; + } + int i = index_child(child); + + // TODO floating + parent->children->items[i] = new_child; + new_child->parent = parent; + child->parent = NULL; + + // Set geometry for new child + new_child->x = child->x; + new_child->y = child->y; + new_child->width = child->width; + new_child->height = child->height; + + // reset geometry for child + child->width = 0; + child->height = 0; + + return parent; +} + +struct sway_container *container_split(struct sway_container *child, + enum sway_container_layout layout) { + // TODO floating: cannot split a floating container + if (!sway_assert(child, "child cannot be null")) { + return NULL; + } + struct sway_container *cont = container_create(C_CONTAINER); + + wlr_log(L_DEBUG, "creating container %p around %p", cont, child); + + cont->prev_layout = L_NONE; + cont->layout = layout; + cont->width = child->width; + cont->height = child->height; + cont->x = child->x; + cont->y = child->y; + + /* Container inherits all of workspaces children, layout and whatnot */ + if (child->type == C_WORKSPACE) { + struct sway_container *workspace = child; + // reorder focus + int i; + for (i = 0; i < workspace->children->length; ++i) { + ((struct sway_container *)workspace->children->items[i])->parent = + cont; + } + + // Swap children + list_t *tmp_list = workspace->children; + workspace->children = cont->children; + cont->children = tmp_list; + // add container to workspace chidren + container_add_child(workspace, cont); + // give them proper layouts + cont->layout = workspace->workspace_layout; + cont->prev_layout = workspace->prev_layout; + } else { // Or is built around container + container_replace_child(child, cont); + container_add_child(cont, child); + } + return cont; } -- cgit v1.2.3 From b2d871cfe215a82266d01847f4787bbcf8c721c9 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 21:21:26 -0400 Subject: Partially implement move command Works: - move [container|window] to workspace - Note, this should be able to move C_CONTAINER but this is untested - move [workspace] to output [left|right|up|down|] Not implemented yet: - move [left|right|up|down] - move scratchpad - move position --- include/sway/output.h | 2 + include/sway/tree/container.h | 5 ++ include/sway/tree/layout.h | 12 +-- sway/commands.c | 1 + sway/commands/focus.c | 7 +- sway/commands/move.c | 181 ++++++++++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 9 ++- sway/input/keyboard.c | 4 +- sway/meson.build | 1 + sway/tree/container.c | 18 +++++ sway/tree/layout.c | 58 ++++++++------ sway/tree/output.c | 11 +++ 12 files changed, 268 insertions(+), 41 deletions(-) create mode 100644 sway/commands/move.c (limited to 'sway/meson.build') diff --git a/include/sway/output.h b/include/sway/output.h index b4980cd8..b343ecff 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -36,4 +36,6 @@ void output_damage_whole(struct sway_output *output); void output_damage_whole_view(struct sway_output *output, struct sway_view *view); +struct sway_container *output_by_name(const char *name); + #endif diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 6aa66da0..aff2e58e 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -84,9 +84,14 @@ struct sway_container { struct { struct wl_signal destroy; + // Raised after the tree updates, but before arrange_windows + // Passed the previous parent + struct wl_signal reparent; } events; }; +const char *container_type_to_str(enum sway_container_type type); + // TODO only one container create function and pass the type? struct sway_container *container_output_create( struct sway_output *sway_output); diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 0a904c4b..e1034657 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -11,9 +11,6 @@ enum movement_direction { MOVE_DOWN, MOVE_PARENT, MOVE_CHILD, - MOVE_NEXT, - MOVE_PREV, - MOVE_FIRST }; struct sway_container; @@ -32,7 +29,8 @@ struct sway_root { void layout_init(void); -void container_add_child(struct sway_container *parent, struct sway_container *child); +void container_add_child(struct sway_container *parent, + struct sway_container *child); struct sway_container *container_add_sibling(struct sway_container *parent, struct sway_container *child); @@ -44,7 +42,11 @@ struct sway_container *container_reap_empty(struct sway_container *container); void container_move_to(struct sway_container* container, struct sway_container* destination); -enum sway_container_layout container_get_default_layout(struct sway_container *output); +void container_move(struct sway_container *container, + enum movement_direction dir, int move_amt); + +enum sway_container_layout container_get_default_layout( + struct sway_container *output); void container_sort_workspaces(struct sway_container *output); diff --git a/sway/commands.c b/sway/commands.c index 90544220..b6af3d1a 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -162,6 +162,7 @@ static struct cmd_handler command_handlers[] = { { "focus", cmd_focus }, { "kill", cmd_kill }, { "layout", cmd_layout }, + { "move", cmd_move }, { "reload", cmd_reload }, }; diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 64f079f4..0a521b9e 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -20,10 +20,6 @@ static bool parse_movement_direction(const char *name, *out = MOVE_PARENT; } else if (strcasecmp(name, "child") == 0) { *out = MOVE_CHILD; - } else if (strcasecmp(name, "next") == 0) { - *out = MOVE_NEXT; - } else if (strcasecmp(name, "prev") == 0) { - *out = MOVE_PREV; } else { return false; } @@ -51,7 +47,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) { "Expected 'focus ' or 'focus output '"); } - struct sway_container *next_focus = container_get_in_direction(con, seat, direction); + struct sway_container *next_focus = container_get_in_direction( + con, seat, direction); if (next_focus) { sway_seat_set_focus(seat, next_focus); } diff --git a/sway/commands/move.c b/sway/commands/move.c new file mode 100644 index 00000000..222ef314 --- /dev/null +++ b/sway/commands/move.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/input/seat.h" +#include "sway/output.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/workspace.h" +#include "stringop.h" +#include "list.h" + +static const char* expected_syntax = + "Expected 'move <[px] px>' or " + "'move to workspace ' or " + "'move to output ' or " + "'move position mouse'"; + +static struct sway_container *output_in_direction(const char *direction, + struct wlr_output *reference, int ref_ox, int ref_oy) { + int ref_lx = ref_ox + reference->lx, + ref_ly = ref_oy + reference->ly; + struct { + char *name; + enum wlr_direction direction; + } names[] = { + { "up", WLR_DIRECTION_UP }, + { "down", WLR_DIRECTION_DOWN }, + { "left", WLR_DIRECTION_LEFT }, + { "right", WLR_DIRECTION_RIGHT }, + }; + for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { + if (strcasecmp(names[i].name, direction) == 0) { + struct wlr_output *adjacent = wlr_output_layout_adjacent_output( + root_container.sway_root->output_layout, + names[i].direction, reference, ref_lx, ref_ly); + if (adjacent) { + struct sway_output *sway_output = adjacent->data; + return sway_output->swayc; + } + break; + } + } + return output_by_name(direction); +} + +static struct cmd_results *cmd_move_container(struct sway_container *current, + int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "move container/window", + EXPECTED_AT_LEAST, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") == 0 + && strcasecmp(argv[2], "workspace") == 0) { + // move container to workspace x + if (current->type == C_WORKSPACE) { + // TODO: Wrap children in a container and move that + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (current->type != C_CONTAINER && current->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", + "Can only move containers and views."); + } + struct sway_container *ws; + const char *num_name = NULL; + char *ws_name = NULL; + if (argc == 5 && strcasecmp(argv[3], "number") == 0) { + // move "container to workspace number x" + num_name = argv[4]; + ws = workspace_by_number(num_name); + } else { + ws_name = join_args(argv + 3, argc - 3); + ws = workspace_by_name(ws_name); + } + if (!ws) { + ws = workspace_create(ws_name ? ws_name : num_name); + } + free(ws_name); + struct sway_container *old_parent = current->parent; + struct sway_container *focus = sway_seat_get_focus_inactive( + config->handler_context.seat, ws); + container_move_to(current, focus); + sway_seat_set_focus(config->handler_context.seat, old_parent); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } else if (strcasecmp(argv[1], "to") == 0 + && strcasecmp(argv[2], "output") == 0) { + if (current->type == C_WORKSPACE) { + // TODO: Wrap children in a container and move that + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (current->type != C_CONTAINER + && current->type != C_VIEW) { + return cmd_results_new(CMD_FAILURE, "move", + "Can only move containers and views."); + } + struct sway_container *source = container_parent(current, C_OUTPUT); + struct sway_container *destination = output_in_direction(argv[3], + source->sway_output->wlr_output, current->x, current->y); + if (!destination) { + return cmd_results_new(CMD_FAILURE, "move workspace", + "Can't find output with name/direction '%s'", argv[3]); + } + struct sway_container *focus = sway_seat_get_focus_inactive( + config->handler_context.seat, destination); + if (!focus) { + // We've never been to this output before + focus = destination->children->items[0]; + } + container_move_to(current, focus); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + return cmd_results_new(CMD_INVALID, "move", expected_syntax); +} + +static struct cmd_results *cmd_move_workspace(struct sway_container *current, + int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { + return error; + } else if (strcasecmp(argv[1], "to") != 0 + || strcasecmp(argv[2], "output") != 0) { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + struct sway_container *source = container_parent(current, C_OUTPUT); + int center_x = current->width / 2 + current->x, + center_y = current->height / 2 + current->y; + struct sway_container *destination = output_in_direction(argv[3], + source->sway_output->wlr_output, center_x, center_y); + if (!destination) { + return cmd_results_new(CMD_FAILURE, "move workspace", + "Can't find output with name/direction '%s'", argv[3]); + } + if (current->type != C_WORKSPACE) { + current = container_parent(current, C_WORKSPACE); + } + container_move_to(current, destination); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_move(int argc, char **argv) { + struct cmd_results *error = NULL; + int move_amt = 10; + if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct sway_container *current = config->handler_context.current_container; + + if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) { + char *inv; + move_amt = (int)strtol(argv[1], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + move_amt = 10; + } + } + + if (strcasecmp(argv[0], "left") == 0) { + container_move(current, MOVE_LEFT, move_amt); + } else if (strcasecmp(argv[0], "right") == 0) { + container_move(current, MOVE_RIGHT, move_amt); + } else if (strcasecmp(argv[0], "up") == 0) { + container_move(current, MOVE_UP, move_amt); + } else if (strcasecmp(argv[0], "down") == 0) { + container_move(current, MOVE_DOWN, move_amt); + } else if (strcasecmp(argv[0], "container") == 0 + || strcasecmp(argv[0], "window") == 0) { + return cmd_move_container(current, argc, argv); + } else if (strcasecmp(argv[0], "workspace") == 0) { + return cmd_move_workspace(current, argc, argv); + } else if (strcasecmp(argv[0], "scratchpad") == 0 + || (strcasecmp(argv[0], "to") == 0 + && strcasecmp(argv[1], "scratchpad") == 0)) { + // TODO: scratchpad + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else if (strcasecmp(argv[0], "position") == 0) { + // TODO: floating + return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + } else { + return cmd_results_new(CMD_INVALID, "move", expected_syntax); + } + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0d706c52..c4265818 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -229,9 +229,12 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = sway_seat_get_focus_inactive(seat, output->swayc); - struct sway_container *workspace = (focus->type == C_WORKSPACE ? - focus : - container_parent(focus, C_WORKSPACE)); + if (!focus) { + // We've never been to this output before + focus = output->swayc->children->items[0]; + } + struct sway_container *workspace = focus->type == C_WORKSPACE ? + focus : container_parent(focus, C_WORKSPACE); struct render_data rdata = { .output = output, diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 99685052..8d22b684 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -97,8 +97,8 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, config->handler_context.seat = keyboard->seat_device->sway_seat; struct cmd_results *results = execute_command(binding->command, NULL); if (results->status != CMD_SUCCESS) { - wlr_log(L_DEBUG, "could not run command for binding: %s", - binding->command); + wlr_log(L_DEBUG, "could not run command for binding: %s (%s)", + binding->command, results->error); } free_cmd_results(results); } diff --git a/sway/meson.build b/sway/meson.build index 0cc620ea..38945b4c 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -19,6 +19,7 @@ sway_sources = files( 'commands/input.c', 'commands/layout.c', 'commands/mode.c', + 'commands/move.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 746dbf1f..21fe3fb0 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -33,6 +33,23 @@ static list_t *get_bfs_queue() { return bfs_queue; } +const char *container_type_to_str(enum sway_container_type type) { + switch (type) { + case C_ROOT: + return "C_ROOT"; + case C_OUTPUT: + return "C_OUTPUT"; + case C_WORKSPACE: + return "C_WORKSPACE"; + case C_CONTAINER: + return "C_CONTAINER"; + case C_VIEW: + return "C_VIEW"; + default: + return "C_UNKNOWN"; + } +} + static void notify_new_container(struct sway_container *container) { wl_signal_emit(&root_container.sway_root->events.new_container, container); ipc_event_window(container, "new"); @@ -54,6 +71,7 @@ static struct sway_container *container_create(enum sway_container_type type) { } wl_signal_init(&c->events.destroy); + wl_signal_init(&c->events.reparent); return c; } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ce0682dc..a8941a40 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -106,8 +106,10 @@ struct sway_container *container_reap_empty(struct sway_container *container) { if (!sway_assert(container, "reaping null container")) { return NULL; } - wlr_log(L_DEBUG, "reaping %p %s", container, container->name); - while (container != &root_container && container->children->length == 0) { + wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, + container_type_to_str(container->type), container->name); + while (container->type != C_ROOT && container->type != C_OUTPUT + && container->children->length == 0) { if (container->type == C_WORKSPACE) { if (!workspace_is_visible(container)) { struct sway_container *parent = container->parent; @@ -138,22 +140,46 @@ struct sway_container *container_remove_child(struct sway_container *child) { return container_reap_empty(parent); } -void container_move_to(struct sway_container* container, - struct sway_container* destination) { +void container_move_to(struct sway_container *container, + struct sway_container *destination) { if (container == destination || container_has_anscestor(container, destination)) { return; } struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; - struct sway_container *new_parent = - container_add_sibling(destination, container); + struct sway_container *new_parent; + if (destination->type == C_VIEW) { + new_parent = container_add_sibling(destination, container); + } else { + new_parent = destination; + container_add_child(destination, container); + } + wl_signal_emit(&container->events.reparent, old_parent); + if (container->type == C_WORKSPACE) { + struct sway_seat *seat = sway_input_manager_get_default_seat( + input_manager); + if (old_parent->children->length == 0) { + char *ws_name = workspace_next_name(old_parent->name); + struct sway_container *ws = + container_workspace_create(old_parent, ws_name); + free(ws_name); + sway_seat_set_focus(seat, ws); + } + container_sort_workspaces(new_parent); + sway_seat_set_focus(seat, new_parent); + } if (old_parent) { arrange_windows(old_parent, -1, -1); } arrange_windows(new_parent, -1, -1); } +void container_move(struct sway_container *container, + enum movement_direction dir, int move_amt) { + // TODO +} + enum sway_container_layout container_get_default_layout( struct sway_container *output) { if (config->default_layout != L_NONE) { @@ -521,26 +547,6 @@ static struct sway_container *get_swayc_in_direction_under( } } - if (dir == MOVE_PREV || dir == MOVE_NEXT) { - int focused_idx = index_child(container); - if (focused_idx == -1) { - return NULL; - } else { - int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % - parent->children->length; - if (desired < 0) { - desired += parent->children->length; - } - return parent->children->items[desired]; - } - } - - // If moving to an adjacent output we need a starting position (since this - // output might border to multiple outputs). - //struct wlc_point abs_pos; - //get_layout_center_position(container, &abs_pos); - - // TODO WLR fullscreen /* if (container->type == C_VIEW && swayc_is_fullscreen(container)) { diff --git a/sway/tree/output.c b/sway/tree/output.c index 7248fd00..2331dc2b 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -1,3 +1,4 @@ +#include #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/output.h" @@ -37,3 +38,13 @@ struct sway_container *container_output_destroy(struct sway_container *output) { container_destroy(output); return &root_container; } + +struct sway_container *output_by_name(const char *name) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if (strcasecmp(output->name, name) == 0){ + return output; + } + } + return NULL; +} -- cgit v1.2.3 From cba258e16ac4d37841b89f2b6a38e1056acae97b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 3 Apr 2018 12:39:03 -0400 Subject: move output code out of the tree --- sway/desktop/output.c | 11 +++++++++++ sway/meson.build | 1 - sway/tree/output.c | 15 --------------- 3 files changed, 11 insertions(+), 16 deletions(-) delete mode 100644 sway/tree/output.c (limited to 'sway/meson.build') diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a1f89cf9..e60fac5f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,16 @@ #include "sway/tree/layout.h" #include "sway/tree/view.h" +struct sway_container *output_by_name(const char *name) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + if (strcasecmp(output->name, name) == 0){ + return output; + } + } + return NULL; +} + /** * Rotate a child's position relative to a parent. The parent size is (pw, ph), * the child position is (*sx, *sy) and its size is (sw, sh). diff --git a/sway/meson.build b/sway/meson.build index a6a633a0..87d882d2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -86,7 +86,6 @@ sway_sources = files( 'security.c', 'tree/container.c', 'tree/layout.c', - 'tree/output.c', 'tree/view.c', 'tree/workspace.c', ) diff --git a/sway/tree/output.c b/sway/tree/output.c deleted file mode 100644 index af17b856..00000000 --- a/sway/tree/output.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include "sway/tree/container.h" -#include "sway/tree/layout.h" -#include "sway/output.h" -#include "log.h" - -struct sway_container *output_by_name(const char *name) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - if (strcasecmp(output->name, name) == 0){ - return output; - } - } - return NULL; -} -- cgit v1.2.3 From fa004dd0d78b922b75a6cc9c970824d18aa4e4aa Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 3 Apr 2018 20:00:09 -0400 Subject: move output create to its own file --- include/sway/tree/output.h | 0 sway/meson.build | 1 + sway/tree/container.c | 66 ----------------------------------------- sway/tree/output.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 66 deletions(-) create mode 100644 include/sway/tree/output.h create mode 100644 sway/tree/output.c (limited to 'sway/meson.build') diff --git a/include/sway/tree/output.h b/include/sway/tree/output.h new file mode 100644 index 00000000..e69de29b diff --git a/sway/meson.build b/sway/meson.build index 87d882d2..91aab0a0 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -88,6 +88,7 @@ sway_sources = files( 'tree/layout.c', 'tree/view.c', 'tree/workspace.c', + 'tree/output.c', ) sway_deps = [ diff --git a/sway/tree/container.c b/sway/tree/container.c index 8ed30b44..7f55ad90 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -7,7 +7,6 @@ #include #include #include -#include "log.h" #include "sway/config.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" @@ -312,71 +311,6 @@ struct sway_container *container_close(struct sway_container *con) { return parent; } -struct sway_container *output_create( - struct sway_output *sway_output) { - struct wlr_box size; - wlr_output_effective_resolution(sway_output->wlr_output, &size.width, - &size.height); - - const char *name = sway_output->wlr_output->name; - char identifier[128]; - output_get_identifier(identifier, sizeof(identifier), sway_output); - - struct output_config *oc = NULL, *all = NULL; - for (int i = 0; i < config->output_configs->length; ++i) { - struct output_config *cur = config->output_configs->items[i]; - - if (strcasecmp(name, cur->name) == 0 || - strcasecmp(identifier, cur->name) == 0) { - wlr_log(L_DEBUG, "Matched output config for %s", name); - oc = cur; - } - if (strcasecmp("*", cur->name) == 0) { - wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); - all = cur; - } - - if (oc && all) { - break; - } - } - if (!oc) { - oc = all; - } - - if (oc && !oc->enabled) { - return NULL; - } - - struct sway_container *output = container_create(C_OUTPUT); - output->sway_output = sway_output; - output->name = strdup(name); - if (output->name == NULL) { - container_destroy(output); - return NULL; - } - - apply_output_config(oc, output); - container_add_child(&root_container, output); - load_swaybars(); - - // Create workspace - char *ws_name = workspace_next_name(output->name); - wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); - struct sway_container *ws = workspace_create(output, ws_name); - // Set each seat's focus if not already set - struct sway_seat *seat = NULL; - wl_list_for_each(seat, &input_manager->seats, link) { - if (!seat->has_focus) { - seat_set_focus(seat, ws); - } - } - - free(ws_name); - container_create_notify(output); - return output; -} - struct sway_container *container_view_create(struct sway_container *sibling, struct sway_view *sway_view) { if (!sway_assert(sibling, diff --git a/sway/tree/output.c b/sway/tree/output.c new file mode 100644 index 00000000..6c7044a2 --- /dev/null +++ b/sway/tree/output.c @@ -0,0 +1,73 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include "sway/output.h" +#include "sway/tree/output.h" +#include "sway/tree/workspace.h" +#include "log.h" + +struct sway_container *output_create( + struct sway_output *sway_output) { + struct wlr_box size; + wlr_output_effective_resolution(sway_output->wlr_output, &size.width, + &size.height); + + const char *name = sway_output->wlr_output->name; + char identifier[128]; + output_get_identifier(identifier, sizeof(identifier), sway_output); + + struct output_config *oc = NULL, *all = NULL; + for (int i = 0; i < config->output_configs->length; ++i) { + struct output_config *cur = config->output_configs->items[i]; + + if (strcasecmp(name, cur->name) == 0 || + strcasecmp(identifier, cur->name) == 0) { + wlr_log(L_DEBUG, "Matched output config for %s", name); + oc = cur; + } + if (strcasecmp("*", cur->name) == 0) { + wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); + all = cur; + } + + if (oc && all) { + break; + } + } + if (!oc) { + oc = all; + } + + if (oc && !oc->enabled) { + return NULL; + } + + struct sway_container *output = container_create(C_OUTPUT); + output->sway_output = sway_output; + output->name = strdup(name); + if (output->name == NULL) { + container_destroy(output); + return NULL; + } + + apply_output_config(oc, output); + container_add_child(&root_container, output); + load_swaybars(); + + // Create workspace + char *ws_name = workspace_next_name(output->name); + wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); + struct sway_container *ws = workspace_create(output, ws_name); + // Set each seat's focus if not already set + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input_manager->seats, link) { + if (!seat->has_focus) { + seat_set_focus(seat, ws); + } + } + + free(ws_name); + container_create_notify(output); + return output; +} + -- cgit v1.2.3 From fc9398a42e1dfc15bbb8490c049981034abb4926 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 3 Apr 2018 00:47:45 -0400 Subject: Implement opacity command --- include/sway/commands.h | 1 + include/sway/tree/container.h | 2 ++ sway/commands.c | 1 + sway/commands/opacity.c | 39 +++++++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 34 ++++++++++++++++++---------------- sway/meson.build | 1 + sway/sway.5.txt | 4 ++++ sway/tree/container.c | 2 ++ 8 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 sway/commands/opacity.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index 66f097ea..edb5a213 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -123,6 +123,7 @@ sway_cmd cmd_mark; sway_cmd cmd_mode; sway_cmd cmd_mouse_warping; sway_cmd cmd_move; +sway_cmd cmd_opacity; sway_cmd cmd_new_float; sway_cmd cmd_new_window; sway_cmd cmd_no_focus; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 277165ea..3a3a9429 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -83,6 +83,8 @@ struct sway_container { list_t *marks; // list of char* + float alpha; + struct { struct wl_signal destroy; // Raised after the tree updates, but before arrange_windows diff --git a/sway/commands.c b/sway/commands.c index 8156a08e..2786a879 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -163,6 +163,7 @@ static struct cmd_handler command_handlers[] = { { "kill", cmd_kill }, { "layout", cmd_layout }, { "move", cmd_move }, + { "opacity", cmd_opacity }, { "reload", cmd_reload }, { "split", cmd_split }, { "splith", cmd_splith }, diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c new file mode 100644 index 00000000..b8cd1f09 --- /dev/null +++ b/sway/commands/opacity.c @@ -0,0 +1,39 @@ +#include +#include +#include "sway/commands.h" +#include "sway/tree/view.h" +#include "log.h" + +static bool parse_opacity(const char *opacity, float *val) { + char *err; + *val = strtof(opacity, &err); + if (*val < 0 || *val > 1 || *err) { + return false; + } + return true; +} + +struct cmd_results *cmd_opacity(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "layout", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_container *con = + config->handler_context.current_container; + + float opacity = 0.0f; + + if (!parse_opacity(argv[0], &opacity)) { + return cmd_results_new(CMD_INVALID, "opacity ", + "Invalid value (expected 0..1): %s", argv[0]); + } + + con->alpha = opacity; + + if (con->type == C_VIEW) { + view_damage_whole(con->sway_view); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8a4fb4a2..6cf5da48 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -75,7 +75,7 @@ static bool surface_intersect_output(struct wlr_surface *surface, static void render_surface(struct wlr_surface *surface, struct wlr_output *wlr_output, struct timespec *when, - double ox, double oy, float rotation) { + double ox, double oy, float rotation, float alpha) { struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); @@ -95,8 +95,8 @@ static void render_surface(struct wlr_surface *surface, wlr_matrix_project_box(matrix, &box, transform, rotation, wlr_output->transform_matrix); - // TODO: configurable alpha - wlr_render_texture_with_matrix(renderer, surface->texture, matrix, 1.0f); + wlr_render_texture_with_matrix(renderer, surface->texture, + matrix, alpha); wlr_surface_send_frame_done(surface, when); } @@ -110,13 +110,13 @@ static void render_surface(struct wlr_surface *surface, surface->current->width, surface->current->height, rotation); render_surface(subsurface->surface, wlr_output, when, - ox + sx, oy + sy, rotation); + ox + sx, oy + sy, rotation, alpha); } } static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, struct wlr_output *wlr_output, struct timespec *when, double base_x, - double base_y, float rotation) { + double base_y, float rotation, float alpha) { double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -136,19 +136,19 @@ static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, width, height, rotation); render_surface(popup->surface, wlr_output, when, - base_x + popup_sx, base_y + popup_sy, rotation); + base_x + popup_sx, base_y + popup_sy, rotation, alpha); render_xdg_v6_popups(popup, wlr_output, when, - base_x + popup_sx, base_y + popup_sy, rotation); + base_x + popup_sx, base_y + popup_sy, rotation, alpha); } } static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, struct wlr_output *wlr_output, struct timespec *when, - double lx, double ly, float rotation, + double lx, double ly, float rotation, float alpha, bool is_child) { if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { render_surface(surface->surface, wlr_output, when, - lx, ly, rotation); + lx, ly, rotation, alpha); double width = surface->surface->current->width; double height = surface->surface->current->height; @@ -164,7 +164,7 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, width, height, rotation); render_wl_shell_surface(popup, wlr_output, when, - lx + popup_x, ly + popup_y, rotation, true); + lx + popup_x, ly + popup_y, rotation, alpha, true); } } } @@ -181,6 +181,7 @@ static void render_view(struct sway_container *view, void *data) { struct wlr_output *wlr_output = output->wlr_output; struct sway_view *sway_view = view->sway_view; struct wlr_surface *surface = sway_view->surface; + float alpha = sway_view->swayc->alpha; if (!surface) { return; @@ -191,17 +192,18 @@ static void render_view(struct sway_container *view, void *data) { int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x; int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; render_surface(surface, wlr_output, when, - view->x - window_offset_x, view->y - window_offset_y, 0); + view->x - window_offset_x, view->y - window_offset_y, 0, alpha); render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, - when, view->x - window_offset_x, view->y - window_offset_y, 0); + when, view->x - window_offset_x, view->y - window_offset_y, 0, alpha); break; } case SWAY_WL_SHELL_VIEW: render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, - when, view->x, view->y, 0, false); + when, view->x, view->y, 0, alpha, false); break; case SWAY_XWAYLAND_VIEW: - render_surface(surface, wlr_output, when, view->x, view->y, 0); + render_surface(surface, wlr_output, when, view->x, view->y, + 0, alpha); break; default: break; @@ -214,7 +216,7 @@ static void render_layer(struct sway_output *output, struct timespec *when, wl_list_for_each(sway_layer, layer, link) { struct wlr_layer_surface *layer = sway_layer->layer_surface; render_surface(layer->surface, output->wlr_output, when, - sway_layer->geo.x, sway_layer->geo.y, 0); + sway_layer->geo.x, sway_layer->geo.y, 0, 1.0f); wlr_surface_send_frame_done(layer->surface, when); } } @@ -288,7 +290,7 @@ static void render_output(struct sway_output *output, struct timespec *when, } render_surface(xsurface->surface, wlr_output, &output->last_frame, - view_box.x - output_box->x, view_box.y - output_box->y, 0); + view_box.x - output_box->x, view_box.y - output_box->y, 0, 1.0f); } // TODO: Consider revising this when fullscreen windows are supported diff --git a/sway/meson.build b/sway/meson.build index 91aab0a0..f210c195 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -15,6 +15,7 @@ sway_sources = files( 'commands/focus.c', 'commands/focus_follows_mouse.c', 'commands/kill.c', + 'commands/opacity.c', 'commands/include.c', 'commands/input.c', 'commands/layout.c', diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 900e499a..59c3295a 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -413,6 +413,10 @@ The default colors are: However, any mark that starts with an underscore will not be drawn even if the option is on. The default option is _on_. +**opacity** :: + Set the opacity of the window between 0 (completely transparent) and 1 + (completely opaque). + **unmark** :: **Unmark** will remove _identifier_ from the list of current marks on a window. If no _identifier_ is specified, then **unmark** will remove all marks. diff --git a/sway/tree/container.c b/sway/tree/container.c index 753f333c..3be08645 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -72,6 +72,8 @@ struct sway_container *container_create(enum sway_container_type type) { c->layout = L_NONE; c->workspace_layout = L_NONE; c->type = type; + c->alpha = 1.0f; + if (type != C_VIEW) { c->children = create_list(); } -- cgit v1.2.3 From f77986338fc4186d003908012685c12d718ed647 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 4 Apr 2018 21:32:31 -0400 Subject: Implement resize command --- config.in | 16 +-- include/sway/tree/layout.h | 10 ++ sway/commands.c | 1 + sway/commands/resize.c | 284 +++++++++++++++++++++++++++++++++++++++++++++ sway/meson.build | 46 +++++--- sway/tree/layout.c | 21 ++++ 6 files changed, 351 insertions(+), 27 deletions(-) create mode 100644 sway/commands/resize.c (limited to 'sway/meson.build') diff --git a/config.in b/config.in index 086b66dc..54817f2a 100644 --- a/config.in +++ b/config.in @@ -164,16 +164,16 @@ mode "resize" { # right will grow the containers width # up will shrink the containers height # down will grow the containers height - bindsym $left resize shrink width 10 px or 10 ppt - bindsym $down resize grow height 10 px or 10 ppt - bindsym $up resize shrink height 10 px or 10 ppt - bindsym $right resize grow width 10 px or 10 ppt + bindsym $left resize shrink width 10px + bindsym $down resize grow height 10px + bindsym $up resize shrink height 10px + bindsym $right resize grow width 10px # ditto, with arrow keys - bindsym Left resize shrink width 10 px or 10 ppt - bindsym Down resize grow height 10 px or 10 ppt - bindsym Up resize shrink height 10 px or 10 ppt - bindsym Right resize grow width 10 px or 10 ppt + bindsym Left resize shrink width 10px + bindsym Down resize grow height 10px + bindsym Up resize shrink height 10px + bindsym Right resize grow width 10px # return to default mode bindsym Return mode "default" diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 784dcc9b..fc5ce21f 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -13,6 +13,13 @@ enum movement_direction { MOVE_CHILD, }; +enum resize_edge { + RESIZE_EDGE_LEFT, + RESIZE_EDGE_RIGHT, + RESIZE_EDGE_TOP, + RESIZE_EDGE_BOTTOM, +}; + struct sway_container; struct sway_root { @@ -63,4 +70,7 @@ struct sway_container *container_get_in_direction(struct sway_container struct sway_container *container_split(struct sway_container *child, enum sway_container_layout layout); +void container_recursive_resize(struct sway_container *container, + double amount, enum resize_edge edge); + #endif diff --git a/sway/commands.c b/sway/commands.c index 2786a879..22decef3 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -165,6 +165,7 @@ static struct cmd_handler command_handlers[] = { { "move", cmd_move }, { "opacity", cmd_opacity }, { "reload", cmd_reload }, + { "resize", cmd_resize }, { "split", cmd_split }, { "splith", cmd_splith }, { "splitt", cmd_splitt }, diff --git a/sway/commands/resize.c b/sway/commands/resize.c new file mode 100644 index 00000000..93c1fe7d --- /dev/null +++ b/sway/commands/resize.c @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/tree/layout.h" +#include "log.h" + +static const int MIN_SANE_W = 100, MIN_SANE_H = 60; + +enum resize_unit { + RESIZE_UNIT_PX, + RESIZE_UNIT_PPT, + RESIZE_UNIT_DEFAULT, + RESIZE_UNIT_INVALID, +}; + +enum resize_axis { + RESIZE_AXIS_HORIZONTAL, + RESIZE_AXIS_VERTICAL, + RESIZE_AXIS_INVALID, +}; + +static enum resize_unit parse_resize_unit(const char *unit) { + if (strcasecmp(unit, "px") == 0) { + return RESIZE_UNIT_PX; + } + if (strcasecmp(unit, "ppt") == 0) { + return RESIZE_UNIT_PPT; + } + if (strcasecmp(unit, "default") == 0) { + return RESIZE_UNIT_DEFAULT; + } + return RESIZE_UNIT_INVALID; +} + +static enum resize_axis parse_resize_axis(const char *axis) { + if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { + return RESIZE_AXIS_HORIZONTAL; + } + if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { + return RESIZE_AXIS_VERTICAL; + } + return RESIZE_AXIS_INVALID; +} + +static int parallel_coord(struct sway_container *c, enum resize_axis a) { + return a == RESIZE_AXIS_HORIZONTAL ? c->x : c->y; +} + +static int parallel_size(struct sway_container *c, enum resize_axis a) { + return a == RESIZE_AXIS_HORIZONTAL ? c->width : c->height; +} + +static void resize_tiled(int amount, enum resize_axis axis) { + struct sway_container *parent = config->handler_context.current_container; + struct sway_container *focused = parent; + if (!parent) { + return; + } + + enum sway_container_layout parallel_layout = + axis == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; + int minor_weight = 0; + int major_weight = 0; + while (parent->parent) { + struct sway_container *next = parent->parent; + if (next->layout == parallel_layout) { + for (int i = 0; i < next->children->length; i++) { + struct sway_container *sibling = next->children->items[i]; + + int sibling_pos = parallel_coord(sibling, axis); + int focused_pos = parallel_coord(focused, axis); + int parent_pos = parallel_coord(parent, axis); + + if (sibling_pos != focused_pos) { + if (sibling_pos < parent_pos) { + minor_weight++; + } else if (sibling_pos > parent_pos) { + major_weight++; + } + } + } + if (major_weight || minor_weight) { + break; + } + } + parent = next; + } + + if (parent->type == C_ROOT) { + return; + } + + wlr_log(L_DEBUG, + "Found the proper parent: %p. It has %d l conts, and %d r conts", + parent->parent, minor_weight, major_weight); + + int min_sane = axis == RESIZE_AXIS_HORIZONTAL ? MIN_SANE_W : MIN_SANE_H; + + //TODO: Ensure rounding is done in such a way that there are NO pixel leaks + // ^ ????? + + for (int i = 0; i < parent->parent->children->length; i++) { + struct sway_container *sibling = parent->parent->children->items[i]; + + int sibling_pos = parallel_coord(sibling, axis); + int focused_pos = parallel_coord(focused, axis); + int parent_pos = parallel_coord(parent, axis); + + int sibling_size = parallel_size(sibling, axis); + int parent_size = parallel_size(parent, axis); + + if (sibling_pos != focused_pos) { + if (sibling_pos < parent_pos) { + double pixels = -amount / minor_weight; + if (major_weight && (sibling_size + pixels / 2) < min_sane) { + return; // Too small + } else if ((sibling_size + pixels) < min_sane) { + return; // Too small + } + } else if (sibling_pos > parent_pos) { + double pixels = -amount / major_weight; + if (minor_weight && (sibling_size + pixels / 2) < min_sane) { + return; // Too small + } else if ((sibling_size + pixels) < min_sane) { + return; // Too small + } + } + } else { + double pixels = amount; + if (parent_size + pixels < min_sane) { + return; // Too small + } + } + } + + enum resize_edge minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? + RESIZE_EDGE_LEFT : RESIZE_EDGE_TOP; + enum resize_edge major_edge = axis == RESIZE_AXIS_HORIZONTAL ? + RESIZE_EDGE_RIGHT : RESIZE_EDGE_BOTTOM; + + for (int i = 0; i < parent->parent->children->length; i++) { + struct sway_container *sibling = parent->parent->children->items[i]; + + int sibling_pos = parallel_coord(sibling, axis); + int focused_pos = parallel_coord(focused, axis); + int parent_pos = parallel_coord(parent, axis); + + if (sibling_pos != focused_pos) { + if (sibling_pos < parent_pos) { + double pixels = -1 * amount; + pixels /= minor_weight; + if (major_weight) { + container_recursive_resize(sibling, pixels / 2, major_edge); + } else { + container_recursive_resize(sibling, pixels, major_edge); + } + } else if (sibling_pos > parent_pos) { + double pixels = -1 * amount; + pixels /= major_weight; + if (minor_weight) { + container_recursive_resize(sibling, pixels / 2, minor_edge); + } else { + container_recursive_resize(sibling, pixels, minor_edge); + } + } + } else { + if (major_weight != 0 && minor_weight != 0) { + double pixels = amount; + pixels /= 2; + container_recursive_resize(parent, pixels, minor_edge); + container_recursive_resize(parent, pixels, major_edge); + } else if (major_weight) { + container_recursive_resize(parent, amount, major_edge); + } else if (minor_weight) { + container_recursive_resize(parent, amount, minor_edge); + } + } + } + + arrange_windows(parent->parent, -1, -1); +} + +static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { + struct sway_container *current = config->handler_context.current_container; + if (unit == RESIZE_UNIT_DEFAULT) { + // Default for tiling; TODO floating should be px + unit = RESIZE_UNIT_PPT; + } + + if (unit == RESIZE_UNIT_PPT) { + float pct = amount / 100.0f; + switch (axis) { + case RESIZE_AXIS_HORIZONTAL: + amount = (float)current->width * pct; + break; + case RESIZE_AXIS_VERTICAL: + amount = (float)current->height * pct; + break; + default: + sway_assert(0, "invalid resize axis"); + return; + } + } + + return resize_tiled(amount, axis); +} + +struct cmd_results *cmd_resize(int argc, char **argv) { + struct sway_container *current = config->handler_context.current_container; + if (!current) { + return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); + } + if (current->type != C_VIEW && current->type != C_CONTAINER) { + return cmd_results_new(CMD_INVALID, "resize", + "Can only resize views/containers"); + } + if (strcasecmp(argv[0], "set") == 0) { + // TODO + //return cmd_resize_set(argc - 1, &argv[1]); + return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented"); + } + struct cmd_results *error; + if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { + return error; + } + + // TODO: resize grow|shrink left|right|up|down + + const char *usage = "Expected 'resize " + " [] [px|ppt]'"; + + int multiplier = 0; + if (strcasecmp(*argv, "grow") == 0) { + multiplier = 1; + } else if (strcasecmp(*argv, "shrink") == 0) { + multiplier = -1; + } else { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + --argc; ++argv; + + enum resize_axis axis = parse_resize_axis(*argv); + if (axis == RESIZE_AXIS_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + --argc; ++argv; + + int amount = 10; // Default amount + enum resize_unit unit = RESIZE_UNIT_DEFAULT; + + if (argc) { + char *err; + amount = (int)strtol(*argv, &err, 10); + if (*err) { + // e.g. `resize grow width 10px` + unit = parse_resize_unit(err); + if (unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + } + --argc; ++argv; + } + + if (argc) { + unit = parse_resize_unit(*argv); + if (unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + --argc; ++argv; + } + + if (argc) { + // Provied too many args, the bastard + return cmd_results_new(CMD_INVALID, "resize", usage); + } + + resize(amount * multiplier, axis, unit); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index f210c195..ec7b4c42 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -2,10 +2,28 @@ sway_sources = files( 'main.c', 'server.c', 'commands.c', + 'config.c', + 'criteria.c', + 'ipc-json.c', + 'ipc-server.c', + 'security.c', + + 'desktop/output.c', + 'desktop/layer_shell.c', + 'desktop/wl_shell.c', + 'desktop/xdg_shell_v6.c', + 'desktop/xwayland.c', + 'input/input-manager.c', 'input/seat.c', 'input/cursor.c', 'input/keyboard.c', + + 'config/bar.c', + 'config/output.c', + 'config/seat.c', + 'config/input.c', + 'commands/bar.c', 'commands/bind.c', 'commands/default_orientation.c', @@ -20,13 +38,19 @@ sway_sources = files( 'commands/input.c', 'commands/layout.c', 'commands/mode.c', - 'commands/split.c', + 'commands/mouse_warping.c', 'commands/move.c', + 'commands/output.c', + 'commands/reload.c', + 'commands/resize.c', 'commands/seat.c', 'commands/seat/attach.c', 'commands/seat/fallback.c', 'commands/set.c', + 'commands/split.c', 'commands/swaybg_command.c', + 'commands/workspace.c', + 'commands/bar/activate_button.c', 'commands/bar/binding_mode_indicator.c', 'commands/bar/bindsym.c', @@ -51,6 +75,7 @@ sway_sources = files( 'commands/bar/tray_padding.c', 'commands/bar/workspace_buttons.c', 'commands/bar/wrap_scroll.c', + 'commands/input/accel_profile.c', 'commands/input/click_method.c', 'commands/input/drag_lock.c', @@ -67,24 +92,7 @@ sway_sources = files( 'commands/input/xkb_options.c', 'commands/input/xkb_rules.c', 'commands/input/xkb_variant.c', - 'commands/mouse_warping.c', - 'commands/output.c', - 'commands/reload.c', - 'commands/workspace.c', - 'config.c', - 'config/bar.c', - 'config/output.c', - 'config/seat.c', - 'config/input.c', - 'criteria.c', - 'ipc-json.c', - 'ipc-server.c', - 'desktop/output.c', - 'desktop/layer_shell.c', - 'desktop/wl_shell.c', - 'desktop/xdg_shell_v6.c', - 'desktop/xwayland.c', - 'security.c', + 'tree/container.c', 'tree/layout.c', 'tree/view.c', diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 5abdbc32..7e2c61ed 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -729,3 +729,24 @@ struct sway_container *container_split(struct sway_container *child, return cont; } + +void container_recursive_resize(struct sway_container *container, + double amount, enum resize_edge edge) { + bool layout_match = true; + wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); + if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { + container->width += amount; + layout_match = container->layout == L_HORIZ; + } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { + container->height += amount; + layout_match = container->layout == L_VERT; + } + if (container->children) { + for (int i = 0; i < container->children->length; i++) { + struct sway_container *child = container->children->items[i]; + double amt = layout_match ? + amount / container->children->length : amount; + container_recursive_resize(child, amt, edge); + } + } +} -- cgit v1.2.3 From 1c91d0c10ffbed14cafaba79276a14f55172b7eb Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 5 Apr 2018 17:37:24 -0400 Subject: Add damage tracking for xwayland unmanaged surfaces --- include/sway/desktop.h | 7 +++++++ include/sway/output.h | 3 +++ sway/desktop/desktop.c | 20 ++++++++++++++++++++ sway/desktop/output.c | 6 ++++++ sway/desktop/xwayland.c | 22 +++++++++++++--------- sway/meson.build | 1 + 6 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 include/sway/desktop.h create mode 100644 sway/desktop/desktop.c (limited to 'sway/meson.build') diff --git a/include/sway/desktop.h b/include/sway/desktop.h new file mode 100644 index 00000000..96bdc94c --- /dev/null +++ b/include/sway/desktop.h @@ -0,0 +1,7 @@ +#include + +void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, + double ly); + +void desktop_damage_from_surface(struct wlr_surface *surface, double lx, + double ly); diff --git a/include/sway/output.h b/include/sway/output.h index 98d0f83f..9964a484 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -37,6 +37,9 @@ void output_damage_whole(struct sway_output *output); void output_damage_whole_view(struct sway_output *output, struct sway_view *view); +void output_damage_whole_surface(struct sway_output *output, + struct wlr_surface *surface, double ox, double oy); + struct sway_container *output_by_name(const char *name); #endif diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c new file mode 100644 index 00000000..78a2d49f --- /dev/null +++ b/sway/desktop/desktop.c @@ -0,0 +1,20 @@ +#include "sway/tree/container.h" +#include "sway/desktop.h" +#include "sway/output.h" + +void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, + double ly) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT) { + output_damage_whole_surface(cont->sway_output, surface, + lx - cont->x, ly - cont->y); + } + } +} + +void desktop_damage_from_surface(struct wlr_surface *surface, double lx, + double ly) { + // TODO + desktop_damage_whole_surface(surface, lx, ly); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0e8a9485..0ae5e782 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -341,6 +341,12 @@ void output_damage_whole_view(struct sway_output *output, output_damage_whole(output); } +void output_damage_whole_surface(struct sway_output *output, + struct wlr_surface *surface, double ox, double oy) { + // TODO + output_damage_whole(output); +} + static void damage_handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, damage_destroy); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 3842c2c8..4797b801 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -2,17 +2,18 @@ #include #include #include -#include #include #include +#include +#include "log.h" +#include "sway/desktop.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/output.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" -#include "sway/server.h" #include "sway/tree/view.h" -#include "sway/output.h" -#include "sway/input/seat.h" -#include "sway/input/input-manager.h" -#include "log.h" static void unmanaged_handle_request_configure(struct wl_listener *listener, void *data) { @@ -27,7 +28,9 @@ static void unmanaged_handle_request_configure(struct wl_listener *listener, static void unmanaged_handle_commit(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, commit); - // TODO: damage tracking + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + desktop_damage_from_surface(xsurface->surface, xsurface->x, xsurface->y); + // TODO: handle window motion } static void unmanaged_handle_map(struct wl_listener *listener, void *data) { @@ -38,15 +41,16 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { &surface->link); wl_signal_add(&xsurface->surface->events.commit, &surface->commit); surface->commit.notify = unmanaged_handle_commit; - // TODO: damage tracking + desktop_damage_whole_surface(xsurface->surface, xsurface->x, xsurface->y); } static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, unmap); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + desktop_damage_whole_surface(xsurface->surface, xsurface->x, xsurface->y); wl_list_remove(&surface->link); wl_list_remove(&surface->commit.link); - // TODO: damage tracking } static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/meson.build b/sway/meson.build index ec7b4c42..29aaa7b7 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -8,6 +8,7 @@ sway_sources = files( 'ipc-server.c', 'security.c', + 'desktop/desktop.c', 'desktop/output.c', 'desktop/layer_shell.c', 'desktop/wl_shell.c', -- cgit v1.2.3 From 603e0e42c577026f1c688c393989e65dc3482808 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 6 Apr 2018 11:49:27 -0400 Subject: Add debug tree view --- include/sway/debug.h | 7 +++ include/sway/tree/layout.h | 4 +- sway/debug-tree.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ sway/desktop/output.c | 5 +++ sway/input/seat.c | 3 ++ sway/main.c | 6 ++- sway/meson.build | 4 ++ sway/tree/layout.c | 8 ++++ 8 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 include/sway/debug.h create mode 100644 sway/debug-tree.c (limited to 'sway/meson.build') diff --git a/include/sway/debug.h b/include/sway/debug.h new file mode 100644 index 00000000..2430d319 --- /dev/null +++ b/include/sway/debug.h @@ -0,0 +1,7 @@ +#ifndef SWAY_DEBUG_H +#define SWAY_DEBUG_H + +extern bool enable_debug_tree; +void update_debug_tree(); + +#endif diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index fc5ce21f..49ae00e4 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h @@ -1,7 +1,7 @@ #ifndef _SWAY_LAYOUT_H #define _SWAY_LAYOUT_H - #include +#include #include "sway/tree/container.h" enum movement_direction { @@ -29,6 +29,8 @@ struct sway_root { struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link + struct wlr_texture *debug_tree; + struct { struct wl_signal new_container; } events; diff --git a/sway/debug-tree.c b/sway/debug-tree.c new file mode 100644 index 00000000..08ee3585 --- /dev/null +++ b/sway/debug-tree.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include "config.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/server.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "cairo.h" +#include "config.h" +#include "pango.h" + +static const char *layout_to_str(enum sway_container_layout layout) { + switch (layout) { + case L_HORIZ: + return "L_HORIZ"; + case L_VERT: + return "L_VERT"; + case L_STACKED: + return "L_STACKED"; + case L_TABBED: + return "L_TABBED"; + case L_FLOATING: + return "L_FLOATING"; + case L_NONE: + default: + return "L_NONE"; + } +} + +static int draw_container(cairo_t *cairo, struct sway_container *container, + struct sway_container *focus, int x, int y) { + int text_width, text_height; + get_text_size(cairo, "monospace", &text_width, &text_height, + 1, false, "%s '%s' %s %dx%d@%d,%d", + container_type_to_str(container->type), container->name, + layout_to_str(container->layout), + container->width, container->height, container->x, container->y); + cairo_rectangle(cairo, x, y, text_width, text_height); + cairo_set_source_u32(cairo, 0xFFFFFFFF); + cairo_fill(cairo); + cairo_move_to(cairo, x, y); + if (focus == container) { + cairo_set_source_u32(cairo, 0xFF0000FF); + } else { + cairo_set_source_u32(cairo, 0x000000FF); + } + pango_printf(cairo, "monospace", 1, false, "%s '%s' %s %dx%d@%d,%d", + container_type_to_str(container->type), container->name, + layout_to_str(container->layout), + container->width, container->height, container->x, container->y); + int height = text_height; + if (container->children) { + for (int i = 0; i < container->children->length; ++i) { + struct sway_container *child = container->children->items[i]; + height += draw_container(cairo, child, focus, x + 10, y + height); + } + } + return height; +} + +bool enable_debug_tree = false; + +void update_debug_tree() { + if (!enable_debug_tree) { + return; + } + + int width = 640, height = 480; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *container = root_container.children->items[i]; + if (container->width > width) { + width = container->width; + } + if (container->height > height) { + height = container->height; + } + } + cairo_surface_t *surface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cairo_t *cairo = cairo_create(surface); + PangoContext *pango = pango_cairo_create_context(cairo); + + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &input_manager->seats, link) { + break; + } + + struct sway_container *focus; + if (seat != NULL) { + focus = seat_get_focus(seat); + } + draw_container(cairo, &root_container, focus, 0, 0); + + cairo_surface_flush(surface); + struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend); + if (root_container.sway_root->debug_tree) { + wlr_texture_destroy(root_container.sway_root->debug_tree); + } + unsigned char *data = cairo_image_surface_get_data(surface); + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + struct wlr_texture *texture = wlr_texture_from_pixels(renderer, + WL_SHM_FORMAT_ARGB8888, stride, width, height, data); + root_container.sway_root->debug_tree = texture; + cairo_surface_destroy(surface); + g_object_unref(pango); + cairo_destroy(cairo); +} diff --git a/sway/desktop/output.c b/sway/desktop/output.c index aa18f1b8..ad777796 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -294,6 +294,11 @@ static void render_output(struct sway_output *output, struct timespec *when, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); renderer_end: + if (root_container.sway_root->debug_tree) { + wlr_render_texture(renderer, root_container.sway_root->debug_tree, + wlr_output->transform_matrix, 0, 0, 1); + } + wlr_renderer_end(renderer); if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { return; diff --git a/sway/input/seat.c b/sway/input/seat.c index ad3584a0..e8cf9824 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -5,6 +5,7 @@ #include #include #include +#include "sway/debug.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" #include "sway/input/seat.h" @@ -432,6 +433,8 @@ void seat_set_focus_warp(struct sway_seat *seat, } seat->has_focus = (container != NULL); + + update_debug_tree(); } void seat_set_focus(struct sway_seat *seat, diff --git a/sway/main.c b/sway/main.c index e7f8ddd3..efb674b6 100644 --- a/sway/main.c +++ b/sway/main.c @@ -17,6 +17,7 @@ #endif #include #include "sway/config.h" +#include "sway/debug.h" #include "sway/server.h" #include "sway/tree/layout.h" #include "sway/ipc-server.h" @@ -288,7 +289,7 @@ int main(int argc, char **argv) { int c; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "hCdvVc:", long_options, &option_index); + c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index); if (c == -1) { break; } @@ -306,6 +307,9 @@ int main(int argc, char **argv) { case 'd': // debug debug = 1; break; + case 'D': // extended debug options + enable_debug_tree = true; + break; case 'v': // version fprintf(stdout, "sway version " SWAY_VERSION "\n"); exit(EXIT_SUCCESS); diff --git a/sway/meson.build b/sway/meson.build index 29aaa7b7..1fe0f29a 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -4,6 +4,7 @@ sway_sources = files( 'commands.c', 'config.c', 'criteria.c', + 'debug-tree.c', 'ipc-json.c', 'ipc-server.c', 'security.c', @@ -102,10 +103,13 @@ sway_sources = files( ) sway_deps = [ + cairo, + gdk_pixbuf, jsonc, libcap, libinput, math, + pango, pcre, pixman, server_protos, diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 0011a9e3..e633acc6 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -6,6 +6,7 @@ #include #include #include +#include "sway/debug.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/output.h" @@ -431,6 +432,11 @@ void container_move(struct sway_container *container, return; } + if (old_parent) { + seat_set_focus(config->handler_context.seat, old_parent); + seat_set_focus(config->handler_context.seat, container); + } + struct sway_container *last_ws = old_parent; struct sway_container *next_ws = container->parent; if (last_ws && last_ws->type != C_WORKSPACE) { @@ -594,6 +600,8 @@ void arrange_windows(struct sway_container *container, break; } container_damage_whole(container); + // TODO: Make this less shitty + update_debug_tree(); } static void apply_horiz_layout(struct sway_container *container, -- cgit v1.2.3 From 042b80b9faef72c36451eecb5c803223fda3264a Mon Sep 17 00:00:00 2001 From: db Date: Sun, 8 Apr 2018 16:44:59 +0200 Subject: Add workspace_auto_back_and_forth command This is the only missing piece - other code regarding this functionality has already been ported from pre-wlroots source. --- sway/commands.c | 1 + sway/commands/ws_auto_back_and_forth.c | 12 ++++++++++++ sway/meson.build | 1 + 3 files changed, 14 insertions(+) create mode 100644 sway/commands/ws_auto_back_and_forth.c (limited to 'sway/meson.build') diff --git a/sway/commands.c b/sway/commands.c index 22decef3..20b8a2aa 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -106,6 +106,7 @@ static struct cmd_handler handlers[] = { { "output", cmd_output }, { "seat", cmd_seat }, { "workspace", cmd_workspace }, + { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, }; static struct cmd_handler bar_handlers[] = { diff --git a/sway/commands/ws_auto_back_and_forth.c b/sway/commands/ws_auto_back_and_forth.c new file mode 100644 index 00000000..2485db35 --- /dev/null +++ b/sway/commands/ws_auto_back_and_forth.c @@ -0,0 +1,12 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_ws_auto_back_and_forth(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1))) { + return error; + } + config->auto_back_and_forth = !strcasecmp(argv[0], "yes"); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 1fe0f29a..2521069f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -52,6 +52,7 @@ sway_sources = files( 'commands/split.c', 'commands/swaybg_command.c', 'commands/workspace.c', + 'commands/ws_auto_back_and_forth.c', 'commands/bar/activate_button.c', 'commands/bar/binding_mode_indicator.c', -- cgit v1.2.3 From 0e3ddf255ef56b7fe2b868232b80d04ea961120b Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 8 Apr 2018 14:15:13 -0400 Subject: Add input "identifier" map_to_output "identifier" --- include/sway/commands.h | 1 + include/sway/config.h | 4 +++- sway/commands.c | 1 + sway/commands/input/map_to_output.c | 27 +++++++++++++++++++++++++++ sway/config/input.c | 4 ++++ sway/input/seat.c | 30 ++++++++++++++++++++++++++++++ sway/meson.build | 1 + sway/sway-input.5.txt | 20 ++++++++++++++++++++ 8 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 sway/commands/input/map_to_output.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index edb5a213..bc5d5412 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -192,6 +192,7 @@ sway_cmd input_cmd_drag_lock; sway_cmd input_cmd_dwt; sway_cmd input_cmd_events; sway_cmd input_cmd_left_handed; +sway_cmd input_cmd_map_to_output; sway_cmd input_cmd_middle_emulation; sway_cmd input_cmd_natural_scroll; sway_cmd input_cmd_pointer_accel; diff --git a/include/sway/config.h b/include/sway/config.h index 91f772b5..ed49fbbd 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -52,7 +52,7 @@ struct sway_mode { }; /** - * libinput options for input devices + * options for input devices */ struct input_config { char *identifier; @@ -75,6 +75,8 @@ struct input_config { char *xkb_rules; char *xkb_variant; + char *mapped_output; + bool capturable; struct wlr_box region; }; diff --git a/sway/commands.c b/sway/commands.c index 20b8a2aa..55929659 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -187,6 +187,7 @@ static struct cmd_handler input_handlers[] = { { "dwt", input_cmd_dwt }, { "events", input_cmd_events }, { "left_handed", input_cmd_left_handed }, + { "map_to_output", input_cmd_map_to_output }, { "middle_emulation", input_cmd_middle_emulation }, { "natural_scroll", input_cmd_natural_scroll }, { "pointer_accel", input_cmd_pointer_accel }, diff --git a/sway/commands/input/map_to_output.c b/sway/commands/input/map_to_output.c new file mode 100644 index 00000000..60e4608e --- /dev/null +++ b/sway/commands/input/map_to_output.c @@ -0,0 +1,27 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "log.h" + +struct cmd_results *input_cmd_map_to_output(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "map_to_output", EXPECTED_EQUAL_TO, 1))) { + return error; + } + struct input_config *current_input_config = + config->handler_context.input_config; + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "map_to_output", + "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + new_config->mapped_output = strdup(argv[0]); + apply_input_config(new_config); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config/input.c b/sway/config/input.c index c4f6211d..5e657c43 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -88,6 +88,10 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { free(dst->xkb_variant); dst->xkb_variant = strdup(src->xkb_variant); } + if (src->mapped_output) { + free(dst->mapped_output); + dst->mapped_output = strdup(src->mapped_output); + } } struct input_config *copy_input_config(struct input_config *ic) { diff --git a/sway/input/seat.c b/sway/input/seat.c index d9b42828..7b01fe88 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1,6 +1,7 @@ #define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 199309L #include +#include #include #include #include @@ -219,10 +220,38 @@ struct sway_seat *seat_create(struct sway_input_manager *input, return seat; } +static void seat_apply_input_config(struct sway_seat *seat, + struct sway_seat_device *sway_device) { + struct input_config *ic = input_device_get_config( + sway_device->input_device); + if (!ic) { + return; + } + wlr_log(L_DEBUG, "Applying input config to %s", + sway_device->input_device->identifier); + if (ic->mapped_output) { + struct sway_container *output = NULL; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *_output = root_container.children->items[i]; + if (strcasecmp(_output->name, ic->mapped_output) == 0) { + output = _output; + break; + } + } + if (output) { + wlr_cursor_map_input_to_output(seat->cursor->cursor, + sway_device->input_device->wlr_device, + output->sway_output->wlr_output); + wlr_log(L_DEBUG, "Mapped to output %s", output->name); + } + } +} + static void seat_configure_pointer(struct sway_seat *seat, struct sway_seat_device *sway_device) { wlr_cursor_attach_input_device(seat->cursor->cursor, sway_device->input_device->wlr_device); + seat_apply_input_config(seat, sway_device); } static void seat_configure_keyboard(struct sway_seat *seat, @@ -249,6 +278,7 @@ static void seat_configure_tablet_tool(struct sway_seat *seat, struct sway_seat_device *sway_device) { wlr_cursor_attach_input_device(seat->cursor->cursor, sway_device->input_device->wlr_device); + seat_apply_input_config(seat, sway_device); } static struct sway_seat_device *seat_get_device(struct sway_seat *seat, diff --git a/sway/meson.build b/sway/meson.build index 2521069f..d0730296 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -85,6 +85,7 @@ sway_sources = files( 'commands/input/dwt.c', 'commands/input/events.c', 'commands/input/left_handed.c', + 'commands/input/map_to_output.c', 'commands/input/middle_emulation.c', 'commands/input/natural_scroll.c', 'commands/input/pointer_accel.c', diff --git a/sway/sway-input.5.txt b/sway/sway-input.5.txt index 0603616b..05725360 100644 --- a/sway/sway-input.5.txt +++ b/sway/sway-input.5.txt @@ -40,6 +40,26 @@ For more information on these xkb configuration options, see **input** xkb_variant :: Sets the variant of the keyboard like _dvorak_ or _colemak_. +Mapping Configuration +--------------------- + +**input** map_to_output :: + Maps inputs from this device to the specified output. Only meaningful if the + device is a pointer, touch, or drawing tablet device. + +**input** map_to_region :: + Maps inputs from this device to the specified region of the global output + layout. Only meaningful if the device is a pointer, touch, or drawing tablet + device. + +**input** map_region :: + Ignores inputs from this device that do not occur within the specified region. + Can be in millimeters (e.g. 10mmx20mm\@10mm,20mm) or in terms of 0..1 (e.g. + 0.5x0.5\@0,0). Not all devices support millimeters. Only meaningful if the + device is not a keyboard an provides events in absolute terms (such as a + drawing tablet or touch screen - most pointers provide events relative to the + previous frame). + Libinput Configuration ~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 1edb2bd89254069066bab51d316962e85d4445b4 Mon Sep 17 00:00:00 2001 From: Danny Bautista Date: Tue, 10 Apr 2018 11:32:37 -0400 Subject: Implement cursor event simulation with sway commands. --- include/sway/commands.h | 3 +- include/sway/input/cursor.h | 1 + sway/commands.c | 1 + sway/commands/seat.c | 2 ++ sway/commands/seat/cursor.c | 83 +++++++++++++++++++++++++++++++++++++++++++++ sway/input/cursor.c | 2 +- sway/meson.build | 1 + 7 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 sway/commands/seat/cursor.c (limited to 'sway/meson.build') diff --git a/include/sway/commands.h b/include/sway/commands.h index bc5d5412..dbebaa49 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -204,8 +204,9 @@ sway_cmd input_cmd_xkb_options; sway_cmd input_cmd_xkb_rules; sway_cmd input_cmd_xkb_variant; -sway_cmd seat_cmd_fallback; sway_cmd seat_cmd_attach; +sway_cmd seat_cmd_fallback; +sway_cmd seat_cmd_cursor; sway_cmd cmd_ipc_cmd; sway_cmd cmd_ipc_events; diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index daf7d4ee..30169aa1 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -30,5 +30,6 @@ struct sway_cursor { void sway_cursor_destroy(struct sway_cursor *cursor); struct sway_cursor *sway_cursor_create(struct sway_seat *seat); void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time); +void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state); #endif diff --git a/sway/commands.c b/sway/commands.c index 55929659..54d84450 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -203,6 +203,7 @@ static struct cmd_handler input_handlers[] = { // must be in order for the bsearch static struct cmd_handler seat_handlers[] = { { "attach", seat_cmd_attach }, + { "cursor", seat_cmd_cursor }, { "fallback", seat_cmd_fallback }, }; diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 819b769c..5916015f 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -40,6 +40,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) { struct cmd_results *res; if (strcasecmp("attach", argv[1]) == 0) { res = seat_cmd_attach(argc_new, argv_new); + } else if (strcasecmp("cursor", argv[1]) == 0) { + res = seat_cmd_cursor(argc_new, argv_new); } else if (strcasecmp("fallback", argv[1]) == 0) { res = seat_cmd_fallback(argc_new, argv_new); } else { diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c new file mode 100644 index 00000000..2f2aa5ca --- /dev/null +++ b/sway/commands/seat/cursor.c @@ -0,0 +1,83 @@ +#define _XOPEN_SOURCE 700 +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif + +#include +#include +#include "sway/commands.h" +#include "sway/input/cursor.h" + +static struct cmd_results *press_or_release(struct sway_cursor *cursor, char *action, char *button_str); + +static const char *expected_syntax = "Expected 'cursor ' or " + "'cursor ' or " + "'curor '"; + +struct cmd_results *seat_cmd_cursor(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "cursor", EXPECTED_AT_LEAST, 2))) { + return error; + } + struct sway_seat *seat = config->handler_context.seat; + if (!seat) { + return cmd_results_new(CMD_FAILURE, "cursor", "No seat defined"); + } + + struct sway_cursor *cursor = seat->cursor; + + if (strcasecmp(argv[0], "move") == 0) { + if (argc < 3) { + return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); + } + int delta_x = strtol(argv[1], NULL, 10); + int delta_y = strtol(argv[2], NULL, 10); + wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y); + cursor_send_pointer_motion(cursor, 1); + } else if (strcasecmp(argv[0], "set") == 0) { + if (argc < 3) { + return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); + } + // map absolute coords (0..1,0..1) to root container coords + float x = strtof(argv[1], NULL) / root_container.width; + float y = strtof(argv[2], NULL) / root_container.height; + wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); + cursor_send_pointer_motion(cursor, 0); + } else { + if (argc < 2) { + return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); + } + if ((error = press_or_release(cursor, argv[0], argv[1]))) { + return error; + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *press_or_release(struct sway_cursor *cursor, char *action, char *button_str) { + enum wlr_button_state state; + uint32_t button; + if (strcasecmp(action, "press") == 0) { + state = WLR_BUTTON_PRESSED; + } else if (strcasecmp(action, "release") == 0) { + state = WLR_BUTTON_RELEASED; + } else { + return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); + } + + if (strcasecmp(button_str, "left") == 0) { + button = BTN_LEFT; + } else if (strcasecmp(button_str, "right") == 0) { + button = BTN_RIGHT; + } else { + button = strtol(button_str, NULL, 10); + if (button == 0) { + return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); + } + } + dispatch_cursor_button(cursor, 1, button, state); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 0df01504..15a61cbf 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -166,7 +166,7 @@ static void handle_cursor_motion_absolute( cursor_send_pointer_motion(cursor, event->time_msec); } -static void dispatch_cursor_button(struct sway_cursor *cursor, +void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, uint32_t button, enum wlr_button_state state) { struct wlr_surface *surface = NULL; double sx, sy; diff --git a/sway/meson.build b/sway/meson.build index d0730296..9e55e335 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -47,6 +47,7 @@ sway_sources = files( 'commands/resize.c', 'commands/seat.c', 'commands/seat/attach.c', + 'commands/seat/cursor.c', 'commands/seat/fallback.c', 'commands/set.c', 'commands/split.c', -- cgit v1.2.3