Merge branch 'master' into feature/xwm-rewrite

This commit is contained in:
Tony Crisci 2017-10-27 15:22:00 -04:00
commit c555a66dda
23 changed files with 622 additions and 74 deletions

View file

@ -76,7 +76,7 @@ static void session_signal(struct wl_listener *listener, void *data) {
struct wlr_drm_plane *plane = conn->crtc->cursor;
drm->iface->crtc_set_cursor(drm, conn->crtc,
plane ? plane->cursor_bo : NULL);
(plane && plane->cursor_enabled) ? plane->cursor_bo : NULL);
}
} else {
wlr_log(L_INFO, "DRM fd paused");

View file

@ -505,8 +505,10 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
if (!buf && update_pixels) {
// Hide the cursor
plane->cursor_enabled = false;
return drm->iface->crtc_set_cursor(drm, crtc, NULL);
}
plane->cursor_enabled = true;
// We don't have a real cursor plane, so we make a fake one
if (!plane) {

View file

@ -33,6 +33,7 @@ struct wlr_drm_plane {
float matrix[16];
struct wlr_texture *wlr_tex;
struct gbm_bo *cursor_bo;
bool cursor_enabled;
union wlr_drm_plane_props props;
};

View file

@ -26,6 +26,17 @@ struct binding_config {
struct wl_list link;
};
struct keyboard_config {
char *name;
uint32_t meta_key;
char *rules;
char *model;
char *layout;
char *variant;
char *options;
struct wl_list link;
};
struct roots_config {
bool xwayland;
// TODO: Multiple cursors, multiseat
@ -34,13 +45,10 @@ struct roots_config {
struct wlr_box *mapped_box;
} cursor;
struct {
uint32_t meta_key;
} keyboard;
struct wl_list outputs;
struct wl_list devices;
struct wl_list bindings;
struct wl_list keyboards;
char *config_path;
char *startup_cmd;
};
@ -54,13 +62,20 @@ void roots_config_destroy(struct roots_config *config);
* NULL.
*/
struct output_config *config_get_output(struct roots_config *config,
struct wlr_output *output);
struct wlr_output *output);
/**
* Get configuration for the device. If the device is not configured, returns
* NULL.
*/
struct device_config *config_get_device(struct roots_config *config,
struct wlr_input_device *device);
struct wlr_input_device *device);
/**
* Get configuration for the keyboard. If the keyboard is not configured,
* returns NULL. A NULL device returns the default config for keyboards.
*/
struct keyboard_config *config_get_keyboard(struct roots_config *config,
struct wlr_input_device *device);
#endif

View file

@ -37,11 +37,13 @@ struct roots_desktop {
struct wlr_xdg_shell_v6 *xdg_shell_v6;
struct wlr_gamma_control_manager *gamma_control_manager;
struct wlr_screenshooter *screenshooter;
struct wlr_server_decoration_manager *server_decoration_manager;
struct wl_listener output_add;
struct wl_listener output_remove;
struct wl_listener xdg_shell_v6_surface;
struct wl_listener wl_shell_surface;
struct wl_listener decoration_new;
#ifdef HAS_XWAYLAND
struct wlr_xwayland *xwayland;

View file

@ -88,14 +88,13 @@ struct roots_input {
// TODO: multiseat, multicursor
struct wlr_cursor *cursor;
struct wlr_xcursor_theme *theme;
struct wlr_xcursor *xcursor;
struct wlr_xcursor_theme *xcursor_theme;
struct wlr_seat *wl_seat;
struct wl_list drag_icons;
struct wl_client *cursor_client;
enum roots_cursor_mode mode;
struct roots_view *active_view, *last_active_view;
struct roots_view *active_view;
int offs_x, offs_y;
int view_x, view_y, view_width, view_height;
float view_rotation;
@ -158,6 +157,12 @@ void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor,
void view_begin_resize(struct roots_input *input, struct wlr_cursor *cursor,
struct roots_view *view, uint32_t edges);
struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme);
struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme);
struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme,
uint32_t edges);
struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme);
void set_view_focus(struct roots_input *input, struct roots_desktop *desktop,
struct roots_view *view);

View file

