2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2005-2009 Kim Woelders
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:
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.
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.
28 #include "e16-ecore_list.h"
32 #include "windowmatch.h"
34 typedef struct _windowmatch WindowMatch;
44 int width_min, width_max;
45 int height_min, height_max;
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
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
65 #define MATCH_OP_BORDER 1
66 #define MATCH_OP_ICON 2
67 #define MATCH_OP_WINOP 3
69 static int WindowMatchEobjOpsParse(EObj * eo, const char *ops);
71 static Ecore_List *wm_list = NULL;
73 static const char *MatchType[] = {
74 NULL, "Title", "Name", "Class", "Size", "Width", "Height", "Prop", NULL
77 static const char *MatchProp[] = {
78 NULL, "Transient", "Shaped", "FixedSize", "FixedWidth", "FixedHeight", NULL
81 static const char *MatchOp[] = {
82 NULL, "Border", "Icon", "Winop", NULL
86 MatchFind(const char **list, const char *str)
90 for (i = 1; list[i]; i++)
91 if (!strcmp(str, list[i]))
98 WindowMatchCreate(const char *name)
102 b = ECALLOC(WindowMatch, 1);
107 wm_list = ecore_list_new();
108 ecore_list_prepend(wm_list, b);
110 b->name = Estrdup(name);
111 b->width_max = 99999;
112 b->height_max = 99999;
118 WindowMatchDestroy(WindowMatch * wm)
123 ecore_list_node_remove(wm_list, wm);
133 WindowMatchConfigLoad(FILE * fs)
137 char s[FILEPATH_LEN_MAX];
138 char s2[FILEPATH_LEN_MAX];
141 while (GetLine(s, sizeof(s), fs))
143 i1 = ConfigParseline1(s, s2, NULL, NULL);
147 case CONFIG_WINDOWMATCH:
151 case CONFIG_CLASSNAME:
152 wm = WindowMatchCreate(s2);
158 if (!wm->match || !wm->op)
159 WindowMatchDestroy(wm);
165 case WINDOWMATCH_MATCHTITLE:
168 wm->match = MATCH_TYPE_TITLE;
169 wm->value = Estrdup(s2);
171 case WINDOWMATCH_MATCHNAME:
174 wm->match = MATCH_TYPE_WM_NAME;
175 wm->value = Estrdup(s2);
177 case WINDOWMATCH_MATCHCLASS:
180 wm->match = MATCH_TYPE_WM_CLASS;
181 wm->value = Estrdup(s2);
184 case WINDOWMATCH_WIDTH:
187 if (wm->match == MATCH_TYPE_SIZE_V)
188 wm->match = MATCH_TYPE_SIZE;
190 wm->match = MATCH_TYPE_SIZE_H;
191 sscanf(s, "%*s %u %u", &(wm->width_min), &(wm->width_max));
193 case WINDOWMATCH_HEIGHT:
196 if (wm->match == MATCH_TYPE_SIZE_H)
197 wm->match = MATCH_TYPE_SIZE;
199 wm->match = MATCH_TYPE_SIZE_V;
200 sscanf(s, "%*s %u %u", &(wm->height_min), &(wm->height_max));
203 case WINDOWMATCH_TRANSIENT:
206 wm->match = MATCH_TYPE_PROP;
207 wm->prop = MATCH_PROP_TRANSIENT;
208 wm->qual = !atoi(s2);
210 case WINDOWMATCH_SHAPED:
213 wm->match = MATCH_TYPE_PROP;
214 wm->prop = MATCH_PROP_SHAPED;
215 wm->qual = !atoi(s2);
217 case WINDOWMATCH_NO_RESIZE_H:
220 wm->match = MATCH_TYPE_PROP;
221 if (wm->prop == MATCH_PROP_FIXEDSIZE_V)
222 wm->prop = MATCH_PROP_FIXEDSIZE;
224 wm->prop = MATCH_PROP_FIXEDSIZE_H;
225 wm->qual = !atoi(s2);
227 case WINDOWMATCH_NO_RESIZE_V:
230 wm->match = MATCH_TYPE_PROP;
231 if (wm->prop == MATCH_PROP_FIXEDSIZE_H)
232 wm->prop = MATCH_PROP_FIXEDSIZE;
234 wm->prop = MATCH_PROP_FIXEDSIZE_V;
235 wm->qual = !atoi(s2);
239 case WINDOWMATCH_USEBORDER:
242 wm->border = BorderFind(s2);
245 wm->op = MATCH_OP_BORDER;
248 case WINDOWMATCH_ICON:
250 #if 0 /* This has not been active since at least 0.16.5 */
253 wm->icon = ImageclassFind(s2, 0);
256 wm->op = MATCH_OP_ICON;
257 wm->icon->ref_count++;
261 case WINDOWMATCH_DESKTOP:
263 #if 0 /* This has not been active since at least 0.16.5 */
268 case WINDOWMATCH_MAKESTICKY:
271 wm->args = Estrdupcat2(wm->args, ":", "stick");
275 ConfigParseError("WindowMatch", s);
285 WindowMatchDecode(const char *line)
287 char match[32], value[1024], op[32];
289 WindowMatch *wm = NULL;
290 int err, num, w1, w2, h1, h2;
292 match[0] = value[0] = op[0] = '\0';
293 num = sscanf(line, "%32s %1024s %32s %n", match, value, op, &w1);
302 num = MatchFind(MatchType, match);
305 Eprintf("WindowMatchDecode: Error (%s): %s\n", match, line);
310 wm = WindowMatchCreate(NULL);
318 case MATCH_TYPE_TITLE:
319 case MATCH_TYPE_WM_NAME:
320 case MATCH_TYPE_WM_CLASS:
321 wm->value = Estrdup(value);
324 case MATCH_TYPE_SIZE:
325 num = sscanf(value, "%u-%ux%u-%u", &w1, &w2, &h1, &h2);
333 case MATCH_TYPE_SIZE_H:
334 num = sscanf(value, "%u-%u", &w1, &w2);
340 case MATCH_TYPE_SIZE_V:
341 num = sscanf(value, "%u-%u", &h1, &h2);
348 case MATCH_TYPE_PROP:
355 wm->prop = MatchFind(MatchProp, value + num);
361 Eprintf("WindowMatchDecode: Error (%s): %s\n", value, line);
366 wm->op = MatchFind(MatchOp, op);
369 Eprintf("WindowMatchDecode: Error (%s): %s\n", op, line);
376 case MATCH_OP_BORDER:
377 wm->border = BorderFind(args);
386 /* FIXME - Check if exists */
387 wm->args = Estrdup(args);
391 if (WindowMatchEobjOpsParse(NULL, args))
393 Eprintf("WindowMatchDecode: Error (%s): %s\n", args, line);
397 wm->args = Estrdup(args);
405 WindowMatchDestroy(wm);
409 ecore_list_append(wm_list, ecore_list_node_remove(wm_list, wm));
415 WindowMatchEncode(WindowMatch * wm, char *buf, int len)
418 const char *qual, *value, *args;
428 case MATCH_TYPE_SIZE:
430 sprintf(s, "%u-%ux%u-%u", wm->width_min, wm->width_max,
431 wm->height_min, wm->height_max);
433 case MATCH_TYPE_SIZE_H:
435 sprintf(s, "%u-%u", wm->width_min, wm->width_max);
437 case MATCH_TYPE_SIZE_V:
439 sprintf(s, "%u-%u", wm->height_min, wm->height_max);
442 case MATCH_TYPE_PROP:
443 qual = (wm->qual) ? "!" : " ";
444 value = MatchProp[(int)wm->prop];
454 case MATCH_OP_BORDER:
455 args = BorderGetName(wm->border);
459 Esnprintf(buf, len, "%-8s %s%-16s %s %s", MatchType[(int)wm->match],
460 qual, value, MatchOp[(int)wm->op], args);
466 WindowMatchConfigLoad2(FILE * fs)
468 char s[FILEPATH_LEN_MAX], *ss;
473 ss = fgets(s, sizeof(s), fs);
477 len = strcspn(s, "#\r\n");
482 WindowMatchDecode(s);
489 WindowMatchEwinTest(const WindowMatch * wm, const EWin * ewin)
497 case MATCH_TYPE_TITLE:
498 return matchregexp(wm->value, EwinGetIcccmName(ewin));
500 case MATCH_TYPE_WM_NAME:
501 return matchregexp(wm->value, EwinGetIcccmCName(ewin));
503 case MATCH_TYPE_WM_CLASS:
504 return matchregexp(wm->value, EwinGetIcccmClass(ewin));
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);
512 case MATCH_TYPE_SIZE_H:
513 match = (ewin->client.w >= wm->width_min &&
514 ewin->client.w <= wm->width_max);
516 case MATCH_TYPE_SIZE_V:
517 match = (ewin->client.h >= wm->height_min &&
518 ewin->client.h <= wm->height_max);
521 case MATCH_TYPE_PROP:
524 case MATCH_PROP_TRANSIENT:
525 match = EwinIsTransient(ewin);
528 case MATCH_PROP_SHAPED:
529 match = ewin->state.shaped;
532 case MATCH_PROP_FIXEDSIZE:
533 match = ewin->props.no_resize_h && ewin->props.no_resize_v;
535 case MATCH_PROP_FIXEDSIZE_H:
536 match = ewin->props.no_resize_h;
538 case MATCH_PROP_FIXEDSIZE_V:
539 match = ewin->props.no_resize_v;
551 WindowMatchEobjTest(const WindowMatch * wm, const EObj * eo)
559 case MATCH_TYPE_TITLE:
560 return matchregexp(wm->value, EobjGetName(eo));
562 case MATCH_TYPE_WM_NAME:
563 return matchregexp(wm->value, EobjGetCName(eo));
565 case MATCH_TYPE_WM_CLASS:
566 return matchregexp(wm->value, EobjGetClass(eo));
581 WindowMatchTypeMatch(const void *data, const void *match)
583 const WindowMatch *wm = (WindowMatch *) data;
584 const wmatch_type_data *wmtd = (wmatch_type_data *) match;
586 return !(wm->op == wmtd->type && WindowMatchEwinTest(wm, wmtd->ewin));
590 WindowMatchType(const EWin * ewin, int type)
592 wmatch_type_data wmtd;
597 return (WindowMatch *) ecore_list_find(wm_list, WindowMatchTypeMatch, &wmtd);
601 WindowMatchEwinBorder(const EWin * ewin)
605 wm = WindowMatchType(ewin, MATCH_OP_BORDER);
607 Eprintf("WindowMatchEwinBorder %s %s\n", EwinGetTitle(ewin),
608 (wm) ? BorderGetName(wm->border) : "???");
616 WindowMatchEwinIcon(const EWin * ewin)
620 wm = WindowMatchType(ewin, MATCH_OP_ICON);
622 Eprintf("WindowMatchEwinIcon %s %s\n", EwinGetTitle(ewin),
623 (wm) ? wm->args : "???");
631 GetBoolean(const char *value)
633 /* We set off if "0" or "off", otherwise on */
636 else if (!strcmp(value, "0") || !strcmp(value, "off"))
641 #define WINOP_SET_BOOL(item, val) item = GetBoolean(val)
644 WindowMatchEwinOpsAction(EWin * ewin, int op, const char *args)
648 /* NB! This must only be used when a new client is being adopted */
653 /* We should not get here */
657 Efree(EwinGetIcccmName(ewin));
658 EwinGetIcccmName(ewin) = Estrdup(args);
661 case EWIN_OP_ICONIFY:
662 WINOP_SET_BOOL(ewin->icccm.start_iconified, args);
666 WINOP_SET_BOOL(ewin->state.shaded, args);
670 WINOP_SET_BOOL(ewin->o.sticky, args);
674 EoSetDesk(ewin, DeskGet(atoi(args)));
677 #if 0 /* Causes crash */
680 if (sscanf(args, "%u %u", &a, &b) < 2)
682 EwinMoveToArea(ewin, a, b); /* FIXME - We should not move here */
689 if (sscanf(args, "%i %i", &a, &b) < 2)
693 ewin->state.placed = 1;
699 if (sscanf(args, "%u %u", &a, &b) < 2)
703 ewin->state.maximized_horz = ewin->state.maximized_vert = 0;
706 case EWIN_OP_FULLSCREEN:
707 WINOP_SET_BOOL(ewin->state.fullscreen, args);
711 EoSetLayer(ewin, atoi(args));
714 case EWIN_OP_OPACITY:
716 ewin->ewmh.opacity = OpacityFromPercent(OpacityFix(a, 0));
719 case EWIN_OP_FOCUSED_OPACITY:
721 ewin->props.focused_opacity = OpacityFromPercent(OpacityFix(a, 0));
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;
730 case EWIN_OP_FOCUS_CLICK:
731 WINOP_SET_BOOL(ewin->props.focusclick, args);
734 case EWIN_OP_NEVER_USE_AREA:
735 WINOP_SET_BOOL(ewin->props.never_use_area, args);
738 case EWIN_OP_NO_BUTTON_GRABS:
739 WINOP_SET_BOOL(ewin->props.no_button_grabs, args);
742 case EWIN_OP_AUTOSHADE:
743 WINOP_SET_BOOL(ewin->props.autoshade, args);
746 case EWIN_OP_INH_APP_FOCUS:
747 WINOP_SET_BOOL(EwinInhGetApp(ewin, focus), args);
750 case EWIN_OP_INH_APP_MOVE:
751 WINOP_SET_BOOL(EwinInhGetApp(ewin, move), args);
754 case EWIN_OP_INH_APP_SIZE:
755 WINOP_SET_BOOL(EwinInhGetApp(ewin, size), args);
758 case EWIN_OP_INH_USER_CLOSE:
759 WINOP_SET_BOOL(EwinInhGetUser(ewin, close), args);
762 case EWIN_OP_INH_USER_MOVE:
763 WINOP_SET_BOOL(EwinInhGetUser(ewin, move), args);
766 case EWIN_OP_INH_USER_SIZE:
767 WINOP_SET_BOOL(EwinInhGetUser(ewin, size), args);
770 case EWIN_OP_INH_WM_FOCUS:
771 WINOP_SET_BOOL(EwinInhGetWM(ewin, focus), args);
776 WINOP_SET_BOOL(ewin->o.fade, args);
780 WINOP_SET_BOOL(ewin->o.shadow, args);
783 case EWIN_OP_NO_REDIRECT:
784 WINOP_SET_BOOL(ewin->o.noredir, args);
787 case EWIN_OP_NO_ARGB:
788 WINOP_SET_BOOL(ewin->props.no_argb, args);
796 WindowMatchEobjOpsAction(EObj * eo, int op, const char *args)
803 /* We should not get here */
806 case EWIN_OP_OPACITY:
808 eo->opacity = OpacityFromPercent(OpacityFix(a, 100));
812 WINOP_SET_BOOL(eo->fade, args);
816 WINOP_SET_BOOL(eo->shadow, args);
819 case EWIN_OP_NO_REDIRECT:
820 WINOP_SET_BOOL(eo->noredir, args);
827 WindowMatchEobjOpsParse(EObj * eo, const char *ops)
831 char *ops2, *s, *p, op[32];
836 /* Parse ':' separated operations list, e.g. "layer 3:desk 1: shade" */
837 p = ops2 = Estrdup(ops);
848 sscanf(p, "%31s %n", op, &len);
853 wop = EwinOpFind(op);
854 if (!wop || !wop->ok_match)
860 /* If eo is NULL, we are validating the configuration */
864 if (eo->type == EOBJ_TYPE_EWIN)
865 WindowMatchEwinOpsAction((EWin *) eo, wop->op, p);
867 WindowMatchEobjOpsAction(eo, wop->op, p);
869 WindowMatchEwinOpsAction((EWin *) eo, wop->op, p);
879 _WindowMatchEwinFunc(void *_wm, void *_ew)
881 const WindowMatch *wm = (WindowMatch *) _wm;
882 EWin *ew = (EWin *) _ew;
884 if (wm->op != MATCH_OP_WINOP || !WindowMatchEwinTest(wm, ew))
887 /* Match found - do the ops */
888 WindowMatchEobjOpsParse(EoObj(ew), wm->args);
892 WindowMatchEwinOps(EWin * ew)
894 ecore_list_for_each(wm_list, _WindowMatchEwinFunc, ew);
899 _WindowMatchEobjFunc(void *_wm, void *_eo)
901 const WindowMatch *wm = (WindowMatch *) _wm;
902 EObj *eo = (EObj *) _eo;
904 if (wm->op != MATCH_OP_WINOP || !WindowMatchEobjTest(wm, eo))
907 /* Match found - do the ops */
908 WindowMatchEobjOpsParse(eo, wm->args);
912 WindowMatchEobjOps(EObj * eo)
914 ecore_list_for_each(wm_list, _WindowMatchEobjFunc, eo);
923 WindowMatchSighan(int sig, void *prm __UNUSED__)
927 case ESIGNAL_CONFIGURE:
928 #if 0 /* Done as part of theme loading */
929 ConfigFileLoad("windowmatches.cfg", Mode.theme.path,
930 WindowMatchConfigLoad, 1);
932 ConfigFileLoad("matches.cfg", NULL, WindowMatchConfigLoad2, 0);
934 WindowMatchConfigLoadUser();
937 IcondefChecker(0, NULL);
944 WindowMatchIpc(const char *params)
947 char cmd[128], prm[4096], buf[4096];
950 cmd[0] = prm[0] = '\0';
955 sscanf(p, "%100s %4000s %n", cmd, prm, &len);
959 if (!p || cmd[0] == '?')
962 else if (!strncmp(cmd, "list", 2))
966 ECORE_LIST_FOR_EACH(wm_list, wm)
967 IpcPrintf("%s\n", WindowMatchEncode(wm, buf, sizeof(buf)));
971 static const IpcItem WindowMatchIpcArray[] = {
975 "Window match functions",
976 " wmatch list List window matches\n"}
979 #define N_IPC_FUNCS (sizeof(WindowMatchIpcArray)/sizeof(IpcItem))
984 extern const EModule ModWindowMatch;
985 const EModule ModWindowMatch = {
988 {N_IPC_FUNCS, WindowMatchIpcArray}