aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/pango.c9
-rw-r--r--include/sway/config.h27
-rw-r--r--include/sway/input/input-manager.h23
-rw-r--r--include/sway/input/seat.h37
-rw-r--r--include/sway/output.h3
-rw-r--r--include/sway/tree/container.h76
-rw-r--r--include/sway/tree/layout.h26
-rw-r--r--include/sway/tree/view.h59
-rw-r--r--include/swaybar/ipc.h2
-rw-r--r--include/swaybar/status_line.h53
-rw-r--r--protocols/desktop-shell.xml138
-rw-r--r--protocols/gamma-control.xml57
-rw-r--r--protocols/server-decoration.xml94
-rw-r--r--protocols/swaylock.xml18
-rw-r--r--protocols/xdg-shell.xml430
-rw-r--r--sway/commands.c25
-rw-r--r--sway/commands/focus.c11
-rw-r--r--sway/commands/kill.c27
-rw-r--r--sway/commands/move.c184
-rw-r--r--sway/commands/seat.c11
-rw-r--r--sway/commands/split.c76
-rw-r--r--sway/commands/workspace.c2
-rw-r--r--sway/config.c2
-rw-r--r--sway/desktop/layer_shell.c27
-rw-r--r--sway/desktop/output.c100
-rw-r--r--sway/desktop/wl_shell.c61
-rw-r--r--sway/desktop/xdg_shell_v6.c67
-rw-r--r--sway/desktop/xwayland.c136
-rw-r--r--sway/input/cursor.c32
-rw-r--r--sway/input/input-manager.c144
-rw-r--r--sway/input/keyboard.c6
-rw-r--r--sway/input/seat.c251
-rw-r--r--sway/ipc-json.c8
-rw-r--r--sway/ipc-server.c6
-rw-r--r--sway/main.c2
-rw-r--r--sway/meson.build2
-rw-r--r--sway/server.c2
-rw-r--r--sway/tree/container.c56
-rw-r--r--sway/tree/layout.c181
-rw-r--r--sway/tree/output.c12
-rw-r--r--sway/tree/view.c188
-rw-r--r--sway/tree/workspace.c16
-rw-r--r--swaybar/bar.c4
-rw-r--r--swaybar/i3bar.c211
-rw-r--r--swaybar/ipc.c2
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/render.c238
-rw-r--r--swaybar/status_line.c69
48 files changed, 1854 insertions, 1358 deletions
diff --git a/common/pango.c b/common/pango.c
index 2ae7883c..658d2876 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "log.h"
PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
const char *text, int32_t scale, bool markup) {
@@ -13,7 +14,13 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
PangoAttrList *attrs;
if (markup) {
char *buf;
- pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, NULL);
+ GError *error = NULL;
+ if (!sway_assert(pango_parse_markup(
+ text, -1, 0, &attrs, &buf, NULL, &error),
+ "pango_parse_markup '%s' -> error %s", text,
+ error ? error->message : NULL)) {
+ return NULL;
+ }
pango_layout_set_markup(layout, buf, -1);
free(buf);
} else {
diff --git a/include/sway/config.h b/include/sway/config.h
index 03b51948..91f772b5 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -377,6 +377,7 @@ void free_config(struct sway_config *config);
void config_clear_handler_context(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.
*/
@@ -385,44 +386,68 @@ char *do_var_replacement(char *str);
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);
+
struct input_config *copy_input_config(struct input_config *ic);
+
void free_input_config(struct input_config *ic);
+
void apply_input_config(struct input_config *input);
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);
+
struct seat_config *copy_seat_config(struct seat_config *seat);
+
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);
+
void apply_seat_config(struct seat_config *seat);
int output_name_cmp(const void *item, const void *data);
+
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output);
+
struct output_config *new_output_config(const char *name);
+
void merge_output_config(struct output_config *dst, struct output_config *src);
+
void apply_output_config(struct output_config *oc,
struct sway_container *output);
+
void free_output_config(struct output_config *oc);
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);
-/* Bar stuff */
void load_swaybars();
+
void invoke_swaybar(struct bar_config *bar);
+
void terminate_swaybg(pid_t pid);
+
struct bar_config *default_bar_config(void);
+
void free_bar_config(struct bar_config *bar);
/* Global config singleton. */
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h
index c6c73dba..8e39a4a7 100644
--- a/include/sway/input/input-manager.h
+++ b/include/sway/input/input-manager.h
@@ -14,7 +14,6 @@ extern struct sway_input_manager *input_manager;
struct sway_input_device {
char *identifier;
struct wlr_input_device *wlr_device;
- struct input_config *config;
struct wl_list link;
struct wl_listener device_destroy;
};
@@ -27,30 +26,34 @@ struct sway_input_manager {
struct wl_listener new_input;
};
-struct sway_input_manager *sway_input_manager_create(
- struct sway_server *server);
+struct sway_input_manager *input_manager_create(struct sway_server *server);
-bool sway_input_manager_has_focus(struct sway_input_manager *input,
+bool input_manager_has_focus(struct sway_input_manager *input,
struct sway_container *container);
-void sway_input_manager_set_focus(struct sway_input_manager *input,
+void input_manager_set_focus(struct sway_input_manager *input,
struct sway_container *container);
-void sway_input_manager_configure_xcursor(struct sway_input_manager *input);
+void input_manager_configure_xcursor(struct sway_input_manager *input);
-void sway_input_manager_apply_input_config(struct sway_input_manager *input,
+void 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,
+void 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_seat *input_manager_get_default_seat(
struct sway_input_manager *input);
struct sway_seat *input_manager_get_seat(struct sway_input_manager *input,
const char *seat_name);
-/** Gets the last seat the user interacted with */
+/**
+ * Gets the last seat the user interacted with
+ */
struct sway_seat *input_manager_current_seat(struct sway_input_manager *input);
+struct input_config *input_device_get_config(struct sway_input_device *device);
+
+
#endif
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 31210a5a..137fcd22 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -1,6 +1,7 @@
#ifndef _SWAY_INPUT_SEAT_H
#define _SWAY_INPUT_SEAT_H
+#include <wlr/types/wlr_layer_shell.h>
#include <wlr/types/wlr_seat.h>
#include "sway/input/input-manager.h"
@@ -8,7 +9,6 @@ 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
};
@@ -23,13 +23,15 @@ struct sway_seat_container {
struct sway_seat {
struct wlr_seat *wlr_seat;
- struct seat_config *config;
struct sway_cursor *cursor;
struct sway_input_manager *input;
bool has_focus;
struct wl_list focus_stack; // list of containers in focus order
+ // If the focused layer is set, views cannot receive keyboard focus
+ struct wlr_layer_surface *focused_layer;
+
struct wl_listener focus_destroy;
struct wl_listener new_container;
@@ -38,28 +40,31 @@ struct sway_seat {
struct wl_list link; // input_manager::seats
};
-struct sway_seat *sway_seat_create(struct sway_input_manager *input,
+struct sway_seat *seat_create(struct sway_input_manager *input,
const char *seat_name);
-void sway_seat_destroy(struct sway_seat *seat);
+void seat_destroy(struct sway_seat *seat);
-void sway_seat_add_device(struct sway_seat *seat,
+void seat_add_device(struct sway_seat *seat,
struct sway_input_device *device);
-void sway_seat_configure_device(struct sway_seat *seat,
+void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *device);
-void sway_seat_remove_device(struct sway_seat *seat,
+void seat_remove_device(struct sway_seat *seat,
struct sway_input_device *device);
-void sway_seat_configure_xcursor(struct sway_seat *seat);
+void seat_configure_xcursor(struct sway_seat *seat);
-void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *container);
+void seat_set_focus(struct sway_seat *seat, struct sway_container *container);
-void sway_seat_set_focus_warp(struct sway_seat *seat,
+void seat_set_focus_warp(struct sway_seat *seat,
struct sway_container *container, bool warp);
-struct sway_container *sway_seat_get_focus(struct sway_seat *seat);
+void seat_set_focus_layer(struct sway_seat *seat,
+ struct wlr_layer_surface *layer);
+
+struct sway_container *seat_get_focus(struct sway_seat *seat);
/**
* Return the last container to be focused for the seat (or the most recently
@@ -70,12 +75,14 @@ struct sway_container *sway_seat_get_focus(struct sway_seat *seat);
* is destroyed, or focus moves to a container with children and we need to
* descend into the next leaf in focus order.
*/
-struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat,
+struct sway_container *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 *seat_get_focus_by_type(struct sway_seat *seat,
+ struct sway_container *container, enum sway_container_type type);
+
+void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config);
-void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config);
+struct seat_config *seat_get_config(struct sway_seat *seat);
#endif
diff --git a/include/sway/output.h b/include/sway/output.h
index b4980cd8..98d0f83f 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -24,6 +24,7 @@ struct sway_output {
struct wl_listener destroy;
struct wl_listener mode;
struct wl_listener transform;
+ struct wl_listener scale;
struct wl_listener damage_destroy;
struct wl_listener damage_frame;
@@ -36,4 +37,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..464f80c4 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -70,9 +70,10 @@ struct sway_container {
enum sway_container_layout prev_layout;
enum sway_container_layout workspace_layout;
- // TODO convert to layout coordinates
+ // For C_ROOT, this has no meaning
+ // For C_OUTPUT, this is the output position in layout coordinates
+ // For other types, this is the position in output-local coordinates
double x, y;
-
// does not include borders or gaps.
double width, height;
@@ -84,38 +85,67 @@ 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;
};
+// TODO make private and use the container-specific create functions
+struct sway_container *container_create(enum sway_container_type type);
+
+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);
-struct sway_container *container_workspace_create(
- struct sway_container *output, const char *name);
+/**
+ * Create a new container container. A container container can be a a child of
+ * a workspace container or another container container.
+ */
+struct sway_container *container_container_create();
-struct sway_container *container_view_create(
- struct sway_container *sibling, struct sway_view *sway_view);
+/**
+ * Create a new output. Outputs are children of the root container and have no
+ * order in the tree structure.
+ */
+struct sway_container *container_output_create(struct sway_output *sway_output);
-struct sway_container *container_output_destroy(struct sway_container *output);
+/**
+ * Create a new workspace container. Workspaces are children of an output
+ * container and are ordered alphabetically by name.
+ */
+struct sway_container *container_workspace_create(struct sway_container *output, const char *name);
-struct sway_container *container_workspace_destroy(
- struct sway_container *workspace);
+/*
+ * Create a new view container. A view can be a child of a workspace container
+ * or a container container and are rendered in the order and structure of
+ * how they are attached to the tree.
+ */
+// TODO view containers should be created in a detached state.
+struct sway_container *container_view_create(
+ struct sway_container *sibling, struct sway_view *sway_view);
-struct sway_container *container_view_destroy(struct sway_container *view);
+// TODO don't return the parent on destroy
+struct sway_container *container_destroy(struct sway_container *container);
-struct sway_container *container_destroy(struct sway_container *cont);
+struct sway_container *container_workspace_destroy(struct sway_container *container);
+struct sway_container *container_output_destroy(struct sway_container *container);
+struct sway_container *container_view_destroy(struct sway_container *container);
+// TODO move to layout.c
struct sway_container *container_set_layout(struct sway_container *container,
enum sway_container_layout layout);
+// TODO rename to container_descendants_for_each()
void container_descendants(struct sway_container *root,
enum sway_container_type type,
void (*func)(struct sway_container *item, void *data), void *data);
/**
- * Finds a container based on test criteria. Returns the first container that
- * passes the test.
+ * Search a container's descendants a container based on test criteria. Returns
+ * the first container that passes the test.
*/
struct sway_container *container_find(struct sway_container *container,
bool (*test)(struct sway_container *view, void *data), void *data);
@@ -123,18 +153,21 @@ struct sway_container *container_find(struct sway_container *container,
/**
* Finds a parent container with the given struct sway_containerype.
*/
+// TODO rename to container_parent_of_type()
struct sway_container *container_parent(struct sway_container *container,
enum sway_container_type type);
/**
- * Find a container at the given coordinates.
+ * Find a container at the given coordinates. Returns the the surface and
+ * surface-local coordinates of the given layout coordinates if the container
+ * is a view and the view contains a surface at those coordinates.
*/
-struct sway_container *container_at(struct sway_container *parent,
+struct sway_container *container_at(struct sway_container *container,
double lx, double ly, struct wlr_surface **surface,
double *sx, double *sy);
/**
- * Apply the function for each child of the container breadth first.
+ * Apply the function for each descendant of the container breadth first.
*/
void container_for_each_descendant_bfs(struct sway_container *container,
void (*f)(struct sway_container *container, void *data), void *data);
@@ -145,7 +178,16 @@ void container_for_each_descendant_bfs(struct sway_container *container,
void container_for_each_descendant_dfs(struct sway_container *container,
void (*f)(struct sway_container *container, void *data), void *data);
-bool container_has_anscestor(struct sway_container *descendant,
+/**
+ * Returns true if the given container is an ancestor of this container.
+ */
+bool container_has_anscestor(struct sway_container *container,
struct sway_container *anscestor);
+/**
+ * Returns true if the given container is a child descendant of this container.
+ */
+bool container_has_child(struct sway_container *con,
+ struct sway_container *child);
+
#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index 0a904c4b..8badb244 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;
@@ -23,7 +20,7 @@ struct sway_root {
struct wl_listener output_layout_change;
- struct wl_list unmanaged_views; // sway_view::unmanaged_view_link
+ struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
struct {
struct wl_signal new_container;
@@ -32,26 +29,43 @@ struct sway_root {
void layout_init(void);
-void container_add_child(struct sway_container *parent, struct sway_container *child);
+// TODO move to tree.h
+void container_add_child(struct sway_container *parent,
+ struct sway_container *child);
+// TODO move to tree.h
struct sway_container *container_add_sibling(struct sway_container *parent,
struct sway_container *child);
+// TODO move to tree.h
struct sway_container *container_remove_child(struct sway_container *child);
+// TODO PRIVATE in tree.h
struct sway_container *container_reap_empty(struct sway_container *container);
+// TODO move to tree.h
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);
+
+// TODO move to output.c
+enum sway_container_layout container_get_default_layout(
+ struct sway_container *output);
+// TODO move to output.c
void container_sort_workspaces(struct sway_container *output);
void arrange_windows(struct sway_container *container,
double width, double height);
+// TODO move to container.h
struct sway_container *container_get_in_direction(struct sway_container
*container, struct sway_seat *seat, enum movement_direction dir);
+// TODO move to tree.h
+struct sway_container *container_split(struct sway_container *child,
+ enum sway_container_layout layout);
+
#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 3965d2b7..4b84205e 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -4,6 +4,8 @@
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
#include <wlr/xwayland.h>
+#include "sway/input/input-manager.h"
+#include "sway/input/seat.h"
struct sway_container;
struct sway_view;
@@ -37,6 +39,13 @@ struct sway_xwayland_surface {
int pending_width, pending_height;
};
+struct sway_xwayland_unmanaged {
+ struct wlr_xwayland_surface *wlr_xwayland_surface;
+ struct wl_list link;
+
+ struct wl_listener destroy;
+};
+
struct sway_wl_shell_surface {
struct sway_view *view;
@@ -64,10 +73,21 @@ enum sway_view_prop {
VIEW_PROP_INSTANCE,
};
+struct sway_view_impl {
+ const char *(*get_prop)(struct sway_view *view,
+ enum sway_view_prop prop);
+ void (*configure)(struct sway_view *view, double ox, double oy, int width,
+ int height);
+ void (*set_activated)(struct sway_view *view, bool activated);
+ void (*close)(struct sway_view *view);
+};
+
struct sway_view {
enum sway_view_type type;
- struct sway_container *swayc;
- struct wlr_surface *surface;
+ const struct sway_view_impl *impl;
+
+ struct sway_container *swayc; // NULL for unmanaged views
+ struct wlr_surface *surface; // NULL for unmapped views
int width, height;
union {
@@ -82,21 +102,15 @@ struct sway_view {
struct sway_wl_shell_surface *sway_wl_shell_surface;
};
- struct {
- const char *(*get_prop)(struct sway_view *view,
- enum sway_view_prop prop);
- void (*set_size)(struct sway_view *view,
- int width, int height);
- 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)
- struct wl_list unmanaged_view_link; // sway_root::unmanaged views
+ struct wl_list unmanaged_view_link; // sway_root::unmanaged_views
};
+struct sway_view *view_create(enum sway_view_type type,
+ const struct sway_view_impl *impl);
+
+void view_destroy(struct sway_view *view);
+
const char *view_get_title(struct sway_view *view);
const char *view_get_app_id(struct sway_view *view);
@@ -105,18 +119,25 @@ 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_configure(struct sway_view *view, double ox, double oy, int width,
+ int height);
void view_set_activated(struct sway_view *view, bool activated);
void view_close(struct sway_view *view);
-void view_update_outputs(struct sway_view *view, const struct wlr_box *before);
-
void view_damage_whole(struct sway_view *view);
void view_damage_from(struct sway_view *view);
+// view implementation
+
+void view_map(struct sway_view *view, struct wlr_surface *wlr_surface);
+
+void view_unmap(struct sway_view *view);
+
+void view_update_position(struct sway_view *view, double ox, double oy);
+
+void view_update_size(struct sway_view *view, int width, int height);
+
#endif
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h
index 6ea7c4d6..a1696bcf 100644
--- a/include/swaybar/ipc.h
+++ b/include/swaybar/ipc.h
@@ -4,7 +4,7 @@
#include "swaybar/bar.h"
void ipc_initialize(struct swaybar *bar, const char *bar_id);
-bool handle_ipc_event(struct swaybar *bar);
+bool handle_ipc_readable(struct swaybar *bar);
void ipc_get_workspaces(struct swaybar *bar);
void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index 6c595df0..3538f49c 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -7,10 +7,52 @@
enum status_protocol {
PROTOCOL_UNDEF,
+ PROTOCOL_ERROR,
PROTOCOL_TEXT,
PROTOCOL_I3BAR,
};
+struct text_protocol_state {
+ char *buffer;
+ size_t buffer_size;
+};
+
+enum json_node_type {
+ JSON_NODE_UNKNOWN,
+ JSON_NODE_ARRAY,
+ JSON_NODE_STRING,
+};
+
+struct i3bar_protocol_state {
+ bool click_events;
+ char *buffer;
+ size_t buffer_size;
+ size_t buffer_index;
+ const char *current_node;
+ bool escape;
+ size_t depth;
+ enum json_node_type nodes[16];
+};
+
+struct i3bar_block {
+ struct wl_list link;
+ char *full_text, *short_text, *align;
+ bool urgent;
+ uint32_t *color;
+ int min_width;
+ char *name, *instance;
+ bool separator;
+ int separator_block_width;
+ bool markup;
+ // Airblader features
+ uint32_t background;
+ uint32_t border;
+ int border_top;
+ int border_bottom;
+ int border_left;
+ int border_right;
+};
+
struct status_line {
pid_t pid;
int read_fd, write_fd;
@@ -18,13 +60,18 @@ struct status_line {
enum status_protocol protocol;
const char *text;
+ struct wl_list blocks; // i3bar_block::link
- char *buffer;
- size_t buffer_size;
+ struct text_protocol_state text_state;
+ struct i3bar_protocol_state i3bar_state;
};
struct status_line *status_line_init(char *cmd);
+void status_error(struct status_line *status, const char *text);
+bool status_handle_readable(struct status_line *status);
void status_line_free(struct status_line *status);
-bool handle_status_readable(struct status_line *status);
+bool i3bar_handle_readable(struct status_line *status);
+void i3bar_block_send_click(struct status_line *status,
+ struct i3bar_block *block, int x, int y, uint32_t button);
#endif
diff --git a/protocols/desktop-shell.xml b/protocols/desktop-shell.xml
deleted file mode 100644
index 581f0c5d..00000000
--- a/protocols/desktop-shell.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<protocol name="desktop">
-
- <interface name="desktop_shell" version="3">
- <description summary="create desktop widgets and helpers">
- Traditional user interfaces can rely on this interface to define the
- foundations of typical desktops. Currently it's possible to set up
- background, panels and locking surfaces.
- </description>
-
- <request name="set_background">
- <arg name="output" type="object" interface="wl_output"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="set_panel">
- <arg name="output" type="object" interface="wl_output"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="set_lock_surface">
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="unlock"/>
-
- <request name="set_grab_surface">
- <description summary="set grab surface">
- The surface set by this request will receive a fake
- pointer.enter event during grabs at position 0, 0 and is
- expected to set an appropriate cursor image as described by
- the grab_cursor event sent just before the enter event.
- </description>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <!-- We'll fold most of wl_shell into this interface and then
- they'll share the configure event. -->
- <event name="configure">
- <arg name="edges" type="uint"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- <arg name="width" type="int"/>
- <arg name="height" type="int"/>
- </event>
-
- <event name="prepare_lock_surface">
- <description summary="tell the client to create, set the lock surface">
- Tell the client we want it to create and set the lock surface, which is
- a GUI asking the user to unlock the screen. The lock surface is
- announced with 'set_lock_surface'. Whether or not the client actually
- implements locking, it MUST send 'unlock' request to let the normal
- desktop resume.
- </description>
- </event>
-
- <event name="grab_cursor">
- <description summary="tell client what cursor to show during a grab">
- This event will be sent immediately before a fake enter event on the
- grab surface.
- </description>
- <arg name="cursor" type="uint"/>
- </event>
-
- <enum name="cursor">
- <entry name="none" value="0"/>
-
- <entry name="resize_top" value="1"/>
- <entry name="resize_bottom" value="2"/>
-
- <entry name="arrow" value="3"/>
-
- <entry name="resize_left" value="4"/>
- <entry name="resize_top_left" value="5"/>
- <entry name="resize_bottom_left" value="6"/>
-
- <entry name="move" value="7"/>
-
- <entry name="resize_right" value="8"/>
- <entry name="resize_top_right" value="9"/>
- <entry name="resize_bottom_right" value="10"/>
-
- <entry name="busy" value="11"/>
- </enum>
-
- <!-- Version 2 additions -->
-
- <request name="desktop_ready" since="2">
- <description summary="desktop is ready to be shown">
- Tell the server, that enough desktop elements have been drawn
- to make the desktop look ready for use. During start-up, the
- server can wait for this request with a black screen before
- starting to fade in the desktop, for instance. If the client
- parts of a desktop take a long time to initialize, we avoid
- showing temporary garbage.
- </description>
- </request>
-
- <!-- Version 3 additions -->
-
- <enum name="panel_position">
- <entry name="top" value="0"/>
- <entry name="bottom" value="1"/>
- <entry name="left" value="2"/>
- <entry name="right" value="3"/>
- </enum>
-
- <enum name="error">
- <entry name="invalid_argument" value="0"
- summary="an invalid argument was provided in a request"/>
- </enum>
-
- <request name="set_panel_position" since="3">
- <description summary="set panel position">
- Tell the shell which side of the screen the panel is
- located. This is so that new windows do not overlap the panel
- and maximized windows maximize properly.
- </description>
- <arg name="position" type="uint"/>
- </request>
-
- </interface>
-
- <interface name="screensaver" version="1">
- <description summary="interface for implementing screensavers">
- Only one client can bind this interface at a time.
- </description>
-
- <request name="set_surface">
- <description summary="set the surface type as a screensaver">
- A screensaver surface is normally hidden, and only visible after an
- idle timeout.
- </description>
-
- <arg name="surface" type="object" interface="wl_surface"/>
- <arg name="output" type="object" interface="wl_output"/>
- </request>
-
- </interface>
-</protocol>
diff --git a/protocols/gamma-control.xml b/protocols/gamma-control.xml
deleted file mode 100644
index e6e33265..00000000
--- a/protocols/gamma-control.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="gamma_control">
-
- <copyright>
- Copyright © 2015 Giulio camuffo
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that copyright notice and this permission
- notice appear in supporting documentation, and that the name of
- the copyright holders not be used in advertising or publicity
- pertaining to distribution of the software without specific,
- written prior permission. The copyright holders make no
- representations about the suitability of this software for any
- purpose. It is provided "as is" without express or implied
- warranty.
-
- THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
- </copyright>
-
- <interface name="gamma_control_manager" version="1">
- <request name="destroy" type="destructor"/>
-
- <request name="get_gamma_control">
- <arg name="id" type="new_id" interface="gamma_control"/>
- <arg name="output" type="object" interface="wl_output"/>
- </request>
- </interface>
-
- <interface name="gamma_control" version="1">
- <enum name="error">
- <entry name="invalid_gamma" value="0"/>
- </enum>
-
- <request name="destroy" type="destructor"/>
-
- <request name="set_gamma">
- <arg name="red" type="array"/>
- <arg name="green" type="array"/>
- <arg name="blue" type="array"/>
- </request>
-
- <request name="reset_gamma"/>
-
- <event name="gamma_size">
- <arg name="size" type="uint"/>
- </event>
- </interface>
-</protocol>
diff --git a/protocols/server-decoration.xml b/protocols/server-decoration.xml
deleted file mode 100644
index 8bc106c7..00000000
--- a/protocols/server-decoration.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="server_decoration">
- <copyright><![CDATA[
- Copyright (C) 2015 Martin Gräßlin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 2.1 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ]]></copyright>
- <interface name="org_kde_kwin_server_decoration_manager" version="1">
- <description summary="Server side window decoration manager">
- This interface allows to coordinate whether the server should create
- a server-side window decoration around a wl_surface representing a
- shell surface (wl_shell_surface or similar). By announcing support
- for this interface the server indicates that it supports server
- side decorations.
- </description>
- <request name="create">
- <description summary="Create a server-side decoration object for a given surface">
- When a client creates a server-side decoration object it indicates
- that it supports the protocol. The client is supposed to tell the
- server whether it wants server-side decorations or will provide
- client-side decorations.
-
- If the client does not create a server-side decoration object for
- a surface the server interprets this as lack of support for this
- protocol and considers it as client-side decorated. Nevertheless a
- client-side decorated surface should use this protocol to indicate
- to the server that it does not want a server-side deco.
- </description>
- <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
- <enum name="mode">
- <description summary="Possible values to use in request_mode and the event mode."/>
- <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
- <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
- <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
- </enum>
- <event name="default_mode">
- <description summary="The default mode used on the server">
- This event is emitted directly after binding the interface. It contains
- the default mode for the decoration. When a new server decoration object
- is created this new object will be in the default mode until the first
- request_mode is requested.
-
- The server may change the default mode at any time.
- </description>
- <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/>
- </event>
- </interface>
- <interface name="org_kde_kwin_server_decoration" version="1">
- <request name="release" type="destructor">
- <description summary="release the server decoration object"/>
- </request>
- <enum name="mode">
- <description summary="Possible values to use in request_mode and the event mode."/>
- <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
- <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
- <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
- </enum>
- <request name="request_mode">
- <description summary="The decoration mode the surface wants to use."/>
- <arg name="mode" type="uint" summary="The mode this surface wants to use."/>
- </request>
- <event name="mode">
- <description summary="The new decoration mode applied by the server">
- This event is emitted directly after the decoration is created and
- represents the base decoration policy by the server. E.g. a server
- which wants all surfaces to be client-side decorated will send Client,
- a server which wants server-side decoration will send Server.
-
- The client can request a different mode through the decoration request.
- The server will acknowledge this by another event with the same mode. So
- even if a server prefers server-side decoration it's possible to force a
- client-side decoration.
-
- The server may emit this event at any time. In this case the client can
- again request a different mode. It's the responsibility of the server to
- prevent a feedback loop.
- </description>
- <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
- </event>
- </interface>
-</protocol>
diff --git a/protocols/swaylock.xml b/protocols/swaylock.xml
deleted file mode 100644
index c7a102dd..00000000
--- a/protocols/swaylock.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<protocol name="lock">
-
- <interface name="lock" version="1">
- <description summary="create lock screen UIs">
- The Weston desktop-shell protocol's locking functionality depends more
- on the behavior of the compositor than of a screen locking client, so
- another protocol is necessary.
- </description>
-
- <request name="set_lock_surface">
- <arg name="output" type="object" interface="wl_output"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="unlock"/>
-
- </interface>
-</protocol>
diff --git a/protocols/xdg-shell.xml b/protocols/xdg-shell.xml
deleted file mode 100644
index 7bf4ae3a..00000000
--- a/protocols/xdg-shell.xml
+++ /dev/null
@@ -1,430 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="xdg_shell">
-
- <copyright>
- Copyright © 2008-2013 Kristian Høgsberg
- Copyright © 2013 Rafael Antognolli
- Copyright © 2013 Jasper St. Pierre
- Copyright © 2010-2013 Intel Corporation
-
- Permission to use, copy, modify, distribute, and sell this
- software and its documentation for any purpose is hereby granted
- without fee, provided that the above copyright notice appear in
- all copies and that both that copyright notice and this permission
- notice appear in supporting documentation, and that the name of
- the copyright holders not be used in advertising or publicity
- pertaining to distribution of the software without specific,
- written prior permission. The copyright holders make no
- representations about the suitability of this software for any
- purpose. It is provided "as is" without express or implied
- warranty.
-
- THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
- </copyright>
-
- <interface name="xdg_shell" version="1">
- <description summary="create desktop-style surfaces">
- This interface is implemented by servers that provide
- desktop-style user interfaces.
-
- It allows clients to associate a xdg_surface with
- a basic surface.
- </description>
-
- <enum name="version">
- <description summary="latest protocol version">
- The 'current' member of this enum gives the version of the
- protocol. Implementations can compare this to the version
- they implement using static_assert to ensure the protocol and
- implementation versions match.
- </description>
- <entry name="current" value="4" summary="Always the latest version"/>
- </enum>
-
- <enum name="error">
- <entry name="role" value="0" summary="given wl_surface has another role"/>
- </enum>
-
- <request name="use_unstable_version">
- <description summary="enable use of this unstable version">
- Negotiate the unstable version of the interface. This
- mechanism is in place to ensure client and server agree on the
- unstable versions of the protocol that they speak or exit
- cleanly if they don't agree. This request will go away once
- the xdg-shell protocol is stable.
- </description>
- <arg name="version" type="int"/>
- </request>
-
- <request name="get_xdg_surface">
- <description summary="create a shell surface from a surface">
- Create a shell surface for an existing surface.
-
- This request gives the surface the role of xdg_surface. If the
- surface already has another role, it raises a protocol error.
-
- Only one shell or popup surface can be associated with a given
- surface.
- </description>
- <arg name="id" type="new_id" interface="xdg_surface"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
-
- <request name="get_xdg_popup">
- <description summary="create a shell surface from a surface">
- Create a popup surface for an existing surface.
-
- This request gives the surface the role of xdg_popup. If the
- surface already has another role, it raises a protocol error.
-
- Only one shell or popup surface can be associated with a given
- surface.
- </description>
- <arg name="id" type="new_id" interface="xdg_popup"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- <arg name="parent" type="object" interface="wl_surface"/>
- <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
- <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
- <arg name="x" type="int"/>
- <arg name="y" type="int"/>
- <arg name="flags" type="uint"/>
- </request>
-
- <event name="ping">
- <description summary="check if the client is alive">
- The ping event asks the client if it's still alive. Pass the
- serial specified in the event back to the compositor by sending
- a "pong" request back with the specified serial.
-
- Compositors can use this to determine if the client is still
- alive. It's unspecified what will happen if the client doesn't
- respond to the ping request, or in what timeframe. Clients should
- try to respond in a reasonable amount of time.
- </description>
- <arg name="serial" type="uint" summary="pass this to the callback"/>
- </event>
-
- <request name="pong">
- <description summary="respond to a ping event">
- A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive.
- </description>
- <arg name="serial" type="uint" summary="serial of the ping event"/>
- </request>
- </interface>
-
- <interface name="xdg_surface" version="1">
-
- <description summary="desktop-style metadata interface">
- An interface that may be implemented by a wl_surface, for
- implementations that provide a desktop-style user interface.
-
- It provides requests to treat surfaces like windows, allowing to set
- properties like maximized, fullscreen, minimized, and to move and resize
- them, and associate metadata like title and app id.
-
- On the server side the object is automatically destroyed when
- the related wl_surface is destroyed. On client side,
- xdg_surface.destroy() must be called before destroying
- the wl_surface object.
- </description>
-
- <request name="destroy" type="destructor">
- <description summary="remove xdg_surface interface">
- The xdg_surface interface is removed from the wl_surface object
- that was turned into a xdg_surface with
- xdg_shell.get_xdg_surface request. The xdg_surface properties,
- like maximized and fullscreen, are lost. The wl_surface loses
- its role as a xdg_surface. The wl_surface is unmapped.
- </description>
- </request>
-
- <request name="set_parent">
- <description summary="surface is a child of another surface">
- Child surfaces are stacked above their parents, and will be
- unmapped if the parent is unmapped too. They should not appear
- on task bars and alt+tab.
- </description>
- <arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
- </request>
-
- <request name="set_title">
- <description summary="set surface title">
- Set a short title for the surface.
-
- This string may be used to identify the surface in a task bar,
- window list, or other user interface elements provided by the
- compositor.
-
- The string must be encoded in UTF-8.
- </description>
- <arg name="title" type="string"/>
- </request>
-
- <request name="set_app_id">
- <description summary="set surface class">
- Set an id for the surface.
-
- The app id identifies the general class of applications to which
- the surface belongs.
-
- It should be the ID that appears in the new desktop entry
- specification, the interface name.
- </description>
- <arg name="app_id" type="string"/>
- </request>
-
- <request name="show_window_menu">
- <description summary="show the window menu">
- Clients implementing client-side decorations might want to show
- a context menu when right-clicking on the decorations, giving the
- user a menu that they can use to maximize or minimize the window.
-
- This request asks the compositor to pop up such a window menu at
- the given position, relative to the parent surface. There are
- no guarantees as to what the window menu contains.
-
- Your surface must have focus on the seat passed in to pop up the
- window menu.
- </description>
-
- <arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/>
- <arg name="serial" type="uint" summary="serial of the event to pop up the window for"/>
- <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
- <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
- </request>
-
- <request name="move">
- <description summary="start an interactive move">
- Start a pointer-driven move of the surface.
-
- This request must be used in response to a button press event.
- The server may ignore move requests depending on the state of
- the surface (e.g. fullscreen or maximized).
- </description>
- <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
- <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
- </request>
-
- <enum name="resize_edge">
- <description summary="edge values for resizing">
- These values are used to indicate which edge of a surface
- is being dragged in a resize operation. The server may
- use this information to adapt its behavior, e.g. choose
- an appropriate cursor image.
- </description>
- <entry name="none" value="0"/>
- <entry name="top" value="1"/>
- <entry name="bottom" value="2"/>
- <entry name="left" value="4"/>
- <entry name="top_left" value="5"/>
- <entry name="bottom_left" value="6"/>
- <entry name="right" value="8"/>
- <entry name="top_right" value="9"/>
- <entry name="bottom_right" value="10"/>
- </enum>
-
- <request name="resize">
- <description summary="start an interactive resize">
- Start a pointer-driven resizing of the surface.
-
- This request must be used in response to a button press event.
- The server may ignore resize requests depending on the state of
- the surface (e.g. fullscreen or maximized).
- </description>
- <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/>
- <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
- <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
- </request>
-
- <enum name="state">
- <description summary="types of state on the surface">
- The different state values used on the surface. This is designed for
- state values like maximized, fullscreen. It is paired with the
- configure event to ensure that both the client and the compositor
- setting the state can be synchronized.
-
- States set in this way are double-buffered. They will get applied on
- the next commit.
-
- Desktop environments may extend this enum by taking up a range of
- values and documenting the range they chose in this description.
- They are not required to document the values for the range that they
- chose. Ideally, any good extensions from a desktop environment should
- make its way into standardization into this enum.
-
- The current reserved ranges are:
-
- 0x0000 - 0x0FFF: xdg-shell core values, documented below.
- 0x1000 - 0x1FFF: GNOME
- </description>
- <entry name="maximized" value="1">
- <description summary="the surface is maximized">
- The surface is maximized. The window geometry specified in the configure
- event must be obeyed by the client.
- </description>
- </entry>
- <entry name="fullscreen" value="2">
- <description summary="the surface is fullscreen">
- The surface is fullscreen. The window geometry specified in the configure
- event must be obeyed by the client.
- </description>
- </entry>
- <entry name="resizing" value="3">
- <description summary="the surface is being resized">
- The surface is being resized. The window geometry specified in the
- configure event is a maximum; the client cannot resize beyond it.
- Clients that have aspect ratio or cell sizing configuration can use
- a smaller size, however.
- </description>
- </entry>
- <entry name="activated" value="4">
- <description summary="the client window is active">
- Client window decorations should be painted as if the window is
- active. Do not assume this means that the window actually has
- keyboard or pointer focus.
- </description>
- </entry>
- </enum>
-
- <event name="configure">
- <description summary="suggest a surface change">
- The configure event asks the client to resize its surface.
-
- The width and height arguments specify a hint to the window
- about how its surface should be resized in window geometry
- coordinates. The states listed in the event specify how the
- width/height arguments should be interpreted.
-
- A client should arrange a new surface, and then send a
- ack_configure request with the serial sent in this configure
- event before attaching a new surface.
-
- If the client receives multiple configure events before it
- can respond to one, it is free to discard all but the last
- event it received.
- </description>
-
- <arg name="width" type="int"/>
- <arg name="height" type="int"/>
- <arg name="states" type="array"/>
- <arg name="serial" type="uint"/>
- </event>
-
- <request name="ack_configure">
- <description summary="ack a configure event">
- When a configure event is received, a client should then ack it
- using the ack_configure request to ensure that the compositor
- knows the client has seen the event.
-
- By this point, the state is confirmed, and the next attach should
- contain the buffer drawn for the configure event you are acking.
- </description>
- <arg name="serial" type="uint" summary="a serial to configure for"/>
- </request>
-
- <request name="set_window_geometry">
- <description summary="set the new window geometry">
- The window geometry of a window is its "visible bounds" from the
- user's perspective. Client-side decorations often have invisible
- portions like drop-shadows which should be ignored for the
- purposes of aligning, placing and constraining windows.
-
- The default value is the full bounds of the surface, including any
- subsurfaces. Once the window geometry of the surface is set once,
- it is not possible to unset it, and it will remain the same until
- set_window_geometry is called again, even if a new subsurface or
- buffer is attached.
-
- If responding to a configure event, the window geometry in here
- must respect the sizing negotiations specified by the states in
- the configure event.
- </description>
- <arg name="x" type="int"/>
- <arg name="y" type="int"/>
- <arg name="width" type="int"/>
- <arg name="height" type="int"/>
- </request>
-
- <request name="set_maximized" />
- <request name="unset_maximized" />
-
- <request name="set_fullscreen">
- <description summary="set the window as fullscreen on a monitor">
- Make the surface fullscreen.
-
- You can specify an output that you would prefer to be fullscreen.
- If this value is NULL, it's up to the compositor to choose which
- display will be used to map this surface.
- </description>
- <arg name="output" type="object" interface="wl_output" allow-null="true"/>
- </request>
- <request name="unset_fullscreen" />
-
- <request name="set_minimized" />
-
- <event name="close">
- <description summary="surface wants to be closed">
- The close event is sent by the compositor when the user
- wants the surface to be closed. This should be equivalent to
- the user clicking the close button in client-side decorations,
- if your application has any...
-
- This is only a request that the user intends to close your
- window. The client may choose to ignore this request, or show
- a dialog to ask the user to save their data...
- </description>
- </event>
- </interface>
-
- <interface name="xdg_popup" version="1">
- <description summary="desktop-style metadata interface">
- An interface that may be implemented by a wl_surface, for
- implementations that provide a desktop-style popups/menus. A popup
- surface is a transient surface with an added pointer grab.
-
- An existing implicit grab will be changed to owner-events mode,
- and the popup grab will continue after the implicit grab ends
- (i.e. releasing the mouse button does not cause the popup to be
- unmapped).
-
- The popup grab continues until the window is destroyed or a mouse
- button is pressed in any other clients window. A click in any of
- the clients surfaces is reported as normal, however, clicks in
- other clients surfaces will be discarded and trigger the callback.
-
- The x and y arguments specify the locations of the upper left
- corner of the surface relative to the upper left corner of the
- parent surface, in surface local coordinates.
-
- xdg_popup surfaces are always transient for another surface.
- </description>
-
- <request name="destroy" type="destructor">
- <description summary="remove xdg_surface interface">
- The xdg_surface interface is removed from the wl_surface object
- that was turned into a xdg_surface with
- xdg_shell.get_xdg_surface request. The xdg_surface properties,
- like maximized and fullscreen, are lost. The wl_surface loses
- its role as a xdg_surface. The wl_surface is unmapped.
- </description>
- </request>
-
- <event name="popup_done">
- <description summary="popup interaction is done">
- The popup_done event is sent out when a popup grab is broken,
- that is, when the users clicks a surface that doesn't belong
- to the client owning the popup surface.
- </description>
- <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/>
- </event>
-
- </interface>
-</protocol>
diff --git a/sway/commands.c b/sway/commands.c
index 90544220..8156a08e 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -72,23 +72,23 @@ void apply_input_config(struct input_config *input) {
list_add(config->input_configs, input);
}
- sway_input_manager_apply_input_config(input_manager, input);
+ input_manager_apply_input_config(input_manager, input);
}
-void apply_seat_config(struct seat_config *seat) {
+void apply_seat_config(struct seat_config *seat_config) {
int i;
- i = list_seq_find(config->seat_configs, seat_name_cmp, seat->name);
+ i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->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;
+ merge_seat_config(sc, seat_config);
+ free_seat_config(seat_config);
+ seat_config = sc;
} else {
- list_add(config->seat_configs, seat);
+ list_add(config->seat_configs, seat_config);
}
- sway_input_manager_apply_seat_config(input_manager, seat);
+ input_manager_apply_seat_config(input_manager, seat_config);
}
/* Keep alphabetized */
@@ -162,7 +162,12 @@ static struct cmd_handler command_handlers[] = {
{ "focus", cmd_focus },
{ "kill", cmd_kill },
{ "layout", cmd_layout },
+ { "move", cmd_move },
{ "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) {
@@ -262,7 +267,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
if (seat == NULL) {
// passing a NULL seat means we just pick the default seat
- seat = sway_input_manager_get_default_seat(input_manager);
+ seat = input_manager_get_default_seat(input_manager);
if (!sway_assert(seat, "could not find a seat to run the command on")) {
return NULL;
}
@@ -340,7 +345,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
// without criteria, the command acts upon the focused
// container
config->handler_context.current_container =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
if (!sway_assert(config->handler_context.current_container,
"could not get focus-inactive for root container")) {
return NULL;
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 64f079f4..74d9d535 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;
}
@@ -40,7 +36,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
}
if (argc == 0) {
- sway_seat_set_focus(seat, con);
+ seat_set_focus(seat, con);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
@@ -51,9 +47,10 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
"Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
}
- 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);
+ seat_set_focus(seat, next_focus);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index f6774767..46d6e98e 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -3,21 +3,28 @@
#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:
+ case C_TYPES:
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);
+ arrange_windows(con, -1, -1);
+ break;
+ case C_VIEW:
+ view_close(con->sway_view);
+ break;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/move.c b/sway/commands/move.c
new file mode 100644
index 00000000..644c622b
--- /dev/null
+++ b/sway/commands/move.c
@@ -0,0 +1,184 @@
+#include <string.h>
+#include <strings.h>
+#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_output_layout.h>
+#include <wlr/util/log.h>
+#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 <left|right|up|down> <[px] px>' or "
+ "'move <container|window> to workspace <name>' or "
+ "'move <container|window|workspace> to output <name|direction>' 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 = seat_get_focus_inactive(
+ config->handler_context.seat, ws);
+ container_move_to(current, focus);
+ 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 = seat_get_focus_inactive(
+ config->handler_context.seat, destination);
+ if (!focus) {
+ // We've never been to this output before
+ focus = destination->children->items[0];
+ }
+ struct sway_container *old_parent = current->parent;
+ container_move_to(current, focus);
+ seat_set_focus(config->handler_context.seat, old_parent);
+ 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) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Invalid distance specified");
+ }
+ }
+
+ 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/commands/seat.c b/sway/commands/seat.c
index 45079616..819b769c 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -14,7 +14,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
free_seat_config(config->handler_context.seat_config);
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
- return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
+ return cmd_results_new(CMD_FAILURE, NULL,
+ "Couldn't allocate config");
}
wlr_log(L_DEBUG, "entering seat block: %s", argv[0]);
return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
@@ -28,7 +29,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
if (!has_context) {
config->handler_context.seat_config = new_seat_config(argv[0]);
if (!config->handler_context.seat_config) {
- return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
+ return cmd_results_new(CMD_FAILURE, NULL,
+ "Couldn't allocate config");
}
}
@@ -41,7 +43,10 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
} else if (strcasecmp("fallback", argv[1]) == 0) {
res = seat_cmd_fallback(argc_new, argv_new);
} else {
- res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
+ res =
+ cmd_results_new(CMD_INVALID,
+ "seat <name>", "Unknown command %s",
+ argv[1]);
}
if (!has_context) {
diff --git a/sway/commands/split.c b/sway/commands/split.c
new file mode 100644
index 00000000..ab8565a9
--- /dev/null
+++ b/sway/commands/split.c
@@ -0,0 +1,76 @@
+#include <string.h>
+#include <strings.h>
+#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 layout) {
+ struct sway_container *con = config->handler_context.current_container;
+ struct sway_container *parent = container_split(con, layout);
+ arrange_windows(parent, -1, -1);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *cmd_split(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
+ do_split(L_VERT);
+ } else if (strcasecmp(argv[0], "h") == 0 ||
+ strcasecmp(argv[0], "horizontal") == 0) {
+ do_split(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(L_HORIZ);
+ } else {
+ do_split(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) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+ return do_split(L_VERT);
+}
+
+struct cmd_results *cmd_splith(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+ return do_split(L_HORIZ);
+}
+
+struct cmd_results *cmd_splitt(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) {
+ return error;
+ }
+
+ struct sway_container *con = config->handler_context.current_container;
+
+ if (con->parent->layout == L_VERT) {
+ return do_split(L_HORIZ);
+ } else {
+ return do_split(L_VERT);
+ }
+}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 8f39e5fc..aa4096f7 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -91,7 +91,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
workspace_switch(ws);
current_container =
- sway_seat_get_focus(config->handler_context.seat);
+ seat_get_focus(config->handler_context.seat);
struct sway_container *new_output = container_parent(current_container, C_OUTPUT);
if (config->mouse_warping && old_output != new_output) {
diff --git a/sway/config.c b/sway/config.c
index 0eecf7f6..90b833ab 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -125,7 +125,7 @@ static void destroy_removed_seats(struct sway_config *old_config,
seat_name_cmp, seat_config->name) < 0) {
seat = input_manager_get_seat(input_manager,
seat_config->name);
- sway_seat_destroy(seat);
+ seat_destroy(seat);
}
}
}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index c18f51c7..3c7b45f7 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -7,6 +7,8 @@
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
+#include "sway/input/input-manager.h"
+#include "sway/input/seat.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
@@ -187,6 +189,31 @@ void arrange_layers(struct sway_output *output) {
&usable_area, false);
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
&usable_area, false);
+
+ // Find topmost keyboard interactive layer, if such a layer exists
+ uint32_t layers_above_shell[] = {
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ };
+ size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
+ struct sway_layer_surface *layer, *topmost = NULL;
+ for (size_t i = 0; i < nlayers; ++i) {
+ wl_list_for_each_reverse(layer,
+ &output->layers[layers_above_shell[i]], link) {
+ if (layer->layer_surface->current.keyboard_interactive) {
+ topmost = layer;
+ break;
+ }
+ }
+ if (topmost != NULL) {
+ break;
+ }
+ }
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &input_manager->seats, link) {
+ seat_set_focus_layer(seat, topmost ? topmost->layer_surface : NULL);
+ }
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 0d706c52..10ed1f6d 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -39,6 +39,32 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,
}
}
+/**
+ * Checks whether a surface at (lx, ly) intersects an output. If `box` is not
+ * NULL, it populates it with the surface box in the output, in output-local
+ * coordinates.
+ */
+static bool surface_intersect_output(struct wlr_surface *surface,
+ struct wlr_output_layout *output_layout, struct wlr_output *wlr_output,
+ double lx, double ly, float rotation, struct wlr_box *box) {
+ double ox = lx, oy = ly;
+ wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy);
+
+ if (box != NULL) {
+ box->x = ox * wlr_output->scale;
+ box->y = oy * wlr_output->scale;
+ box->width = surface->current->width * wlr_output->scale;
+ box->height = surface->current->height * wlr_output->scale;
+ }
+
+ struct wlr_box layout_box = {
+ .x = lx, .y = ly,
+ .width = surface->current->width, .height = surface->current->height,
+ };
+ wlr_box_rotated_bounds(&layout_box, rotation, &layout_box);
+ return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);
+}
+
static void render_surface(struct wlr_surface *surface,
struct wlr_output *wlr_output, struct timespec *when,
double lx, double ly, float rotation) {
@@ -48,29 +74,21 @@ static void render_surface(struct wlr_surface *surface,
if (!wlr_surface_has_buffer(surface)) {
return;
}
+
struct wlr_output_layout *layout = root_container.sway_root->output_layout;
- int width = surface->current->width;
- int height = surface->current->height;
- int render_width = width * wlr_output->scale;
- int render_height = height * wlr_output->scale;
- int owidth, oheight;
- wlr_output_effective_resolution(wlr_output, &owidth, &oheight);
-
- // FIXME: view coords are inconsistently assumed to be in output or layout coords
- struct wlr_box layout_box = {
- .x = lx + wlr_output->lx, .y = ly + wlr_output->ly,
- .width = render_width, .height = render_height,
- };
- if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) {
- struct wlr_box render_box = {
- .x = lx, .y = ly,
- .width = render_width, .height = render_height
- };
+
+ struct wlr_box box;
+ bool intersects = surface_intersect_output(surface, layout, wlr_output,
+ lx, ly, rotation, &box);
+ if (intersects) {
float matrix[9];
- wlr_matrix_project_box(matrix, &render_box, surface->current->transform,
- 0, wlr_output->transform_matrix);
- wlr_render_texture_with_matrix(renderer, surface->texture, matrix,
- 1.0f); // TODO: configurable alpha
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(surface->current->transform);
+ 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_surface_send_frame_done(surface, when);
}
@@ -80,9 +98,8 @@ static void render_surface(struct wlr_surface *surface,
struct wlr_surface_state *state = subsurface->surface->current;
double sx = state->subsurface_position.x;
double sy = state->subsurface_position.y;
- double sw = state->buffer_width / state->scale;
- double sh = state->buffer_height / state->scale;
- rotate_child_position(&sx, &sy, sw, sh, width, height, rotation);
+ rotate_child_position(&sx, &sy, state->width, state->height,
+ surface->current->width, surface->current->height, rotation);
render_surface(subsurface->surface, wlr_output, when,
lx + sx, ly + sy, rotation);
@@ -228,10 +245,13 @@ 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));
+ seat_get_focus_inactive(seat, output->swayc);
+ 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,
@@ -240,15 +260,15 @@ static void render_output(struct sway_output *output, struct timespec *when,
container_descendants(workspace, C_VIEW, render_view, &rdata);
// render unmanaged views on top
- struct sway_view *view;
- wl_list_for_each(view, &root_container.sway_root->unmanaged_views,
- unmanaged_view_link) {
- if (view->type != SWAY_XWAYLAND_VIEW) {
+ struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
+ struct sway_xwayland_unmanaged *sway_surface;
+ wl_list_for_each(sway_surface, unmanaged, link) {
+ struct wlr_xwayland_surface *xsurface =
+ sway_surface->wlr_xwayland_surface;
+ if (xsurface->surface == NULL) {
continue;
}
- struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
-
const struct wlr_box view_box = {
.x = xsurface->x,
.y = xsurface->y,
@@ -260,7 +280,7 @@ static void render_output(struct sway_output *output, struct timespec *when,
continue;
}
- render_surface(view->surface, wlr_output, &output->last_frame,
+ render_surface(xsurface->surface, wlr_output, &output->last_frame,
view_box.x - output_box->x, view_box.y - output_box->y, 0);
}
@@ -338,6 +358,12 @@ static void handle_transform(struct wl_listener *listener, void *data) {
arrange_windows(output->swayc, -1, -1);
}
+static void handle_scale(struct wl_listener *listener, void *data) {
+ struct sway_output *output = wl_container_of(listener, output, scale);
+ arrange_layers(output);
+ arrange_windows(output->swayc, -1, -1);
+}
+
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
@@ -370,7 +396,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
wl_list_init(&output->layers[i]);
}
- sway_input_manager_configure_xcursor(input_manager);
+ input_manager_configure_xcursor(input_manager);
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
@@ -378,6 +404,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->mode.notify = handle_mode;
wl_signal_add(&wlr_output->events.transform, &output->transform);
output->transform.notify = handle_transform;
+ wl_signal_add(&wlr_output->events.scale, &output->scale);
+ output->scale.notify = handle_scale;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
output->damage_frame.notify = damage_handle_frame;
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index 4fcc6317..6528a397 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -30,28 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
if (!assert_wl_shell(view)) {
return;
}
+ view_update_position(view, ox, oy);
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 set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_wl_shell(view)) {
- return;
- }
- view->swayc->x = ox;
- view->swayc->y = oy;
-}
-
-static void set_activated(struct sway_view *view, bool activated) {
- // no way to activate wl_shell
-}
-
-static void close(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_wl_shell(view)) {
return;
}
@@ -59,14 +49,20 @@ static void close(struct sway_view *view) {
wl_client_destroy(view->wlr_wl_shell_surface->client);
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .close = _close,
+};
+
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;
// 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;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
@@ -75,15 +71,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_container_of(listener, sway_surface, destroy);
wl_list_remove(&sway_surface->commit.link);
wl_list_remove(&sway_surface->destroy.link);
- struct sway_container *parent = container_view_destroy(sway_surface->view->swayc);
- free(sway_surface->view);
+ view_destroy(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 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_POPUP) {
@@ -103,20 +97,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
return;
}
- struct sway_view *sway_view = calloc(1, sizeof(struct sway_view));
- if (!sway_assert(sway_view, "Failed to allocate view!")) {
+ struct sway_view *view = view_create(SWAY_WL_SHELL_VIEW, &view_impl);
+ if (!sway_assert(view, "Failed to allocate view")) {
return;
}
- sway_view->type = SWAY_WL_SHELL_VIEW;
- sway_view->iface.get_prop = get_prop;
- 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;
- sway_surface->view = sway_view;
+ view->wlr_wl_shell_surface = shell_surface;
+ view->sway_wl_shell_surface = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Wire up listeners
@@ -132,11 +119,5 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
sway_surface->destroy.notify = handle_destroy;
wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy);
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
- struct sway_container *cont = container_view_create(focus, sway_view);
- sway_view->swayc = cont;
-
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
+ view_map(view, shell_surface->surface);
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 713437f2..49305b39 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -30,23 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
if (!assert_xdg(view)) {
return;
}
+
+ view_update_position(view, ox, oy);
view->sway_xdg_surface_v6->pending_width = width;
view->sway_xdg_surface_v6->pending_height = height;
wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
}
-static void set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_xdg(view)) {
- return;
- }
- view->swayc->x = ox;
- view->swayc->y = oy;
-}
-
static void set_activated(struct sway_view *view, bool activated) {
if (!assert_xdg(view)) {
return;
@@ -57,7 +52,7 @@ static void set_activated(struct sway_view *view, bool activated) {
}
}
-static void close(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_xdg(view)) {
return;
}
@@ -67,6 +62,13 @@ static void close(struct sway_view *view) {
}
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .set_activated = set_activated,
+ .close = _close,
+};
+
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, commit);
@@ -74,37 +76,22 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// NOTE: We intentionally discard the view's desired width here
// TODO: Store this for restoration when moving to floating plane
// TODO: Let floating views do whatever
- view->width = sway_surface->pending_width;
- view->height = sway_surface->pending_height;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, unmap);
- view_damage_whole(sway_surface->view);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ view_unmap(sway_surface->view);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xdg_surface_v6 *sway_surface =
wl_container_of(listener, sway_surface, map);
struct sway_view *view = sway_surface->view;
-
- sway_surface->view->surface = view->wlr_xdg_surface_v6->surface;
-
- container_view_destroy(view->swayc);
-
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
- struct sway_container *cont = container_view_create(focus, view);
- view->swayc = cont;
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
-
- view_damage_whole(sway_surface->view);
+ view_map(view, view->wlr_xdg_surface_v6->surface);
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -112,8 +99,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);
- container_view_destroy(sway_xdg_surface->view->swayc);
- free(sway_xdg_surface->view);
+ wl_list_remove(&sway_xdg_surface->map.link);
+ wl_list_remove(&sway_xdg_surface->unmap.link);
+ view_destroy(sway_xdg_surface->view);
free(sway_xdg_surface);
}
@@ -138,23 +126,16 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
return;
}
- struct sway_view *sway_view = calloc(1, sizeof(struct sway_view));
- if (!sway_assert(sway_view, "Failed to allocate view!")) {
+ struct sway_view *view = view_create(SWAY_XDG_SHELL_V6_VIEW, &view_impl);
+ if (!sway_assert(view, "Failed to allocate view")) {
return;
}
- sway_view->type = SWAY_XDG_SHELL_V6_VIEW;
- sway_view->iface.get_prop = get_prop;
- 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_surface->view = sway_view;
+ view->wlr_xdg_surface_v6 = xdg_surface;
+ view->sway_xdg_surface_v6 = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Look up pid and open on appropriate workspace
- // - Set new view to maximized so it behaves nicely
// - Criteria
sway_surface->commit.notify = handle_commit;
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 273ca2bf..bfef68cf 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -14,6 +14,33 @@
#include "sway/input/input-manager.h"
#include "log.h"
+static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_unmanaged *sway_surface =
+ wl_container_of(listener, sway_surface, destroy);
+ wl_list_remove(&sway_surface->destroy.link);
+ wl_list_remove(&sway_surface->link);
+ free(sway_surface);
+}
+
+static void create_unmanaged(struct wlr_xwayland_surface *xsurface) {
+ struct sway_xwayland_unmanaged *sway_surface =
+ calloc(1, sizeof(struct sway_xwayland_unmanaged));
+ if (!sway_assert(sway_surface, "Failed to allocate surface")) {
+ return;
+ }
+
+ sway_surface->wlr_xwayland_surface = xsurface;
+
+ wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy);
+ sway_surface->destroy.notify = unmanaged_handle_destroy;
+
+ wl_list_insert(&root_container.sway_root->xwayland_unmanaged,
+ &sway_surface->link);
+
+ // TODO: damage tracking
+}
+
+
static bool assert_xwayland(struct sway_view *view) {
return sway_assert(view->type == SWAY_XWAYLAND_VIEW,
"Expected xwayland view!");
@@ -33,22 +60,13 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}
-static void set_size(struct sway_view *view, int width, int height) {
+static void configure(struct sway_view *view, double ox, double oy, 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, xsurface->x, xsurface->y,
- width, height);
-}
-static void set_position(struct sway_view *view, double ox, double oy) {
- if (!assert_xwayland(view)) {
- return;
- }
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
if (!sway_assert(output, "view must be within tree to set position")) {
return;
@@ -64,13 +82,12 @@ static void set_position(struct sway_view *view, double ox, double oy) {
return;
}
- view->swayc->x = ox;
- view->swayc->y = oy;
+ view_update_position(view, ox, oy);
- wlr_xwayland_surface_configure(view->wlr_xwayland_surface,
- ox + loutput->x, oy + loutput->y,
- view->wlr_xwayland_surface->width,
- view->wlr_xwayland_surface->height);
+ view->sway_xwayland_surface->pending_width = width;
+ view->sway_xwayland_surface->pending_height = height;
+ wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y,
+ width, height);
}
static void set_activated(struct sway_view *view, bool activated) {
@@ -81,77 +98,58 @@ static void set_activated(struct sway_view *view, bool activated) {
wlr_xwayland_surface_activate(surface, activated);
}
-static void close_view(struct sway_view *view) {
+static void _close(struct sway_view *view) {
if (!assert_xwayland(view)) {
return;
}
wlr_xwayland_surface_close(view->wlr_xwayland_surface);
}
+static const struct sway_view_impl view_impl = {
+ .get_prop = get_prop,
+ .configure = configure,
+ .set_activated = set_activated,
+ .close = _close,
+};
+
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;
// 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;
+ view_update_size(view, sway_surface->pending_width,
+ sway_surface->pending_height);
view_damage_from(view);
}
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);
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ wl_list_remove(&sway_surface->map.link);
+ wl_list_remove(&sway_surface->unmap.link);
+ view_destroy(sway_surface->view);
+ free(sway_surface);
}
static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, unmap);
- view_damage_whole(sway_surface->view);
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- wl_list_init(&sway_surface->view->unmanaged_view_link);
- container_view_destroy(sway_surface->view->swayc);
- sway_surface->view->swayc = NULL;
- sway_surface->view->surface = NULL;
+ view_unmap(sway_surface->view);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xwayland_surface *sway_surface =
wl_container_of(listener, sway_surface, map);
struct wlr_xwayland_surface *xsurface = data;
-
- sway_surface->view->surface = xsurface->surface;
+ struct sway_view *view = sway_surface->view;
// put it back into the tree
- if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
- xsurface->override_redirect) {
- wl_list_remove(&sway_surface->view->unmanaged_view_link);
- wl_list_insert(&root_container.sway_root->unmanaged_views,
- &sway_surface->view->unmanaged_view_link);
- } else {
- struct sway_view *view = sway_surface->view;
- container_view_destroy(view->swayc);
-
- wlr_xwayland_surface_set_maximized(xsurface, true);
-
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat,
- &root_container);
- struct sway_container *cont = container_view_create(focus, view);
- view->swayc = cont;
- arrange_windows(cont->parent, -1, -1);
- sway_input_manager_set_focus(input_manager, cont);
- }
-
- view_damage_whole(sway_surface->view);
+ wlr_xwayland_surface_set_maximized(xsurface, true);
+ view_map(view, xsurface->surface);
}
static void handle_request_configure(struct wl_listener *listener, void *data) {
@@ -171,34 +169,32 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
listener, server, xwayland_surface);
struct wlr_xwayland_surface *xsurface = data;
+ if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
+ xsurface->override_redirect) {
+ wlr_log(L_DEBUG, "New xwayland unmanaged surface");
+ create_unmanaged(xsurface);
+ return;
+ }
+
wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
- xsurface->title, xsurface->class);
+ 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!")) {
+ 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!")) {
+ struct sway_view *view = view_create(SWAY_XWAYLAND_VIEW, &view_impl);
+ if (!sway_assert(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->iface.set_position = set_position;
- sway_view->iface.set_activated = set_activated;
- sway_view->iface.close = close_view;
- sway_view->wlr_xwayland_surface = xsurface;
- sway_view->sway_xwayland_surface = sway_surface;
- sway_surface->view = sway_view;
-
- wl_list_init(&sway_view->unmanaged_view_link);
+ view->wlr_xwayland_surface = xsurface;
+ view->sway_xwayland_surface = sway_surface;
+ sway_surface->view = view;
// TODO:
// - Look up pid and open on appropriate workspace
- // - Set new view to maximized so it behaves nicely
// - Criteria
wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit);
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index d608a9cf..9229e92d 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -47,14 +47,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
struct wlr_surface **surface, double *sx, double *sy) {
// check for unmanaged views first
- struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views;
- struct sway_view *view;
- wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) {
- if (view->type != SWAY_XWAYLAND_VIEW) {
+ struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
+ struct sway_xwayland_unmanaged *sway_surface;
+ wl_list_for_each_reverse(sway_surface, unmanaged, link) {
+ struct wlr_xwayland_surface *xsurface =
+ sway_surface->wlr_xwayland_surface;
+ if (xsurface->surface == NULL) {
continue;
}
- struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct wlr_box box = {
.x = xsurface->x,
.y = xsurface->y,
@@ -84,7 +85,7 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
// find the focused workspace on the output for this seat
struct sway_container *ws =
- sway_seat_get_focus_inactive(cursor->seat, output->swayc);
+ seat_get_focus_inactive(cursor->seat, output->swayc);
if (ws && ws->type != C_WORKSPACE) {
ws = container_parent(ws, C_WORKSPACE);
}
@@ -129,7 +130,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
double sx, sy;
struct sway_container *c = container_at_cursor(cursor, &surface, &sx, &sy);
if (c && config->focus_follows_mouse) {
- sway_seat_set_focus_warp(cursor->seat, c, false);
+ seat_set_focus_warp(cursor->seat, c, false);
}
// reset cursor if switching between clients
@@ -179,27 +180,32 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
double sx, sy;
struct sway_container *cont =
container_at_cursor(cursor, &surface, &sx, &sy);
+ if (surface && wlr_surface_is_layer_surface(surface)) {
+ struct wlr_layer_surface *layer =
+ wlr_layer_surface_from_wlr_surface(surface);
+ if (layer->current.keyboard_interactive) {
+ seat_set_focus_layer(cursor->seat, layer);
+ return;
+ }
+ }
// 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);
+ struct sway_container *old_ws = 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);
+ seat_set_focus(cursor->seat, cont);
}
} else {
- sway_seat_set_focus(cursor->seat, cont);
+ seat_set_focus(cursor->seat, cont);
}
wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index d421a03f..c3507f65 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -26,7 +26,7 @@ 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);
+ seat = input_manager_get_default_seat(input_manager);
}
return seat;
}
@@ -40,7 +40,7 @@ struct sway_seat *input_manager_get_seat(
}
}
- return sway_seat_create(input, seat_name);
+ return seat_create(input, seat_name);
}
static char *get_device_identifier(struct wlr_input_device *device) {
@@ -83,7 +83,8 @@ static struct sway_input_device *input_sway_device_from_wlr(
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) {
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config) {
return true;
}
}
@@ -91,9 +92,10 @@ static bool input_has_seat_configuration(struct sway_input_manager *input) {
return false;
}
-static void sway_input_manager_libinput_config_pointer(struct sway_input_device *input_device) {
+static void input_manager_libinput_config_pointer(
+ struct sway_input_device *input_device) {
struct wlr_input_device *wlr_device = input_device->wlr_device;
- struct input_config *ic = input_device->config;
+ struct input_config *ic = input_device_get_config(input_device);
struct libinput_device *libinput_device;
if (!ic || !wlr_input_device_is_libinput(wlr_device)) {
@@ -101,22 +103,27 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
}
libinput_device = wlr_libinput_get_device_handle(wlr_device);
- wlr_log(L_DEBUG, "sway_input_manager_libinput_config_pointer(%s)", ic->identifier);
+ wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)",
+ ic->identifier);
if (ic->accel_profile != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
ic->identifier, ic->accel_profile);
- libinput_device_config_accel_set_profile(libinput_device, ic->accel_profile);
+ libinput_device_config_accel_set_profile(libinput_device,
+ ic->accel_profile);
}
if (ic->click_method != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
ic->identifier, ic->click_method);
- libinput_device_config_click_set_method(libinput_device, ic->click_method);
+ libinput_device_config_click_set_method(libinput_device,
+ ic->click_method);
}
if (ic->drag_lock != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
ic->identifier, ic->click_method);
- libinput_device_config_tap_set_drag_lock_enabled(libinput_device, ic->drag_lock);
+ libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
+ ic->drag_lock);
}
if (ic->dwt != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
@@ -124,34 +131,43 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device
libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt);
}
if (ic->left_handed != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) left_handed_set_enabled(%d)",
ic->identifier, ic->left_handed);
- libinput_device_config_left_handed_set(libinput_device, ic->left_handed);
+ libinput_device_config_left_handed_set(libinput_device,
+ ic->left_handed);
}
if (ic->middle_emulation != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
ic->identifier, ic->middle_emulation);
- libinput_device_config_middle_emulation_set_enabled(libinput_device, ic->middle_emulation);
+ libinput_device_config_middle_emulation_set_enabled(libinput_device,
+ ic->middle_emulation);
}
if (ic->natural_scroll != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
+ wlr_log(L_DEBUG,
+ "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
ic->identifier, ic->natural_scroll);
- libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, ic->natural_scroll);
+ libinput_device_config_scroll_set_natural_scroll_enabled(
+ libinput_device, ic->natural_scroll);
}
if (ic->pointer_accel != FLT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
ic->identifier, ic->pointer_accel);
- libinput_device_config_accel_set_speed(libinput_device, ic->pointer_accel);
+ libinput_device_config_accel_set_speed(libinput_device,
+ ic->pointer_accel);
}
if (ic->scroll_method != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
ic->identifier, ic->scroll_method);
- libinput_device_config_scroll_set_method(libinput_device, ic->scroll_method);
+ libinput_device_config_scroll_set_method(libinput_device,
+ ic->scroll_method);
}
if (ic->send_events != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
ic->identifier, ic->send_events);
- libinput_device_config_send_events_set_mode(libinput_device, ic->send_events);
+ libinput_device_config_send_events_set_mode(libinput_device,
+ ic->send_events);
}
if (ic->tap != INT_MIN) {
wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
@@ -175,12 +191,11 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
- sway_seat_remove_device(seat, input_device);
+ seat_remove_device(seat, input_device);
}
wl_list_remove(&input_device->link);
wl_list_remove(&input_device->device_destroy.link);
- free_input_config(input_device->config);
free(input_device->identifier);
free(input_device);
}
@@ -203,44 +218,36 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
wlr_log(L_DEBUG, "adding device: '%s'",
input_device->identifier);
- // 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, input_device->identifier) == 0) {
- free_input_config(input_device->config);
- input_device->config = copy_input_config(input_config);
- break;
- }
- }
-
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
- sway_input_manager_libinput_config_pointer(input_device);
+ input_manager_libinput_config_pointer(input_device);
}
struct sway_seat *seat = NULL;
if (!input_has_seat_configuration(input)) {
wlr_log(L_DEBUG, "no seat configuration, using default seat");
seat = input_manager_get_seat(input, default_seat);
- sway_seat_add_device(seat, input_device);
+ seat_add_device(seat, input_device);
return;
}
bool added = false;
wl_list_for_each(seat, &input->seats, link) {
- bool has_attachment = seat->config &&
- (seat_config_get_attachment(seat->config, input_device->identifier) ||
- seat_config_get_attachment(seat->config, "*"));
+ struct seat_config *seat_config = seat_get_config(seat);
+ bool has_attachment = seat_config &&
+ (seat_config_get_attachment(seat_config, input_device->identifier) ||
+ seat_config_get_attachment(seat_config, "*"));
if (has_attachment) {
- sway_seat_add_device(seat, input_device);
+ 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);
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config && seat_config->fallback == 1) {
+ seat_add_device(seat, input_device);
added = true;
}
}
@@ -256,7 +263,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
input_device->device_destroy.notify = handle_device_destroy;
}
-struct sway_input_manager *sway_input_manager_create(
+struct sway_input_manager *input_manager_create(
struct sway_server *server) {
struct sway_input_manager *input =
calloc(1, sizeof(struct sway_input_manager));
@@ -277,11 +284,11 @@ struct sway_input_manager *sway_input_manager_create(
return input;
}
-bool sway_input_manager_has_focus(struct sway_input_manager *input,
+bool input_manager_has_focus(struct sway_input_manager *input,
struct sway_container *container) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (sway_seat_get_focus(seat) == container) {
+ if (seat_get_focus(seat) == container) {
return true;
}
}
@@ -289,35 +296,32 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input,
return false;
}
-void sway_input_manager_set_focus(struct sway_input_manager *input,
+void input_manager_set_focus(struct sway_input_manager *input,
struct sway_container *container) {
struct sway_seat *seat ;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_set_focus(seat, container);
+ seat_set_focus(seat, container);
}
}
-void sway_input_manager_apply_input_config(struct sway_input_manager *input,
+void input_manager_apply_input_config(struct sway_input_manager *input,
struct input_config *input_config) {
struct sway_input_device *input_device = NULL;
wl_list_for_each(input_device, &input->devices, link) {
if (strcmp(input_device->identifier, input_config->identifier) == 0) {
- free_input_config(input_device->config);
- input_device->config = copy_input_config(input_config);
-
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
- sway_input_manager_libinput_config_pointer(input_device);
+ input_manager_libinput_config_pointer(input_device);
}
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_configure_device(seat, input_device);
+ seat_configure_device(seat, input_device);
}
}
}
}
-void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
+void input_manager_apply_seat_config(struct sway_input_manager *input,
struct seat_config *seat_config) {
wlr_log(L_DEBUG, "applying new seat config for seat %s",
seat_config->name);
@@ -326,7 +330,7 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
return;
}
- sway_seat_set_config(seat, seat_config);
+ seat_apply_config(seat, seat_config);
// for every device, try to add it to a seat and if no seat has it
// attached, add it to the fallback seats.
@@ -335,11 +339,12 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
list_t *seat_list = create_list();
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- if (!seat->config) {
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (!seat_config) {
continue;
}
- if (seat_config_get_attachment(seat->config, "*") ||
- seat_config_get_attachment(seat->config,
+ if (seat_config_get_attachment(seat_config, "*") ||
+ seat_config_get_attachment(seat_config,
input_device->identifier)) {
list_add(seat_list, seat);
}
@@ -355,17 +360,18 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
}
}
if (attached) {
- sway_seat_add_device(seat, input_device);
+ seat_add_device(seat, input_device);
} else {
- sway_seat_remove_device(seat, input_device);
+ 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);
+ struct seat_config *seat_config = seat_get_config(seat);
+ if (seat_config && seat_config->fallback == 1) {
+ seat_add_device(seat, input_device);
} else {
- sway_seat_remove_device(seat, input_device);
+ seat_remove_device(seat, input_device);
}
}
}
@@ -373,14 +379,14 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input,
}
}
-void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
+void input_manager_configure_xcursor(struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
- sway_seat_configure_xcursor(seat);
+ seat_configure_xcursor(seat);
}
}
-struct sway_seat *sway_input_manager_get_default_seat(
+struct sway_seat *input_manager_get_default_seat(
struct sway_input_manager *input) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
@@ -390,3 +396,15 @@ struct sway_seat *sway_input_manager_get_default_seat(
}
return seat;
}
+
+struct input_config *input_device_get_config(struct sway_input_device *device) {
+ struct input_config *input_config = NULL;
+ for (int i = 0; i < config->input_configs->length; ++i) {
+ input_config = config->input_configs->items[i];
+ if (strcmp(input_config->identifier, device->identifier) == 0) {
+ return input_config;
+ }
+ }
+
+ return NULL;
+}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 99685052..dbb0c359 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);
}
@@ -428,7 +428,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
struct xkb_rule_names rules;
memset(&rules, 0, sizeof(rules));
struct input_config *input_config =
- keyboard->seat_device->input_device->config;
+ input_device_get_config(keyboard->seat_device->input_device);
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 9aa34aca..cf519a82 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,4 +1,5 @@
#define _XOPEN_SOURCE 700
+#include <assert.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xcursor_manager.h>
@@ -25,7 +26,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
free(seat_device);
}
-void sway_seat_destroy(struct sway_seat *seat) {
+void seat_destroy(struct sway_seat *seat) {
struct sway_seat_device *seat_device, *next;
wl_list_for_each_safe(seat_device, next, &seat->devices, link) {
seat_device_destroy(seat_device);
@@ -35,30 +36,89 @@ void sway_seat_destroy(struct sway_seat *seat) {
wlr_seat_destroy(seat->wlr_seat);
}
+static struct sway_seat_container *seat_container_from_container(
+ struct sway_seat *seat, struct sway_container *con);
+
+static void seat_container_destroy(struct sway_seat_container *seat_con) {
+ struct sway_container *con = seat_con->container;
+ struct sway_container *child = NULL;
+
+ if (con->children != NULL) {
+ for (int i = 0; i < con->children->length; ++i) {
+ child = con->children->items[i];
+ struct sway_seat_container *seat_child =
+ seat_container_from_container(seat_con->seat, child);
+ seat_container_destroy(seat_child);
+ }
+ }
+
+ wl_list_remove(&seat_con->destroy.link);
+ wl_list_remove(&seat_con->link);
+ free(seat_con);
+}
+
+static void seat_send_focus(struct sway_seat *seat,
+ struct sway_container *con) {
+ if (con->type != C_VIEW) {
+ return;
+ }
+ struct sway_view *view = con->sway_view;
+ if (view->type == SWAY_XWAYLAND_VIEW) {
+ struct wlr_xwayland *xwayland =
+ seat->input->server->xwayland;
+ wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
+ }
+ view_set_activated(view, true);
+ struct wlr_keyboard *keyboard =
+ wlr_seat_get_keyboard(seat->wlr_seat);
+ if (keyboard) {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ view->surface, keyboard->keycodes,
+ keyboard->num_keycodes, &keyboard->modifiers);
+ } else {
+ wlr_seat_keyboard_notify_enter(
+ seat->wlr_seat, view->surface, NULL, 0, NULL);
+ }
+
+}
+
static void handle_seat_container_destroy(struct wl_listener *listener,
void *data) {
struct sway_seat_container *seat_con =
wl_container_of(listener, seat_con, destroy);
struct sway_seat *seat = seat_con->seat;
struct sway_container *con = seat_con->container;
+ struct sway_container *parent = con->parent;
+ struct sway_container *focus = seat_get_focus(seat);
- bool is_focus = (sway_seat_get_focus(seat) == con);
+ bool set_focus =
+ focus != NULL &&
+ (focus == con || container_has_child(con, focus)) &&
+ con->type != C_WORKSPACE;
- wl_list_remove(&seat_con->link);
+ seat_container_destroy(seat_con);
- if (is_focus) {
- // pick next focus
- sway_seat_set_focus(seat, NULL);
- struct sway_container *next = sway_seat_get_focus_inactive(seat, con->parent);
- if (next == NULL) {
- next = con->parent;
- }
- sway_seat_set_focus(seat, next);
- }
+ if (set_focus) {
+ struct sway_container *next_focus = NULL;
+ while (next_focus == NULL) {
+ next_focus = seat_get_focus_by_type(seat, parent, C_VIEW);
- wl_list_remove(&seat_con->destroy.link);
+ if (next_focus == NULL && parent->type == C_WORKSPACE) {
+ next_focus = parent;
+ break;
+ }
- free(seat_con);
+ parent = parent->parent;
+ }
+
+ // the structure change might have caused it to move up to the top of
+ // the focus stack without sending focus notifications to the view
+ if (seat_get_focus(seat) == next_focus) {
+ seat_send_focus(seat, next_focus);
+ } else {
+ seat_set_focus(seat, next_focus);
+ }
+ }
}
static struct sway_seat_container *seat_container_from_container(
@@ -110,7 +170,7 @@ static void collect_focus_iter(struct sway_container *con, void *data) {
wl_list_insert(&seat->focus_stack, &seat_con->link);
}
-struct sway_seat *sway_seat_create(struct sway_input_manager *input,
+struct sway_seat *seat_create(struct sway_input_manager *input,
const char *seat_name) {
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
if (!seat) {
@@ -133,7 +193,8 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
// init the focus stack
wl_list_init(&seat->focus_stack);
- container_for_each_descendant_dfs(&root_container, collect_focus_iter, seat);
+ container_for_each_descendant_dfs(&root_container,
+ collect_focus_iter, seat);
wl_signal_add(&root_container.sway_root->events.new_container,
&seat->new_container);
@@ -147,7 +208,7 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input,
WL_SEAT_CAPABILITY_POINTER |
WL_SEAT_CAPABILITY_TOUCH);
- sway_seat_configure_xcursor(seat);
+ seat_configure_xcursor(seat);
wl_list_insert(&input->seats, &seat->link);
@@ -165,11 +226,12 @@ static void seat_configure_keyboard(struct sway_seat *seat,
if (!seat_device->keyboard) {
sway_keyboard_create(seat, seat_device);
}
- struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard;
+ struct wlr_keyboard *wlr_keyboard =
+ seat_device->input_device->wlr_device->keyboard;
sway_keyboard_configure(seat_device->keyboard);
wlr_seat_set_keyboard(seat->wlr_seat,
seat_device->input_device->wlr_device);
- struct sway_container *focus = sway_seat_get_focus(seat);
+ struct sway_container *focus = seat_get_focus(seat);
if (focus && focus->type == C_VIEW) {
// force notify reenter to pick up the new configuration
wlr_seat_keyboard_clear_focus(seat->wlr_seat);
@@ -179,7 +241,7 @@ static void seat_configure_keyboard(struct sway_seat *seat,
}
}
-static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
+static struct sway_seat_device *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) {
@@ -191,19 +253,14 @@ static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat,
return NULL;
}
-void sway_seat_configure_device(struct sway_seat *seat,
+void 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);
+ seat_get_device(seat, input_device);
if (!seat_device) {
return;
}
- 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_configure_pointer(seat, seat_device);
@@ -219,10 +276,10 @@ void sway_seat_configure_device(struct sway_seat *seat,
}
}
-void sway_seat_add_device(struct sway_seat *seat,
+void 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);
+ if (seat_get_device(seat, input_device)) {
+ seat_configure_device(seat, input_device);
return;
}
@@ -240,13 +297,13 @@ void sway_seat_add_device(struct sway_seat *seat,
seat_device->input_device = input_device;
wl_list_insert(&seat->devices, &seat_device->link);
- sway_seat_configure_device(seat, input_device);
+ seat_configure_device(seat, input_device);
}
-void sway_seat_remove_device(struct sway_seat *seat,
+void seat_remove_device(struct sway_seat *seat,
struct sway_input_device *input_device) {
struct sway_seat_device *seat_device =
- sway_seat_get_device(seat, input_device);
+ seat_get_device(seat, input_device);
if (!seat_device) {
return;
@@ -258,7 +315,7 @@ void sway_seat_remove_device(struct sway_seat *seat,
seat_device_destroy(seat_device);
}
-void sway_seat_configure_xcursor(struct sway_seat *seat) {
+void seat_configure_xcursor(struct sway_seat *seat) {
// TODO configure theme and size
const char *cursor_theme = NULL;
@@ -273,7 +330,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
}
for (int i = 0; i < root_container.children->length; ++i) {
- struct sway_container *output_container = root_container.children->items[i];
+ struct sway_container *output_container =
+ root_container.children->items[i];
struct wlr_output *output =
output_container->sway_output->wlr_output;
bool result =
@@ -292,10 +350,13 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) {
seat->cursor->cursor->y);
}
-void sway_seat_set_focus_warp(struct sway_seat *seat,
+void seat_set_focus_warp(struct sway_seat *seat,
struct sway_container *container, bool warp) {
- struct sway_container *last_focus = sway_seat_get_focus(seat);
+ if (seat->focused_layer) {
+ return;
+ }
+ struct sway_container *last_focus = seat_get_focus(seat);
if (container && last_focus == container) {
return;
}
@@ -311,23 +372,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
wl_list_insert(&seat->focus_stack, &seat_con->link);
if (container->type == C_VIEW) {
- struct sway_view *view = container->sway_view;
- view_set_activated(view, true);
- if (view->type == SWAY_XWAYLAND_VIEW) {
- struct wlr_xwayland *xwayland =
- seat->input->server->xwayland;
- wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
- }
- struct wlr_keyboard *keyboard =
- wlr_seat_get_keyboard(seat->wlr_seat);
- if (keyboard) {
- wlr_seat_keyboard_notify_enter(seat->wlr_seat,
- view->surface, keyboard->keycodes,
- keyboard->num_keycodes, &keyboard->modifiers);
- } else {
- wlr_seat_keyboard_notify_enter(
- seat->wlr_seat, view->surface, NULL, 0, NULL);
- }
+ seat_send_focus(seat, container);
}
}
@@ -364,7 +409,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
}
if (last_focus && last_focus->type == C_VIEW &&
- !sway_input_manager_has_focus(seat->input, last_focus)) {
+ !input_manager_has_focus(seat->input, last_focus)) {
struct sway_view *view = last_focus->sway_view;
view_set_activated(view, false);
}
@@ -372,23 +417,69 @@ void sway_seat_set_focus_warp(struct sway_seat *seat,
seat->has_focus = (container != NULL);
}
-void sway_seat_set_focus(struct sway_seat *seat,
+void seat_set_focus(struct sway_seat *seat,
struct sway_container *container) {
- sway_seat_set_focus_warp(seat, container, true);
+ seat_set_focus_warp(seat, container, true);
}
-struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) {
+void seat_set_focus_layer(struct sway_seat *seat,
+ struct wlr_layer_surface *layer) {
+ if (!layer) {
+ seat->focused_layer = NULL;
+ return;
+ }
+ if (seat->focused_layer == layer) {
+ return;
+ }
+ if (seat->has_focus) {
+ struct sway_container *focus = seat_get_focus(seat);
+ if (focus->type == C_VIEW) {
+ wlr_seat_keyboard_clear_focus(seat->wlr_seat);
+ view_set_activated(focus->sway_view, false);
+ }
+ }
+ if (layer->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
+ seat->focused_layer = layer;
+ }
+ struct wlr_keyboard *keyboard =
+ wlr_seat_get_keyboard(seat->wlr_seat);
+ if (keyboard) {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ layer->surface, keyboard->keycodes,
+ keyboard->num_keycodes, &keyboard->modifiers);
+ } else {
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ layer->surface, NULL, 0, NULL);
+ }
+}
+
+struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
+ struct sway_container *container) {
+ return 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 seat_get_focus_inactive(seat, &root_container);
+}
+
+struct sway_container *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) {
parent = current->container->parent;
- if (current->container == container) {
+ if (current->container == container &&
+ (type == C_TYPES || container->type == type)) {
return current->container;
}
while (parent) {
- if (parent == container) {
+ if (parent == container && (type == C_TYPES ||
+ current->container->type == type)) {
return current->container;
}
parent = parent->parent;
@@ -398,42 +489,34 @@ 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) {
+struct sway_container *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
}
- return sway_seat_get_focus_inactive(seat, &root_container);
+ return 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,
+void seat_apply_config(struct sway_seat *seat,
struct seat_config *seat_config) {
- // clear configs
- free_seat_config(seat->config);
- 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 = copy_seat_config(seat_config);
-
wl_list_for_each(seat_device, &seat->devices, link) {
- sway_seat_configure_device(seat, seat_device->input_device);
+ seat_configure_device(seat, seat_device->input_device);
}
}
+
+struct seat_config *seat_get_config(struct sway_seat *seat) {
+ struct seat_config *seat_config = NULL;
+ for (int i = 0; i < config->seat_configs->length; ++i ) {
+ seat_config = config->seat_configs->items[i];
+ if (strcmp(seat->wlr_seat->name, seat_config->name) == 0) {
+ return seat_config;
+ }
+ }
+
+ return NULL;
+}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 7c5f7304..3427c8ec 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -88,11 +88,11 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje
json_object_new_string(
ipc_json_get_output_transform(wlr_output->transform)));
- struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager);
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
const char *ws = NULL;
if (seat) {
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, container);
+ seat_get_focus_inactive(seat, container);
if (focus && focus->type != C_WORKSPACE) {
focus = container_parent(focus, C_WORKSPACE);
}
@@ -139,8 +139,8 @@ json_object *ipc_json_describe_container(struct sway_container *c) {
return NULL;
}
- struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager);
- bool focused = sway_seat_get_focus(seat) == c;
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ bool focused = seat_get_focus(seat) == c;
json_object *object = json_object_new_object();
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 869f1ed0..df5fb699 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -388,8 +388,8 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
// override the default focused indicator because
// it's set differently for the get_workspaces reply
struct sway_seat *seat =
- sway_input_manager_get_default_seat(input_manager);
- struct sway_container *focused_ws = sway_seat_get_focus(seat);
+ input_manager_get_default_seat(input_manager);
+ struct sway_container *focused_ws = seat_get_focus(seat);
if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {
focused_ws = container_parent(focused_ws, C_WORKSPACE);
}
@@ -399,7 +399,7 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
json_object_new_boolean(focused));
json_object_array_add((json_object *)data, workspace_json);
- focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent);
+ focused_ws = seat_get_focus_inactive(seat, workspace->parent);
if (focused_ws->type != C_WORKSPACE) {
focused_ws = container_parent(focused_ws, C_WORKSPACE);
}
diff --git a/sway/main.c b/sway/main.c
index ded922ee..e7f8ddd3 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -118,7 +118,7 @@ void run_as_ipc_client(char *command, char *socket_path) {
static void log_env() {
const char *log_vars[] = {
"PATH",
- "LD_LOAD_PATH",
+ "LD_LIBRARY_PATH",
"LD_PRELOAD_PATH",
"LD_LIBRARY_PATH",
"SWAY_CURSOR_THEME",
diff --git a/sway/meson.build b/sway/meson.build
index 0cc620ea..a6a633a0 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -19,6 +19,8 @@ sway_sources = files(
'commands/input.c',
'commands/layout.c',
'commands/mode.c',
+ 'commands/split.c',
+ 'commands/move.c',
'commands/seat.c',
'commands/seat/attach.c',
'commands/seat/fallback.c',
diff --git a/sway/server.c b/sway/server.c
index f5cc199c..54945312 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -109,7 +109,7 @@ bool server_init(struct sway_server *server) {
return false;
}
- input_manager = sway_input_manager_create(server);
+ input_manager = input_manager_create(server);
return true;
}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 746dbf1f..4db93ce8 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -33,12 +33,29 @@ 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");
}
-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));
@@ -54,11 +71,12 @@ 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;
}
-struct sway_container *container_destroy(struct sway_container *cont) {
+static struct sway_container *_container_destroy(struct sway_container *cont) {
if (cont == NULL) {
return NULL;
}
@@ -66,13 +84,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) {
- container_destroy(cont->children->items[0]);
+ while (cont->children != NULL && cont->children->length != 0) {
+ struct sway_container *child = cont->children->items[0];
+ container_remove_child(child);
+ container_destroy(child);
}
- list_free(cont->children);
}
if (cont->marks) {
list_foreach(cont->marks, free);
@@ -84,10 +103,19 @@ struct sway_container *container_destroy(struct sway_container *cont) {
if (cont->name) {
free(cont->name);
}
+ list_free(cont->children);
+ cont->children = NULL;
free(cont);
return parent;
}
+struct sway_container *container_destroy(struct sway_container *cont) {
+ struct sway_container *parent = _container_destroy(cont);
+ parent = container_reap_empty(parent);
+ arrange_windows(&root_container, -1, -1);
+ return parent;
+}
+
struct sway_container *container_output_create(
struct sway_output *sway_output) {
struct wlr_box size;
@@ -144,7 +172,7 @@ struct sway_container *container_output_create(
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input_manager->seats, link) {
if (!seat->has_focus) {
- sway_seat_set_focus(seat, ws);
+ seat_set_focus(seat, ws);
}
}
@@ -395,3 +423,17 @@ bool container_has_anscestor(struct sway_container *descendant,
}
return false;
}
+
+static bool find_child_func(struct sway_container *con, void *data) {
+ struct sway_container *child = data;
+ return con == child;
+}
+
+bool container_has_child(struct sway_container *con,
+ struct sway_container *child) {
+ if (child == NULL || child->type == C_VIEW ||
+ child->children->length == 0) {
+ return false;
+ }
+ return container_find(con, find_child_func, child);
+}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index ce0682dc..95a84d12 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
@@ -57,7 +58,7 @@ void layout_init(void) {
root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
root_container.sway_root->output_layout = wlr_output_layout_create();
- wl_list_init(&root_container.sway_root->unmanaged_views);
+ wl_list_init(&root_container.sway_root->xwayland_unmanaged);
wl_signal_init(&root_container.sway_root->events.new_container);
root_container.sway_root->output_layout_change.notify =
@@ -103,11 +104,13 @@ void container_add_child(struct sway_container *parent,
}
struct sway_container *container_reap_empty(struct sway_container *container) {
- if (!sway_assert(container, "reaping null container")) {
+ if (container == NULL) {
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;
@@ -135,25 +138,49 @@ 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,
- 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 = 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);
+ seat_set_focus(seat, ws);
+ }
+ container_sort_workspaces(new_parent);
+ 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) {
@@ -248,8 +275,8 @@ void arrange_windows(struct sway_container *container,
struct wlr_box *area = &output->sway_output->usable_area;
wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
area->width, area->height, area->x, area->y);
- container->width = area->width;
- container->height = area->height;
+ container->width = width = area->width;
+ container->height = height = area->height;
container->x = x = area->x;
container->y = y = area->y;
wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
@@ -261,7 +288,7 @@ void arrange_windows(struct sway_container *container,
{
container->width = width;
container->height = height;
- view_set_size(container->sway_view,
+ view_configure(container->sway_view, container->x, container->y,
container->width, container->height);
wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f",
container->width, container->height,
@@ -322,7 +349,14 @@ 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_configure(child->sway_view, child_x, y, child->width,
+ child->height);
+ } else {
+ child->x = child_x;
+ child->y = y;
+ }
if (i == end - 1) {
double remaining_width = x + width - child_x;
@@ -373,7 +407,13 @@ void apply_vert_layout(struct sway_container *container,
wlr_log(L_DEBUG,
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, height, scale);
- view_set_position(child->sway_view, x, child_y);
+ if (child->type == C_VIEW) {
+ view_configure(child->sway_view, x, child_y, child->width,
+ child->height);
+ } else {
+ child->x = x;
+ child->y = child_y;
+ }
if (i == end - 1) {
double remaining_height = y + height - child_y;
@@ -404,7 +444,7 @@ static struct sway_container *get_swayc_in_output_direction(
return NULL;
}
- struct sway_container *ws = sway_seat_get_focus_inactive(seat, output);
+ struct sway_container *ws = seat_get_focus_inactive(seat, output);
if (ws->type != C_WORKSPACE) {
ws = container_parent(ws, C_WORKSPACE);
}
@@ -425,7 +465,7 @@ static struct sway_container *get_swayc_in_output_direction(
case MOVE_UP:
case MOVE_DOWN: {
struct sway_container *focused =
- sway_seat_get_focus_inactive(seat, ws);
+ seat_get_focus_inactive(seat, ws);
if (focused && focused->parent) {
struct sway_container *parent = focused->parent;
if (parent->layout == L_VERT) {
@@ -505,11 +545,11 @@ 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);
+ return seat_get_focus_inactive(seat, container);
}
struct sway_container *parent = container->parent;
@@ -521,26 +561,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)) {
@@ -559,7 +579,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 +608,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 seat_get_focus_by_type(seat, next, C_VIEW);
} else {
return next;
}
@@ -619,21 +638,23 @@ static struct sway_container *get_swayc_in_direction_under(
wrap_candidate = parent->children->items[0];
}
if (config->force_focus_wrapping) {
- return wrap_candidate;
+ return 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 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 +662,70 @@ 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->width = child->width;
+ cont->height = child->height;
+ cont->x = child->x;
+ cont->y = child->y;
+
+ if (child->type == C_WORKSPACE) {
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+ struct sway_container *workspace = child;
+ bool set_focus = (seat_get_focus(seat) == workspace);
+
+ while (workspace->children->length) {
+ struct sway_container *ws_child = workspace->children->items[0];
+ container_remove_child(ws_child);
+ container_add_child(cont, ws_child);
+ }
+
+ container_add_child(workspace, cont);
+ container_set_layout(workspace, layout);
+
+ if (set_focus) {
+ seat_set_focus(seat, cont);
+ }
+ } else {
+ cont->layout = layout;
+ container_replace_child(child, cont);
+ container_add_child(cont, child);
+ }
+
+ return cont;
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 7248fd00..0509db23 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -1,3 +1,4 @@
+#include <strings.h>
#include "sway/tree/container.h"
#include "sway/tree/layout.h"
#include "sway/output.h"
@@ -29,6 +30,7 @@ struct sway_container *container_output_destroy(struct sway_container *output) {
wl_list_remove(&output->sway_output->destroy.link);
wl_list_remove(&output->sway_output->mode.link);
wl_list_remove(&output->sway_output->transform.link);
+ wl_list_remove(&output->sway_output->scale.link);
wl_list_remove(&output->sway_output->damage_destroy.link);
wl_list_remove(&output->sway_output->damage_frame.link);
@@ -37,3 +39,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;
+}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index b7d1a41b..09c804e4 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h>
#include "log.h"
@@ -6,82 +7,117 @@
#include "sway/tree/layout.h"
#include "sway/tree/view.h"
+struct sway_view *view_create(enum sway_view_type type,
+ const struct sway_view_impl *impl) {
+ struct sway_view *view = calloc(1, sizeof(struct sway_view));
+ if (view == NULL) {
+ return NULL;
+ }
+ view->type = type;
+ view->impl = impl;
+ return view;
+}
+
+void view_destroy(struct sway_view *view) {
+ if (view == NULL) {
+ return;
+ }
+
+ if (view->surface != NULL) {
+ view_unmap(view);
+ }
+
+ container_view_destroy(view->swayc);
+ free(view);
+}
+
const char *view_get_title(struct sway_view *view) {
- if (view->iface.get_prop) {
- return view->iface.get_prop(view, VIEW_PROP_TITLE);
+ if (view->impl->get_prop) {
+ return view->impl->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);
+ if (view->impl->get_prop) {
+ return view->impl->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);
+ if (view->impl->get_prop) {
+ return view->impl->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);
+ if (view->impl->get_prop) {
+ return view->impl->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) {
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
- view->iface.set_size(view, width, height);
- view_update_outputs(view, &box);
+void view_configure(struct sway_view *view, double ox, double oy, int width,
+ int height) {
+ if (view->impl->configure) {
+ view->impl->configure(view, ox, oy, width, height);
}
}
-// TODO make view coordinates in layout coordinates
-void view_set_position(struct sway_view *view, double ox, double oy) {
- if (view->iface.set_position) {
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
- view->iface.set_position(view, ox, oy);
- view_update_outputs(view, &box);
+void view_set_activated(struct sway_view *view, bool activated) {
+ if (view->impl->set_activated) {
+ view->impl->set_activated(view, activated);
}
}
-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->impl->close) {
+ view->impl->close(view);
}
}
-void view_close(struct sway_view *view) {
- if (view->iface.close) {
- view->iface.close(view);
+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;
+}
+
+void view_damage_whole(struct sway_view *view) {
+ 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_view(cont->sway_output, view);
+ }
+ }
+}
+
+void view_damage_from(struct sway_view *view) {
+ // TODO
+ view_damage_whole(view);
+}
+
+static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) {
+ struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+
+ box->x = output->x + view->swayc->x;
+ box->y = output->y + view->swayc->y;
+ box->width = view->width;
+ box->height = view->height;
}
-void view_update_outputs(struct sway_view *view, const struct wlr_box *before) {
+static void view_update_outputs(struct sway_view *view,
+ const struct wlr_box *before) {
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+
struct wlr_output_layout *output_layout =
root_container.sway_root->output_layout;
- struct wlr_box box = {
- .x = view->swayc->x,
- .y = view->swayc->y,
- .width = view->width,
- .height = view->height,
- };
struct wlr_output_layout_output *layout_output;
wl_list_for_each(layout_output, &output_layout->outputs, link) {
bool intersected = before != NULL && wlr_output_layout_intersects(
@@ -97,27 +133,63 @@ 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;
+void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
+ if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {
+ return;
}
- wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
- struct sway_container *parent = container_destroy(view);
- arrange_windows(parent, -1, -1);
- return parent;
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *focus = seat_get_focus_inactive(seat,
+ &root_container);
+ struct sway_container *cont = container_view_create(focus, view);
+
+ view->surface = wlr_surface;
+ view->swayc = cont;
+
+ arrange_windows(cont->parent, -1, -1);
+ input_manager_set_focus(input_manager, cont);
+
+ view_damage_whole(view);
+ view_update_outputs(view, NULL);
}
-void view_damage_whole(struct sway_view *view) {
- struct sway_container *cont = NULL;
- for (int i = 0; i < root_container.children->length; ++i) {
- cont = root_container.children->items[i];
- if (cont->type == C_OUTPUT) {
- output_damage_whole_view(cont->sway_output, view);
- }
+void view_unmap(struct sway_view *view) {
+ if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) {
+ return;
}
+
+ view_damage_whole(view);
+
+ container_view_destroy(view->swayc);
+
+ view->swayc = NULL;
+ view->surface = NULL;
}
-void view_damage_from(struct sway_view *view) {
- // TODO
+void view_update_position(struct sway_view *view, double ox, double oy) {
+ if (view->swayc->x == ox && view->swayc->y == oy) {
+ return;
+ }
+
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+ view_damage_whole(view);
+ view->swayc->x = ox;
+ view->swayc->y = oy;
+ view_update_outputs(view, &box);
+ view_damage_whole(view);
+}
+
+void view_update_size(struct sway_view *view, int width, int height) {
+ if (view->width == width && view->height == height) {
+ return;
+ }
+
+ struct wlr_box box;
+ view_get_layout_box(view, &box);
+ view_damage_whole(view);
+ view->width = width;
+ view->height = height;
+ view_update_outputs(view, &box);
view_damage_whole(view);
}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index d6fd7c70..8077de2e 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -176,7 +176,7 @@ static bool _workspace_by_name(struct sway_container *view, void *data) {
struct sway_container *workspace_by_name(const char *name) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *current_workspace = NULL, *current_output = NULL;
- struct sway_container *focus = sway_seat_get_focus(seat);
+ struct sway_container *focus = seat_get_focus(seat);
if (focus) {
current_workspace = container_parent(focus, C_WORKSPACE);
current_output = container_parent(focus, C_OUTPUT);
@@ -218,7 +218,7 @@ struct sway_container *workspace_create(const char *name) {
// Otherwise create a new one
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
parent = focus;
parent = container_parent(parent, C_OUTPUT);
struct sway_container *new_ws = container_workspace_create(parent, name);
@@ -278,7 +278,7 @@ struct sway_container *workspace_output_prev_next_impl(
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = sway_seat_get_focus_inactive(seat, output);
+ struct sway_container *focus = seat_get_focus_inactive(seat, output);
struct sway_container *workspace = (focus->type == C_WORKSPACE ?
focus :
container_parent(focus, C_WORKSPACE));
@@ -363,13 +363,13 @@ bool workspace_switch(struct sway_container *workspace) {
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *focus =
- sway_seat_get_focus_inactive(seat, &root_container);
+ seat_get_focus_inactive(seat, &root_container);
if (!seat || !focus) {
return false;
}
struct sway_container *active_ws = focus;
if (active_ws->type != C_WORKSPACE) {
- container_parent(focus, C_WORKSPACE);
+ active_ws = container_parent(focus, C_WORKSPACE);
}
if (config->auto_back_and_forth
@@ -394,11 +394,11 @@ bool workspace_switch(struct sway_container *workspace) {
wlr_log(L_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name);
- struct sway_container *next = sway_seat_get_focus_inactive(seat, workspace);
+ struct sway_container *next = seat_get_focus_inactive(seat, workspace);
if (next == NULL) {
next = workspace;
}
- sway_seat_set_focus(seat, next);
+ seat_set_focus(seat, next);
struct sway_container *output = container_parent(workspace, C_OUTPUT);
arrange_windows(output, -1, -1);
return true;
@@ -407,7 +407,7 @@ bool workspace_switch(struct sway_container *workspace) {
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);
+ struct sway_container *focus = seat_get_focus_inactive(seat, output);
if (focus->type != C_WORKSPACE) {
focus = container_parent(focus, C_WORKSPACE);
}
diff --git a/swaybar/bar.c b/swaybar/bar.c
index f743236c..fb417095 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -308,14 +308,14 @@ static void display_in(int fd, short mask, void *_bar) {
static void ipc_in(int fd, short mask, void *_bar) {
struct swaybar *bar = (struct swaybar *)_bar;
- if (handle_ipc_event(bar)) {
+ if (handle_ipc_readable(bar)) {
render_all_frames(bar);
}
}
static void status_in(int fd, short mask, void *_bar) {
struct swaybar *bar = (struct swaybar *)_bar;
- if (handle_status_readable(bar->status)) {
+ if (status_handle_readable(bar->status)) {
render_all_frames(bar);
}
}
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
new file mode 100644
index 00000000..ed134a01
--- /dev/null
+++ b/swaybar/i3bar.c
@@ -0,0 +1,211 @@
+#define _POSIX_C_SOURCE 200809L
+#include <json-c/json.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include "swaybar/config.h"
+#include "swaybar/status_line.h"
+
+static void i3bar_block_free(struct i3bar_block *block) {
+ if (!block) {
+ return;
+ }
+ wl_list_remove(&block->link);
+ free(block->full_text);
+ free(block->short_text);
+ free(block->align);
+ free(block->name);
+ free(block->instance);
+ free(block->color);
+}
+
+static bool i3bar_parse_json(struct status_line *status, const char *text) {
+ struct i3bar_block *block, *tmp;
+ wl_list_for_each_safe(block, tmp, &status->blocks, link) {
+ i3bar_block_free(block);
+ }
+ json_object *results = json_tokener_parse(text);
+ if (!results) {
+ status_error(status, "[failed to parse i3bar json]");
+ return false;
+ }
+ wlr_log(L_DEBUG, "Got i3bar json: '%s'", text);
+ for (size_t i = 0; i < json_object_array_length(results); ++i) {
+ json_object *full_text, *short_text, *color, *min_width, *align, *urgent;
+ json_object *name, *instance, *separator, *separator_block_width;
+ json_object *background, *border, *border_top, *border_bottom;
+ json_object *border_left, *border_right, *markup;
+ json_object *json = json_object_array_get_idx(results, i);
+ if (!json) {
+ continue;
+ }
+ json_object_object_get_ex(json, "full_text", &full_text);
+ json_object_object_get_ex(json, "short_text", &short_text);
+ json_object_object_get_ex(json, "color", &color);
+ json_object_object_get_ex(json, "min_width", &min_width);
+ json_object_object_get_ex(json, "align", &align);
+ json_object_object_get_ex(json, "urgent", &urgent);
+ json_object_object_get_ex(json, "name", &name);
+ json_object_object_get_ex(json, "instance", &instance);
+ json_object_object_get_ex(json, "markup", &markup);
+ json_object_object_get_ex(json, "separator", &separator);
+ json_object_object_get_ex(json, "separator_block_width", &separator_block_width);
+ json_object_object_get_ex(json, "background", &background);
+ json_object_object_get_ex(json, "border", &border);
+ json_object_object_get_ex(json, "border_top", &border_top);
+ json_object_object_get_ex(json, "border_bottom", &border_bottom);
+ json_object_object_get_ex(json, "border_left", &border_left);
+ json_object_object_get_ex(json, "border_right", &border_right);
+
+ struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block));
+ block->full_text = full_text ?
+ strdup(json_object_get_string(full_text)) : NULL;
+ block->short_text = short_text ?
+ strdup(json_object_get_string(short_text)) : NULL;
+ if (color) {
+ block->color = malloc(sizeof(uint32_t));
+ *block->color = parse_color(json_object_get_string(color));
+ }
+ if (min_width) {
+ json_type type = json_object_get_type(min_width);
+ if (type == json_type_int) {
+ block->min_width = json_object_get_int(min_width);
+ } else if (type == json_type_string) {
+ /* the width will be calculated when rendering */
+ block->min_width = 0;
+ }
+ }
+ block->align = strdup(align ? json_object_get_string(align) : "left");
+ block->urgent = urgent ? json_object_get_int(urgent) : false;
+ block->name = name ? strdup(json_object_get_string(name)) : NULL;
+ block->instance = instance ?
+ strdup(json_object_get_string(instance)) : NULL;
+ if (markup) {
+ block->markup = false;
+ const char *markup_str = json_object_get_string(markup);
+ if (strcmp(markup_str, "pango") == 0) {
+ block->markup = true;
+ }
+ }
+ block->separator = separator ? json_object_get_int(separator) : true;
+ block->separator_block_width = separator_block_width ?
+ json_object_get_int(separator_block_width) : 9;
+ // Airblader features
+ block->background = background ?
+ parse_color(json_object_get_string(background)) : 0;
+ block->border = border ?
+ parse_color(json_object_get_string(border)) : 0;
+ block->border_top = border_top ? json_object_get_int(border_top) : 1;
+ block->border_bottom = border_bottom ?
+ json_object_get_int(border_bottom) : 1;
+ block->border_left = border_left ? json_object_get_int(border_left) : 1;
+ block->border_right = border_right ?
+ json_object_get_int(border_right) : 1;
+ wl_list_insert(&status->blocks, &block->link);
+ }
+ return true;
+}
+
+bool i3bar_handle_readable(struct status_line *status) {
+ struct i3bar_protocol_state *state = &status->i3bar_state;
+
+ char *cur = &state->buffer[state->buffer_index];
+ ssize_t n = read(status->read_fd, cur,
+ state->buffer_size - state->buffer_index);
+ if (n == 0) {
+ return 0;
+ }
+
+ if (n == (ssize_t)(state->buffer_size - state->buffer_index)) {
+ state->buffer_size = state->buffer_size * 2;
+ char *new_buffer = realloc(state->buffer, state->buffer_size);
+ if (!new_buffer) {
+ free(state->buffer);
+ status_error(status, "[failed to allocate buffer]");
+ return -1;
+ }
+ state->buffer = new_buffer;
+ }
+
+ bool redraw = false;
+ while (*cur) {
+ if (state->nodes[state->depth] == JSON_NODE_STRING) {
+ if (!state->escape && *cur == '"') {
+ --state->depth;
+ }
+ state->escape = !state->escape && *cur == '\\';
+ } else {
+ switch (*cur) {
+ case '[':
+ ++state->depth;
+ if (state->depth >
+ sizeof(state->nodes) / sizeof(state->nodes[0])) {
+ status_error(status, "[i3bar json too deep]");
+ return false;
+ }
+ state->nodes[state->depth] = JSON_NODE_ARRAY;
+ if (state->depth == 1) {
+ state->current_node = cur;
+ }
+ break;
+ case ']':
+ if (state->nodes[state->depth] != JSON_NODE_ARRAY) {
+ status_error(status, "[failed to parse i3bar json]");
+ return false;
+ }
+ --state->depth;
+ if (state->depth == 0) {
+ // cur[1] is valid since cur[0] != '\0'
+ char p = cur[1];
+ cur[1] = '\0';
+ redraw = i3bar_parse_json(
+ status, state->current_node) || redraw;
+ cur[1] = p;
+ memmove(state->buffer, cur,
+ state->buffer_size - (cur - state->buffer));
+ cur = state->buffer;
+ state->current_node = cur + 1;
+ }
+ break;
+ case '"':
+ ++state->depth;
+ if (state->depth >
+ sizeof(state->nodes) / sizeof(state->nodes[0])) {
+ status_error(status, "[i3bar json too deep]");
+ return false;
+ }
+ state->nodes[state->depth] = JSON_NODE_STRING;
+ break;
+ }
+ }
+ ++cur;
+ }
+ state->buffer_index = cur - state->buffer;
+ return redraw;
+}
+
+void i3bar_block_send_click(struct status_line *status,
+ struct i3bar_block *block, int x, int y, uint32_t button) {
+ wlr_log(L_DEBUG, "block %s clicked", block->name ? block->name : "(nil)");
+ if (!block->name || !status->i3bar_state.click_events) {
+ return;
+ }
+
+ struct json_object *event_json = json_object_new_object();
+ json_object_object_add(event_json, "name",
+ json_object_new_string(block->name));
+ if (block->instance) {
+ json_object_object_add(event_json, "instance",
+ json_object_new_string(block->instance));
+ }
+
+ json_object_object_add(event_json, "button", json_object_new_int(button));
+ json_object_object_add(event_json, "x", json_object_new_int(x));
+ json_object_object_add(event_json, "y", json_object_new_int(y));
+ if (dprintf(status->write_fd, "%s\n",
+ json_object_to_json_string(event_json)) < 0) {
+ status_error(status, "[failed to write click event]");
+ }
+ json_object_put(event_json);
+}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 64583df0..ed5d9a31 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -323,7 +323,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) {
IPC_SUBSCRIBE, subscribe, &len));
}
-bool handle_ipc_event(struct swaybar *bar) {
+bool handle_ipc_readable(struct swaybar *bar) {
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
if (!resp) {
return false;
diff --git a/swaybar/meson.build b/swaybar/meson.build
index bf6f6d7a..d65edb11 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -3,6 +3,7 @@ executable(
'bar.c',
'config.c',
'event_loop.c',
+ 'i3bar.c',
'ipc.c',
'main.c',
'render.c',
diff --git a/swaybar/render.c b/swaybar/render.c
index c2358724..6f3b0788 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -18,10 +18,33 @@ static const int ws_horizontal_padding = 5;
static const double ws_vertical_padding = 1.5;
static const double border_width = 1;
+static uint32_t render_status_line_error(cairo_t *cairo,
+ struct swaybar_config *config, const char *error,
+ double *x, uint32_t width, uint32_t height) {
+ if (!error) {
+ return 0;
+ }
+ cairo_set_source_u32(cairo, 0xFF0000FF);
+ static const int margin = 3;
+ int text_width, text_height;
+ get_text_size(cairo, config->font,
+ &text_width, &text_height, 1, false, "%s", error);
+ uint32_t ideal_height = text_height + ws_vertical_padding * 2;
+ if (height < ideal_height) {
+ return ideal_height;
+ }
+ *x -= text_width + margin;
+ double text_y = height / 2.0 - text_height / 2.0;
+ cairo_move_to(cairo, *x, (int)floor(text_y));
+ pango_printf(cairo, config->font, 1, false, "%s", error);
+ *x -= margin;
+ return ideal_height;
+}
+
static uint32_t render_status_line_text(cairo_t *cairo,
- struct swaybar_config *config, struct status_line *status,
- bool focused, uint32_t width, uint32_t height) {
- if (!status->text) {
+ struct swaybar_config *config, const char *text,
+ bool focused, double *x, uint32_t width, uint32_t height) {
+ if (!text) {
return 0;
}
cairo_set_source_u32(cairo, focused ?
@@ -29,38 +52,211 @@ static uint32_t render_status_line_text(cairo_t *cairo,
static const int margin = 3;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height,
- 1, config->pango_markup, "%s", status->text);
+ 1, config->pango_markup, "%s", text);
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
if (height < ideal_height) {
return ideal_height;
}
+ *x -= text_width + margin;
double text_y = height / 2.0 - text_height / 2.0;
- cairo_move_to(cairo, width - text_width - margin, (int)floor(text_y));
- pango_printf(cairo, config->font, 1, config->pango_markup,
- "%s", status->text);
+ cairo_move_to(cairo, *x, (int)floor(text_y));
+ pango_printf(cairo, config->font, 1, config->pango_markup, "%s", text);
+ *x -= margin;
+ return ideal_height;
+}
+
+static void render_sharp_line(cairo_t *cairo, uint32_t color,
+ double x, double y, double width, double height) {
+ cairo_set_source_u32(cairo, color);
+ if (width > 1 && height > 1) {
+ cairo_rectangle(cairo, x, y, width, height);
+ cairo_fill(cairo);
+ } else {
+ if (width == 1) {
+ x += 0.5;
+ height += y;
+ width = x;
+ }
+ if (height == 1) {
+ y += 0.5;
+ width += x;
+ height = y;
+ }
+ cairo_move_to(cairo, x, y);
+ cairo_set_line_width(cairo, 1.0);
+ cairo_line_to(cairo, width, height);
+ cairo_stroke(cairo);
+ }
+}
+
+static void block_hotspot_callback(struct swaybar_output *output,
+ int x, int y, uint32_t button, void *data) {
+ struct i3bar_block *block = data;
+ struct status_line *status = output->bar->status;
+ i3bar_block_send_click(status, block, x, y, button);
+}
+
+static uint32_t render_status_block(cairo_t *cairo,
+ struct swaybar_config *config, struct swaybar_output *output,
+ struct i3bar_block *block, double *x,
+ uint32_t height, bool focused, bool edge) {
+ static const int margin = 3;
+ if (!block->full_text || !*block->full_text) {
+ return 0;
+ }
+
+ int text_width, text_height;
+ get_text_size(cairo, config->font, &text_width, &text_height,
+ 1, block->markup, "%s", block->full_text);
+ int width = text_width;
+ if (width < block->min_width) {
+ width = block->min_width;
+ }
+ double block_width = width;
+ uint32_t ideal_height = text_height + ws_vertical_padding * 2;
+ if (height < ideal_height) {
+ return ideal_height;
+ }
+
+ *x -= width;
+ if (block->border && block->border_left > 0) {
+ *x -= (block->border_left + margin);
+ block_width += block->border_left + margin;
+ }
+ if (block->border && block->border_right > 0) {
+ *x -= (block->border_right + margin);
+ block_width += block->border_right + margin;
+ }
+
+ int sep_width;
+ if (!edge) {
+ if (config->sep_symbol) {
+ int _height;
+ get_text_size(cairo, config->font, &sep_width, &_height,
+ 1, false, "%s", config->sep_symbol);
+ uint32_t _ideal_height = _height + ws_vertical_padding * 2;
+ if (height < _ideal_height) {
+ return _height;
+ }
+ if (sep_width > block->separator_block_width) {
+ block->separator_block_width = sep_width + margin * 2;
+ }
+ }
+ *x -= block->separator_block_width;
+ } else {
+ *x -= margin;
+ }
+
+ struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
+ hotspot->x = *x;
+ hotspot->y = 0;
+ hotspot->width = width;
+ hotspot->height = height;
+ hotspot->callback = block_hotspot_callback;
+ hotspot->destroy = NULL;
+ hotspot->data = block;
+ wl_list_insert(&output->hotspots, &hotspot->link);
+
+ double pos = *x;
+ if (block->background) {
+ cairo_set_source_u32(cairo, block->background);
+ cairo_rectangle(cairo, pos - 0.5, 1, block_width, height);
+ cairo_fill(cairo);
+ }
+
+ if (block->border && block->border_top > 0) {
+ render_sharp_line(cairo, block->border,
+ pos - 0.5, 1, block_width, block->border_top);
+ }
+ if (block->border && block->border_bottom > 0) {
+ render_sharp_line(cairo, block->border,
+ pos - 0.5, height - 1 - block->border_bottom,
+ block_width, block->border_bottom);
+ }
+ if (block->border != 0 && block->border_left > 0) {
+ render_sharp_line(cairo, block->border,
+ pos - 0.5, 1, block->border_left, height);
+ pos += block->border_left + margin;
+ }
+
+ double offset = 0;
+ if (strncmp(block->align, "left", 5) == 0) {
+ offset = pos;
+ } else if (strncmp(block->align, "right", 5) == 0) {
+ offset = pos + width - text_width;
+ } else if (strncmp(block->align, "center", 6) == 0) {
+ offset = pos + (width - text_width) / 2;
+ }
+ cairo_move_to(cairo, offset, height / 2.0 - text_height / 2.0);
+ uint32_t color = block->color ? *block->color : config->colors.statusline;
+ cairo_set_source_u32(cairo, color);
+ pango_printf(cairo, config->font, 1, block->markup, "%s", block->full_text);
+ pos += width;
+
+ if (block->border && block->border_right > 0) {
+ pos += margin;
+ render_sharp_line(cairo, block->border,
+ pos - 0.5, 1, block->border_right, height);
+ pos += block->border_right;
+ }
+
+ if (!edge && block->separator) {
+ if (focused) {
+ cairo_set_source_u32(cairo, config->colors.focused_separator);
+ } else {
+ cairo_set_source_u32(cairo, config->colors.separator);
+ }
+ if (config->sep_symbol) {
+ offset = pos + (block->separator_block_width - sep_width) / 2;
+ cairo_move_to(cairo, offset, margin);
+ pango_printf(cairo, config->font, 1, false,
+ "%s", config->sep_symbol);
+ } else {
+ cairo_set_line_width(cairo, 1);
+ cairo_move_to(cairo,
+ pos + block->separator_block_width / 2, margin);
+ cairo_line_to(cairo,
+ pos + block->separator_block_width / 2, height - margin);
+ cairo_stroke(cairo);
+ }
+ }
return ideal_height;
}
static uint32_t render_status_line_i3bar(cairo_t *cairo,
- struct swaybar_config *config, struct status_line *status,
- bool focused, uint32_t width, uint32_t height) {
- // TODO
- return 0;
+ struct swaybar_config *config, struct swaybar_output *output,
+ struct status_line *status, bool focused,
+ double *x, uint32_t width, uint32_t height) {
+ uint32_t max_height = 0;
+ bool edge = true;
+ struct i3bar_block *block;
+ wl_list_for_each(block, &status->blocks, link) {
+ uint32_t h = render_status_block(cairo, config, output,
+ block, x, height, focused, edge);
+ max_height = h > max_height ? h : max_height;
+ edge = false;
+ }
+ return max_height;
}
static uint32_t render_status_line(cairo_t *cairo,
- struct swaybar_config *config, struct status_line *status,
- bool focused, uint32_t width, uint32_t height) {
+ struct swaybar_config *config, struct swaybar_output *output,
+ struct status_line *status, bool focused,
+ double *x, uint32_t width, uint32_t height) {
switch (status->protocol) {
+ case PROTOCOL_ERROR:
+ return render_status_line_error(cairo,
+ config, status->text, x, width, height);
case PROTOCOL_TEXT:
return render_status_line_text(cairo,
- config, status, focused, width, height);
+ config, status->text, focused, x, width, height);
case PROTOCOL_I3BAR:
- return render_status_line_i3bar(cairo,
- config, status, focused, width, height);
- default:
+ return render_status_line_i3bar(cairo, config, output, status,
+ focused, x, width, height);
+ case PROTOCOL_UNDEF:
return 0;
}
+ return 0;
}
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
@@ -166,8 +362,8 @@ static uint32_t render_workspace_button(cairo_t *cairo,
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x;
hotspot->y = 0;
- hotspot->height = height;
hotspot->width = width;
+ hotspot->height = height;
hotspot->callback = workspace_hotspot_callback;
hotspot->destroy = free;
hotspot->data = strdup(name);
@@ -180,6 +376,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
static uint32_t render_to_cairo(cairo_t *cairo,
struct swaybar *bar, struct swaybar_output *output) {
struct swaybar_config *config = bar->config;
+ wlr_log(L_DEBUG, "output %p", output);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
if (output->focused) {
@@ -211,9 +408,10 @@ static uint32_t render_to_cairo(cairo_t *cairo,
cairo, config, config->mode, x, output->height);
max_height = h > max_height ? h : max_height;
}
+ x = output->width;
if (bar->status) {
- uint32_t h = render_status_line(cairo, config, bar->status,
- output->focused, output->width, output->height);
+ uint32_t h = render_status_line(cairo, config, output, bar->status,
+ output->focused, &x, output->width, output->height);
max_height = h > max_height ? h : max_height;
}
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 3454f207..8afe4707 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE
#include <fcntl.h>
+#include <json-c/json.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -9,35 +10,83 @@
#include "swaybar/status_line.h"
#include "readline.h"
-bool handle_status_readable(struct status_line *status) {
- char *line = read_line_buffer(status->read,
- status->buffer, status->buffer_size);
+void status_error(struct status_line *status, const char *text) {
+ close(status->read_fd);
+ close(status->write_fd);
+ status->protocol = PROTOCOL_ERROR;
+ status->text = text;
+}
+
+bool status_handle_readable(struct status_line *status) {
+ char *line;
switch (status->protocol) {
+ case PROTOCOL_ERROR:
+ return false;
case PROTOCOL_I3BAR:
- // TODO
+ if (i3bar_handle_readable(status) > 0) {
+ return true;
+ }
break;
case PROTOCOL_TEXT:
- status->text = line;
+ line = read_line_buffer(status->read,
+ status->text_state.buffer, status->text_state.buffer_size);
+ if (!line) {
+ status_error(status, "[error reading from status command]");
+ } else {
+ status->text = line;
+ }
return true;
case PROTOCOL_UNDEF:
+ line = read_line_buffer(status->read,
+ status->text_state.buffer, status->text_state.buffer_size);
if (!line) {
+ status_error(status, "[error reading from status command]");
return false;
}
if (line[0] == '{') {
- // TODO: JSON
+ json_object *proto = json_tokener_parse(line);
+ if (proto) {
+ json_object *version;
+ if (json_object_object_get_ex(proto, "version", &version)
+ && json_object_get_int(version) == 1) {
+ wlr_log(L_DEBUG, "Switched to i3bar protocol.");
+ status->protocol = PROTOCOL_I3BAR;
+ }
+ json_object *click_events;
+ if (json_object_object_get_ex(
+ proto, "click_events", &click_events)
+ && json_object_get_boolean(click_events)) {
+ wlr_log(L_DEBUG, "Enabled click events.");
+ status->i3bar_state.click_events = true;
+ const char *events_array = "[\n";
+ ssize_t len = strlen(events_array);
+ if (write(status->write_fd, events_array, len) != len) {
+ status_error(status,
+ "[failed to write to status command]");
+ }
+ }
+ json_object_put(proto);
+ }
+
+ status->protocol = PROTOCOL_I3BAR;
+ free(status->text_state.buffer);
+ wl_list_init(&status->blocks);
+ status->i3bar_state.buffer_size = 4096;
+ status->i3bar_state.buffer =
+ malloc(status->i3bar_state.buffer_size);
} else {
- status->text = line;
status->protocol = PROTOCOL_TEXT;
+ status->text = line;
}
- return false;
+ return true;
}
return false;
}
struct status_line *status_line_init(char *cmd) {
struct status_line *status = calloc(1, sizeof(struct status_line));
- status->buffer_size = 4096;
- status->buffer = malloc(status->buffer_size);
+ status->text_state.buffer_size = 8192;
+ status->text_state.buffer = malloc(status->text_state.buffer_size);
int pipe_read_fd[2];
int pipe_write_fd[2];