1 /*
2 * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture GmbH
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27
28 #include <weston.h>
29 #include <libweston-desktop.h>
30 #include "config-parser.h"
31 #include <ivi-layout-export.h>
32
33 #ifndef INVALID_ID
34 #define INVALID_ID 0xFFFFFFFF
35 #endif
36
37 struct db_elem
38 {
39 struct wl_list link;
40 uint32_t surface_id;
41 char *cfg_app_id;
42 char *cfg_title;
43 struct ivi_layout_surface *layout_surface;
44 };
45
46 struct ivi_id_agent
47 {
48 uint32_t default_behavior_set;
49 uint32_t default_surface_id;
50 uint32_t default_surface_id_max;
51 struct wl_list app_list;
52 struct weston_compositor *compositor;
53 const struct ivi_layout_interface *interface;
54
55 struct wl_listener desktop_surface_configured;
56 struct wl_listener destroy_listener;
57 struct wl_listener surface_removed;
58 };
59
60 static int32_t
check_config_parameter(char * cfg_val,char * val)61 check_config_parameter(char *cfg_val, char *val)
62 {
63 if (cfg_val == NULL)
64 return IVI_SUCCEEDED;
65 else if (val == NULL || strcmp(cfg_val, val) != 0)
66 return IVI_FAILED;
67
68 return IVI_SUCCEEDED;
69 }
70
71 static int32_t
get_id_from_config(struct ivi_id_agent * ida,struct ivi_layout_surface * layout_surface)72 get_id_from_config(struct ivi_id_agent *ida, struct ivi_layout_surface
73 *layout_surface) {
74 struct db_elem *db_elem;
75 char *temp_app_id = NULL;
76 char *temp_title = NULL;
77 int ret = IVI_FAILED;
78
79 struct weston_surface *weston_surface =
80 ida->interface->surface_get_weston_surface(layout_surface);
81
82 /* Get app id and title */
83 struct weston_desktop_surface *wds = weston_surface_get_desktop_surface(
84 weston_surface);
85
86 if (weston_desktop_surface_get_app_id(wds) != NULL)
87 temp_app_id = strdup(weston_desktop_surface_get_app_id(wds));
88
89 if (weston_desktop_surface_get_title(wds) != NULL)
90 temp_title = strdup(weston_desktop_surface_get_title(wds));
91
92 /*
93 * Check for every config parameter to be fulfilled. This part must be
94 * extended, if additional attributes are desired to be checked.
95 */
96 wl_list_for_each(db_elem, &ida->app_list, link)
97 {
98 if (check_config_parameter(db_elem->cfg_app_id, temp_app_id) == 0) {
99 if (check_config_parameter(db_elem->cfg_title, temp_title) == 0) {
100 /* Found configuration for application. */
101 int res = ida->interface->surface_set_id(layout_surface,
102 db_elem->surface_id);
103 if (res)
104 continue;
105
106 db_elem->layout_surface = layout_surface;
107 ret = IVI_SUCCEEDED;
108
109 break;
110 }
111 }
112 }
113
114 free(temp_app_id);
115 free(temp_title);
116
117 return ret;
118 }
119
120 /*
121 * This function generates the id of a surface in regard to the desired
122 * parameters. For implementation of different behavior in id generation please
123 * adjust this function.
124 * In this implementation the app_id and/or title of the application is used for
125 * identification. It is also possible to use the pid, uid or gid for example.
126 */
127 static int32_t
get_id(struct ivi_id_agent * ida,struct ivi_layout_surface * layout_surface)128 get_id(struct ivi_id_agent *ida, struct ivi_layout_surface *layout_surface)
129 {
130 if (get_id_from_config(ida, layout_surface) == IVI_SUCCEEDED)
131 return IVI_SUCCEEDED;
132
133 /* No default layer available */
134 if (ida->default_behavior_set == 0) {
135 weston_log("ivi-id-agent: Could not find configuration for application\n");
136 goto ivi_failed;
137
138 /* Default behavior for unknown applications */
139 } else if (ida->default_surface_id < ida->default_surface_id_max) {
140 weston_log("ivi-id-agent: No configuration for application adding to "
141 "default layer\n");
142
143 /*
144 * Check if ivi-shell application already created an application with
145 * desired surface_id
146 */
147 struct ivi_layout_surface *temp_layout_surf =
148 ida->interface->get_surface_from_id(
149 ida->default_surface_id);
150 if ((temp_layout_surf != NULL) && (temp_layout_surf != layout_surface)) {
151 weston_log("ivi-id-agent: surface_id already used by an ivi-shell "
152 "application\n");
153 goto ivi_failed;
154 }
155
156 ida->interface->surface_set_id(layout_surface,
157 ida->default_surface_id);
158 ida->default_surface_id++;
159
160 } else {
161 weston_log("ivi-id-agent: Interval for default surface_id generation "
162 "exceeded\n");
163 goto ivi_failed;
164 }
165
166 return IVI_SUCCEEDED;
167
168 ivi_failed:
169 return IVI_FAILED;
170 }
171
172 static void
desktop_surface_event_configure(struct wl_listener * listener,void * data)173 desktop_surface_event_configure(struct wl_listener *listener,
174 void *data)
175 {
176 struct ivi_id_agent *ida = wl_container_of(listener, ida,
177 desktop_surface_configured);
178
179 struct ivi_layout_surface *layout_surface =
180 (struct ivi_layout_surface *) data;
181
182 if (get_id(ida, layout_surface) == IVI_FAILED)
183 weston_log("ivi-id-agent: Could not create surface_id for application\n");
184 }
185
186 static void
surface_event_remove(struct wl_listener * listener,void * data)187 surface_event_remove(struct wl_listener *listener, void *data) {
188 struct ivi_id_agent *ida = wl_container_of(listener, ida,
189 surface_removed);
190 struct ivi_layout_surface *layout_surface =
191 (struct ivi_layout_surface *) data;
192 struct db_elem *db_elem = NULL;
193
194 wl_list_for_each(db_elem, &ida->app_list, link)
195 {
196 if(db_elem->layout_surface == layout_surface) {
197 db_elem->layout_surface = NULL;
198 break;
199 }
200 }
201 }
202
203 static int32_t deinit(struct ivi_id_agent *ida);
204
205 static void
id_agent_module_deinit(struct wl_listener * listener,void * data)206 id_agent_module_deinit(struct wl_listener *listener, void *data) {
207 (void)data;
208 struct ivi_id_agent *ida = wl_container_of(listener, ida, destroy_listener);
209
210 deinit(ida);
211 }
212
213 static int32_t
check_config(struct db_elem * curr_db_elem,struct ivi_id_agent * ida)214 check_config(struct db_elem *curr_db_elem, struct ivi_id_agent *ida)
215 {
216 struct db_elem *db_elem;
217
218 if (ida->default_surface_id <= curr_db_elem->surface_id
219 && curr_db_elem->surface_id <= ida->default_surface_id_max) {
220 weston_log("ivi-id-agent: surface_id: %d in default id interval "
221 "[%d, %d] (CONFIG ERROR)\n", curr_db_elem->surface_id,
222 ida->default_surface_id, ida->default_surface_id_max);
223 goto ivi_failed;
224 }
225
226 wl_list_for_each(db_elem, &ida->app_list, link)
227 {
228 if(curr_db_elem == db_elem)
229 continue;
230
231 if (db_elem->surface_id == curr_db_elem->surface_id) {
232 weston_log("ivi-id-agent: Duplicate surface_id: %d (CONFIG ERROR)\n",
233 curr_db_elem->surface_id);
234 goto ivi_failed;
235 }
236 }
237
238 return IVI_SUCCEEDED;
239
240 ivi_failed:
241 return IVI_FAILED;
242 }
243
244 static int32_t
read_config(struct ivi_id_agent * ida)245 read_config(struct ivi_id_agent *ida)
246 {
247 struct weston_config *config = NULL;
248 struct weston_config_section *section = NULL;
249 const char *name = NULL;
250
251 config = wet_get_config(ida->compositor);
252 if (!config)
253 goto ivi_failed;
254
255 section = weston_config_get_section(config, "desktop-app-default", NULL,
256 NULL);
257
258 if (section) {
259 weston_log("ivi-id-agent: Default behavior for unknown applications is "
260 "set\n");
261 ida->default_behavior_set = 1;
262
263 weston_config_section_get_uint(section, "default-surface-id",
264 &ida->default_surface_id, INVALID_ID);
265 weston_config_section_get_uint(section, "default-surface-id-max",
266 &ida->default_surface_id_max, INVALID_ID);
267
268 if (ida->default_surface_id == INVALID_ID ||
269 ida->default_surface_id_max == INVALID_ID) {
270 weston_log("ivi-id-agent: Missing configuration for default "
271 "behavior\n");
272 ida->default_behavior_set = 0;
273 }
274 } else {
275 ida->default_behavior_set = 0;
276 }
277
278 section = NULL;
279 while (weston_config_next_section(config, §ion, &name)) {
280 struct db_elem *db_elem = NULL;
281
282 if (strcmp(name, "desktop-app") != 0)
283 continue;
284
285 db_elem = calloc(1, sizeof *db_elem);
286 if (db_elem == NULL) {
287 weston_log("ivi-id-agent: No memory to allocate\n");
288 goto ivi_failed;
289 }
290
291 wl_list_insert(&ida->app_list, &db_elem->link);
292
293 weston_config_section_get_uint(section, "surface-id",
294 &db_elem->surface_id, INVALID_ID);
295
296 if (db_elem->surface_id == INVALID_ID) {
297 weston_log("ivi-id-agent: surface-id is not set in configuration\n");
298 goto ivi_failed;
299 }
300
301 weston_config_section_get_string(section, "app-id",
302 &db_elem->cfg_app_id, NULL);
303 weston_config_section_get_string(section, "app-title",
304 &db_elem->cfg_title, NULL);
305
306 if (db_elem->cfg_app_id == NULL && db_elem->cfg_title == NULL) {
307 weston_log("ivi-id-agent: Every parameter is NULL in app "
308 "configuration\n");
309 goto ivi_failed;
310 }
311
312 if (check_config(db_elem, ida) == IVI_FAILED) {
313 weston_log("ivi-id-agent: No valid config found, deinit...\n");
314 goto ivi_failed;
315 }
316 }
317
318 if(ida->default_behavior_set == 0 && wl_list_empty(&ida->app_list)) {
319 weston_log("ivi-id-agent: No valid config found, deinit...\n");
320 goto ivi_failed;
321 }
322
323 return IVI_SUCCEEDED;
324
325 ivi_failed:
326 return IVI_FAILED;
327 }
328
329 WL_EXPORT int32_t
id_agent_module_init(struct weston_compositor * compositor,const struct ivi_layout_interface * interface)330 id_agent_module_init(struct weston_compositor *compositor,
331 const struct ivi_layout_interface *interface)
332 {
333 struct ivi_id_agent *ida = NULL;
334
335 ida = calloc(1, sizeof *ida);
336 if (ida == NULL) {
337 weston_log("failed to allocate ivi_id_agent\n");
338 goto ivi_failed;
339 }
340
341 ida->compositor = compositor;
342 ida->interface = interface;
343 ida->desktop_surface_configured.notify = desktop_surface_event_configure;
344 ida->destroy_listener.notify = id_agent_module_deinit;
345 ida->surface_removed.notify = surface_event_remove;
346
347 wl_signal_add(&compositor->destroy_signal, &ida->destroy_listener);
348 ida->interface->add_listener_configure_desktop_surface(
349 &ida->desktop_surface_configured);
350 interface->add_listener_remove_surface(&ida->surface_removed);
351
352 wl_list_init(&ida->app_list);
353 if(read_config(ida) != 0) {
354 weston_log("ivi-id-agent: Read config failed\n");
355 deinit(ida);
356 goto ivi_failed;
357 }
358
359 return IVI_SUCCEEDED;
360
361 ivi_failed:
362 return IVI_FAILED;
363 }
364
365 static int32_t
deinit(struct ivi_id_agent * ida)366 deinit(struct ivi_id_agent *ida)
367 {
368 struct db_elem *db_elem;
369 wl_list_for_each(db_elem, &ida->app_list, link) {
370 free(db_elem->cfg_app_id);
371 free(db_elem->cfg_title);
372 free(db_elem);
373 }
374
375 wl_list_remove(&ida->desktop_surface_configured.link);
376 wl_list_remove(&ida->destroy_listener.link);
377 wl_list_remove(&ida->surface_removed.link);
378 free(ida);
379
380 return IVI_SUCCEEDED;
381 }
382