@ -84,6 +84,7 @@ void view_resize(struct roots_view *view, uint32_t width, uint32_t height);
void view_set_position(struct roots_view *view, double x, double y);
void view_close(struct roots_view *view);
bool view_center(struct roots_view *view);
void view_initialize(struct roots_view *view);
void view_setup(struct roots_view *view);
void view_teardown(struct roots_view *view);
#endif

View file

@ -0,0 +1,44 @@
#ifndef WLR_TYPES_WLR_SERVER_DECORATION_H
#define WLR_TYPES_WLR_SERVER_DECORATION_H
#include <wayland-server.h>
struct wlr_server_decoration_manager {
struct wl_global *wl_global;
struct wl_list wl_resources;
struct wl_list decorations; // wlr_server_decoration::link
uint32_t default_mode; // enum org_kde_kwin_server_decoration_manager_mode
struct {
struct wl_signal new_decoration;
} events;
void *data;
};
struct wlr_server_decoration {
struct wl_resource *resource;
struct wlr_surface *surface;
struct wl_list link;
uint32_t mode; // enum org_kde_kwin_server_decoration_manager_mode
struct {
struct wl_signal destroy;
struct wl_signal mode;
} events;
struct wl_listener surface_destroy_listener;
void *data;
};
struct wlr_server_decoration_manager *wlr_server_decoration_manager_create(
struct wl_display *display);
void wlr_server_decoration_manager_set_default_mode(
struct wlr_server_decoration_manager *manager, uint32_t default_mode);
void wlr_server_decoration_manager_destroy(
struct wlr_server_decoration_manager *manager);
#endif

View file

@ -24,12 +24,14 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
'gamma-control.xml',
'screenshooter.xml',
'server-decoration.xml',
]
client_protocols = [
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
'gamma-control.xml',
'screenshooter.xml',
'server-decoration.xml',
]
wl_protos_src = []

View file

@ -0,0 +1,94 @@
<?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>

View file

