mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
implement input_inhibit protocol, needed for swaylock
this is in "it appears to work" state, though I blindly copy-pasted a little more code than I'm happy with, so might benefit from a review
This commit is contained in:
parent
65f5bf189d
commit
39b1d92f9b
7 changed files with 212 additions and 8 deletions
|
|
@ -65,6 +65,7 @@ struct seat {
|
|||
/* if set, views cannot receive focus */
|
||||
struct wlr_layer_surface_v1 *focused_layer;
|
||||
|
||||
struct wl_client *active_client_while_inhibited;
|
||||
struct wl_list inputs;
|
||||
struct wl_listener new_input;
|
||||
|
||||
|
|
@ -99,6 +100,10 @@ struct server {
|
|||
struct wl_listener new_xwayland_surface;
|
||||
#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 unmanaged_surfaces;
|
||||
|
||||
|
|
@ -369,4 +374,11 @@ void action(struct server *server, const char *action, const char *command);
|
|||
/* update onscreen display 'alt-tab' texture */
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ wayland_scanner_server = generator(
|
|||
server_protocols = [
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||
]
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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 */
|
||||
damage_all_outputs(server);
|
||||
|
||||
if (surface) {
|
||||
if (surface &&
|
||||
! input_inhibit_blocks_surface(&server->seat, surface->resource)) {
|
||||
bool focus_changed =
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
if(input_inhibit_blocks_surface(seat, view->surface->resource))
|
||||
return;
|
||||
|
||||
struct wlr_surface *prev_surface;
|
||||
prev_surface = seat->seat->keyboard_state.focused_surface;
|
||||
if (prev_surface == view->surface) {
|
||||
|
|
@ -96,6 +99,9 @@ desktop_focus_view(struct seat *seat, struct view *view)
|
|||
seat_focus_surface(seat, NULL);
|
||||
return;
|
||||
}
|
||||
if(input_inhibit_blocks_surface(seat, view->surface->resource))
|
||||
return;
|
||||
|
||||
if (view->minimized) {
|
||||
/* this will unmap and then focus */
|
||||
view_minimize(view, false);
|
||||
|
|
|
|||
|
|
@ -41,14 +41,12 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_key_notify(struct wl_listener *listener, void *data)
|
||||
static bool
|
||||
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 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;
|
||||
|
||||
/* Translate libinput keycode -> xkbcommon */
|
||||
|
|
@ -68,13 +66,14 @@ keyboard_key_notify(struct wl_listener *listener, void *data)
|
|||
/* end cycle */
|
||||
desktop_focus_view(&server->seat, server->cycle_view);
|
||||
server->cycle_view = NULL;
|
||||
/* XXX should we handled=true here? */
|
||||
} else if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
/* cycle to next */
|
||||
server->cycle_view =
|
||||
desktop_cycle_view(server, server->cycle_view);
|
||||
osd_update(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) {
|
||||
wlr_seat_set_keyboard(wlr_seat, device);
|
||||
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
||||
|
|
|
|||
89
src/server.c
89
src/server.c
|
|
@ -5,6 +5,7 @@
|
|||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_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_screencopy_v1.h>
|
||||
#include "config/rcxml.h"
|
||||
|
|
@ -78,6 +79,81 @@ drop_permissions(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void seat_clear_touch_points(struct seat *seat,
|
||||
struct wl_client *active_client){
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
struct wlr_touch_point *point;
|
||||
wl_list_for_each(point, &seat->seat->touch_state.touch_points, link) {
|
||||
if (point->client->client != active_client) {
|
||||
wlr_seat_touch_point_clear_focus(seat->seat,
|
||||
now.tv_nsec / 1000, point->touch_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
{
|
||||
wlr_log(WLR_INFO, "defocus layer");
|
||||
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) {
|
||||
wlr_log(WLR_INFO, "defocus surface");
|
||||
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_log(WLR_INFO, "defocus ptr");
|
||||
wlr_seat_pointer_clear_focus(seat->seat);
|
||||
}
|
||||
seat_clear_touch_points(seat, active_client);
|
||||
}
|
||||
|
||||
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 roots_output *output;
|
||||
wl_list_for_each(output, &seat->input->server->desktop->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
|
||||
server_init(struct server *server)
|
||||
{
|
||||
|
|
@ -203,6 +279,19 @@ server_init(struct server *server)
|
|||
wlr_data_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 =
|
||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue