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 }