570 lines
14 KiB
C
570 lines
14 KiB
C
/*
|
|
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
|
|
* Copyright (C) 2004-2021 Kim Woelders
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
* and software packages that this Software was used.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <math.h>
|
|
#include <X11/Xlib.h>
|
|
#if USE_XRENDER
|
|
#define FX_USE_RENDER 1
|
|
#include <X11/extensions/Xrender.h>
|
|
#endif
|
|
|
|
#include "E.h"
|
|
#include "animation.h"
|
|
#include "desktops.h"
|
|
#include "dialog.h"
|
|
#include "ecompmgr.h"
|
|
#include "eimage.h"
|
|
#include "emodule.h"
|
|
#include "settings.h"
|
|
#include "util.h"
|
|
#include "xwin.h"
|
|
|
|
#define M_2PI_F ((float)(2 * M_PI))
|
|
|
|
#define FX_OP_ENABLE 1 /* Enable, start */
|
|
#define FX_OP_DISABLE 2 /* Disable, stop */
|
|
#define FX_OP_START 3 /* Start (if enabled) */
|
|
#define FX_OP_PAUSE 4
|
|
#define FX_OP_DESK 5
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
void (*init_func)(const char *name);
|
|
void (*ops_func)(int op);
|
|
char enabled;
|
|
char active;
|
|
} FXHandler;
|
|
|
|
typedef struct {
|
|
Win win;
|
|
EX_Window root;
|
|
EX_Pixmap above;
|
|
int count;
|
|
float incv, inch, incx;
|
|
#if FX_USE_RENDER
|
|
EX_Picture pict_buf;
|
|
EX_Picture pict_win;
|
|
#if USE_COMPOSITE
|
|
EX_Picture pict_win_clip;
|
|
#endif
|
|
#else
|
|
GC gc1;
|
|
#endif
|
|
} FXData;
|
|
|
|
static void
|
|
_FxSetup(FXData *d, unsigned int height)
|
|
{
|
|
EObj *bgeo;
|
|
|
|
if (!d->above)
|
|
{
|
|
bgeo = DeskGetBackgroundObj(DesksGetCurrent());
|
|
|
|
d->win = EobjGetWin(bgeo);
|
|
#if USE_COMPOSITE
|
|
if (ECompMgrIsActive() && !Mode.wm.window)
|
|
d->root = ECompMgrRootWin();
|
|
else
|
|
#endif
|
|
d->root = EobjGetXwin(bgeo);
|
|
d->above = ECreatePixmap(d->win, WinGetW(VROOT), height, 0);
|
|
|
|
#if FX_USE_RENDER
|
|
XRenderPictureAttributes pa;
|
|
|
|
d->pict_buf = EPictureCreate(NULL, d->above);
|
|
d->pict_win = EPictureCreate(NULL, d->root);
|
|
#if USE_COMPOSITE
|
|
d->pict_win_clip = EPictureCreate(NULL, d->root);
|
|
#endif
|
|
pa.subwindow_mode = ClipByChildren;
|
|
XRenderChangePicture(disp, d->pict_win, CPSubwindowMode, &pa);
|
|
#else
|
|
XGCValues xgcv;
|
|
|
|
xgcv.subwindow_mode = ClipByChildren;
|
|
if (!d->gc1)
|
|
d->gc1 = EXCreateGC(d->root, GCSubwindowMode, &xgcv);
|
|
#endif
|
|
}
|
|
|
|
#if USE_COMPOSITE
|
|
#if FX_USE_RENDER
|
|
EPictureSetClip(d->pict_win_clip, ECompMgrChildClipRegion());
|
|
#else
|
|
/* As of composite 0.4 we need to set the clip region */
|
|
EGCSetClip(d->gc1, ECompMgrChildClipRegion());
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
_FxCleanup(FXData *d, int h)
|
|
{
|
|
if (h == 0)
|
|
{
|
|
EFreePixmap(d->above);
|
|
d->above = NoXID;
|
|
d->count = 0;
|
|
}
|
|
else
|
|
{
|
|
#if FX_USE_RENDER
|
|
EPictureDestroy(d->pict_buf);
|
|
EPictureDestroy(d->pict_win);
|
|
#if USE_COMPOSITE
|
|
EPictureDestroy(d->pict_win_clip);
|
|
#endif
|
|
#else
|
|
EXFreeGC(d->gc1);
|
|
#endif
|
|
|
|
EClearArea(d->win, 0, WinGetH(VROOT) - h, WinGetW(VROOT), h);
|
|
#if USE_COMPOSITE
|
|
ECompMgrDamageArea(0, WinGetH(VROOT) - h, WinGetW(VROOT), h);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
_FxCopyArea(FXData *d, int out, int src_x, int src_y, int dst_x, int dst_y,
|
|
unsigned int width, unsigned int height)
|
|
{
|
|
EX_ID src, dst;
|
|
|
|
#if FX_USE_RENDER
|
|
if (out)
|
|
{
|
|
src = d->pict_buf;
|
|
#if USE_COMPOSITE
|
|
dst = d->pict_win_clip;
|
|
#else
|
|
dst = d->pict_win;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
src = d->pict_win;
|
|
dst = d->pict_buf;
|
|
}
|
|
|
|
XRenderComposite(disp, PictOpSrc, src, NoXID, dst,
|
|
src_x, src_y, 0, 0, dst_x, dst_y, width, height);
|
|
#else
|
|
if (out)
|
|
{
|
|
src = d->above;
|
|
dst = d->root;
|
|
|
|
EXCopyAreaGC(src, dst, d->gc1, src_x, src_y, width, height,
|
|
dst_x, dst_y);
|
|
}
|
|
else
|
|
{
|
|
src = d->root;
|
|
dst = d->above;
|
|
|
|
EXCopyArea(src, dst, src_x, src_y, width, height, dst_x, dst_y);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************** RIPPLES *************************************/
|
|
|
|
#define FX_RIPPLE_WATERH 64
|
|
|
|
static Animator *fx_ripple = NULL;
|
|
|
|
static int
|
|
FX_ripple_timeout(EObj *eo __UNUSED__, int run __UNUSED__, void *state)
|
|
{
|
|
FXData *d = (FXData *) state;
|
|
int y;
|
|
|
|
_FxSetup(d, FX_RIPPLE_WATERH * 2);
|
|
|
|
if (d->count == 0)
|
|
_FxCopyArea(d, 0, 0, WinGetH(VROOT) - (FX_RIPPLE_WATERH * 3), 0, 0,
|
|
WinGetW(VROOT), FX_RIPPLE_WATERH * 2);
|
|
|
|
d->count++;
|
|
if (d->count > 32)
|
|
d->count = 0;
|
|
|
|
d->incv += 0.40f;
|
|
if (d->incv > M_2PI_F)
|
|
d->incv = 0;
|
|
d->inch += 0.32f;
|
|
if (d->inch > M_2PI_F)
|
|
d->inch = 0;
|
|
|
|
for (y = 0; y < FX_RIPPLE_WATERH; y++)
|
|
{
|
|
float a, p;
|
|
int xoff, yoff, yy;
|
|
|
|
p = (float)(FX_RIPPLE_WATERH - y) / (float)FX_RIPPLE_WATERH;
|
|
|
|
a = p * p * 48 + d->incv;
|
|
yoff = y + (int)(sinf(a) * 7) + 8; /* 0:63 + -7:7 + 8 = 1:78 */
|
|
yy = (FX_RIPPLE_WATERH * 2) - yoff; /* 128 - 1:78 = 127:50 */
|
|
|
|
a = p * p * 64 + d->inch;
|
|
xoff = (int)(sinf(a) * 10 * (1 - p));
|
|
|
|
_FxCopyArea(d, 1, 0, yy, xoff, WinGetH(VROOT) - FX_RIPPLE_WATERH + y,
|
|
WinGetW(VROOT), 1);
|
|
}
|
|
|
|
return 4;
|
|
}
|
|
|
|
static void
|
|
FX_Ripple_Init(const char *name __UNUSED__)
|
|
{
|
|
FXData fxd;
|
|
|
|
memset(&fxd, 0, sizeof(fxd));
|
|
|
|
fx_ripple = AnimatorAdd(NULL, ANIM_FX_RIPPLES, FX_ripple_timeout, -1, 0,
|
|
sizeof(fxd), &fxd);
|
|
}
|
|
|
|
static void
|
|
FX_Ripple_Ops(int op)
|
|
{
|
|
FXData *d;
|
|
|
|
d = (FXData *) AnimatorGetData(fx_ripple);
|
|
if (!d)
|
|
return;
|
|
|
|
_FxCleanup(d, 0);
|
|
|
|
if (op != FX_OP_DISABLE)
|
|
return;
|
|
|
|
_FxCleanup(d, FX_RIPPLE_WATERH);
|
|
|
|
AnimatorDel(NULL, fx_ripple);
|
|
fx_ripple = NULL;
|
|
}
|
|
|
|
/****************************** WAVES ***************************************/
|
|
/* by tsade :) */
|
|
/****************************************************************************/
|
|
|
|
#define FX_WAVE_WATERH 64
|
|
#define FX_WAVE_WATERW 64
|
|
#define FX_WAVE_DEPTH 10
|
|
#define FX_WAVE_CROSSPERIOD 0.42f
|
|
|
|
static Animator *fx_waves = NULL;
|
|
|
|
static int
|
|
FX_Wave_timeout(EObj *eo __UNUSED__, int run __UNUSED__, void *state)
|
|
{
|
|
FXData *d = (FXData *) state;
|
|
float incx2;
|
|
int y;
|
|
|
|
_FxSetup(d, FX_WAVE_WATERH * 2);
|
|
|
|
/* On the zero, grab the desktop again. */
|
|
if (d->count == 0)
|
|
_FxCopyArea(d, 0, 0, WinGetH(VROOT) - (FX_WAVE_WATERH * 3), 0, 0,
|
|
WinGetW(VROOT), FX_WAVE_WATERH * 2);
|
|
|
|
/* Increment and roll the counter */
|
|
d->count++;
|
|
if (d->count > 32)
|
|
d->count = 0;
|
|
|
|
/* Increment and roll some other variables */
|
|
d->incv += 0.40f;
|
|
if (d->incv > M_2PI_F)
|
|
d->incv = 0;
|
|
|
|
d->inch += 0.32f;
|
|
if (d->inch > M_2PI_F)
|
|
d->inch = 0;
|
|
|
|
d->incx += 0.32f;
|
|
if (d->incx > M_2PI_F)
|
|
d->incx = 0;
|
|
|
|
/* Go through the bottom couple (FX_WAVE_WATERH) lines of the window */
|
|
for (y = 0; y < FX_WAVE_WATERH; y++)
|
|
{
|
|
/* Variables */
|
|
float a, p;
|
|
int xoff, yoff, yy;
|
|
int x;
|
|
|
|
/* Figure out the side-to-side movement */
|
|
p = (float)(FX_WAVE_WATERH - y) / (float)FX_WAVE_WATERH;
|
|
|
|
a = p * p * 48 + d->incv;
|
|
yoff = y + (int)(sinf(a) * 7) + 8; /* 0:63 + -7:7 + 8 = 1:78 */
|
|
yy = (FX_WAVE_WATERH * 2) - yoff; /* 128 - 1:78 = 127:50 */
|
|
|
|
a = p * p * 64 + d->inch;
|
|
xoff = (int)(sinf(a) * 10 * (1 - p));
|
|
|
|
/* Set up the next part */
|
|
incx2 = d->incx;
|
|
|
|
/* Go through the width of the screen, in block sizes */
|
|
for (x = 0; x < WinGetW(VROOT); x += FX_WAVE_WATERW)
|
|
{
|
|
/* Variables */
|
|
int sx;
|
|
|
|
/* Add something to incx2 and roll it */
|
|
incx2 += FX_WAVE_CROSSPERIOD;
|
|
|
|
if (incx2 > M_2PI_F)
|
|
incx2 = 0;
|
|
|
|
/* Figure it out */
|
|
sx = (int)(sinf(incx2) * FX_WAVE_DEPTH);
|
|
|
|
/* Display this block */
|
|
_FxCopyArea(d, 1, x, yy, xoff + x,
|
|
WinGetH(VROOT) - FX_WAVE_WATERH + y + sx,
|
|
FX_WAVE_WATERW, 1);
|
|
}
|
|
}
|
|
|
|
return 4;
|
|
}
|
|
|
|
static void
|
|
FX_Waves_Init(const char *name __UNUSED__)
|
|
{
|
|
FXData fxd;
|
|
|
|
memset(&fxd, 0, sizeof(fxd));
|
|
|
|
fx_waves = AnimatorAdd(NULL, ANIM_FX_WAVES, FX_Wave_timeout, -1, 0,
|
|
sizeof(fxd), &fxd);
|
|
}
|
|
|
|
static void
|
|
FX_Waves_Ops(int op)
|
|
{
|
|
FXData *d;
|
|
|
|
d = (FXData *) AnimatorGetData(fx_waves);
|
|
if (!d)
|
|
return;
|
|
|
|
_FxCleanup(d, 0);
|
|
|
|
if (op != FX_OP_DISABLE)
|
|
return;
|
|
|
|
_FxCleanup(d, 2 * FX_WAVE_WATERH + FX_WAVE_DEPTH);
|
|
|
|
AnimatorDel(NULL, fx_waves);
|
|
fx_waves = NULL;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
#define fx_rip fx_handlers[0]
|
|
#define fx_wav fx_handlers[1]
|
|
|
|
static FXHandler fx_handlers[] = {
|
|
{ "ripples", FX_Ripple_Init, FX_Ripple_Ops, 0, 0 },
|
|
{ "waves", FX_Waves_Init, FX_Waves_Ops, 0, 0 },
|
|
};
|
|
|
|
/****************************** Effect handlers *****************************/
|
|
|
|
static void
|
|
FX_Op(FXHandler *fxh, int op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case FX_OP_ENABLE:
|
|
if (fxh->enabled)
|
|
break;
|
|
fxh->enabled = 1;
|
|
goto do_start;
|
|
|
|
case FX_OP_DISABLE:
|
|
if (!fxh->enabled)
|
|
break;
|
|
fxh->enabled = 0;
|
|
goto do_stop;
|
|
|
|
case FX_OP_START:
|
|
if (!fxh->enabled)
|
|
break;
|
|
do_start:
|
|
if (fxh->active)
|
|
break;
|
|
fxh->init_func(fxh->name);
|
|
fxh->active = 1;
|
|
break;
|
|
|
|
case FX_OP_PAUSE:
|
|
if (!fxh->enabled)
|
|
break;
|
|
do_stop:
|
|
if (!fxh->active)
|
|
break;
|
|
fxh->ops_func(FX_OP_DISABLE);
|
|
fxh->active = 0;
|
|
break;
|
|
|
|
case FX_OP_DESK:
|
|
if (!fxh->enabled)
|
|
break;
|
|
fxh->ops_func(FX_OP_DESK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
FX_OpForEach(int op)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < E_ARRAY_SIZE(fx_handlers); i++)
|
|
FX_Op(&fx_handlers[i], op);
|
|
}
|
|
|
|
static void
|
|
FxCfgFunc(void *item __UNUSED__, const char *value)
|
|
{
|
|
FXHandler *fxh = NULL;
|
|
|
|
if (item == &fx_rip.enabled)
|
|
fxh = &fx_rip;
|
|
else if (item == &fx_wav.enabled)
|
|
fxh = &fx_wav;
|
|
if (!fxh)
|
|
return;
|
|
|
|
FX_Op(fxh, atoi(value) ? FX_OP_ENABLE : FX_OP_DISABLE);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* Fx Module
|
|
*/
|
|
|
|
static void
|
|
FxSighan(int sig, void *prm __UNUSED__)
|
|
{
|
|
switch (sig)
|
|
{
|
|
case ESIGNAL_START:
|
|
FX_OpForEach(FX_OP_START);
|
|
break;
|
|
case ESIGNAL_DESK_SWITCH_START:
|
|
break;
|
|
case ESIGNAL_DESK_SWITCH_DONE:
|
|
FX_OpForEach(FX_OP_DESK);
|
|
break;
|
|
case ESIGNAL_ANIMATION_SUSPEND:
|
|
FX_OpForEach(FX_OP_PAUSE);
|
|
break;
|
|
case ESIGNAL_ANIMATION_RESUME:
|
|
FX_OpForEach(FX_OP_START);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if ENABLE_DIALOGS
|
|
static char tmp_effect_ripples;
|
|
static char tmp_effect_waves;
|
|
|
|
static void
|
|
_DlgApplyFx(Dialog *d __UNUSED__, int val __UNUSED__, void *data __UNUSED__)
|
|
{
|
|
FX_Op(&fx_rip, tmp_effect_ripples ? FX_OP_ENABLE : FX_OP_DISABLE);
|
|
FX_Op(&fx_wav, tmp_effect_waves ? FX_OP_ENABLE : FX_OP_DISABLE);
|
|
|
|
autosave();
|
|
}
|
|
|
|
static void
|
|
_DlgFillFx(Dialog *d __UNUSED__, DItem *table, void *data __UNUSED__)
|
|
{
|
|
DItem *di;
|
|
|
|
tmp_effect_ripples = fx_rip.enabled;
|
|
tmp_effect_waves = fx_wav.enabled;
|
|
|
|
DialogItemTableSetOptions(table, 1, 0, 0, 0);
|
|
|
|
/* Effects */
|
|
di = DialogAddItem(table, DITEM_TEXT);
|
|
DialogItemSetText(di, _("Effects"));
|
|
di = DialogAddItem(table, DITEM_CHECKBUTTON);
|
|
DialogItemSetText(di, _("Ripples"));
|
|
DialogItemCheckButtonSetPtr(di, &tmp_effect_ripples);
|
|
di = DialogAddItem(table, DITEM_CHECKBUTTON);
|
|
DialogItemSetText(di, _("Waves"));
|
|
DialogItemCheckButtonSetPtr(di, &tmp_effect_waves);
|
|
}
|
|
|
|
const DialogDef DlgFx = {
|
|
"CONFIGURE_FX",
|
|
N_("FX"), N_("Special FX Settings"),
|
|
0,
|
|
SOUND_SETTINGS_FX,
|
|
"pix/fx.png",
|
|
N_("Enlightenment Special Effects\n" "Settings Dialog"),
|
|
_DlgFillFx,
|
|
DLG_OAC, _DlgApplyFx, NULL
|
|
};
|
|
#endif /* ENABLE_DIALOGS */
|
|
|
|
#define CFR_FUNC_BOOL(conf, name, dflt, func) \
|
|
{ #name, &conf, ITEM_TYPE_BOOL, dflt, func }
|
|
|
|
static const CfgItem FxCfgItems[] = {
|
|
CFR_FUNC_BOOL(fx_handlers[0].enabled, ripples.enabled, 0, FxCfgFunc),
|
|
CFR_FUNC_BOOL(fx_handlers[1].enabled, waves.enabled, 0, FxCfgFunc),
|
|
};
|
|
|
|
/*
|
|
* Module descriptor
|
|
*/
|
|
extern const EModule ModEffects;
|
|
|
|
const EModule ModEffects = {
|
|
"effects", "fx",
|
|
FxSighan,
|
|
{ 0, NULL },
|
|
MOD_ITEMS(FxCfgItems)
|
|
};
|