You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/twin/kompmgr/kompmgr.c

3953 lines
98 KiB

/*
* $Id$
*
* Copyright © 2003 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* Modified by Matthew Hawn. I don't know what to say here so follow what it
says above. Not that I can really do anything about it
*/
/* Modified by Dan Doel*/
/* Modified by Timothy Pearson
*
* CHANGELOG:
* http://patchwork.freedesktop.org/patch/1049/ [Add default background color option] 08/11/2011
* http://patchwork.freedesktop.org/patch/1052/ [Prevent flicker on root pixmap change] 08/11/2011
* Added SIGUSR1 handler to change process UID [Prevent flicker on login] 08/12/2011
* Added ability to write PID of process to home directory 08/14/2011
* Added SIGUSR2 handler to reload settings [Prevent flicker on settings change] 08/14/2011
* Added SIGTERM handler to clean up stale PID files on exit 08/14/2011
* Added hack to work around ATI fglrx XDamage event generation bugs [WORK_AROUND_FGLRX] 09/01/2011
* Redraw root window automatically when X damage events are detected (this fixes xsetroot) 10/23/2011
*
* TODO:
* http://patchwork.freedesktop.org/patch/1053/ [Fix window mapping with re-used window ids]
*/
/*
Version 2.x of xcompmgr, kompmgr changes by Thomas L<EFBFBD>bking and Heiko Przybyl
check baghira.sf.net for more infos
*/
#define _VERSION_ 2.02
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/shape.h>
#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
#define HAS_NAME_WINDOW_PIXMAP 1
#endif
#define CAN_DO_USABLE 1
#define WORK_AROUND_FGLRX 1
#define _TOPHEIGHT_(x) ((x >> 24) & 0xff)
#define _RIGHTWIDTH_(x) ((x >> 16) & 0xff)
#define _BOTTOMHEIGHT_(x) ((x >> 8) & 0xff)
#define _LEFTWIDTH_(x) (x & 0xff)
/* #define USE_ENV_HOME 1 */
#define WRITE_PID_FILE 1
#ifndef USE_ENV_HOME
#include <pwd.h>
#endif
typedef enum {
WINTYPE_DESKTOP,
WINTYPE_DOCK,
WINTYPE_TOOLBAR,
WINTYPE_MENU,
WINTYPE_UTILITY,
WINTYPE_SPLASH,
WINTYPE_DIALOG,
WINTYPE_NORMAL,
WINTYPE_DROPDOWN_MENU,
WINTYPE_POPUP_MENU,
WINTYPE_TOOLTIP,
WINTYPE_NOTIFY,
WINTYPE_COMBO,
WINTYPE_DND,
NUM_WINTYPES
} wintype;
typedef struct _ignore {
struct _ignore *next;
unsigned long sequence;
} ignore;
typedef struct _win {
struct _win *next;
Window id;
#if HAS_NAME_WINDOW_PIXMAP
Pixmap pixmap;
#endif
XWindowAttributes a;
XWindowAttributes a_prev;
#if CAN_DO_USABLE
Bool usable; /* mapped and all damaged at one point */
XRectangle damage_bounds; /* bounds of damage */
#endif
Bool isInFade;
int mode;
int damaged;
Damage damage;
Picture picture;
Picture alphaPict;
Picture shadowPict;
XserverRegion borderSize;
XserverRegion decoRegion;
XserverRegion contentRegion;
XserverRegion extents;
unsigned int preShadeOpacity;
Picture shadow;
/*Picture alpha;*/
int shadow_dx;
int shadow_dy;
int shadow_width;
int shadow_height;
unsigned int opacity;
unsigned int shadowSize;
wintype windowType;
unsigned long damage_sequence; /* sequence when damage was created */
int destroyed;
Bool destruct_queued;
Bool destruct_requested;
int destruct_request_time;
Bool shapable; /* this will allow window managers to exclude windows if just the deco is shaped*/
Bool shaped;
XRectangle shape_bounds;
XRectangle shape_bounds_prev;
unsigned int decoHash;
Picture dimPicture;
/* for drawing translucent windows */
XserverRegion borderClip;
struct _win *prev_trans;
/* setting whether a window will be transparent to the desktop or the windows below it */
Bool show_root_tile;
/* setting whether a window will be transparent to a black background or something else */
Bool show_black_background;
} win;
typedef struct _conv {
int size;
double *data;
} conv;
typedef struct _fade {
struct _fade *next;
win *w;
double cur;
double finish;
double step;
void (*callback) (Display *dpy, win *w, Bool gone);
Display *dpy;
unsigned int decoHash;
Bool gone;
} fade;
struct sigaction usr_action;
sigset_t block_mask;
int my_exit_code = 3;
win *list;
fade *fades;
Display *dpy;
char *display = 0;
int scr;
Window root;
Picture rootPicture;
Picture rootBuffer;
Picture blackPicture;
Picture transBlackPicture;
Picture rootTile;
XserverRegion allDamage;
Bool clipChanged;
#if HAS_NAME_WINDOW_PIXMAP
Bool hasNamePixmap;
#endif
XRenderColor fill_color;
int root_height, root_width;
ignore *ignore_head, **ignore_tail = &ignore_head;
int xfixes_event, xfixes_error;
int damage_event, damage_error;
int composite_event, composite_error;
int render_event, render_error;
int xshape_event, xshape_error;
Bool synchronize;
int composite_opcode;
Bool screen_damaged = False;
Bool disable_argb = False;
int shapeEvent;
/* find these once and be done with it */
Atom opacityAtom;
Atom shadowAtom;
Atom shadeAtom;
Atom shapableAtom;
Atom decoHashAtom;
Atom dimAtom;
Atom deskChangeAtom;
Atom winTypeAtom;
Atom winTDETTDAtom;
Atom winTDETTBAtom;
Atom winType[NUM_WINTYPES];
double winTypeOpacity[NUM_WINTYPES];
Bool winTypeShadow[NUM_WINTYPES];
Bool winTypeFade[NUM_WINTYPES];
/* opacity property name; sometime soon I'll write up an EWMH spec for it */
#define OPACITY_PROP "_KDE_WM_WINDOW_OPACITY"
#define SHADOW_PROP "_KDE_WM_WINDOW_SHADOW"
#define SHADE_PROP "_KDE_WM_WINDOW_SHADE"
#define SHAPABLE_PROP "_KDE_WM_WINDOW_SHAPABLE"
#define DECOHASH_PROP "_KDE_WM_WINDOW_DECOHASH"
#define DIM_PROP "_KDE_WM_WINDOW_DIM"
#define DESKCHANGE_PROP "_KDE_WM_DESKTOP_CHANGE"
#define TRANSLUCENT 0xe0000000
#define OPAQUE 0xffffffff
conv *gaussianMap;
#define WINDOW_SOLID 0
#define WINDOW_TRANS 1
#define WINDOW_ARGB 2
#define TRANS_OPACITY 0.75
#define NDEBUG 1
#define DEBUG_WINDWS 0
#define DEBUG_REPAINT 0
#define DEBUG_WINDOWS 0
#define DEBUG_EVENTS 0
#define MONITOR_REPAINT 0
#define SHADOWS 1
#define SHARP_SHADOW 0
typedef enum _compMode {
CompSimple, /* looks like a regular X server */
CompServerShadows, /* use window alpha for shadow; sharp, but precise */
CompClientShadows /* use window extents for shadow, blurred */
} CompMode;
static void
determine_mode(Display *dpy, win *w);
static double
get_opacity_percent(Display *dpy, win *w);
static XserverRegion
win_extents (Display *dpy, win *w);
static void
presum_gaussian (conv *map);
static conv *
make_gaussian_map (Display *dpy, double r);
Picture
solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b);
CompMode compMode = CompSimple;
int shadowRadius = 12;
int shadowOffsetX = 0;
int shadowOffsetY = 0;
double shadowOpacity = .75;
XRenderColor shadowColor;
double fade_in_step = 0.028;
double fade_out_step = 0.03;
int fade_delta = 10;
int fade_time = 0;
Bool fadeTrans = False;
Bool autoRedirect = False;
#if WORK_AROUND_FGLRX
Bool restartOnSigterm = True;
#endif
/* For shadow precomputation */
int Gsize = -1;
unsigned char *shadowCorner = NULL;
unsigned char *shadowTop = NULL;
XRenderPictFormat* sXRenderFindVisualFormat(Display *dpy, _Xconst Visual *visual)
{
XRenderPictFormat* format = XRenderFindVisualFormat(dpy,visual);
if (format)
return format;
else
return XRenderFindStandardFormat (dpy, PictStandardRGB24);
}
int
get_time_in_milliseconds ()
{
struct timeval tv;
gettimeofday (&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
void write_pid_file(pid_t pid)
{
#ifdef WRITE_PID_FILE
#ifdef USE_ENV_HOME
const char *home = getenv("HOME");
#else
const char *home;
struct passwd *p;
p = getpwuid(getuid());
if (p)
home = p->pw_dir;
else
home = getenv("HOME");
#endif
const char *filename;
const char *configfile = "/.kompmgr.pid";
int n = strlen(home)+strlen(configfile)+1;
filename = (char*)malloc(n*sizeof(char));
memset(filename,0,n);
strcat(filename, home);
strcat(filename, configfile);
printf("writing '%s' as pidfile\n\n", filename);
/* now that we did all that by way of introduction...write the file! */
FILE *pFile;
char buffer[255];
sprintf(buffer, "%d", pid);
pFile = fopen(filename, "w");
if (pFile) {
fwrite(buffer,1,strlen(buffer), pFile);
fclose(pFile);
}
free(filename);
filename = NULL;
#endif
}
void delete_pid_file()
{
#ifdef WRITE_PID_FILE
#ifdef USE_ENV_HOME
const char *home = getenv("HOME");
#else
const char *home;
struct passwd *p;
p = getpwuid(getuid());
if (p)
home = p->pw_dir;
else
home = getenv("HOME");
#endif
const char *filename;
const char *configfile = "/.kompmgr.pid";
int n = strlen(home)+strlen(configfile)+1;
filename = (char*)malloc(n*sizeof(char));
memset(filename,0,n);
strcat(filename, home);
strcat(filename, configfile);
printf("deleting '%s' as pidfile\n\n", filename);
/* now that we did all that by way of introduction...delete the file! */
unlink(filename);
free(filename);
filename = NULL;
#endif
#if WORK_AROUND_FGLRX
if ((my_exit_code == 3) && (restartOnSigterm)) {
printf("kompmgr lost connection to X server, restarting...\n"); fflush(stdout);
sleep(1);
char me[2048];
int chars = readlink("/proc/self/exe", me, sizeof(me));
me[chars] = 0;
me[2047] = 0;
execl(me, basename(me), (char*)NULL);
}
#endif
}
void clear_shadow_cache()
{
win *w;
for (w = list; w; w = w->next) {
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
if (w->opacity != OPAQUE && !w->alphaPict)
w->alphaPict = solid_picture (dpy, False,
(double) w->opacity / OPAQUE, shadowColor.red, shadowColor.green, shadowColor.blue);
if( w->extents != None ) {
XFixesDestroyRegion( dpy, w->extents );
}
w->extents = win_extents (dpy, w);
w->damaged = 1; /* redraw */
}
}
}
void handle_siguser (int sig)
{
int uidnum;
if (sig == SIGTERM) {
my_exit_code=0;
delete_pid_file();
exit(0);
}
if (sig == SIGUSR1) {
char newuid[1024];
#ifndef NDEBUG
printf("Enter the new user ID:\n"); fflush(stdout);
#endif
char *eof;
newuid[0] = '\0';
newuid[sizeof(newuid)-1] = '\0';
eof = fgets(newuid, sizeof(newuid), stdin);
uidnum = atoi(newuid);
#ifndef NDEBUG
printf("Setting kompmgr process uid to %d...\n", uidnum); fflush(stdout);
#endif
my_exit_code=4;
delete_pid_file();
my_exit_code=3;
setuid(uidnum);
write_pid_file(getpid());
}
else {
uidnum = getuid();
}
if ((sig == SIGUSR1) || (sig == SIGUSR2)) {
#ifdef USE_ENV_HOME
const char *home = getenv("HOME");
#else
const char *home;
struct passwd *p;
p = getpwuid(uidnum);
if (p)
home = p->pw_dir;
else
home = getenv("HOME");
#endif
const char *filename;
const char *configfile = "/.xcompmgrrc";
int n = strlen(home)+strlen(configfile)+1;
filename = (char*)malloc(n*sizeof(char));
memset(filename,0,n);
strcat(filename, home);
strcat(filename, configfile);
loadConfig(filename); /* reload the configuration file */
/* set background/shadow picture using the new settings */
blackPicture = solid_picture (dpy, True, 1, (double)(shadowColor.red)/0xff, (double)(shadowColor.green)/0xff, (double)(shadowColor.blue)/0xff);
if (compMode == CompServerShadows)
transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
/* regenerate shadows using the new settings */
if (compMode == CompClientShadows)
{
gaussianMap = make_gaussian_map(dpy, shadowRadius);
presum_gaussian (gaussianMap);
}
clear_shadow_cache();
free(filename);
filename = NULL;
}
}
fade *
find_fade (win *w)
{
fade *f;
for (f = fades; f; f = f->next)
{
if (f->w == w)
return f;
}
return 0;
}
void dequeue_fade (Display *dpy, fade *f)
{
fade **prev;
f->w->isInFade = False;
f->w->decoHash = f->decoHash;
for (prev = &fades; *prev; prev = &(*prev)->next)
if (*prev == f)
{
*prev = f->next;
if (f->callback)
{
(*f->callback) (dpy, f->w, f->gone);
}
free (f);
break;
}
}
void
cleanup_fade (Display *dpy, win *w)
{
fade *f = find_fade (w);
if (f)
dequeue_fade (dpy, f);
}
void
enqueue_fade (Display *dpy, fade *f)
{
f->w->isInFade = True;
if (!fades)
fade_time = get_time_in_milliseconds () + fade_delta;
f->next = fades;
fades = f;
}
static void unmap_callback (Display *dpy, win *w, Bool gone);
static void
set_fade (Display *dpy, win *w, double start, double finish, double step,
void (*callback) (Display *dpy, win *w, Bool gone),
Bool gone, Bool exec_callback, Bool override, Bool wholeWin)
{
fade *f;
f = find_fade (w);
if (!f)
{
if (start == finish)
return;
f = malloc (sizeof (fade));
f->next = 0;
f->w = w;
f->decoHash = w->decoHash;
f->cur = start;
enqueue_fade (dpy, f);
}
else if(!override)
return;
else
{
if (exec_callback && f->callback)
(*f->callback)(dpy, f->w, f->gone);
}
if (finish < 0)
finish = 0;
if (finish > 1)
finish = 1;
f->finish = finish;
if (f->cur < finish)
f->step = step;
else if (f->cur > finish)
f->step = -step;
f->gone = gone && (exec_callback || f->callback != unmap_callback);
f->callback = callback;
w->opacity = f->cur * OPAQUE;
if (wholeWin)
w->decoHash = 0;
#if 0
printf ("set_fade start %g step %g\n", f->cur, f->step);
#endif
determine_mode (dpy, w);
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
if( w->extents != None )
XFixesDestroyRegion( dpy, w->extents );
w->extents = win_extents (dpy, w);
}
/* fading windows need to be drawn, mark them as damaged.
when a window maps, if it tries to fade in but it already at the right
opacity (map/unmap/map fast) then it will never get drawn without this
until it repaints */
w->damaged = 1;
}
int
fade_timeout (void)
{
int now;
int delta;
if (!fades)
return -1;
now = get_time_in_milliseconds();
delta = fade_time - now;
if (delta < 0)
delta = 0;
/* printf ("timeout %d\n", delta); */
return delta;
}
void
run_fades (Display *dpy)
{
int now = get_time_in_milliseconds();
fade *f, *next;
int steps;
Bool need_dequeue;
#if 0
printf ("run fades\n");
#endif
if (fade_time - now > 0)
return;
steps = 1 + (now - fade_time) / fade_delta;
for (next = fades; (f = next); )
{
win *w = f->w;
next = f->next;
f->cur += f->step * steps;
if (f->cur >= 1)
f->cur = 1;
else if (f->cur < 0)
f->cur = 0;
#if 0
printf ("opacity now %g -> %g\n", f->cur, f->finish);
#endif
w->opacity = f->cur * OPAQUE;
need_dequeue = False;
if (f->step > 0)
{
if (f->cur >= f->finish)
{
w->opacity = f->finish*OPAQUE;
need_dequeue = True;
}
}
else
{
if (f->cur <= f->finish)
{
w->opacity = f->finish*OPAQUE;
need_dequeue = True;
}
}
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
if( w->extents != None )
XFixesDestroyRegion( dpy, w->extents );
w->extents = win_extents(dpy, w);
}
determine_mode (dpy, w);
/* Must do this last as it might destroy f->w in callbacks */
if (need_dequeue)
dequeue_fade (dpy, f);
}
fade_time = now + fade_delta;
}
#define SHADOW_OFFSET_X ((-shadowRadius * 7 / 5) - shadowOffsetX * shadowRadius / 100) * w->shadowSize
#define SHADOW_OFFSET_Y ((-shadowRadius * 7 / 5) - shadowOffsetY * shadowRadius / 100) * w->shadowSize
/*#define SHADOW_OFFSET_X (w->shadowSize * -shadowRadius * 7 / 500) - w->shadowSize * shadowOffsetX * shadowRadius / 10000
#define SHADOW_OFFSET_Y (w->shadowSize * -shadowRadius * 7 / 500) - w->shadowSize * shadowOffsetY * shadowRadius / 10000*/
static double
gaussian (double r, double x, double y)
{
return ((1 / (sqrt (2 * M_PI * r))) *
exp ((- (x * x + y * y)) / (2 * r * r)));
}
static conv *
make_gaussian_map (Display *dpy, double r)
{
conv *c;
int size = ((int) ceil ((r * 3)) + 1) & ~1;
int center = size / 2;
int x, y;
double t;
double g;
c = malloc (sizeof (conv) + size * size * sizeof (double));
c->size = size;
c->data = (double *) (c + 1);
t = 0.0;
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
{
g = gaussian (r, (double) (x - center), (double) (y - center));
t += g;
c->data[y * size + x] = g;
}
/* printf ("gaussian total %f\n", t); */
for (y = 0; y < size; y++)
for (x = 0; x < size; x++)
{
c->data[y*size + x] /= t;
}
return c;
}
/*
* A picture will help
*
* -center 0 width width+center
* -center +-----+-------------------+-----+
* | | | |
* | | | |
* 0 +-----+-------------------+-----+
* | | | |
* | | | |
* | | | |
* height +-----+-------------------+-----+
* | | | |
* height+ | | | |
* center +-----+-------------------+-----+
*/
static unsigned char
sum_gaussian (conv *map, double opacity, int x, int y, int width, int height)
{
int fx, fy;
double *g_data;
double *g_line = map->data;
int g_size = map->size;
int center = g_size / 2;
int fx_start, fx_end;
int fy_start, fy_end;
double v;
/*
* Compute set of filter values which are "in range",
* that's the set with:
* 0 <= x + (fx-center) && x + (fx-center) < width &&
* 0 <= y + (fy-center) && y + (fy-center) < height
*
* 0 <= x + (fx - center) x + fx - center < width
* center - x <= fx fx < width + center - x
*/
fx_start = center - x;
if (fx_start < 0)
fx_start = 0;
fx_end = width + center - x;
if (fx_end > g_size)
fx_end = g_size;
fy_start = center - y;
if (fy_start < 0)
fy_start = 0;
fy_end = height + center - y;
if (fy_end > g_size)
fy_end = g_size;
g_line = g_line + fy_start * g_size + fx_start;
v = 0;
for (fy = fy_start; fy < fy_end; fy++)
{
g_data = g_line;
g_line += g_size;
for (fx = fx_start; fx < fx_end; fx++)
v += *g_data++;
}
if (v > 1)
v = 1;
return ((unsigned char) (v * opacity * 255.0));
}
/* precompute shadow corners and sides to save time for large windows */
static void
presum_gaussian (conv *map)
{
int center = map->size/2;
int opacity, x, y;
Gsize = map->size;
if (shadowCorner)
free ((void *)shadowCorner);
if (shadowTop)
free ((void *)shadowTop);
shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26));
shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26));
for (x = 0; x <= Gsize; x++)
{
shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2);
for(opacity = 0; opacity < 25; opacity++)
shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25;
for(y = 0; y <= x; y++)
{
shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
= sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2);
shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
= shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
for(opacity = 0; opacity < 25; opacity++)
shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]
= shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y]
= shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25;
}
}
}
static XImage *
make_shadow (Display *dpy, double opacity, int width, int height)
{
XImage *ximage;
unsigned char *data;
int gsize = gaussianMap->size;
int ylimit, xlimit;
int swidth = width + gsize;
int sheight = height + gsize;
int center = gsize / 2;
int x, y;
unsigned char d;
int x_diff;
int opacity_int = (int)(opacity * 25);
data = malloc (swidth * sheight * sizeof (unsigned char));
if (!data)
return 0;
ximage = XCreateImage (dpy,
DefaultVisual(dpy, DefaultScreen(dpy)),
8,
ZPixmap,
0,
(char *) data,
swidth, sheight, 8, swidth * sizeof (unsigned char));
if (!ximage)
{
free (data);
return 0;
}
/*
* Build the gaussian in sections
*/
/*
* center (fill the complete data array)
*/
if (Gsize > 0)
d = shadowTop[opacity_int * (Gsize + 1) + Gsize];
else
d = sum_gaussian (gaussianMap, opacity, center, center, width, height);
memset(data, d, sheight * swidth);
/*
* corners
*/
ylimit = gsize;
if (ylimit > sheight / 2)
ylimit = (sheight + 1) / 2;
xlimit = gsize;
if (xlimit > swidth / 2)
xlimit = (swidth + 1) / 2;
for (y = 0; y < ylimit; y++)
for (x = 0; x < xlimit; x++)
{
if (xlimit == Gsize && ylimit == Gsize)
d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x];
else
d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height);
data[y * swidth + x] = d;
data[(sheight - y - 1) * swidth + x] = d;
data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
data[y * swidth + (swidth - x - 1)] = d;
}
/*
* top/bottom
*/
x_diff = swidth - (gsize * 2);
if (x_diff > 0 && ylimit > 0)
{
for (y = 0; y < ylimit; y++)
{
if (ylimit == Gsize)
d = shadowTop[opacity_int * (Gsize + 1) + y];
else
d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height);
memset (&data[y * swidth + gsize], d, x_diff);
memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff);
}
}
/*
* sides
*/
for (x = 0; x < xlimit; x++)
{
if (xlimit == Gsize)
d = shadowTop[opacity_int * (Gsize + 1) + x];
else
d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height);
for (y = gsize; y < sheight - gsize; y++)
{
data[y * swidth + x] = d;
data[y * swidth + (swidth - x - 1)] = d;
}
}
return ximage;
}
static Picture
shadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp)
{
XImage *shadowImage;
Pixmap shadowPixmap;
Pixmap finalPixmap;
Picture shadowPicture;
Picture finalPicture;
GC gc;
shadowImage = make_shadow (dpy, opacity, width, height);
if (!shadowImage)
return None;
shadowPixmap = XCreatePixmap (dpy, root,
shadowImage->width,
shadowImage->height,
8);
if (!shadowPixmap)
{
XDestroyImage (shadowImage);
return None;
}
shadowPicture = XRenderCreatePicture (dpy, shadowPixmap,
XRenderFindStandardFormat (dpy, PictStandardA8),
0, 0);
if (!shadowPicture)
{
XDestroyImage (shadowImage);
XFreePixmap (dpy, shadowPixmap);
return None;
}
gc = XCreateGC (dpy, shadowPixmap, 0, 0);
if (!gc)
{
XDestroyImage (shadowImage);
XFreePixmap (dpy, shadowPixmap);
XRenderFreePicture (dpy, shadowPicture);
return None;
}
XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
shadowImage->width,
shadowImage->height);
*wp = shadowImage->width;
*hp = shadowImage->height;
XFreeGC (dpy, gc);
XDestroyImage (shadowImage);
XFreePixmap (dpy, shadowPixmap);
return shadowPicture;
}
Picture
solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b)
{
Pixmap pixmap;
Picture picture;
XRenderPictureAttributes pa;
XRenderColor c;
pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8);
if (!pixmap)
return None;
pa.repeat = True;
picture = XRenderCreatePicture (dpy, pixmap,
XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8),
CPRepeat,
&pa);
if (!picture)
{
XFreePixmap (dpy, pixmap);
return None;
}
c.alpha = a * 0xffff;
c.red = r * 0xffff;
c.green = g * 0xffff;
c.blue = b * 0xffff;
XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
XFreePixmap (dpy, pixmap);
return picture;
}
void
discard_ignore (Display *dpy, unsigned long sequence)
{
while (ignore_head)
{
if ((long) (sequence - ignore_head->sequence) > 0)
{
ignore *next = ignore_head->next;
free (ignore_head);
ignore_head = next;
if (!ignore_head)
ignore_tail = &ignore_head;
}
else
break;
}
}
void
set_ignore (Display *dpy, unsigned long sequence)
{
ignore *i = malloc (sizeof (ignore));
if (!i) {
return;
}
i->sequence = sequence;
i->next = 0;
*ignore_tail = i;
ignore_tail = &i->next;
}
int
should_ignore (Display *dpy, unsigned long sequence)
{
discard_ignore (dpy, sequence);
return ignore_head && ignore_head->sequence == sequence;
}
static win *
find_win (Display *dpy, Window id)
{
win *w;
for (w = list; w; w = w->next) {
if ((!w->destroyed) && (w->id == id)) {
return w;
}
}
return 0;
}
static char *backgroundProps[] = {
"_XROOTPMAP_ID",
"_XSETROOT_ID",
0,
};
static Bool
determine_window_transparent_to_black(Display *dpy, Window w);
static Bool
determine_window_transparent_to_desktop(Display *dpy, Window w);
static Picture
root_tile (Display *dpy)
{
Picture picture;
Atom actual_type;
Pixmap pixmap;
int actual_format;
unsigned long nitems;
unsigned long bytes_after;
unsigned char *prop;
Bool fill;
XRenderPictureAttributes pa;
int p;
pixmap = None;
for (p = 0; backgroundProps[p]; p++)
{
if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False),
0, 4, False, AnyPropertyType,
&actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success &&
actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1)
{
pixmap = *(long*)prop;
XFree (prop);
fill = False;
break;
}
}
if (!pixmap)
{
pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr));
fill = True;
}
pa.repeat = True;
picture = XRenderCreatePicture (dpy, pixmap,
sXRenderFindVisualFormat (dpy,
DefaultVisual (dpy, scr)),
CPRepeat, &pa);
if (fill)
{
XRenderFillRectangle (dpy, PictOpSrc, picture, &fill_color,
0, 0, 1, 1);
}
return picture;
}
static void
paint_root (Display *dpy)
{
if (!rootTile)
rootTile = root_tile (dpy);
XRenderComposite (dpy, PictOpSrc,
rootTile, None, rootBuffer,
0, 0, 0, 0, 0, 0, root_width, root_height);
}
static XserverRegion
win_extents (Display *dpy, win *w)
{
XRectangle r;
r.x = w->a.x;
r.y = w->a.y;
r.width = w->a.width + w->a.border_width * 2;
r.height = w->a.height + w->a.border_width * 2;
if (winTypeShadow[w->windowType])
{
if (compMode == CompServerShadows || w->mode != WINDOW_ARGB)
{
XRectangle sr;
if (compMode == CompServerShadows)
{
w->shadow_dx = 2;
w->shadow_dy = 7;
w->shadow_width = w->a.width;
w->shadow_height = w->a.height;
}
else
{
w->shadow_dx = SHADOW_OFFSET_X;
w->shadow_dx = w->shadow_dx / 100;
w->shadow_dy = SHADOW_OFFSET_Y;
w->shadow_dy = w->shadow_dy / 100;
if (!w->shadow)
{
double opacity = shadowOpacity;
if (w->shadowSize > 100)
opacity = opacity/(w->shadowSize*0.015);
if (w->mode == WINDOW_TRANS)
opacity = opacity * ((double)w->opacity)/((double)OPAQUE);
w->shadow = shadow_picture (dpy, opacity, w->alphaPict,
w->a.width + w->a.border_width * 2 - 2*(shadowRadius - (w->shadowSize*shadowRadius/100)) ,
w->a.height + w->a.border_width * 2 - 2*(shadowRadius - (w->shadowSize*shadowRadius/100)),
&w->shadow_width, &w->shadow_height);
/*int kill;
w->alpha = shadow_picture (dpy, 0.9, w->alphaPict,
w->a.width + w->a.border_width * 2,
w->a.height + w->a.border_width * 2,
&kill, &kill);*/
}
}
sr.x = w->a.x + w->shadow_dx;
sr.y = w->a.y + w->shadow_dy;
sr.width = w->shadow_width;
sr.height = w->shadow_height;
if (sr.x < r.x)
{
r.width = (r.x + r.width) - sr.x;
r.x = sr.x;
}
if (sr.y < r.y)
{
r.height = (r.y + r.height) - sr.y;
r.y = sr.y;
}
if (sr.x + sr.width > r.x + r.width)
r.width = sr.x + sr.width - r.x;
if (sr.y + sr.height > r.y + r.height)
r.height = sr.y + sr.height - r.y;
}
}
return XFixesCreateRegion (dpy, &r, 1);
}
static XserverRegion
border_size (Display *dpy, win *w)
{
XserverRegion border;
/*
* if window doesn't exist anymore, this will generate an error
* as well as not generate a region. Perhaps a better XFixes
* architecture would be to have a request that copies instead
* of creates, that way you'd just end up with an empty region
* instead of an invalid XID.
*/
set_ignore (dpy, NextRequest (dpy));
border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding);
/* translate this */
set_ignore (dpy, NextRequest (dpy));
XFixesTranslateRegion (dpy, border,
w->a.x + w->a.border_width,
w->a.y + w->a.border_width);
return border;
}
static XserverRegion
deco_region (Display *dpy, win *w)
{
XserverRegion title;
XRectangle r; /*titlebounding rect*/
/*
* if window doesn't exist anymore, this will generate an error
* as well as not generate a region. Perhaps a better XFixes
* architecture would be to have a request that copies instead
* of creates, that way you'd just end up with an empty region
* instead of an invalid XID.
*/
r.x = w->a.x - w->a.border_width + _LEFTWIDTH_(w->decoHash);
r.y = w->a.y - w->a.border_width + _TOPHEIGHT_(w->decoHash);
r.width = w->a.width + w->a.border_width * 2 - _LEFTWIDTH_(w->decoHash) - _RIGHTWIDTH_(w->decoHash);
r.height = w->a.height + w->a.border_width - _TOPHEIGHT_(w->decoHash) - _BOTTOMHEIGHT_(w->decoHash);
set_ignore (dpy, NextRequest (dpy));
title = XFixesCreateRegion (dpy, &r, 1);
if (!w->borderSize)
w->borderSize = border_size (dpy, w);
set_ignore (dpy, NextRequest (dpy));
XFixesSubtractRegion(dpy, title, w->borderSize, title);
return title;
}
static void finish_destroy_win (Display *dpy, Window id, Bool gone);
static XserverRegion
content_region (Display *dpy, win *w)
{
XserverRegion content;
XRectangle r; /*contentbounding rect*/
/*
* if window doesn't exist anymore, this will generate an error
* as well as not generate a region. Perhaps a better XFixes
* architecture would be to have a request that copies instead
* of creates, that way you'd just end up with an empty region
* instead of an invalid XID.
*/
r.x = w->a.x - w->a.border_width + _LEFTWIDTH_(w->decoHash);
r.y = w->a.y - w->a.border_width + _TOPHEIGHT_(w->decoHash);
r.width = w->a.width + w->a.border_width * 2 - _LEFTWIDTH_(w->decoHash) - _RIGHTWIDTH_(w->decoHash);
r.height = w->a.height + w->a.border_width - _TOPHEIGHT_(w->decoHash) - _BOTTOMHEIGHT_(w->decoHash);
set_ignore (dpy, NextRequest (dpy));
content = XFixesCreateRegion (dpy, &r, 1);
if (!w->borderSize)
w->borderSize = border_size (dpy, w);
set_ignore (dpy, NextRequest (dpy));
XFixesIntersectRegion(dpy, content, w->borderSize, content);
return content;
}
static void
paint_all (Display *dpy, XserverRegion region)
{
win *w;
win *t = 0;
#if DEBUG_WINDOWS
int window_count = 0;
#endif
if (!region)
{
XRectangle r;
r.x = 0;
r.y = 0;
r.width = root_width;
r.height = root_height;
region = XFixesCreateRegion (dpy, &r, 1);
}
#if MONITOR_REPAINT
rootBuffer = rootPicture;
#else
if (!rootBuffer)
{
Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height,
DefaultDepth (dpy, scr));
rootBuffer = XRenderCreatePicture (dpy, rootPixmap,
sXRenderFindVisualFormat (dpy,
DefaultVisual (dpy, scr)),
0, 0);
XFreePixmap (dpy, rootPixmap);
}
#endif
XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
#if MONITOR_REPAINT
XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture,
0, 0, 0, 0, 0, 0, root_width, root_height);
#endif
#if DEBUG_REPAINT
printf ("paint:");
#endif
// Time delayed garbage collect
// It waits 10 seconds before destroying window data
// This allows the fade out to perform smoothly under all conditions
// Yes, this code is somewhat inefficient!
// But it shouldn't matter unless someone has tens of thousands of windows open...
// If the user can set a fade out that is longer than 10 seconds,
// then the value must be increased. I am assuming that 10 seconds
// is far too long for any normal human being to wait... ;-)
for (w = list; w; w = w->next)
{
if (w->destruct_requested) {
int curtime = get_time_in_milliseconds();
if ((curtime - w->destruct_request_time) > 10000) {
finish_destroy_win (dpy, w->id, True);
w = list;
}
}
}
for (w = list; w; w = w->next)
{
#if DEBUG_WINDOWS
window_count++;
#endif
#if CAN_DO_USABLE
if (!w->usable)
continue;
#endif
/* never painted, ignore it */
if ((!screen_damaged) && (!w->damaged)) {
#if DEBUG_REPAINT
printf(" [not damaged: 0x%x]", w->id);
#endif
continue;
}
/* skip invisible windows */
if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 || w->a.x >= root_width || w->a.y >= root_height) {
#if DEBUG_REPAINT
printf(" [invisible: 0x%x]", w->id);
#endif
continue;
}
if (!w->picture)
{
XRenderPictureAttributes pa;
XRenderPictFormat *format;
Drawable draw = w->id;
#if HAS_NAME_WINDOW_PIXMAP
if (hasNamePixmap && !w->pixmap)
w->pixmap = XCompositeNameWindowPixmap (dpy, w->id);
if (w->pixmap)
draw = w->pixmap;
#endif
format = sXRenderFindVisualFormat (dpy, w->a.visual);
pa.subwindow_mode = IncludeInferiors;
w->picture = XRenderCreatePicture (dpy, draw,
format,
CPSubwindowMode,
&pa);
}
#if DEBUG_REPAINT
printf (" [painting 0x%x]", w->id);
#endif
if (clipChanged)
{
if (w->borderSize)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->borderSize);
w->borderSize = None;
}
if (w->decoRegion)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->decoRegion);
w->decoRegion = None;
}
if (w->contentRegion)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->contentRegion);
w->contentRegion = None;
}
if (w->extents)
{
XFixesDestroyRegion (dpy, w->extents);
w->extents = None;
}
if (w->borderClip)
{
XFixesDestroyRegion (dpy, w->borderClip);
w->borderClip = None;
}
}
if (!w->borderSize)
w->borderSize = border_size (dpy, w);
if (!w->extents)
w->extents = win_extents (dpy, w);
if ((w->mode == WINDOW_SOLID) || ((w->mode == WINDOW_TRANS) && w->decoHash))
{
int x, y, wid, hei;
#if HAS_NAME_WINDOW_PIXMAP
x = w->a.x;
y = w->a.y;
wid = w->a.width + w->a.border_width * 2;
hei = w->a.height + w->a.border_width * 2;
#else
x = w->a.x + w->a.border_width;
y = w->a.y + w->a.border_width;
wid = w->a.width;
hei = w->a.height;
#endif
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
set_ignore (dpy, NextRequest (dpy));
/*XFixesSubtractRegion (dpy, region, region, w->borderSize);
set_ignore (dpy, NextRequest (dpy));*/
if (w->mode == WINDOW_SOLID)
{
XFixesSubtractRegion (dpy, region, region, w->borderSize);
set_ignore (dpy, NextRequest (dpy));
XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
0, 0, 0, 0, x, y, wid, hei);
if (w->dimPicture)
XRenderComposite (dpy, PictOpOver, w->dimPicture, None, rootBuffer, 0, 0, 0, 0, x, y, wid, hei);
}
else
{
if (!w->contentRegion)
w->contentRegion = content_region (dpy, w);
XFixesSubtractRegion (dpy, region, region, w->contentRegion);
set_ignore (dpy, NextRequest (dpy));
/*solid part*/
XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
_LEFTWIDTH_(w->decoHash), _TOPHEIGHT_(w->decoHash), 0, 0,
x + _LEFTWIDTH_(w->decoHash),
y + _TOPHEIGHT_(w->decoHash),
wid - _LEFTWIDTH_(w->decoHash) - _RIGHTWIDTH_(w->decoHash),
hei - _TOPHEIGHT_(w->decoHash) - _BOTTOMHEIGHT_(w->decoHash));
}
}
if (!w->borderClip)
{
w->borderClip = XFixesCreateRegion (dpy, 0, 0);
XFixesCopyRegion (dpy, w->borderClip, region);
}
w->prev_trans = t;
t = w;
}
#if DEBUG_WINDOWS
printf("window count: %d\n", window_count);
#endif
#if DEBUG_REPAINT
printf ("\n");
fflush (stdout);
#endif
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
paint_root (dpy);
for (w = t; w; w = w->prev_trans)
{
if (w->shadowSize > 0){
if (winTypeShadow[w->windowType]) {
switch (compMode) {
case CompSimple:
break;
case CompServerShadows:
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
set_ignore (dpy, NextRequest (dpy));
if (w->opacity != OPAQUE && !w->shadowPict)
w->shadowPict = solid_picture (dpy, True,
(double) w->opacity / OPAQUE * 0.3,
0, 0, 0);
XRenderComposite (dpy, PictOpOver,
w->shadowPict ? w->shadowPict : transBlackPicture,
w->picture, rootBuffer,
0, 0, 0, 0,
w->a.x + w->shadow_dx,
w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height);
break;
case CompClientShadows:
if (w->shadow)
{
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer,
0, 0, 0, 0,
w->a.x + w->shadow_dx,
w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height);
}
break;
}
}
}
if (w->opacity != OPAQUE && !w->alphaPict)
w->alphaPict = solid_picture (dpy, False,
(double) w->opacity / OPAQUE, shadowColor.red, shadowColor.green, shadowColor.blue);
if (w->mode == WINDOW_TRANS)
{
int x, y, wid, hei;
XFixesIntersectRegion (dpy, w->borderClip, w->borderClip, w->borderSize);
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
#if HAS_NAME_WINDOW_PIXMAP
x = w->a.x;
y = w->a.y;
wid = w->a.width + w->a.border_width * 2;
hei = w->a.height + w->a.border_width * 2;
#else
x = w->a.x + w->a.border_width;
y = w->a.y + w->a.border_width;
wid = w->a.width;
hei = w->a.height;
#endif
set_ignore (dpy, NextRequest (dpy));
if (!w->decoHash)
{
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
0, 0, 0, 0, x, y, wid, hei);
}
else
{
/*trans part*/
/* PICTURE ;)
|-----------------------------|
| top |
|-----------------------------|
|l | | r|
|e | | i|
|f | | g|
|t | | h|
|--------------------------| t|
| bottom | |
|--------------------------|--|*/
/*top*/
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
0, 0, 0, 0, x, y, wid, _TOPHEIGHT_(w->decoHash));
/*right*/
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
wid - _RIGHTWIDTH_(w->decoHash), _TOPHEIGHT_(w->decoHash),
0, 0,
x + wid - _RIGHTWIDTH_(w->decoHash),
y + _TOPHEIGHT_(w->decoHash), _RIGHTWIDTH_(w->decoHash),
hei - _TOPHEIGHT_(w->decoHash));
/*bottom*/
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
0, hei - _BOTTOMHEIGHT_(w->decoHash), 0, 0,
x, y + hei - _BOTTOMHEIGHT_(w->decoHash),
wid - _RIGHTWIDTH_(w->decoHash), _BOTTOMHEIGHT_(w->decoHash));
/*left*/
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
0, _TOPHEIGHT_(w->decoHash), 0, 0,
x, y + _TOPHEIGHT_(w->decoHash),
_LEFTWIDTH_(w->decoHash), hei - _TOPHEIGHT_(w->decoHash) - _BOTTOMHEIGHT_(w->decoHash));
}
}
else if (w->mode == WINDOW_ARGB)
{
int x, y, wid, hei;
XFixesIntersectRegion (dpy, w->borderClip, w->borderClip, w->borderSize);
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
#if HAS_NAME_WINDOW_PIXMAP
x = w->a.x;
y = w->a.y;
wid = w->a.width + w->a.border_width * 2;
hei = w->a.height + w->a.border_width * 2;
#else
x = w->a.x + w->a.border_width;
y = w->a.y + w->a.border_width;
wid = w->a.width;
hei = w->a.height;
#endif
set_ignore (dpy, NextRequest (dpy));
/* Here we redraw the background of the transparent window if we want
to do anything special (i.e. anything other than showing the
windows and desktop prestacked behind of the window).
For example, if you want to blur the background or show another
background pixmap entirely here is the place to do it; simply
draw the new background onto rootBuffer before continuing! */
if (w->isInFade == False) {
// HACK
// For an unknown reason the PropertyNotify event handler is not
// fired when either the show_black_background or show_root_tile
// control atoms are changed. This works around the problem but
// causes an unquantified, likely relatively low, performance loss.
w->show_black_background = determine_window_transparent_to_black(dpy, w->id);
if (w->show_black_background == True) {
XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootBuffer,
x, y, x, y,
x, y, wid, hei);
}
else if (w->show_root_tile == True) {
XRenderComposite (dpy, PictOpSrc, rootTile, None, rootBuffer,
x, y, x, y,
x, y, wid, hei);
}
}
XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer,
0, 0, 0, 0,
x, y, wid, hei);
}
XFixesDestroyRegion (dpy, w->borderClip);
w->borderClip = None;
}
XFixesDestroyRegion (dpy, region);
if (rootBuffer != rootPicture)
{
#if 0
XTransform t;
t.matrix[0][0] = XDoubleToFixed (3.0 /*/ scale*/);
t.matrix[0][1] = 0.0;
t.matrix[0][2] = 0.0;
t.matrix[1][0] = 0.0;
t.matrix[1][1] = XDoubleToFixed (1.0 /*/ scale*/);
t.matrix[1][2] = 0.0;
t.matrix[2][0] = 0.0;
t.matrix[2][1] = 0.0;
t.matrix[2][2] = XDoubleToFixed (1.0);
XRenderSetPictureTransform (dpy, rootBuffer, &t);
#endif
XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
0, 0, 0, 0, 0, 0, root_width, root_height);
}
screen_damaged = False;
}
static void
add_damage (Display *dpy, XserverRegion damage)
{
if (allDamage)
{
XFixesUnionRegion (dpy, allDamage, allDamage, damage);
XFixesDestroyRegion (dpy, damage);
}
else
allDamage = damage;
}
static void damage_win (Display *dpy, XDamageNotifyEvent *de);
static void
repair_win (Display *dpy, win *w)
{
XserverRegion parts;
if (!w->damaged)
{
parts = win_extents (dpy, w);
set_ignore (dpy, NextRequest (dpy));
XDamageSubtract (dpy, w->damage, None, None);
}
else
{
XserverRegion o;
parts = XFixesCreateRegion (dpy, 0, 0);
set_ignore (dpy, NextRequest (dpy));
XDamageSubtract (dpy, w->damage, None, parts);
XFixesTranslateRegion (dpy, parts,
w->a.x + w->a.border_width,
w->a.y + w->a.border_width);
if (compMode == CompServerShadows)
{
o = XFixesCreateRegion (dpy, 0, 0);
XFixesCopyRegion (dpy, o, parts);
XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy);
XFixesUnionRegion (dpy, parts, parts, o);
XFixesDestroyRegion (dpy, o);
}
}
add_damage (dpy, parts);
w->damaged = 1;
}
static const char*
wintype_name(wintype type)
{
const char *t;
switch (type) {
case WINTYPE_DESKTOP: t = "desktop"; break;
case WINTYPE_DOCK: t = "dock"; break;
case WINTYPE_TOOLBAR: t = "toolbar"; break;
case WINTYPE_MENU: t = "menu"; break;
case WINTYPE_UTILITY: t = "utility"; break;
case WINTYPE_SPLASH: t = "slash"; break;
case WINTYPE_DIALOG: t = "dialog"; break;
case WINTYPE_NORMAL: t = "normal"; break;
case WINTYPE_DROPDOWN_MENU: t = "dropdown"; break;
case WINTYPE_POPUP_MENU: t = "popup"; break;
case WINTYPE_TOOLTIP: t = "tooltip"; break;
case WINTYPE_NOTIFY: t = "notification"; break;
case WINTYPE_COMBO: t = "combo"; break;
case WINTYPE_DND: t = "dnd"; break;
default: t = "unknown"; break;
}
return t;
}
void repaint_root_overlay_window ()
{
XRectangle r;
r.x = 0;
r.y = 0;
r.width = root_width;
r.height = root_height;
XserverRegion region = XFixesCreateRegion (dpy, &r, 1);
add_damage (dpy, region);
}
static wintype
get_wintype_prop(Display * dpy, Window w)
{
Atom actual;
wintype ret;
int format;
unsigned long n, left, off;
unsigned char *data;
ret = (wintype)-1;
off = 0;
do {
set_ignore (dpy, NextRequest (dpy));
int result = XGetWindowProperty (dpy, w, winTypeAtom, off, 1L, False,
XA_ATOM, &actual, &format,
&n, &left, &data);
if (result != Success)
break;
if (data != None)
{
int i;
for (i = 0; i < NUM_WINTYPES; ++i) {
Atom a;
memcpy (&a, data, sizeof (Atom));
if (a == winType[i]) {
/* known type */
ret = i;
break;
}
}
XFree ( (void *) data);
}
++off;
} while (left >= 4 && ret == (wintype)-1);
return ret;
}
static wintype
determine_wintype (Display *dpy, Window w, Window top)
{
Window root_return, parent_return;
Window *children = NULL;
unsigned int nchildren, i;
wintype type;
type = get_wintype_prop (dpy, w);
if (type != (wintype)-1)
return type;
set_ignore (dpy, NextRequest (dpy));
if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
&nchildren))
{
/* XQueryTree failed. */
if (children)
XFree ((void *)children);
return (wintype)-1;
}
for (i = 0;i < nchildren;i++)
{
type = determine_wintype (dpy, children[i], top);
if (type != (wintype)-1)
return type;
}
if (children)
XFree ((void *)children);
if (w != top)
return (wintype)-1;
else
return WINTYPE_NORMAL;
}
static unsigned int
get_opacity_prop(Display *dpy, win *w, unsigned int def);
static void
map_win (Display *dpy, Window id, unsigned long sequence, Bool fade)
{
win *w = find_win (dpy, id);
Drawable back;
#if DEBUG_WINDOWS
printf("map_win: 0x%x 0x%x\n", w, id);
#endif
if (!w) {
return;
}
w->a.map_state = IsViewable;
/* This needs to be here or else we lose transparency messages */
XSelectInput (dpy, id, PropertyChangeMask);
/* This needs to be here since we don't get PropertyNotify when unmapped */
w->opacity = get_opacity_prop (dpy, w, OPAQUE);
w->show_root_tile = determine_window_transparent_to_desktop(dpy, id);
w->show_black_background = determine_window_transparent_to_black(dpy, id);
determine_mode (dpy, w);
w->windowType = determine_wintype (dpy, w->id, w->id);
if ((w->windowType < 0) || (w->windowType > NUM_WINTYPES)) w->windowType = WINTYPE_NORMAL;
#if 0
printf("window 0x%x type %s\n", w->id, wintype_name(w->windowType));
#endif
#if CAN_DO_USABLE
w->damage_bounds.x = w->damage_bounds.y = 0;
w->damage_bounds.width = w->damage_bounds.height = 0;
#endif
w->damaged = 0;
#if WORK_AROUND_FGLRX
if (w->a.x != 0) {
XserverRegion extents = win_extents (dpy, w);
XDamageNotifyEvent de;
de.drawable = w->id;
de.area.x = 0;
de.area.y = 0;
de.area.width = w->a.width + w->a.border_width * 2;
de.area.height = w->a.height + w->a.border_width * 2;
damage_win(dpy, &de);
XFixesDestroyRegion (dpy, extents);
}
#endif
w->a_prev = w->a;
if (fade && winTypeFade[w->windowType]) {
set_fade (dpy, w, 0, get_opacity_prop(dpy, w, OPAQUE)*1.0/OPAQUE, fade_in_step, 0, False, True, True, True);
}
}
static void
finish_unmap_win (Display *dpy, win *w)
{
#if DEBUG_WINDOWS
printf("finish_unmap_win: 0x%x\n", w->id);
#endif
w->damaged = 0;
#if CAN_DO_USABLE
w->usable = False;
#endif
if (w->extents != None)
{
add_damage (dpy, w->extents); /* destroys region */
w->extents = None;
}
#if HAS_NAME_WINDOW_PIXMAP
if (w->pixmap)
{
XFreePixmap (dpy, w->pixmap);
w->pixmap = None;
}
#endif
if (w->picture)
{
set_ignore (dpy, NextRequest (dpy));
XRenderFreePicture (dpy, w->picture);
w->picture = None;
}
/* don't care about properties anymore */
set_ignore (dpy, NextRequest (dpy));
XSelectInput(dpy, w->id, 0);
if (w->borderSize)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->borderSize);
w->borderSize = None;
}
if (w->decoRegion)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->decoRegion);
w->decoRegion = None;
}
if (w->contentRegion)
{
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, w->contentRegion);
w->contentRegion = None;
}
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
}
if (w->borderClip)
{
XFixesDestroyRegion (dpy, w->borderClip);
w->borderClip = None;
}
clipChanged = True;
}
#if HAS_NAME_WINDOW_PIXMAP
static void
unmap_callback (Display *dpy, win *w, Bool gone)
{
finish_unmap_win (dpy, w);
}
#endif
static void
unmap_win (Display *dpy, Window id, Bool fade)
{
win *w = find_win (dpy, id);
#if DEBUG_WINDOWS
printf("unmap_win: 0x%x 0x%x\n", w, id);
#endif
if (!w)
return;
if (w->a.map_state != IsUnmapped) {
w->a.map_state = IsUnmapped;
#if HAS_NAME_WINDOW_PIXMAP
if (w->pixmap && fade && winTypeFade[w->windowType]) {
set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True, True);
}
else
#endif
finish_unmap_win (dpy, w);
}
}
/* Get the opacity prop from window
not found: default
otherwise the value
*/
static unsigned int
get_opacity_prop(Display *dpy, win *w, unsigned int def)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data;
int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL && format == 32 )
{
unsigned int i;
i = *(long*)data;
XFree( (void *) data);
return i;
}
return def;
}
static unsigned int
get_shadow_prop(Display *dpy, win *w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, w->id, shadowAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL && format == 32 )
{
unsigned int i;
i = *(long*)data;
XFree( (void *) data);
/*i added this for security reaons but limiting a value to 200% is somewhat indiscriminate
if (i > 200)
return 200;
else*/
return i;
}
return 100;
}
static unsigned int
get_shade_prop(Display *dpy, win *w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, w->id, shadeAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL && format == 32 )
{
unsigned int i;
i = *(long*)data;
XFree( (void *) data);
return i;
}
return 0;
}
static Bool
get_shapable_prop(Display *dpy, win *w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, w->id, shapableAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL && format == 32 )
{
unsigned int i;
i = *(long*)data;
XFree( (void *) data);
return i==1;
}
return True; /*in general, the window should be shapable*/
}
static unsigned int
get_decoHash_prop(Display *dpy, win *w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, w->id, decoHashAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL && format == 32 )
{
unsigned int i;
i = *(long*)data;
XFree( (void *) data);
return i;
}
return 0; /*no titlebar*/
}
static unsigned int
get_dim_prop(Display *dpy, win *w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, w->id, dimAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL)
{
unsigned int i;
memcpy (&i, data, sizeof (unsigned int));
XFree( (void *) data);
if (i == 0) i = 1;
return i;
}
return OPAQUE; /*in general, the window is not dimmed*/
}
static unsigned int
get_deskchange_prop(Display *dpy, Window id)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data = NULL;
int result = XGetWindowProperty(dpy, id, deskChangeAtom, 0L, 1L, False,
XA_CARDINAL, &actual, &format,
&n, &left, &data);
if (result == Success && data != NULL)
{
unsigned int i;
memcpy (&i, data, sizeof (unsigned int));
XFree( (void *) data);
if (i < 3)
return i;
}
return 0; /*no valid change state*/
}
/* Get the opacity property from the window in a percent format
not found: default
otherwise: the value
*/
static double
get_opacity_percent(Display *dpy, win *w)
{
if (w && w->isInFade)
{
fade *f = find_fade(w);
return f->finish;
}
else
{
double def = winTypeOpacity[w->windowType];
unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def));
return opacity*1.0/OPAQUE;
}
}
#if 0
static void
damage_shape(Display *dpy, win *w, XRectangle *shape_damage)
{
set_ignore (dpy, NextRequest (dpy));
XserverRegion region = XFixesCreateRegion (dpy, shape_damage, 1);
set_ignore (dpy, NextRequest (dpy));
XserverRegion tmpRegion;
add_damage(dpy, region);
win *i;
XRectangle *rect;
int n;
for (i = w; i; i = i->next)
{
XFixesIntersectRegion (dpy, tmpRegion, region, w->extents);
rect = XFixesFetchRegion (dpy, region, &n);
free(rect);
printf("%d\n",n);
if (n != 1)
{
w->damage = True;
XFixesSubtractRegion (dpy, region, region, w->extents);
}
else
break;
}
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, tmpRegion);
set_ignore (dpy, NextRequest (dpy));
XFixesDestroyRegion (dpy, region);
}
#endif
static Bool
get_window_transparent_to_desktop(Display * dpy, Window w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data;
int result = XGetWindowProperty (dpy, w, winTDETTDAtom, 0L, 1L, False,
XA_ATOM, &actual, &format,
&n, &left, &data);
if (result == Success && data != None && format == 32 )
{
Atom a;
a = *(long*)data;
XFree ( (void *) data);
return True;
}
return False;
}
static Bool
get_window_transparent_to_black(Display * dpy, Window w)
{
Atom actual;
int format;
unsigned long n, left;
unsigned char *data;
int result = XGetWindowProperty (dpy, w, winTDETTBAtom, 0L, 1L, False,
XA_ATOM, &actual, &format,
&n, &left, &data);
if (result == Success && data != None && format == 32 )
{
Atom a;
a = *(long*)data;
XFree ( (void *) data);
return True;
}
return False;
}
static void
determine_mode(Display *dpy, win *w)
{
int mode;
XRenderPictFormat *format;
unsigned int default_opacity;
/* if trans prop == -1 fall back on previous tests*/
if (w->alphaPict)
{
XRenderFreePicture (dpy, w->alphaPict);
w->alphaPict = None;
}
if (w->shadowPict)
{
XRenderFreePicture (dpy, w->shadowPict);
w->shadowPict = None;
}
if (w->a.class == InputOnly)
{
format = 0;
}
else
{
format = XRenderFindVisualFormat (dpy, w->a.visual);
}
if (!disable_argb && format && format->type == PictTypeDirect && format->direct.alphaMask)
{
mode = WINDOW_ARGB;
}
else if (w->opacity != OPAQUE)
{
mode = WINDOW_TRANS;
}
else
{
mode = WINDOW_SOLID;
}
w->mode = mode;
if (w->extents)
{
XserverRegion damage;
damage = XFixesCreateRegion (dpy, 0, 0);
XFixesCopyRegion (dpy, damage, w->extents);
add_damage (dpy, damage);
}
}
static Bool
determine_window_transparent_to_desktop (Display *dpy, Window w)
{
Window root_return, parent_return;
Window *children = NULL;
unsigned int nchildren, i;
Bool type;
type = get_window_transparent_to_desktop (dpy, w);
if (type == True) {
return True;
}
if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
&nchildren))
{
/* XQueryTree failed. */
if (children)
XFree ((void *)children);
return False;
}
for (i = 0;i < nchildren;i++)
{
type = determine_window_transparent_to_desktop (dpy, children[i]);
if (type == True)
return True;
}
if (children)
XFree ((void *)children);
return False;
}
static Bool
determine_window_transparent_to_black (Display *dpy, Window w)
{
Window root_return, parent_return;
Window *children = NULL;
unsigned int nchildren, i;
Bool type;
type = get_window_transparent_to_black (dpy, w);
if (type == True) {
return True;
}
if (!XQueryTree (dpy, w, &root_return, &parent_return, &children,
&nchildren))
{
/* XQueryTree failed. */
if (children)
XFree ((void *)children);
return False;
}
for (i = 0;i < nchildren;i++)
{
type = determine_window_transparent_to_black (dpy, children[i]);
if (type == True)
return True;
}
if (children)
XFree ((void *)children);
return False;
}
static void
add_win (Display *dpy, Window id, Window prev)
{
win *new = malloc (sizeof (win));
win **p;
unsigned int tmp;
#if DEBUG_WINDOWS
printf("add_win: 0x%x\n", id);
#endif
if (!new) {
return;
}
if (prev) {
for (p = &list; *p; p = &(*p)->next) {
if (((*p)->id == prev) && (!(*p)->destroyed)) {
break;
}
}
}
else {
p = &list;
}
new->id = id;
set_ignore (dpy, NextRequest (dpy));
if (!XGetWindowAttributes (dpy, id, &new->a))
{
#if DEBUG_WINDOWS
printf("not adding 0x%x: failed to get attributes\n", new->id);
#endif
free (new);
return;
}
new->shaped = False;
new->shape_bounds.x = new->a.x;
new->shape_bounds.y = new->a.y;
new->shape_bounds_prev = new->shape_bounds;
new->shape_bounds.width = new->a.width;
new->shape_bounds.height = new->a.height;
new->a_prev = new->a;
new->damaged = 0;
#if CAN_DO_USABLE
new->usable = False;
#endif
#if HAS_NAME_WINDOW_PIXMAP
new->pixmap = None;
#endif
new->picture = None;
if (new->a.class == InputOnly)
{
new->damage_sequence = 0;
new->damage = None;
}
else
{
new->damage_sequence = NextRequest (dpy);
new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
XShapeSelectInput (dpy, id, ShapeNotifyMask);
}
new->isInFade = False;
new->alphaPict = None;
new->shadowPict = None;
new->borderSize = None;
new->decoRegion = None;
new->contentRegion = None;
new->extents = None;
new->shadow = None;
new->shadow_dx = 0;
new->shadow_dy = 0;
new->shadow_width = 0;
new->shadow_height = 0;
new->opacity = OPAQUE;
new->destroyed = False;
new->destruct_queued = False;
new->destruct_requested = False;
new->destruct_request_time = 0;
new->shadowSize = 100;
new->decoHash = 0;
new->show_root_tile = determine_window_transparent_to_desktop(dpy, id);
new->show_black_background = determine_window_transparent_to_black(dpy, id);
new->windowType = determine_wintype (dpy, new->id, new->id);
if ((new->windowType < 0) || (new->windowType > NUM_WINTYPES)) new->windowType = WINTYPE_NORMAL;
new->borderClip = None;
new->prev_trans = 0;
XShapeSelectInput( dpy, id, ShapeNotifyMask );
new->shadowSize = get_shadow_prop (dpy, new);
new->shapable = get_shapable_prop(dpy, new);
new->decoHash = get_decoHash_prop(dpy, new);
tmp = get_dim_prop(dpy, new);
new->dimPicture = (tmp < OPAQUE) ? solid_picture (dpy, True, (double)tmp/OPAQUE, 0.1, 0.1, 0.1) : None;
new->next = *p;
*p = new;
if (new->a.map_state == IsViewable) {
map_win (dpy, id, new->damage_sequence - 1, True);
}
}
void
restack_win (Display *dpy, win *w, Window new_above)
{
Window old_above;
#if DEBUG_WINDOWS
printf("restack_win: 0x%x\n", w->id);
#endif
if (w->next) {
old_above = w->next->id;
}
else {
old_above = None;
}
if (old_above != new_above) {
win **prev;
/* unhook */
for (prev = &list; *prev; prev = &(*prev)->next) {
if ((*prev) == w) {
break;
}
}
*prev = w->next;
/* rehook */
for (prev = &list; *prev; prev = &(*prev)->next) {
if ((!(*prev)->destroyed) && ((*prev)->id == new_above)) {
break;
}
}
w->next = *prev;
*prev = w;
}
}
static void
configure_win (Display *dpy, XConfigureEvent *ce)
{
win *w = find_win (dpy, ce->window);
Window above;
XserverRegion damage = None;
if (!w)
{
if (ce->window == root)
{
if (rootBuffer)
{
XRenderFreePicture (dpy, rootBuffer);
rootBuffer = None;
}
root_width = ce->width;
root_height = ce->height;
}
return;
}
#if CAN_DO_USABLE
if (w->usable)
#endif
{
damage = XFixesCreateRegion (dpy, 0, 0);
if (w->extents != None)
XFixesCopyRegion (dpy, damage, w->extents);
}
w->shape_bounds.x -= w->a.x;
w->shape_bounds.y -= w->a.y;
w->a.x = ce->x;
w->a.y = ce->y;
/* Only destroy the pixmap if the window is mapped */
if (w->a.map_state != IsUnmapped &&
(w->a.width != ce->width || w->a.height != ce->height))
{
#if HAS_NAME_WINDOW_PIXMAP
if (w->pixmap)
{
XFreePixmap (dpy, w->pixmap);
w->pixmap = None;
if (w->picture)
{
XRenderFreePicture (dpy, w->picture);
w->picture = None;
}
}
#endif
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
}
}
w->a.width = ce->width;
w->a.height = ce->height;
w->a.border_width = ce->border_width;
w->a.override_redirect = ce->override_redirect;
restack_win (dpy, w, ce->above);
if (w->a.map_state != IsUnmapped && damage)
{
XserverRegion extents = win_extents (dpy, w);
XFixesUnionRegion (dpy, damage, damage, extents);
XFixesDestroyRegion (dpy, extents);
add_damage (dpy, damage);
}
w->shape_bounds.x += w->a.x;
w->shape_bounds.y += w->a.y;
if (!w->shaped)
{
w->shape_bounds.width = w->a.width;
w->shape_bounds.height = w->a.height;
}
if (w->a.map_state != IsUnmapped)
clipChanged = True;
}
static void
circulate_win (Display *dpy, XCirculateEvent *ce)
{
win *w = find_win (dpy, ce->window);
Window new_above;
if (!w)
return;
if (ce->place == PlaceOnTop)
new_above = list->id;
else
new_above = None;
restack_win (dpy, w, new_above);
clipChanged = True;
}
static void
finish_destroy_win (Display *dpy, Window id, Bool gone)
{
win **prev, *w;
#if DEBUG_WINDOWS
printf("finish_destroy_win: 0x%x\n", id);
#endif
for (prev = &list; (w = *prev); prev = &w->next) {
if (w->id == id && w->destroyed) {
if (gone) {
finish_unmap_win (dpy, w);
}
*prev = w->next;
if (w->picture)
{
set_ignore (dpy, NextRequest (dpy));
XRenderFreePicture (dpy, w->picture);
w->picture = None;
}
if (w->alphaPict)
{
XRenderFreePicture (dpy, w->alphaPict);
w->alphaPict = None;
}
if (w->shadowPict)
{
XRenderFreePicture (dpy, w->shadowPict);
w->shadowPict = None;
}
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
}
if (w->damage != None)
{
set_ignore (dpy, NextRequest (dpy));
XDamageDestroy (dpy, w->damage);
w->damage = None;
}
cleanup_fade (dpy, w);
free (w);
break;
}
}
}
#if HAS_NAME_WINDOW_PIXMAP
static void
destroy_callback (Display *dpy, win *w, Bool gone)
{
finish_destroy_win (dpy, w->id, gone);
}
#endif
static void
destroy_win (Display *dpy, Window id, Bool gone, Bool fadeout)
{
fade *f;
win *w = find_win (dpy, id);
#if DEBUG_WINDOWS
printf("destroy_win: 0x%x 0x%x\n", w, id);
#endif
if (w) {
w->destroyed = True;
}
if (w && w->destruct_queued == False) {
f = find_fade (w);
if (f) {
w->destruct_queued = True;
f->callback = destroy_callback;
}
else {
#if HAS_NAME_WINDOW_PIXMAP
if (w->pixmap && fadeout && winTypeFade[w->windowType]) {
set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True, True);
}
else
#endif
{
if (!gone) {
finish_destroy_win (dpy, id, gone);
}
else {
w->destruct_queued = True;
w->destruct_requested = True;
w->destruct_request_time = get_time_in_milliseconds();
}
}
}
}
}
#if DEBUG_WINDOWS
static void
dump_win (win *w)
{
printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id,
w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width);
}
static void
dump_wins (void)
{
win *w;
printf ("windows:\n");
for (w = list; w; w = w->next) {
dump_win (w);
}
}
#endif
static void
damage_win (Display *dpy, XDamageNotifyEvent *de)
{
win *w = find_win (dpy, de->drawable);
if (!w)
return;
#if WORK_AROUND_FGLRX
if (w->a.map_state != IsViewable)
return;
#endif
#if CAN_DO_USABLE
if (!w->usable)
{
if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0)
{
w->damage_bounds = de->area;
}
else
{
if (de->area.x < w->damage_bounds.x)
{
w->damage_bounds.width += (w->damage_bounds.x - de->area.x);
w->damage_bounds.x = de->area.x;
}
if (de->area.y < w->damage_bounds.y)
{
w->damage_bounds.height += (w->damage_bounds.y - de->area.y);
w->damage_bounds.y = de->area.y;
}
if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width)
w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x;
if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height)
w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y;
}
#if 0
printf ("unusable damage [%d] %d, %d: %d x %d bounds %d, %d: %d x %d\n",
de->drawable,
de->area.x,
de->area.y,
de->area.width,
de->area.height,
w->damage_bounds.x,
w->damage_bounds.y,
w->damage_bounds.width,
w->damage_bounds.height);
#endif
if (w->damage_bounds.x <= 0 &&
w->damage_bounds.y <= 0 &&
w->a.width <= w->damage_bounds.x + w->damage_bounds.width &&
w->a.height <= w->damage_bounds.y + w->damage_bounds.height)
{
clipChanged = True;
if (winTypeFade[w->windowType]) {
set_fade (dpy, w, 0, get_opacity_percent (dpy, w), fade_in_step, 0, False, True, True, False);
}
w->usable = True;
}
}
if (w->usable)
#endif
repair_win (dpy, w);
}
static const char *
shape_kind(int kind)
{
static char buf[128];
switch(kind){
case ShapeBounding:
return "ShapeBounding";
case ShapeClip:
return "ShapeClip";
case ShapeInput:
return "ShapeInput";
default:
sprintf (buf, "Shape %d", kind);
return buf;
}
}
static void
shape_win (Display *dpy, XShapeEvent *se)
{
win *w = find_win (dpy, se->window);
if (!w)
return;
if (w->a.map_state == IsUnmapped)
return;
if (w->isInFade)
return;
if (se->kind == ShapeClip || se->kind == ShapeBounding)
{
XserverRegion region0;
XserverRegion region1;
#if 0
printf("win 0x%lx %s:%s %ux%u+%d+%d (@%d+%d)\n",
(unsigned long) se->window,
shape_kind(se->kind),
(se->shaped == True) ? "true" : "false",
se->width, se->height,
se->x, se->y,
w->a.x, w->a.y);
printf("\told %s %d+%d (@%d+%d)\n",
(w->shaped == True) ? "true" : "false",
w->shape_bounds_prev.width, w->shape_bounds_prev.height,
w->shape_bounds_prev.x, w->shape_bounds_prev.y);
#endif
clipChanged = True;
region0 = XFixesCreateRegion (dpy, &w->shape_bounds_prev, 1);
if (se->shaped == True)
{
w->shaped = True;
w->shape_bounds.x = w->a.x + se->x;
w->shape_bounds.y = w->a.y + se->y;
w->shape_bounds.width = se->width;
w->shape_bounds.height = se->height;
}
else
{
w->shaped = False;
w->shape_bounds.x = w->a.x;
w->shape_bounds.y = w->a.y;
w->shape_bounds.width = w->a.width;
w->shape_bounds.height = w->a.height;
}
region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1);
XFixesUnionRegion (dpy, region0, region0, region1);
XFixesDestroyRegion (dpy, region1);
/* ask for repaint of the old and new region */
paint_all (dpy, region0);
}
w->shape_bounds_prev = w->shape_bounds;
}
static void
damage_screen (Display *dpy)
{
XserverRegion region;
XRectangle r;
r.x = 0;
r.y = 0;
r.width = root_width;
r.height = root_height;
region = XFixesCreateRegion (dpy, &r, 1);
add_damage (dpy, region);
screen_damaged = True;
}
static int
error (Display *dpy, XErrorEvent *ev)
{
int o;
char *name = 0;
if (should_ignore (dpy, ev->serial))
return 0;
if (ev->request_code == composite_opcode &&
ev->minor_code == X_CompositeRedirectSubwindows)
{
fprintf (stderr, "Another composite manager is already running\n");
my_exit_code=2;
exit (2);
}
o = ev->error_code - xfixes_error;
switch (o) {
case BadRegion: name = "BadRegion"; break;
default: break;
}
o = ev->error_code - damage_error;
switch (o) {
case BadDamage: name = "BadDamage"; break;
default: break;
}
o = ev->error_code - render_error;
switch (o) {
case BadPictFormat: name ="BadPictFormat"; break;
case BadPicture: name ="BadPicture"; break;
case BadPictOp: name ="BadPictOp"; break;
case BadGlyphSet: name ="BadGlyphSet"; break;
case BadGlyph: name ="BadGlyph"; break;
default: break;
}
#ifndef NDEBUG
fprintf (stderr,"error %d request %d minor %d serial %d\n",
ev->error_code, ev->request_code, ev->minor_code, ev->serial);
#endif
/* abort (); this is just annoying to most people */
return 0;
}
static void
expose_root (Display *dpy, Window root, XRectangle *rects, int nrects)
{
XserverRegion region = XFixesCreateRegion (dpy, rects, nrects);
add_damage (dpy, region);
}
static int
ev_serial (XEvent *ev)
{
if ((ev->type & 0x7f) != KeymapNotify)
return ev->xany.serial;
return NextRequest (ev->xany.display);
}
static char *
ev_name (XEvent *ev)
{
static char buf[128];
switch (ev->type & 0x7f) {
case Expose:
return "Expose";
case MapNotify:
return "Map";
case UnmapNotify:
return "Unmap";
case ReparentNotify:
return "Reparent";
case CirculateNotify:
return "Circulate";
default:
if (ev->type == damage_event + XDamageNotify) {
return "Damage";
}
else if (ev->type == xshape_event + ShapeNotify)
{
return "Shape";
}
sprintf (buf, "Event %d", ev->type);
return buf;
}
}
static Window
ev_window (XEvent *ev)
{
switch (ev->type) {
case Expose:
return ev->xexpose.window;
case MapNotify:
return ev->xmap.window;
case UnmapNotify:
return ev->xunmap.window;
case ReparentNotify:
return ev->xreparent.window;
case CirculateNotify:
return ev->xcirculate.window;
default:
if (ev->type == damage_event + XDamageNotify) {
// fprintf(stderr, "%d", ev->type);
return ((XDamageNotifyEvent *) ev)->drawable;
}
else if (ev->type == xshape_event + ShapeNotify)
{
// fprintf(stderr, "%d", ev->type);
return ((XShapeEvent *) ev)->window;
}
return 0;
}
}
void
setShadowColor(char *value){ /*format nach #xxxxxx (html) <20>ndern?*/
unsigned int tmp;
char **res = NULL;
tmp = strtoul(value, res, 16);
if( !value || strlen(value) < 6 || strlen(value) > 8 || (*(value+1) == 'x' && strlen(value) < 8) || res != NULL ){
shadowColor.red = 0;
shadowColor.green = 0;
shadowColor.blue = 0;
printf("wrong hexadecimal (use 0xXXXXXX or XXXXXX)! defaulting to black...\n");
return;
}
shadowColor.blue = tmp&0xff;
tmp >>= 8;
shadowColor.green = tmp&0xff;
tmp >>= 8;
shadowColor.red = tmp&0xff;
}
typedef enum _option{
Display_=0,
Compmode,
ExcludeDockShadows,
FadeWindows,
FadeTrans,
AutoRedirect,
Synchronize,
ShadowColor,
ShadowRadius,
ShadowOpacity,
ShadowOffsetX,
ShadowOffsetY,
FadeOutStep,
FadeInStep,
FadeDelta,
DisableARGB,
FadeMenuWindows,
NUMBEROFOPTIONS
} Option;
const char *
options[NUMBEROFOPTIONS] = {
"Display", /*0*/
"Compmode", /*1*/
"ExcludeDockShadows", /*2*/
"FadeWindows", /*3*/
"FadeTrans", /*4*/
"AutoRedirect", /*5*/
"Synchronize", /*6*/
"ShadowColor", /*7*/
"ShadowRadius", /*8*/
"ShadowOpacity", /*9*/
"ShadowOffsetX", /*10*/
"ShadowOffsetY", /*11*/
"FadeOutStep", /*12*/
"FadeInStep", /*13*/
"FadeDelta", /*14*/
"DisableARGB", /*15*/
"FadeMenuWindows", /*16*/
/*put your thingy in here...*/
};
void
setValue(Option option, char *value ){
int i;
switch(option){ /*please keep that upside-down, because this way adding a new option is easier (all in one view)*/
case FadeDelta:
fade_delta = atoi(value);
if (fade_delta < 1)
fade_delta = 10;
break;
case FadeInStep:
fade_in_step = atof(value);
if (fade_in_step <= 0)
fade_in_step = 0.01;
break;
case FadeOutStep:
fade_out_step = atof(value);
if (fade_out_step <= 0)
fade_out_step = 0.01;
break;
case ShadowOffsetY:
shadowOffsetY = atoi(value);
break;
case ShadowOffsetX:
shadowOffsetX = atoi(value);
break;
case ShadowOpacity:
shadowOpacity = atof(value);
break;
case ShadowRadius:
shadowRadius = atoi(value);
break;
case ShadowColor:
setShadowColor(value);
break;
case Synchronize:
synchronize = ( strcasecmp(value, "true") == 0 );
break;
case AutoRedirect:
autoRedirect = ( strcasecmp(value, "true") == 0 );
break;
case FadeTrans:
fadeTrans = ( strcasecmp(value, "true") == 0 );
break;
case FadeWindows:
if ( strcasecmp(value, "true") == 0 ) {
int i;
for (i = 0; i < NUM_WINTYPES; ++i) {
if (i != WINTYPE_POPUP_MENU)
winTypeFade[i] = True;
}
}
break;
case FadeMenuWindows:
if ( strcasecmp(value, "true") == 0 ) {
winTypeFade[WINTYPE_POPUP_MENU] = True;
}
break;
case ExcludeDockShadows:
if ( strcasecmp(value, "true") == 0 ) {
winTypeShadow[WINTYPE_DOCK] = False;
}
break;
case Compmode:
if( strcasecmp(value, "CompClientShadows") == 0 ){
compMode = CompClientShadows;
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = True;
}
else if( strcasecmp(value, "CompServerShadows") == 0 ){
compMode = CompServerShadows;
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = True;
}
else{
compMode = CompSimple; /*default*/
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = False;
}
break;
case Display_:
break;
display = strdup(value);
break;
case DisableARGB:
disable_argb = ( strcasecmp(value, "true") == 0 );
break;
default:
break;
}
}
int
setParameter(char *line){
char *name = strtok(line, "=");
char *value = line+strlen(name)+1;
Option i;
for(i=Display_; i < NUMBEROFOPTIONS; i++){
if( strcasecmp(name, *(options+i) ) == 0 ){
setValue(i, value);
name = value = NULL;
return 1;
}
}
printf("ignored unknown option: <%s>\n", name);
name = value = NULL;
return 0;
}
void
loadConfig(char *filename){
FILE *file = NULL;
char line[ 1024 ];
size_t length = 0;
Bool wasNull = False;
Bool section = False;
if( filename == NULL ){
#ifdef USE_ENV_HOME
const char *home = getenv("HOME");
#else
const char *home;
struct passwd *p;
p = getpwuid(getuid());
if (p)
home = p->pw_dir;
else
home = getenv("HOME");
#endif
const char *configfile = "/.xcompmgrrc";
int n = strlen(home)+strlen(configfile)+1;
filename = (char*)malloc(n*sizeof(char));
memset(filename,0,n);
wasNull = True;
strcat(filename, home);
strcat(filename, configfile);
}
printf("trying '%s' as configfile\n\n", filename);
if( (file = fopen(filename, "r")) == NULL ){
printf("failed to open config file. does it exist?\n");
if( wasNull ){
free(filename);
filename = NULL;
}
return;
}
/*find section*/
while( !section && fgets(line, 1023, file) != NULL ){
if( strcmp(line, "[xcompmgr]\n") == 0 )
section = True;
}
/*read and set values*/
while( section && fgets(line, 1023, file) != NULL ){
int ret = strlen( line );
if( ret > 1 ){
if( *line == '[' )/*found new section - maybe check for '\n'?*/
break;
*(line+ret-1) = '\0';
setParameter(line);
}
}
printf("\nfinished parsing the config file\n");
fclose(file);
if( wasNull ){
free(filename);
filename = NULL;
}
}
void
usage (char *program)
{
fprintf (stderr, "%s v1.0\n", program);
fprintf (stderr, "usage: %s [options]\n", program);
fprintf (stderr, "Options\n");
fprintf (stderr, " -d display\n Specifies which display should be managed.\n");
fprintf (stderr, " -r radius\n Specifies the blur radius for client-side shadows. (default 12)\n");
fprintf (stderr, " -o opacity\n Specifies the translucency for client-side shadows. (default .75)\n");
fprintf (stderr, " -l left-offset\n Specifies the left offset for client-side shadows. (default -15)\n");
fprintf (stderr, " -t top-offset\n Specifies the top offset for clinet-side shadows. (default -15)\n");
fprintf (stderr, " -b color\n Specifies the background color to use if no root pixmap is set. (default is black)\n");
fprintf (stderr, " -I fade-in-step\n Specifies the opacity change between steps while fading in. (default 0.028)\n");
fprintf (stderr, " -O fade-out-step\n Specifies the opacity change between steps while fading out. (default 0.03)\n");
fprintf (stderr, " -D fade-delta-time\n Specifies the time between steps in a fade in milliseconds. (default 10)\n");
fprintf (stderr, " -a\n Use automatic server-side compositing. Faster, but no special effects.\n");
fprintf (stderr, " -c\n Draw client-side shadows with fuzzy edges.\n");
fprintf (stderr, " -C\n Avoid drawing shadows on dock/panel windows.\n");
fprintf (stderr, " -f\n Fade windows in/out when opening/closing.\n");
fprintf (stderr, " -F\n Fade windows during opacity changes.\n");
fprintf (stderr, " -n\n Normal client-side compositing with transparency support\n");
fprintf (stderr, " -s\n Draw server-side shadows with sharp edges.\n");
fprintf (stderr, " -S\n Enable synchronous operation (for debugging).\n");
fprintf (stderr, " -x [0x]XXXXXX\n Choose Custom Color in hex format\n");
fprintf (stderr, " -v\n Print version Number and exit\n");
fprintf (stderr, " -h\n Print this help\n");
my_exit_code=2;
exit (2);
}
static Bool
register_cm (void)
{
Window w;
Atom a;
static char net_wm_cm[] = "_NET_WM_CM_Sxx";
snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr);
a = XInternAtom (dpy, net_wm_cm, False);
/* w = XGetSelectionOwner (dpy, a);
if (w != None)
{
XTextProperty tp;
char **strs;
int count;
Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False);
if (!XGetTextProperty (dpy, w, &tp, winNameAtom) &&
!XGetTextProperty (dpy, w, &tp, XA_WM_NAME))
{
fprintf (stderr,
"Another composite manager is already running (0x%lx)\n",
(unsigned long) w);
return False;
}
if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success)
{
fprintf (stderr,
"Another composite manager is already running (%s)\n",
strs[0]);
XFreeStringList (strs);
}
XFree (tp.value);
return False;
}*/
w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None,
None);
Xutf8SetWMProperties(dpy, w, "kcompmgr", "kcompmgr", NULL, 0, NULL, NULL,
NULL);
/* setting this causes kompmgr to abort on TDE login */
/* XSetSelectionOwner (dpy, a, w, 0); */
return True;
}
int
main (int argc, char **argv)
{
XEvent ev;
Window root_return, parent_return;
Window *children;
Pixmap transPixmap;
Pixmap blackPixmap;
unsigned int nchildren;
int i;
XRenderPictureAttributes pa;
XRenderColor c;
XRectangle *expose_rects = 0;
int size_expose = 0;
int n_expose = 0;
struct pollfd ufd;
int n;
int last_update;
int now;
int p;
int composite_major, composite_minor;
Bool noDockShadow = False;
for (i = 0; i < NUM_WINTYPES; ++i) {
winTypeFade[i] = False;
winTypeShadow[i] = False;
winTypeOpacity[i] = 1.0;
}
int o;
char *fill_color_name = NULL;
char **res = NULL;
shadowColor.red = 0;
shadowColor.green = 0;
shadowColor.blue = 0;
// Initialize signal handlers
sigfillset(&block_mask);
usr_action.sa_handler = handle_siguser;
usr_action.sa_mask = block_mask;
usr_action.sa_flags = 0;
sigaction(SIGUSR1, &usr_action, NULL);
sigaction(SIGUSR2, &usr_action, NULL);
sigaction(SIGTERM, &usr_action, NULL);
loadConfig(NULL); /*we do that before cmdline-parsing, so config-values can be overridden*/
/*used for shadow colors*/
while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:b:scnfFmCaSx:vhk")) != -1)
{
switch (o) {
case 'd':
display = optarg;
break;
case 'D':
fade_delta = atoi (optarg);
if (fade_delta < 1)
fade_delta = 10;
break;
case 'I':
fade_in_step = atof (optarg);
if (fade_in_step <= 0)
fade_in_step = 0.01;
break;
case 'O':
fade_out_step = atof (optarg);
if (fade_out_step <= 0)
fade_out_step = 0.01;
break;
case 's':
compMode = CompServerShadows;
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = True;
break;
case 'c':
compMode = CompClientShadows;
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = True;
break;
case 'C':
winTypeShadow[WINTYPE_DOCK] = False;
break;
case 'n':
compMode = CompSimple;
for (i = 0; i < NUM_WINTYPES; ++i)
winTypeShadow[i] = False;
break;
case 'f':
for (i = 0; i < NUM_WINTYPES; ++i) {
if (i != WINTYPE_POPUP_MENU)
winTypeFade[i] = True;
}
break;
case 'm':
winTypeFade[WINTYPE_POPUP_MENU] = True;
break;
case 'F':
fadeTrans = True;
break;
case 'a':
autoRedirect = True;
break;
case 'S':
synchronize = True;
break;
case 'r':
shadowRadius = atoi (optarg);
break;
case 'o':
shadowOpacity = atof (optarg);
break;
case 'l':
shadowOffsetX = atoi (optarg);
break;
case 't':
shadowOffsetY = atoi (optarg);
break;
case 'b':
fill_color_name = optarg;
break;
case 'x':
if( compMode != CompClientShadows ){
fprintf(stderr, "sorry, but we need ClientShadows (-c) for coloring to work properly!\ndefaulting to black...\n");
break;
}
setShadowColor(optarg);
break;
case 'v': fprintf (stderr, "%s v%-3.2f\n", argv[0], _VERSION_); my_exit_code=0; exit (0);
case 'k':
restartOnSigterm = False;
break;
case 'h':
default:
usage (argv[0]);
break;
}
}
/* don't bother to do anything for the desktop */
winTypeOpacity[WINTYPE_DESKTOP] = 1.0;
winTypeShadow[WINTYPE_DESKTOP] = False;
winTypeFade[WINTYPE_DESKTOP] = False;
dpy = XOpenDisplay (display);
if (!dpy)
{
fprintf (stderr, "Can't open display\n");
my_exit_code=2;
exit (2);
}
XSetErrorHandler (error);
if (synchronize)
XSynchronize (dpy, 1);
scr = DefaultScreen (dpy);
root = RootWindow (dpy, scr);
if (!XRenderQueryExtension (dpy, &render_event, &render_error))
{
fprintf (stderr, "No render extension\n");
my_exit_code=2;
exit (2);
}
if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode,
&composite_event, &composite_error))
{
fprintf (stderr, "No composite extension\n");
my_exit_code=2;
exit (2);
}
XCompositeQueryVersion (dpy, &composite_major, &composite_minor);
#if HAS_NAME_WINDOW_PIXMAP
if (composite_major > 0 || composite_minor >= 2)
hasNamePixmap = True;
#endif
if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
{
fprintf (stderr, "No damage extension\n");
my_exit_code=2;
exit (2);
}
if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
{
fprintf (stderr, "No XFixes extension\n");
my_exit_code=2;
exit (2);
}
if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error))
{
fprintf (stderr, "No XShape extension\n");
my_exit_code=2;
exit (2);
}
fprintf(stderr, "Started\n");
if (!register_cm())
{
my_exit_code=2;
exit (2);
}
/* get atoms */
shadowAtom = XInternAtom (dpy, SHADOW_PROP, False);
opacityAtom = XInternAtom (dpy, OPACITY_PROP, False);
shadeAtom = XInternAtom (dpy, SHADE_PROP, False);
shapableAtom = XInternAtom (dpy, SHAPABLE_PROP, False);
decoHashAtom = XInternAtom (dpy, DECOHASH_PROP, False);
dimAtom = XInternAtom (dpy, DIM_PROP, False);
deskChangeAtom = XInternAtom (dpy, DESKCHANGE_PROP, False);
winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False);
winTDETTDAtom = XInternAtom (dpy, "_KDE_TRANSPARENT_TO_DESKTOP", False);
winTDETTBAtom = XInternAtom (dpy, "_KDE_TRANSPARENT_TO_BLACK", False);
winType[WINTYPE_DESKTOP] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
winType[WINTYPE_DOCK] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
winType[WINTYPE_TOOLBAR] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
winType[WINTYPE_MENU] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
winType[WINTYPE_UTILITY] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
winType[WINTYPE_SPLASH] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
winType[WINTYPE_DIALOG] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
winType[WINTYPE_NORMAL] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
winType[WINTYPE_DROPDOWN_MENU] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
winType[WINTYPE_POPUP_MENU] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
winType[WINTYPE_TOOLTIP] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
winType[WINTYPE_NOTIFY] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
winType[WINTYPE_COMBO] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_COMBO", False);
winType[WINTYPE_DND] = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DND", False);
pa.subwindow_mode = IncludeInferiors;
if (compMode == CompClientShadows)
{
gaussianMap = make_gaussian_map(dpy, shadowRadius);
presum_gaussian (gaussianMap);
}
if (fill_color_name)
{
XColor c;
if (! XParseColor (dpy, DefaultColormap (dpy, scr),
fill_color_name, &c))
{
fprintf (stderr, "Could not parse fill color.\n");
my_exit_code=2;
exit (2);
}
if (! XAllocColor (dpy, DefaultColormap (dpy, scr), &c))
{
fprintf (stderr, "Could not allocate color.\n");
my_exit_code=2;
exit (2);
}
fill_color.red = c.red;
fill_color.green = c.green;
fill_color.blue = c.blue;
}
else
{
fill_color.red = fill_color.green = fill_color.blue = 0x0;
}
fill_color.alpha = 0xffff;
root_width = DisplayWidth (dpy, scr);
root_height = DisplayHeight (dpy, scr);
rootPicture = XRenderCreatePicture (dpy, root,
sXRenderFindVisualFormat (dpy,
DefaultVisual (dpy, scr)),
CPSubwindowMode,
&pa);
blackPicture = solid_picture (dpy, True, 1, (double)(shadowColor.red)/0xff, (double)(shadowColor.green)/0xff, (double)(shadowColor.blue)/0xff);
if (compMode == CompServerShadows)
transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0);
allDamage = None;
clipChanged = True;
XGrabServer (dpy);
if (autoRedirect) {
XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic);
}
else
{
int dummy;
XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
XSelectInput (dpy, root,
SubstructureNotifyMask|
ExposureMask|
StructureNotifyMask|
PropertyChangeMask |
VisibilityChangeMask);
/*shaping stuff*/
XShapeQueryExtension(dpy, &shapeEvent, &dummy);
XShapeSelectInput (dpy, root, ShapeNotifyMask);
XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren);
for (i = 0; i < nchildren; i++) {
add_win (dpy, children[i], i ? children[i-1] : None);
}
XFree (children);
}
XUngrabServer (dpy);
ufd.fd = ConnectionNumber (dpy);
ufd.events = POLLIN;
if (!autoRedirect) {
paint_all (dpy, None);
}
/* Under no circumstances should these two lines EVER be moved earlier in main() than this point */
atexit(delete_pid_file);
write_pid_file(getpid());
for (;;)
{
#if DEBUG_WINDOWS
dump_wins ();
#endif
do {
if (autoRedirect) {
XFlush (dpy);
}
if (!QLength (dpy))
{
if (poll (&ufd, 1, fade_timeout()) == 0)
{
run_fades (dpy);
break;
}
}
XNextEvent (dpy, &ev);
if ((ev.type & 0x7f) != KeymapNotify) {
discard_ignore (dpy, ev.xany.serial);
}
#if DEBUG_EVENTS
printf ("event %10.10s serial 0x%08x window 0x%08x\n",
ev_name(&ev), ev_serial (&ev), ev_window (&ev));
#endif
if (!autoRedirect) switch (ev.type) {
case CreateNotify:
add_win (dpy, ev.xcreatewindow.window, 0);
break;
case ConfigureNotify:
configure_win (dpy, &ev.xconfigure);
break;
case DestroyNotify:
destroy_win (dpy, ev.xdestroywindow.window, True, True);
break;
case MapNotify:
map_win (dpy, ev.xmap.window, ev.xmap.serial, True);
break;
case UnmapNotify:
unmap_win (dpy, ev.xunmap.window, True);
break;
case ReparentNotify:
if (ev.xreparent.parent == root)
add_win (dpy, ev.xreparent.window, 0);
else
destroy_win (dpy, ev.xreparent.window, False, True);
break;
case CirculateNotify:
circulate_win (dpy, &ev.xcirculate);
break;
case Expose:
if (ev.xexpose.window == root)
{
int more = ev.xexpose.count + 1;
if (n_expose == size_expose)
{
if (expose_rects)
{
expose_rects = realloc (expose_rects,
(size_expose + more) *
sizeof (XRectangle));
size_expose += more;
}
else
{
expose_rects = malloc (more * sizeof (XRectangle));
size_expose = more;
}
}
expose_rects[n_expose].x = ev.xexpose.x;
expose_rects[n_expose].y = ev.xexpose.y;
expose_rects[n_expose].width = ev.xexpose.width;
expose_rects[n_expose].height = ev.xexpose.height;
n_expose++;
if (ev.xexpose.count == 0)
{
expose_root (dpy, root, expose_rects, n_expose);
n_expose = 0;
}
}
break;
case PropertyNotify:
for (p = 0; backgroundProps[p]; p++)
{
if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False))
{
if (rootTile)
{
XRenderFreePicture (dpy, rootTile);
rootTile = None;
damage_screen (dpy);
break;
}
}
}
/* Window set shade? */
if (ev.xproperty.atom == shadeAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w){
unsigned int tmp = get_shade_prop(dpy, w);
if (tmp)
{
if (tmp == 1)
{
w->preShadeOpacity = w->opacity;
w->opacity = w->opacity-1; /*assuming that no human being will ever be able to shade an invisable window ;) */
determine_mode(dpy, w);
}
else if (tmp == 2)
{
w->opacity = w->preShadeOpacity;
determine_mode(dpy, w);
}
}
break;
}
}
else if (ev.xproperty.atom == shapableAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
w->shapable = get_shapable_prop(dpy, w);
/* printf("%u is %s shapable\n",w->id,w->shapable?"":"not");*/
}
else
printf("arrrg, window not found\n");
}
else if (ev.xproperty.atom == decoHashAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
w->decoHash = get_decoHash_prop(dpy, w);
}
else
printf("arrrg, window not found\n");
}
else if (ev.xproperty.atom == dimAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
unsigned int tmp = get_dim_prop(dpy, w);
if (w->dimPicture)
{
XRenderFreePicture (dpy, w->dimPicture);
w->dimPicture = None;
}
if (tmp < OPAQUE)
w->dimPicture = solid_picture (dpy, True, (double)tmp/OPAQUE, 0.1, 0.1, 0.1);
}
else
printf("arrrg, window not found\n");
}
/* check if Trans or Shadow property was changed */
else if (ev.xproperty.atom == opacityAtom || ev.xproperty.atom == shadowAtom)
{
/* reset mode and redraw window */
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
unsigned int tmp;
unsigned int oldShadowSize = w->shadowSize;
if (ev.xproperty.atom == opacityAtom)
{
tmp = get_opacity_prop(dpy, w, OPAQUE);
/*This will most probably happen if window is in fade - resulting in that the fade process isn't updated or broken -> we may have a wrong opacity in the future*/
/*if (tmp == w->opacity)
break;*/ /*skip if opacity does not change*/
if (fadeTrans)
{
static double start, finish, step;
start = w->opacity*1.0/OPAQUE;
finish = (tmp*1.0)/OPAQUE;
if ( start > finish )
step = fade_out_step;
else
step = fade_in_step;
set_fade (dpy, w, start, finish, step, 0, False, True, True, False);
break;
}
else {
w->opacity = tmp;
}
}
else
{
tmp = get_shadow_prop(dpy, w);
if (tmp == w->shadowSize)
break; /*skip if shadow does not change*/
w->shadowSize = tmp;
/* if (w->isInFade)
break; */
}
if (w->shadow)
{
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
}
if (oldShadowSize < w->shadowSize) /* this is important to catch size changes on cleanup with determine_mode*/
{
if( w->extents != None )
XFixesDestroyRegion( dpy, w->extents );
w->extents = win_extents (dpy, w);
determine_mode(dpy, w);
}
else
{
determine_mode(dpy, w);
if( w->extents != None )
XFixesDestroyRegion( dpy, w->extents );
w->extents = win_extents (dpy, w);
}
}
}
else if (ev.xproperty.atom == deskChangeAtom)
{
/*just set global variable*/
unsigned int tmp = get_deskchange_prop(dpy, ev.xproperty.window);
printf("desk change, state:%d\n",tmp);
}
else if (ev.xproperty.atom == winTDETTDAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
w->show_root_tile = determine_window_transparent_to_desktop(dpy, ev.xproperty.window);
}
}
else if (ev.xproperty.atom == winTDETTBAtom)
{
win * w = find_win(dpy, ev.xproperty.window);
if (w)
{
w->show_black_background = determine_window_transparent_to_black(dpy, ev.xproperty.window);
}
}
break;
default:
if (ev.type == damage_event + XDamageNotify)
{
/* printf("damaging win: %u\n",ev.xany.window);*/
damage_win (dpy, (XDamageNotifyEvent *) &ev);
repaint_root_overlay_window();
}
if (ev.type == xshape_event + ShapeNotify)
{
shape_win (dpy, (XShapeEvent *) &ev);
}
if (ev.type == shapeEvent)
{
win * w = find_win(dpy, ev.xany.window);
#if 1
if (w && w->shapable)
#endif
#if 0
if (w)
#endif
{
#if 0
XRectangle rect;
rect.x = ((XShapeEvent*)&ev)->x;
rect.y = ((XShapeEvent*)&ev)->y;
rect.width = ((XShapeEvent*)&ev)->width;
rect.height = ((XShapeEvent*)&ev)->height;
damage_shape(dpy, w, &rect);
#endif
#if 0
if (w->shadowSize != 0)
{
w->shadowSize = 0;
XRenderFreePicture (dpy, w->shadow);
w->shadow = None;
determine_mode(dpy, w);
if( w->extents != None )
XFixesDestroyRegion( dpy, w->extents );
w->extents = win_extents (dpy, w);
}
#endif
/*this is hardly efficient, but a current workaraound
shaping support isn't that good so far (e.g. we lack shaped shadows)
IDEA: use XRender to scale/shift a copy of the window and then blur it*/
#if 1
if (w->picture)
{
clipChanged = True;
repair_win (dpy, w);
}
#endif
}
}
break;
}
} while (QLength (dpy));
if (allDamage && !autoRedirect)
{
paint_all (dpy, allDamage);
XSync (dpy, False);
allDamage = None;
clipChanged = False;
}
}
XClearArea (dpy, root, 0, 0, 0, 0, True);
XSync (dpy, False);
}