chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / windowmatch.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2005-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 "borders.h"
26 #include "conf.h"
27 #include "desktops.h"
28 #include "e16-ecore_list.h"
29 #include "emodule.h"
30 #include "ewins.h"
31 #include "ewin-ops.h"
32 #include "windowmatch.h"
33
34 typedef struct _windowmatch WindowMatch;
35
36 struct _windowmatch {
37    char               *name;
38    /* Match criteria */
39    char                match;
40    char                op;
41    char                prop;
42    char                qual;
43    char               *value;
44    int                 width_min, width_max;
45    int                 height_min, height_max;
46    /* Match actions */
47    char               *args;
48    Border             *border;
49 };
50
51 #define MATCH_TYPE_TITLE        1
52 #define MATCH_TYPE_WM_NAME      2
53 #define MATCH_TYPE_WM_CLASS     3
54 #define MATCH_TYPE_SIZE         4
55 #define MATCH_TYPE_SIZE_H       5
56 #define MATCH_TYPE_SIZE_V       6
57 #define MATCH_TYPE_PROP         7
58
59 #define MATCH_PROP_TRANSIENT    1
60 #define MATCH_PROP_SHAPED       2
61 #define MATCH_PROP_FIXEDSIZE    3
62 #define MATCH_PROP_FIXEDSIZE_H  4
63 #define MATCH_PROP_FIXEDSIZE_V  5
64
65 #define MATCH_OP_BORDER         1
66 #define MATCH_OP_ICON           2
67 #define MATCH_OP_WINOP          3
68
69 static int          WindowMatchEobjOpsParse(EObj * eo, const char *ops);
70
71 static Ecore_List  *wm_list = NULL;
72
73 static const char  *MatchType[] = {
74    NULL, "Title", "Name", "Class", "Size", "Width", "Height", "Prop", NULL
75 };
76
77 static const char  *MatchProp[] = {
78    NULL, "Transient", "Shaped", "FixedSize", "FixedWidth", "FixedHeight", NULL
79 };
80
81 static const char  *MatchOp[] = {
82    NULL, "Border", "Icon", "Winop", NULL
83 };
84
85 static int
86 MatchFind(const char **list, const char *str)
87 {
88    int                 i;
89
90    for (i = 1; list[i]; i++)
91       if (!strcmp(str, list[i]))
92          return i;
93
94    return 0;
95 }
96
97 static WindowMatch *
98 WindowMatchCreate(const char *name)
99 {
100    WindowMatch        *b;
101
102    b = ECALLOC(WindowMatch, 1);
103    if (!b)
104       return NULL;
105
106    if (!wm_list)
107       wm_list = ecore_list_new();
108    ecore_list_prepend(wm_list, b);
109
110    b->name = Estrdup(name);
111    b->width_max = 99999;
112    b->height_max = 99999;
113
114    return b;
115 }
116
117 static void
118 WindowMatchDestroy(WindowMatch * wm)
119 {
120    if (!wm)
121       return;
122
123    ecore_list_node_remove(wm_list, wm);
124
125    Efree(wm->name);
126    Efree(wm->value);
127    Efree(wm->args);
128
129    Efree(wm);
130 }
131
132 int
133 WindowMatchConfigLoad(FILE * fs)
134 {
135    int                 err = 0;
136    WindowMatch        *wm = 0;
137    char                s[FILEPATH_LEN_MAX];
138    char                s2[FILEPATH_LEN_MAX];
139    int                 i1;
140
141    while (GetLine(s, sizeof(s), fs))
142      {
143         i1 = ConfigParseline1(s, s2, NULL, NULL);
144         switch (i1)
145           {
146           case CONFIG_VERSION:
147           case CONFIG_WINDOWMATCH:
148              err = -1;
149              break;
150
151           case CONFIG_CLASSNAME:
152              wm = WindowMatchCreate(s2);
153              break;
154
155           case CONFIG_CLOSE:
156              if (wm)
157                {
158                   if (!wm->match || !wm->op)
159                      WindowMatchDestroy(wm);
160                   wm = NULL;
161                   err = 0;
162                }
163              goto done;
164
165           case WINDOWMATCH_MATCHTITLE:
166              if (!wm)
167                 break;
168              wm->match = MATCH_TYPE_TITLE;
169              wm->value = Estrdup(s2);
170              break;
171           case WINDOWMATCH_MATCHNAME:
172              if (!wm)
173                 break;
174              wm->match = MATCH_TYPE_WM_NAME;
175              wm->value = Estrdup(s2);
176              break;
177           case WINDOWMATCH_MATCHCLASS:
178              if (!wm)
179                 break;
180              wm->match = MATCH_TYPE_WM_CLASS;
181              wm->value = Estrdup(s2);
182              break;
183
184           case WINDOWMATCH_WIDTH:
185              if (!wm)
186                 break;
187              if (wm->match == MATCH_TYPE_SIZE_V)
188                 wm->match = MATCH_TYPE_SIZE;
189              else
190                 wm->match = MATCH_TYPE_SIZE_H;
191              sscanf(s, "%*s %u %u", &(wm->width_min), &(wm->width_max));
192              break;
193           case WINDOWMATCH_HEIGHT:
194              if (!wm)
195                 break;
196              if (wm->match == MATCH_TYPE_SIZE_H)
197                 wm->match = MATCH_TYPE_SIZE;
198              else
199                 wm->match = MATCH_TYPE_SIZE_V;
200              sscanf(s, "%*s %u %u", &(wm->height_min), &(wm->height_max));
201              break;
202
203           case WINDOWMATCH_TRANSIENT:
204              if (!wm)
205                 break;
206              wm->match = MATCH_TYPE_PROP;
207              wm->prop = MATCH_PROP_TRANSIENT;
208              wm->qual = !atoi(s2);
209              break;
210           case WINDOWMATCH_SHAPED:
211              if (!wm)
212                 break;
213              wm->match = MATCH_TYPE_PROP;
214              wm->prop = MATCH_PROP_SHAPED;
215              wm->qual = !atoi(s2);
216              break;
217           case WINDOWMATCH_NO_RESIZE_H:
218              if (!wm)
219                 break;
220              wm->match = MATCH_TYPE_PROP;
221              if (wm->prop == MATCH_PROP_FIXEDSIZE_V)
222                 wm->prop = MATCH_PROP_FIXEDSIZE;
223              else
224                 wm->prop = MATCH_PROP_FIXEDSIZE_H;
225              wm->qual = !atoi(s2);
226              break;
227           case WINDOWMATCH_NO_RESIZE_V:
228              if (!wm)
229                 break;
230              wm->match = MATCH_TYPE_PROP;
231              if (wm->prop == MATCH_PROP_FIXEDSIZE_H)
232                 wm->prop = MATCH_PROP_FIXEDSIZE;
233              else
234                 wm->prop = MATCH_PROP_FIXEDSIZE_V;
235              wm->qual = !atoi(s2);
236              break;
237
238           case CONFIG_BORDER:
239           case WINDOWMATCH_USEBORDER:
240              if (!wm)
241                 break;
242              wm->border = BorderFind(s2);
243              if (!wm->border)
244                 break;
245              wm->op = MATCH_OP_BORDER;
246              break;
247
248           case WINDOWMATCH_ICON:
249           case CONFIG_ICONBOX:
250 #if 0                           /* This has not been active since at least 0.16.5 */
251              if (!wm)
252                 break;
253              wm->icon = ImageclassFind(s2, 0);
254              if (!wm->icon)
255                 break;
256              wm->op = MATCH_OP_ICON;
257              wm->icon->ref_count++;
258 #endif
259              break;
260
261           case WINDOWMATCH_DESKTOP:
262           case CONFIG_DESKTOP:
263 #if 0                           /* This has not been active since at least 0.16.5 */
264              wm->desk = atoi(s2);
265 #endif
266              break;
267
268           case WINDOWMATCH_MAKESTICKY:
269              if (!wm)
270                 break;
271              wm->args = Estrdupcat2(wm->args, ":", "stick");
272              break;
273
274           default:
275              ConfigParseError("WindowMatch", s);
276              break;
277           }
278      }
279
280  done:
281    return err;
282 }
283
284 static WindowMatch *
285 WindowMatchDecode(const char *line)
286 {
287    char                match[32], value[1024], op[32];
288    const char         *args;
289    WindowMatch        *wm = NULL;
290    int                 err, num, w1, w2, h1, h2;
291
292    match[0] = value[0] = op[0] = '\0';
293    num = sscanf(line, "%32s %1024s %32s %n", match, value, op, &w1);
294    if (num < 3)
295       return NULL;
296    args = line + w1;
297    if (*args == '\0')
298       return NULL;
299
300    err = 0;
301
302    num = MatchFind(MatchType, match);
303    if (num <= 0)
304      {
305         Eprintf("WindowMatchDecode: Error (%s): %s\n", match, line);
306         err = 1;
307         goto done;
308      }
309
310    wm = WindowMatchCreate(NULL);
311    if (!wm)
312       return NULL;
313
314    wm->match = num;
315
316    switch (wm->match)
317      {
318      case MATCH_TYPE_TITLE:
319      case MATCH_TYPE_WM_NAME:
320      case MATCH_TYPE_WM_CLASS:
321         wm->value = Estrdup(value);
322         break;
323
324      case MATCH_TYPE_SIZE:
325         num = sscanf(value, "%u-%ux%u-%u", &w1, &w2, &h1, &h2);
326         if (num < 4)
327            goto case_error;
328         wm->width_min = w1;
329         wm->width_max = w2;
330         wm->height_min = h1;
331         wm->height_max = h2;
332         break;
333      case MATCH_TYPE_SIZE_H:
334         num = sscanf(value, "%u-%u", &w1, &w2);
335         if (num < 2)
336            goto case_error;
337         wm->width_min = w1;
338         wm->width_max = w2;
339         break;
340      case MATCH_TYPE_SIZE_V:
341         num = sscanf(value, "%u-%u", &h1, &h2);
342         if (num < 2)
343            goto case_error;
344         wm->height_min = h1;
345         wm->height_max = h2;
346         break;
347
348      case MATCH_TYPE_PROP:
349         num = 0;
350         if (*value == '!')
351           {
352              wm->qual = 1;
353              num = 1;
354           }
355         wm->prop = MatchFind(MatchProp, value + num);
356         if (wm->prop <= 0)
357            goto case_error;
358         break;
359
360       case_error:
361         Eprintf("WindowMatchDecode: Error (%s): %s\n", value, line);
362         err = 1;
363         goto done;
364      }
365
366    wm->op = MatchFind(MatchOp, op);
367    if (wm->op <= 0)
368      {
369         Eprintf("WindowMatchDecode: Error (%s): %s\n", op, line);
370         err = 1;
371         goto done;
372      }
373
374    switch (wm->op)
375      {
376      case MATCH_OP_BORDER:
377         wm->border = BorderFind(args);
378         if (!wm->border)
379           {
380              err = 1;
381              goto done;
382           }
383         break;
384
385      case MATCH_OP_ICON:
386         /* FIXME - Check if exists */
387         wm->args = Estrdup(args);
388         break;
389
390      case MATCH_OP_WINOP:
391         if (WindowMatchEobjOpsParse(NULL, args))
392           {
393              Eprintf("WindowMatchDecode: Error (%s): %s\n", args, line);
394              err = 1;
395              goto done;
396           }
397         wm->args = Estrdup(args);
398         break;
399      }
400
401  done:
402    if (err)
403      {
404         if (wm)
405            WindowMatchDestroy(wm);
406      }
407    else
408      {
409         ecore_list_append(wm_list, ecore_list_node_remove(wm_list, wm));
410      }
411    return wm;
412 }
413
414 static char        *
415 WindowMatchEncode(WindowMatch * wm, char *buf, int len)
416 {
417    char                s[1024];
418    const char         *qual, *value, *args;
419
420    qual = " ";
421
422    switch (wm->match)
423      {
424      default:
425         value = wm->value;
426         break;
427
428      case MATCH_TYPE_SIZE:
429         value = s;
430         sprintf(s, "%u-%ux%u-%u", wm->width_min, wm->width_max,
431                 wm->height_min, wm->height_max);
432         break;
433      case MATCH_TYPE_SIZE_H:
434         value = s;
435         sprintf(s, "%u-%u", wm->width_min, wm->width_max);
436         break;
437      case MATCH_TYPE_SIZE_V:
438         value = s;
439         sprintf(s, "%u-%u", wm->height_min, wm->height_max);
440         break;
441
442      case MATCH_TYPE_PROP:
443         qual = (wm->qual) ? "!" : " ";
444         value = MatchProp[(int)wm->prop];
445         break;
446      }
447
448    switch (wm->op)
449      {
450      default:
451         args = wm->args;
452         break;
453
454      case MATCH_OP_BORDER:
455         args = BorderGetName(wm->border);
456         break;
457      }
458
459    Esnprintf(buf, len, "%-8s %s%-16s %s %s", MatchType[(int)wm->match],
460              qual, value, MatchOp[(int)wm->op], args);
461
462    return buf;
463 }
464
465 static int
466 WindowMatchConfigLoad2(FILE * fs)
467 {
468    char                s[FILEPATH_LEN_MAX], *ss;
469    int                 len;
470
471    for (;;)
472      {
473         ss = fgets(s, sizeof(s), fs);
474         if (!ss)
475            break;
476
477         len = strcspn(s, "#\r\n");
478         if (len <= 0)
479            continue;
480         s[len] = '\0';
481
482         WindowMatchDecode(s);
483      }
484
485    return 0;
486 }
487
488 static int
489 WindowMatchEwinTest(const WindowMatch * wm, const EWin * ewin)
490 {
491    int                 match;
492
493    match = 0;
494
495    switch (wm->match)
496      {
497      case MATCH_TYPE_TITLE:
498         return matchregexp(wm->value, EwinGetIcccmName(ewin));
499
500      case MATCH_TYPE_WM_NAME:
501         return matchregexp(wm->value, EwinGetIcccmCName(ewin));
502
503      case MATCH_TYPE_WM_CLASS:
504         return matchregexp(wm->value, EwinGetIcccmClass(ewin));
505
506      case MATCH_TYPE_SIZE:
507         match = (ewin->client.w >= wm->width_min &&
508                  ewin->client.w <= wm->width_max &&
509                  ewin->client.h >= wm->height_min &&
510                  ewin->client.h <= wm->height_max);
511         break;
512      case MATCH_TYPE_SIZE_H:
513         match = (ewin->client.w >= wm->width_min &&
514                  ewin->client.w <= wm->width_max);
515         break;
516      case MATCH_TYPE_SIZE_V:
517         match = (ewin->client.h >= wm->height_min &&
518                  ewin->client.h <= wm->height_max);
519         break;
520
521      case MATCH_TYPE_PROP:
522         switch (wm->prop)
523           {
524           case MATCH_PROP_TRANSIENT:
525              match = EwinIsTransient(ewin);
526              break;
527
528           case MATCH_PROP_SHAPED:
529              match = ewin->state.shaped;
530              break;
531
532           case MATCH_PROP_FIXEDSIZE:
533              match = ewin->props.no_resize_h && ewin->props.no_resize_v;
534              break;
535           case MATCH_PROP_FIXEDSIZE_H:
536              match = ewin->props.no_resize_h;
537              break;
538           case MATCH_PROP_FIXEDSIZE_V:
539              match = ewin->props.no_resize_v;
540              break;
541           }
542      }
543
544    if (wm->qual)
545       match = !match;
546    return match;
547 }
548
549 #if USE_COMPOSITE
550 static int
551 WindowMatchEobjTest(const WindowMatch * wm, const EObj * eo)
552 {
553    int                 match;
554
555    match = 0;
556
557    switch (wm->match)
558      {
559      case MATCH_TYPE_TITLE:
560         return matchregexp(wm->value, EobjGetName(eo));
561
562      case MATCH_TYPE_WM_NAME:
563         return matchregexp(wm->value, EobjGetCName(eo));
564
565      case MATCH_TYPE_WM_CLASS:
566         return matchregexp(wm->value, EobjGetClass(eo));
567      }
568
569    if (wm->qual)
570       match = !match;
571    return match;
572 }
573 #endif
574
575 typedef struct {
576    int                 type;
577    const EWin         *ewin;
578 } wmatch_type_data;
579
580 static int
581 WindowMatchTypeMatch(const void *data, const void *match)
582 {
583    const WindowMatch  *wm = (WindowMatch *) data;
584    const wmatch_type_data *wmtd = (wmatch_type_data *) match;
585
586    return !(wm->op == wmtd->type && WindowMatchEwinTest(wm, wmtd->ewin));
587 }
588
589 static WindowMatch *
590 WindowMatchType(const EWin * ewin, int type)
591 {
592    wmatch_type_data    wmtd;
593
594    wmtd.type = type;
595    wmtd.ewin = ewin;
596
597    return (WindowMatch *) ecore_list_find(wm_list, WindowMatchTypeMatch, &wmtd);
598 }
599
600 Border             *
601 WindowMatchEwinBorder(const EWin * ewin)
602 {
603    WindowMatch        *wm;
604
605    wm = WindowMatchType(ewin, MATCH_OP_BORDER);
606 #if 0
607    Eprintf("WindowMatchEwinBorder %s %s\n", EwinGetTitle(ewin),
608            (wm) ? BorderGetName(wm->border) : "???");
609 #endif
610    if (wm)
611       return wm->border;
612    return NULL;
613 }
614
615 const char         *
616 WindowMatchEwinIcon(const EWin * ewin)
617 {
618    WindowMatch        *wm;
619
620    wm = WindowMatchType(ewin, MATCH_OP_ICON);
621 #if 0
622    Eprintf("WindowMatchEwinIcon %s %s\n", EwinGetTitle(ewin),
623            (wm) ? wm->args : "???");
624 #endif
625    if (wm)
626       return wm->args;
627    return NULL;
628 }
629
630 static int
631 GetBoolean(const char *value)
632 {
633    /* We set off if "0" or "off", otherwise on */
634    if (!value)
635       return 1;
636    else if (!strcmp(value, "0") || !strcmp(value, "off"))
637       return 0;
638    return 1;
639 }
640
641 #define WINOP_SET_BOOL(item, val) item = GetBoolean(val)
642
643 static void
644 WindowMatchEwinOpsAction(EWin * ewin, int op, const char *args)
645 {
646    int                 a, b;
647
648    /* NB! This must only be used when a new client is being adopted */
649
650    switch (op)
651      {
652      default:
653         /* We should not get here */
654         return;
655
656      case EWIN_OP_TITLE:
657         Efree(EwinGetIcccmName(ewin));
658         EwinGetIcccmName(ewin) = Estrdup(args);
659         break;
660
661      case EWIN_OP_ICONIFY:
662         WINOP_SET_BOOL(ewin->icccm.start_iconified, args);
663         break;
664
665      case EWIN_OP_SHADE:
666         WINOP_SET_BOOL(ewin->state.shaded, args);
667         break;
668
669      case EWIN_OP_STICK:
670         WINOP_SET_BOOL(ewin->o.sticky, args);
671         break;
672
673      case EWIN_OP_DESK:
674         EoSetDesk(ewin, DeskGet(atoi(args)));
675         break;
676
677 #if 0                           /* Causes crash */
678      case EWIN_OP_AREA:
679         a = b = 0;
680         if (sscanf(args, "%u %u", &a, &b) < 2)
681            break;
682         EwinMoveToArea(ewin, a, b);     /* FIXME - We should not move here */
683         break;
684 #endif
685
686      case EWIN_OP_MOVE:
687         a = ewin->client.x;
688         b = ewin->client.y;
689         if (sscanf(args, "%i %i", &a, &b) < 2)
690            break;
691         ewin->client.x = a;
692         ewin->client.y = b;
693         ewin->state.placed = 1;
694         break;
695
696      case EWIN_OP_SIZE:
697         a = ewin->client.w;
698         b = ewin->client.h;
699         if (sscanf(args, "%u %u", &a, &b) < 2)
700            break;
701         ewin->client.w = a;
702         ewin->client.h = b;
703         ewin->state.maximized_horz = ewin->state.maximized_vert = 0;
704         break;
705
706      case EWIN_OP_FULLSCREEN:
707         WINOP_SET_BOOL(ewin->state.fullscreen, args);
708         break;
709
710      case EWIN_OP_LAYER:
711         EoSetLayer(ewin, atoi(args));
712         break;
713
714      case EWIN_OP_OPACITY:
715         a = atoi(args);
716         ewin->ewmh.opacity = OpacityFromPercent(OpacityFix(a, 0));
717         break;
718
719      case EWIN_OP_FOCUSED_OPACITY:
720         a = atoi(args);
721         ewin->props.focused_opacity = OpacityFromPercent(OpacityFix(a, 0));
722         break;
723
724      case EWIN_OP_SKIP_LISTS:
725         WINOP_SET_BOOL(ewin->props.skip_winlist, args);
726         ewin->props.skip_focuslist = ewin->props.skip_ext_task =
727            ewin->props.skip_winlist;
728         break;
729
730      case EWIN_OP_FOCUS_CLICK:
731         WINOP_SET_BOOL(ewin->props.focusclick, args);
732         break;
733
734      case EWIN_OP_NEVER_USE_AREA:
735         WINOP_SET_BOOL(ewin->props.never_use_area, args);
736         break;
737
738      case EWIN_OP_NO_BUTTON_GRABS:
739         WINOP_SET_BOOL(ewin->props.no_button_grabs, args);
740         break;
741
742      case EWIN_OP_AUTOSHADE:
743         WINOP_SET_BOOL(ewin->props.autoshade, args);
744         break;
745
746      case EWIN_OP_INH_APP_FOCUS:
747         WINOP_SET_BOOL(EwinInhGetApp(ewin, focus), args);
748         break;
749
750      case EWIN_OP_INH_APP_MOVE:
751         WINOP_SET_BOOL(EwinInhGetApp(ewin, move), args);
752         break;
753
754      case EWIN_OP_INH_APP_SIZE:
755         WINOP_SET_BOOL(EwinInhGetApp(ewin, size), args);
756         break;
757
758      case EWIN_OP_INH_USER_CLOSE:
759         WINOP_SET_BOOL(EwinInhGetUser(ewin, close), args);
760         break;
761
762      case EWIN_OP_INH_USER_MOVE:
763         WINOP_SET_BOOL(EwinInhGetUser(ewin, move), args);
764         break;
765
766      case EWIN_OP_INH_USER_SIZE:
767         WINOP_SET_BOOL(EwinInhGetUser(ewin, size), args);
768         break;
769
770      case EWIN_OP_INH_WM_FOCUS:
771         WINOP_SET_BOOL(EwinInhGetWM(ewin, focus), args);
772         break;
773
774 #if USE_COMPOSITE
775      case EWIN_OP_FADE:
776         WINOP_SET_BOOL(ewin->o.fade, args);
777         break;
778
779      case EWIN_OP_SHADOW:
780         WINOP_SET_BOOL(ewin->o.shadow, args);
781         break;
782
783      case EWIN_OP_NO_REDIRECT:
784         WINOP_SET_BOOL(ewin->o.noredir, args);
785         break;
786
787      case EWIN_OP_NO_ARGB:
788         WINOP_SET_BOOL(ewin->props.no_argb, args);
789         break;
790 #endif
791      }
792 }
793
794 #if USE_COMPOSITE
795 static void
796 WindowMatchEobjOpsAction(EObj * eo, int op, const char *args)
797 {
798    int                 a;
799
800    switch (op)
801      {
802      default:
803         /* We should not get here */
804         return;
805
806      case EWIN_OP_OPACITY:
807         a = atoi(args);
808         eo->opacity = OpacityFromPercent(OpacityFix(a, 100));
809         break;
810
811      case EWIN_OP_FADE:
812         WINOP_SET_BOOL(eo->fade, args);
813         break;
814
815      case EWIN_OP_SHADOW:
816         WINOP_SET_BOOL(eo->shadow, args);
817         break;
818
819      case EWIN_OP_NO_REDIRECT:
820         WINOP_SET_BOOL(eo->noredir, args);
821         break;
822      }
823 }
824 #endif
825
826 static int
827 WindowMatchEobjOpsParse(EObj * eo, const char *ops)
828 {
829    int                 err, len;
830    const WinOp        *wop;
831    char               *ops2, *s, *p, op[32];
832
833    if (!ops)
834       return -1;
835
836    /* Parse ':' separated operations list, e.g. "layer 3:desk 1: shade" */
837    p = ops2 = Estrdup(ops);
838
839    err = 0;
840    for (; p; p = s)
841      {
842         /* Break at ':' */
843         s = strchr(p, ':');
844         if (s)
845            *s++ = '\0';
846
847         len = 0;
848         sscanf(p, "%31s %n", op, &len);
849         if (len <= 0)
850            break;
851         p += len;
852
853         wop = EwinOpFind(op);
854         if (!wop || !wop->ok_match)
855           {
856              err = -1;
857              break;
858           }
859
860         /* If eo is NULL, we are validating the configuration */
861         if (!eo)
862            continue;
863 #if USE_COMPOSITE
864         if (eo->type == EOBJ_TYPE_EWIN)
865            WindowMatchEwinOpsAction((EWin *) eo, wop->op, p);
866         else
867            WindowMatchEobjOpsAction(eo, wop->op, p);
868 #else
869         WindowMatchEwinOpsAction((EWin *) eo, wop->op, p);
870 #endif
871      }
872
873    Efree(ops2);
874
875    return err;
876 }
877
878 static void
879 _WindowMatchEwinFunc(void *_wm, void *_ew)
880 {
881    const WindowMatch  *wm = (WindowMatch *) _wm;
882    EWin               *ew = (EWin *) _ew;
883
884    if (wm->op != MATCH_OP_WINOP || !WindowMatchEwinTest(wm, ew))
885       return;
886
887    /* Match found - do the ops */
888    WindowMatchEobjOpsParse(EoObj(ew), wm->args);
889 }
890
891 void
892 WindowMatchEwinOps(EWin * ew)
893 {
894    ecore_list_for_each(wm_list, _WindowMatchEwinFunc, ew);
895 }
896
897 #if USE_COMPOSITE
898 static void
899 _WindowMatchEobjFunc(void *_wm, void *_eo)
900 {
901    const WindowMatch  *wm = (WindowMatch *) _wm;
902    EObj               *eo = (EObj *) _eo;
903
904    if (wm->op != MATCH_OP_WINOP || !WindowMatchEobjTest(wm, eo))
905       return;
906
907    /* Match found - do the ops */
908    WindowMatchEobjOpsParse(eo, wm->args);
909 }
910
911 void
912 WindowMatchEobjOps(EObj * eo)
913 {
914    ecore_list_for_each(wm_list, _WindowMatchEobjFunc, eo);
915 }
916 #endif
917
918 /*
919  * Winmatch module
920  */
921
922 static void
923 WindowMatchSighan(int sig, void *prm __UNUSED__)
924 {
925    switch (sig)
926      {
927      case ESIGNAL_CONFIGURE:
928 #if 0                           /* Done as part of theme loading */
929         ConfigFileLoad("windowmatches.cfg", Mode.theme.path,
930                        WindowMatchConfigLoad, 1);
931 #endif
932         ConfigFileLoad("matches.cfg", NULL, WindowMatchConfigLoad2, 0);
933 #if 0
934         WindowMatchConfigLoadUser();
935 #endif
936 #if 0
937         IcondefChecker(0, NULL);
938 #endif
939         break;
940      }
941 }
942
943 static void
944 WindowMatchIpc(const char *params)
945 {
946    const char         *p;
947    char                cmd[128], prm[4096], buf[4096];
948    int                 len;
949
950    cmd[0] = prm[0] = '\0';
951    p = params;
952    if (p)
953      {
954         len = 0;
955         sscanf(p, "%100s %4000s %n", cmd, prm, &len);
956         p += len;
957      }
958
959    if (!p || cmd[0] == '?')
960      {
961      }
962    else if (!strncmp(cmd, "list", 2))
963      {
964         WindowMatch        *wm;
965
966         ECORE_LIST_FOR_EACH(wm_list, wm)
967            IpcPrintf("%s\n", WindowMatchEncode(wm, buf, sizeof(buf)));
968      }
969 }
970
971 static const IpcItem WindowMatchIpcArray[] = {
972    {
973     WindowMatchIpc,
974     "wmatch", "wma",
975     "Window match functions",
976     "  wmatch list               List window matches\n"}
977    ,
978 };
979 #define N_IPC_FUNCS (sizeof(WindowMatchIpcArray)/sizeof(IpcItem))
980
981 /*
982  * Module descriptor
983  */
984 extern const EModule ModWindowMatch;
985 const EModule       ModWindowMatch = {
986    "winmatch", NULL,
987    WindowMatchSighan,
988    {N_IPC_FUNCS, WindowMatchIpcArray}
989    ,
990    {0, NULL}
991 };