diff options
Diffstat (limited to 'sway/lock.c')
-rw-r--r-- | sway/lock.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/sway/lock.c b/sway/lock.c new file mode 100644 index 00000000..04f80079 --- /dev/null +++ b/sway/lock.c | |||
@@ -0,0 +1,184 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <assert.h> | ||
3 | #include "log.h" | ||
4 | #include "sway/input/keyboard.h" | ||
5 | #include "sway/input/seat.h" | ||
6 | #include "sway/output.h" | ||
7 | #include "sway/server.h" | ||
8 | |||
9 | struct sway_session_lock_surface { | ||
10 | struct wlr_session_lock_surface_v1 *lock_surface; | ||
11 | struct sway_output *output; | ||
12 | struct wlr_surface *surface; | ||
13 | struct wl_listener map; | ||
14 | struct wl_listener destroy; | ||
15 | struct wl_listener surface_commit; | ||
16 | struct wl_listener output_mode; | ||
17 | struct wl_listener output_commit; | ||
18 | }; | ||
19 | |||
20 | static void handle_surface_map(struct wl_listener *listener, void *data) { | ||
21 | struct sway_session_lock_surface *surf = wl_container_of(listener, surf, map); | ||
22 | sway_force_focus(surf->surface); | ||
23 | output_damage_whole(surf->output); | ||
24 | } | ||
25 | |||
26 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | ||
27 | struct sway_session_lock_surface *surf = wl_container_of(listener, surf, surface_commit); | ||
28 | output_damage_surface(surf->output, 0, 0, surf->surface, false); | ||
29 | } | ||
30 | |||
31 | static void handle_output_mode(struct wl_listener *listener, void *data) { | ||
32 | struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_mode); | ||
33 | wlr_session_lock_surface_v1_configure(surf->lock_surface, | ||
34 | surf->output->width, surf->output->height); | ||
35 | } | ||
36 | |||
37 | static void handle_output_commit(struct wl_listener *listener, void *data) { | ||
38 | struct wlr_output_event_commit *event = data; | ||
39 | struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_commit); | ||
40 | if (event->committed & ( | ||
41 | WLR_OUTPUT_STATE_MODE | | ||
42 | WLR_OUTPUT_STATE_SCALE | | ||
43 | WLR_OUTPUT_STATE_TRANSFORM)) { | ||
44 | wlr_session_lock_surface_v1_configure(surf->lock_surface, | ||
45 | surf->output->width, surf->output->height); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static void handle_surface_destroy(struct wl_listener *listener, void *data) { | ||
50 | struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy); | ||
51 | wl_list_remove(&surf->map.link); | ||
52 | wl_list_remove(&surf->destroy.link); | ||
53 | wl_list_remove(&surf->surface_commit.link); | ||
54 | wl_list_remove(&surf->output_mode.link); | ||
55 | wl_list_remove(&surf->output_commit.link); | ||
56 | output_damage_whole(surf->output); | ||
57 | free(surf); | ||
58 | } | ||
59 | |||
60 | static void handle_new_surface(struct wl_listener *listener, void *data) { | ||
61 | struct wlr_session_lock_surface_v1 *lock_surface = data; | ||
62 | struct sway_session_lock_surface *surf = calloc(1, sizeof(*surf)); | ||
63 | if (surf == NULL) { | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | sway_log(SWAY_DEBUG, "new lock layer surface"); | ||
68 | |||
69 | struct sway_output *output = lock_surface->output->data; | ||
70 | wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height); | ||
71 | |||
72 | surf->lock_surface = lock_surface; | ||
73 | surf->surface = lock_surface->surface; | ||
74 | surf->output = output; | ||
75 | surf->map.notify = handle_surface_map; | ||
76 | wl_signal_add(&lock_surface->events.map, &surf->map); | ||
77 | surf->destroy.notify = handle_surface_destroy; | ||
78 | wl_signal_add(&lock_surface->events.destroy, &surf->destroy); | ||
79 | surf->surface_commit.notify = handle_surface_commit; | ||
80 | wl_signal_add(&surf->surface->events.commit, &surf->surface_commit); | ||
81 | surf->output_mode.notify = handle_output_mode; | ||
82 | wl_signal_add(&output->wlr_output->events.mode, &surf->output_mode); | ||
83 | surf->output_commit.notify = handle_output_commit; | ||
84 | wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit); | ||
85 | } | ||
86 | |||
87 | static void handle_unlock(struct wl_listener *listener, void *data) { | ||
88 | sway_log(SWAY_DEBUG, "session unlocked"); | ||
89 | server.session_lock.locked = false; | ||
90 | server.session_lock.lock = NULL; | ||
91 | |||
92 | wl_list_remove(&server.session_lock.lock_new_surface.link); | ||
93 | wl_list_remove(&server.session_lock.lock_unlock.link); | ||
94 | wl_list_remove(&server.session_lock.lock_destroy.link); | ||
95 | |||
96 | struct sway_seat *seat; | ||
97 | wl_list_for_each(seat, &server.input->seats, link) { | ||
98 | seat_set_exclusive_client(seat, NULL); | ||
99 | // copied from seat_set_focus_layer -- deduplicate? | ||
100 | struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); | ||
101 | if (previous) { | ||
102 | // Hack to get seat to re-focus the return value of get_focus | ||
103 | seat_set_focus(seat, NULL); | ||
104 | seat_set_focus(seat, previous); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | // redraw everything | ||
109 | for (int i = 0; i < root->outputs->length; ++i) { | ||
110 | struct sway_output *output = root->outputs->items[i]; | ||
111 | output_damage_whole(output); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void handle_abandon(struct wl_listener *listener, void *data) { | ||
116 | sway_log(SWAY_INFO, "session lock abandoned"); | ||
117 | server.session_lock.lock = NULL; | ||
118 | |||
119 | wl_list_remove(&server.session_lock.lock_new_surface.link); | ||
120 | wl_list_remove(&server.session_lock.lock_unlock.link); | ||
121 | wl_list_remove(&server.session_lock.lock_destroy.link); | ||
122 | |||
123 | struct sway_seat *seat; | ||
124 | wl_list_for_each(seat, &server.input->seats, link) { | ||
125 | seat->exclusive_client = NULL; | ||
126 | } | ||
127 | |||
128 | // redraw everything | ||
129 | for (int i = 0; i < root->outputs->length; ++i) { | ||
130 | struct sway_output *output = root->outputs->items[i]; | ||
131 | output_damage_whole(output); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static void handle_session_lock(struct wl_listener *listener, void *data) { | ||
136 | struct wlr_session_lock_v1 *lock = data; | ||
137 | struct wl_client *client = wl_resource_get_client(lock->resource); | ||
138 | |||
139 | if (server.session_lock.lock) { | ||
140 | wlr_session_lock_v1_destroy(lock); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | sway_log(SWAY_DEBUG, "session locked"); | ||
145 | server.session_lock.locked = true; | ||
146 | server.session_lock.lock = lock; | ||
147 | |||
148 | struct sway_seat *seat; | ||
149 | wl_list_for_each(seat, &server.input->seats, link) { | ||
150 | seat_set_exclusive_client(seat, client); | ||
151 | } | ||
152 | |||
153 | wl_signal_add(&lock->events.new_surface, &server.session_lock.lock_new_surface); | ||
154 | wl_signal_add(&lock->events.unlock, &server.session_lock.lock_unlock); | ||
155 | wl_signal_add(&lock->events.destroy, &server.session_lock.lock_destroy); | ||
156 | |||
157 | wlr_session_lock_v1_send_locked(lock); | ||
158 | |||
159 | // redraw everything | ||
160 | for (int i = 0; i < root->outputs->length; ++i) { | ||
161 | struct sway_output *output = root->outputs->items[i]; | ||
162 | output_damage_whole(output); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static void handle_session_lock_destroy(struct wl_listener *listener, void *data) { | ||
167 | assert(server.session_lock.lock == NULL); | ||
168 | wl_list_remove(&server.session_lock.new_lock.link); | ||
169 | wl_list_remove(&server.session_lock.manager_destroy.link); | ||
170 | } | ||
171 | |||
172 | void sway_session_lock_init(void) { | ||
173 | server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display); | ||
174 | |||
175 | server.session_lock.lock_new_surface.notify = handle_new_surface; | ||
176 | server.session_lock.lock_unlock.notify = handle_unlock; | ||
177 | server.session_lock.lock_destroy.notify = handle_abandon; | ||
178 | server.session_lock.new_lock.notify = handle_session_lock; | ||
179 | server.session_lock.manager_destroy.notify = handle_session_lock_destroy; | ||
180 | wl_signal_add(&server.session_lock.manager->events.new_lock, | ||
181 | &server.session_lock.new_lock); | ||
182 | wl_signal_add(&server.session_lock.manager->events.destroy, | ||
183 | &server.session_lock.manager_destroy); | ||
184 | } | ||