]> Pileus Git - wmpus/blob - sys-xwl.c
a3ad0de39b9e48ea385302a5642c3c8cbe10ffdf
[wmpus] / sys-xwl.c
1 /*
2  * Copyright (c) 2014-2015 Andy Spencer <andy753421@gmail.com>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  */
15
16 #define _GNU_SOURCE
17 #include <string.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <sys/mman.h>
23
24 #include <libevdev/libevdev.h>
25 #include <xkbcommon/xkbcommon.h>
26 #include <wayland-server.h>
27 #include <wayland-client.h>
28
29 #include <gtk/gtk.h>
30
31 #include "util.h"
32 #include "conf.h"
33 #include "sys.h"
34 #include "wm.h"
35
36 #include "xdg-shell-client-protocol.h"
37 #include "xdg-shell-server-protocol.h"
38 #include "gtk-shell-client-protocol.h"
39 #include "gtk-shell-server-protocol.h"
40
41 /* Window Managers calls */
42 void wm_update(void);
43
44 /* Wayland user data */
45 typedef struct {
46         uint8_t             *mem;
47         size_t               size;
48 } sys_pool_t;
49
50 typedef struct {
51         sys_pool_t          *pool;
52         uint8_t             *mem;
53         cairo_surface_t     *surface;
54 } sys_bdata_t;
55
56 typedef struct {
57         struct wl_client    *cli;
58         list_t              *ptrs;    // of struct wl_resource
59         list_t              *kbds;    // of struct wl_resource
60         list_t              *tchs;    // of struct wl_resource
61 } sys_cdata_t;
62
63 /* Internal structures */
64 struct win_sys {
65         struct wl_resource  *sfc;
66         struct wl_resource  *ssfc;
67         struct wl_resource  *xsfc;
68         struct wl_resource  *buf;
69         sys_cdata_t         *cdata;
70         int                  x,y;     // surface x,y
71         int                  wx,wy;   // window  x,y inside sfc
72         int                  ww,wh;   // window  w,h inside sfc
73 };
74
75 /* Global data */
76 static win_t                *root;
77 static win_t                *focus;
78 static list_t               *clients; // of sys_cdata_t
79 static list_t               *windows; // of win_t
80
81 static win_t                *cursor;
82 static double                cursor_x;
83 static double                cursor_y;
84 static double                cursor_dx;
85 static double                cursor_dy;
86
87 static GtkWidget            *screen;
88
89 static struct wl_resource   *output;
90 static struct wl_display    *display;
91 static struct wl_event_loop *events;
92
93 /********************
94  * Helper Functions *
95  ********************/
96
97 static int get_serial(void)
98 {
99         static int serial = 0;
100         return serial++;
101 }
102
103 static int get_time(void)
104 {
105         static uint64_t epoch;
106
107         struct timespec ts;
108         clock_gettime(CLOCK_REALTIME, &ts);
109
110         uint64_t now = (((uint64_t)ts.tv_sec ) * 1000)
111                      + (((uint64_t)ts.tv_nsec) / 1000000);
112
113         if (epoch == 0)
114                 epoch = now;
115
116         return (int)(now - epoch);
117 }
118
119 static win_t *find_win(int x, int y)
120 {
121         for (list_t *cur = windows; cur; cur = cur->prev) {
122                 win_t *win = cur->data;
123                 int l = win->x;
124                 int r = win->w + l;
125                 int t = win->y;
126                 int b = win->h + t;
127                 if (l <= x && x <= r && t <= y && y <= b)
128                         return win;
129         }
130         return NULL;
131 }
132
133 static sys_cdata_t *find_cdata(struct wl_client *cli)
134 {
135         // Search for existing client
136         for (list_t *cur = clients; cur; cur = cur->next) {
137                 sys_cdata_t *cdata = cur->data;
138                 if (cdata->cli == cli)
139                         return cdata;
140         }
141
142         // Not found, create new one
143         sys_cdata_t *cdata = new0(sys_cdata_t);
144         clients = list_insert(clients, cdata);
145         cdata->cli = cli;
146         return cdata;
147 }
148
149 /****************************
150  * Wayland Buffer Interface *
151  ****************************/
152 static void buffer_destroy(struct wl_client *cli, struct wl_resource *reso)
153 {
154         printf("buffer_destroy\n");
155 }
156
157 static struct wl_buffer_interface buffer_iface = {
158         .destroy  = buffer_destroy,
159 };
160
161 /***********************************
162  * Wayland Shared Memory Interface *
163  ***********************************/
164
165 /* Shm Pool */
166 static void pool_create_buffer(struct wl_client *cli, struct wl_resource *pool,
167                 uint32_t id, int32_t offset, int32_t width, int32_t height,
168                 int32_t stride, uint32_t format)
169 {
170         sys_bdata_t *bdata = new0(sys_bdata_t);
171         bdata->pool = wl_resource_get_user_data(pool);
172         bdata->mem  = bdata->pool->mem + offset;
173
174         printf("pool_create_buffer - %dx%d %p+%d : %d,%d,%d\n",
175                         width, height, bdata->pool->mem, offset, id, stride, format);
176
177         if (offset > bdata->pool->size || offset < 0)
178         {
179                 printf("\n\nerror\n\n");
180                 wl_resource_post_error(pool, WL_SHM_ERROR_INVALID_STRIDE,
181                                 "offset is too big or negative");
182                 return;
183         }
184
185         cairo_format_t cf =
186                 format == WL_SHM_FORMAT_ARGB8888 ? CAIRO_FORMAT_ARGB32 :
187                 format == WL_SHM_FORMAT_XRGB8888 ? CAIRO_FORMAT_RGB24  : CAIRO_FORMAT_INVALID;
188
189         bdata->surface = cairo_image_surface_create_for_data(bdata->mem, cf, width, height, stride);
190
191         struct wl_resource *res = wl_resource_create(cli, &wl_buffer_interface,
192                                         wl_resource_get_version(pool), id);
193         wl_resource_set_implementation(res, &buffer_iface, bdata, NULL);
194 }
195
196 static void pool_destroy(struct wl_client *cli, struct wl_resource *pool)
197 {
198         printf("pool_destroy\n");
199 }
200
201 static void pool_resize(struct wl_client *cli, struct wl_resource *pool,
202                 int32_t size)
203 {
204         printf("[   WMPUS   ] pool_resize - %d\n", size);
205         sys_pool_t *data = wl_resource_get_user_data(pool);
206         void *ptr = mremap(data->mem, data->size, size, MREMAP_MAYMOVE);
207         if (ptr == MAP_FAILED)
208         {
209                 printf("\n\nerror\n\n");
210                 wl_resource_post_error(pool, WL_SHM_ERROR_INVALID_FD,
211                                 "mremap failed: %s", strerror(errno));
212                 return;
213         }
214         data->mem  = ptr;
215         data->size = size;
216 }
217
218 static struct wl_shm_pool_interface pool_iface = {
219         .create_buffer = &pool_create_buffer,
220         .destroy       = &pool_destroy,
221         .resize        = &pool_resize,
222 };
223
224 /* Shm */
225 static void shm_create_pool(struct wl_client *cli, struct wl_resource *shm,
226                 uint32_t id, int32_t fd, int32_t size)
227 {
228         printf("shm_create_pool - #%d %d %d\n", id, fd, size);
229
230         sys_pool_t *data = new0(sys_pool_t);
231
232         struct wl_resource *res = wl_resource_create(cli, &wl_shm_pool_interface,
233                                         wl_resource_get_version(shm), id);
234         wl_resource_set_implementation(res, &pool_iface, data, NULL);
235
236         data->mem  = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
237         data->size = size;
238 }
239
240 static struct wl_shm_interface shm_iface = {
241         .create_pool = shm_create_pool,
242 };
243
244 /**************************
245  * Wayland Seat Interface *
246  **************************/
247
248 /* Pointer */
249 static void pointer_kill(struct wl_resource *ptr)
250 {
251         sys_cdata_t *cdata = wl_resource_get_user_data(ptr);
252         list_t *link = list_find(cdata->ptrs, ptr);
253         cdata->ptrs = list_remove(cdata->ptrs, link, 0);
254         if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
255                 list_t *clink = list_find(clients, cdata);
256                 clients = list_remove(clients, clink, 1);
257         }
258 }
259
260 static void pointer_set_cursor(struct wl_client *cli, struct wl_resource *ptr,
261                            uint32_t serial, struct wl_resource *sfc,
262                            int32_t hotspot_x, int32_t hotspot_y)
263 {
264         printf("pointer_set_cursor %d,%d\n", hotspot_x, hotspot_y);
265         win_t *win = wl_resource_get_user_data(sfc);
266         win->type = TYPE_CURSOR;
267         cursor_dx = hotspot_x;
268         cursor_dy = hotspot_y;
269         cursor    = win;
270 }
271
272 static void pointer_release(struct wl_client *cli, struct wl_resource *ptr)
273 {
274         printf("pointer_release\n");
275 }
276
277 static struct wl_pointer_interface pointer_iface = {
278         .set_cursor = pointer_set_cursor,
279         .release    = pointer_release,
280 };
281
282 /* Keyboard */
283 static void keyboard_kill(struct wl_resource *kbd)
284 {
285         sys_cdata_t *cdata = wl_resource_get_user_data(kbd);
286         list_t *link = list_find(cdata->kbds, kbd);
287         cdata->kbds = list_remove(cdata->kbds, link, 0);
288         if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
289                 list_t *clink = list_find(clients, cdata);
290                 clients = list_remove(clients, clink, 1);
291         }
292 }
293
294 static void keyboard_release(struct wl_client *cli, struct wl_resource *kbd)
295 {
296         printf("keyboard_release\n");
297 }
298
299 static struct wl_keyboard_interface keyboard_iface = {
300         .release = keyboard_release,
301 };
302
303 /* Touch */
304 static void touch_kill(struct wl_resource *tch)
305 {
306         sys_cdata_t *cdata = wl_resource_get_user_data(tch);
307         list_t *link = list_find(cdata->tchs, tch);
308         cdata->tchs = list_remove(cdata->tchs, link, 0);
309         if (!cdata->ptrs && !cdata->kbds && !cdata->tchs) {
310                 list_t *clink = list_find(clients, cdata);
311                 clients = list_remove(clients, clink, 1);
312         }
313 }
314
315 static void touch_release(struct wl_client *cli, struct wl_resource *tch)
316 {
317         printf("touch_release\n");
318 }
319
320 static struct wl_touch_interface touch_iface = {
321         .release = touch_release,
322 };
323
324 /* Seat */
325 static void seat_get_pointer(struct wl_client *cli, struct wl_resource *seat,
326                 uint32_t id) {
327         sys_cdata_t *cdata = find_cdata(cli);
328         struct wl_resource *res = wl_resource_create(cli, &wl_pointer_interface, 3, id);
329         wl_resource_set_implementation(res, &pointer_iface, cdata, pointer_kill);
330         cdata->ptrs = list_insert(cdata->ptrs, res);
331         printf("seat_get_pointer - cli=%p cdata=%p ptr=%p\n", cli, cdata, res);
332 }
333
334 static void seat_get_keyboard(struct wl_client *cli, struct wl_resource *seat,
335                 uint32_t id) {
336         sys_cdata_t *cdata = find_cdata(cli);
337         struct wl_resource *res = wl_resource_create(cli, &wl_keyboard_interface, 4, id);
338         wl_resource_set_implementation(res, &keyboard_iface, cdata, keyboard_kill);
339
340         //map = xkb_keymap_new_from_names(xkb->context, NULL, 0);
341         //xkb->context    = xkb_context_new(0);
342         //xkb->keymap.map = xkb_keymap_new_from_names(xkb->context, NULL, 0);
343         //wl_keyboard_send_keymap(cli, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
344         //              keyboard->xkb.keymap.fd,
345         //              keyboard->xkb.keymap.size - 1);
346
347         cdata->kbds = list_insert(cdata->kbds, res);
348         printf("seat_get_keyboard - cli=%p cdata=%p kbd=%p\n", cli, cdata, res);
349 }
350
351 static void seat_get_touch(struct wl_client *cli, struct wl_resource *seat,
352                 uint32_t id) {
353         sys_cdata_t *cdata = find_cdata(cli);
354         struct wl_resource *res = wl_resource_create(cli, &wl_touch_interface, 3, id);
355         wl_resource_set_implementation(res, &touch_iface, cdata, touch_kill);
356         cdata->tchs = list_insert(cdata->tchs, res);
357         printf("seat_get_touch - cli=%p cdata=%p tch=%p\n", cli, cdata, res);
358 }
359
360 static struct wl_seat_interface seat_iface = {
361         .get_pointer  = &seat_get_pointer,
362         .get_keyboard = &seat_get_keyboard,
363         .get_touch    = &seat_get_touch,
364 };
365
366 /*****************************************
367  * Wayland Data Device Manager Interface *
368  *****************************************/
369
370 /* Data Offer */
371 static void doff_accept(struct wl_client *cli, struct wl_resource *doff,
372                uint32_t serial, const char *mime_type)
373 {
374         printf("doff_accept\n");
375 }
376
377 static void doff_receive(struct wl_client *cli, struct wl_resource *doff,
378                 const char *mime_type, int32_t fd)
379 {
380         printf("doff_receive\n");
381 }
382
383 static void doff_destroy(struct wl_client *cli, struct wl_resource *doff)
384 {
385         printf("doff_destroy\n");
386 }
387
388 static struct wl_data_offer_interface doff_iface = {
389         .accept  = doff_accept,
390         .receive = doff_receive,
391         .destroy = doff_destroy,
392 };
393
394 /* Data Source */
395 static void dsrc_offer(struct wl_client *cli, struct wl_resource *dsrc,
396               const char *mime_type)
397 {
398         (void)doff_iface;
399         printf("dsrc_offer\n");
400 }
401
402 static void dsrc_destroy(struct wl_client *cli, struct wl_resource *dsrc)
403 {
404         printf("dsrc_destroy\n");
405 }
406
407 static struct wl_data_source_interface dsrc_iface = {
408         .offer   = dsrc_offer,
409         .destroy = dsrc_destroy,
410 };
411
412 /* Data Device */
413 static void ddev_start_drag(struct wl_client *cli, struct wl_resource *dsrc,
414                    struct wl_resource *source, struct wl_resource *origin,
415                    struct wl_resource *icon, uint32_t serial)
416 {
417         printf("start_drag\n");
418 }
419
420 static void ddev_set_selection(struct wl_client *cli, struct wl_resource *dsrc,
421                       struct wl_resource *source, uint32_t serial)
422 {
423         printf("set_selection\n");
424 }
425
426 static struct wl_data_device_interface ddev_iface = {
427         .start_drag    = ddev_start_drag,
428         .set_selection = ddev_set_selection,
429 };
430
431 /* Data Device Manager */
432 static void ddm_create_data_source(struct wl_client *cli, struct wl_resource *ddm,
433                 uint32_t id)
434 {
435         printf("ddm_create_data_source\n");
436         struct wl_resource *res = wl_resource_create(cli, &wl_data_device_interface, 1, id);
437         wl_resource_set_implementation(res, &dsrc_iface, NULL, NULL);
438 }
439
440 static void ddm_get_data_device(struct wl_client *cli, struct wl_resource *ddm,
441                 uint32_t id, struct wl_resource *seat)
442 {
443         printf("ddm_get_data_device\n");
444         struct wl_resource *res = wl_resource_create(cli, &wl_data_device_interface, 1, id);
445         wl_resource_set_implementation(res, &ddev_iface, NULL, NULL);
446 }
447
448 static struct wl_data_device_manager_interface ddm_iface = {
449         .create_data_source = &ddm_create_data_source,
450         .get_data_device    = &ddm_get_data_device,
451 };
452
453 /**************************************
454  * Wayland Shell/Compositor Interface *
455  **************************************/
456
457 /* Surface */
458 static void surface_kill(struct wl_resource *sfc)
459 {
460         printf("surface_kill\n");
461         win_t  *win  = wl_resource_get_user_data(sfc);
462         list_t *link = list_find(windows, win);
463         free(win->sys);
464         free(win);
465         windows = list_remove(windows, link, 0);
466         gtk_widget_queue_draw(screen);
467 }
468
469 static void surface_destroy(struct wl_client *cli, struct wl_resource *sfc)
470 {
471         printf("surface_destroy\n");
472         surface_kill(sfc);
473 }
474
475 static void surface_attach(struct wl_client *cli, struct wl_resource *sfc,
476                 struct wl_resource *buf, int32_t x, int32_t y)
477 {
478         win_t       *win   = wl_resource_get_user_data(sfc);
479         sys_bdata_t *bdata = wl_resource_get_user_data(buf);
480         printf("surface_attach - %p - %d,%d\n", bdata->pool->mem, x, y);
481         win->sys->buf = buf;
482         win->sys->x   = x;
483         win->sys->y   = y;
484 }
485
486 static void surface_damage(struct wl_client *cli, struct wl_resource *sfc,
487                    int32_t x, int32_t y, int32_t width, int32_t height)
488 {
489         printf("surface_damage\n");
490 }
491
492 static void surface_frame(struct wl_client *cli, struct wl_resource *sfc,
493                 uint32_t id)
494 {
495         printf("surface_frame\n");
496         struct wl_resource *cb = wl_resource_create(cli, &wl_callback_interface, 1, id);
497         wl_resource_set_implementation(cb, NULL, NULL, NULL);
498         wl_callback_send_done(cb, get_time());
499 }
500
501 static void surface_set_opaque_region(struct wl_client *cli, struct wl_resource *sfc,
502                 struct wl_resource *reg)
503 {
504         printf("surface_set_opaque_region\n");
505 }
506
507 static void surface_set_input_region(struct wl_client *cli, struct wl_resource *sfc,
508                 struct wl_resource *reg)
509 {
510         printf("surface_set_input_region\n");
511 }
512
513 static void surface_commit(struct wl_client *cli, struct wl_resource *sfc)
514 {
515         printf("surface_commit\n");
516         gtk_widget_queue_draw(screen);
517 }
518
519 static void surface_set_buffer_transform(struct wl_client *cli, struct wl_resource *sfc,
520                 int32_t transform)
521 {
522         printf("surface_set_buffer_transform\n");
523 }
524
525 static void surface_set_buffer_scale(struct wl_client *cli, struct wl_resource *sfc,
526                 int32_t scale)
527 {
528         printf("surface_set_buffer_scale\n");
529 }
530
531 static struct wl_surface_interface surface_iface = {
532         .destroy              = surface_destroy,
533         .attach               = surface_attach,
534         .damage               = surface_damage,
535         .frame                = surface_frame,
536         .set_opaque_region    = surface_set_opaque_region,
537         .set_input_region     = surface_set_input_region,
538         .commit               = surface_commit,
539         .set_buffer_transform = surface_set_buffer_transform,
540         .set_buffer_scale     = surface_set_buffer_scale,
541 };
542
543 /* Region */
544 static void region_destroy(struct wl_client *cli, struct wl_resource *reg)
545 {
546         printf("region_destroy\n");
547 }
548
549 static void region_add(struct wl_client *cli, struct wl_resource *reg,
550                 int32_t x, int32_t y, int32_t width, int32_t height)
551 {
552         printf("region_add\n");
553 }
554
555 static void region_subtract(struct wl_client *cli, struct wl_resource *reg,
556                      int32_t x, int32_t y, int32_t width, int32_t height)
557 {
558         printf("region_subtract\n");
559 }
560
561 static struct wl_region_interface region_iface = {
562         .destroy  = region_destroy,
563         .add      = region_add,
564         .subtract = region_subtract,
565 };
566
567 /* Compositor */
568 static void comp_create_surface(struct wl_client *cli, struct wl_resource *comp,
569                 uint32_t id)
570 {
571         win_t *win = new0(win_t);
572         win->sys   = new0(win_sys_t);
573
574         struct wl_resource *res = wl_resource_create(cli, &wl_surface_interface, 3, id);
575         wl_resource_set_implementation(res, &surface_iface, win, surface_kill);
576         wl_surface_send_enter(res, output);
577
578         win->sys->sfc   = res;
579         win->sys->cdata = find_cdata(cli);
580
581         windows = list_insert(windows, win);
582
583         printf("comp_create_surface - cli=%p win=%p cdata=%p\n",
584                         cli, win, win->sys->cdata);
585 }
586
587 static void comp_create_region(struct wl_client *cli, struct wl_resource *comp,
588                 uint32_t id)
589 {
590         printf("comp_create_region\n");
591         struct wl_resource *res = wl_resource_create(cli, &wl_region_interface, 1, id);
592         wl_resource_set_implementation(res, &region_iface, NULL, NULL);
593 }
594
595 static struct wl_compositor_interface comp_iface = {
596         .create_surface = comp_create_surface,
597         .create_region  = comp_create_region,
598 };
599
600 /* Shell Surface */
601 static void ssurface_kill(struct wl_resource *ssfc)
602 {
603         win_t *win = wl_resource_get_user_data(ssfc);
604         printf("ssurface_kill - %p\n", win);
605         win->sys->ssfc = NULL;
606         if (!win->sys->xsfc)
607                 wm_remove(win);
608 }
609
610 static void ssurface_pong(struct wl_client *cli, struct wl_resource *ssfc,
611                 uint32_t serial)
612 {
613         printf("ssurface_pong\n");
614 }
615
616 static void ssurface_move(struct wl_client *cli, struct wl_resource *ssfc,
617                 struct wl_resource *seat, uint32_t serial)
618 {
619         printf("ssurface_move\n");
620 }
621
622 static void ssurface_resize(struct wl_client *cli, struct wl_resource *ssfc,
623                 struct wl_resource *seat, uint32_t serial, uint32_t edges)
624 {
625         printf("ssurface_resize\n");
626 }
627
628 static void ssurface_set_toplevel(struct wl_client *cli, struct wl_resource *ssfc)
629 {
630         printf("ssurface_set_toplevel\n");
631 }
632
633 static void ssurface_set_transient(struct wl_client *cli, struct wl_resource *ssfc,
634                 struct wl_resource *parent, int32_t x, int32_t y, uint32_t flags)
635 {
636         printf("ssurface_set_transient\n");
637 }
638
639 static void ssurface_set_fullscreen(struct wl_client *cli, struct wl_resource *ssfc,
640                 uint32_t method, uint32_t framerate, struct wl_resource *out)
641 {
642         printf("ssurface_set_fullscreen\n");
643 }
644
645 static void ssurface_set_popup(struct wl_client *cli, struct wl_resource *ssfc,
646                 struct wl_resource *seat, uint32_t serial, struct wl_resource *parent,
647                 int32_t x, int32_t y, uint32_t flags)
648 {
649         printf("ssurface_set_popup\n");
650 }
651
652 static void ssurface_set_maximized(struct wl_client *cli, struct wl_resource *ssfc,
653                 struct wl_resource *out)
654 {
655         printf("ssurface_set_maximized\n");
656 }
657
658 static void ssurface_set_title(struct wl_client *cli, struct wl_resource *ssfc,
659                 const char *title)
660 {
661         printf("ssurface_set_title\n");
662 }
663
664 static void ssurface_set_class(struct wl_client *cli, struct wl_resource *ssfc,
665                 const char *class)
666 {
667         printf("ssurface_set_class\n");
668 }
669
670 static struct wl_shell_surface_interface ssurface_iface = {
671         .pong           = ssurface_pong,
672         .move           = ssurface_move,
673         .resize         = ssurface_resize,
674         .set_toplevel   = ssurface_set_toplevel,
675         .set_transient  = ssurface_set_transient,
676         .set_fullscreen = ssurface_set_fullscreen,
677         .set_popup      = ssurface_set_popup,
678         .set_maximized  = ssurface_set_maximized,
679         .set_title      = ssurface_set_title,
680         .set_class      = ssurface_set_class,
681 };
682
683 /* Shell */
684 static void shell_get_shell_surface(struct wl_client *cli, struct wl_resource *shell, uint32_t id,
685                               struct wl_resource *sfc) {
686         win_t *win = wl_resource_get_user_data(sfc);
687         printf("shell_get_shell_surface - %p\n", win);
688
689         struct wl_resource *res = wl_resource_create(cli, &wl_shell_surface_interface, 1, id);
690         wl_resource_set_implementation(res, &ssurface_iface, win, ssurface_kill);
691
692         win->type = TYPE_NORMAL;
693         win->sys->ssfc = res;
694         wm_insert(win);
695 }
696
697 static struct wl_shell_interface shell_iface = {
698         .get_shell_surface = shell_get_shell_surface,
699 };
700
701 /* XDG Popup */
702 static void xpopup_destroy(struct wl_client *cli, struct wl_resource *xpopup)
703 {
704         printf("xpopup_destroy\n");
705 }
706
707 static struct xdg_popup_interface xpopup_iface = {
708         .destroy = xpopup_destroy,
709 };
710
711 /* XDG Surface */
712 static void xsurface_kill(struct wl_resource *xsfc)
713 {
714         win_t *win = wl_resource_get_user_data(xsfc);
715         printf("xsurface_kill - %p\n", win);
716         win->sys->xsfc = NULL;
717         if (!win->sys->ssfc)
718                 wm_remove(win);
719 }
720
721 static void xsurface_destroy(struct wl_client *cli, struct wl_resource *xsfc)
722 {
723         printf("xsurface_destroy\n");
724 }
725
726 static void xsurface_set_parent(struct wl_client *cli, struct wl_resource *xsfc,
727                 struct wl_resource *parent)
728 {
729         win_t *win = wl_resource_get_user_data(xsfc);
730         printf("xsurface_set_parent - %p\n", win);
731         win->type = TYPE_DIALOG;
732 }
733
734 static void xsurface_set_title(struct wl_client *cli, struct wl_resource *xsfc,
735                 const char *title)
736 {
737         printf("xsurface_set_title\n");
738 }
739
740 static void xsurface_set_app_id(struct wl_client *cli, struct wl_resource *xsfc,
741                 const char *app_id)
742 {
743         printf("xsurface_set_app_id\n");
744 }
745
746 static void xsurface_show_window_menu(struct wl_client *cli, struct wl_resource *xsfc,
747                 struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y)
748 {
749         printf("xsurface_show_window_menu\n");
750 }
751
752 static void xsurface_move(struct wl_client *cli, struct wl_resource *xsfc,
753                 struct wl_resource *seat, uint32_t serial)
754 {
755         printf("xsurface_move\n");
756 }
757
758 static void xsurface_resize(struct wl_client *cli, struct wl_resource *xsfc,
759                 struct wl_resource *seat, uint32_t serial, uint32_t edges)
760 {
761         printf("xsurface_resize\n");
762 }
763
764 static void xsurface_ack_configure(struct wl_client *cli, struct wl_resource *xsfc,
765                 uint32_t serial)
766 {
767         printf("xsurface_ack_configure\n");
768 }
769
770 static void xsurface_set_window_geometry(struct wl_client *cli, struct wl_resource *xsfc,
771                 int32_t x, int32_t y, int32_t width, int32_t height)
772 {
773         win_t *win = wl_resource_get_user_data(xsfc);
774         printf("xsurface_set_window_geometry - %p\n", win);
775         win->sys->wx = x;
776         win->sys->wy = y;
777         win->sys->ww = width;
778         win->sys->wh = height;
779 }
780
781 static void xsurface_set_maximized(struct wl_client *cli, struct wl_resource *xsfc)
782 {
783         printf("xsurface_set_maximized\n");
784 }
785
786 static void xsurface_unset_maximized(struct wl_client *cli, struct wl_resource *xsfc)
787 {
788         printf("xsurface_unset_maximized\n");
789 }
790
791 static void xsurface_set_fullscreen(struct wl_client *cli, struct wl_resource *xsfc,
792                 struct wl_resource *output)
793 {
794         printf("xsurface_set_fullscreen\n");
795 }
796
797 static void xsurface_unset_fullscreen(struct wl_client *cli, struct wl_resource *xsfc)
798 {
799         printf("xsurface_unset_fullscreen\n");
800 }
801
802 static void xsurface_set_minimized(struct wl_client *cli, struct wl_resource *xsfc)
803 {
804         printf("xsurface_set_minimized\n");
805 }
806
807 static struct xdg_surface_interface xsurface_iface = {
808         .destroy             = xsurface_destroy,
809         .set_parent          = xsurface_set_parent,
810         .set_title           = xsurface_set_title,
811         .set_app_id          = xsurface_set_app_id,
812         .show_window_menu    = xsurface_show_window_menu,
813         .move                = xsurface_move,
814         .resize              = xsurface_resize,
815         .ack_configure       = xsurface_ack_configure,
816         .set_window_geometry = xsurface_set_window_geometry,
817         .set_maximized       = xsurface_set_maximized,
818         .unset_maximized     = xsurface_unset_maximized,
819         .set_fullscreen      = xsurface_set_fullscreen,
820         .unset_fullscreen    = xsurface_unset_fullscreen,
821         .set_minimized       = xsurface_set_minimized,
822 };
823
824 /* XDG Shell */
825 static void xshell_use_unstable_version(struct wl_client *cli, struct wl_resource *xshell,
826                 int32_t version)
827 {
828         printf("xshell_use_unstable_version\n");
829 }
830
831 static void xshell_get_xdg_surface(struct wl_client *cli, struct wl_resource *xshell,
832                 uint32_t id, struct wl_resource *sfc)
833 {
834         win_t *win = wl_resource_get_user_data(sfc);
835         printf("xshell_get_xdg_surface - %p\n", win);
836
837         struct wl_resource *res = wl_resource_create(cli, &xdg_surface_interface, 1, id);
838         wl_resource_set_implementation(res, &xsurface_iface, win, xsurface_kill);
839
840         win->type = TYPE_NORMAL;
841         win->sys->xsfc = res;
842         wm_insert(win);
843 }
844
845 static void xshell_get_xdg_popup(struct wl_client *cli, struct wl_resource *xshell,
846                 uint32_t id, struct wl_resource *sfc, struct wl_resource *parent,
847                 struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y, uint32_t flags)
848 {
849         printf("xshell_get_xdg_popup\n");
850         struct wl_resource *res = wl_resource_create(cli, &xdg_popup_interface, 1, id);
851         wl_resource_set_implementation(res, &xpopup_iface, NULL, NULL);
852 }
853
854 static void xshell_pong(struct wl_client *cli, struct wl_resource *xshell,
855                 uint32_t serial)
856 {
857         printf("xshell_pong\n");
858 }
859
860 static struct xdg_shell_interface xshell_iface = {
861         .use_unstable_version = xshell_use_unstable_version,
862         .get_xdg_surface      = xshell_get_xdg_surface,
863         .get_xdg_popup        = xshell_get_xdg_popup,
864         .pong                 = xshell_pong,
865 };
866
867 /* GTK Surface */
868 static void gsurface_set_dbus_properties(struct wl_client *cli, struct wl_resource *gsfc,
869                             const char *application_id, const char *app_menu_path,
870                             const char *menubar_path, const char *window_object_path,
871                             const char *application_object_path, const char *unique_bus_name)
872 {
873         printf("gsurface_set_dbus_properties\n");
874 }
875
876 static struct gtk_surface_interface gsurface_iface = {
877         .set_dbus_properties = gsurface_set_dbus_properties,
878 };
879
880 /* GTK Shell */
881 static void gshell_get_gtk_surface(struct wl_client *cli, struct wl_resource *gshell,
882                 uint32_t id, struct wl_resource *sfc)
883 {
884         printf("gshell_get_gtk_surface\n");
885         struct wl_resource *res = wl_resource_create(cli, &gtk_surface_interface, 1, id);
886         wl_resource_set_implementation(res, &gsurface_iface, NULL, NULL);
887 }
888
889 static struct gtk_shell_interface gshell_iface = {
890         .get_gtk_surface = gshell_get_gtk_surface,
891 };
892
893 /*******************
894  * Wayland Globals *
895  *******************/
896
897 /* References */
898 static struct wl_global *ref_shm;
899 static struct wl_global *ref_output;
900 static struct wl_global *ref_seat;
901 static struct wl_global *ref_ddm;
902 static struct wl_global *ref_comp;
903 static struct wl_global *ref_shell;
904 static struct wl_global *ref_xshell;
905 static struct wl_global *ref_gshell;
906
907 /* Bind functions */
908 static void bind_shm(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
909 {
910         printf("bind_shm\n");
911
912         if (version > 1)
913                 version = 1;
914
915         struct wl_resource *res = wl_resource_create(cli, &wl_shm_interface, version, id);
916         wl_resource_set_implementation(res, &shm_iface, NULL, NULL);
917
918         wl_shm_send_format(res, WL_SHM_FORMAT_XRGB8888);
919         wl_shm_send_format(res, WL_SHM_FORMAT_ARGB8888);
920 }
921
922 static void bind_output(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
923 {
924         printf("bind_output\n");
925
926         struct wl_resource *res = wl_resource_create(cli, &wl_output_interface, version, id);
927         output = res;
928
929         wl_output_send_geometry(res,
930                         0, 0, 330, 210,              // x/y (px), w/h (mm)
931                         WL_OUTPUT_SUBPIXEL_UNKNOWN,  // subpixel format
932                         "unknown", "unknown",        // make, model
933                         WL_OUTPUT_TRANSFORM_NORMAL); // rotatoin
934         wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 800,  600,  60);
935         wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 1024, 768,  60);
936         wl_output_send_mode(res, WL_OUTPUT_MODE_CURRENT, 1280, 1024, 60);
937         wl_output_send_done(res);
938 }
939
940 static void bind_seat(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
941 {
942         printf("bind_seat\n");
943
944         struct wl_resource *res = wl_resource_create(cli, &wl_seat_interface, version, id);
945         wl_resource_set_implementation(res, &seat_iface, NULL, NULL);
946
947         wl_seat_send_capabilities(res,
948                         WL_SEAT_CAPABILITY_KEYBOARD |
949                         WL_SEAT_CAPABILITY_POINTER);
950 }
951
952 static void bind_ddm(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
953 {
954         printf("bind_ddm\n");
955
956         struct wl_resource *res = wl_resource_create(cli, &wl_data_device_manager_interface, version, id);
957         wl_resource_set_implementation(res, &ddm_iface, NULL, NULL);
958 }
959
960 static void bind_comp(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
961 {
962         printf("bind_comp\n");
963         struct wl_resource *res = wl_resource_create(cli, &wl_compositor_interface, version, id);
964         wl_resource_set_implementation(res, &comp_iface, NULL, NULL);
965 }
966
967 static void bind_shell(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
968 {
969         printf("bind_shell\n");
970         struct wl_resource *res = wl_resource_create(cli, &wl_shell_interface, version, id);
971         wl_resource_set_implementation(res, &shell_iface, NULL, NULL);
972 }
973
974 static void bind_xshell(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
975 {
976         printf("bind_xshell\n");
977         struct wl_resource *res = wl_resource_create(cli, &xdg_shell_interface, version, id);
978         wl_resource_set_implementation(res, &xshell_iface, NULL, NULL);
979 }
980
981 static void bind_gshell(struct wl_client *cli, void *data, uint32_t version, uint32_t id)
982 {
983         printf("bind_gshell\n");
984         struct wl_resource *res = wl_resource_create(cli, &gtk_shell_interface, version, id);
985         wl_resource_set_implementation(res, &gshell_iface, NULL, NULL);
986 }
987
988 /*****************
989  * Gtk Callbacks *
990  *****************/
991
992 static void on_destroy(GtkWidget *widget, GdkEvent *event, gpointer user_data)
993 {
994         printf("on_destroy\n");
995         sys_exit();
996 }
997
998 static gboolean on_key(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
999 {
1000         /* Handle special keys */
1001         if (event->keyval == GDK_KEY_q)
1002                 sys_exit();
1003         if (event->keyval == GDK_KEY_t)
1004                 g_spawn_command_line_async("st-wl", NULL);
1005
1006         /* Send key to wayland */
1007         printf(g_ascii_isprint(event->keyval)
1008                 ? "on_key - win=%p cdata=%p '%c'\n"
1009                 : "on_key - win=%p cdata=%p 0x%X\n",
1010                 focus, focus?focus->sys->cdata:0, event->keyval);
1011         if (!focus || !focus->sys->cdata)
1012                 return FALSE;
1013         for (list_t *cur = focus->sys->cdata->kbds; cur; cur = cur->next) {
1014                 uint32_t serial = get_serial();
1015                 uint32_t stamp  = get_time();
1016                 uint32_t key    = event->hardware_keycode-8;
1017                 uint32_t state  = event->type == GDK_KEY_PRESS
1018                         ? WL_KEYBOARD_KEY_STATE_PRESSED
1019                         : WL_KEYBOARD_KEY_STATE_RELEASED;
1020                 wl_keyboard_send_key(cur->data, serial, stamp, key, state);
1021                 printf("    send -> %p tm=%d key=%d state=%d\n",
1022                                 cur->data, stamp, key, state);
1023         }
1024         return TRUE;
1025 }
1026
1027 static gboolean on_button(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1028 {
1029         win_t *win = find_win(event->x, event->y);
1030         printf("on_button - win=%p cdata=%p\n",
1031                         win, win?win->sys->cdata:0);
1032         if (!win || !win->sys->cdata)
1033                 return FALSE;
1034         for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next) {
1035                 uint32_t serial = get_serial();
1036                 uint32_t stamp  = get_time();
1037                 uint32_t button = BTN_MOUSE+(event->button-1);
1038                 uint32_t state  = event->type == GDK_BUTTON_PRESS
1039                         ? WL_POINTER_BUTTON_STATE_PRESSED
1040                         : WL_POINTER_BUTTON_STATE_RELEASED;
1041                 wl_pointer_send_button(cur->data, serial, stamp, button, state);
1042                 printf("    send -> %p tm=%d btn=%d state=%d\n",
1043                                 cur->data, stamp, button, state);
1044         }
1045         return TRUE;
1046 }
1047
1048 static gboolean on_move(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
1049 {
1050         win_t *win = find_win(event->x, event->y);
1051         if (!win)
1052                 return FALSE;
1053
1054         /* Keys */
1055         static struct wl_array keys;
1056
1057         /* Queue draw event for cursor */
1058         gtk_widget_queue_draw(screen);
1059
1060         /* Save cursor position */
1061         cursor_x = event->x;
1062         cursor_y = event->y;
1063
1064         /* Create event */
1065         wl_fixed_t x = wl_fixed_from_double(event->x - win->x);
1066         wl_fixed_t y = wl_fixed_from_double(event->y - win->y);
1067
1068         /* No focus change */
1069         if (win == focus && win->sys->cdata) {
1070                 uint32_t t = get_time();
1071                 for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next)
1072                         wl_pointer_send_motion(cur->data, t, x, y);
1073                 return TRUE;
1074         }
1075
1076         /* Send leave event */
1077         uint32_t s = get_serial();
1078         if  (focus && focus->sys->sfc && focus->sys->cdata) {
1079                 printf("on_move - leave win=%p\n", focus);
1080                 for (list_t *cur = focus->sys->cdata->ptrs; cur; cur = cur->next)
1081                         wl_pointer_send_leave(cur->data, s, focus->sys->sfc);
1082                 for (list_t *cur = focus->sys->cdata->kbds; cur; cur = cur->next)
1083                         wl_keyboard_send_leave(cur->data, s, focus->sys->sfc);
1084         }
1085         if  (win && win->sys->sfc && win->sys->cdata) {
1086                 for (list_t *cur = win->sys->cdata->ptrs; cur; cur = cur->next) {
1087                         printf("on_move - enter win=%p ptr=%p\n", win, cur->data);
1088                         wl_pointer_send_enter(cur->data, s, win->sys->sfc, x, y);
1089                 }
1090                 for (list_t *cur = win->sys->cdata->kbds; cur; cur = cur->next) {
1091                         printf("on_move - enter win=%p kbd=%p\n", win, cur->data);
1092                         wl_keyboard_send_enter(cur->data, s, win->sys->sfc, &keys);
1093                 }
1094         }
1095         focus = win;
1096         return TRUE;
1097 }
1098
1099 static void on_size(GtkWidget *widget, GtkAllocation *alloc, gpointer user_data)
1100 {
1101         printf("on_size - %dx%d\n", alloc->width, alloc->height);
1102         root->w = alloc->width;
1103         root->h = alloc->height;
1104 }
1105
1106 static gboolean on_draw(GtkWidget *widget, cairo_t *cairo, gpointer user_data)
1107 {
1108         printf("on_draw\n");
1109
1110         wm_update(); // Hacks for now
1111
1112         /* Draw windows bottom up */
1113         list_t *bottom = list_last(windows);
1114         for (list_t *cur = bottom; cur; cur = cur->prev) {
1115                 win_t       *win   = cur->data;
1116                 if (win->sys->buf == NULL)
1117                         continue;
1118                 if (win->type == TYPE_CURSOR)
1119                         continue;
1120                 sys_bdata_t *bdata = wl_resource_get_user_data(win->sys->buf);
1121                 int x = win->type == TYPE_NORMAL ? win->x : win->sys->x;
1122                 int y = win->type == TYPE_NORMAL ? win->y : win->sys->y;
1123                 if (win->sys->wx) x -= win->sys->wx;
1124                 if (win->sys->wy) y -= win->sys->wy;
1125                 printf("    win = %p\n", win);
1126                 cairo_surface_mark_dirty(bdata->surface);
1127                 cairo_set_source_surface(cairo, bdata->surface, x, y);
1128                 cairo_paint(cairo);
1129                 //wl_buffer_send_release(win->sys->buf);
1130                 //win->sys->buf = 0;
1131         }
1132
1133         /* Draw cursor */
1134         if (cursor && cursor->sys->buf) {
1135                 int x = cursor_x, y = cursor_y;
1136                 sys_bdata_t *bdata = wl_resource_get_user_data(cursor->sys->buf);
1137                 cairo_surface_mark_dirty(bdata->surface);
1138                 cairo_set_source_surface(cairo, bdata->surface, x, y);
1139                 cairo_paint(cairo);
1140         }
1141
1142         return TRUE;
1143 }
1144
1145 static gboolean on_wayland(gpointer user_data)
1146 {
1147         // TODO - convert to polled execution
1148         wl_display_flush_clients(display);
1149         wl_event_loop_dispatch(events, 0);
1150         return TRUE;
1151 }
1152
1153 /********************
1154  * System functions *
1155  ********************/
1156 void sys_move(win_t *win, int x, int y, int w, int h)
1157 {
1158         static uint32_t        active;
1159         static struct wl_array states;
1160         if (!active) {
1161                 active = XDG_SURFACE_STATE_ACTIVATED;
1162                 wl_array_init(&states);
1163                 uint32_t *ptr = wl_array_add(&states, sizeof(active));
1164                 if (ptr)
1165                         *ptr = active;
1166         }
1167
1168         printf("sys_move: %p - %d,%d  %dx%d\n",
1169                         win, x, y, w, h);
1170
1171         if (win->x == x && win->y == y &&
1172             win->w == w && win->h == h)
1173                 return;
1174
1175         win->x = x;
1176         win->y = y;
1177         win->w = w;
1178         win->h = h;
1179
1180         if (win->sys->ssfc)
1181                 wl_shell_surface_send_configure(win->sys->ssfc,
1182                                 WL_SHELL_SURFACE_RESIZE_NONE, w, h);
1183
1184         if (win->sys->xsfc)
1185                 xdg_surface_send_configure(win->sys->xsfc,
1186                                 w, h, &states, get_serial());
1187 }
1188
1189 void sys_raise(win_t *win)
1190 {
1191         printf("sys_raise: %p\n", win);
1192 }
1193
1194 void sys_focus(win_t *win)
1195 {
1196         printf("sys_focus: %p\n", win);
1197 }
1198
1199 void sys_show(win_t *win, state_t state)
1200 {
1201         printf("sys_show: %p: %d\n", win, state);
1202 }
1203
1204 void sys_watch(win_t *win, event_t ev, mod_t mod)
1205 {
1206         printf("sys_watch: %p - %x %hhx\n",
1207                         win, ev, mod2int(mod));
1208 }
1209
1210 void sys_unwatch(win_t *win, event_t ev, mod_t mod)
1211 {
1212         printf("sys_unwatch: %p - %x %hhx\n",
1213                         win, ev, mod2int(mod));
1214 }
1215
1216 list_t *sys_info(win_t *win)
1217 {
1218         printf("sys_info: %p\n", win);
1219         return list_insert(NULL, win);
1220 }
1221
1222 win_t *sys_init(void)
1223 {
1224         printf("sys_init\n");
1225
1226         /* Create root window */
1227         root = new0(win_t);
1228         root->x = 0;
1229         root->y = 0;
1230         root->w = 800;
1231         root->h = 600;
1232
1233         /* Register log handler */
1234         wl_log_set_handler_server((wl_log_func_t)vprintf);
1235
1236         /* Open the display */
1237         if (!(display = wl_display_create()))
1238                 error("Unable to  create display");
1239         if (wl_display_add_socket(display, NULL) != 0)
1240                 error("Unable to add socket");
1241         if (!(events = wl_display_get_event_loop(display)))
1242                 error("Unable to get event loop");
1243
1244         /* Register interfaces */
1245         ref_shm    = wl_global_create(display, &wl_shm_interface,                 1, NULL, &bind_shm);
1246         ref_output = wl_global_create(display, &wl_output_interface,              2, NULL, &bind_output);
1247         ref_ddm    = wl_global_create(display, &wl_data_device_manager_interface, 1, NULL, &bind_ddm);
1248         ref_shell  = wl_global_create(display, &wl_shell_interface,               1, NULL, &bind_shell);
1249         ref_comp   = wl_global_create(display, &wl_compositor_interface,          3, NULL, &bind_comp);
1250         ref_seat   = wl_global_create(display, &wl_seat_interface,                4, NULL, &bind_seat);
1251         ref_xshell = wl_global_create(display, &xdg_shell_interface,              1, NULL, &bind_xshell);
1252         ref_gshell = wl_global_create(display, &gtk_shell_interface,              1, NULL, &bind_gshell);
1253
1254         /* Setup GTK display */
1255         gtk_init(&conf_argc, &conf_argv);
1256         screen = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1257         gtk_widget_add_events(screen,
1258                         GDK_KEY_PRESS_MASK |
1259                         GDK_BUTTON_PRESS_MASK |
1260                         GDK_BUTTON_RELEASE_MASK |
1261                         GDK_POINTER_MOTION_MASK);
1262         g_signal_connect(screen, "destroy",              G_CALLBACK(on_destroy), NULL);
1263         g_signal_connect(screen, "key-press-event",      G_CALLBACK(on_key),     NULL);
1264         g_signal_connect(screen, "key-release-event",    G_CALLBACK(on_key),     NULL);
1265         g_signal_connect(screen, "button-press-event",   G_CALLBACK(on_button),  NULL);
1266         g_signal_connect(screen, "button-release-event", G_CALLBACK(on_button),  NULL);
1267         g_signal_connect(screen, "motion-notify-event",  G_CALLBACK(on_move),    NULL);
1268         g_signal_connect(screen, "size-allocate",        G_CALLBACK(on_size),    NULL);
1269         g_signal_connect(screen, "draw",                 G_CALLBACK(on_draw),    NULL);
1270         g_timeout_add(1000/60, on_wayland, NULL);
1271         gtk_widget_show(screen);
1272
1273         return root;
1274 }
1275
1276 void sys_run(win_t *root)
1277 {
1278         printf("sys_run: %p\n", root);
1279         gtk_main();
1280 }
1281
1282 void sys_exit(void)
1283 {
1284         printf("sys_exit\n");
1285         gtk_main_quit();
1286 }
1287
1288 void sys_free(win_t *root)
1289 {
1290         printf("sys_free: %p\n", root);
1291 }
1292