Use ds_tizen_keyrouter
[platform/core/uifw/headless-server.git] / src / headless_server.c
1 /*
2  * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <signal.h>
30 #include <time.h>
31
32 #include <dlog.h>
33 #include <tbm_bufmgr.h>
34
35 #include <headless_server.h>
36
37 int use_output = 1;
38
39 static void server_handle_new_shell_surface(struct wl_listener *listener, void *data);
40
41 static int
42 handle_sigint(int signal_number, void *data)
43 {
44         struct wl_display *display = (struct wl_display *)data;
45         wl_display_terminate(display);
46
47         return 0;
48 }
49
50 static bool
51 init_signal(struct wl_display *display)
52 {
53         struct wl_event_loop *loop;
54         struct wl_event_source *sigint;
55
56         loop = wl_display_get_event_loop(display);
57         sigint = wl_event_loop_add_signal(loop, SIGINT, handle_sigint, display);
58         if (!sigint)
59                 return false;
60
61         return true;
62 }
63
64 static int
65 dlog_level_from_ds_log_level(enum ds_log_level level)
66 {
67         switch (level) {
68                 case DS_INF:
69                         return DLOG_INFO;
70                 case DS_DBG:
71                         return DLOG_DEBUG;
72                 default:
73                 case DS_ERR:
74                         return DLOG_ERROR;
75         }
76 }
77
78 static void
79 handle_ds_log(enum ds_log_level level, const char *fmt, va_list args)
80 {
81         dlog_vprint(dlog_level_from_ds_log_level(level), "HEADLESS_SERVER",
82                         fmt, args);
83 }
84
85 int main(int argc, char *argv[])
86 {
87         headless_server_t server = { 0, };
88         const char *socket_name = NULL;
89         bool ret;
90         tbm_bufmgr bufmgr = NULL;
91
92         /* set STDOUT/STDERR bufferless */
93         setvbuf(stdout, NULL, _IONBF, 0);
94         setvbuf(stderr, NULL, _IONBF, 0);
95
96         if (getenv("HEADLESS_SERVER_DLOG_ENABLE")) {
97                 HEADLESS_TRACE("ds log will be written to dlog !\n");
98                 ds_log_init(DS_INF, handle_ds_log);
99         }
100
101         socket_name = getenv("WAYLAND_DISPLAY");
102
103         if (!socket_name)
104                 socket_name = "wayland-0";
105
106         if (!getenv("XDG_RUNTIME_DIR"))
107                 setenv("XDG_RUNTIME_DIR", "/run", 1);
108
109         if(!getenv("RUN_WITH_SPEAKER"))
110         {
111                 use_output = 0;
112         }
113
114         server.display = wl_display_create();
115         if (!server.display) {
116                 ds_err("Could not create wl_display");
117                 return EXIT_FAILURE;
118         }
119
120         wl_list_init(&server.views);
121
122         wl_signal_init(&server.events.focus_change);
123         wl_signal_init(&server.events.top_change);
124
125         server.compositor = ds_compositor_create(server.display);
126         HEADLESS_CHECK(server.compositor, goto end, "Failed to create ds_compositor");
127
128         server.tbm_server = ds_tbm_server_create(server.display);
129         HEADLESS_CHECK(server.tbm_server, goto end, "Failed to create ds_tbm_server");
130
131         /* Init event trace */
132         server.debug = headless_debug_create(&server);
133         HEADLESS_CHECK(server.debug, goto end, "headless_debug_create() failed\n");
134
135         /* Init input for headless */
136         server.input = headless_input_create(&server);
137         HEADLESS_CHECK(server.input, goto end, "headless_input_create() failed\n");
138
139         /* Init Output */
140         if(use_output)
141         {
142                 server.output = headless_output_create(server.display);
143                 HEADLESS_CHECK(server.output, goto end, "headless_output_create() failed.");
144
145                 headless_output_start_boot_ani(server.output);
146                 server.boot_animating = true;
147         }
148         else {
149                 bufmgr = tbm_bufmgr_server_init();
150                 HEADLESS_CHECK(bufmgr, goto end, "Failed to init tbm buffer manager !\n");
151                 ret = tbm_bufmgr_bind_native_display(bufmgr, (void *)server.display);
152                 HEADLESS_CHECK(ret, goto end, "Failed to bind native display with tbm buffer manager !\n");
153         }
154
155         /* Init Shell */
156         server.shell = headless_shell_create(server.display);
157         HEADLESS_CHECK(server.shell, goto end, "headless_shell_create() failed.\n");
158
159         server.new_shell_surface.notify = server_handle_new_shell_surface;
160         headless_shell_add_new_surface_listener(server.shell, &server.new_shell_surface);
161
162         /* Init Signal for SIGINT */
163         init_signal(server.display);
164
165         server.name = wl_display_add_socket_auto(server.display);
166         HEADLESS_CHECK(server.name, goto end, "Could not add socket for wayland");
167
168         setenv("WAYLAND_DISPLAY", server.name, true);
169
170         ds_inf("Running headless server on WAYLAND_DISPLAY=%s", server.name);
171
172         /* run event loop */
173         wl_display_run(server.display);
174
175 end:
176         /* Deinit Process */
177         if (server.shell)
178                 headless_shell_destroy(server.shell);
179
180         if(use_output && server.output)
181                 headless_output_destroy(server.output);
182         if (bufmgr)
183         {
184                 tbm_bufmgr_deinit(bufmgr);
185                 bufmgr = NULL;
186         }
187
188         if (server.debug)
189                 headless_debug_destroy(server.debug);
190
191         if (server.input)
192                 headless_input_destroy(server.input);
193
194         wl_display_destroy_clients(server.display);
195         wl_display_destroy(server.display);
196
197         return EXIT_SUCCESS;
198 }
199
200 static void
201 server_schedule_idle_task(headless_server_t *server);
202 static void
203 server_set_focus_view(headless_server_t *server, headless_view_t *view);
204 static void
205 server_set_top_view(headless_server_t *server, headless_view_t *view);
206
207 static void
208 destroy_view(headless_view_t *view)
209 {
210         ds_inf("view(%p) destroyed", view);
211
212         wl_signal_emit(&view->events.destroy, view);
213
214         wl_list_remove(&view->commit.link);
215         wl_list_remove(&view->map.link);
216         wl_list_remove(&view->unmap.link);
217         wl_list_remove(&view->request_activate.link);
218         wl_list_remove(&view->set_skip_focus.link);
219         wl_list_remove(&view->unset_skip_focus.link);
220         wl_list_remove(&view->link);
221
222         free(view);
223 }
224
225 static void
226 view_handle_shell_surface_destroy(struct wl_listener *listener, void *data)
227 {
228         headless_view_t *view;
229         headless_server_t *server;
230
231         view = wl_container_of(listener, view, shell_surface_destroy);
232         server = view->server;
233
234         if (server->top_view == view) {
235                 server->top_view = NULL;
236                 wl_signal_emit(&server->events.top_change, NULL);
237         }
238
239         server_schedule_idle_task(server);
240
241         destroy_view(view);
242 }
243
244 static void
245 view_handle_surface_commit(struct wl_listener *listener, void *data)
246 {
247         headless_view_t *view;
248
249         view = wl_container_of(listener, view, commit);
250     view->buffer = ds_surface_get_buffer(view->surface);
251
252         // FIXME use the size of surface, not size of buffer
253         if (view->buffer)
254                 ds_buffer_get_size(view->buffer, &view->width, &view->height);
255
256         server_schedule_idle_task(view->server);
257 }
258
259 static void
260 view_handle_shell_surface_map(struct wl_listener *listener, void *data)
261 {
262         headless_view_t *view;
263
264         view = wl_container_of(listener, view, map);
265         view->mapped = true;
266
267         server_schedule_idle_task(view->server);
268 }
269
270 static void
271 view_handle_shell_surface_unmap(struct wl_listener *listener, void *data)
272 {
273         headless_view_t *view;
274
275         view = wl_container_of(listener, view, unmap);
276         view->mapped = false;
277
278         server_schedule_idle_task(view->server);
279 }
280
281 static void
282 view_handle_request_activate(struct wl_listener *listener, void *data)
283 {
284         headless_view_t *view;
285
286         view = wl_container_of(listener, view, request_activate);
287
288         wl_list_remove(&view->link);
289         wl_list_insert(&view->server->views, &view->link);
290
291         server_schedule_idle_task(view->server);
292 }
293
294 static void
295 view_handle_shell_surface_set_skip_focus(struct wl_listener *listener,
296                 void *data)
297 {
298         headless_view_t *view;
299
300         view = wl_container_of(listener, view, set_skip_focus);
301         view->skip_focus = true;
302
303         server_schedule_idle_task(view->server);
304 }
305
306 static void
307 view_handle_shell_surface_unset_skip_focus(struct wl_listener *listener,
308                 void *data)
309 {
310         headless_view_t *view;
311
312         view = wl_container_of(listener, view, unset_skip_focus);
313         view->skip_focus = false;
314
315         server_schedule_idle_task(view->server);
316 }
317
318 static bool
319 create_view(headless_server_t *server, headless_shell_surface_t *shell_surface)
320 {
321         headless_view_t *view;
322
323         view = calloc(1, sizeof *view);
324         if (!view)
325                 return false;
326
327         view->server = server;
328         view->shell_surface = shell_surface;
329         view->surface = headless_shell_surface_get_surface(shell_surface);
330
331         wl_signal_init(&view->events.destroy);
332
333         view->shell_surface_destroy.notify = view_handle_shell_surface_destroy;
334         headless_shell_surface_add_destroy_listener(shell_surface,
335                         &view->shell_surface_destroy);
336
337         view->commit.notify = view_handle_surface_commit;
338         ds_surface_add_commit_listener(view->surface, &view->commit);
339
340         view->map.notify = view_handle_shell_surface_map;
341         headless_shell_surface_add_map_listener(shell_surface, &view->map);
342
343         view->unmap.notify = view_handle_shell_surface_unmap;
344         headless_shell_surface_add_unmap_listener(shell_surface, &view->unmap);
345
346         view->request_activate.notify = view_handle_request_activate;
347         headless_shell_surface_add_request_activate_listener(shell_surface,
348                         &view->request_activate);
349
350         view->set_skip_focus.notify = view_handle_shell_surface_set_skip_focus;
351         headless_shell_surface_add_set_skip_focus_listener(shell_surface,
352                         &view->set_skip_focus);
353
354         view->unset_skip_focus.notify = view_handle_shell_surface_unset_skip_focus;
355         headless_shell_surface_add_unset_skip_focus_listener(shell_surface,
356                         &view->unset_skip_focus);
357
358         wl_list_insert(&server->views, &view->link);
359
360         ds_inf("Create view(%p)", view);
361
362         return true;
363 }
364
365 static void
366 server_handle_new_shell_surface(struct wl_listener *listener, void *data)
367 {
368         headless_server_t *server;
369         headless_shell_surface_t *shell_surface = data;
370
371         server = wl_container_of(listener, server, new_shell_surface);
372
373         ds_inf("shell surface added, server(%p)", server);
374
375         if (server->boot_animating) {
376                 server->boot_animating = false;
377                 headless_output_stop_boot_ani(server->output);
378         }
379
380         HEADLESS_CHECK(create_view(server, shell_surface), return,
381                         "Could not create headless_view");
382 }
383
384 static void
385 server_set_focus_view(headless_server_t *server, headless_view_t *view)
386 {
387         if (server->focus_view == view)
388                 return;
389
390         server->focus_view = view;
391
392         wl_signal_emit(&server->events.focus_change, view);
393 }
394
395 static void
396 server_set_top_view(headless_server_t *server, headless_view_t *view)
397 {
398         if (server->top_view == view)
399                 return;
400
401         // TODO handle input and debug
402
403         if (server->top_view) {
404                 headless_shell_send_visibility(server->top_view->shell_surface,
405                                 TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED);
406         }
407
408         if (view) {
409                 headless_shell_send_visibility(view->shell_surface,
410                                 TIZEN_VISIBILITY_VISIBILITY_UNOBSCURED);
411         }
412
413         server->top_view = view;
414
415         wl_signal_emit(&server->events.top_change, view);
416 }
417
418 static void
419 server_repaint(headless_server_t *server)
420 {
421     struct ds_surface *surface = NULL;
422         struct ds_buffer *buffer = NULL;
423         struct timespec now;
424         void *data = NULL;
425         uint32_t format;
426         size_t stride;
427         bool access = false;
428
429     if (server->top_view) {
430         surface = server->top_view->surface;
431         buffer = server->top_view->buffer;
432     }
433
434         if (buffer) {
435                 access = ds_buffer_begin_data_ptr_access(buffer,
436                                 DS_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride);
437                 if (!access)
438                         ds_err("Could not access ds_buffer(%p)", buffer);
439         }
440
441         headless_output_update_led(server->output, data);
442
443         if (access)
444                 ds_buffer_end_data_ptr_access(buffer);
445
446     if (surface) {
447                 clock_gettime(CLOCK_MONOTONIC, &now);
448                 ds_surface_send_frame_done(surface, &now);
449         }
450 }
451
452 static void
453 idle_task(void *data)
454 {
455         headless_server_t *server = data;
456         headless_view_t *view, *focus_view = NULL, *top_view = NULL;
457
458         server->idle_source = NULL;
459
460         /* This iterates over all our views and attemps to find focusable and
461      * visible views on the top. This relies on server->views being ordered
462      * from top-to-bottom. */
463         wl_list_for_each(view, &server->views, link) {
464                 if (!view->mapped)
465                         continue;
466
467                 if (!top_view)
468                         top_view = view;
469
470                 if (!focus_view && !view->skip_focus)
471                         focus_view = view;
472
473                 if (focus_view && top_view)
474                         break;
475         }
476
477         server_set_focus_view(server, focus_view);
478         server_set_top_view(server, top_view);
479         server_repaint(server);
480 }
481
482 static void
483 server_schedule_idle_task(headless_server_t *server)
484 {
485         if (server->idle_source)
486                 return;
487
488         server->idle_source =
489                 wl_event_loop_add_idle(wl_display_get_event_loop(server->display),
490                                 idle_task, server);
491 }