3ce466e51f45ea09591263261a3fc6188da3a8a0
[platform/upstream/enlightenment.git] / src / bin / e_info_client.c
1 #include "e.h"
2 #include "e_info_shared_types.h"
3 #include <time.h>
4 #include <dirent.h>
5 #include <sys/mman.h>
6
7 typedef void (*E_Info_Message_Cb)(const Eldbus_Message *msg);
8
9 typedef struct _E_Info_Client
10 {
11    /* eldbus */
12    int                eldbus_init;
13    Eldbus_Proxy      *proxy;
14    Eldbus_Connection *conn;
15    Eldbus_Object     *obj;
16
17    /* topvwins */
18    Eina_List         *win_list;
19
20    Eina_List         *input_dev;
21 } E_Info_Client;
22
23 typedef struct _E_Win_Info
24 {
25    Ecore_Window     id;         // native window id
26    uint32_t      res_id;
27    int           pid;
28    const char  *name;       // name of client window
29    int          x, y, w, h; // geometry
30    int          layer;      // value of E_Layer
31    int          vis;        // visibility
32    int          alpha;      // alpha window
33    int          opaque;
34    int          visibility;
35    int          iconic;
36    int          focused;
37    int          hwc;
38    const char  *layer_name; // layer name
39 } E_Win_Info;
40
41 #define VALUE_TYPE_FOR_TOPVWINS "uuisiiiiibbiibbis"
42 #define VALUE_TYPE_REQUEST_RESLIST "ui"
43 #define VALUE_TYPE_REPLY_RESLIST "ssi"
44 #define VALUE_TYPE_FOR_INPUTDEV "ssi"
45
46 static E_Info_Client e_info_client;
47
48 static int keepRunning = 1;
49 static void end_program(int sig);
50 static Eina_Bool _e_info_client_eldbus_message(const char *method, E_Info_Message_Cb cb);
51 static Eina_Bool _e_info_client_eldbus_message_with_args(const char *method, E_Info_Message_Cb cb, const char *signature, ...);
52
53 static E_Win_Info *
54 _e_win_info_new(Ecore_Window id, uint32_t res_id, int pid, Eina_Bool alpha, int opaque, const char *name, int x, int y, int w, int h, int layer, int visible, int visibility, int iconic, int focused, int hwc, const char *layer_name)
55 {
56    E_Win_Info *win = NULL;
57
58    win = E_NEW(E_Win_Info, 1);
59    EINA_SAFETY_ON_NULL_RETURN_VAL(win, NULL);
60
61    win->id = id;
62    win->res_id = res_id;
63    win->pid = pid;
64    win->name = eina_stringshare_add(name);
65    win->x = x;
66    win->y = y;
67    win->w = w;
68    win->h = h;
69    win->layer = layer;
70    win->alpha = alpha;
71    win->opaque = opaque;
72    win->vis = visible;
73    win->visibility = visibility;
74    win->iconic = iconic;
75    win->focused = focused;
76    win->hwc = hwc;
77    win->layer_name = eina_stringshare_add(layer_name);
78
79    return win;
80 }
81
82 static void
83 _e_win_info_free(E_Win_Info *win)
84 {
85    EINA_SAFETY_ON_NULL_RETURN(win);
86
87    if (win->name)
88      eina_stringshare_del(win->name);
89
90    if (win->layer_name)
91      eina_stringshare_del(win->layer_name);
92
93    E_FREE(win);
94 }
95
96 static void
97 _cb_window_info_get(const Eldbus_Message *msg)
98 {
99    const char *name = NULL, *text = NULL;
100    Eldbus_Message_Iter *array, *ec;
101    Eina_Bool res;
102
103    res = eldbus_message_error_get(msg, &name, &text);
104    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
105
106    res = eldbus_message_arguments_get(msg, "a("VALUE_TYPE_FOR_TOPVWINS")", &array);
107    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
108
109    while (eldbus_message_iter_get_and_next(array, 'r', &ec))
110      {
111         const char *win_name;
112         const char *layer_name;
113         int x, y, w, h, layer, visibility, opaque, hwc;
114         Eina_Bool visible, alpha, iconic, focused;
115         Ecore_Window id;
116         uint32_t res_id;
117         int pid;
118         E_Win_Info *win = NULL;
119         res = eldbus_message_iter_arguments_get(ec,
120                                                 VALUE_TYPE_FOR_TOPVWINS,
121                                                 &id,
122                                                 &res_id,
123                                                 &pid,
124                                                 &win_name,
125                                                 &x,
126                                                 &y,
127                                                 &w,
128                                                 &h,
129                                                 &layer,
130                                                 &visible,
131                                                 &alpha,
132                                                 &opaque,
133                                                 &visibility,
134                                                 &iconic,
135                                                 &focused,
136                                                 &hwc,
137                                                 &layer_name);
138         if (!res)
139           {
140              printf("Failed to get win info\n");
141              continue;
142           }
143
144         win = _e_win_info_new(id, res_id, pid, alpha, opaque, win_name, x, y, w, h, layer, visible, visibility, iconic, focused, hwc, layer_name);
145         e_info_client.win_list = eina_list_append(e_info_client.win_list, win);
146      }
147
148 finish:
149    if ((name) || (text))
150      {
151         printf("errname:%s errmsg:%s\n", name, text);
152      }
153 }
154
155 static void
156 _cb_input_device_info_get(const Eldbus_Message *msg)
157 {
158    const char *name = NULL, *text = NULL;
159    Eldbus_Message_Iter *array, *eldbus_msg;
160    Eina_Bool res;
161    E_Comp_Wl_Input_Device *dev;
162
163    res = eldbus_message_error_get(msg, &name, &text);
164    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
165
166    res = eldbus_message_arguments_get(msg, "a("VALUE_TYPE_FOR_INPUTDEV")", &array);
167    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
168
169    while (eldbus_message_iter_get_and_next(array, 'r', &eldbus_msg))
170      {
171         char *dev_name;
172         char *identifier;
173         int capability;
174         res = eldbus_message_iter_arguments_get(eldbus_msg,
175                                                 VALUE_TYPE_FOR_INPUTDEV,
176                                                 &dev_name,
177                                                 &identifier,
178                                                 &capability);
179         if (!res)
180           {
181              printf("Failed to get device info\n");
182              continue;
183           }
184
185         dev = E_NEW(E_Comp_Wl_Input_Device, 1);
186         dev->name = strdup(dev_name);
187         dev->identifier = strdup(identifier);
188         dev->capability = capability;
189
190         e_info_client.input_dev = eina_list_append(e_info_client.input_dev, dev);
191      }
192
193 finish:
194    if ((name) || (text))
195      {
196         printf("errname:%s errmsg:%s\n", name, text);
197      }
198 }
199
200 static void
201 _cb_input_keymap_info_get(const Eldbus_Message *msg)
202 {
203    const char *name = NULL, *text = NULL;
204    Eina_Bool res;
205    int i;
206    int min_keycode=0, max_keycode=0, fd=0, size=0, num_mods=0, num_groups = 0;
207    struct xkb_context *context = NULL;
208    struct xkb_keymap *keymap = NULL;
209    struct xkb_state *state = NULL;
210    xkb_keysym_t sym = XKB_KEY_NoSymbol;
211    char keyname[256] = {0, };
212    char *map = NULL;
213
214    res = eldbus_message_error_get(msg, &name, &text);
215    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
216
217    res = eldbus_message_arguments_get(msg, "hi", &fd, &size);
218    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
219
220    context = xkb_context_new(0);
221    EINA_SAFETY_ON_NULL_GOTO(context, finish);
222
223    map = mmap(NULL, size, 0x01, 0x0001, fd, 0);
224    if (map == ((void *)-1))
225      {
226         close(fd);
227         return;
228      }
229
230    keymap = xkb_map_new_from_string(context, map, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
231
232    munmap(map, size);
233    close(fd);
234
235    EINA_SAFETY_ON_NULL_GOTO(keymap, finish);
236    state = xkb_state_new(keymap);
237    EINA_SAFETY_ON_NULL_GOTO(state, finish);
238
239    min_keycode = xkb_keymap_min_keycode(keymap);
240    max_keycode = xkb_keymap_max_keycode(keymap);
241    num_groups = xkb_map_num_groups(keymap);
242    num_mods = xkb_keymap_num_mods(keymap);
243
244    printf("\n");
245    printf("    min keycode: %d\n", min_keycode);
246    printf("    max keycode: %d\n", max_keycode);
247    printf("    num_groups : %d\n", num_groups);
248    printf("    num_mods   : %d\n", num_mods);
249    for (i = 0; i < num_mods; i++)
250      {
251         printf("        [%2d] mod: %s\n", i, xkb_keymap_mod_get_name(keymap, i));
252      }
253
254    printf("\n\n\tkeycode\t\tkeyname\t\t  keysym\t    repeat\n");
255    printf("    ----------------------------------------------------------------------\n");
256
257    for (i = min_keycode; i < (max_keycode + 1); i++)
258      {
259         sym = xkb_state_key_get_one_sym(state, i);
260
261         memset(keyname, 0, sizeof(keyname));
262         xkb_keysym_get_name(sym, keyname, sizeof(keyname));
263
264         printf("\t%4d%-5s%-25s%-20p%-5d\n", i, "", keyname, (void *)sym, xkb_keymap_key_repeats(keymap, i));
265      }
266 finish:
267    if ((name) || (text ))
268      {
269         printf("errname:%s errmsg:%s\n", name, text);
270      }
271    if (state) xkb_state_unref(state);
272    if (keymap) xkb_map_unref(keymap);
273    if (context) xkb_context_unref(context);
274 }
275
276 static void
277 _e_info_client_proc_protocol_trace(int argc, char **argv)
278 {
279    char fd_name[PATH_MAX];
280    int pid;
281    Eina_Bool disable = EINA_FALSE;
282    char cwd[PATH_MAX];
283
284    if (argc != 3 || !argv[2])
285      {
286         printf("protocol-trace: Usage> enlightenment_info -protocol_trace [console | file path | disable]\n");
287         return;
288      }
289
290    pid = getpid();
291
292    cwd[0] = '\0';
293    if (!getcwd(cwd, sizeof(cwd)))
294      snprintf(cwd, sizeof(cwd), "/tmp");
295
296    if (!strncmp(argv[2], "console", 7))
297      snprintf(fd_name, PATH_MAX, "/proc/%d/fd/1", pid);
298    else if (!strncmp(argv[2], "disable", 7))
299      disable = EINA_TRUE;
300    else
301      {
302         if (argv[2][0] == '/')
303           snprintf(fd_name, PATH_MAX, "%s", argv[2]);
304         else
305           {
306              if (strlen(cwd) > 0)
307                snprintf(fd_name, PATH_MAX, "%s/%s", cwd, argv[2]);
308              else
309                snprintf(fd_name, PATH_MAX, "%s", argv[2]);
310           }
311      }
312
313    printf("protocol-trace: %s\n", disable ? "disable" : fd_name);
314
315    if (!_e_info_client_eldbus_message_with_args("protocol_trace", NULL, "s", disable ? "disable" : fd_name))
316      return;
317 }
318
319 static void
320 _e_info_client_proc_topvwins_info(int argc, char **argv)
321 {
322    E_Win_Info *win;
323    Eina_List *l;
324    int i = 0;
325    int prev_layer = -1;
326    const char *prev_layer_name = NULL;
327    E_Win_Info *nocomp_win = NULL;
328
329    if (!_e_info_client_eldbus_message("get_window_info", _cb_window_info_get))
330      return;
331
332    printf("%d Top level windows\n", eina_list_count(e_info_client.win_list));
333    printf("--------------------------------------[ topvwins ]----------------------------------------------------------\n");
334    printf(" No   Win_ID    RcsID    PID     w     h     x      y   Focus Depth Opaq Visi Icon  Map_State    Title              \n");
335    printf("------------------------------------------------------------------------------------------------------------\n");
336
337    if (!e_info_client.win_list)
338      {
339         printf("no window\n");
340         return;
341      }
342
343    EINA_LIST_FOREACH(e_info_client.win_list, l, win)
344      {
345         if (!win) return;
346         i++;
347         if (win->layer != prev_layer)
348           {
349              if (prev_layer != -1)
350                 printf("------------------------------------------------------------------------------------------------------------[%s]\n",
351                        prev_layer_name ? prev_layer_name : " ");
352              prev_layer = win->layer;
353              prev_layer_name = win->layer_name;
354           }
355         printf("%3d 0x%08x  %5d  %5d  %5d %5d %6d %6d   %c  %5d    %d   ", i, win->id, win->res_id, win->pid, win->w, win->h, win->x, win->y, win->focused ? 'O':' ', win->alpha? 32:24, win->opaque);
356         printf("%2d    %d   %-11s  %s\n", win->visibility, win->iconic, win->vis? "Viewable":"NotViewable", win->name?:"No Name");
357         if(win->hwc == 2) nocomp_win = win;
358      }
359
360    if (prev_layer_name)
361       printf("------------------------------------------------------------------------------------------------------------[%s]\n",
362              prev_layer_name ? prev_layer_name : " ");
363
364    if(nocomp_win)
365      printf("\nNocomp : %s(0x%08x)\n\n", nocomp_win->name?:"No Name", nocomp_win->id);
366
367    E_FREE_LIST(e_info_client.win_list, _e_win_info_free);
368 }
369
370 static void
371 _e_info_client_proc_input_device_info(int argc, char **argv)
372 {
373    E_Comp_Wl_Input_Device *dev;
374    Eina_List *l;
375    int i = 0;
376
377    if (!_e_info_client_eldbus_message("get_input_devices", _cb_input_device_info_get))
378      return;
379
380    printf("--------------------------------------[ input devices ]----------------------------------------------------------\n");
381    printf(" No                               Name                        identifier            Cap\n");
382    printf("-----------------------------------------------------------------------------------------------------------------\n");
383
384    if (!e_info_client.input_dev)
385      {
386         printf("no devices\n");
387         return;
388      }
389
390    EINA_LIST_FOREACH(e_info_client.input_dev, l, dev)
391      {
392         i++;
393         printf("%3d %50s %20s         ", i, dev->name, dev->identifier);
394         if (dev->capability & ECORE_DEVICE_POINTER) printf("Pointer | ");
395         if (dev->capability & ECORE_DEVICE_KEYBOARD) printf("Keyboard | ");
396         if (dev->capability & ECORE_DEVICE_TOUCH) printf("Touch | ");
397         printf("(0x%x)\n", dev->capability);
398      }
399
400    E_FREE_LIST(e_info_client.input_dev, free);
401 }
402
403 static void
404 _e_info_client_proc_keymap_info(int argc, char **argv)
405 {
406    if (!_e_info_client_eldbus_message("get_keymap", _cb_input_keymap_info_get))
407       return;
408 }
409
410 static char *
411 _directory_make(char *path)
412 {
413    char dir[PATH_MAX], curdir[PATH_MAX], stamp[PATH_MAX];
414    time_t timer;
415    struct tm *t, *buf;
416    char *fullpath;
417    DIR *dp;
418
419    timer = time(NULL);
420
421    buf = calloc (1, sizeof (struct tm));
422    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
423
424    t = localtime_r(&timer, buf);
425    if (!t)
426      {
427         free(buf);
428         printf("fail to get local time\n");
429         return NULL;
430      }
431
432    fullpath = (char*) calloc(1, PATH_MAX*sizeof(char));
433    if (!fullpath)
434      {
435         free(buf);
436         printf("fail to alloc pathname memory\n");
437         return NULL;
438      }
439
440    if (path && path[0] == '/')
441      snprintf(dir, PATH_MAX, "%s", path);
442    else
443      {
444         char *temp = getcwd(curdir, PATH_MAX);
445         if (!temp)
446           {
447              free(buf);
448              free(fullpath);
449              return NULL;
450           }
451         if (path)
452           {
453              if (strlen(curdir) == 1 && curdir[0] == '/')
454                snprintf(dir, PATH_MAX, "/%s", path);
455              else
456                snprintf(dir, PATH_MAX, "%s/%s", curdir, path);
457           }
458         else
459           snprintf(dir, PATH_MAX, "%s", curdir);
460      }
461
462    if (!(dp = opendir (dir)))
463      {
464         free(buf);
465         free(fullpath);
466         printf("not exist: %s\n", dir);
467         return NULL;
468      }
469    else
470       closedir (dp);
471
472    /* make the folder for the result of xwd files */
473    snprintf(stamp, PATH_MAX, "%04d%02d%02d.%02d%02d%02d", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
474
475    if (strlen(dir) == 1 && dir[0] == '/')
476      snprintf(fullpath, PATH_MAX, "/topvwins-%s", stamp);
477    else
478      snprintf(fullpath, PATH_MAX, "%s/topvwins-%s", dir, stamp);
479
480    free (buf);
481
482    if ((mkdir(fullpath, 0755)) < 0)
483      {
484         printf("fail: mkdir '%s'\n", fullpath);
485         free(fullpath);
486         return NULL;
487      }
488
489    printf("directory: %s\n", fullpath);
490
491    return fullpath;
492 }
493
494 static void
495 _e_info_client_proc_topvwins_shot(int argc, char **argv)
496 {
497    char *directory = _directory_make(argv[2]);
498    EINA_SAFETY_ON_NULL_RETURN(directory);
499
500    if (!_e_info_client_eldbus_message_with_args("dump_topvwins", NULL, "s", directory))
501      {
502         free(directory);
503         return;
504      }
505
506    free(directory);
507 }
508
509 static void
510 _e_info_client_proc_eina_log_levels(int argc, char **argv)
511 {
512    EINA_SAFETY_ON_FALSE_RETURN(argc == 3);
513    EINA_SAFETY_ON_NULL_RETURN(argv[2]);
514
515    if (!_e_info_client_eldbus_message_with_args("eina_log_levels", NULL, "s", argv[2]))
516      {
517         return;
518      }
519 }
520
521 static void
522 _e_info_client_proc_eina_log_path(int argc, char **argv)
523 {
524    char fd_name[PATH_MAX];
525    int pid;
526    char cwd[PATH_MAX];
527
528    EINA_SAFETY_ON_FALSE_RETURN(argc == 3);
529    EINA_SAFETY_ON_NULL_RETURN(argv[2]);
530
531    pid = getpid();
532
533    cwd[0] = '\0';
534    if (!getcwd(cwd, sizeof(cwd)))
535      snprintf(cwd, sizeof(cwd), "/tmp");
536
537    if (!strncmp(argv[2], "console", 7))
538      snprintf(fd_name, PATH_MAX, "/proc/%d/fd/1", pid);
539    else
540      {
541         if (argv[2][0] == '/')
542           snprintf(fd_name, PATH_MAX, "%s", argv[2]);
543         else
544           {
545              if (strlen(cwd) > 0)
546                snprintf(fd_name, PATH_MAX, "%s/%s", cwd, argv[2]);
547              else
548                snprintf(fd_name, PATH_MAX, "%s", argv[2]);
549           }
550      }
551
552    printf("eina-log-path: %s\n", fd_name);
553
554    if (!_e_info_client_eldbus_message_with_args("eina_log_path", NULL, "s", fd_name))
555      {
556         return;
557      }
558 }
559
560 static void
561 _cb_window_prop_get(const Eldbus_Message *msg)
562 {
563    const char *name = NULL, *text = NULL;
564    Eldbus_Message_Iter *array, *ec;
565    Eina_Bool res;
566
567    res = eldbus_message_error_get(msg, &name, &text);
568    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
569
570    res = eldbus_message_arguments_get(msg, "a(ss)", &array);
571    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
572
573    printf("--------------------------------------[ window prop ]-----------------------------------------------------\n");
574    while (eldbus_message_iter_get_and_next(array, 'r', &ec))
575      {
576         const char *title;
577         const char *value;
578         res = eldbus_message_iter_arguments_get(ec,
579                                                 "ss",
580                                                 &title,
581                                                 &value);
582         if (!res)
583           {
584              printf("Failed to get win prop info\n");
585              continue;
586           }
587
588         if (!strcmp(title, "[WINDOW PROP]"))
589            printf("---------------------------------------------------------------------------------------------------------\n");
590         else
591            printf("%20s : %s\n", title, value);
592      }
593    printf("----------------------------------------------------------------------------------------------------------\n");
594
595 finish:
596    if ((name) || (text))
597      {
598         printf("errname:%s errmsg:%s\n", name, text);
599      }
600 }
601
602 static void
603 _e_info_client_prop_prop_info(int argc, char **argv)
604 {
605    const static int WINDOW_ID_MODE = 0;
606    const static int WINDOW_PID_MODE = 1;
607    const static int WINDOW_NAME_MODE = 2;
608    const char *value;
609    uint32_t mode = 0;
610
611    if (argc < 3 || argv[2] == NULL)
612      {
613         printf("Error Check Args: enlightenment_info -prop [windowID]\n"
614                "                  enlightenment_info -prop -id [windowID]\n"
615                "                  enlightenment_info -prop -pid [PID]\n"
616                "                  enlightenment_info -prop -name [name]\n");
617         return;
618      }
619
620    if (strlen(argv[2]) > 2 && argv[2][0] == '-')
621      {
622         if (!strcmp(argv[2], "-id")) mode = WINDOW_ID_MODE;
623         if (!strcmp(argv[2], "-pid")) mode = WINDOW_PID_MODE;
624         if (!strcmp(argv[2], "-name")) mode = WINDOW_NAME_MODE;
625         value = (argc >= 4 ? argv[3] : NULL);
626      }
627    else
628      {
629         mode = WINDOW_ID_MODE;
630         value = argv[2];
631      }
632
633    if (!_e_info_client_eldbus_message_with_args("get_window_prop", _cb_window_prop_get, "us", mode, value))
634      {
635         printf("_e_info_client_eldbus_message_with_args error");
636         return;
637      }
638 }
639
640 static void
641 _cb_window_proc_connected_clients_get(const Eldbus_Message *msg)
642 {
643    const char *name = NULL, *text = NULL;
644    Eldbus_Message_Iter *array, *ec;
645    Eina_Bool res;
646
647    res = eldbus_message_error_get(msg, &name, &text);
648    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
649
650    res = eldbus_message_arguments_get(msg, "a(ss)", &array);
651    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
652
653    printf("--------------------------------------[ connected clients ]-----------------------------------------------------\n");
654    int cnt = 0;
655    while (eldbus_message_iter_get_and_next(array, 'r', &ec))
656      {
657         const char *title;
658         const char *value;
659         res = eldbus_message_iter_arguments_get(ec,
660                                                 "ss",
661                                                 &title,
662                                                 &value);
663         if (!res)
664           {
665              printf("Failed to get connected clients info\n");
666              continue;
667           }
668
669         if (!strcmp(title, "[Connected Clients]"))
670           {
671              printf("\n[%2d] %s\n", ++cnt, value);
672           }
673         else if (!strcmp(title, "[E_Client Info]"))
674           {
675              printf("      |----- %s :: %s\n", title, value);
676           }
677      }
678
679 finish:
680    if ((name) || (text))
681      {
682         printf("errname:%s errmsg:%s\n", name, text);
683      }
684 }
685
686 static void
687 _e_info_client_proc_connected_clients(int argc, char **argv)
688 {
689    if (!_e_info_client_eldbus_message("get_connected_clients", _cb_window_proc_connected_clients_get))
690      {
691         printf("_e_info_client_eldbus_message error");
692         return;
693      }
694 }
695
696 #define ROTATION_USAGE \
697    "[COMMAND] [ARG]...\n" \
698    "\tset     : Set the orientation of zone (Usage: set [zone-no] [rval(0|90|180|270)]\n" \
699    "\tinfo    : Get the information of zone's rotation (Usage: info [zone-no]) (Not Implemented)\n" \
700    "\tenable  : Enable the rotation of zone (Usage: enable [zone-no]\n" \
701    "\tdisable : Disable the rotation of zone (Usage: disable [zone-no]\n"
702
703 static void
704 _cb_rotation_query(const Eldbus_Message *msg)
705 {
706    (void)msg;
707    /* TODO: need implementation */
708 }
709
710 static void
711 _e_info_client_proc_rotation(int argc, char **argv)
712 {
713    E_Info_Rotation_Message req;
714    int32_t zone_num = -1;
715    int32_t rval = -1;
716    const int off_len = 2, cmd_len = 1;
717    Eina_Bool res = EINA_FALSE;
718
719    if (argc < off_len + cmd_len)
720      goto arg_err;
721
722    if (eina_streq(argv[off_len], "info"))
723      {
724         if (argc > off_len + cmd_len)
725           zone_num = atoi(argv[off_len + 1]);
726
727         res = _e_info_client_eldbus_message_with_args("rotation_query",
728                                                       _cb_rotation_query,
729                                                       "i", zone_num);
730      }
731    else
732      {
733         if (eina_streq(argv[off_len], "set"))
734           {
735              if (argc < off_len + cmd_len + 1)
736                goto arg_err;
737              else if (argc > off_len + cmd_len + 1)
738                {
739                   zone_num = atoi(argv[off_len + 1]);
740                   rval = atoi(argv[off_len + 2]);
741                }
742              else
743                rval = atoi(argv[off_len + 1]);
744
745              if ((rval < 0) || (rval > 270) || (rval % 90 != 0))
746                goto arg_err;
747
748              req = E_INFO_ROTATION_MESSAGE_SET;
749           }
750         else
751           {
752              if (argc > off_len + cmd_len)
753                zone_num = atoi(argv[off_len + 1]);
754
755              if (eina_streq(argv[off_len], "enable"))
756                req = E_INFO_ROTATION_MESSAGE_ENABLE;
757              else if (eina_streq(argv[off_len], "disable"))
758                req = E_INFO_ROTATION_MESSAGE_DISABLE;
759              else
760                goto arg_err;
761           }
762
763         res = _e_info_client_eldbus_message_with_args("rotation_message",
764                                                       NULL, "iii",
765                                                       req, zone_num, rval);
766      }
767
768    if (!res)
769      printf("_e_info_client_eldbus_message_with_args error");
770
771    return;
772 arg_err:
773    printf("Usage: enlightenment_info -rotation %s", ROTATION_USAGE);
774 }
775
776 #define RESLIST_USAGE \
777    "[-tree|-p]\n" \
778    "\t-tree     : All resources\n" \
779    "\t-p {pid}  : Specify client pid\n"
780
781 enum
782 {
783    DEFAULT_SUMMARY = 0,
784    TREE,
785    PID
786 };
787
788 static void
789 _pname_get(pid_t pid, char *name, int size)
790 {
791    if (!name) return;
792
793    FILE *h;
794    char proc[512], pname[512];
795    size_t len;
796
797    snprintf(proc, 512,"/proc/%d/cmdline", pid);
798
799    h = fopen(proc, "r");
800    if (!h) return;
801
802    len = fread(pname, sizeof(char), 512, h);
803    if (len > 0)
804      {
805         if ('\n' == pname[len - 1])
806           pname[len - 1] = '\0';
807      }
808
809    fclose(h);
810
811    strncpy(name, pname, size);
812 }
813
814
815 static void
816 _cb_disp_res_lists_get(const Eldbus_Message *msg)
817 {
818    const char *name = NULL, *text = NULL;
819    Eldbus_Message_Iter *array, *resource;
820    Eina_Bool res;
821    int nClient = 0, nResource = 0;
822    char temp[PATH_MAX];
823    int pid = 0;
824
825    res = eldbus_message_error_get(msg, &name, &text);
826    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
827
828    res = eldbus_message_arguments_get(msg, "a("VALUE_TYPE_REPLY_RESLIST")", &array);
829    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
830
831    snprintf(temp, PATH_MAX,"%6s   %6s   %s   %s\n", "NO", "PID", "N_of_Res", "NAME");
832    printf("%s",temp);
833
834    while (eldbus_message_iter_get_and_next(array, 'r', &resource))
835      {
836         char cmd[512] = {0, };
837         const char *type;
838         const char *item;
839         int id = 0;
840         res = eldbus_message_iter_arguments_get(resource,
841                                                 VALUE_TYPE_REPLY_RESLIST,
842                                                 &type,
843                                                 &item,
844                                                 &id);
845         if (!res)
846           {
847              printf("Failed to get connected clients info\n");
848              continue;
849           }
850         if (!strcmp(type, "[client]"))
851           {
852              pid = id;
853              nResource = 0;
854              ++nClient;
855           }
856         else if (!strcmp(type, "[count]"))
857           {
858              nResource = id;
859              _pname_get(pid, cmd, sizeof(cmd));
860
861              printf("%6d   %6d   %4d      %9s\n", nClient, pid, nResource, cmd);
862              pid = 0;
863           }
864      }
865
866 finish:
867    if ((name) || (text))
868      {
869         printf("errname:%s errmsg:%s\n", name, text);
870      }
871 }
872
873 static void
874 _cb_disp_res_lists_get_detail(const Eldbus_Message *msg)
875 {
876    const char *name = NULL, *text = NULL;
877    Eldbus_Message_Iter *array, *resource;
878    Eina_Bool res;
879    int nClient = 0, nResource = 0;
880
881    res = eldbus_message_error_get(msg, &name, &text);
882    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
883
884    res = eldbus_message_arguments_get(msg, "a("VALUE_TYPE_REPLY_RESLIST")", &array);
885    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
886
887    while (eldbus_message_iter_get_and_next(array, 'r', &resource))
888      {
889         const char *type;
890         const char *item;
891         char cmd[512] = {0, };
892         int id = 0, pid = 0;
893
894         res = eldbus_message_iter_arguments_get(resource,
895                                                 VALUE_TYPE_REPLY_RESLIST,
896                                                 &type,
897                                                 &item,
898                                                 &id);
899
900         if (!res)
901           {
902              printf("Failed to get connected clients info\n");
903              continue;
904           }
905         if (!strcmp(type, "[client]"))
906           {
907              nResource = 0;
908              pid = id;
909              ++nClient;
910              _pname_get(pid, cmd, sizeof(cmd));
911              printf("[%2d] pid %d  (%s)\n", nClient, pid, cmd);
912
913           }
914         else if (!strcmp(type, "[resource]"))
915           {
916              ++nResource;
917              printf("      |----- %s obj@%d\n", item, id);
918           }
919
920      }
921
922 finish:
923    if ((name) || (text))
924      {
925         printf("errname:%s errmsg:%s\n", name, text);
926      }
927 }
928
929 static void
930 _e_info_client_proc_res_lists(int argc, char **argv)
931 {
932    uint32_t mode;
933    int pid = 0;
934
935    if (argc == 2)
936      {
937         mode = DEFAULT_SUMMARY;
938         if (!_e_info_client_eldbus_message_with_args("get_res_lists", _cb_disp_res_lists_get, VALUE_TYPE_REQUEST_RESLIST, mode, pid))
939           {
940              printf("%s error\n", __FUNCTION__);
941              return;
942           }
943      }
944    else if (argc == 3)
945      {
946         if (eina_streq(argv[2], "-tree")) mode = TREE;
947         else goto arg_err;
948
949         if (!_e_info_client_eldbus_message_with_args("get_res_lists", _cb_disp_res_lists_get_detail, VALUE_TYPE_REQUEST_RESLIST, mode, pid))
950           {
951              printf("%s error\n", __FUNCTION__);
952              return;
953           }
954      }
955    else if (argc == 4)
956      {
957         if (eina_streq(argv[2], "-p"))
958           {
959              mode = PID;
960              pid = atoi(argv[3]);
961              if (pid <= 0) goto arg_err;
962           }
963         else goto arg_err;
964
965         if (!_e_info_client_eldbus_message_with_args("get_res_lists", _cb_disp_res_lists_get_detail, VALUE_TYPE_REQUEST_RESLIST, mode, pid))
966           {
967              printf("%s error\n", __FUNCTION__);
968              return;
969           }
970      }
971    else goto arg_err;
972
973    return;
974 arg_err:
975    printf("Usage: enlightenment_info -reslist\n%s", RESLIST_USAGE);
976
977 }
978
979 static void
980 _cb_fps_info_get(const Eldbus_Message *msg)
981 {
982    const char *name = NULL, *text = NULL;
983    Eina_Bool res;
984    const char *fps;
985
986    res = eldbus_message_error_get(msg, &name, &text);
987    EINA_SAFETY_ON_TRUE_GOTO(res, finish);
988
989    res = eldbus_message_arguments_get(msg, "s", &fps);
990    EINA_SAFETY_ON_FALSE_GOTO(res, finish);
991    if (strcmp(fps, "no_update"))
992         printf("%s\n", fps);
993
994 finish:
995    if ((name) || (text ))
996      {
997         printf("errname:%s errmsg:%s\n", name, text);
998      }
999 }
1000
1001 static void
1002 _e_info_client_proc_fps_info(int argc, char **argv)
1003 {
1004    keepRunning = 1;
1005
1006    do
1007      {
1008         if (!_e_info_client_eldbus_message("get_fps_info", _cb_fps_info_get))
1009           return;
1010         sleep(1);
1011      }
1012    while (keepRunning);
1013 }
1014
1015 static void
1016 _e_info_client_proc_transform_set(int argc, char **argv)
1017 {
1018    int32_t id_enable_xy_sxsy_angle[8];
1019    int i;
1020
1021    if (argc < 5)
1022      {
1023         printf("Error Check Args: enlightenment_info -transform [windowID] [transform id] [enable] [x] [y] [scale_x(percent)] [scale_y(percent)] [degree] [keep_ratio]\n");
1024         return;
1025      }
1026
1027    id_enable_xy_sxsy_angle[0] = 0;      // transform id
1028    id_enable_xy_sxsy_angle[1] = 1;      // enable
1029    id_enable_xy_sxsy_angle[2] = 0;      // move x
1030    id_enable_xy_sxsy_angle[3] = 0;      // move y
1031    id_enable_xy_sxsy_angle[4] = 100;    // scale x percent
1032    id_enable_xy_sxsy_angle[5] = 100;    // scale y percent
1033    id_enable_xy_sxsy_angle[6] = 0;      // rotation degree
1034    id_enable_xy_sxsy_angle[7] = 0;      // keep ratio
1035
1036    for (i = 0 ; i < 8 &&  i+3 < argc; ++i)
1037       id_enable_xy_sxsy_angle[i] = atoi(argv[i+3]);
1038
1039    if (!_e_info_client_eldbus_message_with_args("transform_message", NULL, "siiiiiiii",
1040                                                 argv[2], id_enable_xy_sxsy_angle[0] , id_enable_xy_sxsy_angle[1], id_enable_xy_sxsy_angle[2],
1041                                                 id_enable_xy_sxsy_angle[3], id_enable_xy_sxsy_angle[4], id_enable_xy_sxsy_angle[5],
1042                                                 id_enable_xy_sxsy_angle[6], id_enable_xy_sxsy_angle[7]))
1043      {
1044         printf("_e_info_client_eldbus_message_with_args error");
1045         return;
1046      }
1047 }
1048
1049 static void
1050 _e_info_client_proc_buffer_shot(int argc, char **argv)
1051 {
1052    if (argc == 3)
1053      {
1054         int dumprun = atoi(argv[2]);
1055
1056         if (dumprun < 0 || dumprun > 1)
1057           {
1058              printf("Error Check Args : enlightenment_info -dump_buffers [1: start, 0: stop]\n");
1059              return;
1060           }
1061
1062         if (!_e_info_client_eldbus_message_with_args("dump_buffers", NULL, "i", dumprun))
1063           {
1064              printf("_e_info_client_proc_buffer_shot fail (%d)\n", dumprun);
1065              return;
1066           }
1067         printf("_e_info_client_proc_buffer_shot %s\n", (dumprun == 1 ? "start" : "stop"));
1068      }
1069    else
1070      {
1071         printf("Error Check Args : enlightenment_info -dump_buffers [1: start, 0: stop]\n");
1072      }
1073 }
1074
1075 #ifdef HAVE_HWC
1076 static void
1077 _e_info_client_proc_hwc_trace(int argc, char **argv)
1078 {
1079    uint32_t onoff;
1080
1081    if (argc < 3)
1082      {
1083         printf("Error Check Args: enlightenment_info -hwc_trace [0/1]\n");
1084         return;
1085      }
1086
1087    onoff = atoi(argv[2]);
1088
1089    if (onoff == 1 || onoff == 0)
1090      {
1091         if (!_e_info_client_eldbus_message_with_args("hwc_trace_message", NULL, "i", onoff))
1092           {
1093              printf("_e_info_client_eldbus_message_with_args error");
1094              return;
1095           }
1096      }
1097    else
1098      printf("Error Check Args: enlightenment_info -hwc_trace [0/1]\n");
1099 }
1100 #endif
1101
1102 static struct
1103 {
1104    const char *option;
1105    const char *params;
1106    const char *description;
1107    void (*func)(int argc, char **argv);
1108 } procs[] =
1109 {
1110    {
1111       "protocol_trace", "[console|file_path|disable]",
1112       "Enable/disable wayland protocol trace",
1113       _e_info_client_proc_protocol_trace
1114    },
1115    {
1116       "topvwins", NULL,
1117       "Print top visible windows",
1118       _e_info_client_proc_topvwins_info
1119    },
1120    {
1121       "dump_topvwins", "[directory_path]",
1122       "Dump top-level visible windows (default directory_path : current working directory)",
1123       _e_info_client_proc_topvwins_shot
1124    },
1125    {
1126       "eina_log_levels", "[mymodule1:5,mymodule2:2]",
1127       "Set EINA_LOG_LEVELS in runtime",
1128       _e_info_client_proc_eina_log_levels
1129    },
1130    {
1131       "eina_log_path", "[console|file_path]",
1132       "Set eina-log path in runtime",
1133       _e_info_client_proc_eina_log_path
1134    },
1135    {
1136       "prop", "[id]",
1137       "Print window infomation",
1138       _e_info_client_prop_prop_info
1139    },
1140    {
1141       "connected_clients", NULL,
1142       "Print connected clients on Enlightenment",
1143       _e_info_client_proc_connected_clients
1144    },
1145    {
1146       "rotation",
1147       ROTATION_USAGE,
1148       "Send a message about rotation",
1149       _e_info_client_proc_rotation
1150    },
1151    {
1152       "reslist",
1153       RESLIST_USAGE,
1154       "Print connected client's resources",
1155       _e_info_client_proc_res_lists
1156    },
1157    {
1158       "input_devices", NULL,
1159       "Print connected input devices",
1160       _e_info_client_proc_input_device_info
1161    },
1162    {
1163       "fps", NULL,
1164       "Print FPS in every sec",
1165       _e_info_client_proc_fps_info
1166    },
1167    {
1168       "transform",
1169       "[id enable x y w h angle keep_ratio]",
1170       "Set transform in runtime",
1171       _e_info_client_proc_transform_set
1172    },
1173    {
1174       "dump_buffers", "[start:1,stop:0]",
1175       "Dump attach buffers (start:1,stop:0, path:/tmp/dump_xxx/)",
1176       _e_info_client_proc_buffer_shot
1177    },
1178 #ifdef HAVE_HWC
1179    {
1180       "hwc_trace",
1181       "[on: 1, off: 0]",
1182       "Show the hwc trace log",
1183       _e_info_client_proc_hwc_trace
1184    },
1185 #endif
1186    {
1187       "keymap", NULL,
1188       "Print a current keymap",
1189       _e_info_client_proc_keymap_info
1190    },
1191 };
1192
1193 static void
1194 _e_info_client_eldbus_message_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED)
1195 {
1196    E_Info_Message_Cb cb = (E_Info_Message_Cb)data;
1197
1198    if (cb) cb(msg);
1199
1200    ecore_main_loop_quit();
1201 }
1202
1203 static Eina_Bool
1204 _e_info_client_eldbus_message(const char *method, E_Info_Message_Cb cb)
1205 {
1206    Eldbus_Pending *p;
1207
1208    p = eldbus_proxy_call(e_info_client.proxy, method,
1209                          _e_info_client_eldbus_message_cb,
1210                          cb, -1, "");
1211    EINA_SAFETY_ON_NULL_RETURN_VAL(p, EINA_FALSE);
1212
1213    ecore_main_loop_begin();
1214    return EINA_TRUE;
1215 }
1216
1217 static Eina_Bool
1218 _e_info_client_eldbus_message_with_args(const char *method, E_Info_Message_Cb cb, const char *signature, ...)
1219 {
1220    Eldbus_Pending *p;
1221    va_list ap;
1222
1223    va_start(ap, signature);
1224    p = eldbus_proxy_vcall(e_info_client.proxy, method,
1225                           _e_info_client_eldbus_message_cb,
1226                           cb, -1, signature, ap);
1227    va_end(ap);
1228    EINA_SAFETY_ON_NULL_RETURN_VAL(p, EINA_FALSE);
1229
1230    ecore_main_loop_begin();
1231    return EINA_TRUE;
1232 }
1233
1234 static void
1235 _e_info_client_eldbus_disconnect(void)
1236 {
1237    if (e_info_client.proxy)
1238      {
1239         eldbus_proxy_unref(e_info_client.proxy);
1240         e_info_client.proxy = NULL;
1241      }
1242
1243    if (e_info_client.obj)
1244      {
1245         eldbus_object_unref(e_info_client.obj);
1246         e_info_client.obj = NULL;
1247      }
1248
1249    if (e_info_client.conn)
1250      {
1251         eldbus_connection_unref(e_info_client.conn);
1252         e_info_client.conn = NULL;
1253      }
1254
1255    if (e_info_client.eldbus_init)
1256      {
1257         eldbus_shutdown();
1258         e_info_client.eldbus_init = 0;
1259      }
1260 }
1261
1262 static Eina_Bool
1263 _e_info_client_eldbus_connect(void)
1264 {
1265    e_info_client.eldbus_init = eldbus_init();
1266    EINA_SAFETY_ON_FALSE_GOTO(e_info_client.eldbus_init > 0, err);
1267
1268    e_info_client.conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
1269    EINA_SAFETY_ON_NULL_GOTO(e_info_client.conn, err);
1270
1271    e_info_client.obj = eldbus_object_get(e_info_client.conn,
1272                                          "org.enlightenment.wm",
1273                                          "/org/enlightenment/wm");
1274    EINA_SAFETY_ON_NULL_GOTO(e_info_client.obj, err);
1275
1276    e_info_client.proxy = eldbus_proxy_get(e_info_client.obj, "org.enlightenment.wm.info");
1277    EINA_SAFETY_ON_NULL_GOTO(e_info_client.proxy, err);
1278
1279    return EINA_TRUE;
1280
1281 err:
1282    _e_info_client_eldbus_disconnect();
1283    return EINA_FALSE;
1284 }
1285
1286 static Eina_Bool
1287 _e_info_client_process(int argc, char **argv)
1288 {
1289    int nproc = sizeof(procs) / sizeof(procs[0]);
1290    int i;
1291
1292    signal(SIGINT,  end_program);
1293    signal(SIGALRM, end_program);
1294    signal(SIGHUP,  end_program);
1295    signal(SIGPIPE, end_program);
1296    signal(SIGQUIT, end_program);
1297    signal(SIGTERM, end_program);
1298
1299    for (i = 0; i < nproc; i++)
1300      {
1301         if (!strncmp(argv[1]+1, procs[i].option, strlen(procs[i].option)))
1302           {
1303              if (procs[i].func)
1304                procs[i].func(argc, argv);
1305
1306              return EINA_TRUE;
1307           }
1308      }
1309
1310    return EINA_FALSE;
1311 }
1312
1313 static void
1314 _e_info_client_print_usage(const char *exec)
1315 {
1316    int nproc = sizeof(procs) / sizeof(procs[0]);
1317    int i;
1318
1319    printf("\nUsage:\n");
1320
1321    for (i = 0; i < nproc; i++)
1322      printf("  %s -%s %s\n", exec, procs[i].option, (procs[i].params)?procs[i].params:"");
1323
1324    printf("\nOptions:\n");
1325
1326    for (i = 0; i < nproc; i++)
1327      {
1328         printf("  -%s\n", procs[i].option);
1329         printf("      %s\n", (procs[i].description)?procs[i].description:"");
1330      }
1331
1332    printf("\n");
1333 }
1334
1335 static void
1336 end_program(int sig)
1337 {
1338    keepRunning = 0;
1339 }
1340
1341 int
1342 main(int argc, char **argv)
1343 {
1344    if (argc < 2 || argv[1][0] != '-')
1345      {
1346         _e_info_client_print_usage(argv[0]);
1347         return 0;
1348      }
1349
1350    /* connecting dbus */
1351    if (!_e_info_client_eldbus_connect())
1352      goto err;
1353
1354    if (!strcmp(argv[1], "-h") ||
1355        !strcmp(argv[1], "-help") ||
1356        !strcmp(argv[1], "--help"))
1357      {
1358         _e_info_client_print_usage(argv[0]);
1359      }
1360    else
1361      {
1362         /* handling a client request */
1363         if (!_e_info_client_process(argc, argv))
1364           {
1365              printf("unknown option: %s\n", argv[1]);
1366              _e_info_client_print_usage(argv[0]);
1367           }
1368      }
1369
1370    /* disconnecting dbus */
1371    _e_info_client_eldbus_disconnect();
1372
1373    return 0;
1374
1375 err:
1376    _e_info_client_eldbus_disconnect();
1377    return -1;
1378 }