shell: implement wl_shell_interface
[platform/core/uifw/libds-tizen.git] / src / libds / shell.c
1 #include <assert.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4
5 #include "libds/log.h"
6 #include "libds/shell.h"
7
8 #include "shell.h"
9
10 #define WL_SHELL_VERSION 1
11 #define SHELL_PING_TIMEOUT  10000
12
13 static void shell_handle_display_destroy(struct wl_listener *listener,
14         void *data);
15 static void shell_bind(struct wl_client *wl_client, void *data,
16         uint32_t verison, uint32_t id);
17
18 WL_EXPORT struct ds_shell *
19 ds_shell_create(struct wl_display *display)
20 {
21     struct ds_shell *shell;
22
23     shell = calloc(1, sizeof *shell);
24     if (!shell) {
25         return NULL;
26     }
27
28     shell->global = wl_global_create(display, &wl_shell_interface,
29             WL_SHELL_VERSION, shell, shell_bind);
30     if (!shell->global) {
31         free(shell);
32         return NULL;
33     }
34
35     wl_list_init(&shell->clients);
36
37     shell->display_destroy.notify = shell_handle_display_destroy;
38     wl_display_add_destroy_listener(display, &shell->display_destroy);
39
40     wl_signal_init(&shell->events.destroy);
41     wl_signal_init(&shell->events.new_surface);
42
43     shell->ping_timeout = SHELL_PING_TIMEOUT;
44
45     ds_inf("Global created: xdg_wm_base shell(%p)", shell);
46
47     return shell;
48 }
49
50 WL_EXPORT void
51 ds_shell_add_destroy_listener(struct ds_shell *shell,
52         struct wl_listener *listener)
53 {
54     wl_signal_add(&shell->events.destroy, listener);
55 }
56
57 WL_EXPORT void
58 ds_shell_add_new_surface_listener(struct ds_shell *shell,
59         struct wl_listener *listener)
60 {
61     wl_signal_add(&shell->events.new_surface, listener);
62 }
63
64 static void
65 shell_handle_display_destroy(struct wl_listener *listener, void *data)
66 {
67     struct ds_shell *shell;
68
69     shell = wl_container_of(listener, shell, display_destroy);
70
71     ds_inf("Global destroy: xdg_wm_base shell(%p)", shell);
72
73     wl_signal_emit(&shell->events.destroy, shell);
74     wl_list_remove(&shell->display_destroy.link);
75     wl_global_destroy(shell->global);
76     free(shell);
77 }
78
79 static void
80 shell_handle_get_shell_surface(struct wl_client *wl_client,
81         struct wl_resource *resource, uint32_t id,
82         struct wl_resource *surface_resource)
83 {
84     struct ds_shell_client *client;
85     struct ds_surface *surface;
86
87     client = wl_resource_get_user_data(resource);
88     surface = ds_surface_from_resource(surface_resource);
89     create_shell_surface(client, surface, id);
90 }
91
92 static const struct wl_shell_interface shell_impl =
93 {
94     .get_shell_surface = shell_handle_get_shell_surface,
95 };
96
97 static void
98 shell_client_handle_resource_destroy(struct wl_resource *resource)
99 {
100     struct ds_shell_client *client;
101     struct ds_shell_surface *shell_surface, *tmp;
102
103     client = wl_resource_get_user_data(resource);
104
105     wl_list_for_each_safe(shell_surface, tmp, &client->shell_surfaces, link)
106         destroy_shell_surface(shell_surface);
107
108     if (client->ping_timer != NULL)
109         wl_event_source_remove(client->ping_timer);
110
111     wl_list_remove(&client->link);
112     free(client);
113 }
114
115 static int
116 shell_client_handle_ping_timeout(void *user_data)
117 {
118     struct ds_shell_client *client = user_data;
119     struct ds_shell_surface *surface;
120
121     wl_list_for_each(surface, &client->shell_surfaces, link)
122         wl_signal_emit(&surface->events.ping_timeout, surface);
123
124     client->ping_serial = 0;
125
126     return 1;
127 }
128
129 static void
130 shell_client_init_ping_timer(struct ds_shell_client *client)
131 {
132     struct wl_display *display;
133     struct wl_event_loop *loop;
134
135     display = wl_client_get_display(client->wl_client);
136     loop = wl_display_get_event_loop(display);
137     client->ping_timer = wl_event_loop_add_timer(loop,
138             shell_client_handle_ping_timeout, client);
139     if (client->ping_timer == NULL)
140         wl_client_post_no_memory(client->wl_client);
141 }
142
143 static void
144 shell_bind(struct wl_client *wl_client, void *data, uint32_t version,
145         uint32_t id)
146 {
147     struct ds_shell *shell = data;
148     struct ds_shell_client *client;
149
150     client = calloc(1, sizeof *client);
151     if (client == NULL) {
152         wl_client_post_no_memory(wl_client);
153         return;
154     }
155
156     client->wl_client = wl_client;
157     client->shell = shell;
158
159     wl_list_init(&client->shell_surfaces);
160
161     client->resource =
162         wl_resource_create(wl_client, &wl_shell_interface, version, id);
163     if (client->resource == NULL) {
164         free(client);
165         wl_client_post_no_memory(wl_client);
166         return;
167     }
168
169     wl_resource_set_implementation(client->resource, &shell_impl, client,
170             shell_client_handle_resource_destroy);
171
172     wl_list_insert(&shell->clients, &client->link);
173
174     shell_client_init_ping_timer(client);
175 }