1 /*
2 * winrules plugin for compiz
3 *
4 * Copyright (C) 2007 Bellegarde Cedric (gnumdk (at) gmail.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "winrules.h"
23
24 COMPIZ_PLUGIN_20090315 (winrules, WinrulesPluginVTable);
25
26 void
27 WinrulesScreen::setProtocols (unsigned int protocols,
28 Window id)
29 {
30 Atom protocol[4];
31 int count = 0;
32
33 if (protocols & CompWindowProtocolDeleteMask)
34 protocol[count++] = Atoms::wmDeleteWindow;
35 if (protocols & CompWindowProtocolTakeFocusMask)
36 protocol[count++] = Atoms::wmTakeFocus;
37 if (protocols & CompWindowProtocolPingMask)
38 protocol[count++] = Atoms::wmPing;
39 if (protocols & CompWindowProtocolSyncRequestMask)
40 protocol[count++] = Atoms::wmSyncRequest;
41
42 XSetWMProtocols (screen->dpy (), id, protocol, count);
43 }
44
45 bool
46 WinrulesWindow::is ()
47 {
48 if (window->overrideRedirect ())
49 return false;
50
51 if (window->wmType () & CompWindowTypeDesktopMask)
52 return false;
53
54 return true;
55 }
56
57 bool
58 WinrulesWindow::isFocussable () const
59 {
60 window->isFocussable ();
61
62 return false; // We only want to return false else where we are not wrapped
63 }
64
65 bool
66 WinrulesWindow::focus ()
67 {
68 window->focus ();
69
70 return false; // We only want to return false for the window we are wrapped
71 }
72
73 bool
74 WinrulesWindow::alpha () const
75 {
76 window->alpha ();
77
78 return false; // We only want to return false else where we are not wrapped
79 }
80
81 void
82 WinrulesWindow::setNoFocus (int optNum)
83 {
84 unsigned int newProtocol = window->protocols ();
85
86 WINRULES_SCREEN (screen);
87
88 if (!is ())
89 return;
90
91 if (ws->getOptions ().at (optNum). value ().match ().evaluate (window))
92 {
93 if (window->protocols () & CompWindowProtocolTakeFocusMask)
94 {
95 protocolSetMask |= (window->protocols () &
96 CompWindowProtocolTakeFocusMask);
97 newProtocol = window->protocols () & ~CompWindowProtocolTakeFocusMask;
98 }
99 window->isFocussableSetEnabled (this, true);// causes w->isFocussable ()
100 // to return false
101 window->focusSetEnabled (this, true); // causes w->focus () to return
102 // false for this window
103 }
104 else if ((protocolSetMask & CompWindowProtocolTakeFocusMask))
105 {
106 newProtocol = window->protocols () |
107 (protocolSetMask & CompWindowProtocolTakeFocusMask);
108 protocolSetMask &= ~CompWindowProtocolTakeFocusMask;
109 window->isFocussableSetEnabled (this, false);
110 window->focusSetEnabled (this, false);
111 }
112
113 if (newProtocol != window->protocols ())
114 {
115 ws->setProtocols (newProtocol, window->id ());
116 }
117 }
118
119 void
120 WinrulesWindow::setNoAlpha (int optNum)
121 {
122 WINRULES_SCREEN (screen);
123
124 if (!is ())
125 return;
126
127 if (ws->getOptions ().at (optNum). value ().match ().evaluate (window))
128 {
129 window->alphaSetEnabled (this, true); // Causes w->alpha () to return
130 // false
131 }
132 else
133 {
134 window->alphaSetEnabled (this, false);
135 }
136 }
137
138 void
139 WinrulesWindow::updateState (int optNum,
140 int mask)
141 {
142 unsigned int newState = window->state ();
143
144 WINRULES_SCREEN (screen);
145
146 if (!is ())
147 return;
148
149 if (ws->getOptions ().at (optNum). value ().match ().evaluate (window))
150 {
151 newState |= mask;
152 newState = window->constrainWindowState (newState, window->actions ());
153 stateSetMask |= (newState & mask);
154 }
155 else if (stateSetMask & mask)
156 {
157 newState &= ~mask;
158 stateSetMask &= ~mask;
159 }
160
161 if (newState != window->state ())
162 {
163 window->changeState (newState);
164
165 if (mask & (CompWindowStateFullscreenMask |
166 CompWindowStateAboveMask |
167 CompWindowStateBelowMask ))
168 window->updateAttributes (CompStackingUpdateModeNormal);
169 else
170 window->updateAttributes (CompStackingUpdateModeNone);
171 }
172 }
173
174 void
175 WinrulesWindow::setAllowedActions (int optNum,
176 int action)
177 {
178 WINRULES_SCREEN (screen);
179
180 if (!is ())
181 return;
182
183 if (ws->getOptions ().at (optNum). value ().match ().evaluate (window))
184 allowedActions &= ~action;
185 else if (!(allowedActions & action))
186 allowedActions |= action;
187
188 window->recalcActions ();
189 }
190
191 bool
192 WinrulesWindow::matchSizeValue (CompOption::Value::Vector matches,
193 CompOption::Value::Vector widthValues,
194 CompOption::Value::Vector heightValues,
195 int *width,
196 int *height)
197 {
198 int min;
199
200 if (!is ())
201 return false;
202
203 if (window->type () & CompWindowTypeDesktopMask)
204 return false;
205
206 min = MIN (matches.size (), widthValues.size ());
207 min = MIN ((unsigned int) min, heightValues.size ());
208 min = MIN ((unsigned int) min, matches.size ());
209
210 for (int i = 0; i < min; i++)
211 {
212 if ((matches.at (i).match ().evaluate (window)))
213 {
214 *width = widthValues.at (i).i ();
215 *height = heightValues.at (i).i ();
216
217 return true;
218 }
219 }
220
221 return false;
222 }
223
224 bool
225 WinrulesWindow::matchSize (int *width,
226 int *height)
227 {
228 WINRULES_SCREEN (screen);
229
230 return matchSizeValue (ws->optionGetSizeMatches (),
231 ws->optionGetSizeWidthValues (),
232 ws->optionGetSizeHeightValues (),
233 width, height);
234 }
235
236 void
237 WinrulesWindow::updateWindowSize (int width,
238 int height)
239 {
240 XWindowChanges xwc;
241 unsigned int xwcm = 0;
242
243 if (width != window->serverWidth ())
244 xwcm |= CWWidth;
245 if (height != window->serverHeight ())
246 xwcm |= CWHeight;
247
248 xwc.width = width;
249 xwc.height = height;
250
251 if (window->mapNum () && xwcm)
252 window->sendSyncRequest ();
253
254 window->configureXWindow (xwcm, &xwc);
255 }
256
257 void
258 WinrulesScreen::optionChanged (CompOption *option,
259 WinrulesOptions::Options num)
260 {
261
262 unsigned int updateStateMask = 0, updateActionsMask = 0;
263
264 switch (num)
265 {
266 case WinrulesOptions::SkiptaskbarMatch:
267 updateStateMask = CompWindowStateSkipTaskbarMask;
268 break;
269 case WinrulesOptions::SkippagerMatch:
270 updateStateMask = CompWindowStateSkipPagerMask;
271 break;
272 case WinrulesOptions::AboveMatch:
273 updateStateMask = CompWindowStateAboveMask;
274 break;
275 case WinrulesOptions::BelowMatch:
276 updateStateMask = CompWindowStateBelowMask;
277 break;
278 case WinrulesOptions::StickyMatch:
279 updateStateMask = CompWindowStateStickyMask;
280 break;
281 case WinrulesOptions::FullscreenMatch:
282 updateStateMask = CompWindowStateFullscreenMask;
283 break;
284 case WinrulesOptions::MaximizeMatch:
285 updateStateMask = CompWindowStateMaximizedHorzMask |
286 CompWindowStateMaximizedVertMask;
287 break;
288 case WinrulesOptions::NoMoveMatch:
CID 12431 - DEADCODE
Assigning: "updateActionsMask" = "1U".
289 updateActionsMask = CompWindowActionMoveMask;
290 break;
291 case WinrulesOptions::NoResizeMatch:
CID 12431 - DEADCODE
Assigning: "updateActionsMask" = "2U".
292 updateActionsMask = CompWindowActionResizeMask;
293 break;
294 case WinrulesOptions::NoMinimizeMatch:
CID 12431 - DEADCODE
Assigning: "updateActionsMask" = "8U".
295 updateActionsMask = CompWindowActionMinimizeMask;
296 break;
297 case WinrulesOptions::NoMaximizeMatch:
CID 12431 - DEADCODE
Assigning: "updateActionsMask" = "48U".
298 updateActionsMask = CompWindowActionMaximizeVertMask |
299 CompWindowActionMaximizeHorzMask;
300 break;
301 case WinrulesOptions::NoCloseMatch:
CID 12431 - DEADCODE
Assigning: "updateActionsMask" = "128U".
302 updateActionsMask = CompWindowActionCloseMask;
303 break;
304 case WinrulesOptions::NoArgbMatch:
305 foreach (CompWindow *w, screen->windows ())
306 {
307 WINRULES_WINDOW (w);
308 ww->setNoAlpha (num);
309 }
310
311 return;
312 break;
313 case WinrulesOptions::SizeMatches:
314 foreach (CompOption::Value &v, option->value ().list ())
315 {
316 CompMatch &m = v.match ();
317 m.update ();
318 }
319 return;
320 break;
321 default:
322 return;
323 break;
324 }
325
326 if (updateStateMask)
327 {
328 /* We traverse a copy of the list here because windows can be unhooked
329 * on state change rather than the delayed unhook that happens in <0.8.x
330 */
331
332 CompWindowList windows = screen->windows ();
333
334 foreach (CompWindow *w, windows)
335 {
336 WINRULES_WINDOW (w);
337 ww->updateState (num, updateStateMask);
338 }
339
340 return;
341 }
342
CID 12431 - DEADCODE
At condition "updateActionsMask", the value of "updateActionsMask" must be in one of the following intervals: {[1,2], [8,8], [48,48], [128,128]}.
The condition "updateActionsMask" must be true.
343 if (updateActionsMask)
344 {
345 foreach (CompWindow *w, screen->windows ())
346 {
347 WINRULES_WINDOW (w);
348 ww->setAllowedActions (num, updateActionsMask);
349 }
350
351 return;
352 }
353
CID 12431 - DEADCODE
Execution cannot reach this statement "return;".
354 return;
355 }
356
357
358 bool
359 WinrulesWindow::applyRules ()
360 {
361 int width, height;
362
363 updateState (WinrulesOptions::SkiptaskbarMatch,
364 CompWindowStateSkipTaskbarMask);
365
366 updateState (WinrulesOptions::SkippagerMatch,
367 CompWindowStateSkipPagerMask);
368
369 updateState (WinrulesOptions::AboveMatch,
370 CompWindowStateAboveMask);
371
372 updateState (WinrulesOptions::BelowMatch,
373 CompWindowStateBelowMask);
374
375 updateState (WinrulesOptions::StickyMatch,
376 CompWindowStateStickyMask);
377
378 updateState (WinrulesOptions::FullscreenMatch,
379 CompWindowStateFullscreenMask);
380
381 updateState (WinrulesOptions::MaximizeMatch,
382 CompWindowStateMaximizedHorzMask |
383 CompWindowStateMaximizedVertMask);
384
385 setAllowedActions (WinrulesOptions::NoMoveMatch,
386 CompWindowActionMoveMask);
387
388 setAllowedActions (WinrulesOptions::NoResizeMatch,
389 CompWindowActionResizeMask);
390
391 setAllowedActions (WinrulesOptions::NoMinimizeMatch,
392 CompWindowActionMinimizeMask);
393
394 setAllowedActions (WinrulesOptions::NoMaximizeMatch,
395 CompWindowActionMaximizeVertMask |
396 CompWindowActionMaximizeHorzMask);
397
398 setAllowedActions (WinrulesOptions::NoCloseMatch,
399 CompWindowActionCloseMask);
400
401 setNoAlpha (WinrulesOptions::NoArgbMatch);
402
403 if (matchSize (&width, &height))
404 updateWindowSize (width, height);
405
406 return false;
407 }
408
409
410 void
411 WinrulesScreen::handleEvent (XEvent *event)
412 {
413 if (event->type == MapRequest)
414 {
415 CompWindow *w = screen->findWindow (event->xmap.window);
416 if (w)
417 {
418 WINRULES_WINDOW (w);
419 ww->setNoFocus (WinrulesOptions::NoFocusMatch);
420 ww->applyRules ();
421 }
422 }
423
424 screen->handleEvent (event);
425
426 }
427
428 void
429 WinrulesWindow::getAllowedActions (unsigned int &setActions,
430 unsigned int &clearActions)
431 {
432 window->getAllowedActions (setActions, clearActions);
433
434 clearActions |= ~allowedActions;
435 }
436
437 void
438 WinrulesScreen::matchExpHandlerChanged ()
439 {
440 screen->matchExpHandlerChanged ();
441
442 /* match options are up to date after the call to matchExpHandlerChanged */
443 foreach (CompWindow *w, screen->windows ())
444 {
445 WINRULES_WINDOW (w);
446 ww->applyRules ();
447 }
448 }
449
450 void
451 WinrulesScreen::matchPropertyChanged (CompWindow *w)
452 {
453 WINRULES_WINDOW (w);
454
455 /* Re-apply rules on match property change */
456 ww->applyRules ();
457
458 screen->matchPropertyChanged (w);
459 }
460
461 WinrulesScreen::WinrulesScreen (CompScreen *screen) :
462 PluginClassHandler <WinrulesScreen, CompScreen> (screen)
463 {
464 ScreenInterface::setHandler (screen);
465
466 optionSetSkiptaskbarMatchNotify (boost::bind
467 (&WinrulesScreen::optionChanged, this,
468 _1, _2));
469
470 optionSetSkippagerMatchNotify (boost::bind
471 (&WinrulesScreen::optionChanged, this,
472 _1, _2));
473
474 optionSetAboveMatchNotify (boost::bind
475 (&WinrulesScreen::optionChanged, this,
476 _1, _2));
477
478 optionSetBelowMatchNotify (boost::bind
479 (&WinrulesScreen::optionChanged, this,
480 _1, _2));
481
482 optionSetFullscreenMatchNotify (boost::bind
483 (&WinrulesScreen::optionChanged, this,
484 _1, _2));
485
486 optionSetStickyMatchNotify (boost::bind
487 (&WinrulesScreen::optionChanged, this,
488 _1, _2));
489
490 optionSetMaximizeMatchNotify (boost::bind
491 (&WinrulesScreen::optionChanged, this,
492 _1, _2));
493
494 optionSetNoArgbMatchNotify (boost::bind
495 (&WinrulesScreen::optionChanged, this,
496 _1, _2));
497
498 optionSetNoMoveMatchNotify (boost::bind
499 (&WinrulesScreen::optionChanged, this,
500 _1, _2));
501
502 optionSetNoResizeMatchNotify (boost::bind
503 (&WinrulesScreen::optionChanged, this,
504 _1, _2));
505
506 optionSetNoMinimizeMatchNotify (boost::bind
507 (&WinrulesScreen::optionChanged, this,
508 _1, _2));
509
510 optionSetNoMaximizeMatchNotify (boost::bind
511 (&WinrulesScreen::optionChanged, this,
512 _1, _2));
513
514 optionSetNoCloseMatchNotify (boost::bind
515 (&WinrulesScreen::optionChanged, this,
516 _1, _2));
517
518 optionSetNoFocusMatchNotify (boost::bind
519 (&WinrulesScreen::optionChanged, this,
520 _1, _2));
521
522 }
523
524 WinrulesWindow::WinrulesWindow (CompWindow *window) :
525 PluginClassHandler <WinrulesWindow, CompWindow> (window),
526 window (window),
527 allowedActions (~0),
528 stateSetMask (0),
529 protocolSetMask (0)
530 {
531 CompTimer timer;
532
533 WindowInterface::setHandler (window);
534
535 window->isFocussableSetEnabled (this, false);
536 window->alphaSetEnabled (this, false);
537 window->focusSetEnabled (this, false);
538
539 timer.setCallback (boost::bind(&WinrulesWindow::applyRules, this));
540 timer.setTimes (0, 0);
541
542 timer.start ();
543
544 }
545
546 bool
547 WinrulesPluginVTable::init ()
548 {
549 if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
550 return false;
551
552 return true;
553 }