xdg-shell: Implement xdg-shell interface.

The whole xdg-shell interface is implement, except from the "focused_set"
and "focused_unset" events.
This commit is contained in:
Rafael Antognolli 2013-12-03 15:35:45 -02:00 committed by Kristian Høgsberg
parent 4b99a40bcb
commit e2a3455642
3 changed files with 508 additions and 15 deletions

2
src/.gitignore vendored
View file

@ -19,3 +19,5 @@ workspaces-protocol.c
workspaces-server-protocol.h
input-method-protocol.c
input-method-server-protocol.h
xdg-shell-protocol.c
xdg-shell-server-protocol.h

View file

@ -294,7 +294,9 @@ desktop_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
desktop_shell_la_SOURCES = \
shell.c \
desktop-shell-protocol.c \
desktop-shell-server-protocol.h
desktop-shell-server-protocol.h \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h
endif
if ENABLE_TABLET_SHELL
@ -355,6 +357,8 @@ BUILT_SOURCES = \
input-method-server-protocol.h \
workspaces-server-protocol.h \
workspaces-protocol.c \
xdg-shell-protocol.c \
xdg-shell-server-protocol.h \
git-version.h
CLEANFILES = $(BUILT_SOURCES)

View file

@ -40,6 +40,7 @@
#include "input-method-server-protocol.h"
#include "workspaces-server-protocol.h"
#include "../shared/config-parser.h"
#include "xdg-shell-server-protocol.h"
#define DEFAULT_NUM_WORKSPACES 1
#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
@ -417,6 +418,19 @@ get_shell_seat(struct weston_seat *seat);
static void
shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
static bool
shell_surface_is_wl_shell_surface(struct shell_surface *shsurf);
static bool
shell_surface_is_xdg_surface(struct shell_surface *shsurf);
static bool
shell_surface_is_xdg_popup(struct shell_surface *shsurf);
static void
shell_surface_set_parent(struct shell_surface *shsurf,
struct weston_surface *parent);
static bool
shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
{
@ -1622,8 +1636,8 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
}
static void
shell_surface_move(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial)
common_surface_move(struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial)
{
struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
@ -1645,6 +1659,13 @@ shell_surface_move(struct wl_client *client, struct wl_resource *resource,
}
}
static void
shell_surface_move(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial)
{
common_surface_move(resource, seat_resource, serial);
}
struct weston_resize_grab {
struct shell_grab base;
uint32_t edges;
@ -1799,9 +1820,9 @@ surface_resize(struct shell_surface *shsurf,
}
static void
shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial,
uint32_t edges)
common_surface_resize(struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial,
uint32_t edges)
{
struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
@ -1820,6 +1841,14 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
wl_resource_post_no_memory(resource);
}
static void
shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial,
uint32_t edges)
{
common_surface_resize(resource, seat_resource, serial, edges);
}
static void
end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer);
@ -1960,7 +1989,12 @@ ping_handler(struct weston_surface *surface, uint32_t serial)
wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
wl_shell_surface_send_ping(shsurf->resource, serial);
if (shell_surface_is_wl_shell_surface(shsurf))
wl_shell_surface_send_ping(shsurf->resource, serial);
else if (shell_surface_is_xdg_surface(shsurf))
xdg_surface_send_ping(shsurf->resource, serial);
else if (shell_surface_is_xdg_popup(shsurf))
xdg_popup_send_ping(shsurf->resource, serial);
}
}
@ -2001,12 +2035,22 @@ create_pointer_focus_listener(struct weston_seat *seat)
}
static void
shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
uint32_t serial)
xdg_surface_set_transient_for(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *parent_resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
struct weston_seat *seat;
struct weston_surface *parent =
wl_resource_get_user_data(parent_resource);
shell_surface_set_parent(shsurf, parent);
}
static void
surface_pong(struct shell_surface *shsurf, uint32_t serial)
{
struct weston_compositor *ec = shsurf->surface->compositor;
struct weston_seat *seat;
if (shsurf->ping_timer == NULL)
/* Just ignore unsolicited pong. */
@ -2022,6 +2066,16 @@ shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
}
}
static void
shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
uint32_t serial)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
surface_pong(shsurf, serial);
}
static void
set_title(struct shell_surface *shsurf, const char *title)
{
@ -2866,6 +2920,16 @@ static const struct weston_pointer_grab_interface popup_grab_interface = {
popup_grab_cancel,
};
static void
shell_surface_send_popup_done(struct shell_surface *shsurf)
{
if (shell_surface_is_wl_shell_surface(shsurf))
wl_shell_surface_send_popup_done(shsurf->resource);
else if (shell_surface_is_xdg_popup(shsurf))
xdg_popup_send_popup_done(shsurf->resource,
shsurf->popup.serial);
}
static void
popup_grab_end(struct weston_pointer *pointer)
{
@ -2882,7 +2946,7 @@ popup_grab_end(struct weston_pointer *pointer)
assert(!wl_list_empty(&shseat->popup_grab.surfaces_list));
/* Send the popup_done event to all the popups open */
wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) {
wl_shell_surface_send_popup_done(shsurf->resource);
shell_surface_send_popup_done(shsurf);
shsurf->popup.shseat = NULL;
if (prev) {
wl_list_init(&prev->popup.grab_link);
@ -2944,7 +3008,7 @@ shell_map_popup(struct shell_surface *shsurf)
if (shseat->seat->pointer->grab_serial == shsurf->popup.serial) {
add_popup_grab(shsurf, shseat);
} else {
wl_shell_surface_send_popup_done(shsurf->resource);
shell_surface_send_popup_done(shsurf);
shseat->popup_grab.client = NULL;
}
}
@ -3027,9 +3091,9 @@ get_shell_surface(struct weston_surface *surface)
return NULL;
}
static struct shell_surface *
create_shell_surface(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client)
static struct shell_surface *
create_common_surface(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
@ -3092,6 +3156,19 @@ create_shell_surface(void *shell, struct weston_surface *surface,
return shsurf;
}
static struct shell_surface *
create_shell_surface(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
shsurf = create_common_surface(shell, surface, client);
shsurf->type = SHELL_SURFACE_NONE;
shsurf->next_type = SHELL_SURFACE_NONE;
return shsurf;
}
static struct weston_view *
get_primary_view(void *shell, struct shell_surface *shsurf)
{
@ -3132,10 +3209,403 @@ shell_get_shell_surface(struct wl_client *client,
shsurf, shell_destroy_shell_surface);
}
static bool
shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
{
return wl_resource_instance_of(shsurf->resource,
&wl_shell_surface_interface,
&shell_surface_implementation);
}
static const struct wl_shell_interface shell_implementation = {
shell_get_shell_surface
};
/****************************
* xdg-shell implementation */
static void
xdg_surface_destroy(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
xdg_surface_pong(struct wl_client *client,
struct wl_resource *resource,
uint32_t serial)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
surface_pong(shsurf, serial);
}
static void
xdg_surface_set_app_id(struct wl_client *client,
struct wl_resource *resource,
const char *app_id)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
free(shsurf->class);
shsurf->class = strdup(app_id);
}
static void
xdg_surface_set_title(struct wl_client *client,
struct wl_resource *resource, const char *title)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
set_title(shsurf, title);
}
static void
xdg_surface_move(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial)
{
common_surface_move(resource, seat_resource, serial);
}
static void
xdg_surface_resize(struct wl_client *client, struct wl_resource *resource,
struct wl_resource *seat_resource, uint32_t serial,
uint32_t edges)
{
common_surface_resize(resource, seat_resource, serial, edges);
}
static void
xdg_surface_set_output(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
struct weston_output *output;
if (output_resource)
output = wl_resource_get_user_data(output_resource);
else
output = NULL;
if (!weston_surface_is_mapped(shsurf->surface))
shsurf->output = output;
}
static void
xdg_surface_set_fullscreen(struct wl_client *client,
struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
if (!shsurf->next_state.fullscreen) {
shsurf->next_state.fullscreen = true;
shsurf->state_changed = true;
set_fullscreen(shsurf,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, shsurf->output);
}
}
static void
xdg_surface_unset_fullscreen(struct wl_client *client,
struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
shsurf->next_state.fullscreen = false;
shsurf->state_changed = true;
}
static void
xdg_surface_set_maximized(struct wl_client *client,
struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
if (!shsurf->next_state.maximized) {
shsurf->next_state.maximized = true;
shsurf->state_changed = true;
set_maximized(shsurf, shsurf->output);
}
}
static void
xdg_surface_unset_maximized(struct wl_client *client,
struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
shsurf->next_state.maximized = false;
shsurf->state_changed = true;
}
static const struct xdg_surface_interface xdg_surface_implementation = {
xdg_surface_destroy,
xdg_surface_set_transient_for,
xdg_surface_set_title,
xdg_surface_set_app_id,
xdg_surface_pong,
xdg_surface_move,
xdg_surface_resize,
xdg_surface_set_output,
xdg_surface_set_fullscreen,
xdg_surface_unset_fullscreen,
xdg_surface_set_maximized,
xdg_surface_unset_maximized,
NULL /* set_minimized */
};
static void
xdg_send_configure(struct weston_surface *surface,
uint32_t edges, int32_t width, int32_t height)
{
struct shell_surface *shsurf = get_shell_surface(surface);
xdg_surface_send_configure(shsurf->resource, edges, width, height);
}
static const struct weston_shell_client xdg_client = {
xdg_send_configure
};
static void
xdg_use_unstable_version(struct wl_client *client,
struct wl_resource *resource,
int32_t version)
{
if (version > 1) {
wl_resource_post_error(resource,
1,
"xdg-shell:: version not implemented yet.");
return;
}
}
static struct shell_surface *
create_xdg_surface(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
shsurf = create_common_surface(shell, surface, client);
shsurf->type = SHELL_SURFACE_NONE;
shsurf->next_type = SHELL_SURFACE_TOPLEVEL;
return shsurf;
}
static void
xdg_get_xdg_surface(struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource)
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct shell_surface *shsurf;
if (get_shell_surface(surface)) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"desktop_shell::get_shell_surface already requested");
return;
}
shsurf = create_xdg_surface(shell, surface, &xdg_client);
if (!shsurf) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"surface->configure already set");
return;
}
shsurf->resource =
wl_resource_create(client,
&xdg_surface_interface, 1, id);
wl_resource_set_implementation(shsurf->resource,
&xdg_surface_implementation,
shsurf, shell_destroy_shell_surface);
}
static bool
shell_surface_is_xdg_surface(struct shell_surface *shsurf)
{
return wl_resource_instance_of(shsurf->resource,
&xdg_surface_interface,
&xdg_surface_implementation);
}
/* xdg-popup implementation */
static void
xdg_popup_destroy(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
xdg_popup_pong(struct wl_client *client,
struct wl_resource *resource,
uint32_t serial)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
surface_pong(shsurf, serial);
}
static const struct xdg_popup_interface xdg_popup_implementation = {
xdg_popup_destroy,
xdg_popup_pong
};
static void
xdg_popup_send_configure(struct weston_surface *surface,
uint32_t edges, int32_t width, int32_t height)
{
}
static const struct weston_shell_client xdg_popup_client = {
xdg_popup_send_configure
};
static struct shell_surface *
create_xdg_popup(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client,
struct weston_surface *parent,
struct shell_seat *seat,
uint32_t serial,
int32_t x, int32_t y)
{
struct shell_surface *shsurf;
shsurf = create_common_surface(shell, surface, client);
shsurf->type = SHELL_SURFACE_NONE;
shsurf->next_type = SHELL_SURFACE_POPUP;
shsurf->popup.shseat = seat;
shsurf->popup.serial = serial;
shsurf->popup.x = x;
shsurf->popup.y = y;
shell_surface_set_parent(shsurf, parent);
return shsurf;
}
static void
xdg_get_xdg_popup(struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource,
struct wl_resource *parent_resource,
struct wl_resource *seat_resource,
uint32_t serial,
int32_t x, int32_t y, uint32_t flags)
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct shell_surface *shsurf;
struct weston_surface *parent;
struct shell_seat *seat;
if (get_shell_surface(surface)) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"desktop_shell::get_shell_surface already requested");
return;
}
if (!parent_resource) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"xdg_shell::get_xdg_popup requires a parent shell surface");
}
parent = wl_resource_get_user_data(parent_resource);
seat = get_shell_seat(wl_resource_get_user_data(seat_resource));;
shsurf = create_xdg_popup(shell, surface, &xdg_popup_client,
parent, seat, serial, x, y);
if (!shsurf) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"surface->configure already set");
return;
}
shsurf->resource =
wl_resource_create(client,
&xdg_popup_interface, 1, id);
wl_resource_set_implementation(shsurf->resource,
&xdg_popup_implementation,
shsurf, shell_destroy_shell_surface);
}
static bool
shell_surface_is_xdg_popup(struct shell_surface *shsurf)
{
return wl_resource_instance_of(shsurf->resource,
&xdg_popup_interface,
&xdg_popup_implementation);
}
static const struct xdg_shell_interface xdg_implementation = {
xdg_use_unstable_version,
xdg_get_xdg_surface,
xdg_get_xdg_popup
};
static int
xdg_shell_unversioned_dispatch(const void *implementation,
void *_target, uint32_t opcode,
const struct wl_message *message,
union wl_argument *args)
{
struct wl_resource *resource = _target;
struct desktop_shell *shell = wl_resource_get_user_data(resource);
if (opcode != 0) {
wl_resource_post_error(resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"must call use_unstable_version first");
return 0;
}
#define XDG_SERVER_VERSION 1
if (args[0].i != XDG_SERVER_VERSION) {
wl_resource_post_error(resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"incompatible version, server is %d "
"client wants %d",
XDG_SERVER_VERSION, args[0].i);
return 0;
}
wl_resource_set_implementation(resource, &xdg_implementation,
shell, NULL);
return 1;
}
/* end of xdg-shell implementation */
/***********************************/
static void
shell_fade(struct desktop_shell *shell, enum fade_type type);
@ -4718,6 +5188,19 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
shell, NULL);
}
static void
bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct desktop_shell *shell = data;
struct wl_resource *resource;
resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
if (resource)
wl_resource_set_dispatcher(resource,
xdg_shell_unversioned_dispatch,
NULL, shell, NULL);
}
static void
unbind_desktop_shell(struct wl_resource *resource)
{
@ -6293,6 +6776,10 @@ module_init(struct weston_compositor *ec,
shell, bind_shell) == NULL)
return -1;
if (wl_global_create(ec->wl_display, &xdg_shell_interface, 1,
shell, bind_xdg_shell) == NULL)
return -1;
if (wl_global_create(ec->wl_display,
&desktop_shell_interface, 2,
shell, bind_desktop_shell) == NULL)