@ -147,8 +147,46 @@ void add_binding_config(struct wl_list *bindings, const char* combination,
}
}
static void config_handle_keyboard(struct roots_config *config,
const char *device_name, const char *name, const char *value) {
struct keyboard_config *kc;
bool found = false;
wl_list_for_each(kc, &config->keyboards, link) {
if (strcmp(kc->name, device_name) == 0) {
found = true;
break;
}
}
if (!found) {
kc = calloc(1, sizeof(struct keyboard_config));
kc->name = strdup(device_name);
wl_list_insert(&config->keyboards, &kc->link);
}
if (strcmp(name, "meta-key") == 0) {
kc->meta_key = parse_modifier(value);
if (kc->meta_key == 0) {
wlr_log(L_ERROR, "got unknown meta key: %s", name);
}
} else if (strcmp(name, "rules") == 0) {
kc->rules = strdup(value);
} else if (strcmp(name, "model") == 0) {
kc->model = strdup(value);
} else if (strcmp(name, "layout") == 0) {
kc->layout = strdup(value);
} else if (strcmp(name, "variant") == 0) {
kc->variant = strdup(value);
} else if (strcmp(name, "options") == 0) {
kc->options = strdup(value);
} else {
wlr_log(L_ERROR, "got unknown keyboard config: %s", name);
}
}
static const char *output_prefix = "output:";
static const char *device_prefix = "device:";
static const char *keyboard_prefix = "keyboard:";
static int config_ini_handler(void *user, const char *section, const char *name,
const char *value) {
@ -219,9 +257,9 @@ static int config_ini_handler(void *user, const char *section, const char *name,
}
} else if (strncmp(device_prefix, section, strlen(device_prefix)) == 0) {
const char *device_name = section + strlen(device_prefix);
struct device_config *dc;
bool found = false;
wl_list_for_each(dc, &config->devices, link) {
if (strcmp(dc->name, device_name) == 0) {
found = true;
@ -245,14 +283,10 @@ static int config_ini_handler(void *user, const char *section, const char *name,
wlr_log(L_ERROR, "got unknown device config: %s", name);
}
} else if (strcmp(section, "keyboard") == 0) {
if (strcmp(name, "meta-key") == 0) {
config->keyboard.meta_key = parse_modifier(value);
if (config->keyboard.meta_key == 0) {
wlr_log(L_ERROR, "got unknown meta key: %s", name);
}
} else {
wlr_log(L_ERROR, "got unknown keyboard config: %s", name);
}
config_handle_keyboard(config, "", name, value);
} else if (strncmp(keyboard_prefix, section, strlen(keyboard_prefix)) == 0) {
const char *device_name = section + strlen(keyboard_prefix);
config_handle_keyboard(config, device_name, name, value);
} else if (strcmp(section, "bindings") == 0) {
add_binding_config(&config->bindings, name, value);
} else {
@ -271,6 +305,7 @@ struct roots_config *parse_args(int argc, char *argv[]) {
config->xwayland = true;
wl_list_init(&config->outputs);
wl_list_init(&config->devices);
wl_list_init(&config->keyboards);
wl_list_init(&config->bindings);
int c;
@ -305,10 +340,12 @@ struct roots_config *parse_args(int argc, char *argv[]) {
if (result == -1) {
wlr_log(L_DEBUG, "No config file found. Using sensible defaults.");
config->keyboard.meta_key = WLR_MODIFIER_LOGO;
add_binding_config(&config->bindings, "Logo+Shift+E", "exit");
add_binding_config(&config->bindings, "Ctrl+q", "close");
add_binding_config(&config->bindings, "Alt+Tab", "next_window");
struct keyboard_config *kc = calloc(1, sizeof(struct keyboard_config));
kc->meta_key = WLR_MODIFIER_LOGO;
wl_list_insert(&config->keyboards, &kc->link);
} else if (result == -2) {
wlr_log(L_ERROR, "Could not allocate memory to parse config file");
exit(1);
@ -335,6 +372,17 @@ void roots_config_destroy(struct roots_config *config) {
free(dc);
}
struct keyboard_config *kc, *ktmp = NULL;
wl_list_for_each_safe(kc, ktmp, &config->bindings, link) {
free(kc->name);
free(kc->rules);
free(kc->model);
free(kc->layout);
free(kc->variant);
free(kc->options);
free(kc);
}
struct binding_config *bc, *btmp = NULL;
wl_list_for_each_safe(bc, btmp, &config->bindings, link) {
free(bc->keysyms);
@ -371,3 +419,16 @@ struct device_config *config_get_device(struct roots_config *config,
return NULL;
}
struct keyboard_config *config_get_keyboard(struct roots_config *config,
struct wlr_input_device *device) {
struct keyboard_config *kc;
wl_list_for_each(kc, &config->keyboards, link) {
if ((device != NULL && strcmp(kc->name, device->name) == 0) ||
(device == NULL && strcmp(kc->name, "") == 0)) {
return kc;
}
}
return NULL;
}

View file

@ -31,6 +31,28 @@ const struct roots_input_event *get_input_event(struct roots_input *input,
return NULL;
}
static void cursor_set_xcursor_image(struct roots_input *input,
struct wlr_xcursor_image *image) {
struct roots_output *output;
wl_list_for_each(output, &input->server->desktop->outputs, link) {
if (!wlr_output_set_cursor(output->wlr_output, image->buffer,
image->width, image->width, image->height,
image->hotspot_x, image->hotspot_y)) {
wlr_log(L_DEBUG, "Failed to set hardware cursor");
return;
}
}
}
static void cursor_set_surface(struct roots_input *input,
struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y) {
struct roots_output *output;
wl_list_for_each(output, &input->server->desktop->outputs, link) {
wlr_output_set_cursor_surface(output->wlr_output, surface,
hotspot_x, hotspot_y);
}
}
void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor,
struct roots_view *view) {
input->mode = ROOTS_CURSOR_MOVE;
@ -39,6 +61,11 @@ void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor,
input->view_x = view->x;
input->view_y = view->y;
wlr_seat_pointer_clear_focus(input->wl_seat);
struct wlr_xcursor *xcursor = get_move_xcursor(input->xcursor_theme);
if (xcursor != NULL) {
cursor_set_xcursor_image(input, xcursor->images[0]);
}
}
void view_begin_resize(struct roots_input *input, struct wlr_cursor *cursor,
@ -54,6 +81,11 @@ void view_begin_resize(struct roots_input *input, struct wlr_cursor *cursor,
input->view_height = size.height;
input->resize_edges = edges;
wlr_seat_pointer_clear_focus(input->wl_seat);
struct wlr_xcursor *xcursor = get_resize_xcursor(input->xcursor_theme, edges);
if (xcursor != NULL) {
cursor_set_xcursor_image(input, xcursor->images[0]);
}
}
void view_begin_rotate(struct roots_input *input, struct wlr_cursor *cursor,
@ -63,18 +95,10 @@ void view_begin_rotate(struct roots_input *input, struct wlr_cursor *cursor,
input->offs_y = cursor->y;
input->view_rotation = view->rotation;
wlr_seat_pointer_clear_focus(input->wl_seat);
}
static void cursor_set_xcursor_image(struct roots_input *input,
struct wlr_xcursor_image *image) {
struct roots_output *output;
wl_list_for_each(output, &input->server->desktop->outputs, link) {
if (!wlr_output_set_cursor(output->wlr_output, image->buffer,
image->width, image->width, image->height,
image->hotspot_x, image->hotspot_y)) {
wlr_log(L_DEBUG, "Failed to set hardware cursor");
return;
}
struct wlr_xcursor *xcursor = get_rotate_xcursor(input->xcursor_theme);
if (xcursor != NULL) {
cursor_set_xcursor_image(input, xcursor->images[0]);
}
}
@ -94,8 +118,8 @@ void cursor_update_position(struct roots_input *input, uint32_t time) {
set_compositor_cursor = view_client != input->cursor_client;
}
if (set_compositor_cursor) {
wlr_log(L_DEBUG, "Switching to compositor cursor");
cursor_set_xcursor_image(input, input->xcursor->images[0]);
struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme);
cursor_set_xcursor_image(input, xcursor->images[0]);
input->cursor_client = NULL;
}
if (view) {
@ -172,11 +196,11 @@ void set_view_focus(struct roots_input *input, struct roots_desktop *desktop,
if (!view) {
return;
}
if (view->type == ROOTS_XWAYLAND_VIEW &&
view->xwayland_surface->override_redirect) {
return;
}
input->last_active_view = view;
size_t index = 0;
for (size_t i = 0; i < desktop->views->length; ++i) {
@ -220,8 +244,16 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) {
event->orientation, event->delta);
}
static bool is_meta_pressed(struct roots_input *input) {
uint32_t meta_key = input->server->config->keyboard.meta_key;
static bool is_meta_pressed(struct roots_input *input,
struct wlr_input_device *device) {
uint32_t meta_key = 0;
struct keyboard_config *config;
if ((config = config_get_keyboard(input->server->config, device))) {
meta_key = config->meta_key;
} else if (!meta_key && (config = config_get_keyboard(input->server->config,
NULL))) {
meta_key = config->meta_key;
}
if (meta_key == 0) {
return false;
}
@ -246,20 +278,31 @@ static void do_cursor_button_press(struct roots_input *input,
struct roots_view *view = view_at(desktop,
input->cursor->x, input->cursor->y, &surface, &sx, &sy);
if (state == WLR_BUTTON_PRESSED && view && is_meta_pressed(input)) {
if (state == WLR_BUTTON_PRESSED && view && is_meta_pressed(input, device)) {
set_view_focus(input, desktop, view);
uint32_t edges;
switch (button) {
case BTN_LEFT:
view_begin_move(input, cursor, view);
break;
case BTN_RIGHT:
view_begin_resize(input, cursor, view,
ROOTS_CURSOR_RESIZE_EDGE_RIGHT |
ROOTS_CURSOR_RESIZE_EDGE_BOTTOM);
edges = 0;
if (sx < view->wlr_surface->current->width/2) {
edges |= ROOTS_CURSOR_RESIZE_EDGE_LEFT;
} else {
edges |= ROOTS_CURSOR_RESIZE_EDGE_RIGHT;
}
if (sy < view->wlr_surface->current->height/2) {
edges |= ROOTS_CURSOR_RESIZE_EDGE_TOP;
} else {
edges |= ROOTS_CURSOR_RESIZE_EDGE_BOTTOM;
}
view_begin_resize(input, cursor, view, edges);
break;
case BTN_MIDDLE:
view_begin_rotate(input, cursor, view);
break;
}
return;
}
@ -271,6 +314,7 @@ static void do_cursor_button_press(struct roots_input *input,
switch (state) {
case WLR_BUTTON_RELEASED:
set_view_focus(input, desktop, NULL);
cursor_update_position(input, time);
break;
case WLR_BUTTON_PRESSED:
i = input->input_events_idx;
@ -431,19 +475,13 @@ static void handle_request_set_cursor(struct wl_listener *listener,
wl_resource_get_client(focused_surface->resource);
ok = event->client == focused_client;
}
if (!ok) {
if (!ok || input->mode != ROOTS_CURSOR_PASSTHROUGH) {
wlr_log(L_DEBUG, "Denying request to set cursor from unfocused client");
return;
}
wlr_log(L_DEBUG, "Setting client cursor");
struct roots_output *output;
wl_list_for_each(output, &input->server->desktop->outputs, link) {
wlr_output_set_cursor_surface(output->wlr_output, event->surface,
event->hotspot_x, event->hotspot_y);
}
cursor_set_surface(input, event->surface, event->hotspot_x, event->hotspot_y);
input->cursor_client = event->client;
}

View file

@ -7,11 +7,13 @@
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_wl_shell.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
#include <wlr/util/log.h>
#include "rootston/desktop.h"
#include <server-decoration-protocol.h>
#include "rootston/server.h"
#include "rootston/server.h"
void view_destroy(struct roots_view *view) {
@ -22,9 +24,6 @@ void view_destroy(struct roots_view *view) {
input->active_view = NULL;
input->mode = ROOTS_CURSOR_PASSTHROUGH;
}
if (input->last_active_view == view) {
input->last_active_view = NULL;
}
for (size_t i = 0; i < desktop->views->length; ++i) {
struct roots_view *_view = desktop->views->items[i];
@ -107,13 +106,25 @@ bool view_center(struct roots_view *view) {
return true;
}
void view_initialize(struct roots_view *view) {
void view_setup(struct roots_view *view) {
view_center(view);
struct roots_input *input = view->desktop->server->input;
struct roots_input *input = view->desktop->server->input;
set_view_focus(input, view->desktop, view);
}
void view_teardown(struct roots_view *view) {
struct wlr_list *views = view->desktop->views;
if (views->length < 2 || views->items[views->length-1] != view) {
return;
}
struct roots_view *prev_view = views->items[views->length-2];
struct roots_input *input = prev_view->desktop->server->input;
set_view_focus(input, prev_view->desktop, prev_view);
wlr_seat_keyboard_notify_enter(input->wl_seat, prev_view->wlr_surface);
}
struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
for (int i = desktop->views->length - 1; i >= 0; --i) {
@ -251,6 +262,11 @@ struct roots_desktop *desktop_create(struct roots_server *server,
server->wl_display);
desktop->screenshooter = wlr_screenshooter_create(server->wl_display,
server->renderer);
desktop->server_decoration_manager =
wlr_server_decoration_manager_create(server->wl_display);
wlr_server_decoration_manager_set_default_mode(
desktop->server_decoration_manager,
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
return desktop;
}

View file

@ -81,16 +81,17 @@ struct roots_input *input_create(struct roots_server *server,
input->config = config;
input->server = server;
input->theme = wlr_xcursor_theme_load("default", 16);
if (input->theme == NULL) {
input->xcursor_theme = wlr_xcursor_theme_load("default", 16);
if (input->xcursor_theme == NULL) {
wlr_log(L_ERROR, "Cannot load xcursor theme");
free(input);
return NULL;
}
input->xcursor = wlr_xcursor_theme_get_cursor(input->theme, "left_ptr");
if (input->xcursor == NULL) {
struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme);
if (xcursor == NULL) {
wlr_log(L_ERROR, "Cannot load xcursor from theme");
wlr_xcursor_theme_destroy(input->theme);
wlr_xcursor_theme_destroy(input->xcursor_theme);
free(input);
return NULL;
}
@ -98,7 +99,7 @@ struct roots_input *input_create(struct roots_server *server,
input->wl_seat = wlr_seat_create(server->wl_display, "seat0");
if (input->wl_seat == NULL) {
wlr_log(L_ERROR, "Cannot create seat");
wlr_xcursor_theme_destroy(input->theme);
wlr_xcursor_theme_destroy(input->xcursor_theme);
free(input);
return NULL;
}
@ -117,7 +118,7 @@ struct roots_input *input_create(struct roots_server *server,
input->cursor = wlr_cursor_create();
cursor_initialize(input);
wlr_cursor_set_xcursor(input->cursor, input->xcursor);
wlr_cursor_set_xcursor(input->cursor, xcursor);
wlr_cursor_attach_output_layout(input->cursor, server->desktop->layout);
wlr_cursor_map_to_region(input->cursor, config->cursor.mapped_box);

View file

@ -29,8 +29,10 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard,
if (strcmp(command, "exit") == 0) {
wl_display_terminate(server->wl_display);
} else if (strcmp(command, "close") == 0) {
if (keyboard->input->last_active_view != NULL) {
view_close(keyboard->input->last_active_view);
if (server->desktop->views->length > 0) {
struct roots_view *view =
server->desktop->views->items[server->desktop->views->length-1];
view_close(view);
}
} else if (strcmp(command, "next_window") == 0) {
if (server->desktop->views->length > 0) {
@ -123,6 +125,28 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {
}
}
static void keyboard_config_merge(struct keyboard_config *config,
struct keyboard_config *fallback) {
if (fallback == NULL) {
return;
}
if (config->rules == NULL) {
config->rules = fallback->rules;
}
if (config->model == NULL) {
config->model = fallback->model;
}
if (config->layout == NULL) {
config->layout = fallback->layout;
}
if (config->variant == NULL) {
config->variant = fallback->variant;
}
if (config->options == NULL) {
config->options = fallback->options;
}
}
void keyboard_add(struct wlr_input_device *device, struct roots_input *input) {
struct roots_keyboard *keyboard = calloc(sizeof(struct roots_keyboard), 1);
if (keyboard == NULL) {
@ -135,13 +159,27 @@ void keyboard_add(struct wlr_input_device *device, struct roots_input *input) {
wl_signal_add(&device->keyboard->events.key, &keyboard->key);
wl_list_insert(&input->keyboards, &keyboard->link);
struct keyboard_config config;
memset(&config, 0, sizeof(config));
keyboard_config_merge(&config, config_get_keyboard(input->config, device));
keyboard_config_merge(&config, config_get_keyboard(input->config, NULL));
struct keyboard_config env_config = {
.rules = getenv("XKB_DEFAULT_RULES"),
.model = getenv("XKB_DEFAULT_MODEL"),
.layout = getenv("XKB_DEFAULT_LAYOUT"),
.variant = getenv("XKB_DEFAULT_VARIANT"),
.options = getenv("XKB_DEFAULT_OPTIONS"),
};
keyboard_config_merge(&config, &env_config);
struct xkb_rule_names rules;
memset(&rules, 0, sizeof(rules));
rules.rules = getenv("XKB_DEFAULT_RULES");
rules.model = getenv("XKB_DEFAULT_MODEL");
rules.layout = getenv("XKB_DEFAULT_LAYOUT");
rules.variant = getenv("XKB_DEFAULT_VARIANT");
rules.options = getenv("XKB_DEFAULT_OPTIONS");
rules.rules = config.rules;
rules.model = config.model;
rules.layout = config.layout;
rules.variant = config.variant;
rules.options = config.options;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (context == NULL) {
wlr_log(L_ERROR, "Cannot create XKB context");

View file

@ -10,6 +10,7 @@ sources = [
'pointer.c',
'tablet_tool.c',
'touch.c',
'xcursor.c',
'xdg_shell_v6.c',
'wl_shell.c',
]
@ -17,5 +18,5 @@ if get_option('enable_xwayland')
sources += ['xwayland.c']
endif
executable(
'rootston', sources, dependencies: wlroots
'rootston', sources, dependencies: [wlroots, wlr_protos]
)

View file

@ -200,7 +200,8 @@ void output_add_notify(struct wl_listener *listener, void *data) {
cursor_load_config(config, input->cursor, input, desktop);
struct wlr_xcursor_image *image = input->xcursor->images[0];
struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme);
struct wlr_xcursor_image *image = xcursor->images[0];
// TODO the cursor must be set depending on which surface it is displayed
// over which should happen in the compositor.
if (!wlr_output_set_cursor(wlr_output, image->buffer,

View file

@ -56,6 +56,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct roots_wl_shell_surface *roots_surface =
wl_container_of(listener, roots_surface, destroy);
view_teardown(roots_surface->view);
wl_list_remove(&roots_surface->destroy.link);
wl_list_remove(&roots_surface->request_move.link);
wl_list_remove(&roots_surface->request_resize.link);
@ -111,7 +112,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
view->desktop = desktop;
roots_surface->view = view;
wlr_list_add(desktop->views, view);
view_initialize(view);
view_setup(view);
if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) {
// we need to map it relative to the parent

42
rootston/xcursor.c Normal file
View file

@ -0,0 +1,42 @@
#include <wlr/types/wlr_cursor.h>
#include "rootston/input.h"
struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme) {
return wlr_xcursor_theme_get_cursor(theme, "left_ptr");
}
struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme) {
return wlr_xcursor_theme_get_cursor(theme, "grabbing");
}
static const char *get_resize_xcursor_name(uint32_t edges) {
if (edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) {
if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
return "ne-resize";
} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
return "nw-resize";
}
return "n-resize";
} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) {
if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
return "se-resize";
} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
return "sw-resize";
}
return "s-resize";
} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) {
return "e-resize";
} else if (edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) {
return "w-resize";
}
return "se-resize"; // fallback
}
struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme,
uint32_t edges) {
return wlr_xcursor_theme_get_cursor(theme, get_resize_xcursor_name(edges));
}
struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme) {
return wlr_xcursor_theme_get_cursor(theme, "grabbing");
}

View file

@ -74,6 +74,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct roots_xdg_surface_v6 *roots_xdg_surface =
wl_container_of(listener, roots_xdg_surface, destroy);
view_teardown(roots_xdg_surface->view);
wl_list_remove(&roots_xdg_surface->commit.link);
wl_list_remove(&roots_xdg_surface->destroy.link);
wl_list_remove(&roots_xdg_surface->request_move.link);
@ -126,5 +127,5 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
roots_surface->view = view;
wlr_list_add(desktop->views, view);
view_initialize(view);
view_setup(view);
}

View file

@ -39,6 +39,7 @@ static void close(struct roots_view *view) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct roots_xwayland_surface *roots_surface =
wl_container_of(listener, roots_surface, destroy);
view_teardown(roots_surface->view);
wl_list_remove(&roots_surface->destroy.link);
wl_list_remove(&roots_surface->map_notify.link);
wl_list_remove(&roots_surface->unmap_notify.link);
@ -191,6 +192,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
wlr_list_add(desktop->views, view);
if (!surface->override_redirect) {
view_initialize(view);
view_setup(view);
}
}

View file

@ -15,6 +15,7 @@ lib_wlr_types = static_library(
'wlr_region.c',
'wlr_screenshooter.c',
'wlr_seat.c',
'wlr_server_decoration.c',
'wlr_surface.c',
'wlr_tablet_pad.c',
'wlr_tablet_tool.c',

View file

@ -0,0 +1,180 @@
#include <assert.h>
#include <stdlib.h>
#include <server-decoration-protocol.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/util/log.h>
static void server_decoration_handle_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void server_decoration_handle_request_mode(struct wl_client *client,
struct wl_resource *resource, uint32_t mode) {
struct wlr_server_decoration *decoration =
wl_resource_get_user_data(resource);
if (decoration->mode == mode) {
return;
}
decoration->mode = mode;
wl_signal_emit(&decoration->events.mode, decoration);
org_kde_kwin_server_decoration_send_mode(decoration->resource,
decoration->mode);
}
static void server_decoration_destroy(
struct wlr_server_decoration *decoration) {
wl_signal_emit(&decoration->events.destroy, decoration);
wl_list_remove(&decoration->surface_destroy_listener.link);
wl_resource_set_user_data(decoration->resource, NULL);
wl_list_remove(&decoration->link);
free(decoration);
}
static void server_decoration_destroy_resource(struct wl_resource *resource) {
struct wlr_server_decoration *decoration =
wl_resource_get_user_data(resource);
if (decoration != NULL) {
server_decoration_destroy(decoration);
}
}
static void server_decoration_handle_surface_destroy(
struct wl_listener *listener, void *data) {
struct wlr_server_decoration *decoration =
wl_container_of(listener, decoration, surface_destroy_listener);
server_decoration_destroy(decoration);
}
static const struct org_kde_kwin_server_decoration_interface
server_decoration_impl = {
.release = server_decoration_handle_release,
.request_mode = server_decoration_handle_request_mode,
};
static void server_decoration_manager_handle_create(struct wl_client *client,
struct wl_resource *manager_resource, uint32_t id,
struct wl_resource *surface_resource) {
struct wlr_server_decoration_manager *manager =
wl_resource_get_user_data(manager_resource);
struct wlr_surface *surface = wl_resource_get_user_data(surface_resource);
struct wlr_server_decoration *decoration =
calloc(1, sizeof(struct wlr_server_decoration));
if (decoration == NULL) {
wl_client_post_no_memory(client);
return;
}
decoration->surface = surface;
decoration->mode = manager->default_mode;
int version = wl_resource_get_version(manager_resource);
decoration->resource = wl_resource_create(client,
&org_kde_kwin_server_decoration_interface, version, id);
if (decoration->resource == NULL) {
wl_client_post_no_memory(client);
free(decoration);
return;
}
wl_resource_set_implementation(decoration->resource,
&server_decoration_impl, decoration,
server_decoration_destroy_resource);
wlr_log(L_DEBUG, "new server_decoration %p (res %p)", decoration,
decoration->resource);
wl_signal_init(&decoration->events.destroy);
wl_signal_init(&decoration->events.mode);
wl_signal_add(&surface->events.destroy,
&decoration->surface_destroy_listener);
decoration->surface_destroy_listener.notify =
server_decoration_handle_surface_destroy;
wl_list_insert(&manager->decorations, &decoration->link);
org_kde_kwin_server_decoration_send_mode(decoration->resource,
decoration->mode);
wl_signal_emit(&manager->events.new_decoration, decoration);
}
static const struct org_kde_kwin_server_decoration_manager_interface
server_decoration_manager_impl = {
.create = server_decoration_manager_handle_create,
};
void wlr_server_decoration_manager_set_default_mode(
struct wlr_server_decoration_manager *manager, uint32_t default_mode) {
manager->default_mode = default_mode;
struct wl_resource *resource;
wl_resource_for_each(resource, &manager->wl_resources) {
org_kde_kwin_server_decoration_manager_send_default_mode(resource,
manager->default_mode);
}
}
void server_decoration_manager_destroy_resource(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
}
static void server_decoration_manager_bind(struct wl_client *client,
void *_manager, uint32_t version, uint32_t id) {
struct wlr_server_decoration_manager *manager = _manager;
assert(client && manager);
struct wl_resource *resource = wl_resource_create(client,
&org_kde_kwin_server_decoration_manager_interface, version, id);
if (resource == NULL) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &server_decoration_manager_impl,
manager, server_decoration_manager_destroy_resource);
wl_list_insert(&manager->wl_resources, wl_resource_get_link(resource));
org_kde_kwin_server_decoration_manager_send_default_mode(resource,
manager->default_mode);
}
struct wlr_server_decoration_manager *wlr_server_decoration_manager_create(
struct wl_display *display) {
struct wlr_server_decoration_manager *manager =
calloc(1, sizeof(struct wlr_server_decoration_manager));
if (manager == NULL) {
return NULL;
}
manager->wl_global = wl_global_create(display,
&org_kde_kwin_server_decoration_manager_interface, 1, manager,
server_decoration_manager_bind);
if (manager->wl_global == NULL) {
free(manager);
return NULL;
}
manager->default_mode = ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
wl_list_init(&manager->wl_resources);
wl_list_init(&manager->decorations);
wl_signal_init(&manager->events.new_decoration);
return manager;
}
void wlr_server_decoration_manager_destroy(
struct wlr_server_decoration_manager *manager) {
if (manager == NULL) {
return;
}
struct wlr_server_decoration *decoration, *tmp_decoration;
wl_list_for_each_safe(decoration, tmp_decoration, &manager->decorations,
link) {
server_decoration_destroy(decoration);
}
struct wl_resource *resource, *tmp_resource;
wl_resource_for_each_safe(resource, tmp_resource, &manager->wl_resources) {
server_decoration_manager_destroy_resource(resource);
}
wl_global_destroy(manager->wl_global);
free(manager);
}