1 /*
2  * Compiz configuration system library
3  *
4  * Copyright (C) 2007  Danny Baumann <maniac@opencompositing.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10 
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15 
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 /*
22  * Based on Compiz option.c
23  * Copyright © 2005 Novell, Inc.
24  * Author: David Reveman <davidr@novell.com>
25  */
26 
27 
28 #define _GNU_SOURCE
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <math.h>
36 
37 #include <X11/X.h>
38 #include <X11/Xlib.h>
39 
40 #include <ccs.h>
41 
42 #define CompAltMask        (1 << 16)
43 #define CompMetaMask       (1 << 17)
44 #define CompSuperMask      (1 << 18)
45 #define CompHyperMask      (1 << 19)
46 #define CompModeSwitchMask (1 << 20)
47 #define CompNumLockMask    (1 << 21)
48 #define CompScrollLockMask (1 << 22)
49 
50 #define SCREEN_EDGE_LEFT	(1 << 0)
51 #define SCREEN_EDGE_RIGHT	(1 << 1)
52 #define SCREEN_EDGE_TOP		(1 << 2)
53 #define SCREEN_EDGE_BOTTOM	(1 << 3)
54 #define SCREEN_EDGE_TOPLEFT	(1 << 4)
55 #define SCREEN_EDGE_TOPRIGHT	(1 << 5)
56 #define SCREEN_EDGE_BOTTOMLEFT	(1 << 6)
57 #define SCREEN_EDGE_BOTTOMRIGHT (1 << 7)
58 
59 struct _Modifier
60 {
61     char *name;
62     int  modifier;
63 }
64 
65 modifierList[] = {
66     { "<Shift>",      ShiftMask		 },
67     { "<Control>",    ControlMask	 },
68     { "<Mod1>",	      Mod1Mask		 },
69     { "<Mod2>",	      Mod2Mask		 },
70     { "<Mod3>",	      Mod3Mask		 },
71     { "<Mod4>",	      Mod4Mask		 },
72     { "<Mod5>",	      Mod5Mask		 },
73     { "<Alt>",	      CompAltMask        },
74     { "<Meta>",	      CompMetaMask       },
75     { "<Super>",      CompSuperMask      },
76     { "<Hyper>",      CompHyperMask	 },
77     { "<ModeSwitch>", CompModeSwitchMask },
78 };
79 
80 #define N_MODIFIERS (sizeof (modifierList) / sizeof (struct _Modifier))
81 
82 struct _Edge {
83     char *name;
84     char *modName;
85     int  modifier;
86 }
87 
88 edgeList[] = {
89     { "Left",        "<LeftEdge>",	  SCREEN_EDGE_LEFT },
90     { "Right",       "<RightEdge>",	  SCREEN_EDGE_RIGHT },
91     { "Top",         "<TopEdge>",	  SCREEN_EDGE_TOP },
92     { "Bottom",      "<BottomEdge>",	  SCREEN_EDGE_BOTTOM },
93     { "TopLeft",     "<TopLeftEdge>",	  SCREEN_EDGE_TOPLEFT },
94     { "TopRight",    "<TopRightEdge>",	  SCREEN_EDGE_TOPRIGHT },
95     { "BottomLeft",  "<BottomLeftEdge>",  SCREEN_EDGE_BOTTOMLEFT },
96     { "BottomRight", "<BottomRightEdge>", SCREEN_EDGE_BOTTOMRIGHT }
97 };
98 
99 #define N_EDGES (sizeof (edgeList) / sizeof (edgeList[0]))
100 
101 static char *
stringAppend(char * s,char * a)102 stringAppend (char *s,
103 	      char *a)
104 {
105     char *r;
106     int  len;
107 
108     if (!a)
109 	return s;
110 
111     len = strlen (a);
112 
113     if (s)
114 	len += strlen (s);
115 
116     r = malloc (len + 1);
117 
118     if (r)
119     {
120 	if (s)
121 	{
122 	    sprintf (r, "%s%s", s, a);
123 	    free (s);
124 	}
125 	else
126 	{
127 	    sprintf (r, "%s", a);
128 	}
129 
130 	s = r;
131     }
132 
133     return s;
134 }
135 
136 char *
ccsModifiersToString(unsigned int modMask)137 ccsModifiersToString (unsigned int modMask)
138 {
139     char *binding = NULL;
140     int  i;
141 
142     for (i = 0; i < N_MODIFIERS; i++)
143     {
144 	if (modMask & modifierList[i].modifier)
145 	    binding = stringAppend (binding, modifierList[i].name);
146     }
147 
148     return binding;
149 }
150 
151 char *
ccsEdgesToModString(unsigned int edgeMask)152 ccsEdgesToModString (unsigned int edgeMask)
153 {
154     char *binding = NULL;
155     int  i;
156 
157     for (i = 0; i < N_EDGES; i++)
158     {
159 	if (edgeMask & edgeList[i].modifier)
160 	    binding = stringAppend (binding, edgeList[i].modName);
161     }
162 
163     return binding;
164 }
165 
166 char *
ccsEdgesToString(unsigned int edgeMask)167 ccsEdgesToString (unsigned int edgeMask)
168 {
169     char *binding = NULL;
170     int  i;
171 
172     for (i = 0; i < N_EDGES; i++)
173     {
174 	if (edgeMask & edgeList[i].modifier)
175 	{
176 	    if (binding)
177 		binding = stringAppend (binding, "|");
178 	    binding = stringAppend (binding, edgeList[i].name);
179 	}
180     }
181 
182     if (!binding)
183 	return strdup ("");
184 
185     return binding;
186 }
187 
188 char *
ccsKeyBindingToString(CCSSettingKeyValue * key)189 ccsKeyBindingToString (CCSSettingKeyValue *key)
190 {
191     char *binding;
192 
193     binding = ccsModifiersToString (key->keyModMask);
194 
195     if (key->keysym != NoSymbol)
196     {
197 	char *keyname;
198 
199 	keyname = XKeysymToString (key->keysym);
200 	if (keyname)
201 	{
202 	    binding = stringAppend (binding, keyname);
203 	}
204     }
205 
206     if (!binding)
207 	return strdup ("Disabled");
208     return binding;
209 }
210 
211 char *
ccsButtonBindingToString(CCSSettingButtonValue * button)212 ccsButtonBindingToString (CCSSettingButtonValue *button)
213 {
214     char *binding;
215     char *edges;
216     char buttonStr[256];
217 
218     edges = ccsEdgesToModString (button->edgeMask);
219     binding = stringAppend (edges, ccsModifiersToString (button->buttonModMask));
220 
221     if (button->button)
222     {
223         snprintf (buttonStr, 256, "Button%d", button->button);
224         binding = stringAppend (binding, buttonStr);
225     }
226 
227     if (!binding)
228 	return strdup ("Disabled");
229     return binding;
230 }
231 
232 unsigned int
ccsStringToModifiers(const char * binding)233 ccsStringToModifiers (const char *binding)
234 {
235     unsigned int mods = 0;
236     int		 i;
237 
238     for (i = 0; i < N_MODIFIERS; i++)
239     {
240 	if (strcasestr (binding, modifierList[i].name))
241 	    mods |= modifierList[i].modifier;
242     }
243 
244     return mods;
245 }
246 
247 unsigned int
ccsStringToEdges(const char * binding)248 ccsStringToEdges (const char *binding)
249 {
250     unsigned int edgeMask = 0;
251     const char   *needle;
252     int          i;
253 
254     for (i = 0; i < N_EDGES; i++)
255     {
256         int edgeLen = strlen (edgeList[i].name);
257 
258         /* Look for all occurrences of edgeList[i].name in binding */
259         needle = binding;
260         while ((needle = strstr (needle, edgeList[i].name)) != NULL)
261         {
262             if (needle != binding && isalnum (*(needle - 1)))
263             {
264                 needle += edgeLen;
265                 continue;
266             }
267 
268             needle += edgeLen;
269 
270             if (*needle && isalnum (*needle))
271                 continue;
272 
273             edgeMask |= 1 << i;
274         }
275     }
276 
277     return edgeMask;
278 
279 }
280 
281 unsigned int
ccsModStringToEdges(const char * binding)282 ccsModStringToEdges (const char *binding)
283 {
284     unsigned int mods = 0;
285     int		 i;
286 
287     for (i = 0; i < N_EDGES; i++)
288     {
289 	if (strcasestr (binding, edgeList[i].modName))
290 	    mods |= edgeList[i].modifier;
291     }
292 
293     return mods;
294 }
295 
296 Bool
ccsStringToKeyBinding(const char * binding,CCSSettingKeyValue * value)297 ccsStringToKeyBinding (const char         *binding,
298 		       CCSSettingKeyValue *value)
299 {
300     char	  *ptr;
301     unsigned int  mods;
302     KeySym	  keysym;
303 
304     if (!binding || !strlen(binding) ||
305 	strncasecmp (binding, "Disabled", strlen ("Disabled")) == 0)
306     {
307 	value->keysym     = 0;
308 	value->keyModMask = 0;
309 	return TRUE;
310     }
311 
312     mods = ccsStringToModifiers (binding);
313 
314     ptr = strrchr (binding, '>');
315 
316     if (ptr)
317 	binding = ptr + 1;
318 
319     while (*binding && !isalnum (*binding))
320 	binding++;
321 
322     if (!*binding)
323     {
324 	if (mods)
325 	{
326 	    value->keysym     = 0;
327 	    value->keyModMask = mods;
328 
329 	    return TRUE;
330 	}
331 
332 	return FALSE;
333     }
334 
335     keysym = XStringToKeysym (binding);
336 
337     if (keysym != NoSymbol)
338     {
339 	value->keysym     = keysym;
340 	value->keyModMask = mods;
341 
342 	return TRUE;
343     }
344 
345     return FALSE;
346 }
347 
348 Bool
ccsStringToButtonBinding(const char * binding,CCSSettingButtonValue * value)349 ccsStringToButtonBinding (const char            *binding,
350 			  CCSSettingButtonValue *value)
351 {
352     char	 *ptr;
353     unsigned int mods;
354     unsigned int edges;
355 
356     if (!binding || !strlen(binding) ||
357 	strncmp (binding, "Disabled", strlen ("Disabled")) == 0)
358     {
359 	value->button        = 0;
360 	value->buttonModMask = 0;
361 	value->edgeMask      = 0;
362 	return TRUE;
363     }
364 
365     mods = ccsStringToModifiers (binding);
366     edges = ccsModStringToEdges (binding);
367 
368     ptr = strrchr (binding, '>');
369 
370     if (ptr)
371 	binding = ptr + 1;
372 
373     while (*binding && !isalnum (*binding))
374 	binding++;
375 
376     if (strncmp (binding, "Button", strlen ("Button")) == 0)
377     {
378 	int buttonNum;
379 
380 	if (sscanf (binding + strlen ("Button"), "%d", &buttonNum) == 1)
381 	{
382 	    value->button        = buttonNum;
383 	    value->buttonModMask = mods;
384 	    value->edgeMask      = edges;
385 
386 	    return TRUE;
387 	}
388     }
389 
390     return FALSE;
391 }
392 
393 Bool
ccsStringToColor(const char * value,CCSSettingColorValue * color)394 ccsStringToColor (const char          *value,
395 		  CCSSettingColorValue *color)
396 {
397     int c[4];
398 
399     if (sscanf (value, "#%2x%2x%2x%2x", &c[0], &c[1], &c[2], &c[3]) == 4)
400     {
401 	color->color.red   = c[0] << 8 | c[0];
402 	color->color.green = c[1] << 8 | c[1];
403 	color->color.blue  = c[2] << 8 | c[2];
404 	color->color.alpha = c[3] << 8 | c[3];
405 
406 	return TRUE;
407     }
408 
409     return FALSE;
410 }
411 
412 char *
ccsColorToString(CCSSettingColorValue * color)413 ccsColorToString (CCSSettingColorValue *color)
414 {
415     char tmp[256];
416 
417     snprintf (tmp, 256, "#%.2x%.2x%.2x%.2x",
418 	      color->color.red >> 8, color->color.green >> 8,
419 	      color->color.blue >> 8, color->color.alpha >> 8);
420 
421     return strdup (tmp);
422 }
423 
424