chiark / gitweb /
abdb1bc48103ae26eb83a84204c31f441a02c1fa
[elogind.git] / src / console / consoled-session.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <libudev.h>
25 #include <stdlib.h>
26 #include "consoled.h"
27 #include "grdev.h"
28 #include "hashmap.h"
29 #include "idev.h"
30 #include "list.h"
31 #include "macro.h"
32 #include "sd-bus.h"
33 #include "sd-event.h"
34 #include "sysview.h"
35 #include "util.h"
36
37 static bool session_feed_keyboard(Session *s, idev_data *data) {
38         idev_data_keyboard *kdata = &data->keyboard;
39
40         if (!data->resync && kdata->value == 1 && kdata->n_syms == 1) {
41                 uint32_t nr;
42                 sysview_seat *seat;
43
44                 /* handle VT-switch requests */
45                 nr = 0;
46
47                 switch (kdata->keysyms[0]) {
48                 case XKB_KEY_F1 ... XKB_KEY_F12:
49                         if (IDEV_KBDMATCH(kdata,
50                                           IDEV_KBDMOD_CTRL | IDEV_KBDMOD_ALT,
51                                           kdata->keysyms[0]))
52                                 nr = kdata->keysyms[0] - XKB_KEY_F1 + 1;
53                         break;
54                 case XKB_KEY_XF86Switch_VT_1 ... XKB_KEY_XF86Switch_VT_12:
55                         nr = kdata->keysyms[0] - XKB_KEY_XF86Switch_VT_1 + 1;
56                         break;
57                 }
58
59                 if (nr != 0) {
60                         seat = sysview_session_get_seat(s->sysview);
61                         sysview_seat_switch_to(seat, nr);
62                         return true;
63                 }
64         }
65
66         return false;
67 }
68
69 static bool session_feed(Session *s, idev_data *data) {
70         switch (data->type) {
71         case IDEV_DATA_KEYBOARD:
72                 return session_feed_keyboard(s, data);
73         default:
74                 return false;
75         }
76 }
77
78 static int session_idev_fn(idev_session *idev, void *userdata, idev_event *event) {
79         Session *s = userdata;
80
81         switch (event->type) {
82         case IDEV_EVENT_DEVICE_ADD:
83                 idev_device_enable(event->device_add.device);
84                 break;
85         case IDEV_EVENT_DEVICE_REMOVE:
86                 idev_device_disable(event->device_remove.device);
87                 break;
88         case IDEV_EVENT_DEVICE_DATA:
89                 if (!session_feed(s, &event->device_data.data))
90                         workspace_feed(s->active_ws, &event->device_data.data);
91                 break;
92         }
93
94         return 0;
95 }
96
97 static void session_grdev_fn(grdev_session *grdev, void *userdata, grdev_event *event) {
98         grdev_display *display;
99         Session *s = userdata;
100         Display *d;
101         int r;
102
103         switch (event->type) {
104         case GRDEV_EVENT_DISPLAY_ADD:
105                 display = event->display_add.display;
106
107                 r = display_new(&d, s, display);
108                 if (r < 0) {
109                         log_error("Cannot create display '%s' on '%s': %s",
110                                   grdev_display_get_name(display), sysview_session_get_name(s->sysview), strerror(-r));
111                         break;
112                 }
113
114                 grdev_display_set_userdata(display, d);
115                 workspace_refresh(s->active_ws);
116                 break;
117         case GRDEV_EVENT_DISPLAY_REMOVE:
118                 display = event->display_remove.display;
119                 d = grdev_display_get_userdata(display);
120                 if (!d)
121                         break;
122
123                 display_free(d);
124                 workspace_refresh(s->active_ws);
125                 break;
126         case GRDEV_EVENT_DISPLAY_CHANGE:
127                 display = event->display_remove.display;
128                 d = grdev_display_get_userdata(display);
129                 if (!d)
130                         break;
131
132                 display_refresh(d);
133                 workspace_refresh(s->active_ws);
134                 break;
135         case GRDEV_EVENT_DISPLAY_FRAME:
136                 display = event->display_remove.display;
137                 d = grdev_display_get_userdata(display);
138                 if (!d)
139                         break;
140
141                 session_dirty(s);
142                 break;
143         }
144 }
145
146 static int session_redraw_fn(sd_event_source *src, void *userdata) {
147         Session *s = userdata;
148         Display *d;
149
150         LIST_FOREACH(displays_by_session, d, s->display_list)
151                 display_render(d, s->active_ws);
152
153         grdev_session_commit(s->grdev);
154
155         return 0;
156 }
157
158 int session_new(Session **out, Manager *m, sysview_session *session) {
159         _cleanup_(session_freep) Session *s = NULL;
160         int r;
161
162         assert(out);
163         assert(m);
164         assert(session);
165
166         s = new0(Session, 1);
167         if (!s)
168                 return -ENOMEM;
169
170         s->manager = m;
171         s->sysview = session;
172
173         r = grdev_session_new(&s->grdev,
174                               m->grdev,
175                               GRDEV_SESSION_MANAGED,
176                               sysview_session_get_name(session),
177                               session_grdev_fn,
178                               s);
179         if (r < 0)
180                 return r;
181
182         r = idev_session_new(&s->idev,
183                              m->idev,
184                              IDEV_SESSION_MANAGED,
185                              sysview_session_get_name(session),
186                              session_idev_fn,
187                              s);
188         if (r < 0)
189                 return r;
190
191         r = workspace_new(&s->my_ws, m);
192         if (r < 0)
193                 return r;
194
195         s->active_ws = workspace_attach(s->my_ws, s);
196
197         r = sd_event_add_defer(m->event, &s->redraw_src, session_redraw_fn, s);
198         if (r < 0)
199                 return r;
200
201         grdev_session_enable(s->grdev);
202         idev_session_enable(s->idev);
203
204         *out = s;
205         s = NULL;
206         return 0;
207 }
208
209 Session *session_free(Session *s) {
210         if (!s)
211                 return NULL;
212
213         assert(!s->display_list);
214
215         sd_event_source_unref(s->redraw_src);
216
217         workspace_detach(s->active_ws, s);
218         workspace_unref(s->my_ws);
219
220         idev_session_free(s->idev);
221         grdev_session_free(s->grdev);
222         free(s);
223
224         return NULL;
225 }
226
227 void session_dirty(Session *s) {
228         int r;
229
230         assert(s);
231
232         r = sd_event_source_set_enabled(s->redraw_src, SD_EVENT_ONESHOT);
233         if (r < 0)
234                 log_error_errno(-r, "Cannot enable redraw-source: %m");
235 }
236
237 void session_add_device(Session *s, sysview_device *device) {
238         unsigned int type;
239
240         assert(s);
241         assert(device);
242
243         type = sysview_device_get_type(device);
244         switch (type) {
245         case SYSVIEW_DEVICE_DRM:
246                 grdev_session_add_drm(s->grdev, sysview_device_get_ud(device));
247                 break;
248         case SYSVIEW_DEVICE_EVDEV:
249                 idev_session_add_evdev(s->idev, sysview_device_get_ud(device));
250                 break;
251         }
252 }
253
254 void session_remove_device(Session *s, sysview_device *device) {
255         unsigned int type;
256
257         assert(s);
258         assert(device);
259
260         type = sysview_device_get_type(device);
261         switch (type) {
262         case SYSVIEW_DEVICE_DRM:
263                 grdev_session_remove_drm(s->grdev, sysview_device_get_ud(device));
264                 break;
265         case SYSVIEW_DEVICE_EVDEV:
266                 idev_session_remove_evdev(s->idev, sysview_device_get_ud(device));
267                 break;
268         }
269 }
270
271 void session_refresh_device(Session *s, sysview_device *device, struct udev_device *ud) {
272         unsigned int type;
273
274         assert(s);
275         assert(device);
276
277         type = sysview_device_get_type(device);
278         switch (type) {
279         case SYSVIEW_DEVICE_DRM:
280                 grdev_session_hotplug_drm(s->grdev, sysview_device_get_ud(device));
281                 break;
282         }
283 }