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 <X11/Xatom.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31
32 #include <compiz-core.h>
33
34 static CompMetadata minMetadata;
35
36 static int displayPrivateIndex;
37
38 typedef struct _MinDisplay {
39 int screenPrivateIndex;
40 HandleEventProc handleEvent;
41 Atom winChangeStateAtom;
42 } MinDisplay;
43
44 #define MIN_SCREEN_OPTION_SPEED 0
45 #define MIN_SCREEN_OPTION_TIMESTEP 1
46 #define MIN_SCREEN_OPTION_WINDOW_MATCH 2
47 #define MIN_SCREEN_OPTION_SHADE_RESISTANCE 3
48 #define MIN_SCREEN_OPTION_NUM 4
49
50 typedef struct _MinScreen {
51 int windowPrivateIndex;
52
53 CompOption opt[MIN_SCREEN_OPTION_NUM];
54
55 PreparePaintScreenProc preparePaintScreen;
56 DonePaintScreenProc donePaintScreen;
57 PaintOutputProc paintOutput;
58 PaintWindowProc paintWindow;
59 DamageWindowRectProc damageWindowRect;
60 FocusWindowProc focusWindow;
61
62 int shadeStep;
63 int moreAdjust;
64 } MinScreen;
65
66 typedef struct _MinWindow {
67 GLfloat xVelocity, yVelocity, xScaleVelocity, yScaleVelocity;
68 GLfloat xScale, yScale;
69 GLfloat tx, ty;
70
71 Bool adjust;
72
73 int state, newState;
74
75 int shade;
76 Region region;
77
78 int unmapCnt;
79
80 Bool ignoreDamage;
81 } MinWindow;
82
83 #define GET_MIN_DISPLAY(d) \
84 ((MinDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
85
86 #define MIN_DISPLAY(d) \
87 MinDisplay *md = GET_MIN_DISPLAY (d)
88
89 #define GET_MIN_SCREEN(s, md) \
90 ((MinScreen *) (s)->base.privates[(md)->screenPrivateIndex].ptr)
91
92 #define MIN_SCREEN(s) \
93 MinScreen *ms = GET_MIN_SCREEN (s, GET_MIN_DISPLAY (s->display))
94
95 #define GET_MIN_WINDOW(w, ms) \
96 ((MinWindow *) (w)->base.privates[(ms)->windowPrivateIndex].ptr)
97
98 #define MIN_WINDOW(w) \
99 MinWindow *mw = GET_MIN_WINDOW (w, \
100 GET_MIN_SCREEN (w->screen, \
101 GET_MIN_DISPLAY (w->screen->display)))
102
103 #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
104
105 static CompOption *
minGetScreenOptions(CompPlugin * plugin,CompScreen * screen,int * count)106 minGetScreenOptions (CompPlugin *plugin,
107 CompScreen *screen,
108 int *count)
109 {
110 MIN_SCREEN (screen);
111
112 *count = NUM_OPTIONS (ms);
113 return ms->opt;
114 }
115
116 static Bool
minSetScreenOption(CompPlugin * plugin,CompScreen * screen,const char * name,CompOptionValue * value)117 minSetScreenOption (CompPlugin *plugin,
118 CompScreen *screen,
119 const char *name,
120 CompOptionValue *value)
121 {
122 CompOption *o;
123 int index;
124
125 MIN_SCREEN (screen);
126
127 o = compFindOption (ms->opt, NUM_OPTIONS (ms), name, &index);
128 if (!o)
129 return FALSE;
130
131 switch (index) {
132 case MIN_SCREEN_OPTION_SHADE_RESISTANCE:
133 if (compSetIntOption (o, value))
134 {
135 if (o->value.i)
136 ms->shadeStep = o->rest.i.max - o->value.i + 1;
137 else
138 ms->shadeStep = 0;
139
140 return TRUE;
141 }
142 break;
143 default:
144 if (compSetOption (o, value))
145 return TRUE;
146 break;
147 }
148
149 return FALSE;
150 }
151
152 static void
minSetShade(CompWindow * w,int shade)153 minSetShade (CompWindow *w,
154 int shade)
155 {
156 REGION rect;
157 int h = w->attrib.height + w->attrib.border_width * 2;
158
159 MIN_WINDOW (w);
160
161 EMPTY_REGION (w->region);
162
163 rect.rects = &rect.extents;
164 rect.numRects = rect.size = 1;
165
166 w->height = shade;
167
168 rect.extents.x1 = 0;
169 rect.extents.y1 = h - shade;
170 rect.extents.x2 = w->width;
171 rect.extents.y2 = h;
172
173 XIntersectRegion (mw->region, &rect, w->region);
174 XOffsetRegion (w->region, w->attrib.x, w->attrib.y - (h - shade));
175
176 w->matrix = w->texture->matrix;
177 w->matrix.x0 -= (w->attrib.x * w->matrix.xx);
178 w->matrix.y0 -= ((w->attrib.y - (h - shade)) * w->matrix.yy);
179
180 (*w->screen->windowResizeNotify) (w, 0, 0, 0, 0);
181 }
182
183 static int
minGetWindowState(CompWindow * w)184 minGetWindowState (CompWindow *w)
185 {
186 Atom actual;
187 int result, format;
188 unsigned long n, left;
189 unsigned char *data;
190 int retval = WithdrawnState;
191
192 result = XGetWindowProperty (w->screen->display->display, w->id,
193 w->screen->display->wmStateAtom, 0L, 1L, FALSE,
194 w->screen->display->wmStateAtom,
195 &actual, &format, &n, &left, &data);
196
197 if (result == Success && data)
198 {
199 if (n)
200 memcpy (&retval, data, sizeof (int));
201
202 XFree ((void *) data);
203 }
204
205 return retval;
206 }
207
208 static int
adjustMinVelocity(CompWindow * w)209 adjustMinVelocity (CompWindow *w)
210 {
211 float dx, dy, dxs, dys, adjust, amount;
212 float x1, y1, xScale, yScale;
213
214 MIN_WINDOW (w);
215
216 if (mw->newState == IconicState)
217 {
218 x1 = w->iconGeometry.x;
219 y1 = w->iconGeometry.y;
220 xScale = (float) w->iconGeometry.width / w->width;
221 yScale = (float) w->iconGeometry.height / w->height;
222 }
223 else
224 {
225 x1 = w->serverX;
226 y1 = w->serverY;
227 xScale = yScale = 1.0f;
228 }
229
230 dx = x1 - (w->attrib.x + mw->tx);
231
232 adjust = dx * 0.15f;
233 amount = fabs (dx) * 1.5f;
234 if (amount < 0.5f)
235 amount = 0.5f;
236 else if (amount > 5.0f)
237 amount = 5.0f;
238
239 mw->xVelocity = (amount * mw->xVelocity + adjust) / (amount + 1.0f);
240
241 dy = y1 - (w->attrib.y + mw->ty);
242
243 adjust = dy * 0.15f;
244 amount = fabs (dy) * 1.5f;
245 if (amount < 0.5f)
246 amount = 0.5f;
247 else if (amount > 5.0f)
248 amount = 5.0f;
249
250 mw->yVelocity = (amount * mw->yVelocity + adjust) / (amount + 1.0f);
251
252 dxs = xScale - mw->xScale;
253
254 adjust = dxs * 0.15f;
255 amount = fabs (dxs) * 10.0f;
256 if (amount < 0.01f)
257 amount = 0.01f;
258 else if (amount > 0.15f)
259 amount = 0.15f;
260
261 mw->xScaleVelocity = (amount * mw->xScaleVelocity + adjust) /
262 (amount + 1.0f);
263
264 dys = yScale - mw->yScale;
265
266 adjust = dys * 0.15f;
267 amount = fabs (dys) * 10.0f;
268 if (amount < 0.01f)
269 amount = 0.01f;
270 else if (amount > 0.15f)
271 amount = 0.15f;
272
273 mw->yScaleVelocity = (amount * mw->yScaleVelocity + adjust) /
274 (amount + 1.0f);
275
276 if (fabs (dx) < 0.1f && fabs (mw->xVelocity) < 0.2f &&
277 fabs (dy) < 0.1f && fabs (mw->yVelocity) < 0.2f &&
278 fabs (dxs) < 0.001f && fabs (mw->xScaleVelocity) < 0.002f &&
279 fabs (dys) < 0.001f && fabs (mw->yScaleVelocity) < 0.002f)
280 {
281 mw->xVelocity = mw->yVelocity = mw->xScaleVelocity =
282 mw->yScaleVelocity = 0.0f;
283 mw->tx = x1 - w->attrib.x;
284 mw->ty = y1 - w->attrib.y;
285 mw->xScale = xScale;
286 mw->yScale = yScale;
287
288 return 0;
289 }
290
291 return 1;
292 }
293
294 static void
minPreparePaintScreen(CompScreen * s,int msSinceLastPaint)295 minPreparePaintScreen (CompScreen *s,
296 int msSinceLastPaint)
297 {
298 MIN_SCREEN (s);
299
300 if (ms->moreAdjust)
301 {
302 CompWindow *w;
303 int steps, h;
304 float amount, chunk;
305
306 amount = msSinceLastPaint * 0.05f *
307 ms->opt[MIN_SCREEN_OPTION_SPEED].value.f;
308 steps = amount / (0.5f * ms->opt[MIN_SCREEN_OPTION_TIMESTEP].value.f);
309 if (!steps) steps = 1;
310 chunk = amount / (float) steps;
311
312 while (steps--)
313 {
314 ms->moreAdjust = 0;
315
316 for (w = s->windows; w; w = w->next)
317 {
318 MIN_WINDOW (w);
319
320 if (mw->adjust)
321 {
322 mw->adjust = adjustMinVelocity (w);
323
324 ms->moreAdjust |= mw->adjust;
325
326 mw->tx += mw->xVelocity * chunk;
327 mw->ty += mw->yVelocity * chunk;
328 mw->xScale += mw->xScaleVelocity * chunk;
329 mw->yScale += mw->yScaleVelocity * chunk;
330
331 if (!mw->adjust)
332 {
333 mw->state = mw->newState;
334
335 mw->ignoreDamage = TRUE;
336 while (mw->unmapCnt)
337 {
338 unmapWindow (w);
339 mw->unmapCnt--;
340 }
341 mw->ignoreDamage = FALSE;
342 }
343 }
344 else if (mw->region && w->damaged)
345 {
346 if (w->shaded)
347 {
348 if (mw->shade > 0)
349 {
350 mw->shade -= (chunk * ms->shadeStep) + 1;
351
352 if (mw->shade > 0)
353 {
354 ms->moreAdjust = TRUE;
355 }
356 else
357 {
358 mw->shade = 0;
359
360 mw->ignoreDamage = TRUE;
361 while (mw->unmapCnt)
362 {
363 unmapWindow (w);
364 mw->unmapCnt--;
365 }
366 mw->ignoreDamage = FALSE;
367 }
368 }
369 }
370 else
371 {
372 h = w->attrib.height + w->attrib.border_width * 2;
373 if (mw->shade < h)
374 {
375 mw->shade += (chunk * ms->shadeStep) + 1;
376
377 if (mw->shade < h)
378 {
379 ms->moreAdjust = TRUE;
380 }
381 else
382 {
383 mw->shade = MAXSHORT;
384
385 minSetShade (w, h);
386
387 XDestroyRegion (mw->region);
388 mw->region = NULL;
389
390 addWindowDamage (w);
391 }
392 }
393 }
394 }
395 }
396
397 if (!ms->moreAdjust)
398 break;
399 }
400
401 if (ms->moreAdjust)
402 {
403 for (w = s->windows; w; w = w->next)
404 {
405 MIN_WINDOW (w);
406
407 if (mw->adjust)
408 {
409 addWindowDamage (w);
410 }
411 else if (mw->region && w->damaged)
412 {
413 h = w->attrib.height + w->attrib.border_width * 2;
414 if (mw->shade && mw->shade < h)
415 {
416 minSetShade (w, mw->shade);
417 addWindowDamage (w);
418 }
419 }
420 }
421 }
422 }
423
424 UNWRAP (ms, s, preparePaintScreen);
425 (*s->preparePaintScreen) (s, msSinceLastPaint);
426 WRAP (ms, s, preparePaintScreen, minPreparePaintScreen);
427 }
428
429 static void
minDonePaintScreen(CompScreen * s)430 minDonePaintScreen (CompScreen *s)
431 {
432 MIN_SCREEN (s);
433
434 if (ms->moreAdjust)
435 {
436 CompWindow *w;
437 int h;
438
439 for (w = s->windows; w; w = w->next)
440 {
441 MIN_WINDOW (w);
442
443 if (mw->adjust)
444 {
445 addWindowDamage (w);
446 }
447 else if (mw->region)
448 {
449 h = w->attrib.height + w->attrib.border_width * 2;
450 if (mw->shade && mw->shade < h)
451 addWindowDamage (w);
452 }
453 }
454 }
455
456 UNWRAP (ms, s, donePaintScreen);
457 (*s->donePaintScreen) (s);
458 WRAP (ms, s, donePaintScreen, minDonePaintScreen);
459 }
460
461 static Bool
minPaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)462 minPaintOutput (CompScreen *s,
463 const ScreenPaintAttrib *sAttrib,
464 const CompTransform *transform,
465 Region region,
466 CompOutput *output,
467 unsigned int mask)
468 {
469 Bool status;
470
471 MIN_SCREEN (s);
472
473 if (ms->moreAdjust)
474 mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
475
476 UNWRAP (ms, s, paintOutput);
477 status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
478 WRAP (ms, s, paintOutput, minPaintOutput);
479
480 return status;
481 }
482
483 static Bool
minPaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)484 minPaintWindow (CompWindow *w,
485 const WindowPaintAttrib *attrib,
486 const CompTransform *transform,
487 Region region,
488 unsigned int mask)
489 {
490 CompScreen *s = w->screen;
491 Bool status;
492
493 MIN_SCREEN (s);
494 MIN_WINDOW (w);
495
496 if (mw->adjust)
497 {
498 FragmentAttrib fragment;
499 CompTransform wTransform = *transform;
500
501 if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
502 return FALSE;
503
504 UNWRAP (ms, s, paintWindow);
505 status = (*s->paintWindow) (w, attrib, transform, region,
506 mask | PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
507 WRAP (ms, s, paintWindow, minPaintWindow);
508
509 initFragmentAttrib (&fragment, &w->lastPaint);
510
511 if (w->alpha || fragment.opacity != OPAQUE)
512 mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
513
514 matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
515 matrixScale (&wTransform, mw->xScale, mw->yScale, 1.0f);
516 matrixTranslate (&wTransform,
517 mw->tx / mw->xScale - w->attrib.x,
518 mw->ty / mw->yScale - w->attrib.y,
519 0.0f);
520
521 glPushMatrix ();
522 glLoadMatrixf (wTransform.m);
523
524 (*s->drawWindow) (w, &wTransform, &fragment, region,
525 mask | PAINT_WINDOW_TRANSFORMED_MASK);
526
527 glPopMatrix ();
528 }
529 else
530 {
531 /* no core instance from windows that have been animated */
532 if (mw->state == IconicState)
533 mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
534
535 UNWRAP (ms, s, paintWindow);
536 status = (*s->paintWindow) (w, attrib, transform, region, mask);
537 WRAP (ms, s, paintWindow, minPaintWindow);
538 }
539
540 return status;
541 }
542
543 static void
minHandleEvent(CompDisplay * d,XEvent * event)544 minHandleEvent (CompDisplay *d,
545 XEvent *event)
546 {
547 CompWindow *w;
548
549 MIN_DISPLAY (d);
550
551 switch (event->type) {
552 case MapNotify:
553 w = findWindowAtDisplay (d, event->xmap.window);
554 if (w)
555 {
556 MIN_WINDOW (w);
557
558 if (mw->adjust)
559 mw->state = mw->newState;
560
561 if (mw->region)
562 w->height = 0;
563
564 mw->ignoreDamage = TRUE;
565 while (mw->unmapCnt)
566 {
567 unmapWindow (w);
568 mw->unmapCnt--;
569 }
570 mw->ignoreDamage = FALSE;
571 }
572 break;
573 case UnmapNotify:
574 w = findWindowAtDisplay (d, event->xunmap.window);
575 if (w)
576 {
577 MIN_SCREEN (w->screen);
578
579 if (w->pendingUnmaps && onCurrentDesktop (w)) /* Normal -> Iconic */
580 {
581 CompMatch *match =
582 &ms->opt[MIN_SCREEN_OPTION_WINDOW_MATCH].value.match;
583
584 MIN_WINDOW (w);
585
586 if (w->shaded)
587 {
588 if (!mw->region)
589 mw->region = XCreateRegion ();
590
591 if (mw->region && ms->shadeStep)
592 {
593 XSubtractRegion (w->region, &emptyRegion, mw->region);
594 XOffsetRegion (mw->region, -w->attrib.x,
595 w->attrib.height +
596 w->attrib.border_width * 2 -
597 w->height - w->attrib.y);
598
599 mw->shade = w->height;
600
601 mw->adjust = FALSE;
602 ms->moreAdjust = TRUE;
603
604 mw->unmapCnt++;
605 w->unmapRefCnt++;
606
607 addWindowDamage (w);
608 }
609 }
610 else if (!w->invisible && matchEval (match, w))
611 {
612 if (w->iconGeometrySet)
613 {
614 mw->newState = IconicState;
615
616 mw->xScale = w->paint.xScale;
617 mw->yScale = w->paint.yScale;
618 mw->tx = w->attrib.x - w->serverX;
619 mw->ty = w->attrib.y - w->serverY;
620
621 if (mw->region)
622 {
623 XDestroyRegion (mw->region);
624 mw->region = NULL;
625 }
626
627 mw->shade = MAXSHORT;
628
629 mw->adjust = TRUE;
630 ms->moreAdjust = TRUE;
631
632 mw->unmapCnt++;
633 w->unmapRefCnt++;
634
635 addWindowDamage (w);
636 }
637 }
638 }
639 else /* X -> Withdrawn */
640 {
641 MIN_WINDOW (w);
642
643 if (mw->adjust)
644 {
645 mw->adjust = FALSE;
646 mw->xScale = mw->yScale = 1.0f;
647 mw->tx = mw->ty = 0.0f;
648 mw->xVelocity = mw->yVelocity = 0.0f;
649 mw->xScaleVelocity = mw->yScaleVelocity = 1.0f;
650 mw->shade = MAXSHORT;
651
652 if (mw->region)
653 {
654 XDestroyRegion (mw->region);
655 mw->region = NULL;
656 }
657 }
658
659 mw->state = NormalState;
660 }
661 }
662 default:
663 break;
664 }
665
666 UNWRAP (md, d, handleEvent);
667 (*d->handleEvent) (d, event);
668 WRAP (md, d, handleEvent, minHandleEvent);
669 }
670
671 static Bool
minDamageWindowRect(CompWindow * w,Bool initial,BoxPtr rect)672 minDamageWindowRect (CompWindow *w,
673 Bool initial,
674 BoxPtr rect)
675 {
676 Bool status = FALSE;
677
678 MIN_SCREEN (w->screen);
679 MIN_WINDOW (w);
680
681 if (mw->ignoreDamage)
682 return TRUE;
683
684 if (initial)
685 {
686 if (mw->state == IconicState)
687 {
688 CompMatch *match =
689 &ms->opt[MIN_SCREEN_OPTION_WINDOW_MATCH].value.match;
690
691 mw->state = NormalState;
692
693 if (!w->invisible &&
694 w->iconGeometrySet &&
695 matchEval (match, w))
696 {
697 if (!mw->adjust)
698 {
699 mw->adjust = TRUE;
700 ms->moreAdjust = TRUE;
701
702 mw->tx = w->iconGeometry.x - w->serverX;
703 mw->ty = w->iconGeometry.y - w->serverY;
704 mw->xScale = (float) w->iconGeometry.width / w->width;
705 mw->yScale = (float) w->iconGeometry.height / w->height;
706
707 addWindowDamage (w);
708 }
709 }
710 }
711 else if (mw->region && mw->shade < w->height)
712 {
713 if (ms->shadeStep && !w->invisible)
714 {
715 XSubtractRegion (w->region, &emptyRegion, mw->region);
716 XOffsetRegion (mw->region, -w->attrib.x, -w->attrib.y);
717
718 /* bind pixmap here so we have something to unshade with */
719 if (!w->texture->pixmap && !w->bindFailed)
720 bindWindow (w);
721
722 ms->moreAdjust = TRUE;
723 }
724 else
725 {
726 mw->shade = MAXSHORT;
727 }
728 }
729
730 mw->newState = NormalState;
731 }
732 else if (mw->adjust)
733 {
734 damageTransformedWindowRect (w,
735 mw->xScale,
736 mw->yScale,
737 mw->tx,
738 mw->ty,
739 rect);
740
741 status = TRUE;
742 }
743
744 UNWRAP (ms, w->screen, damageWindowRect);
745 status |= (*w->screen->damageWindowRect) (w, initial, rect);
746 WRAP (ms, w->screen, damageWindowRect, minDamageWindowRect);
747
748 return status;
749 }
750
751 static Bool
minFocusWindow(CompWindow * w)752 minFocusWindow (CompWindow *w)
753 {
754 Bool status;
755
756 MIN_SCREEN (w->screen);
757 MIN_WINDOW (w);
758
759 if (mw->unmapCnt)
760 return FALSE;
761
762 UNWRAP (ms, w->screen, focusWindow);
763 status = (*w->screen->focusWindow) (w);
764 WRAP (ms, w->screen, focusWindow, minFocusWindow);
765
766 return status;
767 }
768
769 static Bool
minInitDisplay(CompPlugin * p,CompDisplay * d)770 minInitDisplay (CompPlugin *p,
771 CompDisplay *d)
772 {
773 MinDisplay *md;
774
775 if (!checkPluginABI ("core", CORE_ABIVERSION))
776 return FALSE;
777
778 md = malloc (sizeof (MinDisplay));
779 if (!md)
780 return FALSE;
781
782 md->screenPrivateIndex = allocateScreenPrivateIndex (d);
783 if (md->screenPrivateIndex < 0)
784 {
785 free (md);
786 return FALSE;
787 }
788
789 md->winChangeStateAtom = XInternAtom (d->display, "WM_CHANGE_STATE", 0);
790
791 WRAP (md, d, handleEvent, minHandleEvent);
792
793 d->base.privates[displayPrivateIndex].ptr = md;
794
795 return TRUE;
796 }
797
798 static void
minFiniDisplay(CompPlugin * p,CompDisplay * d)799 minFiniDisplay (CompPlugin *p,
800 CompDisplay *d)
801 {
802 MIN_DISPLAY (d);
803
804 freeScreenPrivateIndex (d, md->screenPrivateIndex);
805
806 UNWRAP (md, d, handleEvent);
807
808 free (md);
809 }
810
811 static const CompMetadataOptionInfo minScreenOptionInfo[] = {
812 { "speed", "float", "<min>0.1</min>", 0, 0 },
813 { "timestep", "float", "<min>0.1</min>", 0, 0 },
814 { "window_match", "match", 0, 0, 0 },
815 { "shade_resistance", "int", "<min>0</min><max>100</max>", 0, 0 }
816 };
817
818 static Bool
minInitScreen(CompPlugin * p,CompScreen * s)819 minInitScreen (CompPlugin *p,
820 CompScreen *s)
821 {
822 MinScreen *ms;
823
824 MIN_DISPLAY (s->display);
825
826 ms = malloc (sizeof (MinScreen));
827 if (!ms)
828 return FALSE;
829
830 if (!compInitScreenOptionsFromMetadata (s,
831 &minMetadata,
832 minScreenOptionInfo,
833 ms->opt,
834 MIN_SCREEN_OPTION_NUM))
835 {
836 free (ms);
837 return FALSE;
838 }
839
840 ms->windowPrivateIndex = allocateWindowPrivateIndex (s);
841 if (ms->windowPrivateIndex < 0)
842 {
843 compFiniScreenOptions (s, ms->opt, MIN_SCREEN_OPTION_NUM);
844 free (ms);
845 return FALSE;
846 }
847
848 ms->moreAdjust = FALSE;
849 ms->shadeStep = ms->opt[MIN_SCREEN_OPTION_SHADE_RESISTANCE].rest.i.max -
850 ms->opt[MIN_SCREEN_OPTION_SHADE_RESISTANCE].value.i + 1;
851
852 WRAP (ms, s, preparePaintScreen, minPreparePaintScreen);
853 WRAP (ms, s, donePaintScreen, minDonePaintScreen);
854 WRAP (ms, s, paintOutput, minPaintOutput);
855 WRAP (ms, s, paintWindow, minPaintWindow);
856 WRAP (ms, s, damageWindowRect, minDamageWindowRect);
857 WRAP (ms, s, focusWindow, minFocusWindow);
858
859 s->base.privates[md->screenPrivateIndex].ptr = ms;
860
861 return TRUE;
862 }
863
864 static void
minFiniScreen(CompPlugin * p,CompScreen * s)865 minFiniScreen (CompPlugin *p,
866 CompScreen *s)
867 {
868 MIN_SCREEN (s);
869
870 freeWindowPrivateIndex (s, ms->windowPrivateIndex);
871
872 UNWRAP (ms, s, preparePaintScreen);
873 UNWRAP (ms, s, donePaintScreen);
874 UNWRAP (ms, s, paintOutput);
875 UNWRAP (ms, s, paintWindow);
876 UNWRAP (ms, s, damageWindowRect);
877 UNWRAP (ms, s, focusWindow);
878
879 compFiniScreenOptions (s, ms->opt, MIN_SCREEN_OPTION_NUM);
880
881 free (ms);
882 }
883
884 static Bool
minInitWindow(CompPlugin * p,CompWindow * w)885 minInitWindow (CompPlugin *p,
886 CompWindow *w)
887 {
888 MinWindow *mw;
889
890 MIN_SCREEN (w->screen);
891
892 mw = malloc (sizeof (MinWindow));
893 if (!mw)
894 return FALSE;
895
896 mw->xScale = mw->yScale = 1.0f;
897 mw->tx = mw->ty = 0.0f;
898 mw->adjust = FALSE;
899 mw->xVelocity = mw->yVelocity = 0.0f;
900 mw->xScaleVelocity = mw->yScaleVelocity = 1.0f;
901
902 mw->unmapCnt = 0;
903
904 mw->ignoreDamage = FALSE;
905
906 if (w->state & CompWindowStateHiddenMask)
907 {
908 if (w->shaded)
909 {
910 mw->state = mw->newState = NormalState;
911 mw->shade = 0;
912 mw->region = XCreateRegion ();
913 }
914 else
915 {
916 mw->state = mw->newState = minGetWindowState (w);
917 mw->shade = MAXSHORT;
918 mw->region = NULL;
919 }
920 }
921 else
922 {
923 mw->state = mw->newState = NormalState;
924 mw->shade = MAXSHORT;
925 mw->region = NULL;
926 }
927
928 w->base.privates[ms->windowPrivateIndex].ptr = mw;
929
930 return TRUE;
931 }
932
933 static void
minFiniWindow(CompPlugin * p,CompWindow * w)934 minFiniWindow (CompPlugin *p,
935 CompWindow *w)
936 {
937 MIN_WINDOW (w);
938
939 mw->ignoreDamage = TRUE;
940 while (mw->unmapCnt--)
941 unmapWindow (w);
942 mw->ignoreDamage = FALSE;
943
944 if (mw->region)
945 XDestroyRegion (mw->region);
946
947 free (mw);
948 }
949
950 static CompBool
minInitObject(CompPlugin * p,CompObject * o)951 minInitObject (CompPlugin *p,
952 CompObject *o)
953 {
954 static InitPluginObjectProc dispTab[] = {
955 (InitPluginObjectProc) 0, /* InitCore */
956 (InitPluginObjectProc) minInitDisplay,
957 (InitPluginObjectProc) minInitScreen,
958 (InitPluginObjectProc) minInitWindow
959 };
960
961 RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
962 }
963
964 static void
minFiniObject(CompPlugin * p,CompObject * o)965 minFiniObject (CompPlugin *p,
966 CompObject *o)
967 {
968 static FiniPluginObjectProc dispTab[] = {
969 (FiniPluginObjectProc) 0, /* FiniCore */
970 (FiniPluginObjectProc) minFiniDisplay,
971 (FiniPluginObjectProc) minFiniScreen,
972 (FiniPluginObjectProc) minFiniWindow
973 };
974
975 DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
976 }
977
978 static CompOption *
minGetObjectOptions(CompPlugin * plugin,CompObject * object,int * count)979 minGetObjectOptions (CompPlugin *plugin,
980 CompObject *object,
981 int *count)
982 {
983 static GetPluginObjectOptionsProc dispTab[] = {
984 (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
985 (GetPluginObjectOptionsProc) 0, /* GetDisplayOptions */
986 (GetPluginObjectOptionsProc) minGetScreenOptions
987 };
988
989 *count = 0;
990 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
991 (void *) count, (plugin, object, count));
992 }
993
994 static CompBool
minSetObjectOption(CompPlugin * plugin,CompObject * object,const char * name,CompOptionValue * value)995 minSetObjectOption (CompPlugin *plugin,
996 CompObject *object,
997 const char *name,
998 CompOptionValue *value)
999 {
1000 static SetPluginObjectOptionProc dispTab[] = {
1001 (SetPluginObjectOptionProc) 0, /* SetCoreOption */
1002 (SetPluginObjectOptionProc) 0, /* SetDisplayOption */
1003 (SetPluginObjectOptionProc) minSetScreenOption
1004 };
1005
1006 RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
1007 (plugin, object, name, value));
1008 }
1009
1010 static Bool
minInit(CompPlugin * p)1011 minInit (CompPlugin *p)
1012 {
1013 if (!compInitPluginMetadataFromInfo (&minMetadata,
1014 p->vTable->name, 0, 0,
1015 minScreenOptionInfo,
1016 MIN_SCREEN_OPTION_NUM))
1017 return FALSE;
1018
1019 displayPrivateIndex = allocateDisplayPrivateIndex ();
1020 if (displayPrivateIndex < 0)
1021 {
1022 compFiniMetadata (&minMetadata);
1023 return FALSE;
1024 }
1025
1026 compAddMetadataFromFile (&minMetadata, p->vTable->name);
1027
1028 return TRUE;
1029 }
1030
1031 static void
minFini(CompPlugin * p)1032 minFini (CompPlugin *p)
1033 {
1034 freeDisplayPrivateIndex (displayPrivateIndex);
1035 compFiniMetadata (&minMetadata);
1036 }
1037
1038 static CompMetadata *
minGetMetadata(CompPlugin * plugin)1039 minGetMetadata (CompPlugin *plugin)
1040 {
1041 return &minMetadata;
1042 }
1043
1044 static CompPluginVTable minVTable = {
1045 "minimize",
1046 minGetMetadata,
1047 minInit,
1048 minFini,
1049 minInitObject,
1050 minFiniObject,
1051 minGetObjectOptions,
1052 minSetObjectOption
1053 };
1054
1055 CompPluginVTable *
getCompPluginInfo20070830(void)1056 getCompPluginInfo20070830 (void)
1057 {
1058 return &minVTable;
1059 }
1060