mirror of
https://github.com/labwc/labwc.git
synced 2025-11-02 09:01:47 -05:00
Merge pull request #54 from telent/lockdown
implement input_inhibit protocol, needed for swaylock
This commit is contained in:
commit
824282dd2e
7 changed files with 195 additions and 8 deletions
|
|
@ -65,6 +65,7 @@ struct seat {
|
||||||
/* if set, views cannot receive focus */
|
/* if set, views cannot receive focus */
|
||||||
struct wlr_layer_surface_v1 *focused_layer;
|
struct wlr_layer_surface_v1 *focused_layer;
|
||||||
|
|
||||||
|
struct wl_client *active_client_while_inhibited;
|
||||||
struct wl_list inputs;
|
struct wl_list inputs;
|
||||||
struct wl_listener new_input;
|
struct wl_listener new_input;
|
||||||
|
|
||||||
|
|
@ -99,6 +100,10 @@ struct server {
|
||||||
struct wl_listener new_xwayland_surface;
|
struct wl_listener new_xwayland_surface;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct wlr_input_inhibit_manager *input_inhibit;
|
||||||
|
struct wl_listener input_inhibit_activate;
|
||||||
|
struct wl_listener input_inhibit_deactivate;
|
||||||
|
|
||||||
struct wl_list views;
|
struct wl_list views;
|
||||||
struct wl_list unmanaged_surfaces;
|
struct wl_list unmanaged_surfaces;
|
||||||
|
|
||||||
|
|
@ -345,6 +350,8 @@ void cursor_init(struct seat *seat);
|
||||||
|
|
||||||
void keyboard_init(struct seat *seat);
|
void keyboard_init(struct seat *seat);
|
||||||
|
|
||||||
|
void arrange_layers(struct output *output);
|
||||||
|
|
||||||
void seat_init(struct server *server);
|
void seat_init(struct server *server);
|
||||||
void seat_finish(struct server *server);
|
void seat_finish(struct server *server);
|
||||||
void seat_focus_surface(struct seat *seat, struct wlr_surface *surface);
|
void seat_focus_surface(struct seat *seat, struct wlr_surface *surface);
|
||||||
|
|
@ -375,4 +382,11 @@ void action(struct server *server, const char *action, const char *command);
|
||||||
/* update onscreen display 'alt-tab' texture */
|
/* update onscreen display 'alt-tab' texture */
|
||||||
void osd_update(struct server *server);
|
void osd_update(struct server *server);
|
||||||
|
|
||||||
|
/* wlroots "input inhibitor" extension (required for swaylock) blocks
|
||||||
|
* any client other than the requesting client from receiving events
|
||||||
|
*/
|
||||||
|
bool input_inhibit_blocks_surface(struct seat *seat,
|
||||||
|
struct wl_resource *resource);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LABWC_H */
|
#endif /* __LABWC_H */
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ wayland_scanner_server = generator(
|
||||||
server_protocols = [
|
server_protocols = [
|
||||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
|
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||||
]
|
]
|
||||||
|
|
||||||
server_protos_src = []
|
server_protos_src = []
|
||||||
|
|
|
||||||
67
protocols/wlr-input-inhibitor-unstable-v1.xml
Normal file
67
protocols/wlr-input-inhibitor-unstable-v1.xml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_input_inhibit_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2018 Drew DeVault
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute, and sell this
|
||||||
|
software and its documentation for any purpose is hereby granted
|
||||||
|
without fee, provided that the above copyright notice appear in
|
||||||
|
all copies and that both that copyright notice and this permission
|
||||||
|
notice appear in supporting documentation, and that the name of
|
||||||
|
the copyright holders not be used in advertising or publicity
|
||||||
|
pertaining to distribution of the software without specific,
|
||||||
|
written prior permission. The copyright holders make no
|
||||||
|
representations about the suitability of this software for any
|
||||||
|
purpose. It is provided "as is" without express or implied
|
||||||
|
warranty.
|
||||||
|
|
||||||
|
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||||
|
THIS SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="zwlr_input_inhibit_manager_v1" version="1">
|
||||||
|
<description summary="inhibits input events to other clients">
|
||||||
|
Clients can use this interface to prevent input events from being sent to
|
||||||
|
any surfaces but its own, which is useful for example in lock screen
|
||||||
|
software. It is assumed that access to this interface will be locked down
|
||||||
|
to whitelisted clients by the compositor.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="get_inhibitor">
|
||||||
|
<description summary="inhibit input to other clients">
|
||||||
|
Activates the input inhibitor. As long as the inhibitor is active, the
|
||||||
|
compositor will not send input events to other clients.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_input_inhibitor_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_inhibited" value="0" summary="an input inhibitor is already in use on the compositor"/>
|
||||||
|
</enum>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_input_inhibitor_v1" version="1">
|
||||||
|
<description summary="inhibits input to other clients">
|
||||||
|
While this resource exists, input to clients other than the owner of the
|
||||||
|
inhibitor resource will not receive input events. The client that owns
|
||||||
|
this resource will receive all input events normally. The compositor will
|
||||||
|
also disable all of its own input processing (such as keyboard shortcuts)
|
||||||
|
while the inhibitor is active.
|
||||||
|
|
||||||
|
The compositor may continue to send input events to selected clients,
|
||||||
|
such as an on-screen keyboard (via the input-method protocol).
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the input inhibitor object">
|
||||||
|
Destroy the inhibitor and allow other clients to receive input.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
12
src/cursor.c
12
src/cursor.c
|
|
@ -105,6 +105,15 @@ set_cursor(struct server *server, const char *cursor_name)
|
||||||
server->seat.xcursor_manager, cursor_name, server->seat.cursor);
|
server->seat.xcursor_manager, cursor_name, server->seat.cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool input_inhibit_blocks_surface(struct seat *seat,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
struct wl_client * inhibiting_client =
|
||||||
|
seat->active_client_while_inhibited;
|
||||||
|
return (inhibiting_client != NULL) &&
|
||||||
|
inhibiting_client != wl_resource_get_client(resource);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_cursor_motion(struct server *server, uint32_t time)
|
process_cursor_motion(struct server *server, uint32_t time)
|
||||||
{
|
{
|
||||||
|
|
@ -161,7 +170,8 @@ process_cursor_motion(struct server *server, uint32_t time)
|
||||||
/* Required for iconify/maximize/close button mouse-over deco */
|
/* Required for iconify/maximize/close button mouse-over deco */
|
||||||
damage_all_outputs(server);
|
damage_all_outputs(server);
|
||||||
|
|
||||||
if (surface) {
|
if (surface &&
|
||||||
|
! input_inhibit_blocks_surface(&server->seat, surface->resource)) {
|
||||||
bool focus_changed =
|
bool focus_changed =
|
||||||
wlr_seat->pointer_state.focused_surface != surface;
|
wlr_seat->pointer_state.focused_surface != surface;
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,9 @@ desktop_set_focus_view_only(struct seat *seat, struct view *view)
|
||||||
if (!view || view->minimized || !view->mapped) {
|
if (!view || view->minimized || !view->mapped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(input_inhibit_blocks_surface(seat, view->surface->resource))
|
||||||
|
return;
|
||||||
|
|
||||||
struct wlr_surface *prev_surface;
|
struct wlr_surface *prev_surface;
|
||||||
prev_surface = seat->seat->keyboard_state.focused_surface;
|
prev_surface = seat->seat->keyboard_state.focused_surface;
|
||||||
if (prev_surface == view->surface) {
|
if (prev_surface == view->surface) {
|
||||||
|
|
@ -96,6 +99,9 @@ desktop_focus_view(struct seat *seat, struct view *view)
|
||||||
seat_focus_surface(seat, NULL);
|
seat_focus_surface(seat, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(input_inhibit_blocks_surface(seat, view->surface->resource))
|
||||||
|
return;
|
||||||
|
|
||||||
if (view->minimized) {
|
if (view->minimized) {
|
||||||
/* this will unmap and then focus */
|
/* this will unmap and then focus */
|
||||||
view_minimize(view, false);
|
view_minimize(view, false);
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,12 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
keyboard_key_notify(struct wl_listener *listener, void *data)
|
handle_compositor_keybindings(struct wl_listener *listener,
|
||||||
|
struct wlr_event_keyboard_key *event)
|
||||||
{
|
{
|
||||||
/* This event is raised when a key is pressed or released. */
|
|
||||||
struct seat *seat = wl_container_of(listener, seat, keyboard_key);
|
struct seat *seat = wl_container_of(listener, seat, keyboard_key);
|
||||||
struct server *server = seat->server;
|
struct server *server = seat->server;
|
||||||
struct wlr_event_keyboard_key *event = data;
|
|
||||||
struct wlr_seat *wlr_seat = server->seat.seat;
|
|
||||||
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||||
|
|
||||||
/* Translate libinput keycode -> xkbcommon */
|
/* Translate libinput keycode -> xkbcommon */
|
||||||
|
|
@ -68,13 +66,14 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
|
||||||
/* end cycle */
|
/* end cycle */
|
||||||
desktop_focus_view(&server->seat, server->cycle_view);
|
desktop_focus_view(&server->seat, server->cycle_view);
|
||||||
server->cycle_view = NULL;
|
server->cycle_view = NULL;
|
||||||
|
/* XXX should we handled=true here? */
|
||||||
} else if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
} else if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
/* cycle to next */
|
/* cycle to next */
|
||||||
server->cycle_view =
|
server->cycle_view =
|
||||||
desktop_cycle_view(server, server->cycle_view);
|
desktop_cycle_view(server, server->cycle_view);
|
||||||
osd_update(server);
|
osd_update(server);
|
||||||
damage_all_outputs(server);
|
damage_all_outputs(server);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,8 +94,28 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
keyboard_key_notify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
/* XXX need to check if input inhibited before doing any
|
||||||
|
* compositor bindings
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This event is raised when a key is pressed or released. */
|
||||||
|
struct seat *seat = wl_container_of(listener, seat, keyboard_key);
|
||||||
|
struct server *server = seat->server;
|
||||||
|
struct wlr_event_keyboard_key *event = data;
|
||||||
|
struct wlr_seat *wlr_seat = server->seat.seat;
|
||||||
|
struct wlr_input_device *device = seat->keyboard_group->input_device;
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
if(!seat->active_client_while_inhibited)
|
||||||
|
/* ignore labwc keybindings if input is inhibited */
|
||||||
|
handled = handle_compositor_keybindings(listener, event);
|
||||||
|
|
||||||
/* Otherwise, pass it to the client. */
|
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
wlr_seat_set_keyboard(wlr_seat, device);
|
wlr_seat_set_keyboard(wlr_seat, device);
|
||||||
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
||||||
|
|
|
||||||
70
src/server.c
70
src/server.c
|
|
@ -5,6 +5,7 @@
|
||||||
#include <wlr/types/wlr_data_control_v1.h>
|
#include <wlr/types/wlr_data_control_v1.h>
|
||||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
|
#include <wlr/types/wlr_input_inhibitor.h>
|
||||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||||
#include <wlr/types/wlr_screencopy_v1.h>
|
#include <wlr/types/wlr_screencopy_v1.h>
|
||||||
#include "config/rcxml.h"
|
#include "config/rcxml.h"
|
||||||
|
|
@ -78,6 +79,62 @@ drop_permissions(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void seat_inhibit_input(struct seat *seat, struct wl_client *active_client)
|
||||||
|
{
|
||||||
|
seat->active_client_while_inhibited = active_client;
|
||||||
|
|
||||||
|
if(seat->focused_layer &&
|
||||||
|
(wl_resource_get_client(seat->focused_layer->resource) !=
|
||||||
|
active_client))
|
||||||
|
{
|
||||||
|
seat_set_focus_layer(seat, NULL);
|
||||||
|
}
|
||||||
|
struct wlr_surface * previous_kb_surface = seat->seat->keyboard_state.focused_surface;
|
||||||
|
if (previous_kb_surface &&
|
||||||
|
wl_resource_get_client(previous_kb_surface->resource) != active_client) {
|
||||||
|
seat_focus_surface(seat, NULL); /* keyboard focus */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_seat_client * previous_ptr_client = seat->seat->pointer_state.focused_client;
|
||||||
|
if (previous_ptr_client &&
|
||||||
|
(previous_ptr_client->client != active_client)) {
|
||||||
|
wlr_seat_pointer_clear_focus(seat->seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seat_disinhibit_input(struct seat *seat)
|
||||||
|
{
|
||||||
|
seat->active_client_while_inhibited = NULL;
|
||||||
|
// Triggers a refocus of the topmost surface layer if necessary
|
||||||
|
// TODO: Make layer surface focus per-output based on cursor position
|
||||||
|
|
||||||
|
struct output *output;
|
||||||
|
wl_list_for_each(output, &seat->server->outputs, link)
|
||||||
|
arrange_layers(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_input_inhibit(struct wl_listener *listener, void *data) {
|
||||||
|
wlr_log(WLR_INFO, "activate input inhibit");
|
||||||
|
|
||||||
|
struct server *server = wl_container_of(
|
||||||
|
listener, server, input_inhibit_activate);
|
||||||
|
|
||||||
|
seat_inhibit_input(&server->seat,
|
||||||
|
server->input_inhibit->active_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_input_disinhibit(struct wl_listener *listener, void *data) {
|
||||||
|
wlr_log(WLR_INFO, "deactivate input inhibit");
|
||||||
|
|
||||||
|
struct server *server = wl_container_of(
|
||||||
|
listener, server, input_inhibit_deactivate);
|
||||||
|
|
||||||
|
seat_disinhibit_input(&server->seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
server_init(struct server *server)
|
server_init(struct server *server)
|
||||||
{
|
{
|
||||||
|
|
@ -203,6 +260,19 @@ server_init(struct server *server)
|
||||||
wlr_data_control_manager_v1_create(server->wl_display);
|
wlr_data_control_manager_v1_create(server->wl_display);
|
||||||
wlr_gamma_control_manager_v1_create(server->wl_display);
|
wlr_gamma_control_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
|
// struct wlr_input_inhibit_manager *input_inhibit_mgr = NULL;
|
||||||
|
server->input_inhibit = wlr_input_inhibit_manager_create(server->wl_display);
|
||||||
|
if (!server->input_inhibit) {
|
||||||
|
wlr_log(WLR_ERROR, "unable to create the input inhibit manager");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_add(&server->input_inhibit->events.activate, &server->input_inhibit_activate);
|
||||||
|
server->input_inhibit_activate.notify = handle_input_inhibit;
|
||||||
|
|
||||||
|
wl_signal_add(&server->input_inhibit->events.deactivate, &server->input_inhibit_deactivate);
|
||||||
|
server->input_inhibit_deactivate.notify = handle_input_disinhibit;
|
||||||
|
|
||||||
server->foreign_toplevel_manager =
|
server->foreign_toplevel_manager =
|
||||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue