summaryrefslogtreecommitdiff
path: root/desktop-shell/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'desktop-shell/shell.c')
-rw-r--r--desktop-shell/shell.c505
1 files changed, 330 insertions, 175 deletions
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 466ea937..00922352 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -63,6 +63,8 @@ enum shell_surface_type {
SHELL_SURFACE_XWAYLAND
};
+struct shell_client;
+
/*
* Surface stacking and ordering.
*
@@ -104,6 +106,7 @@ enum shell_surface_type {
struct shell_surface {
struct wl_resource *resource;
struct wl_signal destroy_signal;
+ struct shell_client *owner;
struct weston_surface *surface;
struct weston_view *view;
@@ -163,10 +166,15 @@ struct shell_surface {
bool maximized;
bool fullscreen;
bool relative;
+ bool lowered;
} state, next_state, requested_state; /* surface states */
bool state_changed;
bool state_requested;
+ struct {
+ int left, right, top, bottom;
+ } margin;
+
int focus_count;
};
@@ -186,6 +194,7 @@ struct shell_touch_grab {
struct weston_move_grab {
struct shell_grab base;
wl_fixed_t dx, dy;
+ int client_initiated;
};
struct weston_touch_move_grab {
@@ -208,6 +217,10 @@ struct shell_seat {
struct wl_listener seat_destroy_listener;
struct weston_surface *focused_surface;
+ struct wl_listener caps_changed_listener;
+ struct wl_listener pointer_focus_listener;
+ struct wl_listener keyboard_focus_listener;
+
struct {
struct weston_pointer_grab grab;
struct wl_list surfaces_list;
@@ -226,16 +239,6 @@ struct shell_client {
int unresponsive;
};
-void
-set_alpha_if_fullscreen(struct shell_surface *shsurf)
-{
- if (shsurf && shsurf->state.fullscreen)
- shsurf->fullscreen.black_view->alpha = 0.25;
-}
-
-static struct shell_client *
-get_shell_client(struct wl_client *client);
-
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@@ -248,6 +251,10 @@ shell_fade_startup(struct desktop_shell *shell);
static struct shell_seat *
get_shell_seat(struct weston_seat *seat);
+static int
+get_output_panel_height(struct desktop_shell *shell,
+ struct weston_output *output);
+
static void
shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
@@ -364,6 +371,9 @@ shell_touch_grab_start(struct shell_touch_grab *grab,
{
struct desktop_shell *shell = shsurf->shell;
+ if (touch->seat->pointer)
+ popup_grab_end(touch->seat->pointer);
+
grab->grab.interface = interface;
grab->shsurf = shsurf;
grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
@@ -618,7 +628,7 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
shell = state->seat->compositor->shell_interface.shell;
if (next) {
state->keyboard_focus = NULL;
- activate(shell, next, state->seat);
+ activate(shell, next, state->seat, true);
} else {
if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
if (state->ws->focus_animation)
@@ -694,8 +704,20 @@ restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
{
struct focus_state *state, *next;
struct weston_surface *surface;
+ struct wl_list pending_seat_list;
+ struct weston_seat *seat, *next_seat;
+
+ /* Temporarily steal the list of seats so that we can keep
+ * track of the seats we've already processed */
+ wl_list_init(&pending_seat_list);
+ wl_list_insert_list(&pending_seat_list, &shell->compositor->seat_list);
+ wl_list_init(&shell->compositor->seat_list);
wl_list_for_each_safe(state, next, &ws->focus_list, link) {
+ wl_list_remove(&state->seat->link);
+ wl_list_insert(&shell->compositor->seat_list,
+ &state->seat->link);
+
if (state->seat->keyboard == NULL)
continue;
@@ -703,6 +725,17 @@ restore_focus_state(struct desktop_shell *shell, struct workspace *ws)
weston_keyboard_set_focus(state->seat->keyboard, surface);
}
+
+ /* For any remaining seats that we don't have a focus state
+ * for we'll reset the keyboard focus to NULL */
+ wl_list_for_each_safe(seat, next_seat, &pending_seat_list, link) {
+ wl_list_insert(&shell->compositor->seat_list, &seat->link);
+
+ if (state->seat->keyboard == NULL)
+ continue;
+
+ weston_keyboard_set_focus(seat->keyboard, NULL);
+ }
}
static void
@@ -1380,6 +1413,11 @@ touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
}
static void
+touch_move_grab_frame(struct weston_touch_grab *grab)
+{
+}
+
+static void
touch_move_grab_cancel(struct weston_touch_grab *grab)
{
struct weston_touch_move_grab *move =
@@ -1394,6 +1432,7 @@ static const struct weston_touch_grab_interface touch_move_grab_interface = {
touch_move_grab_down,
touch_move_grab_up,
touch_move_grab_motion,
+ touch_move_grab_frame,
touch_move_grab_cancel,
};
@@ -1407,8 +1446,6 @@ surface_touch_move(struct shell_surface *shsurf, struct weston_seat *seat)
if (shsurf->state.fullscreen)
return 0;
- if (shsurf->grabbed)
- return 0;
move = malloc(sizeof *move);
if (!move)
@@ -1432,22 +1469,47 @@ noop_grab_focus(struct weston_pointer_grab *grab)
}
static void
+constrain_position(struct weston_move_grab *move, int *cx, int *cy)
+{
+ struct shell_surface *shsurf = move->base.shsurf;
+ struct weston_pointer *pointer = move->base.grab.pointer;
+ int x, y, panel_height, bottom;
+ const int safety = 50;
+
+ x = wl_fixed_to_int(pointer->x + move->dx);
+ y = wl_fixed_to_int(pointer->y + move->dy);
+
+ panel_height = get_output_panel_height(shsurf->shell,
+ shsurf->surface->output);
+ bottom = y + shsurf->surface->height - shsurf->margin.bottom;
+ if (bottom - panel_height < safety)
+ y = panel_height + safety -
+ shsurf->surface->height + shsurf->margin.bottom;
+
+ if (move->client_initiated &&
+ y + shsurf->margin.top < panel_height)
+ y = panel_height - shsurf->margin.top;
+
+ *cx = x;
+ *cy = y;
+}
+
+static void
move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
wl_fixed_t x, wl_fixed_t y)
{
struct weston_move_grab *move = (struct weston_move_grab *) grab;
struct weston_pointer *pointer = grab->pointer;
struct shell_surface *shsurf = move->base.shsurf;
- int dx, dy;
+ int cx, cy;
weston_pointer_move(pointer, x, y);
- dx = wl_fixed_to_int(pointer->x + move->dx);
- dy = wl_fixed_to_int(pointer->y + move->dy);
-
if (!shsurf)
return;
- weston_view_set_position(shsurf->view, dx, dy);
+ constrain_position(move, &cx, &cy);
+
+ weston_view_set_position(shsurf->view, cx, cy);
weston_compositor_schedule_repaint(shsurf->surface->compositor);
}
@@ -1486,16 +1548,16 @@ static const struct weston_pointer_grab_interface move_grab_interface = {
};
static int
-surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
+surface_move(struct shell_surface *shsurf, struct weston_seat *seat,
+ int client_initiated)
{
struct weston_move_grab *move;
if (!shsurf)
return -1;
- if (shsurf->grabbed)
- return 0;
- if (shsurf->state.fullscreen || shsurf->state.maximized)
+ if (shsurf->grabbed ||
+ shsurf->state.fullscreen || shsurf->state.maximized)
return 0;
move = malloc(sizeof *move);
@@ -1506,6 +1568,7 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *seat)
seat->pointer->grab_x;
move->dy = wl_fixed_from_double(shsurf->view->geometry.y) -
seat->pointer->grab_y;
+ move->client_initiated = client_initiated;
shell_grab_start(&move->base, &move_grab_interface, shsurf,
seat->pointer, DESKTOP_SHELL_CURSOR_MOVE);
@@ -1527,7 +1590,7 @@ common_surface_move(struct wl_resource *resource,
seat->pointer->grab_serial == serial) {
surface = weston_surface_get_main_surface(seat->pointer->focus->surface);
if ((surface == shsurf->surface) &&
- (surface_move(shsurf, seat) < 0))
+ (surface_move(shsurf, seat, 1) < 0))
wl_resource_post_no_memory(resource);
} else if (seat->touch &&
seat->touch->focus &&
@@ -1588,20 +1651,20 @@ resize_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
height += wl_fixed_to_int(to_y - from_y);
}
- shsurf->client->send_configure(shsurf->surface,
- resize->edges, width, height);
+ shsurf->client->send_configure(shsurf->surface, width, height);
}
static void
-send_configure(struct weston_surface *surface,
- uint32_t edges, int32_t width, int32_t height)
+send_configure(struct weston_surface *surface, int32_t width, int32_t height)
{
struct shell_surface *shsurf = get_shell_surface(surface);
assert(shsurf);
- wl_shell_surface_send_configure(shsurf->resource,
- edges, width, height);
+ if (shsurf->resource)
+ wl_shell_surface_send_configure(shsurf->resource,
+ shsurf->resize_edges,
+ width, height);
}
static const struct weston_shell_client shell_client = {
@@ -1680,7 +1743,8 @@ surface_resize(struct shell_surface *shsurf,
{
struct weston_resize_grab *resize;
- if (shsurf->state.fullscreen || shsurf->state.maximized)
+ if (shsurf->grabbed ||
+ shsurf->state.fullscreen || shsurf->state.maximized)
return 0;
if (edges == 0 || edges > 15 ||
@@ -1711,9 +1775,6 @@ common_surface_resize(struct wl_resource *resource,
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
struct weston_surface *surface;
- if (shsurf->state.fullscreen)
- return;
-
if (seat->pointer->button_count == 0 ||
seat->pointer->grab_serial != serial ||
seat->pointer->focus == NULL)
@@ -1769,10 +1830,10 @@ busy_cursor_grab_button(struct weston_pointer_grab *base,
struct weston_seat *seat = grab->grab.pointer->seat;
if (shsurf && button == BTN_LEFT && state) {
- activate(shsurf->shell, shsurf->surface, seat);
- surface_move(shsurf, seat);
+ activate(shsurf->shell, shsurf->surface, seat, true);
+ surface_move(shsurf, seat, 0);
} else if (shsurf && button == BTN_RIGHT && state) {
- activate(shsurf->shell, shsurf->surface, seat);
+ activate(shsurf->shell, shsurf->surface, seat, true);
surface_rotate(shsurf, seat);
}
}
@@ -1807,6 +1868,9 @@ set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
DESKTOP_SHELL_CURSOR_BUSY);
+ /* Mark the shsurf as ungrabbed so that button binding is able
+ * to move it. */
+ shsurf->grabbed = 0;
}
static void
@@ -1859,12 +1923,10 @@ static void
handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
{
struct weston_compositor *compositor = shsurf->shell->compositor;
- struct wl_client *client = wl_resource_get_client(shsurf->resource);
- struct shell_client *sc;
+ struct shell_client *sc = shsurf->owner;
struct wl_event_loop *loop;
static const int ping_timeout = 200;
- sc = get_shell_client(client);
if (sc->unresponsive) {
xdg_ping_timeout_handler(sc);
return;
@@ -1920,19 +1982,6 @@ handle_pointer_focus(struct wl_listener *listener, void *data)
}
static void
-create_pointer_focus_listener(struct weston_seat *seat)
-{
- struct wl_listener *listener;
-
- if (!seat->pointer)
- return;
-
- listener = malloc(sizeof *listener);
- listener->notify = handle_pointer_focus;
- wl_signal_add(&seat->pointer->focus_signal, listener);
-}
-
-static void
shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
{
if (--shsurf->focus_count == 0)
@@ -1970,32 +2019,6 @@ handle_keyboard_focus(struct wl_listener *listener, void *data)
}
static void
-create_keyboard_focus_listener(struct weston_seat *seat)
-{
- struct wl_listener *listener;
-
- if (!seat->keyboard)
- return;
-
- listener = malloc(sizeof *listener);
- listener->notify = handle_keyboard_focus;
- wl_signal_add(&seat->keyboard->focus_signal, listener);
-}
-
-static struct shell_client *
-get_shell_client(struct wl_client *client)
-{
- struct wl_listener *listener;
-
- listener = wl_client_get_destroy_listener(client,
- handle_shell_client_destroy);
- if (listener == NULL)
- return NULL;
-
- return container_of(listener, struct shell_client, destroy_listener);
-}
-
-static void
shell_client_pong(struct shell_client *sc, uint32_t serial)
{
if (sc->ping_serial != serial)
@@ -2015,9 +2038,9 @@ static void
shell_surface_pong(struct wl_client *client,
struct wl_resource *resource, uint32_t serial)
{
- struct shell_client *sc;
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ struct shell_client *sc = shsurf->owner;
- sc = get_shell_client(client);
shell_client_pong(sc, serial);
}
@@ -2029,6 +2052,16 @@ set_title(struct shell_surface *shsurf, const char *title)
}
static void
+set_margin(struct shell_surface *shsurf,
+ int32_t left, int32_t right, int32_t top, int32_t bottom)
+{
+ shsurf->margin.left = left;
+ shsurf->margin.right = right;
+ shsurf->margin.top = top;
+ shsurf->margin.bottom = bottom;
+}
+
+static void
shell_surface_set_title(struct wl_client *client,
struct wl_resource *resource, const char *title)
{
@@ -2097,9 +2130,15 @@ shell_surface_calculate_layer_link (struct shell_surface *shsurf)
struct weston_view *parent;
switch (shsurf->type) {
+ case SHELL_SURFACE_XWAYLAND:
+ return &shsurf->shell->fullscreen_layer.view_list;
+
+ case SHELL_SURFACE_NONE:
+ return NULL;
+
case SHELL_SURFACE_POPUP:
case SHELL_SURFACE_TOPLEVEL:
- if (shsurf->state.fullscreen) {
+ if (shsurf->state.fullscreen && !shsurf->state.lowered) {
return &shsurf->shell->fullscreen_layer.view_list;
} else if (shsurf->parent) {
/* Move the surface to its parent layer so
@@ -2112,22 +2151,15 @@ shell_surface_calculate_layer_link (struct shell_surface *shsurf)
if (parent)
return parent->layer_link.prev;
}
- break;
-
- case SHELL_SURFACE_XWAYLAND:
- return &shsurf->shell->fullscreen_layer.view_list;
- case SHELL_SURFACE_NONE:
- default:
- /* Go to the fallback, below. */
- break;
+ /* Move the surface to a normal workspace layer so that surfaces
+ * which were previously fullscreen or transient are no longer
+ * rendered on top. */
+ ws = get_current_workspace(shsurf->shell);
+ return &ws->layer.view_list;
}
- /* Move the surface to a normal workspace layer so that surfaces
- * which were previously fullscreen or transient are no longer
- * rendered on top. */
- ws = get_current_workspace(shsurf->shell);
- return &ws->layer.view_list;
+ assert(0 && "Unknown shell surface type");
}
static void
@@ -2139,6 +2171,7 @@ shell_surface_update_child_surface_layers (struct shell_surface *shsurf)
* stacked above shsurf. */
wl_list_for_each_reverse(child, &shsurf->children_list, children_link) {
if (shsurf->view->layer_link.prev != &child->view->layer_link) {
+ weston_view_damage_below(child->view);
weston_view_geometry_dirty(child->view);
wl_list_remove(&child->view->layer_link);
wl_list_insert(shsurf->view->layer_link.prev,
@@ -2167,6 +2200,8 @@ shell_surface_update_layer(struct shell_surface *shsurf)
new_layer_link = shell_surface_calculate_layer_link(shsurf);
+ if (new_layer_link == NULL)
+ return;
if (new_layer_link == &shsurf->view->layer_link)
return;
@@ -2293,7 +2328,7 @@ set_fullscreen(struct shell_surface *shsurf,
shsurf->type = SHELL_SURFACE_TOPLEVEL;
- shsurf->client->send_configure(shsurf->surface, 0,
+ shsurf->client->send_configure(shsurf->surface,
shsurf->output->width,
shsurf->output->height);
@@ -2313,7 +2348,6 @@ unset_fullscreen(struct shell_surface *shsurf)
shell_surface_is_top_fullscreen(shsurf)) {
restore_output_mode(shsurf->fullscreen_output);
}
- shsurf->fullscreen_output = NULL;
shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
shsurf->fullscreen.framerate = 0;
@@ -2408,15 +2442,14 @@ set_maximized(struct shell_surface *shsurf,
struct weston_output *output)
{
struct desktop_shell *shell;
- uint32_t edges = 0, panel_height = 0;
+ uint32_t panel_height = 0;
shell_surface_set_output(shsurf, output);
shell = shell_surface_get_shell(shsurf);
panel_height = get_output_panel_height(shell, shsurf->output);
- edges = WL_SHELL_SURFACE_RESIZE_TOP | WL_SHELL_SURFACE_RESIZE_LEFT;
- shsurf->client->send_configure(shsurf->surface, edges,
+ shsurf->client->send_configure(shsurf->surface,
shsurf->output->width,
shsurf->output->height - panel_height);
@@ -2482,7 +2515,7 @@ set_minimized(struct weston_surface *surface, uint32_t is_true)
wl_list_for_each(seat, &shsurf->shell->compositor->seat_list, link) {
if (!seat->keyboard)
continue;
- activate(shsurf->shell, view->surface, seat);
+ activate(shsurf->shell, view->surface, seat, true);
}
}
@@ -2645,6 +2678,8 @@ shell_ensure_fullscreen_black_view(struct shell_surface *shsurf)
&shsurf->fullscreen.black_view->layer_link);
weston_view_geometry_dirty(shsurf->fullscreen.black_view);
weston_surface_damage(shsurf->surface);
+
+ shsurf->state.lowered = false;
}
/* Create black surface and append it to the associated fullscreen surface.
@@ -2661,6 +2696,10 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
restore_output_mode(output);
+ /* Reverse the effect of lower_fullscreen_layer() */
+ wl_list_remove(&shsurf->view->layer_link);
+ wl_list_insert(&shsurf->shell->fullscreen_layer.view_list, &shsurf->view->layer_link);
+
shell_ensure_fullscreen_black_view(shsurf);
surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
@@ -2758,6 +2797,12 @@ set_xwayland(struct shell_surface *shsurf, int x, int y, uint32_t flags)
shsurf->state_changed = true;
}
+static int
+shell_interface_move(struct shell_surface *shsurf, struct weston_seat *ws)
+{
+ return surface_move(shsurf, ws, 1);
+}
+
static const struct weston_pointer_grab_interface popup_grab_interface;
static void
@@ -2786,6 +2831,30 @@ destroy_shell_seat(struct wl_listener *listener, void *data)
free(shseat);
}
+static void
+shell_seat_caps_changed(struct wl_listener *listener, void *data)
+{
+ struct shell_seat *seat;
+
+ seat = container_of(listener, struct shell_seat, caps_changed_listener);
+
+ if (seat->seat->keyboard &&
+ wl_list_empty(&seat->keyboard_focus_listener.link)) {
+ wl_signal_add(&seat->seat->keyboard->focus_signal,
+ &seat->keyboard_focus_listener);
+ } else if (!seat->seat->keyboard) {
+ wl_list_init(&seat->keyboard_focus_listener.link);
+ }
+
+ if (seat->seat->pointer &&
+ wl_list_empty(&seat->pointer_focus_listener.link)) {
+ wl_signal_add(&seat->seat->pointer->focus_signal,
+ &seat->pointer_focus_listener);
+ } else if (!seat->seat->pointer) {
+ wl_list_init(&seat->pointer_focus_listener.link);
+ }
+}
+
static struct shell_seat *
create_shell_seat(struct weston_seat *seat)
{
@@ -2804,6 +2873,17 @@ create_shell_seat(struct weston_seat *seat)
wl_signal_add(&seat->destroy_signal,
&shseat->seat_destroy_listener);
+ shseat->keyboard_focus_listener.notify = handle_keyboard_focus;
+ wl_list_init(&shseat->keyboard_focus_listener.link);
+
+ shseat->pointer_focus_listener.notify = handle_pointer_focus;
+ wl_list_init(&shseat->pointer_focus_listener.link);
+
+ shseat->caps_changed_listener.notify = shell_seat_caps_changed;
+ wl_signal_add(&seat->updated_caps_signal,
+ &shseat->caps_changed_listener);
+ shell_seat_caps_changed(&shseat->caps_changed_listener, NULL);
+
return shseat;
}
@@ -2813,8 +2893,7 @@ get_shell_seat(struct weston_seat *seat)
struct wl_listener *listener;
listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat);
- if (listener == NULL)
- return create_shell_seat(seat);
+ assert(listener != NULL);
return container_of(listener,
struct shell_seat, seat_destroy_listener);
@@ -3064,8 +3143,8 @@ shell_handle_surface_destroy(struct wl_listener *listener, void *data)
if (shsurf->resource)
wl_resource_destroy(shsurf->resource);
- else
- destroy_shell_surface(shsurf);
+
+ destroy_shell_surface(shsurf);
}
static void
@@ -3083,15 +3162,17 @@ handle_resource_destroy(struct wl_listener *listener, void *data)
container_of(listener, struct shell_surface,
resource_destroy_listener);
+ if (!weston_surface_is_mapped(shsurf->surface))
+ return;
+
shsurf->surface->ref_count++;
pixman_region32_fini(&shsurf->surface->pending.input);
pixman_region32_init(&shsurf->surface->pending.input);
pixman_region32_fini(&shsurf->surface->input);
pixman_region32_init(&shsurf->surface->input);
- if (weston_surface_is_mapped(shsurf->surface))
- weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
- fade_out_done, shsurf);
+ weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
+ fade_out_done, shsurf);
}
static void
@@ -3107,7 +3188,8 @@ get_shell_surface(struct weston_surface *surface)
}
static struct shell_surface *
-create_common_surface(void *shell, struct weston_surface *surface,
+create_common_surface(struct shell_client *owner, void *shell,
+ struct weston_surface *surface,
const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
@@ -3136,6 +3218,7 @@ create_common_surface(void *shell, struct weston_surface *surface,
shsurf->resource_destroy_listener.notify = handle_resource_destroy;
wl_resource_add_destroy_listener(surface->resource,
&shsurf->resource_destroy_listener);
+ shsurf->owner = owner;
shsurf->shell = (struct desktop_shell *) shell;
shsurf->unresponsive = 0;
@@ -3178,7 +3261,7 @@ static struct shell_surface *
create_shell_surface(void *shell, struct weston_surface *surface,
const struct weston_shell_client *client)
{
- return create_common_surface(shell, surface, client);
+ return create_common_surface(NULL, shell, surface, client);
}
static struct weston_view *
@@ -3195,7 +3278,8 @@ shell_get_shell_surface(struct wl_client *client,
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = sc->shell;
struct shell_surface *shsurf;
if (get_shell_surface(surface)) {
@@ -3205,7 +3289,7 @@ shell_get_shell_surface(struct wl_client *client,
return;
}
- shsurf = create_shell_surface(shell, surface, &shell_client);
+ shsurf = create_common_surface(sc, shell, surface, &shell_client);
if (!shsurf) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -3271,8 +3355,9 @@ xdg_surface_set_margin(struct wl_client *client,
int32_t top,
int32_t bottom)
{
- /* Do nothing, Weston doesn't try to constrain or place
- * surfaces in any special manner... */
+ struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+
+ set_margin(shsurf, left, right, top, bottom);
}
static void
@@ -3422,13 +3507,14 @@ static const struct xdg_surface_interface xdg_surface_implementation = {
static void
xdg_send_configure(struct weston_surface *surface,
- uint32_t edges, int32_t width, int32_t height)
+ int32_t width, int32_t height)
{
struct shell_surface *shsurf = get_shell_surface(surface);
assert(shsurf);
- xdg_surface_send_configure(shsurf->resource, width, height);
+ if (shsurf->resource)
+ xdg_surface_send_configure(shsurf->resource, width, height);
}
static const struct weston_shell_client xdg_client = {
@@ -3449,12 +3535,13 @@ xdg_use_unstable_version(struct wl_client *client,
}
static struct shell_surface *
-create_xdg_surface(void *shell, struct weston_surface *surface,
+create_xdg_surface(struct shell_client *owner, void *shell,
+ struct weston_surface *surface,
const struct weston_shell_client *client)
{
struct shell_surface *shsurf;
- shsurf = create_common_surface(shell, surface, client);
+ shsurf = create_common_surface(owner, shell, surface, client);
shsurf->type = SHELL_SURFACE_TOPLEVEL;
return shsurf;
@@ -3479,7 +3566,7 @@ xdg_get_xdg_surface(struct wl_client *client,
return;
}
- shsurf = create_xdg_surface(shell, surface, &xdg_client);
+ shsurf = create_xdg_surface(sc, shell, surface, &xdg_client);
if (!shsurf) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -3519,7 +3606,7 @@ static const struct xdg_popup_interface xdg_popup_implementation = {
static void
xdg_popup_send_configure(struct weston_surface *surface,
- uint32_t edges, int32_t width, int32_t height)
+ int32_t width, int32_t height)
{
}
@@ -3528,7 +3615,8 @@ static const struct weston_shell_client xdg_popup_client = {
};
static struct shell_surface *
-create_xdg_popup(void *shell, struct weston_surface *surface,
+create_xdg_popup(struct shell_client *owner, void *shell,
+ struct weston_surface *surface,
const struct weston_shell_client *client,
struct weston_surface *parent,
struct shell_seat *seat,
@@ -3537,7 +3625,7 @@ create_xdg_popup(void *shell, struct weston_surface *surface,
{
struct shell_surface *shsurf;
- shsurf = create_common_surface(shell, surface, client);
+ shsurf = create_common_surface(owner, shell, surface, client);
shsurf->type = SHELL_SURFACE_POPUP;
shsurf->popup.shseat = seat;
shsurf->popup.serial = serial;
@@ -3582,7 +3670,7 @@ xdg_get_xdg_popup(struct wl_client *client,
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,
+ shsurf = create_xdg_popup(sc, shell, surface, &xdg_popup_client,
parent, seat, serial, x, y);
if (!shsurf) {
wl_resource_post_error(surface_resource,
@@ -3715,6 +3803,12 @@ terminate_screensaver(struct desktop_shell *shell)
if (shell->screensaver.process.pid == 0)
return;
+ /* Disarm the screensaver timer, otherwise it may fire when the
+ * compositor is not in the idle state. In that case, the screen will
+ * be locked, but the wake_signal won't fire on user input, making the
+ * system unresponsive. */
+ wl_event_source_timer_update(shell->screensaver.timer, 0);
+
kill(shell->screensaver.process.pid, SIGTERM);
}
@@ -3982,7 +4076,7 @@ move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *dat
shsurf->state.maximized)
return;
- surface_move(shsurf, (struct weston_seat *) seat);
+ surface_move(shsurf, (struct weston_seat *) seat, 0);
}
static void
@@ -4355,8 +4449,12 @@ rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
surface_rotate(surface, seat);
}
-/* Move all fullscreen layers down to the current workspace in a non-reversible
- * manner. This should be used when implementing shell-wide overlays, such as
+/* Move all fullscreen layers down to the current workspace and hide their
+ * black views. The surfaces' state is set to both fullscreen and lowered,
+ * and this is reversed when such a surface is re-configured, see
+ * shell_configure_fullscreen() and shell_ensure_fullscreen_black_view().
+ *
+ * This should be used when implementing shell-wide overlays, such as
* the alt-tab switcher, which need to de-promote fullscreen layers. */
void
lower_fullscreen_layer(struct desktop_shell *shell)
@@ -4368,16 +4466,32 @@ lower_fullscreen_layer(struct desktop_shell *shell)
wl_list_for_each_reverse_safe(view, prev,
&shell->fullscreen_layer.view_list,
layer_link) {
+ struct shell_surface *shsurf = get_shell_surface(view->surface);
+
+ if (!shsurf)
+ continue;
+
+ /* We can have a non-fullscreen popup for a fullscreen surface
+ * in the fullscreen layer. */
+ if (shsurf->state.fullscreen) {
+ /* Hide the black view */
+ wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
+ wl_list_init(&shsurf->fullscreen.black_view->layer_link);
+ }
+
+ /* Lower the view to the workspace layer */
wl_list_remove(&view->layer_link);
wl_list_insert(&ws->layer.view_list, &view->layer_link);
weston_view_damage_below(view);
weston_surface_damage(view->surface);
+
+ shsurf->state.lowered = true;
}
}
void
activate(struct desktop_shell *shell, struct weston_surface *es,
- struct weston_seat *seat)
+ struct weston_seat *seat, bool configure)
{
struct weston_surface *main_surface;
struct focus_state *state;
@@ -4385,6 +4499,8 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_surface *old_es;
struct shell_surface *shsurf;
+ lower_fullscreen_layer(shell);
+
main_surface = weston_surface_get_main_surface(es);
weston_surface_activate(es, seat);
@@ -4399,7 +4515,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
shsurf = get_shell_surface(main_surface);
assert(shsurf);
- if (shsurf->state.fullscreen)
+ if (shsurf->state.fullscreen && configure)
shell_configure_fullscreen(shsurf);
else
restore_all_output_modes(shell->compositor);
@@ -4448,7 +4564,7 @@ activate_binding(struct weston_seat *seat,
if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
return;
- activate(shell, focus, seat);
+ activate(shell, focus, seat, true);
}
static void
@@ -4475,6 +4591,19 @@ touch_to_activate_binding(struct weston_seat *seat, uint32_t time, void *data)
}
static void
+unfocus_all_seats(struct desktop_shell *shell)
+{
+ struct weston_seat *seat, *next;
+
+ wl_list_for_each_safe(seat, next, &shell->compositor->seat_list, link) {
+ if (seat->keyboard == NULL)
+ continue;
+
+ weston_keyboard_set_focus(seat->keyboard, NULL);
+ }
+}
+
+static void
lock(struct desktop_shell *shell)
{
struct workspace *ws = get_current_workspace(shell);
@@ -4500,6 +4629,11 @@ lock(struct desktop_shell *shell)
launch_screensaver(shell);
+ /* Remove the keyboard focus on all seats. This will be
+ * restored to the workspace's saved state via
+ * restore_focus_state when the compositor is unlocked */
+ unfocus_all_seats(shell);
+
/* TODO: disable bindings that should not work while locked. */
/* All this must be undone in resume_desktop(). */
@@ -4850,7 +4984,7 @@ map(struct desktop_shell *shell, struct shell_surface *shsurf,
if (shell->locked)
break;
wl_list_for_each(seat, &compositor->seat_list, link)
- activate(shell, shsurf->surface, seat);
+ activate(shell, shsurf->surface, seat, true);
break;
case SHELL_SURFACE_POPUP:
case SHELL_SURFACE_NONE:
@@ -5072,7 +5206,7 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
if (sc)
wl_resource_set_implementation(sc->resource,
&shell_implementation,
- shell, NULL);
+ sc, NULL);
}
static void
@@ -5301,7 +5435,7 @@ switcher_destroy(struct switcher *switcher)
if (switcher->current)
activate(switcher->shell, switcher->current,
- (struct weston_seat *) keyboard->seat);
+ (struct weston_seat *) keyboard->seat, true);
wl_list_remove(&switcher->listener.link);
weston_keyboard_end_grab(keyboard);
if (keyboard->input_method_resource)
@@ -5676,9 +5810,12 @@ shell_reposition_view_on_output_destroy(struct weston_view *view)
x = first_output->x + first_output->width / 4;
y = first_output->y + first_output->height / 4;
+
+ weston_view_set_position(view, x, y);
+ } else {
+ weston_view_geometry_dirty(view);
}
- weston_view_set_position(view, x, y);
shsurf = get_shell_surface(view->surface);
@@ -5690,27 +5827,35 @@ shell_reposition_view_on_output_destroy(struct weston_view *view)
}
}
+void
+shell_for_each_layer(struct desktop_shell *shell,
+ shell_for_each_layer_func_t func, void *data)
+{
+ struct workspace **ws;
+
+ func(shell, &shell->fullscreen_layer, data);
+ func(shell, &shell->panel_layer, data);
+ func(shell, &shell->background_layer, data);
+ func(shell, &shell->lock_layer, data);
+ func(shell, &shell->input_panel_layer, data);
+
+ wl_array_for_each(ws, &shell->workspaces.array)
+ func(shell, &(*ws)->layer, data);
+}
+
static void
-shell_reposition_views_on_output_destroy(struct shell_output *shell_output)
+shell_output_destroy_move_layer(struct desktop_shell *shell,
+ struct weston_layer *layer,
+ void *data)
{
- struct desktop_shell *shell = shell_output->shell;
- struct weston_output *output = shell_output->output;
- struct weston_layer *layer;
+ struct weston_output *output = data;
struct weston_view *view;
- /* Move all views in the layers owned by the shell */
- wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
- wl_list_for_each(view, &layer->view_list, layer_link) {
- if (view->output != output)
- continue;
-
- shell_reposition_view_on_output_destroy(view);
- }
+ wl_list_for_each(view, &layer->view_list, layer_link) {
+ if (view->output != output)
+ continue;
- /* We don't start from the beggining of the layer list, so
- * make sure we don't wrap around it. */
- if (layer == &shell->background_layer)
- break;
+ shell_reposition_view_on_output_destroy(view);
}
}
@@ -5719,8 +5864,10 @@ handle_output_destroy(struct wl_listener *listener, void *data)
{
struct shell_output *output_listener =
container_of(listener, struct shell_output, destroy_listener);
+ struct weston_output *output = output_listener->output;
+ struct desktop_shell *shell = output_listener->shell;
- shell_reposition_views_on_output_destroy(output_listener);
+ shell_for_each_layer(shell, shell_output_destroy_move_layer, output);
wl_list_remove(&output_listener->destroy_listener.link);
wl_list_remove(&output_listener->link);
@@ -5756,34 +5903,32 @@ handle_output_create(struct wl_listener *listener, void *data)
}
static void
-handle_output_move(struct wl_listener *listener, void *data)
+handle_output_move_layer(struct desktop_shell *shell,
+ struct weston_layer *layer, void *data)
{
- struct desktop_shell *shell;
- struct weston_output *output;
- struct weston_layer *layer;
+ struct weston_output *output = data;
struct weston_view *view;
float x, y;
- shell = container_of(listener, struct desktop_shell,
- output_move_listener);
- output = data;
+ wl_list_for_each(view, &layer->view_list, layer_link) {
+ if (view->output != output)
+ continue;
- /* Move all views in the layers owned by the shell */
- wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
- wl_list_for_each(view, &layer->view_list, layer_link) {
- if (view->output != output)
- continue;
+ x = view->geometry.x + output->move_x;
+ y = view->geometry.y + output->move_y;
+ weston_view_set_position(view, x, y);
+ }
+}
- x = view->geometry.x + output->move_x;
- y = view->geometry.y + output->move_y;
- weston_view_set_position(view, x, y);
- }
+static void
+handle_output_move(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell;
- /* We don't start from the beggining of the layer list, so
- * make sure we don't wrap around it. */
- if (layer == &shell->background_layer)
- break;
- }
+ shell = container_of(listener, struct desktop_shell,
+ output_move_listener);
+
+ shell_for_each_layer(shell, handle_output_move_layer, data);
}
static void
@@ -5829,6 +5974,7 @@ shell_destroy(struct wl_listener *listener, void *data)
}
wl_list_remove(&shell->output_create_listener.link);
+ wl_list_remove(&shell->output_move_listener.link);
wl_array_for_each(ws, &shell->workspaces.array)
workspace_destroy(*ws);
@@ -5931,6 +6077,14 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
debug_binding, shell);
}
+static void
+handle_seat_created(struct wl_listener *listener, void *data)
+{
+ struct weston_seat *seat = data;
+
+ create_shell_seat(seat);
+}
+
WL_EXPORT int
module_init(struct weston_compositor *ec,
int *argc, char *argv[])
@@ -5961,9 +6115,10 @@ module_init(struct weston_compositor *ec,
ec->shell_interface.set_transient = set_transient;
ec->shell_interface.set_fullscreen = set_fullscreen;
ec->shell_interface.set_xwayland = set_xwayland;
- ec->shell_interface.move = surface_move;
+ ec->shell_interface.move = shell_interface_move;
ec->shell_interface.resize = surface_resize;
ec->shell_interface.set_title = set_title;
+ ec->shell_interface.set_margin = set_margin;
weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link);
weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link);
@@ -6030,10 +6185,10 @@ module_init(struct weston_compositor *ec,
shell->screensaver.timer =
wl_event_loop_add_timer(loop, screensaver_timeout, shell);
- wl_list_for_each(seat, &ec->seat_list, link) {
- create_pointer_focus_listener(seat);
- create_keyboard_focus_listener(seat);
- }
+ wl_list_for_each(seat, &ec->seat_list, link)
+ handle_seat_created(NULL, seat);
+ shell->seat_create_listener.notify = handle_seat_created;
+ wl_signal_add(&ec->seat_created_signal, &shell->seat_create_listener);
screenshooter_create(ec);