1 /*
2 * Animation plugin for compiz/beryl
3 *
4 * animation.c
5 *
6 * Copyright : (C) 2006 Erkin Bahceci
7 * E-mail : erkinbah@gmail.com
8 *
9 * Based on Wobbly and Minimize plugins by
10 * : David Reveman
11 * E-mail : davidr@novell.com>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 */
27
28 #include "private.h"
29
30 // ================= Option Related Functions =================
31
32 AnimEvent win2AnimEventMap[WindowEventNum] =
33 {
34 AnimEventOpen,
35 AnimEventClose,
36 AnimEventMinimize,
37 AnimEventUnminimize,
38 AnimEventShade,
39 AnimEventShade,
40 AnimEventFocus
41 };
42
43 AnimEvent
44 PrivateAnimScreen::getCorrespondingAnimEvent (AnimationOptions::Options optionId)
45 {
46 switch (optionId)
47 {
48 case AnimationOptions::OpenOptions:
49 case AnimationOptions::OpenEffects:
50 case AnimationOptions::OpenRandomEffects:
51 return AnimEventOpen;
52
53 case AnimationOptions::CloseEffects:
54 case AnimationOptions::CloseRandomEffects:
55 case AnimationOptions::CloseOptions:
56 return AnimEventClose;
57
58 case AnimationOptions::MinimizeOptions:
59 case AnimationOptions::MinimizeEffects:
60 case AnimationOptions::MinimizeRandomEffects:
61 return AnimEventMinimize;
62
63 case AnimationOptions::UnminimizeOptions:
64 case AnimationOptions::UnminimizeEffects:
65 case AnimationOptions::UnminimizeRandomEffects:
66 return AnimEventUnminimize;
67
68 case AnimationOptions::FocusOptions:
69 case AnimationOptions::FocusEffects:
70 return AnimEventFocus;
71
72 case AnimationOptions::ShadeOptions:
73 case AnimationOptions::ShadeEffects:
74 case AnimationOptions::ShadeRandomEffects:
75 return AnimEventShade;
76
77 default:
78 return AnimEventNum;
79 }
80 }
81
82 bool
83 IdValuePair::matchesPluginOption (ExtensionPluginInfo *testPluginInfo,
84 int testOptionId) const
85 {
86 return (pluginInfo == testPluginInfo &&
87 optionId == testOptionId);
88 }
89
90 CompOption::Value &
91 AnimWindow::pluginOptVal (ExtensionPluginInfo *pluginInfo,
92 unsigned int optionId,
93 Animation *anim)
94 {
95 PrivateAnimWindow *aw = priv;
96 PrivateAnimScreen *as = aw->paScreen ();
97
98 // Handle -1 case, used in Dodge for non-matching (stable) dodgers
99 if (aw->curAnimSelectionRow () < 0)
100 return (*pluginInfo->effectOptions)[optionId].value ();
101
102 OptionSet *os = as->getOptionSetForSelectedRow (aw, anim);
103
104 IdValuePairVector::iterator it =
105 find_if (os->pairs.begin (),
106 os->pairs.end (),
107 boost::bind (&IdValuePair::matchesPluginOption,
108 _1, pluginInfo, optionId));
109
110 return (it == os->pairs.end () ?
111 (*pluginInfo->effectOptions)[optionId].value () :
112 (*it).value);
113 }
114
115 OptionSet *
116 PrivateAnimScreen::getOptionSetForSelectedRow (PrivateAnimWindow *aw,
117 Animation *anim)
118 {
CID 12391 - CHECKED_RETURN
Calling function "Animation::curWindowEvent()" without checking return value (as is done elsewhere 16 out of 18 times).
No check of the return value of "anim->curWindowEvent()".
119 const AnimEvent event = win2AnimEventMap[anim->curWindowEvent ()];
120 OptionSets &eventOptionSets = mEventOptionSets[event];
121 OptionSet *setSelectedForRow = &eventOptionSets.sets[(unsigned int) aw->curAnimSelectionRow ()];
122
123 return setSelectedForRow;
124 }
125
126 void
127 PrivateAnimScreen::updateOptionSet (OptionSet *os,
128 const char *optNamesValuesOrig)
129 {
130 unsigned int len = strlen (optNamesValuesOrig);
131 char *optNamesValues = (char *)calloc (len + 1, 1);
132
133 // Find the first substring with no spaces in it
134 sscanf (optNamesValuesOrig, " %s ", optNamesValues);
135 if (!strlen (optNamesValues))
136 {
137 free (optNamesValues);
138 return;
139 }
140 // Backup original, since strtok is destructive
141 strcpy (optNamesValues, optNamesValuesOrig);
142
143 char *name;
144 char *nameTrimmed = (char *)calloc (len + 1, 1);
145 char *valueStr = 0;
146 const char *betweenPairs = ",";
147 const char *betweenOptVal = "=";
148
149 // Count number of pairs
150 char *pairToken = (char *)optNamesValuesOrig; // TODO do with CompString
151 unsigned int nPairs = 1;
152
153 while ((pairToken = strchr (pairToken, betweenPairs[0])))
154 {
155 pairToken++; // skip delimiter
156 nPairs++;
157 }
158
159 os->pairs.clear ();
160 os->pairs.reserve (nPairs);
161
162 // Tokenize pairs
163 name = strtok (optNamesValues, betweenOptVal);
164
165 int errorNo = -1;
166 unsigned int i;
167 for (i = 0; name && i < nPairs; i++)
168 {
169 errorNo = 0;
170 if (strchr (name, betweenPairs[0])) // handle "a, b=4" case
171 {
172 errorNo = 1;
173 break;
174 }
175
176 sscanf (name, " %s ", nameTrimmed);
177 if (!strlen (nameTrimmed))
178 {
179 errorNo = 2;
180 break;
181 }
182 valueStr = strtok (0, betweenPairs);
183 if (!valueStr)
184 {
185 errorNo = 3;
186 break;
187 }
188
189 // TODO: Fix: Convert to "pluginname:option_name" format
190 // Warning: Assumes that option names in different extension plugins
191 // will be different.
192 bool matched = false;
193 const ExtensionPluginInfo *chosenExtensionPlugin = NULL;
194 CompOption *o = 0;
195 int optId = -1;
196 foreach (ExtensionPluginInfo *extensionPlugin, mExtensionPlugins)
197 {
198 unsigned int nOptions = extensionPlugin->effectOptions->size ();
199 for (optId = (int)extensionPlugin->firstEffectOptionIndex;
200 optId < (int)nOptions; optId++)
201 {
202 o = &(*extensionPlugin->effectOptions)[(unsigned)optId];
203
204 if (strcasecmp (nameTrimmed, o->name ().c_str ()) == 0)
205 {
206 matched = true;
207 chosenExtensionPlugin = extensionPlugin;
208 break;
209 }
210 }
211 if (matched)
212 break;
213 }
214 if (!matched)
215 {
216 errorNo = 4;
217 break;
218 }
219 CompOption::Value v;
220
221 os->pairs.push_back (IdValuePair ());
222 IdValuePair *pair = &os->pairs[i];
223
224 pair->pluginInfo = chosenExtensionPlugin;
225 pair->optionId = optId;
226 int valueRead = -1;
227 switch (o->type ())
228 {
229 case CompOption::TypeBool:
230 int vb;
231 valueRead = sscanf (valueStr, " %d ", &vb);
232 if (valueRead)
233 pair->value.set ((bool)vb);
234 break;
235 case CompOption::TypeInt:
236 {
237 int vi;
238 valueRead = sscanf (valueStr, " %d ", &vi);
239 if (valueRead > 0)
240 {
241 if (o->rest ().inRange (vi))
242 {
243 v.set (vi);
244 pair->value = v;
245 }
246 else
247 errorNo = 7;
248 }
249 break;
250 }
251 case CompOption::TypeFloat:
252 {
253 float vf;
254 valueRead = sscanf (valueStr, " %f ", &vf);
255 if (valueRead > 0)
256 {
257 if (o->rest ().inRange (vf))
258 {
259 v.set (vf);
260 pair->value = v;
261 }
262 else
263 errorNo = 7;
264 }
265 break;
266 }
267 case CompOption::TypeString:
268 {
269 v.set (CompString (valueStr));
270 valueRead = 1;
271 break;
272 }
273 case CompOption::TypeColor:
274 {
275 unsigned short vc[4];
276 valueRead = sscanf (valueStr, " #%2hx%2hx%2hx%2hx ",
277 &vc[0], &vc[1], &vc[2], &vc[3]);
278 if (valueRead == 4)
279 {
280 CompOption::Value *pairVal = &pair->value;
281 for (int j = 0; j < 4; j++)
282 vc[j] = vc[j] << 8 | vc[j];
283 pairVal->set (vc);
284 }
285 else
286 errorNo = 6;
287 break;
288 }
289 default:
290 break;
291 }
292 if (valueRead == 0)
293 errorNo = 6;
294 if (errorNo > 0)
295 break;
296 // If valueRead is -1 here, then it must be a
297 // non-(int/float/string) option, which is not supported yet.
298 // Such an option doesn't currently exist anyway.
299
300 errorNo = -1;
301 name = strtok (0, betweenOptVal);
302 }
303
304 if (i < nPairs)
305 {
306 switch (errorNo)
307 {
308 case -1:
309 case 2:
310 compLogMessage ("animation", CompLogLevelError,
311 "Option name missing in \"%s\"",
312 optNamesValuesOrig);
313 break;
314 case 1:
315 case 3:
316 compLogMessage ("animation", CompLogLevelError,
317 "Option value missing in \"%s\"",
318 optNamesValuesOrig);
319 break;
320 case 4:
321 //compLogMessage ("animation", CompLogLevelError,
322 // "Unknown option \"%s\" in \"%s\"",
323 // nameTrimmed, optNamesValuesOrig);
324 break;
325 case 6:
326 compLogMessage ("animation", CompLogLevelError,
327 "Invalid value \"%s\" in \"%s\"",
328 valueStr, optNamesValuesOrig);
329 break;
330 case 7:
331 compLogMessage ("animation", CompLogLevelError,
332 "Value \"%s\" out of range in \"%s\"",
333 valueStr, optNamesValuesOrig);
334 break;
335 default:
336 break;
337 }
338 os->pairs.clear ();
339 }
340 free (optNamesValues);
341 free (nameTrimmed);
342 }
343
344 void
345 PrivateAnimScreen::updateOptionSets (AnimEvent e)
346 {
347 OptionSets *oss = &mEventOptionSets[e];
348 CompOption::Value::Vector *listVal =
349 &getOptions ()[(unsigned) customOptionOptionIds[e]].value ().list ();
350 unsigned int n = listVal->size ();
351
352 oss->sets.clear ();
353 oss->sets.reserve (n);
354
355 for (unsigned int i = 0; i < n; i++)
356 {
357 oss->sets.push_back (OptionSet ());
358 updateOptionSet (&oss->sets[i], (*listVal)[i].s ().c_str ());
359 }
360 }