diff options
-rw-r--r-- | backend/backend.c | 2 | ||||
-rw-r--r-- | backend/drm/atomic.c | 4 | ||||
-rw-r--r-- | backend/wayland/backend.c | 4 | ||||
-rw-r--r-- | examples/idle.c | 189 | ||||
-rw-r--r-- | examples/meson.build | 9 | ||||
-rw-r--r-- | include/rootston/desktop.h | 2 | ||||
-rw-r--r-- | include/wlr/backend/wayland.h | 6 | ||||
-rw-r--r-- | include/wlr/types/wlr_idle.h | 51 | ||||
-rw-r--r-- | include/wlr/xwayland.h | 5 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | protocol/idle.xml | 49 | ||||
-rw-r--r-- | protocol/meson.build | 2 | ||||
-rw-r--r-- | rootston/desktop.c | 2 | ||||
-rw-r--r-- | rootston/main.c | 1 | ||||
-rw-r--r-- | rootston/output.c | 36 | ||||
-rw-r--r-- | rootston/seat.c | 25 | ||||
-rw-r--r-- | types/meson.build | 1 | ||||
-rw-r--r-- | types/wlr_idle.c | 190 | ||||
-rw-r--r-- | types/wlr_seat.c | 1 | ||||
-rw-r--r-- | xwayland/xwm.c | 10 |
20 files changed, 576 insertions, 14 deletions
diff --git a/backend/backend.c b/backend/backend.c index 6b32bc6a..54e1cdca 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -53,7 +53,7 @@ struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend) { } static struct wlr_backend *attempt_wl_backend(struct wl_display *display) { - struct wlr_backend *backend = wlr_wl_backend_create(display); + struct wlr_backend *backend = wlr_wl_backend_create(display, NULL); if (backend) { int outputs = 1; const char *_outputs = getenv("WLR_WL_OUTPUTS"); diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 3e8866ad..54024d86 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -177,6 +177,10 @@ bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, int x, int y) { + if (!crtc || !crtc->cursor) { + return true; + } + struct wlr_drm_plane *plane = crtc->cursor; // We can't use atomic operations on fake planes if (plane->id == 0) { diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 36fbd8e0..32fdc2b6 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -158,7 +158,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_wl_backend_destroy(&backend->backend); } -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display) { +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote) { wlr_log(L_INFO, "Creating wayland backend"); struct wlr_wl_backend *backend = calloc(1, sizeof(struct wlr_wl_backend)); @@ -173,7 +173,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display) { backend->local_display = display; - backend->remote_display = wl_display_connect(NULL); + backend->remote_display = wl_display_connect(remote); if (!backend->remote_display) { wlr_log_errno(L_ERROR, "Could not connect to remote display"); return false; diff --git a/examples/idle.c b/examples/idle.c new file mode 100644 index 00000000..e5e01f63 --- /dev/null +++ b/examples/idle.c @@ -0,0 +1,189 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <pthread.h> +#include <wayland-client.h> +#include <wayland-client-protocol.h> +#include <idle-client-protocol.h> + +static struct org_kde_kwin_idle *idle_manager = NULL; +static struct wl_seat *seat = NULL; +static uint32_t timeout = 0, simulate_activity_timeout = 0, close_timeout = 0; +static int run = 1; + +struct thread_args { + struct wl_display *display; + struct org_kde_kwin_idle_timeout *timer; +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + fprintf(stdout, "interfaces found: %s\n", interface); + if (strcmp(interface, "org_kde_kwin_idle") == 0) { + idle_manager = wl_registry_bind(registry, name, &org_kde_kwin_idle_interface, 1); + } + else if (strcmp(interface, "wl_seat") == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { + //TODO +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +static void handle_idle(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "idle state\n"); +} + +static void handle_resume(void* data, struct org_kde_kwin_idle_timeout *timer) { + fprintf(stdout, "active state\n"); +} + +static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = { + .idle = handle_idle, + .resumed = handle_resume, +}; + +int parse_args(int argc, char *argv[]) { + int c; + while ((c = getopt(argc, argv, "c:hs:t:")) != -1) { + switch(c) + { + case 'c': + close_timeout = strtoul(optarg, NULL, 10); + break; + case 's': + simulate_activity_timeout = strtoul(optarg, NULL, 10); + break; + case 't': + timeout = strtoul(optarg, NULL, 10); + break; + case 'h': + case '?': + printf("Usage: %s [OPTIONS]\n", argv[0]); + printf(" -t seconds\t\t\tidle timeout in seconds\n"); + printf(" -s seconds optional\t\tsimulate user activity after x seconds\n"); + printf(" -c seconds optional\t\tclose program after x seconds\n"); + printf(" -h\t\t\t\tthis help menu\n"); + return 1; + default: + return 1; + } + } + return 0; +} + +void *simulate_activity(void *data) { + sleep(simulate_activity_timeout); + fprintf(stdout, "simulate user activity\n"); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_simulate_user_activity(arg->timer); + wl_display_roundtrip(arg->display); + return NULL; +} + +void *close_program(void *data) { + sleep(close_timeout); + struct thread_args *arg = data; + org_kde_kwin_idle_timeout_release(arg->timer); + wl_display_roundtrip(arg->display); + fprintf(stdout, "close program\n"); + run = 0; + return NULL; +} + +void *main_loop(void *data) { + struct wl_display *display = data; + while (wl_display_dispatch(display) != -1) { + ; + } + return NULL; +} + +int main(int argc, char *argv[]) { + + if (parse_args(argc, argv) != 0) { + return -1; + } + if (timeout == 0) { + printf("idle timeout 0 is invalid\n"); + return -1; + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (idle_manager == NULL) { + fprintf(stderr, "display doesn't support idle protocol\n"); + return -1; + } + if (seat== NULL) { + fprintf(stderr, "seat error\n"); + return -1; + } + struct org_kde_kwin_idle_timeout *timer = + org_kde_kwin_idle_get_idle_timeout(idle_manager, seat, timeout * 1000); + + if (timer == NULL) { + fprintf(stderr, "Could not create idle_timeout\n"); + return -1; + } + + pthread_t t1, t2, t3; + struct thread_args arg = { + .timer = timer, + .display = display, + }; + + if (simulate_activity_timeout != 0 && simulate_activity_timeout < close_timeout) { + if (pthread_create(&t1, NULL, &simulate_activity, (void *)&arg) != 0) { + return -1; + } + } + if (close_timeout != 0) { + if (pthread_create(&t2, NULL, &close_program, (void *)&arg) != 0) { + if (simulate_activity_timeout != 0) { + pthread_cancel(t1); + } + return -1; + } + } + + org_kde_kwin_idle_timeout_add_listener(timer, &idle_timer_listener, timer); + fprintf(stdout, "waiting\n"); + + if (pthread_create(&t3, NULL, &main_loop, (void *)display) != 0) { + if (simulate_activity_timeout != 0) { + pthread_cancel(t1); + } + if (close_timeout != 0 ) { + pthread_cancel(t2); + } + } + + if (simulate_activity_timeout != 0) { + pthread_join(t1, NULL); + } + if (close_timeout != 0) { + pthread_join(t2, NULL); + } + pthread_cancel(t3); + + wl_display_disconnect(display); + return 0; +} diff --git a/examples/meson.build b/examples/meson.build index af0f5a18..aa9eac47 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -5,6 +5,8 @@ lib_shared = static_library( include_directories: include_directories('support') ) +threads = dependency('threads') + executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared) executable('pointer', 'pointer.c', dependencies: wlroots, link_with: lib_shared) executable('touch', 'touch.c', dependencies: wlroots, link_with: lib_shared) @@ -32,3 +34,10 @@ executable( dependencies: [wayland_client, wlr_protos, wlroots], link_with: lib_shared, ) + +executable( + 'idle', + 'idle.c', + dependencies: [wayland_client, wlr_protos, wlroots, threads], + link_with: lib_shared, +) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 8d706b65..9dfd7b10 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -13,6 +13,7 @@ #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_screenshooter.h> #include <wlr/types/wlr_list.h> +#include <wlr/types/wlr_idle.h> #include "rootston/view.h" #include "rootston/config.h" @@ -44,6 +45,7 @@ struct roots_desktop { struct wlr_screenshooter *screenshooter; struct wlr_server_decoration_manager *server_decoration_manager; struct wlr_primary_selection_device_manager *primary_selection_device_manager; + struct wlr_idle *idle; struct wl_listener output_add; struct wl_listener output_remove; diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index b10ffee3..f89a6383 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -11,8 +11,12 @@ /** * Creates a new wlr_wl_backend. This backend will be created with no outputs; * you must use wlr_wl_output_create to add them. + * + * The `remote` argument is the name of the host compositor wayland socket. Set + * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 + * default) */ -struct wlr_backend *wlr_wl_backend_create(struct wl_display *display); +struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, const char *remote); /** * Adds a new output to this backend. You may remove outputs by destroying them. diff --git a/include/wlr/types/wlr_idle.h b/include/wlr/types/wlr_idle.h new file mode 100644 index 00000000..689c33a4 --- /dev/null +++ b/include/wlr/types/wlr_idle.h @@ -0,0 +1,51 @@ +#ifndef WLR_TYPES_WLR_IDLE_H +#define WLR_TYPES_WLR_IDLE_H + +#include <wayland-server.h> +#include <wlr/types/wlr_seat.h> + +/** + * Idle protocol is used to create timers which will notify the client when the + * compositor does not receive any input for a given time(in milliseconds). Also + * the client will be notify when the timer receve an activity notify and already + * was in idle state. Besides this, the client is able to simulate user activity + * which will reset the timers and at any time can destroy the timer. + */ + + +struct wlr_idle { + struct wl_global *wl_global; + struct wl_list idle_timers; // wlr_idle_timeout::link + struct wl_event_loop *event_loop; + + struct wl_listener display_destroy; + struct wl_signal activity_notify; + + void *data; +}; + +struct wlr_idle_timeout { + struct wl_resource *resource; + struct wl_list link; + struct wlr_seat *seat; + + struct wl_event_source *idle_source; + bool idle_state; + uint32_t timeout; // milliseconds + + struct wl_listener input_listener; + struct wl_listener seat_destroy; + + void *data; +}; + +struct wlr_idle *wlr_idle_create(struct wl_display *display); + +void wlr_idle_destroy(struct wlr_idle *idle); + +/** + * Send notification to restart all timers for the given seat. Called by + * compositor when there is an user activity event on that seat. + */ +void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat); +#endif diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index b6671de1..c0135943 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -98,9 +98,12 @@ struct wlr_xwayland_surface { char *title; char *class; char *instance; - struct wlr_xwayland_surface *parent; pid_t pid; + struct wl_list children; // wlr_xwayland_surface::parent_link + struct wlr_xwayland_surface *parent; + struct wl_list parent_link; // wlr_xwayland_surface::children + xcb_atom_t *window_type; size_t window_type_len; diff --git a/meson.build b/meson.build index f6ffff40..aee4b11b 100644 --- a/meson.build +++ b/meson.build @@ -159,7 +159,6 @@ subdir('examples') pkgconfig = import('pkgconfig') pkgconfig.generate( libraries: lib_wlr, - subdirs: '@0@'.format(meson.project_name()), version: meson.project_version(), filebase: meson.project_name(), name: meson.project_name(), diff --git a/protocol/idle.xml b/protocol/idle.xml new file mode 100644 index 00000000..92d9989c --- /dev/null +++ b/protocol/idle.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="idle"> + <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_idle" version="1"> + <description summary="User idle time manager"> + This interface allows to monitor user idle time on a given seat. The interface + allows to register timers which trigger after no user activity was registered + on the seat for a given interval. It notifies when user activity resumes. + + This is useful for applications wanting to perform actions when the user is not + interacting with the system, e.g. chat applications setting the user as away, power + management features to dim screen, etc.. + </description> + <request name="get_idle_timeout"> + <arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/> + <arg name="seat" type="object" interface="wl_seat"/> + <arg name="timeout" type="uint" summary="The idle timeout in msec"/> + </request> + </interface> + <interface name="org_kde_kwin_idle_timeout" version="1"> + <request name="release" type="destructor"> + <description summary="release the timeout object"/> + </request> + <request name="simulate_user_activity"> + <description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/> + </request> + <event name="idle"> + <description summary="Triggered when there has not been any user activity in the requested idle time interval"/> + </event> + <event name="resumed"> + <description summary="Triggered on the first user activity after an idle event"/> + </event> + </interface> +</protocol> diff --git a/protocol/meson.build b/protocol/meson.build index f6aca5f5..6e9f4125 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -26,6 +26,7 @@ protocols = [ 'gtk-primary-selection.xml', 'screenshooter.xml', 'server-decoration.xml', + 'idle.xml', ] client_protocols = [ @@ -34,6 +35,7 @@ client_protocols = [ 'gtk-primary-selection.xml', 'screenshooter.xml', 'server-decoration.xml', + 'idle.xml', ] wl_protos_src = [] diff --git a/rootston/desktop.c b/rootston/desktop.c index b74e2cb1..d7da1600 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -8,6 +8,7 @@ #include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_output_layout.h> @@ -502,6 +503,7 @@ struct roots_desktop *desktop_create(struct roots_server *server, WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); desktop->primary_selection_device_manager = wlr_primary_selection_device_manager_create(server->wl_display); + desktop->idle = wlr_idle_create(server->wl_display); return desktop; } diff --git a/rootston/main.c b/rootston/main.c index 46ec3671..a327576a 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -37,7 +37,6 @@ int main(int argc, char **argv) { if (server.backend == NULL) { wlr_log(L_ERROR, "could not start backend"); - wlr_backend_destroy(server.backend); return 1; } diff --git a/rootston/output.c b/rootston/output.c index a8866fa6..c26ea36e 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -169,6 +169,19 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, } } +static void render_xwayland_children(struct wlr_xwayland_surface *surface, + struct roots_desktop *desktop, struct wlr_output *wlr_output, + struct timespec *when) { + struct wlr_xwayland_surface *child; + wl_list_for_each(child, &surface->children, parent_link) { + if (child->surface != NULL && child->added) { + render_surface(child->surface, desktop, wlr_output, when, + child->x, child->y, 0); + } + render_xwayland_children(child, desktop, wlr_output, when); + } +} + static void render_view(struct roots_view *view, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when) { switch (view->type) { @@ -200,7 +213,7 @@ static bool has_standalone_surface(struct roots_view *view) { case ROOTS_WL_SHELL_VIEW: return wl_list_empty(&view->wl_shell_surface->popups); case ROOTS_XWAYLAND_VIEW: - return true; + return wl_list_empty(&view->xwayland_surface->children); } return true; } @@ -222,27 +235,36 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { wlr_renderer_begin(server->renderer, wlr_output); if (output->fullscreen_view != NULL) { + struct roots_view *view = output->fullscreen_view; + // Make sure the view is centered on screen const struct wlr_box *output_box = wlr_output_layout_get_box(desktop->layout, wlr_output); struct wlr_box view_box; - view_get_box(output->fullscreen_view, &view_box); + view_get_box(view, &view_box); double view_x = (double)(output_box->width - view_box.width) / 2 + output_box->x; double view_y = (double)(output_box->height - view_box.height) / 2 + output_box->y; - view_move(output->fullscreen_view, view_x, view_y); + view_move(view, view_x, view_y); - if (has_standalone_surface(output->fullscreen_view)) { - wlr_output_set_fullscreen_surface(wlr_output, - output->fullscreen_view->wlr_surface); + if (has_standalone_surface(view)) { + wlr_output_set_fullscreen_surface(wlr_output, view->wlr_surface); } else { wlr_output_set_fullscreen_surface(wlr_output, NULL); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - render_view(output->fullscreen_view, desktop, wlr_output, &now); + render_view(view, desktop, wlr_output, &now); + + // During normal rendering the xwayland window tree isn't traversed + // because all windows are rendered. Here we only want to render + // the fullscreen window's children so we have to traverse the tree. + if (view->type == ROOTS_XWAYLAND_VIEW) { + render_xwayland_children(view->xwayland_surface, desktop, + wlr_output, &now); + } } wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output); diff --git a/rootston/seat.c b/rootston/seat.c index 2728ca96..130c7b27 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -5,6 +5,7 @@ #include <wlr/config.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/util/log.h> +#include <wlr/types/wlr_idle.h> #include "rootston/xcursor.h" #include "rootston/input.h" #include "rootston/seat.h" @@ -14,6 +15,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_key); + struct roots_desktop *desktop = keyboard->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); struct wlr_event_keyboard_key *event = data; roots_keyboard_handle_key(keyboard, event); } @@ -22,12 +25,16 @@ static void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_modifiers); + struct roots_desktop *desktop = keyboard->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); roots_keyboard_handle_modifiers(keyboard); } static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, motion); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_motion *event = data; roots_cursor_handle_motion(cursor, event); } @@ -36,6 +43,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, motion_absolute); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_motion_absolute *event = data; roots_cursor_handle_motion_absolute(cursor, event); } @@ -43,6 +52,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, static void handle_cursor_button(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, button); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_button *event = data; roots_cursor_handle_button(cursor, event); } @@ -50,6 +61,8 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, axis); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_pointer_axis *event = data; roots_cursor_handle_axis(cursor, event); } @@ -57,6 +70,8 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { static void handle_touch_down(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_down); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_down *event = data; roots_cursor_handle_touch_down(cursor, event); } @@ -64,6 +79,8 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { static void handle_touch_up(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_up); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_up *event = data; roots_cursor_handle_touch_up(cursor, event); } @@ -71,6 +88,8 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { static void handle_touch_motion(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, touch_motion); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_touch_motion *event = data; roots_cursor_handle_touch_motion(cursor, event); } @@ -78,6 +97,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { static void handle_tool_axis(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, tool_axis); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_tablet_tool_axis *event = data; roots_cursor_handle_tool_axis(cursor, event); } @@ -85,6 +106,8 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) { static void handle_tool_tip(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, tool_tip); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_event_tablet_tool_tip *event = data; roots_cursor_handle_tool_tip(cursor, event); } @@ -93,6 +116,8 @@ static void handle_request_set_cursor(struct wl_listener *listener, void *data) { struct roots_cursor *cursor = wl_container_of(listener, cursor, request_set_cursor); + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); struct wlr_seat_pointer_request_set_cursor_event *event = data; roots_cursor_handle_request_set_cursor(cursor, event); } diff --git a/types/meson.build b/types/meson.build index 82031e89..62a2faec 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,6 +6,7 @@ lib_wlr_types = static_library( 'wlr_compositor.c', 'wlr_cursor.c', 'wlr_gamma_control.c', + 'wlr_idle.c', 'wlr_input_device.c', 'wlr_keyboard.c', 'wlr_list.c', diff --git a/types/wlr_idle.c b/types/wlr_idle.c new file mode 100644 index 00000000..f2cad42b --- /dev/null +++ b/types/wlr_idle.c @@ -0,0 +1,190 @@ +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-server.h> +#include <wlr/types/wlr_idle.h> +#include <wlr/util/log.h> +#include "idle-protocol.h" + +static void idle_timeout_destroy(struct wlr_idle_timeout *timer) { + wl_list_remove(&timer->input_listener.link); + wl_list_remove(&timer->seat_destroy.link); + wl_event_source_remove(timer->idle_source); + wl_list_remove(&timer->link); + wl_resource_set_user_data(timer->resource, NULL); + free(timer); +} + +static int idle_notify(void *data) { + struct wlr_idle_timeout *timer = data; + timer->idle_state = true; + org_kde_kwin_idle_timeout_send_idle(timer->resource); + return 1; +} + +static void handle_activity(struct wlr_idle_timeout *timer) { + // rearm the timer + wl_event_source_timer_update(timer->idle_source, timer->timeout); + // in case the previous state was sleeping send a resume event and switch state + if (timer->idle_state) { + timer->idle_state = false; + org_kde_kwin_idle_timeout_send_resumed(timer->resource); + } +} + +static void handle_timer_resource_destroy(struct wl_resource *timer_resource) { + struct wlr_idle_timeout *timer = wl_resource_get_user_data(timer_resource); + if (timer != NULL) { + idle_timeout_destroy(timer); + } +} + +static void handle_seat_destroy(struct wl_listener *listener, void *data) { + struct wlr_idle_timeout *timer = wl_container_of(listener, timer, seat_destroy); + if (timer != NULL) { + idle_timeout_destroy(timer); + } +} + +static void release_idle_timeout(struct wl_client *client, + struct wl_resource *resource){ + handle_timer_resource_destroy(resource); +} + +static void simulate_activity(struct wl_client *client, + struct wl_resource *resource){ + struct wlr_idle_timeout *timer = wl_resource_get_user_data(resource); + handle_activity(timer); +} + +static struct org_kde_kwin_idle_timeout_interface idle_timeout_impl = { + .release = release_idle_timeout, + .simulate_user_activity = simulate_activity, +}; + +static void handle_input_notification(struct wl_listener *listener, void *data) { + struct wlr_idle_timeout *timer = wl_container_of(listener, timer, input_listener); + struct wlr_seat *seat = data; + if (timer->seat == seat) { + handle_activity(timer); + } +} + +static void create_idle_timer(struct wl_client *client, + struct wl_resource *idle_resource, + uint32_t id, + struct wl_resource *seat_resource, + uint32_t timeout) { + struct wlr_idle *idle = wl_resource_get_user_data(idle_resource); + struct wlr_seat_client *client_seat = + wl_resource_get_user_data(seat_resource); + + struct wlr_idle_timeout *timer = + calloc(1, sizeof(struct wlr_idle_timeout)); + if (!timer) { + wl_resource_post_no_memory(idle_resource); + return; + } + timer->seat = client_seat->seat; + timer->timeout = timeout; + timer->idle_state = false; + timer->resource = wl_resource_create(client, + &org_kde_kwin_idle_timeout_interface, + wl_resource_get_version(idle_resource), id); + if (timer->resource == NULL) { + free(timer); + wl_resource_post_no_memory(idle_resource); + return; + } + wl_resource_set_implementation(timer->resource, &idle_timeout_impl, timer, + handle_timer_resource_destroy); + wl_list_insert(&idle->idle_timers, &timer->link); + + timer->seat_destroy.notify = handle_seat_destroy; + wl_signal_add(&timer->seat->events.destroy, &timer->seat_destroy); + + timer->input_listener.notify = handle_input_notification; + wl_signal_add(&idle->activity_notify, &timer->input_listener); + // create the timer + timer->idle_source = + wl_event_loop_add_timer(idle->event_loop, idle_notify, timer); + if (timer->idle_source == NULL) { + wl_list_remove(&timer->link); + wl_list_remove(&timer->input_listener.link); + wl_list_remove(&timer->seat_destroy.link); + wl_resource_set_user_data(timer->resource, NULL); + free(timer); + wl_resource_post_no_memory(idle_resource); + return; + } + // arm the timer + wl_event_source_timer_update(timer->idle_source, timer->timeout); +} + +static struct org_kde_kwin_idle_interface idle_impl = { + .get_idle_timeout = create_idle_timer, +}; + +static void idle_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_idle *idle = data; + assert(wl_client && idle); + + struct wl_resource *wl_resource = wl_resource_create(wl_client, + &org_kde_kwin_idle_interface, version, id); + if (wl_resource == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(wl_resource, &idle_impl, idle, NULL); +} + +void wlr_idle_destroy(struct wlr_idle *idle) { + if (!idle) { + return; + } + wl_list_remove(&idle->display_destroy.link); + struct wlr_idle_timeout *timer, *tmp; + wl_list_for_each_safe(timer, tmp, &idle->idle_timers, link) { + idle_timeout_destroy(timer); + } + wl_global_destroy(idle->wl_global); + free(idle); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_idle *idle = wl_container_of(listener, idle, display_destroy); + wlr_idle_destroy(idle); +} + +struct wlr_idle *wlr_idle_create(struct wl_display *display) { + struct wlr_idle *idle = calloc(1, sizeof(struct wlr_idle)); + if (!idle) { + return NULL; + } + wl_list_init(&idle->idle_timers); + wl_signal_init(&idle->activity_notify); + + idle->event_loop = wl_display_get_event_loop(display); + if (idle->event_loop == NULL) { + free(idle); + return NULL; + } + + idle->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &idle->display_destroy); + + idle->wl_global = wl_global_create(display, &org_kde_kwin_idle_interface, + 1, idle, idle_bind); + if (idle->wl_global == NULL){ + wl_list_remove(&idle->display_destroy.link); + free(idle); + return NULL; + } + wlr_log(L_DEBUG, "idle manager created"); + return idle; +} + +void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat) { + wl_signal_emit(&idle->activity_notify, seat); +} diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 79638822..fd76775d 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -794,6 +794,7 @@ void wlr_seat_set_keyboard(struct wlr_seat *seat, } seat->keyboard_state.keyboard = keyboard; + wlr_seat_keyboard_send_modifiers(seat); } void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat, diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 53aac6a4..dc349ab2 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -96,6 +96,8 @@ static struct wlr_xwayland_surface *wlr_xwayland_surface_create( surface->height = height; surface->override_redirect = override_redirect; wl_list_insert(&xwm->surfaces, &surface->link); + wl_list_init(&surface->children); + wl_list_init(&surface->parent_link); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.request_configure); wl_signal_init(&surface->events.request_move); @@ -215,6 +217,7 @@ static void wlr_xwayland_surface_destroy( } wl_list_remove(&xsurface->link); + wl_list_remove(&xsurface->parent_link); if (xsurface->surface_id) { wl_list_remove(&xsurface->unpaired_link); @@ -305,6 +308,13 @@ static void read_surface_parent(struct wlr_xwm *xwm, xsurface->parent = NULL; } + wl_list_remove(&xsurface->parent_link); + if (xsurface->parent != NULL) { + wl_list_insert(&xsurface->parent->children, &xsurface->parent_link); + } else { + wl_list_init(&xsurface->parent_link); + } + wlr_log(L_DEBUG, "XCB_ATOM_WM_TRANSIENT_FOR: %p", xid); wl_signal_emit(&xsurface->events.set_parent, xsurface); } |