You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
13 KiB

7 years ago
#define _POSIX_C_SOURCE 199309L
#include <stdbool.h>
#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/xwayland.h>
#include "log.h"
#include "sway/desktop.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/layout.h"
#include "sway/tree/view.h"
7 years ago
static void unmanaged_handle_request_configure(struct wl_listener *listener,
void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, request_configure);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
struct wlr_xwayland_surface_configure_event *ev = data;
wlr_xwayland_surface_configure(xsurface, ev->x, ev->y,
ev->width, ev->height);
}
static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, commit);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
// Surface has moved
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
true);
surface->lx = xsurface->x;
surface->ly = xsurface->y;
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
true);
} else {
desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y,
false);
}
}
static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, map);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
wl_list_insert(&root_container.sway_root->xwayland_unmanaged,
&surface->link);
wl_signal_add(&xsurface->surface->events.commit, &surface->commit);
surface->commit.notify = unmanaged_handle_commit;
surface->lx = xsurface->x;
surface->ly = xsurface->y;
desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
if (!wlr_xwayland_surface_is_unmanaged(xsurface)) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct wlr_xwayland *xwayland = seat->input->server->xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
seat_set_focus_surface(seat, xsurface->surface);
}
// TODO: we don't send surface enter/leave events to xwayland unmanaged
// surfaces, but xwayland doesn't support HiDPI anyway
}
static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, unmap);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
wl_list_remove(&surface->link);
wl_list_remove(&surface->commit.link);
}
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, destroy);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
if (xsurface->mapped) {
unmanaged_handle_unmap(&surface->unmap, xsurface);
}
wl_list_remove(&surface->map.link);
wl_list_remove(&surface->unmap.link);
wl_list_remove(&surface->destroy.link);
free(surface);
}
static struct sway_xwayland_unmanaged *create_unmanaged(
struct wlr_xwayland_surface *xsurface) {
struct sway_xwayland_unmanaged *surface =
calloc(1, sizeof(struct sway_xwayland_unmanaged));
if (surface == NULL) {
wlr_log(L_ERROR, "Allocation failed");
return NULL;
}
surface->wlr_xwayland_surface = xsurface;
wl_signal_add(&xsurface->events.request_configure,
&surface->request_configure);
surface->request_configure.notify = unmanaged_handle_request_configure;
wl_signal_add(&xsurface->events.map, &surface->map);
surface->map.notify = unmanaged_handle_map;
wl_signal_add(&xsurface->events.unmap, &surface->unmap);
surface->unmap.notify = unmanaged_handle_unmap;
wl_signal_add(&xsurface->events.destroy, &surface->destroy);
surface->destroy.notify = unmanaged_handle_destroy;
return surface;
}
static struct sway_xwayland_view *xwayland_view_from_view(
struct sway_view *view) {
if (!sway_assert(view->type == SWAY_VIEW_XWAYLAND,
"Expected xwayland view")) {
return NULL;
}
return (struct sway_xwayland_view *)view;
}
7 years ago
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) {
if (xwayland_view_from_view(view) == NULL) {
7 years ago
return NULL;
}
switch (prop) {
case VIEW_PROP_TITLE:
return view->wlr_xwayland_surface->title;
case VIEW_PROP_CLASS:
return view->wlr_xwayland_surface->class;
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
case VIEW_PROP_INSTANCE:
return view->wlr_xwayland_surface->instance;
7 years ago
default:
return NULL;
}
}
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
if (xwayland_view_from_view(view) == NULL) {
return 0;
}
switch (prop) {
case VIEW_PROP_X11_WINDOW_ID:
return view->wlr_xwayland_surface->window_id;
case VIEW_PROP_WINDOW_TYPE:
return *view->wlr_xwayland_surface->window_type;
default:
return 0;
}
}
static void configure(struct sway_view *view, double ox, double oy, int width,
int height) {
struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
if (xwayland_view == NULL) {
7 years ago
return;
}
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
if (!sway_assert(output, "view must be within tree to set position")) {
return;
}
struct sway_container *root = container_parent(output, C_ROOT);
if (!sway_assert(root, "output must be within tree to set position")) {
return;
}
struct wlr_output_layout *layout = root->sway_root->output_layout;
struct wlr_output_layout_output *loutput =
wlr_output_layout_get(layout, output->sway_output->wlr_output);
if (!sway_assert(loutput, "output must be within layout to set position")) {
return;
}
xwayland_view->pending_width = width;
xwayland_view->pending_height = height;
wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y,
width, height);
}
7 years ago
static void set_activated(struct sway_view *view, bool activated) {
if (xwayland_view_from_view(view) == NULL) {
7 years ago
return;
}
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
wlr_xwayland_surface_activate(surface, activated);
}
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xwayland_view_from_view(view) == NULL) {
return;
}
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
wlr_xwayland_surface_set_fullscreen(surface, fullscreen);
}
static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) {
7 years ago
return;
}
wlr_xwayland_surface_close(view->wlr_xwayland_surface);
}
static void destroy(struct sway_view *view) {
struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view);
if (xwayland_view == NULL) {
return;
}
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link);
wl_list_remove(&xwayland_view->request_fullscreen.link);
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
wl_list_remove(&xwayland_view->set_title.link);
wl_list_remove(&xwayland_view->set_class.link);
wl_list_remove(&xwayland_view->set_window_type.link);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
free(xwayland_view);
}
static const struct sway_view_impl view_impl = {
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
.get_string_prop = get_string_prop,
.get_int_prop = get_int_prop,
.configure = configure,
.set_activated = set_activated,
.set_fullscreen = set_fullscreen,
.close = _close,
.destroy = destroy,
};
7 years ago
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, commit);
struct sway_view *view = &xwayland_view->view;
7 years ago
// NOTE: We intentionally discard the view's desired width here
// TODO: Let floating views do whatever
view_update_size(view, xwayland_view->pending_width,
xwayland_view->pending_height);
view_damage_from(view);
7 years ago
}
static void handle_unmap(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, unmap);
wl_list_remove(&xwayland_view->commit.link);
view_unmap(&xwayland_view->view);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, map);
struct wlr_xwayland_surface *xsurface = data;
struct sway_view *view = &xwayland_view->view;
// Wire up the commit listener here, because xwayland map/unmap can change
// the underlying wlr_surface
wl_signal_add(&xsurface->surface->events.commit, &xwayland_view->commit);
xwayland_view->commit.notify = handle_commit;
// Put it back into the tree
wlr_xwayland_surface_set_maximized(xsurface, true);
view_map(view, xsurface->surface);
if (xsurface->fullscreen) {
view_set_fullscreen(view, true);
}
7 years ago
}
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, destroy);
view_destroy(&xwayland_view->view);
}
static void handle_request_configure(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, request_configure);
7 years ago
struct wlr_xwayland_surface_configure_event *ev = data;
struct sway_view *view = &xwayland_view->view;
7 years ago
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
wlr_xwayland_surface_configure(xsurface, ev->x, ev->y,
ev->width, ev->height);
return;
}
// TODO: Let floating views do whatever
configure(view, view->swayc->x, view->swayc->y, view->width, view->height);
7 years ago
}
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, request_fullscreen);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
return;
}
view_set_fullscreen(view, xsurface->fullscreen);
}
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
static void handle_set_title(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_title);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
return;
}
view_update_title(view, false);
view_execute_criteria(view);
}
static void handle_set_class(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_class);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
return;
}
view_execute_criteria(view);
}
static void handle_set_window_type(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_window_type);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
return;
}
view_execute_criteria(view);
}
7 years ago
void handle_xwayland_surface(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server,
xwayland_surface);
7 years ago
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);
7 years ago
struct sway_xwayland_view *xwayland_view =
calloc(1, sizeof(struct sway_xwayland_view));
if (!sway_assert(xwayland_view, "Failed to allocate view")) {
7 years ago
return;
}
view_init(&xwayland_view->view, SWAY_VIEW_XWAYLAND, &view_impl);
xwayland_view->view.wlr_xwayland_surface = xsurface;
7 years ago
// TODO:
// - Look up pid and open on appropriate workspace
wl_signal_add(&xsurface->events.destroy, &xwayland_view->destroy);
xwayland_view->destroy.notify = handle_destroy;
7 years ago
wl_signal_add(&xsurface->events.request_configure,
&xwayland_view->request_configure);
xwayland_view->request_configure.notify = handle_request_configure;
wl_signal_add(&xsurface->events.request_fullscreen,
&xwayland_view->request_fullscreen);
xwayland_view->request_fullscreen.notify = handle_request_fullscreen;
Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace <name>' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace
7 years ago
wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title);
xwayland_view->set_title.notify = handle_set_title;
wl_signal_add(&xsurface->events.set_class, &xwayland_view->set_class);
xwayland_view->set_class.notify = handle_set_class;
wl_signal_add(&xsurface->events.set_window_type,
&xwayland_view->set_window_type);
xwayland_view->set_window_type.notify = handle_set_window_type;
wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
xwayland_view->unmap.notify = handle_unmap;
wl_signal_add(&xsurface->events.map, &xwayland_view->map);
xwayland_view->map.notify = handle_map;
7 years ago
}