Various patches are applied
[platform/framework/web/data-provider-master.git] / src / xmonitor.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <sys/ipc.h>
19 #include <sys/shm.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <malloc.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26
27 #include <Evas.h>
28 #include <Ecore_X.h>
29 #include <Ecore.h>
30
31 #include <sqlite3.h>
32
33 #include <gio/gio.h>
34 #include <dlog.h>
35 #include <livebox-errno.h>
36
37 #include "conf.h"
38 #include "debug.h"
39 #include "client_life.h"
40 #include "slave_life.h"
41 #include "main.h"
42 #include "util.h"
43 #include "setting.h"
44 #include "xmonitor.h"
45
46 int errno;
47
48 struct event_item {
49         int (*cb)(void *user_data);
50         void *user_data;
51 };
52
53 static struct info {
54         Ecore_Event_Handler *create_handler;
55         Ecore_Event_Handler *destroy_handler;
56         Ecore_Event_Handler *client_handler;
57
58         Eina_List *pause_list;
59         Eina_List *resume_list;
60
61         int paused;
62 } s_info = {
63         .create_handler = NULL,
64         .destroy_handler = NULL,
65         .client_handler = NULL,
66
67         .pause_list = NULL,
68         .resume_list = NULL,
69
70         .paused = 1, /*!< The provider is treated as paused process when it is launched */
71 };
72
73 static inline void touch_paused_file(void)
74 {
75         int fd;
76         fd = creat(PAUSED_FILE, 0644);
77         if (fd >= 0)
78                 close(fd);
79         else
80                 ErrPrint("Create .live.paused: %s\n", strerror(errno));
81 }
82
83 static inline void remove_paused_file(void)
84 {
85         if (unlink(PAUSED_FILE) < 0)
86                 ErrPrint("Unlink .live.paused: %s\n", strerror(errno));
87 }
88
89 static inline int get_pid(Ecore_X_Window win)
90 {
91         int pid;
92         Ecore_X_Atom atom;
93         unsigned char *in_pid;
94         int num;
95
96         atom = ecore_x_atom_get("X_CLIENT_PID");
97         if (ecore_x_window_prop_property_get(win, atom, ECORE_X_ATOM_CARDINAL,
98                                 sizeof(int), &in_pid, &num) == EINA_FALSE) {
99                 if (ecore_x_netwm_pid_get(win, &pid) == EINA_FALSE) {
100                         ErrPrint("Failed to get PID from a window 0x%X\n", win);
101                         return LB_STATUS_ERROR_INVALID;
102                 }
103         } else if (in_pid) {
104                 pid = *(int *)in_pid;
105                 DbgFree(in_pid);
106         } else {
107                 ErrPrint("Failed to get PID\n");
108                 return LB_STATUS_ERROR_INVALID;
109         }
110
111         return pid;
112 }
113
114 static Eina_Bool create_cb(void *data, int type, void *event)
115 {
116         Ecore_X_Event_Window_Create *info = event;
117         ecore_x_window_client_sniff(info->win);
118         return ECORE_CALLBACK_PASS_ON;
119 }
120
121 static Eina_Bool destroy_cb(void *data, int type, void *event)
122 {
123         // Ecore_X_Event_Window_Destroy *info = event;
124         return ECORE_CALLBACK_PASS_ON;
125 }
126
127 HAPI void xmonitor_handle_state_changes(void)
128 {
129         int paused;
130         Eina_List *l;
131         struct event_item *item;
132
133         paused = client_is_all_paused() || setting_is_lcd_off();
134         if (s_info.paused == paused)
135                 return;
136
137         s_info.paused = paused;
138
139         if (s_info.paused) {
140                 EINA_LIST_FOREACH(s_info.pause_list, l, item) {
141                         if (item->cb)
142                                 item->cb(item->user_data);
143                 }
144
145                 touch_paused_file();
146
147                 sqlite3_release_memory(SQLITE_FLUSH_MAX);
148                 malloc_trim(0);
149         } else {
150                 remove_paused_file();
151
152                 EINA_LIST_FOREACH(s_info.resume_list, l, item) {
153                         if (item->cb)
154                                 item->cb(item->user_data);
155                 }
156         }
157 }
158
159 HAPI int xmonitor_update_state(int target_pid)
160 {
161         Ecore_X_Window win;
162         struct client_node *client;
163         int pid;
164
165         if (!USE_XMONITOR)
166                 return LB_STATUS_SUCCESS;
167
168         win = ecore_x_window_focus_get();
169
170         pid = get_pid(win);
171         if (pid <= 0) {
172                 DbgPrint("Focused window has no PID %X\n", win);
173                 client = client_find_by_pid(target_pid);
174                 if (client) {
175                         DbgPrint("Client window has no focus now\n");
176                         client_paused(client);
177                 }
178                 return LB_STATUS_ERROR_NOT_EXIST;
179         }
180
181         client = client_find_by_pid(pid);
182         if (!client) {
183                 DbgPrint("Client %d is not registered yet\n", pid);
184                 client = client_find_by_pid(target_pid);
185                 if (client) {
186                         DbgPrint("Client window has no focus now\n");
187                         client_paused(client);
188                 }
189                 return LB_STATUS_ERROR_INVALID;
190         }
191
192         if (target_pid != pid) {
193                 DbgPrint("Client is paused\n");
194                 client_paused(client);
195         } else {
196                 DbgPrint("Client is resumed\n");
197                 client_resumed(client);
198         }
199
200         xmonitor_handle_state_changes();
201         return LB_STATUS_SUCCESS;
202 }
203
204 static Eina_Bool client_cb(void *data, int type, void *event)
205 {
206         Ecore_X_Event_Client_Message *info = event;
207         struct client_node *client;
208         char *name;
209         int pid;
210
211         pid = get_pid(info->win);
212         if (pid <= 0)
213                 return ECORE_CALLBACK_PASS_ON;
214
215         client = client_find_by_pid(pid);
216         if (!client)
217                 return ECORE_CALLBACK_PASS_ON;
218
219         name = ecore_x_atom_name_get(info->message_type);
220         if (!name)
221                 return ECORE_CALLBACK_PASS_ON;
222
223         if (!strcmp(name, "_X_ILLUME_DEACTIVATE_WINDOW")) {
224                 DbgPrint("PAUSE EVENT\n");
225                 xmonitor_pause(client);
226         } else if (!strcmp(name, "_X_ILLUME_ACTIVATE_WINDOW")) {
227                 DbgPrint("RESUME EVENT\n");
228                 xmonitor_resume(client);
229         } else {
230                 /* ignore event */
231         }
232
233         DbgFree(name);
234         return ECORE_CALLBACK_PASS_ON;
235 }
236
237 static inline void sniff_all_windows(void)
238 {
239         Ecore_X_Window root;
240         Ecore_X_Window ret;
241         struct stack_item *new_item;
242         struct stack_item *item;
243         Eina_List *win_stack;
244         //int pid;
245         struct stack_item {
246                 Ecore_X_Window *wins;
247                 int nr_of_wins;
248                 int i;
249         };
250
251         root = ecore_x_window_root_first_get();
252         ecore_x_window_sniff(root);
253
254         new_item = malloc(sizeof(*new_item));
255         if (!new_item) {
256                 ErrPrint("Error(%s)\n", strerror(errno));
257                 return;
258         }
259
260         new_item->nr_of_wins = 0;
261         new_item->wins =
262                 ecore_x_window_children_get(root, &new_item->nr_of_wins);
263         new_item->i = 0;
264
265         win_stack = NULL;
266
267         if (new_item->wins)
268                 win_stack = eina_list_append(win_stack, new_item);
269         else
270                 DbgFree(new_item);
271
272         while ((item = eina_list_nth(win_stack, 0))) {
273                 win_stack = eina_list_remove(win_stack, item);
274
275                 if (!item->wins) {
276                         DbgFree(item);
277                         continue;
278                 }
279
280                 while (item->i < item->nr_of_wins) {
281                         ret = item->wins[item->i];
282
283                         /*
284                          * Now we don't need to care about visibility of window,
285                          * just check whether it is registered or not.
286                          * (ecore_x_window_visible_get(ret))
287                          */
288                         ecore_x_window_client_sniff(ret);
289
290                         new_item = malloc(sizeof(*new_item));
291                         if (!new_item) {
292                                 ErrPrint("Error %s\n", strerror(errno));
293                                 item->i++;
294                                 continue;
295                         }
296
297                         new_item->i = 0;
298                         new_item->nr_of_wins = 0;
299                         new_item->wins =
300                                 ecore_x_window_children_get(ret,
301                                                         &new_item->nr_of_wins);
302                         if (new_item->wins) {
303                                 win_stack =
304                                         eina_list_append(win_stack, new_item);
305                         } else {
306                                 DbgFree(new_item);
307                         }
308
309                         item->i++;
310                 }
311
312                 DbgFree(item->wins);
313                 DbgFree(item);
314         }
315
316         return;
317 }
318
319 HAPI int xmonitor_pause(struct client_node *client)
320 {
321         DbgPrint("%d is paused\n", client_pid(client));
322         client_paused(client);
323         xmonitor_handle_state_changes();
324         return LB_STATUS_SUCCESS;
325 }
326
327 HAPI int xmonitor_resume(struct client_node *client)
328 {
329         DbgPrint("%d is resumed\n", client_pid(client));
330         client_resumed(client);
331         xmonitor_handle_state_changes();
332         return LB_STATUS_SUCCESS;
333 }
334
335 static inline void disable_xmonitor(void)
336 {
337         ecore_event_handler_del(s_info.create_handler);
338         ecore_event_handler_del(s_info.destroy_handler);
339         ecore_event_handler_del(s_info.client_handler);
340
341         s_info.create_handler = NULL;
342         s_info.destroy_handler = NULL;
343         s_info.client_handler = NULL;
344 }
345
346 static inline int enable_xmonitor(void)
347 {
348         if (ecore_x_composite_query() == EINA_FALSE)
349                 DbgPrint("====> COMPOSITOR IS NOT ENABLED\n");
350
351         s_info.create_handler =
352                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
353                                                         create_cb, NULL);
354         if (!s_info.create_handler) {
355                 ErrPrint("Failed to add create event handler\n");
356                 return LB_STATUS_ERROR_FAULT;
357         }
358
359         s_info.destroy_handler =
360                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY,
361                                                         destroy_cb, NULL);
362         if (!s_info.create_handler) {
363                 ErrPrint("Failed to add destroy event handler\n");
364                 ecore_event_handler_del(s_info.create_handler);
365                 s_info.create_handler = NULL;
366                 return LB_STATUS_ERROR_FAULT;
367         }
368
369         s_info.client_handler =
370                 ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
371                                                         client_cb, NULL);
372         if (!s_info.client_handler) {
373                 ErrPrint("Failed to add focus out event handler\n");
374                 ecore_event_handler_del(s_info.create_handler);
375                 ecore_event_handler_del(s_info.destroy_handler);
376                 s_info.create_handler = NULL;
377                 s_info.destroy_handler = NULL;
378                 return LB_STATUS_ERROR_FAULT;
379         }
380
381         sniff_all_windows();
382         return LB_STATUS_SUCCESS;
383 }
384
385 HAPI int xmonitor_init(void)
386 {
387         if (USE_XMONITOR) {
388                 int ret;
389                 ret = enable_xmonitor();
390                 if (ret < 0)
391                         return ret;
392         }
393
394         s_info.paused = client_is_all_paused() || setting_is_lcd_off();
395         if (s_info.paused)
396                 touch_paused_file();
397         else
398                 remove_paused_file();
399
400         return LB_STATUS_SUCCESS;
401 }
402
403 HAPI void xmonitor_fini(void)
404 {
405         if (USE_XMONITOR)
406                 disable_xmonitor();
407 }
408
409 HAPI int xmonitor_add_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data)
410 {
411         struct event_item *item;
412
413         item = malloc(sizeof(*item));
414         if (!item) {
415                 ErrPrint("Heap: %s\n", strerror(errno));
416                 return LB_STATUS_ERROR_MEMORY;
417         }
418
419         item->cb = cb;
420         item->user_data = user_data;
421
422         switch (event) {
423         case XMONITOR_PAUSED:
424                 s_info.pause_list = eina_list_prepend(s_info.pause_list, item);
425                 break;
426         case XMONITOR_RESUMED:
427                 s_info.resume_list = eina_list_prepend(s_info.resume_list, item);
428                 break;
429         default:
430                 ErrPrint("Invalid event type\n");
431                 DbgFree(item);
432                 return LB_STATUS_ERROR_INVALID;
433         }
434
435         return LB_STATUS_SUCCESS;
436 }
437
438 HAPI int xmonitor_del_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data)
439 {
440         struct event_item *item;
441         Eina_List *l;
442         Eina_List *n;
443
444         switch (event) {
445         case XMONITOR_PAUSED:
446                 EINA_LIST_FOREACH_SAFE(s_info.pause_list, l, n, item) {
447                         if (item->cb == cb && item->user_data == user_data) {
448                                 s_info.pause_list = eina_list_remove(s_info.pause_list, item);
449                                 DbgFree(item);
450                                 return LB_STATUS_SUCCESS;
451                         }
452                 }
453                 break;
454
455         case XMONITOR_RESUMED:
456                 EINA_LIST_FOREACH_SAFE(s_info.resume_list, l, n, item) {
457                         if (item->cb == cb && item->user_data == user_data) {
458                                 s_info.resume_list = eina_list_remove(s_info.resume_list, item);
459                                 DbgFree(item);
460                                 return LB_STATUS_SUCCESS;
461                         }
462                 }
463                 break;
464         default:
465                 ErrPrint("Invalid event type\n");
466                 return LB_STATUS_ERROR_INVALID;
467         }
468
469         return LB_STATUS_ERROR_NOT_EXIST;
470 }
471
472 HAPI int xmonitor_is_paused(void)
473 {
474         return s_info.paused;
475 }
476
477 /* End of a file */