3
* Compiz KDE compatibility plugin
7
* Copyright : (C) 2007 by Danny Baumann
8
* E-mail : maniac@opencompositing.org
10
* Based on scale.c and switcher.c:
11
* Copyright : (C) 2007 David Reveman
12
* E-mail : davidr@novell.com
14
* This program is free software; you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License
16
* as published by the Free Software Foundation; either version 2
17
* of the License, or (at your option) any later version.
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
26
#include "kdecompat.h"
29
COMPIZ_PLUGIN_20090315 (kdecompat, KDECompatPluginVTable);
32
KDECompatScreen::checkPaintFunctions ()
36
foreach (CompWindow *w, screen->windows ())
38
KDECompatWindow *kcw = KDECompatWindow::get (w);
39
bool wEnabled = (kcw->mPreviews.size () || kcw->mIsPreview ||
41
kcw->mSlideData->remaining > 0.0));
44
kcw->gWindow->glPaintSetEnabled (kcw, wEnabled);
45
kcw->cWindow->damageRectSetEnabled (kcw, wEnabled);
48
KDECOMPAT_SCREEN (screen);
50
gScreen->glPaintOutputSetEnabled (ks, enabled);
51
cScreen->donePaintSetEnabled (ks, enabled);
52
cScreen->preparePaintSetEnabled (ks, enabled);
56
KDECompatWindow::stopCloseAnimation ()
72
KDECompatWindow::sendSlideEvent (bool start)
74
CompOption::Vector o (2);
76
o[0] = CompOption ("window", CompOption::TypeInt);
77
o[0].value ().set ((int) window->id ());
79
o[1] = CompOption ("active", CompOption::TypeBool);
80
o[1].value ().set (start);
82
screen->handleCompizEvent ("kdecompat", "slide", o);
86
KDECompatWindow::startSlideAnimation (bool appearing)
91
KDECOMPAT_SCREEN (screen);
94
mSlideData->duration = ks->optionGetSlideInDuration ();
96
mSlideData->duration = ks->optionGetSlideOutDuration ();
98
if (mSlideData->remaining > mSlideData->duration)
99
mSlideData->remaining = mSlideData->duration;
101
mSlideData->remaining = mSlideData->duration - mSlideData->remaining;
103
mSlideData->appearing = appearing;
104
ks->mHasSlidingPopups = true;
106
ks->checkPaintFunctions ();
108
cWindow->addDamage ();
109
sendSlideEvent (true);
113
KDECompatWindow::endSlideAnimation ()
117
mSlideData->remaining = 0;
118
stopCloseAnimation ();
119
sendSlideEvent (false);
122
KDECompatScreen::get (screen)->checkPaintFunctions ();
126
KDECompatScreen::preparePaint (int msSinceLastPaint)
128
if (mHasSlidingPopups)
130
foreach (CompWindow *w, screen->windows ())
132
KDECOMPAT_WINDOW (w);
137
kw->mSlideData->remaining -= msSinceLastPaint;
139
if (kw->mSlideData->remaining <= 0)
140
kw->endSlideAnimation ();
144
cScreen->preparePaint (msSinceLastPaint);
148
KDECompatScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
149
const GLMatrix &transform,
150
const CompRegion ®ion,
156
if (mHasSlidingPopups)
157
mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
159
status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
165
KDECompatScreen::donePaint ()
167
if (mHasSlidingPopups)
169
mHasSlidingPopups = false;
171
foreach (CompWindow *w, screen->windows ())
173
KDECOMPAT_WINDOW (w);
175
if (kw->mSlideData && kw->mSlideData->remaining)
177
kw->cWindow->addDamage ();
178
mHasSlidingPopups = true;
183
cScreen->donePaint ();
187
KDECompatWindow::glPaint (const GLWindowPaintAttrib &attrib,
188
const GLMatrix &transform,
189
const CompRegion ®ion,
194
KDECOMPAT_SCREEN (screen);
196
if ((!(ks->optionGetPlasmaThumbnails () || mPreviews.empty ()) &&
197
!(mSlideData || mSlideData->remaining)) ||
198
!window->mapNum () ||
199
(mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
201
status = gWindow->glPaint (attrib, transform, region, mask);
205
if (mSlideData && mSlideData->remaining)
207
GLFragment::Attrib fragment (gWindow->paintAttrib ());
208
GLMatrix wTransform = transform;
209
SlideData *data = mSlideData;
210
float xTranslate = 0, yTranslate = 0, remainder;
211
CompRect clipBox (window->x (), window->y (),
212
window->width (), window->height ());
214
if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
217
remainder = (float) data->remaining / data->duration;
218
if (!data->appearing)
219
remainder = 1.0 - remainder;
221
switch (data->position) {
223
xTranslate = (data->start - window->x ()) * remainder;
224
clipBox.setWidth (data->start - clipBox.x ());
227
xTranslate = (data->start - window->width ()) * remainder;
228
clipBox.setX (data->start);
231
yTranslate = (data->start - window->height ()) * remainder;
232
clipBox.setY (data->start);
236
yTranslate = (data->start - window->y ()) * remainder;
237
clipBox.setHeight (data->start - clipBox.y1 ());
241
status = gWindow->glPaint (attrib, transform, region, mask |
242
PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
244
if (window->alpha () || fragment.getOpacity () != OPAQUE)
245
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
247
wTransform.translate (xTranslate, yTranslate, 0.0f);
250
glLoadMatrixf (wTransform.getMatrix ());
252
glPushAttrib (GL_SCISSOR_BIT);
253
glEnable (GL_SCISSOR_TEST);
255
glScissor (clipBox.x1 (), screen->height () - clipBox.y2 (),
256
clipBox.width (), clipBox.height ());
258
status = gWindow->glDraw (wTransform, fragment, region,
259
mask | PAINT_WINDOW_TRANSFORMED_MASK);
261
glDisable (GL_SCISSOR_TEST);
266
foreach (const Thumb& thumb, mPreviews)
268
CompWindow *tw = screen->findWindow (thumb.id);
270
const CompRect &rect = thumb.thumb;
271
unsigned int paintMask = mask | PAINT_WINDOW_TRANSFORMED_MASK;
272
float xScale = 1.0f, yScale = 1.0f, xTranslate, yTranslate;
273
GLTexture *icon = NULL;
278
gtw = GLWindow::get (tw);
280
xTranslate = rect.x () + window->x () - tw->x ();
281
yTranslate = rect.y () + window->y () - tw->y ();
283
if (!gtw->textures ().empty ())
285
unsigned int width, height;
287
width = tw->width () - tw->input ().left + tw->input ().right;
288
height = tw->height () - tw->input ().top + tw->input ().bottom;
290
xScale = (float) rect.width () / width;
291
yScale = (float) rect.height () / height;
293
xTranslate += tw->input ().left * xScale;
294
yTranslate += tw->input ().top * yScale;
298
icon = gWindow->getIcon (256, 256);
300
icon = ks->gScreen->defaultIcon ();
302
if (icon && !icon->name ())
307
GLTexture::MatrixList matrices (1);
309
paintMask |= PAINT_WINDOW_BLEND_MASK;
311
if (icon->width () >= rect.width () ||
312
icon->height () >= rect.height ())
314
xScale = (float) rect.width () / icon->width ();
315
yScale = (float) rect.height () / icon->height ();
323
xTranslate += rect.width () / 2 -
324
(icon->width () * xScale / 2);
325
yTranslate += rect.height () / 2 -
326
(icon->height () * yScale / 2);
328
matrices[0] = icon->matrix ();
329
matrices[0].x0 -= (tw->x () * icon->matrix ().xx);
330
matrices[0].y0 -= (tw->y () * icon->matrix ().yy);
332
gtw->geometry ().reset ();
333
gtw->glAddGeometry (matrices, tw->geometry (), infiniteRegion);
335
if (!gtw->geometry ().vertices)
340
if (!gtw->textures ().empty () || icon)
342
GLFragment::Attrib fragment (attrib);
343
GLMatrix wTransform (transform);
345
if (tw->alpha () || fragment.getOpacity () != OPAQUE)
346
paintMask |= PAINT_WINDOW_TRANSLUCENT_MASK;
348
wTransform.translate (tw->x (), tw->y (), 0.0f);
349
wTransform.scale (xScale, yScale, 1.0f);
350
wTransform.translate (xTranslate / xScale - tw->x (),
351
yTranslate / yScale - tw->y (),
355
glLoadMatrixf (wTransform.getMatrix ());
357
if (!gtw->textures ().empty ())
358
gtw->glDraw (wTransform, fragment,
359
infiniteRegion, paintMask);
361
gtw->glDrawTexture (icon, fragment, paintMask);
368
status = gWindow->glPaint (attrib, transform, region, mask);
374
KDECompatWindow::updatePreviews ()
378
unsigned long n, left;
379
unsigned char *propData;
380
unsigned int oldPreviewsSize;
382
KDECOMPAT_SCREEN (screen);
384
oldPreviewsSize = mPreviews.size ();
388
result = XGetWindowProperty (screen->dpy (), window->id (),
389
ks->mKdePreviewAtom, 0,
390
32768, false, AnyPropertyType, &actual,
391
&format, &n, &left, &propData);
393
if (result == Success && propData)
395
if (format == 32 && actual == ks->mKdePreviewAtom)
397
long *data = (long *) propData;
398
unsigned int nPreview = *data++;
400
if (n == (6 * nPreview + 1))
402
while (mPreviews.size () < nPreview)
410
t.thumb.setX (*data++);
411
t.thumb.setY (*data++);
412
t.thumb.setWidth (*data++);
413
t.thumb.setHeight (*data++);
415
mPreviews.push_back (t);
423
if (oldPreviewsSize != mPreviews.size ())
424
cWindow->damageOutputExtents ();
426
foreach (CompWindow *cw, screen->windows ())
429
KDECompatWindow *kcw = KDECompatWindow::get (cw);
431
kcw->mIsPreview = false;
433
foreach (rw, screen->windows ())
435
KDECompatWindow *krw = KDECompatWindow::get (rw);
437
foreach (const Thumb& t, krw->mPreviews)
439
if (t.id == cw->id ())
441
kcw->mIsPreview = true;
450
ks->checkPaintFunctions ();
455
KDECompatWindow::updateSlidePosition ()
459
unsigned long n, left;
460
unsigned char *propData;
462
KDECOMPAT_SCREEN (screen);
470
result = XGetWindowProperty (screen->dpy (), window->id (),
471
ks->mKdeSlideAtom, 0, 32768, false,
472
AnyPropertyType, &actual, &format, &n,
475
if (result == Success && propData)
477
if (format == 32 && actual == ks->mKdeSlideAtom && n == 2)
479
long *data = (long *) propData;
481
mSlideData = new SlideData;
484
mSlideData->remaining = 0;
485
mSlideData->start = data[0];
486
mSlideData->position = (KDECompatWindow::SlidePosition) data[1];
490
window->windowNotifySetEnabled (this, true);
495
window->windowNotifySetEnabled (this, false);
497
ks->checkPaintFunctions ();
501
KDECompatWindow::handleClose (bool destroy)
503
KDECOMPAT_SCREEN (screen);
505
if (mSlideData && ks->optionGetSlidingPopups ())
510
window->incrementDestroyReference ();
515
window->incrementUnmapReference ();
518
if (mSlideData->appearing || !mSlideData->remaining)
519
startSlideAnimation (false);
524
KDECompatScreen::getScaleAction (const char *name)
526
CompPlugin *p = mScaleHandle;
531
foreach (CompOption &option, p->vTable->getOptions ())
533
if (option.type () == CompOption::TypeAction ||
534
option.type () == CompOption::TypeButton ||
535
option.type () == CompOption::TypeKey)
537
if (option.name () == name)
538
return &option.value ().action ();
546
KDECompatScreen::scaleActivate ()
548
if (mPresentWindow && !mScaleActive)
550
CompOption::Vector options (2);
553
options[0] = CompOption ("root", CompOption::TypeInt);
554
options[0].value ().set ((int) screen->root ());
556
options[1] = CompOption ("match", CompOption::TypeMatch);
557
options[1].value ().set (CompMatch ());
559
CompMatch& windowMatch = options[1].value ().match ();
561
foreach (Window win, mPresentWindowList)
563
std::ostringstream exp;
565
exp << "xid=" << win;
566
windowMatch |= exp.str ();
569
windowMatch.update ();
571
action = getScaleAction ("initiate_all_key");
572
if (action && action->initiate ())
573
action->initiate () (action, 0, options);
580
KDECompatWindow::presentGroup ()
584
unsigned long n, left;
585
unsigned char *propData;
588
KDECOMPAT_SCREEN (screen);
590
if (!ks->optionGetPresentWindows ())
593
if (!ks->mScaleHandle)
595
compLogMessage ("kdecompat", CompLogLevelWarn,
596
"Scale plugin not loaded, present windows "
597
"effect not available!");
601
result = XGetWindowProperty (screen->dpy (), window->id (),
602
ks->mKdePresentGroupAtom, 0,
603
32768, false, AnyPropertyType, &actual,
604
&format, &n, &left, &propData);
606
if (result == Success && propData)
608
if (format == 32 && actual == ks->mKdePresentGroupAtom)
610
long *property = (long *) propData;
612
if (!n || !property[0])
614
CompOption::Vector o (1);
618
o[0] = CompOption ("root", CompOption::TypeInt);
619
o[0].value ().set ((int) screen->root ());
621
action = ks->getScaleAction ("initiate_all_key");
622
if (action && action->terminate ())
623
action->terminate () (action, CompAction::StateCancel, o);
625
ks->mPresentWindow = NULL;
629
/* Activate scale using a timeout - Rationale:
630
* At the time we get the property notify event, Plasma
631
* most likely holds a pointer grab due to the action being
632
* initiated by a button click. As scale also wants to get
633
* a pointer grab, we need to delay the activation a bit so
634
* Plasma can release its grab.
637
ks->mPresentWindow = window;
638
ks->mPresentWindowList.clear ();
640
for (unsigned int i = 0; i < n; i++)
641
ks->mPresentWindowList.push_back (property[i]);
643
ks->mScaleTimeout.setCallback (
644
boost::bind (&KDECompatScreen::scaleActivate, ks));
645
ks->mScaleTimeout.start ();
654
KDECompatScreen::handleCompizEvent (const char *pluginName,
655
const char *eventName,
656
CompOption::Vector options)
659
screen->handleCompizEvent (pluginName, eventName, options);
662
strcmp (pluginName, "scale") == 0 &&
663
strcmp (eventName, "activate") == 0)
665
mScaleActive = CompOption::getBoolOptionNamed (options, "active", false);
666
if (!mScaleActive && mPresentWindow)
667
XDeleteProperty (screen->dpy (), mPresentWindow->id (),
668
mKdePresentGroupAtom);
673
KDECompatWindow::updateBlurProperty (bool enabled)
677
unsigned long n, left;
678
unsigned char *propData;
679
bool validProperty = false;
681
KDECOMPAT_SCREEN (screen);
683
if (!ks->mBlurLoaded || !ks->optionGetWindowBlur ())
688
if (mBlurPropertySet)
689
XDeleteProperty (screen->dpy (), window->id (),
690
KDECompatScreen::get (screen)->mCompizWindowBlurAtom);
695
if (!mBlurPropertySet)
697
result = XGetWindowProperty (screen->dpy (), window->id (),
698
ks->mCompizWindowBlurAtom, 0, 32768,
699
false, AnyPropertyType, &actual,
700
&format, &n, &left, &propData);
702
if (result == Success && propData)
704
/* somebody else besides us already set a property,
705
* don't touch that property
713
result = XGetWindowProperty (screen->dpy (), window->id (),
714
ks->mKdeBlurBehindRegionAtom, 0, 32768,
715
false, AnyPropertyType, &actual, &format,
716
&n, &left, &propData);
718
if (result == Success && propData)
720
if (format == 32 && actual == XA_CARDINAL &&
721
n > 0 && (n % 4 == 0))
723
long *data = (long *) propData;
724
unsigned int nBox = n / 4;
725
long compizProp[nBox * 6 + 2];
728
compizProp[0] = 2; /* threshold */
729
compizProp[1] = 0; /* filter */
739
compizProp[i++] = GRAVITY_NORTH | GRAVITY_WEST; /* P1 gravity */
740
compizProp[i++] = x; /* P1 X */
741
compizProp[i++] = y; /* P1 Y */
742
compizProp[i++] = GRAVITY_NORTH | GRAVITY_WEST; /* P2 gravity */
743
compizProp[i++] = x + w; /* P2 X */
744
compizProp[i++] = y + h; /* P2 Y */
747
XChangeProperty (screen->dpy (), window->id (), ks->mCompizWindowBlurAtom,
748
XA_INTEGER, 32, PropModeReplace,
749
(unsigned char *) compizProp, i);
751
mBlurPropertySet = true;
752
validProperty = TRUE;
758
if (mBlurPropertySet && !validProperty)
760
mBlurPropertySet = FALSE;
761
XDeleteProperty (screen->dpy (), window->id (), ks->mKdeBlurBehindRegionAtom);
766
KDECompatWindow::windowNotify (CompWindowNotify n)
768
if (!KDECompatScreen::get (screen)->optionGetSlidingPopups ())
769
return window->windowNotify (n);
773
case CompWindowNotifyClose:
776
case CompWindowNotifyBeforeDestroy:
779
case CompWindowNotifyBeforeMap:
780
startSlideAnimation (true);
789
KDECompatScreen::handleEvent (XEvent *event)
793
screen->handleEvent (event);
795
switch (event->type) {
797
if (event->xproperty.atom == mKdePreviewAtom)
799
w = screen->findWindow (event->xproperty.window);
801
KDECompatWindow::get (w)->updatePreviews ();
803
else if (event->xproperty.atom == mKdeSlideAtom)
805
w = screen->findWindow (event->xproperty.window);
807
KDECompatWindow::get (w)->updateSlidePosition ();
809
else if (event->xproperty.atom == mKdePresentGroupAtom)
811
w = screen->findWindow (event->xproperty.window);
813
KDECompatWindow::get (w)->presentGroup ();
815
else if (event->xproperty.atom == mKdeBlurBehindRegionAtom)
817
w = screen->findWindow (event->xproperty.window);
819
KDECompatWindow::get (w)->updateBlurProperty (true);
826
KDECompatWindow::damageRect (bool initial,
827
const CompRect &rect)
831
KDECOMPAT_SCREEN (screen);
833
if (mIsPreview && ks->optionGetPlasmaThumbnails ())
835
foreach (CompWindow *cw, screen->windows ())
837
KDECompatWindow *kdw = KDECompatWindow::get (cw);
839
foreach (const Thumb& thumb, kdw->mPreviews)
841
if (thumb.id != window->id ())
844
CompRect rect (thumb.thumb.x () + cw->x (),
845
thumb.thumb.y () + cw->y (),
846
thumb.thumb.width (),
847
thumb.thumb.height ());
849
ks->cScreen->damageRegion (rect);
854
status = cWindow->damageRect (initial, rect);
860
KDECompatScreen::advertiseSupport (Atom atom,
865
unsigned char value = 0;
867
XChangeProperty (screen->dpy (), screen->root (), atom,
868
mKdePreviewAtom, 8, PropModeReplace, &value, 1);
872
XDeleteProperty (screen->dpy (), screen->root (), atom);
877
KDECompatScreen::optionChanged (CompOption *option,
878
KdecompatOptions::Options num)
880
if (num == KdecompatOptions::PlasmaThumbnails)
881
advertiseSupport (mKdePreviewAtom, option->value ().b ());
882
else if (num == KdecompatOptions::SlidingPopups)
883
advertiseSupport (mKdeSlideAtom, option->value (). b ());
884
else if (num == KdecompatOptions::PresentWindows)
885
advertiseSupport (mKdePresentGroupAtom,
886
option->value ().b () && mScaleHandle);
887
else if (num == KdecompatOptions::WindowBlur)
889
advertiseSupport (mKdeBlurBehindRegionAtom,
890
option->value ().b () && mBlurLoaded);
891
foreach (CompWindow *w, screen->windows ())
892
KDECompatWindow::get (w)->updateBlurProperty (option->value ().b ());
897
KDECompatScreen::KDECompatScreen (CompScreen *screen) :
898
PluginClassHandler<KDECompatScreen, CompScreen> (screen),
899
cScreen (CompositeScreen::get (screen)),
900
gScreen (GLScreen::get (screen)),
901
mKdePreviewAtom (XInternAtom (screen->dpy (), "_KDE_WINDOW_PREVIEW", 0)),
902
mKdeSlideAtom (XInternAtom (screen->dpy (), "_KDE_SLIDE", 0)),
903
mKdePresentGroupAtom (XInternAtom (screen->dpy (),
904
"_KDE_PRESENT_WINDOWS_GROUP", 0)),
905
mKdeBlurBehindRegionAtom (XInternAtom (screen->dpy (),
906
"_KDE_NET_WM_BLUR_BEHIND_REGION",
908
mCompizWindowBlurAtom (XInternAtom (screen->dpy (),
909
"_COMPIZ_WM_WINDOW_BLUR", 0)),
910
mHasSlidingPopups (false),
913
mScaleHandle (CompPlugin::find ("scale")),
914
mScaleActive (false),
915
mBlurLoaded ((CompPlugin::find ("blur") != NULL)),
916
mPresentWindow (NULL)
918
ScreenInterface::setHandler (screen);
919
CompositeScreenInterface::setHandler (cScreen, false);
920
GLScreenInterface::setHandler (gScreen, false);
922
mScaleTimeout.setTimes (100, 200);
924
advertiseSupport (mKdePreviewAtom, optionGetPlasmaThumbnails ());
925
advertiseSupport (mKdeSlideAtom, optionGetSlidingPopups ());
926
advertiseSupport (mKdePresentGroupAtom, optionGetPresentWindows () &&
928
optionSetPlasmaThumbnailsNotify (
929
boost::bind (&KDECompatScreen::optionChanged, this, _1, _2));
932
KDECompatScreen::~KDECompatScreen ()
934
advertiseSupport (mKdePreviewAtom, false);
935
advertiseSupport (mKdeSlideAtom, false);
936
advertiseSupport (mKdePresentGroupAtom, false);
939
KDECompatWindow::KDECompatWindow (CompWindow *window) :
940
PluginClassHandler <KDECompatWindow, CompWindow> (window),
942
cWindow (CompositeWindow::get (window)),
943
gWindow (GLWindow::get (window)),
948
mBlurPropertySet (false)
950
WindowInterface::setHandler (window, false);
951
CompositeWindowInterface::setHandler (cWindow, false);
952
GLWindowInterface::setHandler (gWindow, false);
954
updateBlurProperty (KDECompatScreen::get (screen)->optionGetWindowBlur ());
957
KDECompatWindow::~KDECompatWindow ()
959
stopCloseAnimation ();
964
if (KDECompatScreen::get (screen)->mPresentWindow == window)
965
KDECompatScreen::get (screen)->mPresentWindow = NULL;
967
updateBlurProperty (false);
971
KDECompatPluginVTable::init ()
973
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
974
!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
975
!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))