chiark / gitweb /
Imported Debian patch 1.0.0-5
[e16] / src / ipc.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2009 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "aclass.h"
26 #include "borders.h"            /* FIXME - Should not be here */
27 #include "desktops.h"
28 #include "emodule.h"
29 #include "eobj.h"
30 #include "ewins.h"
31 #include "ewin-ops.h"
32 #include "focus.h"
33 #include "grabs.h"
34 #include "hints.h"              /* FIXME - Should not be here */
35 #include "screen.h"
36 #include "session.h"
37 #include "settings.h"
38 #include "snaps.h"
39 #include "timers.h"
40 #include "xwin.h"
41
42 #define ENABLE_IPC_INSERT_KEYS  0
43
44 #define SS(s) ((s) ? (s) : NoText)
45 static const char   NoText[] = "-NONE-";
46
47 static char        *ipc_bufptr = NULL;
48 static size_t       ipc_bufsiz = 0;
49 static char         ipc_active = 0;
50
51 static void
52 IpcPrintInit(void)
53 {
54    ipc_bufptr = NULL;
55    ipc_bufsiz = 0;
56    ipc_active = 1;
57 }
58
59 static void
60 IpcPrintDone(void)
61 {
62    Efree(ipc_bufptr);
63    ipc_bufptr = NULL;
64    ipc_bufsiz = 0;
65    ipc_active = 0;
66 }
67
68 static const char  *
69 IpcPrintGetBuffer(void)
70 {
71    if (!ipc_bufptr)
72       return NULL;
73    ipc_bufptr[ipc_bufsiz] = '\0';
74    return ipc_bufptr;
75 }
76
77 void
78 IpcPrintf(const char *fmt, ...)
79 {
80    char                tmp[FILEPATH_LEN_MAX];
81    int                 len;
82    va_list             args;
83
84    if (!ipc_active)
85       return;
86
87    va_start(args, fmt);
88    len = Evsnprintf(tmp, sizeof(tmp), fmt, args);
89    va_end(args);
90
91    ipc_bufptr = EREALLOC(char, ipc_bufptr, ipc_bufsiz + len + 1);
92
93    memcpy(ipc_bufptr + ipc_bufsiz, tmp, len);
94    ipc_bufsiz += len;
95 }
96
97 static int
98 SetEwinBoolean(const char *txt, char *item, const char *value, int set)
99 {
100    int                 vold, vnew;
101
102    vnew = vold = *item != 0;    /* Remember old value */
103
104    if (value == NULL || value[0] == '\0')
105       vnew = !vold;
106    else if (!strcmp(value, "on"))
107       vnew = 1;
108    else if (!strcmp(value, "off"))
109       vnew = 0;
110    else if (!strcmp(value, "?"))
111       IpcPrintf("%s: %s", txt, (vold) ? "on" : "off");
112    else
113       IpcPrintf("Error: %s", value);
114
115    if (vnew != vold)
116      {
117         if (set)
118            *item = vnew;
119         return 1;
120      }
121
122    return 0;
123 }
124
125 /* The IPC functions */
126
127 static void
128 IPC_Screen(const char *params)
129 {
130    char                param[1024];
131    int                 l;
132    const char         *p;
133
134    param[0] = '\0';
135    p = params;
136    if (p)
137      {
138         l = 0;
139         sscanf(p, "%1000s %n", param, &l);
140         p += l;
141      }
142
143    if (!p || !strncmp(param, "list", 2))
144      {
145         ScreenShowInfo(p);
146      }
147    else if (!strncmp(param, "size", 2))
148      {
149         IpcPrintf("Screen %d  size %dx%d\n", Dpy.screen,
150                   WinGetW(VROOT), WinGetH(VROOT));
151      }
152    else if (!strcmp(param, "split"))
153      {
154         unsigned int        nx, ny;
155
156         nx = 2;
157         ny = 1;
158         sscanf(p, "%u %u\n", &nx, &ny);
159         ScreenSplit(nx, ny);
160      }
161 }
162
163 static void
164 IPC_Nop(const char *params __UNUSED__)
165 {
166    IpcPrintf("nop");
167 }
168
169 /* Should be elsewhere */
170 static void
171 IPC_Border_CB_List(Border * b, void *data __UNUSED__)
172 {
173    IpcPrintf("%s\n", BorderGetName(b));
174 }
175
176 static void
177 IPC_Border(const char *params)
178 {
179    if (!params)
180      {
181         IpcPrintf("Please specify...\n");
182         return;
183      }
184
185    if (!strncmp(params, "list", 2))
186      {
187         BordersForeach(IPC_Border_CB_List, NULL);
188      }
189 }
190
191 static void
192 IPC_DialogOK(const char *params)
193 {
194    if (params)
195       DialogOKstr(_("Message"), params);
196    else
197       IpcPrintf("Error: No text for dialog specified\n");
198 }
199
200 static int
201 CfgStrlistIndex(const char **list, const char *str)
202 {
203    int                 i;
204
205    for (i = 0; list[i]; i++)
206       if (!strcmp(list[i], str))
207          return i;
208    return -1;
209 }
210
211 static const char  *MovResCfgMoveModes[] = {
212    "opaque", "lined", "box", "shaded", "semi-solid", "translucent", NULL
213 };
214
215 static const char  *MovResCfgResizeModes[] = {
216    "opaque", "lined", "box", "shaded", "semi-solid", NULL
217 };
218
219 static const char  *MovResCfgInfoModes[] = {
220    "never", "center", "corner", NULL
221 };
222
223 static void
224 IPC_MoveResize(const char *params)
225 {
226    char                param1[32];
227    char                param2[32];
228    int                 i;
229
230    if (!params)
231      {
232         IpcPrintf("Please specify...\n");
233         return;
234      }
235
236    param1[0] = param2[0] = '\0';
237    sscanf(params, "%31s %31s", param1, param2);
238
239    if (!strncmp(param1, "move", 2))
240      {
241         if (param2[0] == '\n' || param2[0] == '?')
242           {
243              if (Conf.movres.mode_move < 0 || Conf.movres.mode_move > 5)
244                 Conf.movres.mode_move = 0;
245              IpcPrintf("Move mode: %s\n",
246                        MovResCfgMoveModes[Conf.movres.mode_move]);
247              return;
248           }
249
250         i = CfgStrlistIndex(MovResCfgMoveModes, param2);
251         if (i >= 0)
252           {
253              Conf.movres.mode_move = i;
254           }
255         else
256           {
257              IpcPrintf("Move mode not found: %s\n", param2);
258           }
259
260      }
261    else if (!strncmp(param1, "resize", 2))
262      {
263         if (param2[0] == '\n' || param2[0] == '?')
264           {
265              if (Conf.movres.mode_resize < 0 || Conf.movres.mode_resize > 4)
266                 Conf.movres.mode_resize = 0;
267              IpcPrintf("Resize mode: %s\n",
268                        MovResCfgResizeModes[Conf.movres.mode_resize]);
269              return;
270           }
271
272         i = CfgStrlistIndex(MovResCfgResizeModes, param2);
273         if (i >= 0)
274           {
275              Conf.movres.mode_resize = i;
276           }
277         else
278           {
279              IpcPrintf("Resize mode not found: %s\n", param2);
280           }
281
282      }
283    else if (!strncmp(param1, "info", 2))
284      {
285         if (param2[0] == '\n' || param2[0] == '?')
286           {
287              if (Conf.movres.mode_info < 0 || Conf.movres.mode_info > 2)
288                 Conf.movres.mode_info = 1;
289              IpcPrintf("Info mode: %s\n",
290                        MovResCfgInfoModes[Conf.movres.mode_info]);
291              return;
292           }
293
294         i = CfgStrlistIndex(MovResCfgInfoModes, param2);
295         if (i >= 0)
296           {
297              Conf.movres.mode_info = i;
298           }
299         else
300           {
301              IpcPrintf("Info mode not found: %s\n", param2);
302           }
303
304      }
305 }
306
307 static void
308 IPC_WinList(const char *params)
309 {
310    static const char  *const TxtPG[] = { "NW", "NE", "SW", "SE" };
311    char                format[8];
312    const char         *match;
313    EWin              **lst, *e;
314    int                 num, i;
315
316    format[0] = '\0';
317    match = params;
318    if (match)
319      {
320         num = 0;
321         sscanf(params, "%8s %n", format, &num);
322         match += num;
323      }
324    if (!match || !match[0])
325       match = "all";
326
327    lst = EwinsFindByExpr(match, &num, NULL);
328    if (!lst)
329      {
330         IpcPrintf("No windows matching %s\n", match);
331         return;
332      }
333
334    for (i = 0; i < num; i++)
335      {
336         e = lst[i];
337         switch (format[0])
338           {
339           case '\0':
340              IpcPrintf("%#lx : %s\n", EwinGetClientXwin(e),
341                        SS(EwinGetIcccmName(e)));
342              break;
343
344           default:
345              IpcPrintf("%#lx : %s :: %d : %d %d : %d %d %dx%d\n",
346                        EwinGetClientXwin(e), SS(EwinGetIcccmName(e)),
347                        (EoIsSticky(e)) ? -1 : (int)EoGetDeskNum(e), e->area_x,
348                        e->area_y, EoGetX(e), EoGetY(e), EoGetW(e), EoGetH(e));
349              break;
350
351           case 'a':
352              IpcPrintf("%#10lx : %5d %5d %4dx%4d :: %2d : %d %d : %s\n",
353                        EwinGetClientXwin(e), EoGetX(e), EoGetY(e), EoGetW(e),
354                        EoGetH(e), (EoIsSticky(e)) ? -1 : (int)EoGetDeskNum(e),
355                        e->area_x, e->area_y, SS(EwinGetIcccmName(e)));
356              break;
357
358           case 'g':
359              IpcPrintf
360                 ("%#10lx : %5d %5d %4dx%4d :: %2d : %s %4d,%4d %2d,%2d : %s\n",
361                  EwinGetClientXwin(e), EoGetX(e), EoGetY(e), EoGetW(e),
362                  EoGetH(e), (EoIsSticky(e)) ? -1 : (int)EoGetDeskNum(e),
363                  TxtPG[e->place.gravity & 3], e->place.gx, e->place.gy,
364                  e->place.ax, e->place.ay, SS(EwinGetIcccmName(e)));
365              break;
366
367           case 'p':
368              IpcPrintf
369                 ("%#10lx : %5d %5d %4dx%4d :: %2d : \"%s\" \"%s\" : \"%s\" : \"%s\"\n",
370                  EwinGetClientXwin(e), EoGetX(e), EoGetY(e), EoGetW(e),
371                  EoGetH(e), (EoIsSticky(e)) ? -1 : (int)EoGetDeskNum(e),
372                  SS(EwinGetIcccmCName(e)), SS(EwinGetIcccmClass(e)),
373                  SS(EwinGetIcccmName(e)), SS(e->icccm.wm_role));
374              break;
375           }
376      }
377    Efree(lst);
378 }
379
380 #if 0                           /* TBD */
381 static int
382 doMoveConstrained(EWin * ewin, const char *params)
383 {
384    return ActionMoveStart(ewin, 0, params, 1, 0);
385 }
386
387 static int
388 doMoveNoGroup(EWin * ewin, const char *params)
389 {
390    return ActionMoveStart(ewin, 0, params, 0, 1);
391 }
392
393 static int
394 doSwapMove(EWin * ewin, const char *params)
395 {
396    Mode.move.swap = 1;
397    return ActionMoveStart(ewin, 0, params, 0, 0);
398 }
399
400 static int
401 doMoveConstrainedNoGroup(EWin * ewin, const char *params)
402 {
403    return ActionMoveStart(ewin, 0, params, 1, 1);
404 }
405 #endif
406
407 static Timer       *op_timer = NULL;
408
409 static int
410 OpacityTimeout(void *data)
411 {
412    EWin               *ewin = (EWin *) data;
413
414    if (!EwinFindByPtr(ewin))    /* May be gone */
415       goto done;
416
417    if (ewin->state.active)
418       EoChangeOpacity(ewin, ewin->props.focused_opacity);
419
420  done:
421    ewin->state.show_coords = 0;
422    op_timer = NULL;
423    return 0;
424 }
425
426 static void
427 IpcWinop(const WinOp * wop, EWin * ewin, const char *prm)
428 {
429    char                param1[128], param2[128];
430    unsigned int        val;
431    char                on;
432    int                 a, b;
433
434    param1[0] = param2[0] = '\0';
435    sscanf(prm, "%128s %128s", param1, param2);
436
437    switch (wop->op)
438      {
439      default:
440         /* We should not get here */
441         IpcPrintf("Error: unknown operation");
442         return;
443
444      case EWIN_OP_BORDER:
445         if (!param1[0])
446           {
447              IpcPrintf("Error: no border specified");
448              goto done;
449           }
450         if (!strcmp(param1, "?"))
451           {
452              IpcPrintf("window border: %s", BorderGetName(ewin->border));
453              goto done;
454           }
455         EwinOpSetBorder(ewin, OPSRC_USER, param1);
456         break;
457
458      case EWIN_OP_TITLE:
459         if (!prm[0])
460           {
461              IpcPrintf("Error: no title specified");
462              goto done;
463           }
464         if (!strcmp(prm, "?"))
465           {
466              IpcPrintf("title: %s", EwinGetIcccmName(ewin));
467              goto done;
468           }
469         HintsSetWindowName(EwinGetClientWin(ewin), prm);
470         break;
471
472      case EWIN_OP_CLOSE:
473         EwinOpClose(ewin, OPSRC_USER);
474         break;
475
476      case EWIN_OP_KILL:
477         EwinOpKill(ewin, OPSRC_USER);
478         break;
479
480      case EWIN_OP_ICONIFY:
481         on = ewin->state.iconified;
482         if (SetEwinBoolean("window iconified", &on, param1, 1))
483            EwinOpIconify(ewin, OPSRC_USER, on);
484         break;
485
486      case EWIN_OP_ALONE:
487         EwinAlone(ewin);
488         break;
489
490      case EWIN_OP_SHADE:
491         on = ewin->state.shaded;
492         if (SetEwinBoolean(wop->name, &on, param1, 1))
493            EwinOpShade(ewin, OPSRC_USER, on);
494         break;
495
496      case EWIN_OP_STICK:
497         on = EoIsSticky(ewin);
498         if (SetEwinBoolean(wop->name, &on, param1, 1))
499            EwinOpStick(ewin, OPSRC_USER, on);
500         break;
501
502      case EWIN_OP_FOCUS:
503         if (!strcmp(param1, "?"))
504           {
505              IpcPrintf("focused: %s", (ewin == GetFocusEwin())? "yes" : "no");
506              goto done;
507           }
508         EwinOpActivate(ewin, OPSRC_USER, 1);
509         break;
510
511      case EWIN_OP_DESK:
512         if (!param1[0])
513           {
514              IpcPrintf("Error: no desktop supplied");
515              goto done;
516           }
517         if (!strncmp(param1, "next", 1))
518           {
519              EwinOpMoveToDesk(ewin, OPSRC_USER, EoGetDesk(ewin), 1);
520           }
521         else if (!strncmp(param1, "prev", 1))
522           {
523              EwinOpMoveToDesk(ewin, OPSRC_USER, EoGetDesk(ewin), -1);
524           }
525         else if (!strcmp(param1, "?"))
526           {
527              IpcPrintf("window desk: %d", EoGetDeskNum(ewin));
528           }
529         else
530           {
531              EwinOpMoveToDesk(ewin, OPSRC_USER, NULL, atoi(param1));
532           }
533         break;
534
535      case EWIN_OP_AREA:
536         if (!param1[0])
537           {
538              IpcPrintf("Error: no area supplied");
539              goto done;
540           }
541         if (!strcmp(param1, "?"))
542           {
543              IpcPrintf("window area: %d %d", ewin->area_x, ewin->area_y);
544           }
545         else if (!strcmp(param1, "move"))
546           {
547              a = b = 0;
548              sscanf(prm, "%*s %i %i", &a, &b);
549              EwinMoveToArea(ewin, ewin->area_x + a, ewin->area_y + b);
550           }
551         else
552           {
553              a = ewin->area_x;
554              b = ewin->area_y;
555              sscanf(param1, "%i", &a);
556              sscanf(param2, "%i", &b);
557              EwinMoveToArea(ewin, a, b);
558           }
559         break;
560
561      case EWIN_OP_MOVE:
562         if (!param1[0])
563           {
564              IpcPrintf("Error: no coords supplied");
565              goto done;
566           }
567         if (!strcmp(param1, "ptr"))
568           {
569              ActionMoveStart(ewin, 0, 0, Mode.nogroup);
570           }
571         else if (!strcmp(param1, "kbd"))
572           {
573              ActionMoveStart(ewin, 1, 0, Mode.nogroup);
574           }
575         else if (!strcmp(param1, "?"))
576           {
577              IpcPrintf("window location: %d %d", EoGetX(ewin), EoGetY(ewin));
578           }
579         else if (!strcmp(param1, "??"))
580           {
581              IpcPrintf("client location: %d %d",
582                        EoGetX(ewin) + ewin->border->border.left,
583                        EoGetY(ewin) + ewin->border->border.top);
584           }
585         else
586           {
587              a = EoGetX(ewin);
588              b = EoGetY(ewin);
589              sscanf(param1, "%i", &a);
590              sscanf(param2, "%i", &b);
591              EwinOpMove(ewin, OPSRC_USER, a, b);
592           }
593         break;
594
595      case EWIN_OP_SIZE:
596         if (!param1[0])
597            goto done;
598
599         if (!strcmp(param1, "ptr"))
600           {
601              ActionResizeStart(ewin, 0, MODE_RESIZE);
602           }
603         else if (!strcmp(param1, "ptr-h"))
604           {
605              ActionResizeStart(ewin, 0, MODE_RESIZE_H);
606           }
607         else if (!strcmp(param1, "ptr-v"))
608           {
609              ActionResizeStart(ewin, 0, MODE_RESIZE_V);
610           }
611         else if (!strcmp(param1, "kbd"))
612           {
613              ActionResizeStart(ewin, 1, MODE_RESIZE);
614           }
615         else if (!strcmp(param1, "?"))
616           {
617              IpcPrintf("window size: %d %d", ewin->client.w, ewin->client.h);
618           }
619         else if (!strcmp(param1, "??"))
620           {
621              IpcPrintf("frame size: %d %d", EoGetW(ewin), EoGetH(ewin));
622           }
623         else
624           {
625              a = ewin->client.w;
626              b = ewin->client.h;
627              sscanf(param1, "%i", &a);
628              sscanf(param2, "%i", &b);
629              EwinOpResize(ewin, OPSRC_USER, a, b);
630           }
631         break;
632
633      case EWIN_OP_MOVE_REL:
634         if (!param1[0])
635            goto done;
636         a = b = 0;
637         sscanf(prm, "%i %i", &a, &b);
638         a += EoGetX(ewin);
639         b += EoGetY(ewin);
640         EwinOpMove(ewin, OPSRC_USER, a, b);
641         break;
642
643      case EWIN_OP_SIZE_REL:
644         if (!param1[0])
645            goto done;
646         a = b = 0;
647         sscanf(prm, "%i %i", &a, &b);
648         a += ewin->client.w;
649         b += ewin->client.h;
650         EwinOpResize(ewin, OPSRC_USER, a, b);
651         break;
652
653      case EWIN_OP_MAX_WIDTH:
654         MaxSizeHV(ewin, param1, 1, 0);
655         break;
656
657      case EWIN_OP_MAX_HEIGHT:
658         MaxSizeHV(ewin, param1, 0, 1);
659         break;
660
661      case EWIN_OP_MAX_SIZE:
662         MaxSizeHV(ewin, param1, 1, 1);
663         break;
664
665      case EWIN_OP_FULLSCREEN:
666         on = ewin->state.fullscreen;
667         if (SetEwinBoolean(wop->name, &on, param1, 1))
668            EwinOpFullscreen(ewin, OPSRC_USER, on);
669         break;
670
671      case EWIN_OP_ZOOM:
672         if (InZoom())
673            Zoom(NULL);
674         else
675            Zoom(ewin);
676         break;
677
678      case EWIN_OP_LAYER:
679         if (!strcmp(param1, "?"))
680           {
681              IpcPrintf("window layer: %d", EoGetLayer(ewin));
682              goto done;
683           }
684         val = atoi(param1);
685         EwinOpSetLayer(ewin, OPSRC_USER, val);
686         break;
687
688      case EWIN_OP_RAISE:
689         EwinOpRaise(ewin, OPSRC_USER);
690         break;
691
692      case EWIN_OP_LOWER:
693         EwinOpLower(ewin, OPSRC_USER);
694         break;
695
696      case EWIN_OP_OPACITY:
697         a = OpacityToPercent(ewin->ewmh.opacity);
698         if (!strcmp(param1, "?"))
699           {
700              IpcPrintf("opacity: %u", a);
701              goto done;
702           }
703         b = a;
704         sscanf(param1, "%i", &b);
705         if ((param1[0] == '+') || (param1[0] == '-'))
706            b += a;
707         a = (b < 0) ? 1 : (b > 100) ? 100 : b;
708         EwinOpSetOpacity(ewin, OPSRC_USER, a);
709         if (a && ewin->state.active)
710           {
711              EoChangeOpacity(ewin, OpacityFromPercent(a));
712              TIMER_DEL(op_timer);
713              if (ewin->props.focused_opacity)
714                 TIMER_ADD(op_timer, 0.001 * 700, OpacityTimeout, ewin);
715           }
716         if (ewin->state.in_action)
717            CoordsShowOpacity(ewin);
718         break;
719
720      case EWIN_OP_FOCUSED_OPACITY:
721         a = OpacityToPercent(ewin->props.focused_opacity);
722         if (!strcmp(param1, "?"))
723           {
724              IpcPrintf("focused_opacity: %u", a);
725              goto done;
726           }
727         b = a;
728         sscanf(param1, "%i", &b);
729         if ((param1[0] == '+') || (param1[0] == '-'))
730            b += a;
731         a = (b < 0) ? 0 : (b > 100) ? 100 : b;
732         EwinOpSetFocusedOpacity(ewin, OPSRC_USER, a);
733         if (ewin->state.in_action)
734            CoordsShowOpacity(ewin);
735         break;
736
737      case EWIN_OP_SNAP:
738         SnapshotEwinParse(ewin, prm);
739         break;
740
741      case EWIN_OP_SKIP_LISTS:
742         on = ewin->props.skip_ext_task;
743         if (SetEwinBoolean(wop->name, &on, param1, 1))
744            EwinOpSkipLists(ewin, OPSRC_USER, on);
745         break;
746
747      case EWIN_OP_NEVER_USE_AREA:
748         on = ewin->props.never_use_area;
749         SetEwinBoolean(wop->name, &on, param1, 1);
750         ewin->props.never_use_area = on;
751         goto ewin_update_snap_flags;
752
753      case EWIN_OP_FOCUS_CLICK:
754         on = ewin->props.focusclick;
755         SetEwinBoolean(wop->name, &on, param1, 1);
756         ewin->props.focusclick = on;
757         goto ewin_update_snap_flags;
758
759      case EWIN_OP_AUTOSHADE:
760         on = ewin->props.autoshade;
761         SetEwinBoolean(wop->name, &on, param1, 1);
762         ewin->props.autoshade = on;
763         goto ewin_update_snap_flags;
764
765      case EWIN_OP_NO_BUTTON_GRABS:
766         on = ewin->props.no_button_grabs;
767         if (SetEwinBoolean(wop->name, &on, param1, 1))
768           {
769              ewin->props.no_button_grabs = on;
770              if (ewin->props.no_button_grabs)
771                 UnGrabButtonGrabs(EoGetWin(ewin));
772              else
773                 GrabButtonGrabs(EoGetWin(ewin));
774           }
775         goto ewin_update_snap_flags;
776
777      case EWIN_OP_INH_APP_FOCUS:
778         on = EwinInhGetApp(ewin, focus);
779         SetEwinBoolean(wop->name, &on, param1, 1);
780         EwinInhSetApp(ewin, focus, on);
781         goto ewin_update_snap_flags;
782
783      case EWIN_OP_INH_APP_MOVE:
784         on = EwinInhGetApp(ewin, move);
785         SetEwinBoolean(wop->name, &on, param1, 1);
786         EwinInhSetApp(ewin, move, on);
787         goto ewin_update_snap_flags;
788
789      case EWIN_OP_INH_APP_SIZE:
790         on = EwinInhGetApp(ewin, size);
791         SetEwinBoolean(wop->name, &on, param1, 1);
792         EwinInhSetApp(ewin, size, on);
793         goto ewin_update_snap_flags;
794
795      case EWIN_OP_INH_USER_CLOSE:
796         on = EwinInhGetUser(ewin, close);
797         SetEwinBoolean(wop->name, &on, param1, 1);
798         EwinInhSetUser(ewin, close, on);
799         goto ewin_update_state_hints;
800
801      case EWIN_OP_INH_USER_MOVE:
802         on = EwinInhGetUser(ewin, move);
803         SetEwinBoolean(wop->name, &on, param1, 1);
804         EwinInhSetUser(ewin, move, on);
805         goto ewin_update_state_hints;
806
807      case EWIN_OP_INH_USER_SIZE:
808         on = EwinInhGetUser(ewin, size);
809         SetEwinBoolean(wop->name, &on, param1, 1);
810         EwinInhSetUser(ewin, size, on);
811         goto ewin_update_state_hints;
812
813      case EWIN_OP_INH_WM_FOCUS:
814         on = EwinInhGetWM(ewin, focus);
815         SetEwinBoolean(wop->name, &on, param1, 1);
816         EwinInhSetWM(ewin, focus, on);
817         goto ewin_update_state;
818
819 #if USE_COMPOSITE
820      case EWIN_OP_FADE:
821         on = EoGetFade(ewin);
822         if (SetEwinBoolean(wop->name, &on, param1, 1))
823            EoSetFade(ewin, on);
824         break;
825
826      case EWIN_OP_SHADOW:
827         on = EoGetShadow(ewin);
828         if (SetEwinBoolean(wop->name, &on, param1, 1))
829            EoChangeShadow(ewin, on);
830         break;
831
832      case EWIN_OP_NO_REDIRECT:
833         on = EoGetNoRedirect(ewin);
834         on = ewin->o.noredir;
835         if (SetEwinBoolean(wop->name, &on, param1, 1))
836            EoSetNoRedirect(ewin, on);
837         break;
838 #endif
839       ewin_update_snap_flags:
840         SnapshotEwinUpdate(ewin, SNAP_USE_FLAGS);
841         break;
842
843       ewin_update_state:
844         EwinStateUpdate(ewin);
845         break;
846
847       ewin_update_state_hints:
848         EwinStateUpdate(ewin);
849         HintsSetWindowState(ewin);
850         break;
851      }
852
853  done:
854    return;
855 }
856
857 static void
858 IPC_WinOps(const char *params)
859 {
860    char                match[128];
861    char                operation[128];
862    const char         *p;
863    EWin              **lst;
864    int                 i, num, flags;
865    const WinOp        *wop;
866
867    if (!params)
868      {
869         IpcPrintf("Error: no window specified");
870         return;
871      }
872
873    match[0] = operation[0] = '\0';
874    num = 0;
875    sscanf(params, "%128s %128s %n", match, operation, &num);
876    p = params + num;
877
878    if (!operation[0])
879      {
880         IpcPrintf("Error: no operation specified");
881         return;
882      }
883
884    wop = EwinOpFind(operation);
885    if (!wop)
886      {
887         IpcPrintf("Error: unknown operation");
888         return;
889      }
890
891    lst = EwinsFindByExpr(match, &num, &flags);
892    if (!lst)
893      {
894         IpcPrintf("No windows matching %s\n", match);
895         return;
896      }
897
898    if (flags)
899       Mode.nogroup = 1;
900
901    for (i = 0; i < num; i++)
902       IpcWinop(wop, lst[i], p);
903
904    Mode.nogroup = 0;
905
906    Efree(lst);
907 }
908
909 static void
910 IPC_Remember(const char *params)
911 {
912    int                 window, l;
913    EWin               *ewin;
914
915    if (!params)
916      {
917         IpcPrintf("Error: no parameters\n");
918         goto done;
919      }
920
921    l = 0;
922    window = 0;
923    sscanf(params, "%x %n", &window, &l);
924    if (l <= 0)
925       return;
926
927    ewin = EwinFindByClient(window);
928    if (!ewin)
929      {
930         IpcPrintf("Error: Window not found: %#x\n", window);
931         goto done;
932      }
933
934    SnapshotEwinParse(ewin, params + l);
935
936  done:
937    return;
938 }
939
940 static void
941 IPC_ForceSave(const char *params __UNUSED__)
942 {
943    autosave();
944 }
945
946 static void
947 IPC_Exec(const char *params)
948 {
949    if (params)
950       execApplication(params, EXEC_SET_LANG | EXEC_SET_STARTUP_ID);
951    else
952       IpcPrintf("exec what?\n");
953 }
954
955 static void
956 IPC_Restart(const char *params __UNUSED__)
957 {
958    SessionExit(EEXIT_RESTART, NULL);
959 }
960
961 static void
962 IPC_Exit(const char *params)
963 {
964    char                param1[1024];
965    const char         *p2;
966    int                 l;
967
968    param1[0] = 0;
969    l = 0;
970    if (params)
971       sscanf(params, "%1000s %n", param1, &l);
972    p2 = (l > 0) ? params + l : NULL;
973
974    if (!param1[0])
975       SessionExit(EEXIT_EXIT, NULL);
976    else if (!strcmp(param1, "logout"))
977       SessionExit(EEXIT_LOGOUT, NULL);
978    else if (!strcmp(param1, "restart"))
979       SessionExit(EEXIT_RESTART, NULL);
980    else if (!strcmp(param1, "theme"))
981       SessionExit(EEXIT_THEME, p2);
982    else if (!strcmp(param1, "exec"))
983       SessionExit(EEXIT_EXEC, p2);
984 }
985
986 #if ENABLE_DIALOGS
987 static void
988 IPC_About(const char *params __UNUSED__)
989 {
990    About();
991 }
992 #endif
993
994 static void
995 IPC_Version(const char *params __UNUSED__)
996 {
997    IpcPrintf("%s %s\n", e_wm_name, e_wm_version);
998 }
999
1000 static void
1001 IPC_Debug(const char *params)
1002 {
1003    char                param[1024];
1004    int                 l;
1005    const char         *p;
1006
1007    if (!params)
1008       return;
1009
1010    p = params;
1011    l = 0;
1012    sscanf(p, "%1000s %n", param, &l);
1013    p += l;
1014
1015    if (!strncmp(param, "event", 2))
1016      {
1017         EDebugInit(p);
1018      }
1019    else if (!strncmp(param, "grab", 2))
1020      {
1021         l = 0;
1022         sscanf(p, "%1000s %n", param, &l);
1023         p += l;
1024
1025         if (!strcmp(param, "?"))
1026           {
1027              IpcPrintf("Pointer grab on=%d win=%#lx\n",
1028                        Mode.grabs.pointer_grab_active,
1029                        Mode.grabs.pointer_grab_window);
1030           }
1031         else if (!strncmp(param, "allow", 2))
1032           {
1033              l = 0;
1034              sscanf(p, "%d", &l);
1035              XAllowEvents(disp, l, CurrentTime);
1036              IpcPrintf("XAllowEvents\n");
1037           }
1038         else if (!strncmp(param, "unset", 2))
1039           {
1040              GrabPointerRelease();
1041              IpcPrintf("Ungrab\n");
1042           }
1043      }
1044    else if (!strncmp(param, "sync", 2))
1045      {
1046         l = 0;
1047         sscanf(p, "%1000s %n", param, &l);
1048         p += l;
1049         if (!strncmp(param, "on", 2))
1050           {
1051              XSynchronize(disp, True);
1052              IpcPrintf("Sync on\n");
1053           }
1054         else if (!strncmp(param, "off", 2))
1055           {
1056              XSynchronize(disp, False);
1057              IpcPrintf("Sync off\n");
1058           }
1059      }
1060 }
1061
1062 static void
1063 IPC_Set(const char *params)
1064 {
1065    ConfigurationSet(params);
1066 }
1067
1068 static void
1069 IPC_Show(const char *params)
1070 {
1071    ConfigurationShow(params);
1072 }
1073
1074 static void
1075 EwinShowInfo(const EWin * ewin)
1076 {
1077    int                 bl, br, bt, bb;
1078
1079    EwinBorderGetSize(ewin, &bl, &br, &bt, &bb);
1080
1081    IpcPrintf("WM_NAME                 %s\n"
1082              "_NET_WM_NAME            %s\n"
1083              "WM_ICON_NAME            %s\n"
1084              "WM_CLASS name.class     %s.%s\n"
1085              "WM_WINDOW_ROLE          %s\n"
1086              "WM_COMMAND              %s\n"
1087              "WM_CLIENT_MACHINE       %s\n"
1088              "Client window           %#10lx   x,y %4i,%4i   wxh %4ix%4i\n"
1089              "Container window        %#10lx\n"
1090              "Frame window            %#10lx   x,y %4i,%4i   wxh %4ix%4i\n"
1091 #if USE_COMPOSITE
1092              "Named pixmap            %#10lx\n"
1093 #endif
1094              "Border                  %s   lrtb %i,%i,%i,%i\n"
1095              "Icon window, pixmap, mask %#10lx, %#10lx, %#10lx\n"
1096              "Is group leader  %i  Window group leader %#lx   Client leader %#10lx\n"
1097              "Has transients   %i  Transient type  %i  Transient for %#10lx\n"
1098              "No resize H/V    %i/%i       Shaped      %i\n"
1099              "Base, min, max, inc w/h %ix%i, %ix%i, %ix%i %ix%i\n"
1100              "Aspect min, max         %5.5f, %5.5f\n"
1101              "Struts                  lrtb %i,%i,%i,%i\n"
1102              "MWM border %i resizeh %i title %i menu %i minimize %i maximize %i\n"
1103              "NeedsInput   %i   TakeFocus    %i   FocusNever   %i   FocusClick   %i\n"
1104              "NeverUseArea %i   FixedPos     %i   FixedSize    %i\n"
1105              "Desktop      %i   Layer        %i(%i)\n"
1106              "Iconified    %i   Sticky       %i   Shaded       %i   Docked       %i\n"
1107              "State        %i   Shown        %i   Visibility   %i   Active       %i\n"
1108              "Member of groups        %i\n"
1109 #if USE_COMPOSITE
1110              "Opacity    %3i(%x)  Focused Opacity     %3i\n"
1111              "Shadow       %i   Fade         %i   NoRedirect   %i\n"
1112 #else
1113              "Opacity    %3i\n"
1114 #endif
1115              ,
1116              SS(EwinGetIcccmName(ewin)),
1117              SS(ewin->ewmh.wm_name),
1118              SS(ewin->icccm.wm_icon_name),
1119              SS(EwinGetIcccmCName(ewin)), SS(EwinGetIcccmClass(ewin)),
1120              SS(ewin->icccm.wm_role),
1121              SS(ewin->icccm.wm_command),
1122              SS(ewin->icccm.wm_machine),
1123              EwinGetClientXwin(ewin),
1124              ewin->client.x, ewin->client.y, ewin->client.w, ewin->client.h,
1125              EwinGetContainerXwin(ewin),
1126              EoGetXwin(ewin),
1127              EoGetX(ewin), EoGetY(ewin), EoGetW(ewin), EoGetH(ewin),
1128 #if USE_COMPOSITE
1129              EoGetPixmap(ewin),
1130 #endif
1131              EwinBorderGetName(ewin), bl, br, bt, bb,
1132              ewin->icccm.icon_win,
1133              ewin->icccm.icon_pmap, ewin->icccm.icon_mask,
1134              EwinIsWindowGroupLeader(ewin), EwinGetWindowGroup(ewin),
1135              ewin->icccm.client_leader, EwinGetTransientCount(ewin),
1136              EwinIsTransient(ewin), EwinGetTransientFor(ewin),
1137              ewin->props.no_resize_h, ewin->props.no_resize_v,
1138              ewin->state.shaped, ewin->icccm.base_w, ewin->icccm.base_h,
1139              ewin->icccm.width_min, ewin->icccm.height_min,
1140              ewin->icccm.width_max, ewin->icccm.height_max,
1141              ewin->icccm.w_inc, ewin->icccm.h_inc,
1142              ewin->icccm.aspect_min, ewin->icccm.aspect_max,
1143              ewin->strut.left, ewin->strut.right,
1144              ewin->strut.top, ewin->strut.bottom,
1145              ewin->mwm.decor_border, ewin->mwm.decor_resizeh,
1146              ewin->mwm.decor_title, ewin->mwm.decor_menu,
1147              ewin->mwm.decor_minimize, ewin->mwm.decor_maximize,
1148              ewin->icccm.need_input, ewin->icccm.take_focus,
1149              EwinInhGetWM(ewin, focus), ewin->props.focusclick,
1150              ewin->props.never_use_area, EwinInhGetUser(ewin, move),
1151              EwinInhGetUser(ewin, size), EoGetDeskNum(ewin),
1152              EoGetLayer(ewin), ewin->o.ilayer,
1153              ewin->state.iconified, EoIsSticky(ewin), ewin->state.shaded,
1154              ewin->state.docked, ewin->state.state, EoIsShown(ewin),
1155              ewin->state.visibility, ewin->state.active, ewin->num_groups,
1156              OpacityToPercent(ewin->ewmh.opacity)
1157 #if USE_COMPOSITE
1158              , EoGetOpacity(ewin),
1159              OpacityToPercent(ewin->props.focused_opacity), EoGetShadow(ewin),
1160              EoGetFade(ewin), EoGetNoRedirect(ewin)
1161 #endif
1162       );
1163 }
1164
1165 static void
1166 IPC_EwinInfo(const char *params)
1167 {
1168    char                match[FILEPATH_LEN_MAX];
1169    EWin              **lst;
1170    int                 i, num;
1171
1172    if (!params)
1173       return;
1174
1175    sscanf(params, "%1000s", match);
1176
1177    lst = EwinsFindByExpr(match, &num, NULL);
1178    if (!lst)
1179      {
1180         IpcPrintf("No windows matching %s\n", match);
1181         return;
1182      }
1183
1184    for (i = 0; i < num; i++)
1185      {
1186         EwinShowInfo(lst[i]);
1187         if (i != num - 1)
1188            IpcPrintf("\n");
1189      }
1190
1191    Efree(lst);
1192 }
1193
1194 static void
1195 IPC_ObjInfo(const char *params __UNUSED__)
1196 {
1197    int                 i, num;
1198    EObj               *const *lst, *eo;
1199
1200    lst = EobjListStackGet(&num);
1201
1202    IpcPrintf
1203       ("Num    Window De T V Shape  Dsk S  F   L     Pos       Size    C R Name\n");
1204    for (i = 0; i < num; i++)
1205      {
1206         eo = lst[i];
1207         IpcPrintf
1208            (" %2d %#9lx %2d %d %d %2d/%2d  %3d %d  %d %3d %5d,%5d %4dx%4d %d %d %s\n",
1209             i, EobjGetXwin(eo), WinGetDepth(EobjGetWin(eo)), eo->type,
1210             eo->shown, eo->shaped, EShapeCheck(EobjGetWin(eo)), eo->desk->num,
1211             eo->sticky, eo->floating, eo->ilayer,
1212             EobjGetX(eo), EobjGetY(eo), EobjGetW(eo), EobjGetH(eo),
1213 #if USE_COMPOSITE
1214             (eo->cmhook) ? 1 : 0, !eo->noredir
1215 #else
1216             0, 0
1217 #endif
1218             , EobjGetName(eo));
1219      }
1220 }
1221
1222 static void
1223 IPC_Reparent(const char *params)
1224 {
1225    char                param1[FILEPATH_LEN_MAX];
1226    char                param2[FILEPATH_LEN_MAX];
1227    EWin               *ewin, *enew;
1228
1229    if (params == NULL)
1230       return;
1231
1232    sscanf(params, "%100s %100s", param1, param2);
1233
1234    ewin = EwinFindByExpr(param1);
1235    enew = EwinFindByExpr(param2);
1236    if (!ewin || !enew)
1237       IpcPrintf("No matching client or target EWin found\n");
1238    else
1239       EwinReparent(ewin, EwinGetClientWin(enew));
1240 }
1241
1242 static void
1243 IPC_Warp(const char *params)
1244 {
1245    int                 x, y;
1246
1247    if (!params)
1248       return;
1249
1250    x = y = 0;
1251    if (!strcmp(params, "?"))
1252      {
1253         EQueryPointer(NULL, &x, &y, NULL, NULL);
1254         IpcPrintf("Pointer location: %d %d\n", x, y);
1255      }
1256    else if (!strncmp(params, "abs", 3))
1257      {
1258         sscanf(params, "%*s %i %i", &x, &y);
1259         EXWarpPointer(WinGetXwin(VROOT), x, y);
1260      }
1261    else if (!strncmp(params, "rel", 3))
1262      {
1263         sscanf(params, "%*s %i %i", &x, &y);
1264         EXWarpPointer(None, x, y);
1265      }
1266    else if (!strncmp(params, "scr", 3))
1267      {
1268         x = (Dpy.screen + 1) % ScreenCount(disp);
1269         sscanf(params, "%*s %i", &x);
1270         if (x >= 0 && x < ScreenCount(disp))
1271           {
1272              EXWarpPointer(RootWindow(disp, x), DisplayWidth(disp, x) / 2,
1273                            DisplayHeight(disp, x) / 2);
1274              /* IIRC warping to a different screen once did cause
1275               * LeaveNotify's on the current root window. This does not
1276               * happen in xorg 1.5.3 (and probably other versions).
1277               * So, check and focus out if left. */
1278              FocusCheckScreen();
1279           }
1280      }
1281    else
1282      {
1283         sscanf(params, "%i %i", &x, &y);
1284         EXWarpPointer(None, x, y);
1285      }
1286 }
1287
1288 #if ENABLE_IPC_INSERT_KEYS
1289 struct _keyset {
1290    const char         *sym;
1291    int                 state;
1292    const char         *ch;
1293 };
1294
1295 static const struct _keyset ks[] = {
1296    {"a", 0, "a"},
1297    {"b", 0, "b"},
1298    {"c", 0, "c"},
1299    {"d", 0, "d"},
1300    {"e", 0, "e"},
1301    {"f", 0, "f"},
1302    {"g", 0, "g"},
1303    {"h", 0, "h"},
1304    {"i", 0, "i"},
1305    {"j", 0, "j"},
1306    {"k", 0, "k"},
1307    {"l", 0, "l"},
1308    {"m", 0, "m"},
1309    {"n", 0, "n"},
1310    {"o", 0, "o"},
1311    {"p", 0, "p"},
1312    {"q", 0, "q"},
1313    {"r", 0, "r"},
1314    {"s", 0, "s"},
1315    {"t", 0, "t"},
1316    {"u", 0, "u"},
1317    {"v", 0, "v"},
1318    {"w", 0, "w"},
1319    {"x", 0, "x"},
1320    {"y", 0, "y"},
1321    {"z", 0, "z"},
1322    {"a", ShiftMask, "A"},
1323    {"b", ShiftMask, "B"},
1324    {"c", ShiftMask, "C"},
1325    {"d", ShiftMask, "D"},
1326    {"e", ShiftMask, "E"},
1327    {"f", ShiftMask, "F"},
1328    {"g", ShiftMask, "G"},
1329    {"h", ShiftMask, "H"},
1330    {"i", ShiftMask, "I"},
1331    {"j", ShiftMask, "J"},
1332    {"k", ShiftMask, "K"},
1333    {"l", ShiftMask, "L"},
1334    {"m", ShiftMask, "M"},
1335    {"n", ShiftMask, "N"},
1336    {"o", ShiftMask, "O"},
1337    {"p", ShiftMask, "P"},
1338    {"q", ShiftMask, "Q"},
1339    {"r", ShiftMask, "R"},
1340    {"s", ShiftMask, "S"},
1341    {"t", ShiftMask, "T"},
1342    {"u", ShiftMask, "U"},
1343    {"v", ShiftMask, "V"},
1344    {"w", ShiftMask, "W"},
1345    {"x", ShiftMask, "X"},
1346    {"y", ShiftMask, "Y"},
1347    {"z", ShiftMask, "Z"},
1348    {"grave", 0, "`"},
1349    {"1", 0, "1"},
1350    {"2", 0, "2"},
1351    {"3", 0, "3"},
1352    {"4", 0, "4"},
1353    {"5", 0, "5"},
1354    {"6", 0, "6"},
1355    {"7", 0, "7"},
1356    {"8", 0, "8"},
1357    {"9", 0, "9"},
1358    {"0", 0, "0"},
1359    {"minus", 0, "-"},
1360    {"equal", 0, "="},
1361    {"bracketleft", 0, "["},
1362    {"bracketright", 0, "]"},
1363    {"backslash", 0, "\\\\"},
1364    {"semicolon", 0, "\\s"},
1365    {"apostrophe", 0, "\\a"},
1366    {"comma", 0, ","},
1367    {"period", 0, "."},
1368    {"slash", 0, "/"},
1369    {"grave", ShiftMask, "~"},
1370    {"1", ShiftMask, "!"},
1371    {"2", ShiftMask, "@"},
1372    {"3", ShiftMask, "#"},
1373    {"4", ShiftMask, "$"},
1374    {"5", ShiftMask, "%"},
1375    {"6", ShiftMask, "^"},
1376    {"7", ShiftMask, "&"},
1377    {"8", ShiftMask, "*"},
1378    {"9", ShiftMask, "("},
1379    {"0", ShiftMask, ")"},
1380    {"minus", ShiftMask, "_"},
1381    {"equal", ShiftMask, "+"},
1382    {"bracketleft", ShiftMask, "{"},
1383    {"bracketright", ShiftMask, "}"},
1384    {"backslash", ShiftMask, "|"},
1385    {"semicolon", ShiftMask, ":"},
1386    {"apostrophe", ShiftMask, "\\q"},
1387    {"comma", ShiftMask, "<"},
1388    {"period", ShiftMask, ">"},
1389    {"slash", ShiftMask, "?"},
1390    {"space", ShiftMask, " "},
1391    {"Return", ShiftMask, "\\n"},
1392    {"Tab", ShiftMask, "\\t"}
1393 };
1394
1395 static void
1396 IPC_InsertKeys(const char *params, Client * c __UNUSED__)
1397 {
1398    Window              win = 0;
1399    int                 i, rev;
1400    const char         *s;
1401    XKeyEvent           ev;
1402
1403    if (!params)
1404       return;
1405
1406    s = params;
1407    XGetInputFocus(disp, &win, &rev);
1408    if (win == None)
1409       return;
1410
1411    SoundPlay(SOUND_INSERT_KEYS);
1412    ev.window = win;
1413    for (i = 0; i < (int)strlen(s); i++)
1414      {
1415         int                 j;
1416
1417         ev.x = Mode.events.cx;
1418         ev.y = Mode.events.cy;
1419         ev.x_root = Mode.events.cx;
1420         ev.y_root = Mode.events.cy;
1421         for (j = 0; j < (int)(sizeof(ks) / sizeof(struct _keyset)); j++)
1422           {
1423              if (strncmp(ks[j].ch, &(s[i]), strlen(ks[j].ch)))
1424                 continue;
1425
1426              i += strlen(ks[j].ch) - 1;
1427              ev.keycode = EKeynameToKeycode(ks[j].sym);
1428              ev.state = ks[j].state;
1429              ev.type = KeyPress;
1430              EXSendEvent(win, 0, (XEvent *) & ev);
1431              ev.type = KeyRelease;
1432              EXSendEvent(win, 0, (XEvent *) & ev);
1433              break;
1434           }
1435      }
1436 }
1437 #endif /* ENABLE_IPC_INSERT_KEYS */
1438
1439 /*
1440  * Compatibility stuff - DO NOT USE
1441  */
1442 static int
1443 IPC_Compat(const char *params)
1444 {
1445    int                 ok = 0;
1446    char                param1[128];
1447    const char         *p;
1448    int                 len;
1449
1450    if (!params)
1451       goto done;
1452
1453    len = 0;
1454    param1[0] = '\0';
1455    sscanf(params, "%127s %n", param1, &len);
1456    p = params + len;
1457
1458    ok = 1;
1459    if (!strcmp(param1, "goto_desktop"))
1460      {
1461         if (*p == '?')
1462            IpcPrintf("Current Desktop: %d\n", DesksGetCurrentNum());
1463      }
1464    else if (!strcmp(param1, "num_desks"))
1465      {
1466         if (*p == '?')
1467            IpcPrintf("Number of Desks: %d\n", DesksGetNumber());
1468      }
1469 #if !USE_COMPOSITE
1470    else if (!strcmp(param1, "cm"))
1471      {
1472         DialogOK(_("Message"), _("e16 was built without %s support"),
1473                  _("composite"));
1474      }
1475 #endif
1476 #if !HAVE_SOUND
1477    else if (!strcmp(param1, "sound"))
1478      {
1479         DialogOK(_("Message"), _("e16 was built without %s support"),
1480                  _("sound"));
1481      }
1482 #endif
1483    else
1484      {
1485         ok = 0;
1486      }
1487
1488  done:
1489    return ok;
1490 }
1491
1492 /* the IPC Array */
1493
1494 /* the format of an IPC member of the IPC array is as follows:
1495  * {
1496  *    NameOfMyFunction,
1497  *    "command_name",
1498  *    "quick-help explanation",
1499  *    "extended help data"
1500  *    "may go on for several lines, be sure\n"
1501  *    "to add line feeds when you need them and to \"quote\"\n"
1502  *    "properly"
1503  * }
1504  *
1505  * when you add a function into this array, make sure you also add it into
1506  * the declarations above and also put the function in this file.  PLEASE
1507  * if you add a new function in, add help to it also.  since my end goal
1508  * is going to be to have this whole IPC usable by an end-user or to your
1509  * scripter, it should be easy to learn to use without having to crack
1510  * open the source code.
1511  * --Mandrake
1512  */
1513 static void         IPC_Help(const char *params);
1514
1515 static const IpcItem IPCArray[] = {
1516    {
1517     IPC_Help,
1518     "help", "?",
1519     "Gives you this help screen",
1520     "Additional parameters will retrieve help on many topics - "
1521     "\"help <command>\"." "\n" "use \"help all\" for a list of commands.\n"},
1522    {
1523     IPC_Version,
1524     "version", "ver",
1525     "Displays the current version of Enlightenment running",
1526     NULL},
1527    {
1528     IPC_Nop,
1529     "nop", NULL,
1530     "IPC No-operation - returns nop",
1531     NULL},
1532 #if ENABLE_DIALOGS
1533    {
1534     IPC_About, "about", NULL, "Show E info", NULL},
1535    {
1536     IPC_Cfg, "configure", "cfg", "Configuration dialogs", NULL},
1537 #endif
1538    {
1539     IPC_Exec,
1540     "exec", NULL,
1541     "Execute program",
1542     "  exec <command>       Execute command\n"},
1543    {
1544     IPC_Restart,
1545     "restart", NULL,
1546     "Restart Enlightenment",
1547     NULL},
1548    {
1549     IPC_Exit,
1550     "exit", "q",
1551     "Exit Enlightenment",
1552     "  exit                 Exit immediately\n"
1553     "  exit logout          Show logout dialog\n"
1554     "  exit restart         Restart\n"
1555     "  exit theme <theme>   Restart with new theme\n"
1556     "  exit exec <program>  Exit and start program\n"},
1557    {
1558     IPC_ForceSave,
1559     "save_config", "s",
1560     "Force Enlightenment to save settings now",
1561     NULL},
1562    {
1563     IPC_WinOps,
1564     "win_op", "wop",
1565     "Change a property of a specific window",
1566     "Use \"win_op <windowid> <property> <value>\" to change the property of a window\n"
1567     "You can use the \"window_list\" command to retrieve a list of available windows\n"
1568     "You can use ? after most of these commands to receive the current\n"
1569     "status of that flag\n"
1570     "Available win_op commands are:\n"
1571     "  win_op <windowid> border <BORDERNAME>\n"
1572     "  win_op <windowid> title <title>\n"
1573     "  win_op <windowid> <close/kill>\n"
1574     "  win_op <windowid> <focus/iconify/alone/shade/stick>\n"
1575 #if USE_COMPOSITE
1576     "  win_op <windowid> <fade/shadow>\n"
1577 #endif
1578     "  win_op <windowid> desk <desktochangeto/next/prev>\n"
1579     "  win_op <windowid> area <x> <y>\n"
1580     "  win_op <windowid> <move/size> <x> <y> or <kbd/ptr>\n"
1581     "          (you can use ? and ?? to retreive client and frame locations)\n"
1582     "  win_op <windowid> <mr/sr> <x> <y>   (incremental move/size)\n"
1583     "  win_op <windowid> toggle_<width/height/size> <conservative/available/xinerama>\n"
1584     "  win_op <windowid> <fullscreen/zoom>\n"
1585     "  win_op <windowid> layer <0-100,4=normal>\n"
1586     "  win_op <windowid> <raise/lower>\n"
1587     "  win_op <windowid> opacity [+|-]<1-100(100=opaque)>   (+/-: incremental change)\n"
1588 #if USE_COMPOSITE
1589     "  win_op <windowid> focused_opacity [+|-]<0-100(0=follow opacity, 100=opaque)>\n"
1590 #endif
1591     "  win_op <windowid> snap <what>\n"
1592     "         <what>: all, none, border, command, desktop, dialog, group, icon,\n"
1593     "                 layer, location, opacity, shade, shadow, size, sticky\n"
1594     "  win_op <windowid> <focusclick/never_use_area/no_button_grabs/skiplists>\n"
1595     "  win_op <windowid> <no_app_focus/move/size>\n"
1596     "  win_op <windowid> <no_user_close/move/size>\n"
1597     "  win_op <windowid> <no_wm_focus>\n"
1598     "<windowid> may be substituted with \"current\" to use the current window\n"},
1599    {
1600     IPC_WinList,
1601     "window_list", "wl",
1602     "Get a list of managed application windows",
1603     "The window list can be shown in a number of different formats:\n"
1604     "  window_list       \"windowid : title\"\n"
1605     "  window_list all   \"windowid : x y w x h :: desk : area_x area_y : title\"\n"
1606     "  window_list ext   \"windowid : title :: desk : area_x area_y : x y wxh\"\n"
1607     "  window_list prop  \"windowid : x y w x h :: desk : name class Title\"\n"},
1608    {
1609     IPC_MoveResize,
1610     "movres", "mr",
1611     "Show/set Window move/resize/geometry info modes",
1612     "  movres move   <?/opaque/lined/box/shaded/semi-solid/translucent>\n"
1613     "  movres resize <?/opaque/lined/box/shaded/semi-solid>\n"
1614     "  movres info   <?/never/center/corner>\n"},
1615    {
1616     IPC_DialogOK,
1617     "dialog_ok", "dok",
1618     "Pop up a dialog box with an OK button",
1619     "Use \"dialog_ok <message>\" to pop up a dialog box\n"},
1620    {
1621     IPC_Border, "border", NULL, "List available borders", NULL},
1622    {
1623     IPC_Screen, "screen", NULL, "Return screen information",
1624     "  screen list         List screens\n"
1625     "  screen size         Show current screen size\n"
1626     "  screen split nx ny  Simulate xinerama by subdividing screen\n"},
1627    {
1628     SnapshotsIpcFunc,
1629     "list_remember", "rl",
1630     "Retrieve a list of remembered windows and their attributes",
1631     SnapshotsIpcText},
1632    {
1633     IPC_Debug,
1634     "debug", NULL,
1635     "Set debug options",
1636     "  debug events <EvNo>:<EvNo>...\n"},
1637    {
1638     IPC_Set, "set", NULL, "Set configuration parameter", NULL},
1639    {
1640     IPC_Show, "show", "sh", "Show configuration parameter(s)", NULL},
1641    {
1642     IPC_EwinInfo, "win_info", "wi", "Show client window info", NULL},
1643    {
1644     IPC_ObjInfo, "obj_info", "oi", "Show window object info", NULL},
1645    {
1646     IPC_Reparent,
1647     "reparent", "rep",
1648     "Reparent window",
1649     "  reparent <windowid> <new parent>\n"},
1650    {
1651     IPC_Remember,
1652     "remember", NULL,
1653     "Remembers parameters for client windows (obsolete)",
1654     "  remember <windowid> <parameter>...\n"
1655     "For compatibility with epplets only. In stead use\n"
1656     "  wop <windowid> snap <parameter>...\n"},
1657    {
1658     IPC_Warp,
1659     "warp", NULL,
1660     "Warp/query pointer",
1661     "  warp ?               Get pointer position\n"
1662     "  warp abs <x> <y>     Set pointer position\n"
1663     "  warp rel <x> <y>     Move pointer relative to current position\n"
1664     "  warp scr [<i>]       Move pointer to other screen (default next)\n"
1665     "  warp <x> <y>         Same as \"warp rel\"\n"},
1666 #if ENABLE_IPC_INSERT_KEYS
1667    {
1668     IPC_InsertKeys,
1669     "keys", NULL,
1670     "Send key events to focused window",
1671     "  keys <string>\n"},
1672 #endif
1673 };
1674
1675 static int          ipc_item_count = 0;
1676 static const IpcItem **ipc_item_list = NULL;
1677
1678 static const IpcItem **
1679 IPC_GetList(int *pnum)
1680 {
1681    int                 i, num;
1682    const IpcItem     **lst;
1683
1684    if (ipc_item_list)
1685      {
1686         /* Must be re-generated if modules are ever added/removed */
1687         *pnum = ipc_item_count;
1688         return ipc_item_list;
1689      }
1690
1691    num = sizeof(IPCArray) / sizeof(IpcItem);
1692    lst = EMALLOC(const IpcItem *, num);
1693
1694    for (i = 0; i < num; i++)
1695       lst[i] = &IPCArray[i];
1696
1697    ModulesGetIpcItems(&lst, &num);
1698
1699    ipc_item_count = num;
1700    ipc_item_list = lst;
1701    *pnum = num;
1702    return lst;
1703 }
1704
1705 /* The IPC Handler */
1706 /* this is the function that actually loops through the IPC array
1707  * and finds the command that you were trying to run, and then executes it.
1708  * you shouldn't have to touch this function
1709  * - Mandrake
1710  */
1711 static int
1712 IpcExec(const char *params)
1713 {
1714    int                 i, num, ok;
1715    char                cmd[128];
1716    const char         *prm;
1717    const IpcItem     **lst, *ipc;
1718
1719    if (EDebug(EDBUG_TYPE_IPC))
1720       Eprintf("IpcExec: %s\n", params);
1721
1722    cmd[0] = 0;
1723    num = 0;
1724    if (params)
1725       sscanf(params, "%100s %n", cmd, &num);
1726    prm = (num > 0 && params[num]) ? params + num : NULL;
1727
1728    lst = IPC_GetList(&num);
1729
1730    ok = 0;
1731    for (i = 0; i < num; i++)
1732      {
1733         ipc = lst[i];
1734         if (!(ipc->nick && !strcmp(cmd, ipc->nick)) && strcmp(cmd, ipc->name))
1735            continue;
1736
1737         ipc->func(prm);
1738
1739         ok = 1;
1740         break;
1741      }
1742
1743    if (!ok && params)
1744       ok = IPC_Compat(params);
1745
1746    return ok;
1747 }
1748
1749 int
1750 IpcExecReply(const char *params, IpcReplyFunc * reply, void *data)
1751 {
1752    int                 ok;
1753
1754    IpcPrintInit();
1755    ok = IpcExec(params);
1756    reply(data, IpcPrintGetBuffer());
1757    IpcPrintDone();
1758
1759    return ok;
1760 }
1761
1762 int
1763 EFunc(EWin * ewin, const char *params)
1764 {
1765    int                 ok;
1766
1767    SetContextEwin(ewin);
1768    ok = IpcExec(params);
1769    SetContextEwin(NULL);
1770
1771    return ok;
1772 }
1773
1774 static int
1775 doEFuncDeferred(void *data)
1776 {
1777    void              **prm = (void **)data;
1778    EWin               *ewin;
1779
1780    ewin = (EWin *) prm[0];
1781    if (ewin && !EwinFindByPtr(ewin))
1782       return 0;
1783
1784    EFunc(ewin, (const char *)prm[1]);
1785
1786    Efree(prm[1]);
1787    Efree(data);
1788
1789    return 0;
1790 }
1791
1792 void
1793 EFuncDefer(EWin * ewin, const char *cmd)
1794 {
1795    void              **prm;
1796    Timer              *defer_timer;
1797
1798    prm = EMALLOC(void *, 2);
1799
1800    if (!prm)
1801       return;
1802    prm[0] = ewin;
1803    prm[1] = Estrdup(cmd);
1804
1805    TIMER_ADD(defer_timer, 0.0, doEFuncDeferred, prm);
1806 }
1807
1808 static int
1809 ipccmp(void *p1, void *p2)
1810 {
1811    return strcmp(((IpcItem *) p1)->name, ((IpcItem *) p2)->name);
1812 }
1813
1814 static void
1815 IPC_Help(const char *params)
1816 {
1817    int                 i, num;
1818    const IpcItem     **lst, *ipc;
1819    const char         *nick;
1820
1821    lst = IPC_GetList(&num);
1822
1823    IpcPrintf(_("Enlightenment IPC Commands Help\n"));
1824
1825    if (!params)
1826      {
1827         IpcPrintf(_("Use \"help all\" for descriptions of each command\n"
1828                     "Use \"help <command>\" for an individual description\n\n"));
1829         IpcPrintf(_("Commands currently available:\n"));
1830
1831         Quicksort((void **)lst, 0, num - 1, ipccmp);
1832
1833         for (i = 0; i < num; i++)
1834           {
1835              ipc = lst[i];
1836              nick = (ipc->nick) ? ipc->nick : "";
1837              IpcPrintf("  %-16s %-4s ", ipc->name, nick);
1838              if ((i % 3) == 2)
1839                 IpcPrintf("\n");
1840           }
1841         if (i % 3)
1842            IpcPrintf("\n");
1843      }
1844    else if (!strcmp(params, "all"))
1845      {
1846         IpcPrintf(_
1847                   ("Use \"help full\" for full descriptions of each command\n"));
1848         IpcPrintf(_("Use \"help <command>\" for an individual description\n"));
1849         IpcPrintf(_("Commands currently available:\n"));
1850         IpcPrintf(_("         <command>     : <description>\n"));
1851
1852         for (i = 0; i < num; i++)
1853           {
1854              ipc = lst[i];
1855              nick = (ipc->nick) ? ipc->nick : "";
1856              IpcPrintf("%18s %4s: %s\n", ipc->name, nick, ipc->help_text);
1857           }
1858      }
1859    else if (!strcmp(params, "full"))
1860      {
1861         IpcPrintf(_("Commands currently available:\n"));
1862         IpcPrintf(_("         <command>     : <description>\n"));
1863
1864         for (i = 0; i < num; i++)
1865           {
1866              IpcPrintf("----------------------------------------\n");
1867              ipc = lst[i];
1868              nick = (ipc->nick) ? ipc->nick : "";
1869              IpcPrintf("%18s %4s: %s\n", ipc->name, nick, ipc->help_text);
1870              if (ipc->extended_help_text)
1871                 IpcPrintf("%s", ipc->extended_help_text);
1872           }
1873      }
1874    else
1875      {
1876         for (i = 0; i < num; i++)
1877           {
1878              ipc = lst[i];
1879              if (strcmp(params, ipc->name) &&
1880                  (ipc->nick == NULL || strcmp(params, ipc->nick)))
1881                 continue;
1882
1883              nick = (ipc->nick) ? ipc->nick : "";
1884              IpcPrintf("----------------------------------------\n");
1885              IpcPrintf("%18s %4s: %s\n", ipc->name, nick, ipc->help_text);
1886              IpcPrintf("----------------------------------------\n");
1887              if (ipc->extended_help_text)
1888                 IpcPrintf("%s", ipc->extended_help_text);
1889           }
1890      }
1891 }