2
* Compiz Fusion Freewins plugin
6
* Copyright (C) 2007 Rodolfo Granata <warlock.cc@gmail.com>
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License
10
* as published by the Free Software Foundation; either version 2
11
* of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
19
* Rodolfo Granata <warlock.cc@gmail.com>
20
* Sam Spilsbury <smspillaz@gmail.com>
22
* Button binding support and Reset added by:
23
* enigma_0Z <enigma.0ZA@gmail.com>
25
* Most of the input handling here is based on
27
* : Kristian LyngstĆøl <kristian@bohemians.org>
28
* : Danny Baumann <maniac@opencompositing.org>
32
* This plugin allows you to freely transform the texture of a window,
33
* whether that be rotation or scaling to make better use of screen space
37
* - Fully implement an input redirection system by
38
* finding an inverse matrix, multiplying by it,
39
* translating to the actual window co-ords and
40
* XSendEvent() the co-ords to the actual window.
41
* - Code could be cleaner
42
* - Add timestep and speed options to animation
43
* - Add window hover-over info via paintOutput : i.e
53
/* ------ Window and Output Painting ------------------------------------*/
55
/* Damage util function */
58
FWWindow::damageArea ()
60
CompositeScreen::get (screen)->damageRegion (mOutputRect);
65
FWScreen::preparePaint (int ms)
67
/* FIXME: should only loop over all windows if at least one animation is running */
68
foreach (CompWindow *w, screen->windows ())
71
float speed = optionGetSpeed ();
72
fww->mAnimate.steps = ((float) ms / ((20.1 - speed) * 100));
74
if (fww->mAnimate.steps < 0.005)
75
fww->mAnimate.steps = 0.005;
77
/* Animation. We calculate how much increment
78
* a window must rotate / scale per paint by
79
* using the set destination attributes minus
80
* the old attributes divided by the time
84
/* Don't animate if the window is saved */
85
fww->mTransform.angX += (float) fww->mAnimate.steps * (fww->mAnimate.destAngX - fww->mTransform.angX) * speed;
86
fww->mTransform.angY += (float) fww->mAnimate.steps * (fww->mAnimate.destAngY - fww->mTransform.angY) * speed;
87
fww->mTransform.angZ += (float) fww->mAnimate.steps * (fww->mAnimate.destAngZ - fww->mTransform.angZ) * speed;
89
fww->mTransform.scaleX += (float) fww->mAnimate.steps * (fww->mAnimate.destScaleX - fww->mTransform.scaleX) * speed;
90
fww->mTransform.scaleY += (float) fww->mAnimate.steps * (fww->mAnimate.destScaleY - fww->mTransform.scaleY) * speed;
92
if (((fww->mTransform.angX >= fww->mAnimate.destAngX - 0.05 &&
93
fww->mTransform.angX <= fww->mAnimate.destAngX + 0.05 ) &&
94
(fww->mTransform.angY >= fww->mAnimate.destAngY - 0.05 &&
95
fww->mTransform.angY <= fww->mAnimate.destAngY + 0.05 ) &&
96
(fww->mTransform.angZ >= fww->mAnimate.destAngZ - 0.05 &&
97
fww->mTransform.angZ <= fww->mAnimate.destAngZ + 0.05 ) &&
98
(fww->mTransform.scaleX >= fww->mAnimate.destScaleX - 0.00005 &&
99
fww->mTransform.scaleX <= fww->mAnimate.destScaleX + 0.00005 ) &&
100
(fww->mTransform.scaleY >= fww->mAnimate.destScaleY - 0.00005 &&
101
fww->mTransform.scaleY <= fww->mAnimate.destScaleY + 0.00005 )))
103
fww->mResetting = FALSE;
105
fww->mTransform.angX = fww->mAnimate.destAngX;
106
fww->mTransform.angY = fww->mAnimate.destAngY;
107
fww->mTransform.angZ = fww->mAnimate.destAngZ;
108
fww->mTransform.scaleX = fww->mAnimate.destScaleX;
109
fww->mTransform.scaleY = fww->mAnimate.destScaleY;
111
fww->mTransform.unsnapAngX = fww->mAnimate.destAngX;
112
fww->mTransform.unsnapAngY = fww->mAnimate.destAngY;
113
fww->mTransform.unsnapAngZ = fww->mAnimate.destAngZ;
114
fww->mTransform.unsnapScaleX = fww->mAnimate.destScaleX;
115
fww->mTransform.unsnapScaleY = fww->mAnimate.destScaleX;
118
// fww->damageArea ();
121
cScreen->preparePaint (ms);
124
/* Paint the window rotated or scaled */
126
FWWindow::glPaint (const GLWindowPaintAttrib &attrib,
127
const GLMatrix &transform,
128
const CompRegion ®ion,
132
GLMatrix wTransform (transform);
133
int currentCull, invertCull;
134
glGetIntegerv (GL_CULL_FACE_MODE, ¤tCull);
135
invertCull = (currentCull == GL_BACK) ? GL_FRONT : GL_BACK;
139
FREEWINS_SCREEN (screen);
141
/* Has something happened? */
143
/* Check to see if we are painting on a transformed screen */
144
/* Enable this code when we can animate between the two states */
146
if ((mTransform.angX != 0.0 ||
147
mTransform.angY != 0.0 ||
148
mTransform.angZ != 0.0 ||
149
mTransform.scaleX != 1.0 ||
150
mTransform.scaleY != 1.0 ||
151
mOldWinX != WIN_REAL_X (window) ||
152
mOldWinY != WIN_REAL_Y (window)) && fws->optionGetShapeWindowTypes ().evaluate (window))
154
mOldWinX = WIN_REAL_X (window);
155
mOldWinY = WIN_REAL_Y (window);
157
/* Figure out where our 'origin' is, don't allow the origin to
158
* be where we clicked if the window is not grabbed, etc
161
/* Here we duplicate some of the work the openGL does
162
* but for different reasons. We have access to the
163
* window's transformation matrix, so we will create
164
* our own matrix and apply the same transformations
165
* to it. From there, we create vectors for each point
166
* that we wish to track and multiply them by this
167
* matrix to give us the rotated / scaled co-ordinates.
168
* From there, we project these co-ordinates onto the flat
169
* screen that we have using the OGL viewport, projection
170
* matrix and model matrix. Projection gives us three
171
* co-ordinates, but we ignore Z and just use X and Y
172
* to store in a surrounding rectangle. We can use this
173
* surrounding rectangle to make things like shaping and
174
* damage a lot more accurate than they used to be.
177
calculateOutputRect ();
179
/* Prepare for transformation by
180
* doing any necessary adjustments */
181
float autoScaleX = 1.0f;
182
float autoScaleY = 1.0f;
184
if (fws->optionGetAutoZoom ())
186
float apparantWidth = mOutputRect.width ();
187
float apparantHeight = mOutputRect.height ();
189
autoScaleX = (float) WIN_OUTPUT_W (window) / (float) apparantWidth;
190
autoScaleY = (float) WIN_OUTPUT_H (window) / (float) apparantHeight;
192
if (autoScaleX >= 1.0f)
194
if (autoScaleY >= 1.0f)
197
autoScaleX = autoScaleY = (autoScaleX + autoScaleY) / 2;
199
/* Because we modified the scale after calculating
200
* the output rect, we need to recalculate again */
201
calculateOutputRect ();
205
float scaleX = autoScaleX - (1 - mTransform.scaleX);
206
float scaleY = autoScaleY - (1 - mTransform.scaleY);
209
/* Actually Transform the window */
210
mask |= PAINT_WINDOW_TRANSFORMED_MASK;
212
/* Adjust the window in the matrix to prepare for transformation */
213
if (mGrab != grabRotate && mGrab != grabScale)
216
calculateInputOrigin (WIN_REAL_X (window) + WIN_REAL_W (window) / 2.0f,
217
WIN_REAL_Y (window) + WIN_REAL_H (window) / 2.0f);
218
calculateOutputOrigin (WIN_OUTPUT_X (window) + WIN_OUTPUT_W (window) / 2.0f,
219
WIN_OUTPUT_Y (window) + WIN_OUTPUT_H (window) / 2.0f);
222
float adjustX = 0.0f;
223
float adjustY = 0.0f;
224
fws->modifyMatrix (wTransform,
228
mIMidX, mIMidY , 0.0f,
231
1.0f, adjustX, adjustY, TRUE);
233
/* Create rects for input after we've dealt with output */
234
calculateInputRect ();
236
/* Determine if the window is inverted */
237
Bool xInvert = FALSE;
238
Bool yInvert = FALSE;
240
Bool needsInvert = FALSE;
241
float renX = fabs (fmodf (mTransform.angX, 360.0f));
242
float renY = fabs (fmodf (mTransform.angY, 360.0f));
244
if (90 < renX && renX < 270)
247
if (90 < renY && renY < 270)
250
if ((xInvert || yInvert) && !(xInvert && yInvert))
254
glCullFace (invertCull);
256
status = gWindow->glPaint (attrib, wTransform, region, mask);
259
glCullFace (currentCull);
264
status = gWindow->glPaint (attrib, wTransform, region, mask);
267
// Check if there are rotated windows
268
if (!((mTransform.angX >= 0.0f - 0.05 &&
269
mTransform.angX <= 0.0f + 0.05 ) &&
270
(mTransform.angY >= 0.0f - 0.05 &&
271
mTransform.angY <= 0.0f + 0.05 ) &&
272
(mTransform.angZ >= 0.0f - 0.05 &&
273
mTransform.angZ <= 0.0f + 0.05 ) &&
274
(mTransform.scaleX >= 1.0f - 0.00005 &&
275
mTransform.scaleX <= 1.0f + 0.00005 ) &&
276
(mTransform.scaleY >= 1.0f - 0.00005 &&
277
mTransform.scaleY <= 1.0f + 0.00005 )) && !mTransformed)
279
else if (mTransformed)
280
mTransformed = FALSE;
282
/* There is still animation to be done */
283
if (!(((mTransform.angX >= mAnimate.destAngX - 0.05 &&
284
mTransform.angX <= mAnimate.destAngX + 0.05 ) &&
285
(mTransform.angY >= mAnimate.destAngY - 0.05 &&
286
mTransform.angY <= mAnimate.destAngY + 0.05 ) &&
287
(mTransform.angZ >= mAnimate.destAngZ - 0.05 &&
288
mTransform.angZ <= mAnimate.destAngZ + 0.05 ) &&
289
(mTransform.scaleX >= mAnimate.destScaleX - 0.00005 &&
290
mTransform.scaleX <= mAnimate.destScaleX + 0.00005 ) &&
291
(mTransform.scaleY >= mAnimate.destScaleY - 0.00005 &&
292
mTransform.scaleY <= mAnimate.destScaleY + 0.00005 ))))
297
else if (mIsAnimating) /* We're done animating now, and we were animating */
299
if (handleWindowInputInfo ())
301
mIsAnimating = FALSE;
307
/* Paint the window axis help onto the screen */
309
FWScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
310
const GLMatrix &transform,
311
const CompRegion ®ion,
315
GLMatrix zTransform (transform);
317
if (!mTransformedWindows.empty ())
318
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
320
bool status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
322
if (mAxisHelp && mHoverWindow)
325
float x = WIN_REAL_X(mHoverWindow) + WIN_REAL_W(mHoverWindow)/2.0;
326
float y = WIN_REAL_Y(mHoverWindow) + WIN_REAL_H(mHoverWindow)/2.0;
328
FREEWINS_WINDOW (mHoverWindow);
330
float zRad = fww->mRadius * (optionGetTdPercent () / 100);
332
bool wasCulled = glIsEnabled (GL_CULL_FACE);
334
zTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
337
glLoadMatrixf (zTransform.getMatrix ());
340
glDisable (GL_CULL_FACE);
342
if (optionGetShowCircle () && optionGetRotationAxis () == RotationAxisAlwaysCentre)
344
glColor4usv (optionGetCircleColor ());
347
glBegin (GL_POLYGON);
348
for (j = 0; j < 360; j += 10)
349
glVertex3f ( x + zRad * cos(D2R(j)), y + zRad * sin(D2R(j)), 0.0 );
352
glDisable (GL_BLEND);
353
glColor4usv (optionGetLineColor ());
356
glBegin (GL_LINE_LOOP);
357
for (j = 360; j >= 0; j -= 10)
358
glVertex3f ( x + zRad * cos(D2R(j)), y + zRad * sin(D2R(j)), 0.0 );
361
glBegin (GL_LINE_LOOP);
362
for (j = 360; j >= 0; j -= 10)
363
glVertex3f( x + fww->mRadius * cos(D2R(j)), y + fww->mRadius * sin(D2R(j)), 0.0 );
368
/* Draw the 'gizmo' */
369
if (optionGetShowGizmo ())
373
glTranslatef (x, y, 0.0);
375
glScalef (zRad, zRad, zRad / (float)screen->width ());
377
glRotatef (fww->mTransform.angX, 1.0f, 0.0f, 0.0f);
378
glRotatef (fww->mTransform.angY, 0.0f, 1.0f, 0.0f);
379
glRotatef (fww->mTransform.angZ, 0.0f, 0.0f, 1.0f);
383
for (int i = 0; i < 3; i++)
386
glColor4f (1.0 * (i==0), 1.0 * (i==1), 1.0 * (i==2), 1.0);
387
glRotatef (90.0, 1.0 * (i==0), 1.0 * (i==1), 1.0 * (i==2));
389
glBegin (GL_LINE_LOOP);
390
for (j=360; j>=0; j -= 10)
391
glVertex3f ( cos (D2R (j)), sin (D2R (j)), 0.0 );
397
glColor4usv (defaultColor);
400
/* Draw the bounding box */
401
if (optionGetShowRegion ())
403
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
405
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x4fff);
406
glRecti (fww->mInputRect.x1 (), fww->mInputRect.y1 (), fww->mInputRect.x2 (), fww->mInputRect.y2 ());
407
glColor4us (0x2fff, 0x2fff, 0x4fff, 0x9fff);
408
glBegin (GL_LINE_LOOP);
409
glVertex2i (fww->mInputRect.x1 (), fww->mInputRect.y1 ());
410
glVertex2i (fww->mInputRect.x2 (), fww->mInputRect.y1 ());
411
glVertex2i (fww->mInputRect.x1 (), fww->mInputRect.y2 ());
412
glVertex2i (fww->mInputRect.x2 (), fww->mInputRect.y2 ());
414
glColor4usv (defaultColor);
415
glDisable (GL_BLEND);
416
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
419
if (optionGetShowCross ())
422
glColor4usv (optionGetCrossLineColor ());
424
glVertex3f(x, y - (WIN_REAL_H (mHoverWindow) / 2), 0.0f);
425
glVertex3f(x, y + (WIN_REAL_H (mHoverWindow) / 2), 0.0f);
429
glVertex3f(x - (WIN_REAL_W (mHoverWindow) / 2), y, 0.0f);
430
glVertex3f(x + (WIN_REAL_W (mHoverWindow) / 2), y, 0.0f);
433
/* Move to our first corner (TopLeft) */
437
glVertex3f(fww->mOutput.shapex1, fww->mOutput.shapey1, 0.0f);
438
glVertex3f(fww->mOutput.shapex2, fww->mOutput.shapey2, 0.0f);
442
glVertex3f(fww->mOutput.shapex2, fww->mOutput.shapey2, 0.0f);
443
glVertex3f(fww->mOutput.shapex4, fww->mOutput.shapey4, 0.0f);
447
glVertex3f(fww->mOutput.shapex4, fww->mOutput.shapey4, 0.0f);
448
glVertex3f(fww->mOutput.shapex3, fww->mOutput.shapey3, 0.0f);
452
glVertex3f(fww->mOutput.shapex3, fww->mOutput.shapey3, 0.0f);
453
glVertex3f(fww->mOutput.shapex1, fww->mOutput.shapey1, 0.0f);
458
glEnable(GL_CULL_FACE);
460
glColor4usv(defaultColor);
468
FWScreen::donePaint ()
471
if (mAxisHelp && mHoverWindow)
473
FREEWINS_WINDOW (mHoverWindow);
477
region.rects = ®ion.extents;
478
region.numRects = region.size = 1;
480
region.extents.x1 = MIN (WIN_REAL_X (mHoverWindow),
481
WIN_REAL_X (mHoverWindow)
482
+ WIN_REAL_W (mHoverWindow)
483
/ 2.0f - fww->mRadius);
484
region.extents.x2 = MAX (WIN_REAL_X (mHoverWindow),
485
WIN_REAL_X (mHoverWindow)
486
+ WIN_REAL_W (mHoverWindow)
487
/ 2.0f + fww->mRadius);
489
region.extents.y1 = MIN (WIN_REAL_Y (mHoverWindow),
490
WIN_REAL_Y (mHoverWindow)
491
+ WIN_REAL_H (mHoverWindow)
492
/ 2.0f - fww->mRadius);
493
region.extents.y2 = MAX (WIN_REAL_Y (mHoverWindow),
494
WIN_REAL_Y (mHoverWindow)
495
+ WIN_REAL_H (mHoverWindow)
496
/ 2.0f + fww->mRadius);
498
CompRegion damageRegion (region.extents.x1, region.extents.y1, region.extents.x2 - region.extents.x1, region.extents.y2 - region.extents.y1);
500
cScreen->damageRegion (damageRegion);
503
cScreen->donePaint ();
506
/* Damage the Window Rect */
508
FWWindow::damageRect (bool initial,
509
const CompRect &rect)
511
FREEWINS_SCREEN(screen);
517
* Special situations where we must damage the screen
518
* i.e when we are playing with windows and wobbly is
522
if ((mGrab == grabMove && !fws->optionGetImmediateMoves ())
523
|| (mIsAnimating || window->grabbed ()))
524
fws->cScreen->damageScreen ();
526
return cWindow->damageRect (initial, rect);