1 /*
2  * Copyright © 2005 Novell, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of
9  * Novell, Inc. not be used in advertising or publicity pertaining to
10  * distribution of the software without specific, written prior permission.
11  * Novell, Inc. makes no representations about the suitability of this
12  * software for any purpose. It is provided "as is" without express or
13  * implied warranty.
14  *
15  * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17  * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: David Reveman <davidr@novell.com>
24  */
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <ctype.h>
30 #include <math.h>
31 
32 #include <compiz-core.h>
33 
34 struct _Modifier {
35     char *name;
36     int  modifier;
37 } modifiers[] = {
38     { "<Shift>",      ShiftMask		 },
39     { "<Control>",    ControlMask	 },
40     { "<Mod1>",	      Mod1Mask		 },
41     { "<Mod2>",	      Mod2Mask		 },
42     { "<Mod3>",	      Mod3Mask		 },
43     { "<Mod4>",	      Mod4Mask		 },
44     { "<Mod5>",	      Mod5Mask		 },
45     { "<Alt>",	      CompAltMask        },
46     { "<Meta>",	      CompMetaMask       },
47     { "<Super>",      CompSuperMask      },
48     { "<Hyper>",      CompHyperMask	 },
49     { "<ModeSwitch>", CompModeSwitchMask }
50 };
51 
52 #define N_MODIFIERS (sizeof (modifiers) / sizeof (struct _Modifier))
53 
54 struct _Edge {
55     char *name;
56     char *modifierName;
57 } edges[] = {
58     { "Left",	     "<LeftEdge>"	 },
59     { "Right",	     "<RightEdge>"	 },
60     { "Top",	     "<TopEdge>"	 },
61     { "Bottom",	     "<BottomEdge>"	 },
62     { "TopLeft",     "<TopLeftEdge>"	 },
63     { "TopRight",    "<TopRightEdge>"	 },
64     { "BottomLeft",  "<BottomLeftEdge>"	 },
65     { "BottomRight", "<BottomRightEdge>" }
66 };
67 
68 void
compInitOptionValue(CompOptionValue * v)69 compInitOptionValue (CompOptionValue *v)
70 {
71     memset (v, 0, sizeof (CompOptionValue));
72 }
73 
74 void
compFiniOptionValue(CompOptionValue * v,CompOptionType type)75 compFiniOptionValue (CompOptionValue *v,
76 		     CompOptionType  type)
77 {
78     int i;
79 
80     switch (type) {
81     case CompOptionTypeString:
82 	if (v->s)
83 	    free (v->s);
84 	break;
85     case CompOptionTypeMatch:
86 	matchFini (&v->match);
87 	break;
88     case CompOptionTypeList:
89 	for (i = 0; i < v->list.nValue; i++)
90 	    compFiniOptionValue (&v->list.value[i], v->list.type);
91 
92 	if (v->list.value)
93 	    free (v->list.value);
94 	break;
95     default:
96 	break;
97     }
98 }
99 
100 void
compInitOption(CompOption * o)101 compInitOption (CompOption *o)
102 {
103     memset (o, 0, sizeof (CompOption));
104 }
105 
106 void
compFiniOption(CompOption * o)107 compFiniOption (CompOption *o)
108 {
109     compFiniOptionValue (&o->value, o->type);
110 }
111 
112 CompOption *
compFindOption(CompOption * option,int nOption,const char * name,int * index)113 compFindOption (CompOption *option,
114 		int	    nOption,
115 		const char  *name,
116 		int	    *index)
117 {
118     int i;
119 
120     for (i = 0; i < nOption; i++)
121     {
122 	if (strcmp (option[i].name, name) == 0)
123 	{
124 	    if (index)
125 		*index = i;
126 
127 	    return &option[i];
128 	}
129     }
130 
131     return 0;
132 }
133 
134 Bool
compSetBoolOption(CompOption * option,CompOptionValue * value)135 compSetBoolOption (CompOption	   *option,
136 		   CompOptionValue *value)
137 {
138     int b;
139 
140     b = (value->b) ? TRUE : FALSE;
141 
142     if (option->value.b == b)
143 	return FALSE;
144 
145     option->value.b = b;
146 
147     return TRUE;
148 }
149 
150 Bool
compSetIntOption(CompOption * option,CompOptionValue * value)151 compSetIntOption (CompOption	  *option,
152 		  CompOptionValue *value)
153 {
154     if (value->i < option->rest.i.min ||
155 	value->i > option->rest.i.max ||
156 	value->i == option->value.i)
157 	return FALSE;
158 
159     option->value.i = value->i;
160 
161     return TRUE;
162 }
163 
164 Bool
compSetFloatOption(CompOption * option,CompOptionValue * value)165 compSetFloatOption (CompOption	    *option,
166 		    CompOptionValue *value)
167 {
168     float v, p;
169 
170     /* Workaround for float rounding errors */
171     static float equalRange = 1e-5;
172 
173     int sign = (value->f < 0 ? -1 : 1);
174 
175     p = 1.0f / option->rest.f.precision;
176     v = ((int) (value->f * p + sign * 0.5f)) / p;
177 
178     if (v < (option->rest.f.min - equalRange) ||
179 	v > (option->rest.f.max + equalRange))
180 	return FALSE;
181 
182     if (v > (option->value.f - equalRange) &&
183 	v < (option->value.f + equalRange))
184 	return FALSE;
185 
186     option->value.f = v;
187 
188     return TRUE;
189 }
190 
191 Bool
compSetStringOption(CompOption * option,CompOptionValue * value)192 compSetStringOption (CompOption	     *option,
193 		     CompOptionValue *value)
194 {
195     char *s;
196 
197     s = value->s;
198     if (!s)
199 	s = "";
200 
201     if (option->value.s == s)
202 	return FALSE;
203 
204     if (option->value.s && s)
205     {
206 	if (strcmp (option->value.s, s) == 0)
207 	    return FALSE;
208     }
209 
210     if (option->value.s)
211 	free (option->value.s);
212 
213     option->value.s = strdup (s);
214 
215     return TRUE;
216 }
217 
218 Bool
compSetColorOption(CompOption * option,CompOptionValue * value)219 compSetColorOption (CompOption	    *option,
220 		    CompOptionValue *value)
221 {
222     if (memcmp (value->c, option->value.c, sizeof (value->c)) == 0)
223 	return FALSE;
224 
225     memcpy (option->value.c, value->c, sizeof (value->c));
226 
227     return TRUE;
228 }
229 
230 Bool
compSetActionOption(CompOption * option,CompOptionValue * value)231 compSetActionOption (CompOption      *option,
232 		     CompOptionValue *value)
233 {
234     CompAction	    *action = &option->value.action;
235     CompOptionValue v = *value;
236 
237     /* initiate, terminate, priv and state should never be changed */
238     v.action.initiate  = action->initiate;
239     v.action.terminate = action->terminate;
240     v.action.state     = action->state;
241     v.action.priv      = action->priv;
242 
243     if (action->type == v.action.type)
244     {
245 	switch (option->type) {
246 	case CompOptionTypeKey:
247 	    if (!(action->type & CompBindingTypeKey))
248 		return FALSE;
249 
250 	    if (action->key.keycode   == v.action.key.keycode &&
251 		action->key.modifiers == v.action.key.modifiers)
252 		return FALSE;
253 	    break;
254 	case CompOptionTypeButton:
255 	    if (!(action->type & (CompBindingTypeButton |
256 				  CompBindingTypeEdgeButton)))
257 		return FALSE;
258 
259 	    if (action->type & CompBindingTypeEdgeButton)
260 	    {
261 		if (action->button.button    == v.action.button.button    &&
262 		    action->button.modifiers == v.action.button.modifiers &&
263 		    action->edgeMask         == v.action.edgeMask)
264 		    return FALSE;
265 	    }
266 	    else if (action->type & CompBindingTypeButton)
267 	    {
268 		if (action->button.button    == v.action.button.button &&
269 		    action->button.modifiers == v.action.button.modifiers)
270 		    return FALSE;
271 	    }
272 	    break;
273 	case CompOptionTypeEdge:
274 	    if (v.action.edgeMask == action->edgeMask)
275 		return FALSE;
276 	    break;
277 	case CompOptionTypeBell:
278 	    if (v.action.bell == action->bell)
279 		return FALSE;
280 	    break;
281 	default:
282 	    return FALSE;
283 	}
284     }
285 
286     *action = v.action;
287 
288     return TRUE;
289 }
290 
291 Bool
compSetMatchOption(CompOption * option,CompOptionValue * value)292 compSetMatchOption (CompOption      *option,
293 		    CompOptionValue *value)
294 {
295     CompDisplay *display = option->value.match.display;
296     CompMatch	match;
297 
298     if (matchEqual (&option->value.match, &value->match))
299 	return FALSE;
300 
301     if (!matchCopy (&match, &value->match))
302 	return FALSE;
303 
304     matchFini (&option->value.match);
305 
306     option->value.match.op  = match.op;
307     option->value.match.nOp = match.nOp;
308 
309     if (display)
310 	matchUpdate (display, &option->value.match);
311 
312     return TRUE;
313 }
314 
315 Bool
compSetOptionList(CompOption * option,CompOptionValue * value)316 compSetOptionList (CompOption      *option,
317 		   CompOptionValue *value)
318 {
319     CompOption o;
320     Bool       status = FALSE;
321     int        i, min;
322 
323     if (value->list.nValue != option->value.list.nValue)
324     {
325 	CompOptionValue *v;
326 
327 	v = malloc (sizeof (CompOptionValue) * value->list.nValue);
328 	if (!v)
329 	    return FALSE;
330 
331 	min = MIN (value->list.nValue, option->value.list.nValue);
332 
333 	for (i = min; i < option->value.list.nValue; i++)
334 	{
335 	    switch (option->value.list.type) {
336 	    case CompOptionTypeString:
337 		if (option->value.list.value[i].s)
338 		    free (option->value.list.value[i].s);
339 		break;
340 	    case CompOptionTypeMatch:
341 		matchFini (&option->value.list.value[i].match);
342 	    default:
343 		break;
344 	    }
345 	}
346 
347 	memset (v, 0, sizeof (CompOptionValue) * value->list.nValue);
348 
349 	if (min)
350 	    memcpy (v, option->value.list.value,
351 		    sizeof (CompOptionValue) * min);
352 
353 	if (option->value.list.value)
354 	    free (option->value.list.value);
355 
356 	option->value.list.value = v;
357 	option->value.list.nValue = value->list.nValue;
358 
359 	status = TRUE;
360     }
361 
362     o = *option;
363     o.type = option->value.list.type;
364 
365     for (i = 0; i < value->list.nValue; i++)
366     {
367 	o.value = option->value.list.value[i];
368 
369 	switch (o.type) {
370 	case CompOptionTypeBool:
371 	    status |= compSetBoolOption (&o, &value->list.value[i]);
372 	    break;
373 	case CompOptionTypeInt:
374 	    status |= compSetIntOption (&o, &value->list.value[i]);
375 	    break;
376 	case CompOptionTypeFloat:
377 	    status |= compSetFloatOption (&o, &value->list.value[i]);
378 	    break;
379 	case CompOptionTypeString:
380 	    status |= compSetStringOption (&o, &value->list.value[i]);
381 	    break;
382 	case CompOptionTypeColor:
383 	    status |= compSetColorOption (&o, &value->list.value[i]);
384 	    break;
385 	case CompOptionTypeMatch:
386 	    status |= compSetMatchOption (&o, &value->list.value[i]);
387 	default:
388 	    break;
389 	}
390 
391 	option->value.list.value[i] = o.value;
392     }
393 
394     return status;
395 }
396 
397 Bool
compSetOption(CompOption * option,CompOptionValue * value)398 compSetOption (CompOption      *option,
399 	       CompOptionValue *value)
400 {
401     switch (option->type) {
402     case CompOptionTypeBool:
403 	return compSetBoolOption (option, value);
404     case CompOptionTypeInt:
405 	return compSetIntOption (option, value);
406     case CompOptionTypeFloat:
407 	return compSetFloatOption (option, value);
408     case CompOptionTypeString:
409 	return compSetStringOption (option, value);
410     case CompOptionTypeColor:
411 	return compSetColorOption (option, value);
412     case CompOptionTypeMatch:
413 	return compSetMatchOption (option, value);
414     case CompOptionTypeAction:
415     case CompOptionTypeKey:
416     case CompOptionTypeButton:
417     case CompOptionTypeEdge:
418     case CompOptionTypeBell:
419 	return compSetActionOption (option, value);
420     case CompOptionTypeList:
421 	return compSetOptionList (option, value);
422     }
423 
424     return FALSE;
425 }
426 
427 Bool
getBoolOptionNamed(CompOption * option,int nOption,const char * name,Bool defaultValue)428 getBoolOptionNamed (CompOption *option,
429 		    int	       nOption,
430 		    const char *name,
431 		    Bool       defaultValue)
432 {
433     while (nOption--)
434     {
435 	if (option->type == CompOptionTypeBool)
436 	    if (strcmp (option->name, name) == 0)
437 		return option->value.b;
438 
439 	option++;
440     }
441 
442     return defaultValue;
443 }
444 
445 int
getIntOptionNamed(CompOption * option,int nOption,const char * name,int defaultValue)446 getIntOptionNamed (CompOption *option,
447 		   int	      nOption,
448 		   const char *name,
449 		   int	      defaultValue)
450 {
451     while (nOption--)
452     {
453 	if (option->type == CompOptionTypeInt)
454 	    if (strcmp (option->name, name) == 0)
455 		return option->value.i;
456 
457 	option++;
458     }
459 
460     return defaultValue;
461 }
462 
463 float
getFloatOptionNamed(CompOption * option,int nOption,const char * name,float defaultValue)464 getFloatOptionNamed (CompOption *option,
465 		     int	nOption,
466 		     const char *name,
467 		     float	defaultValue)
468 {
469     while (nOption--)
470     {
471 	if (option->type == CompOptionTypeFloat)
472 	    if (strcmp (option->name, name) == 0)
473 		return option->value.f;
474 
475 	option++;
476     }
477 
478     return defaultValue;
479 }
480 
481 char *
getStringOptionNamed(CompOption * option,int nOption,const char * name,char * defaultValue)482 getStringOptionNamed (CompOption *option,
483 		      int	 nOption,
484 		      const char *name,
485 		      char	 *defaultValue)
486 {
487     while (nOption--)
488     {
489 	if (option->type == CompOptionTypeString)
490 	    if (strcmp (option->name, name) == 0)
491 		return option->value.s;
492 
493 	option++;
494     }
495 
496     return defaultValue;
497 }
498 
499 unsigned short *
getColorOptionNamed(CompOption * option,int nOption,const char * name,unsigned short * defaultValue)500 getColorOptionNamed (CompOption	    *option,
501 		     int	    nOption,
502 		     const char     *name,
503 		     unsigned short *defaultValue)
504 {
505     while (nOption--)
506     {
507 	if (option->type == CompOptionTypeColor)
508 	    if (strcmp (option->name, name) == 0)
509 		return option->value.c;
510 
511 	option++;
512     }
513 
514     return defaultValue;
515 }
516 
517 CompMatch *
getMatchOptionNamed(CompOption * option,int nOption,const char * name,CompMatch * defaultValue)518 getMatchOptionNamed (CompOption	*option,
519 		     int	nOption,
520 		     const char *name,
521 		     CompMatch  *defaultValue)
522 {
523     while (nOption--)
524     {
525 	if (option->type == CompOptionTypeMatch)
526 	    if (strcmp (option->name, name) == 0)
527 		return &option->value.match;
528 
529 	option++;
530     }
531 
532     return defaultValue;
533 }
534 
535 static char *
stringAppend(char * s,const char * a)536 stringAppend (char	 *s,
537 	      const char *a)
538 {
539     char *r;
540     int  len;
541 
542     len = strlen (a);
543 
544     if (s)
545 	len += strlen (s);
546 
547     r = malloc (len + 1);
548     if (r)
549     {
550 	if (s)
551 	{
552 	    sprintf (r, "%s%s", s, a);
553 	    free (s);
554 	}
555 	else
556 	{
557 	    sprintf (r, "%s", a);
558 	}
559 
560 	s = r;
561     }
562 
563     return s;
564 }
565 
566 static char *
modifiersToString(CompDisplay * d,unsigned int modMask)567 modifiersToString (CompDisplay  *d,
568 		   unsigned int modMask)
569 {
570     char *binding = NULL;
571     int  i;
572 
573     for (i = 0; i < N_MODIFIERS; i++)
574     {
575 	if (modMask & modifiers[i].modifier)
576 	    binding = stringAppend (binding, modifiers[i].name);
577     }
578 
579     return binding;
580 }
581 
582 static char *
edgeMaskToBindingString(CompDisplay * d,unsigned int edgeMask)583 edgeMaskToBindingString (CompDisplay  *d,
584 			 unsigned int edgeMask)
585 {
586     char *binding = NULL;
587     int  i;
588 
589     for (i = 0; i < SCREEN_EDGE_NUM; i++)
590 	if (edgeMask & (1 << i))
591 	    binding = stringAppend (binding, edges[i].modifierName);
592 
593     return binding;
594 }
595 
596 char *
keyBindingToString(CompDisplay * d,CompKeyBinding * key)597 keyBindingToString (CompDisplay    *d,
598 		    CompKeyBinding *key)
599 {
600     char *binding;
601 
602     binding = modifiersToString (d, key->modifiers);
603 
604     if (key->keycode != 0)
605     {
606 	KeySym keysym;
607 	char   *keyname;
608 
609 	keysym  = XKeycodeToKeysym (d->display, key->keycode, 0);
610 	keyname = XKeysymToString (keysym);
611 
612 	if (keyname)
613 	{
614 	    binding = stringAppend (binding, keyname);
615 	}
616 	else
617 	{
618 	    char keyCodeStr[256];
619 
620 	    snprintf (keyCodeStr, 256, "0x%x", key->keycode);
621 	    binding = stringAppend (binding, keyCodeStr);
622 	}
623     }
624 
625     return binding;
626 }
627 
628 char *
buttonBindingToString(CompDisplay * d,CompButtonBinding * button)629 buttonBindingToString (CompDisplay       *d,
630 		       CompButtonBinding *button)
631 {
632     char *binding;
633     char buttonStr[256];
634 
635     binding = modifiersToString (d, button->modifiers);
636 
637     snprintf (buttonStr, 256, "Button%d", button->button);
638     binding = stringAppend (binding, buttonStr);
639 
640     return binding;
641 }
642 
643 char *
keyActionToString(CompDisplay * d,CompAction * action)644 keyActionToString (CompDisplay *d,
645 		   CompAction  *action)
646 {
647     char *binding;
648 
649     binding = keyBindingToString (d, &action->key);
650     if (!binding)
651 	return strdup ("Disabled");
652 
653     return binding;
654 }
655 
656 char *
buttonActionToString(CompDisplay * d,CompAction * action)657 buttonActionToString (CompDisplay *d,
658 		      CompAction  *action)
659 {
660     char *binding, *edge;
661     char buttonStr[256];
662 
663     binding = modifiersToString (d, action->button.modifiers);
664     edge    = edgeMaskToBindingString (d, action->edgeMask);
665 
666     if (edge)
667     {
668 	binding = stringAppend (binding, edge);
669 	free (edge);
670     }
671 
672     snprintf (buttonStr, 256, "Button%d", action->button.button);
673     binding = stringAppend (binding, buttonStr);
674 
675     if (!binding)
676 	return strdup ("Disabled");
677 
678     return binding;
679 }
680 
681 static unsigned int
stringToModifiers(CompDisplay * d,const char * binding)682 stringToModifiers (CompDisplay *d,
683 		   const char  *binding)
684 {
685     unsigned int mods = 0;
686     int		 i;
687 
688     for (i = 0; i < N_MODIFIERS; i++)
689     {
690 	if (strstr (binding, modifiers[i].name))
691 	    mods |= modifiers[i].modifier;
692     }
693 
694     return mods;
695 }
696 
697 static unsigned int
bindingStringToEdgeMask(CompDisplay * d,const char * binding)698 bindingStringToEdgeMask (CompDisplay *d,
699 			 const char  *binding)
700 {
701     unsigned int edgeMask = 0;
702     int		 i;
703 
704     for (i = 0; i < SCREEN_EDGE_NUM; i++)
705 	if (strstr (binding, edges[i].modifierName))
706 	    edgeMask |= 1 << i;
707 
708     return edgeMask;
709 }
710 
711 Bool
stringToKeyBinding(CompDisplay * d,const char * binding,CompKeyBinding * key)712 stringToKeyBinding (CompDisplay    *d,
713 		    const char     *binding,
714 		    CompKeyBinding *key)
715 {
716     char	  *ptr;
717     unsigned int  mods;
718     KeySym	  keysym;
719 
720     mods = stringToModifiers (d, binding);
721 
722     ptr = strrchr (binding, '>');
723     if (ptr)
724 	binding = ptr + 1;
725 
726     while (*binding && !isalnum (*binding))
727 	binding++;
728 
729     if (!*binding)
730     {
731 	if (mods)
732 	{
733 	    key->keycode   = 0;
734 	    key->modifiers = mods;
735 
736 	    return TRUE;
737 	}
738 
739 	return FALSE;
740     }
741 
742     keysym = XStringToKeysym (binding);
743     if (keysym != NoSymbol)
744     {
745 	KeyCode keycode;
746 
747 	keycode = XKeysymToKeycode (d->display, keysym);
748 	if (keycode)
749 	{
750 	    key->keycode   = keycode;
751 	    key->modifiers = mods;
752 
753 	    return TRUE;
754 	}
755     }
756 
757     if (strncmp (binding, "0x", 2) == 0)
758     {
759 	key->keycode   = strtol (binding, NULL, 0);
760 	key->modifiers = mods;
761 
762 	return TRUE;
763     }
764 
765     return FALSE;
766 }
767 
768 Bool
stringToButtonBinding(CompDisplay * d,const char * binding,CompButtonBinding * button)769 stringToButtonBinding (CompDisplay	 *d,
770 		       const char	 *binding,
771 		       CompButtonBinding *button)
772 {
773     char	 *ptr;
774     unsigned int mods;
775 
776     mods = stringToModifiers (d, binding);
777 
778     ptr = strrchr (binding, '>');
779     if (ptr)
780 	binding = ptr + 1;
781 
782     while (*binding && !isalnum (*binding))
783 	binding++;
784 
785     if (strncmp (binding, "Button", strlen ("Button")) == 0)
786     {
787 	int buttonNum;
788 
789 	if (sscanf (binding + strlen ("Button"), "%d", &buttonNum) == 1)
790 	{
791 	    button->button    = buttonNum;
792 	    button->modifiers = mods;
793 
794 	    return TRUE;
795 	}
796     }
797 
798     return FALSE;
799 }
800 
801 void
stringToKeyAction(CompDisplay * d,const char * binding,CompAction * action)802 stringToKeyAction (CompDisplay *d,
803 		   const char  *binding,
804 		   CompAction  *action)
805 {
806     if (stringToKeyBinding (d, binding, &action->key))
807 	action->type = CompBindingTypeKey;
808     else
809 	action->type = CompBindingTypeNone;
810 }
811 
812 void
stringToButtonAction(CompDisplay * d,const char * binding,CompAction * action)813 stringToButtonAction (CompDisplay *d,
814 		      const char  *binding,
815 		      CompAction  *action)
816 {
817     if (stringToButtonBinding (d, binding, &action->button))
818     {
819 	action->edgeMask = bindingStringToEdgeMask (d, binding);
820 	if (action->edgeMask)
821 	    action->type = CompBindingTypeEdgeButton;
822 	else
823 	    action->type = CompBindingTypeButton;
824     }
825     else
826     {
827 	action->type = CompBindingTypeNone;
828     }
829 }
830 
831 const char *
edgeToString(unsigned int edge)832 edgeToString (unsigned int edge)
833 {
834     return edges[edge].name;
835 }
836 
837 unsigned int
stringToEdgeMask(const char * edge)838 stringToEdgeMask (const char *edge)
839 {
840     unsigned int edgeMask = 0;
841     char	 *needle;
842     int		 i;
843 
844     for (i = 0; i < SCREEN_EDGE_NUM; i++)
845     {
846 	needle = strstr (edge, edgeToString (i));
847 	if (needle)
848 	{
849 	    if (needle != edge && isalnum (*(needle - 1)))
850 		continue;
851 
852 	    needle += strlen (edgeToString (i));
853 
854 	    if (*needle && isalnum (*needle))
855 		continue;
856 
857 	    edgeMask |= 1 << i;
858 	}
859     }
860 
861     return edgeMask;
862 }
863 
864 char *
edgeMaskToString(unsigned int edgeMask)865 edgeMaskToString (unsigned int edgeMask)
866 {
867     char *edge = NULL;
868     int	 i;
869 
870     for (i = 0; i < SCREEN_EDGE_NUM; i++)
871     {
872 	if (edgeMask & (1 << i))
873 	{
874 	    if (edge)
875 		edge = stringAppend (edge, " | ");
876 
877 	    edge = stringAppend (edge, edgeToString (i));
878 	}
879     }
880 
881     if (!edge)
882 	return strdup ("");
883 
884     return edge;
885 }
886 
887 Bool
stringToColor(const char * color,unsigned short * rgba)888 stringToColor (const char     *color,
889 	       unsigned short *rgba)
890 {
891     int c[4];
892 
893     if (sscanf (color, "#%2x%2x%2x%2x", &c[0], &c[1], &c[2], &c[3]) == 4)
894     {
895 	rgba[0] = c[0] << 8 | c[0];
896 	rgba[1] = c[1] << 8 | c[1];
897 	rgba[2] = c[2] << 8 | c[2];
898 	rgba[3] = c[3] << 8 | c[3];
899 
900 	return TRUE;
901     }
902 
903     return FALSE;
904 }
905 
906 char *
colorToString(unsigned short * rgba)907 colorToString (unsigned short *rgba)
908 {
909     char tmp[256];
910 
911     snprintf (tmp, 256, "#%.2x%.2x%.2x%.2x",
912 	      rgba[0] / 256, rgba[1] / 256, rgba[2] / 256, rgba[3] / 256);
913 
914     return strdup (tmp);
915 }
916 
917 const char *
optionTypeToString(CompOptionType type)918 optionTypeToString (CompOptionType type)
919 {
920     switch (type) {
921     case CompOptionTypeBool:
922 	return "bool";
923     case CompOptionTypeInt:
924 	return "int";
925     case CompOptionTypeFloat:
926 	return "float";
927     case CompOptionTypeString:
928 	return "string";
929     case CompOptionTypeColor:
930 	return "color";
931     case CompOptionTypeAction:
932 	return "action";
933     case CompOptionTypeKey:
934 	return "key";
935     case CompOptionTypeButton:
936 	return "button";
937     case CompOptionTypeEdge:
938 	return "edge";
939     case CompOptionTypeBell:
940 	return "bell";
941     case CompOptionTypeMatch:
942 	return "match";
943     case CompOptionTypeList:
944 	return "list";
945     }
946 
947     return "unknown";
948 }
949 
950 Bool
isActionOption(CompOption * option)951 isActionOption (CompOption *option)
952 {
953     switch (option->type) {
954     case CompOptionTypeAction:
955     case CompOptionTypeKey:
956     case CompOptionTypeButton:
957     case CompOptionTypeEdge:
958     case CompOptionTypeBell:
959 	return TRUE;
960     default:
961 	break;
962     }
963 
964     return FALSE;
965 }
966