12007c8b2Snia/* 22007c8b2Snia * Copyright © 2003 Keith Packard 32007c8b2Snia * 42007c8b2Snia * Permission to use, copy, modify, distribute, and sell this software and its 52007c8b2Snia * documentation for any purpose is hereby granted without fee, provided that 62007c8b2Snia * the above copyright notice appear in all copies and that both that 72007c8b2Snia * copyright notice and this permission notice appear in supporting 82007c8b2Snia * documentation, and that the name of Keith Packard not be used in 92007c8b2Snia * advertising or publicity pertaining to distribution of the software without 102007c8b2Snia * specific, written prior permission. Keith Packard makes no 112007c8b2Snia * representations about the suitability of this software for any purpose. It 122007c8b2Snia * is provided "as is" without express or implied warranty. 132007c8b2Snia * 142007c8b2Snia * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 152007c8b2Snia * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 162007c8b2Snia * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 172007c8b2Snia * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 182007c8b2Snia * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 192007c8b2Snia * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 202007c8b2Snia * PERFORMANCE OF THIS SOFTWARE. 212007c8b2Snia */ 222007c8b2Snia 232007c8b2Snia 242007c8b2Snia/* Modified by Matthew Hawn. I don't know what to say here so follow what it 252007c8b2Snia says above. Not that I can really do anything about it 262007c8b2Snia*/ 272007c8b2Snia 282007c8b2Snia#ifdef HAVE_CONFIG_H 292007c8b2Snia#include "config.h" 302007c8b2Snia#endif 312007c8b2Snia 322007c8b2Snia#include <stdlib.h> 332007c8b2Snia#include <stdio.h> 342007c8b2Snia#include <string.h> 352007c8b2Snia#include <math.h> 362007c8b2Snia#include <sys/poll.h> 372007c8b2Snia#include <sys/time.h> 382007c8b2Snia#include <time.h> 392007c8b2Snia#include <unistd.h> 402007c8b2Snia#include <getopt.h> 412007c8b2Snia#include <X11/Xlib.h> 422007c8b2Snia#include <X11/Xutil.h> 432007c8b2Snia#include <X11/Xatom.h> 442007c8b2Snia#include <X11/extensions/Xcomposite.h> 452007c8b2Snia#include <X11/extensions/Xdamage.h> 462007c8b2Snia#include <X11/extensions/Xrender.h> 472007c8b2Snia#include <X11/extensions/shape.h> 482007c8b2Snia 492007c8b2Snia#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2 502007c8b2Snia#define HAS_NAME_WINDOW_PIXMAP 1 512007c8b2Snia#endif 522007c8b2Snia 532007c8b2Snia#define CAN_DO_USABLE 0 542007c8b2Snia 552007c8b2Sniatypedef struct _ignore { 562007c8b2Snia struct _ignore *next; 572007c8b2Snia unsigned long sequence; 582007c8b2Snia} ignore; 592007c8b2Snia 602007c8b2Sniatypedef struct _win { 612007c8b2Snia struct _win *next; 622007c8b2Snia Window id; 632007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 642007c8b2Snia Pixmap pixmap; 652007c8b2Snia#endif 662007c8b2Snia XWindowAttributes a; 672007c8b2Snia#if CAN_DO_USABLE 682007c8b2Snia Bool usable; /* mapped and all damaged at one point */ 692007c8b2Snia XRectangle damage_bounds; /* bounds of damage */ 702007c8b2Snia#endif 712007c8b2Snia int mode; 722007c8b2Snia int damaged; 732007c8b2Snia Damage damage; 742007c8b2Snia Picture picture; 752007c8b2Snia Picture alphaPict; 762007c8b2Snia Picture shadowPict; 772007c8b2Snia XserverRegion borderSize; 782007c8b2Snia XserverRegion extents; 792007c8b2Snia Picture shadow; 802007c8b2Snia int shadow_dx; 812007c8b2Snia int shadow_dy; 822007c8b2Snia int shadow_width; 832007c8b2Snia int shadow_height; 842007c8b2Snia unsigned int opacity; 852007c8b2Snia Atom windowType; 862007c8b2Snia unsigned long damage_sequence; /* sequence when damage was created */ 872007c8b2Snia Bool shaped; 882007c8b2Snia XRectangle shape_bounds; 892007c8b2Snia 902007c8b2Snia /* for drawing translucent windows */ 912007c8b2Snia XserverRegion borderClip; 922007c8b2Snia struct _win *prev_trans; 932007c8b2Snia} win; 942007c8b2Snia 952007c8b2Sniatypedef struct _conv { 962007c8b2Snia int size; 972007c8b2Snia double *data; 982007c8b2Snia} conv; 992007c8b2Snia 1002007c8b2Sniatypedef struct _fade { 1012007c8b2Snia struct _fade *next; 1022007c8b2Snia win *w; 1032007c8b2Snia double cur; 1042007c8b2Snia double finish; 1052007c8b2Snia double step; 1062007c8b2Snia void (*callback) (Display *dpy, win *w, Bool gone); 1072007c8b2Snia Display *dpy; 1082007c8b2Snia Bool gone; 1092007c8b2Snia} fade; 1102007c8b2Snia 1112007c8b2Sniastatic win *list; 1122007c8b2Sniastatic fade *fades; 1132007c8b2Sniastatic int scr; 1142007c8b2Sniastatic Window root; 1152007c8b2Sniastatic Picture rootPicture; 1162007c8b2Sniastatic Picture rootBuffer; 1172007c8b2Sniastatic Picture blackPicture; 1182007c8b2Sniastatic Picture transBlackPicture; 1192007c8b2Sniastatic Picture rootTile; 1202007c8b2Sniastatic XserverRegion allDamage; 1212007c8b2Sniastatic Bool clipChanged; 1222007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 1232007c8b2Sniastatic Bool hasNamePixmap; 1242007c8b2Snia#endif 1252007c8b2Sniastatic int root_height, root_width; 1262007c8b2Sniastatic ignore *ignore_head, **ignore_tail = &ignore_head; 1272007c8b2Sniastatic int xfixes_event, xfixes_error; 1282007c8b2Sniastatic int damage_event, damage_error; 1292007c8b2Sniastatic int composite_event, composite_error; 1302007c8b2Sniastatic int render_event, render_error; 1312007c8b2Sniastatic int xshape_event, xshape_error; 1322007c8b2Sniastatic Bool synchronize; 1332007c8b2Sniastatic int composite_opcode; 1342007c8b2Snia 1352007c8b2Snia/* find these once and be done with it */ 1362007c8b2Sniastatic Atom opacityAtom; 1372007c8b2Sniastatic Atom winTypeAtom; 1382007c8b2Sniastatic Atom winDesktopAtom; 1392007c8b2Sniastatic Atom winDockAtom; 1402007c8b2Sniastatic Atom winToolbarAtom; 1412007c8b2Sniastatic Atom winMenuAtom; 1422007c8b2Sniastatic Atom winUtilAtom; 1432007c8b2Sniastatic Atom winSplashAtom; 1442007c8b2Sniastatic Atom winDialogAtom; 1452007c8b2Sniastatic Atom winNormalAtom; 1462007c8b2Snia 1472007c8b2Snia/* opacity property name; sometime soon I'll write up an EWMH spec for it */ 1482007c8b2Snia#define OPACITY_PROP "_NET_WM_WINDOW_OPACITY" 1492007c8b2Snia 1502007c8b2Snia#define TRANSLUCENT 0xe0000000 1512007c8b2Snia#define OPAQUE 0xffffffff 1522007c8b2Snia 1532007c8b2Sniastatic conv *gaussianMap; 1542007c8b2Snia 1552007c8b2Snia#define WINDOW_SOLID 0 1562007c8b2Snia#define WINDOW_TRANS 1 1572007c8b2Snia#define WINDOW_ARGB 2 1582007c8b2Snia 1592007c8b2Snia#define TRANS_OPACITY 0.75 1602007c8b2Snia 1612007c8b2Snia#define DEBUG_REPAINT 0 1622007c8b2Snia#define DEBUG_EVENTS 0 1632007c8b2Snia#define DEBUG_SHAPE 0 1642007c8b2Snia#define MONITOR_REPAINT 0 1652007c8b2Snia 1662007c8b2Snia#define SHADOWS 1 1672007c8b2Snia#define SHARP_SHADOW 0 1682007c8b2Snia 1692007c8b2Sniatypedef enum _compMode { 1702007c8b2Snia CompSimple, /* looks like a regular X server */ 1712007c8b2Snia CompServerShadows, /* use window alpha for shadow; sharp, but precise */ 1722007c8b2Snia CompClientShadows, /* use window extents for shadow, blurred */ 1732007c8b2Snia} CompMode; 1742007c8b2Snia 1752007c8b2Sniastatic void 1762007c8b2Sniadetermine_mode(Display *dpy, win *w); 1772007c8b2Snia 1782007c8b2Sniastatic double 1792007c8b2Sniaget_opacity_percent(Display *dpy, win *w, double def); 1802007c8b2Snia 1812007c8b2Sniastatic XserverRegion 1822007c8b2Sniawin_extents (Display *dpy, win *w); 1832007c8b2Snia 1842007c8b2Sniastatic CompMode compMode = CompSimple; 1852007c8b2Snia 1862007c8b2Sniastatic int shadowRadius = 12; 1872007c8b2Sniastatic int shadowOffsetX = -15; 1882007c8b2Sniastatic int shadowOffsetY = -15; 1892007c8b2Sniastatic double shadowOpacity = .75; 1902007c8b2Snia 1912007c8b2Sniastatic double fade_in_step = 0.028; 1922007c8b2Sniastatic double fade_out_step = 0.03; 1932007c8b2Sniastatic int fade_delta = 10; 1942007c8b2Sniastatic int fade_time = 0; 1952007c8b2Sniastatic Bool fadeWindows = False; 1962007c8b2Sniastatic Bool excludeDockShadows = False; 1972007c8b2Sniastatic Bool fadeTrans = False; 1982007c8b2Snia 1992007c8b2Sniastatic Bool autoRedirect = False; 2002007c8b2Snia 2012007c8b2Snia/* For shadow precomputation */ 2022007c8b2Sniastatic int Gsize = -1; 2032007c8b2Sniastatic unsigned char *shadowCorner = NULL; 2042007c8b2Sniastatic unsigned char *shadowTop = NULL; 2052007c8b2Snia 2062007c8b2Sniastatic int 2072007c8b2Sniaget_time_in_milliseconds (void) 2082007c8b2Snia{ 2092007c8b2Snia struct timeval tv; 2102007c8b2Snia 2112007c8b2Snia gettimeofday (&tv, NULL); 2122007c8b2Snia return tv.tv_sec * 1000 + tv.tv_usec / 1000; 2132007c8b2Snia} 2142007c8b2Snia 2152007c8b2Sniastatic fade * 2162007c8b2Sniafind_fade (win *w) 2172007c8b2Snia{ 2182007c8b2Snia fade *f; 2192007c8b2Snia 2202007c8b2Snia for (f = fades; f; f = f->next) 2212007c8b2Snia { 2222007c8b2Snia if (f->w == w) 2232007c8b2Snia return f; 2242007c8b2Snia } 2252007c8b2Snia return NULL; 2262007c8b2Snia} 2272007c8b2Snia 2282007c8b2Sniastatic void 2292007c8b2Sniadequeue_fade (Display *dpy, fade *f) 2302007c8b2Snia{ 2312007c8b2Snia fade **prev; 2322007c8b2Snia 2332007c8b2Snia for (prev = &fades; *prev; prev = &(*prev)->next) 2342007c8b2Snia if (*prev == f) 2352007c8b2Snia { 2362007c8b2Snia *prev = f->next; 2372007c8b2Snia if (f->callback) 2382007c8b2Snia (*f->callback) (dpy, f->w, f->gone); 2392007c8b2Snia free (f); 2402007c8b2Snia break; 2412007c8b2Snia } 2422007c8b2Snia} 2432007c8b2Snia 2442007c8b2Sniastatic void 2452007c8b2Sniacleanup_fade (Display *dpy, win *w) 2462007c8b2Snia{ 2472007c8b2Snia fade *f = find_fade (w); 2482007c8b2Snia if (f) 2492007c8b2Snia dequeue_fade (dpy, f); 2502007c8b2Snia} 2512007c8b2Snia 2522007c8b2Sniastatic void 2532007c8b2Sniaenqueue_fade (Display *dpy, fade *f) 2542007c8b2Snia{ 2552007c8b2Snia if (!fades) 2562007c8b2Snia fade_time = get_time_in_milliseconds () + fade_delta; 2572007c8b2Snia f->next = fades; 2582007c8b2Snia fades = f; 2592007c8b2Snia} 2602007c8b2Snia 2612007c8b2Sniastatic void 2622007c8b2Sniaset_fade (Display *dpy, win *w, double start, double finish, double step, 2632007c8b2Snia void (*callback) (Display *dpy, win *w, Bool gone), 2642007c8b2Snia Bool gone, Bool exec_callback, Bool override) 2652007c8b2Snia{ 2662007c8b2Snia fade *f; 2672007c8b2Snia 2682007c8b2Snia f = find_fade (w); 2692007c8b2Snia if (!f) 2702007c8b2Snia { 2712007c8b2Snia f = malloc (sizeof (fade)); 2722007c8b2Snia f->next = NULL; 2732007c8b2Snia f->w = w; 2742007c8b2Snia f->cur = start; 2752007c8b2Snia enqueue_fade (dpy, f); 2762007c8b2Snia } 2772007c8b2Snia else if(!override) 2782007c8b2Snia return; 2792007c8b2Snia else 2802007c8b2Snia { 2812007c8b2Snia if (exec_callback) 2822007c8b2Snia if (f->callback) 2832007c8b2Snia (*f->callback)(dpy, f->w, f->gone); 2842007c8b2Snia } 2852007c8b2Snia 2862007c8b2Snia if (finish < 0) 2872007c8b2Snia finish = 0; 2882007c8b2Snia if (finish > 1) 2892007c8b2Snia finish = 1; 2902007c8b2Snia f->finish = finish; 2912007c8b2Snia if (f->cur < finish) 2922007c8b2Snia f->step = step; 2932007c8b2Snia else if (f->cur > finish) 2942007c8b2Snia f->step = -step; 2952007c8b2Snia f->callback = callback; 2962007c8b2Snia f->gone = gone; 2972007c8b2Snia w->opacity = f->cur * OPAQUE; 2982007c8b2Snia#if 0 2992007c8b2Snia printf ("set_fade start %g step %g\n", f->cur, f->step); 3002007c8b2Snia#endif 3012007c8b2Snia determine_mode (dpy, w); 3022007c8b2Snia if (w->shadow) 3032007c8b2Snia { 3042007c8b2Snia XRenderFreePicture (dpy, w->shadow); 3052007c8b2Snia w->shadow = None; 3062007c8b2Snia w->extents = win_extents (dpy, w); 3072007c8b2Snia } 3082007c8b2Snia} 3092007c8b2Snia 3102007c8b2Sniastatic int 3112007c8b2Sniafade_timeout (void) 3122007c8b2Snia{ 3132007c8b2Snia int now; 3142007c8b2Snia int delta; 3152007c8b2Snia if (!fades) 3162007c8b2Snia return -1; 3172007c8b2Snia now = get_time_in_milliseconds(); 3182007c8b2Snia delta = fade_time - now; 3192007c8b2Snia if (delta < 0) 3202007c8b2Snia delta = 0; 3212007c8b2Snia/* printf ("timeout %d\n", delta); */ 3222007c8b2Snia return delta; 3232007c8b2Snia} 3242007c8b2Snia 3252007c8b2Sniastatic void 3262007c8b2Sniarun_fades (Display *dpy) 3272007c8b2Snia{ 3282007c8b2Snia int now = get_time_in_milliseconds(); 3292007c8b2Snia fade *next = fades; 3302007c8b2Snia int steps; 3312007c8b2Snia Bool need_dequeue; 3322007c8b2Snia 3332007c8b2Snia#if 0 3342007c8b2Snia printf ("run fades\n"); 3352007c8b2Snia#endif 3362007c8b2Snia if (fade_time - now > 0) 3372007c8b2Snia return; 3382007c8b2Snia steps = 1 + (now - fade_time) / fade_delta; 3392007c8b2Snia 3402007c8b2Snia while (next) 3412007c8b2Snia { 3422007c8b2Snia fade *f = next; 3432007c8b2Snia win *w = f->w; 3442007c8b2Snia next = f->next; 3452007c8b2Snia f->cur += f->step * steps; 3462007c8b2Snia if (f->cur >= 1) 3472007c8b2Snia f->cur = 1; 3482007c8b2Snia else if (f->cur < 0) 3492007c8b2Snia f->cur = 0; 3502007c8b2Snia#if 0 3512007c8b2Snia printf ("opacity now %g\n", f->cur); 3522007c8b2Snia#endif 3532007c8b2Snia w->opacity = f->cur * OPAQUE; 3542007c8b2Snia need_dequeue = False; 3552007c8b2Snia if (f->step > 0) 3562007c8b2Snia { 3572007c8b2Snia if (f->cur >= f->finish) 3582007c8b2Snia { 3592007c8b2Snia w->opacity = f->finish*OPAQUE; 3602007c8b2Snia need_dequeue = True; 3612007c8b2Snia } 3622007c8b2Snia } 3632007c8b2Snia else 3642007c8b2Snia { 3652007c8b2Snia if (f->cur <= f->finish) 3662007c8b2Snia { 3672007c8b2Snia w->opacity = f->finish*OPAQUE; 3682007c8b2Snia need_dequeue = True; 3692007c8b2Snia } 3702007c8b2Snia } 3712007c8b2Snia determine_mode (dpy, w); 3722007c8b2Snia if (w->shadow) 3732007c8b2Snia { 3742007c8b2Snia XRenderFreePicture (dpy, w->shadow); 3752007c8b2Snia w->shadow = None; 3762007c8b2Snia w->extents = win_extents(dpy, w); 3772007c8b2Snia } 3782007c8b2Snia /* Must do this last as it might destroy f->w in callbacks */ 3792007c8b2Snia if (need_dequeue) 3802007c8b2Snia dequeue_fade (dpy, f); 3812007c8b2Snia } 3822007c8b2Snia fade_time = now + fade_delta; 3832007c8b2Snia} 3842007c8b2Snia 3852007c8b2Sniastatic double 3862007c8b2Sniagaussian (double r, double x, double y) 3872007c8b2Snia{ 3882007c8b2Snia return ((1 / (sqrt (2 * M_PI * r))) * 3892007c8b2Snia exp ((- (x * x + y * y)) / (2 * r * r))); 3902007c8b2Snia} 3912007c8b2Snia 3922007c8b2Snia 3932007c8b2Sniastatic conv * 3942007c8b2Sniamake_gaussian_map (Display *dpy, double r) 3952007c8b2Snia{ 3962007c8b2Snia conv *c; 3972007c8b2Snia int size = ((int) ceil ((r * 3)) + 1) & ~1; 3982007c8b2Snia int center = size / 2; 3992007c8b2Snia int x, y; 4002007c8b2Snia double t; 4012007c8b2Snia double g; 4022007c8b2Snia 4032007c8b2Snia c = malloc (sizeof (conv) + size * size * sizeof (double)); 4042007c8b2Snia c->size = size; 4052007c8b2Snia c->data = (double *) (c + 1); 4062007c8b2Snia t = 0.0; 4072007c8b2Snia for (y = 0; y < size; y++) 4082007c8b2Snia for (x = 0; x < size; x++) 4092007c8b2Snia { 4102007c8b2Snia g = gaussian (r, (double) (x - center), (double) (y - center)); 4112007c8b2Snia t += g; 4122007c8b2Snia c->data[y * size + x] = g; 4132007c8b2Snia } 4142007c8b2Snia/* printf ("gaussian total %f\n", t); */ 4152007c8b2Snia for (y = 0; y < size; y++) 4162007c8b2Snia for (x = 0; x < size; x++) 4172007c8b2Snia { 4182007c8b2Snia c->data[y*size + x] /= t; 4192007c8b2Snia } 4202007c8b2Snia return c; 4212007c8b2Snia} 4222007c8b2Snia 4232007c8b2Snia/* 4242007c8b2Snia * A picture will help 4252007c8b2Snia * 4262007c8b2Snia * -center 0 width width+center 4272007c8b2Snia * -center +-----+-------------------+-----+ 4282007c8b2Snia * | | | | 4292007c8b2Snia * | | | | 4302007c8b2Snia * 0 +-----+-------------------+-----+ 4312007c8b2Snia * | | | | 4322007c8b2Snia * | | | | 4332007c8b2Snia * | | | | 4342007c8b2Snia * height +-----+-------------------+-----+ 4352007c8b2Snia * | | | | 4362007c8b2Snia * height+ | | | | 4372007c8b2Snia * center +-----+-------------------+-----+ 4382007c8b2Snia */ 4392007c8b2Snia 4402007c8b2Sniastatic unsigned char 4412007c8b2Sniasum_gaussian (conv *map, double opacity, int x, int y, int width, int height) 4422007c8b2Snia{ 4432007c8b2Snia int fx, fy; 4442007c8b2Snia double *g_data; 4452007c8b2Snia double *g_line = map->data; 4462007c8b2Snia int g_size = map->size; 4472007c8b2Snia int center = g_size / 2; 4482007c8b2Snia int fx_start, fx_end; 4492007c8b2Snia int fy_start, fy_end; 4502007c8b2Snia double v; 4512007c8b2Snia 4522007c8b2Snia /* 4532007c8b2Snia * Compute set of filter values which are "in range", 4542007c8b2Snia * that's the set with: 4552007c8b2Snia * 0 <= x + (fx-center) && x + (fx-center) < width && 4562007c8b2Snia * 0 <= y + (fy-center) && y + (fy-center) < height 4572007c8b2Snia * 4582007c8b2Snia * 0 <= x + (fx - center) x + fx - center < width 4592007c8b2Snia * center - x <= fx fx < width + center - x 4602007c8b2Snia */ 4612007c8b2Snia 4622007c8b2Snia fx_start = center - x; 4632007c8b2Snia if (fx_start < 0) 4642007c8b2Snia fx_start = 0; 4652007c8b2Snia fx_end = width + center - x; 4662007c8b2Snia if (fx_end > g_size) 4672007c8b2Snia fx_end = g_size; 4682007c8b2Snia 4692007c8b2Snia fy_start = center - y; 4702007c8b2Snia if (fy_start < 0) 4712007c8b2Snia fy_start = 0; 4722007c8b2Snia fy_end = height + center - y; 4732007c8b2Snia if (fy_end > g_size) 4742007c8b2Snia fy_end = g_size; 4752007c8b2Snia 4762007c8b2Snia g_line = g_line + fy_start * g_size + fx_start; 4772007c8b2Snia 4782007c8b2Snia v = 0; 4792007c8b2Snia for (fy = fy_start; fy < fy_end; fy++) 4802007c8b2Snia { 4812007c8b2Snia g_data = g_line; 4822007c8b2Snia g_line += g_size; 4832007c8b2Snia 4842007c8b2Snia for (fx = fx_start; fx < fx_end; fx++) 4852007c8b2Snia v += *g_data++; 4862007c8b2Snia } 4872007c8b2Snia if (v > 1) 4882007c8b2Snia v = 1; 4892007c8b2Snia 4902007c8b2Snia return ((unsigned char) (v * opacity * 255.0)); 4912007c8b2Snia} 4922007c8b2Snia 4932007c8b2Snia/* precompute shadow corners and sides to save time for large windows */ 4942007c8b2Sniastatic void 4952007c8b2Sniapresum_gaussian (conv *map) 4962007c8b2Snia{ 4972007c8b2Snia int center = map->size/2; 4982007c8b2Snia int opacity, x, y; 4992007c8b2Snia 5002007c8b2Snia Gsize = map->size; 5012007c8b2Snia 5022007c8b2Snia if (shadowCorner) 5032007c8b2Snia free ((void *)shadowCorner); 5042007c8b2Snia if (shadowTop) 5052007c8b2Snia free ((void *)shadowTop); 5062007c8b2Snia 5072007c8b2Snia shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26)); 5082007c8b2Snia shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26)); 5092007c8b2Snia 5102007c8b2Snia for (x = 0; x <= Gsize; x++) 5112007c8b2Snia { 5122007c8b2Snia shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2); 5132007c8b2Snia for(opacity = 0; opacity < 25; opacity++) 5142007c8b2Snia shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25; 5152007c8b2Snia for(y = 0; y <= x; y++) 5162007c8b2Snia { 5172007c8b2Snia shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] 5182007c8b2Snia = sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2); 5192007c8b2Snia shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] 5202007c8b2Snia = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; 5212007c8b2Snia for(opacity = 0; opacity < 25; opacity++) 5222007c8b2Snia shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] 5232007c8b2Snia = shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] 5242007c8b2Snia = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25; 5252007c8b2Snia } 5262007c8b2Snia } 5272007c8b2Snia} 5282007c8b2Snia 5292007c8b2Sniastatic XImage * 5302007c8b2Sniamake_shadow (Display *dpy, double opacity, int width, int height) 5312007c8b2Snia{ 5322007c8b2Snia XImage *ximage; 5332007c8b2Snia unsigned char *data; 5342007c8b2Snia int gsize = gaussianMap->size; 5352007c8b2Snia int ylimit, xlimit; 5362007c8b2Snia int swidth = width + gsize; 5372007c8b2Snia int sheight = height + gsize; 5382007c8b2Snia int center = gsize / 2; 5392007c8b2Snia int x, y; 5402007c8b2Snia unsigned char d; 5412007c8b2Snia int x_diff; 5422007c8b2Snia int opacity_int = (int)(opacity * 25); 5432007c8b2Snia data = malloc (swidth * sheight * sizeof (unsigned char)); 5442007c8b2Snia if (!data) 5452007c8b2Snia return NULL; 5462007c8b2Snia ximage = XCreateImage (dpy, 5472007c8b2Snia DefaultVisual(dpy, DefaultScreen(dpy)), 5482007c8b2Snia 8, 5492007c8b2Snia ZPixmap, 5502007c8b2Snia 0, 5512007c8b2Snia (char *) data, 5522007c8b2Snia swidth, sheight, 8, swidth * sizeof (unsigned char)); 5532007c8b2Snia if (!ximage) 5542007c8b2Snia { 5552007c8b2Snia free (data); 5562007c8b2Snia return NULL; 5572007c8b2Snia } 5582007c8b2Snia /* 5592007c8b2Snia * Build the gaussian in sections 5602007c8b2Snia */ 5612007c8b2Snia 5622007c8b2Snia /* 5632007c8b2Snia * center (fill the complete data array) 5642007c8b2Snia */ 5652007c8b2Snia if (Gsize > 0) 5662007c8b2Snia d = shadowTop[opacity_int * (Gsize + 1) + Gsize]; 5672007c8b2Snia else 5682007c8b2Snia d = sum_gaussian (gaussianMap, opacity, center, center, width, height); 5692007c8b2Snia memset(data, d, sheight * swidth); 5702007c8b2Snia 5712007c8b2Snia /* 5722007c8b2Snia * corners 5732007c8b2Snia */ 5742007c8b2Snia ylimit = gsize; 5752007c8b2Snia if (ylimit > sheight / 2) 5762007c8b2Snia ylimit = (sheight + 1) / 2; 5772007c8b2Snia xlimit = gsize; 5782007c8b2Snia if (xlimit > swidth / 2) 5792007c8b2Snia xlimit = (swidth + 1) / 2; 5802007c8b2Snia 5812007c8b2Snia for (y = 0; y < ylimit; y++) 5822007c8b2Snia for (x = 0; x < xlimit; x++) 5832007c8b2Snia { 5842007c8b2Snia if (xlimit == Gsize && ylimit == Gsize) 5852007c8b2Snia d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; 5862007c8b2Snia else 5872007c8b2Snia d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height); 5882007c8b2Snia data[y * swidth + x] = d; 5892007c8b2Snia data[(sheight - y - 1) * swidth + x] = d; 5902007c8b2Snia data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; 5912007c8b2Snia data[y * swidth + (swidth - x - 1)] = d; 5922007c8b2Snia } 5932007c8b2Snia 5942007c8b2Snia /* 5952007c8b2Snia * top/bottom 5962007c8b2Snia */ 5972007c8b2Snia x_diff = swidth - (gsize * 2); 5982007c8b2Snia if (x_diff > 0 && ylimit > 0) 5992007c8b2Snia { 6002007c8b2Snia for (y = 0; y < ylimit; y++) 6012007c8b2Snia { 6022007c8b2Snia if (ylimit == Gsize) 6032007c8b2Snia d = shadowTop[opacity_int * (Gsize + 1) + y]; 6042007c8b2Snia else 6052007c8b2Snia d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height); 6062007c8b2Snia memset (&data[y * swidth + gsize], d, x_diff); 6072007c8b2Snia memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff); 6082007c8b2Snia } 6092007c8b2Snia } 6102007c8b2Snia 6112007c8b2Snia /* 6122007c8b2Snia * sides 6132007c8b2Snia */ 6142007c8b2Snia 6152007c8b2Snia for (x = 0; x < xlimit; x++) 6162007c8b2Snia { 6172007c8b2Snia if (xlimit == Gsize) 6182007c8b2Snia d = shadowTop[opacity_int * (Gsize + 1) + x]; 6192007c8b2Snia else 6202007c8b2Snia d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height); 6212007c8b2Snia for (y = gsize; y < sheight - gsize; y++) 6222007c8b2Snia { 6232007c8b2Snia data[y * swidth + x] = d; 6242007c8b2Snia data[y * swidth + (swidth - x - 1)] = d; 6252007c8b2Snia } 6262007c8b2Snia } 6272007c8b2Snia 6282007c8b2Snia return ximage; 6292007c8b2Snia} 6302007c8b2Snia 6312007c8b2Sniastatic Picture 6322007c8b2Sniashadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp) 6332007c8b2Snia{ 6342007c8b2Snia XImage *shadowImage; 6352007c8b2Snia Pixmap shadowPixmap; 6362007c8b2Snia Picture shadowPicture; 6372007c8b2Snia GC gc; 6382007c8b2Snia 6392007c8b2Snia shadowImage = make_shadow (dpy, opacity, width, height); 6402007c8b2Snia if (!shadowImage) 6412007c8b2Snia return None; 6422007c8b2Snia shadowPixmap = XCreatePixmap (dpy, root, 6432007c8b2Snia shadowImage->width, 6442007c8b2Snia shadowImage->height, 6452007c8b2Snia 8); 6462007c8b2Snia if (!shadowPixmap) 6472007c8b2Snia { 6482007c8b2Snia XDestroyImage (shadowImage); 6492007c8b2Snia return None; 6502007c8b2Snia } 6512007c8b2Snia 6522007c8b2Snia shadowPicture = XRenderCreatePicture (dpy, shadowPixmap, 6532007c8b2Snia XRenderFindStandardFormat (dpy, PictStandardA8), 6542007c8b2Snia 0, NULL); 6552007c8b2Snia if (!shadowPicture) 6562007c8b2Snia { 6572007c8b2Snia XDestroyImage (shadowImage); 6582007c8b2Snia XFreePixmap (dpy, shadowPixmap); 6592007c8b2Snia return (Picture)None; 6602007c8b2Snia } 6612007c8b2Snia 6622007c8b2Snia gc = XCreateGC (dpy, shadowPixmap, 0, NULL); 6632007c8b2Snia if (!gc) 6642007c8b2Snia { 6652007c8b2Snia XDestroyImage (shadowImage); 6662007c8b2Snia XFreePixmap (dpy, shadowPixmap); 6672007c8b2Snia XRenderFreePicture (dpy, shadowPicture); 6682007c8b2Snia return (Picture)None; 6692007c8b2Snia } 6702007c8b2Snia 6712007c8b2Snia XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, 6722007c8b2Snia shadowImage->width, 6732007c8b2Snia shadowImage->height); 6742007c8b2Snia *wp = shadowImage->width; 6752007c8b2Snia *hp = shadowImage->height; 6762007c8b2Snia XFreeGC (dpy, gc); 6772007c8b2Snia XDestroyImage (shadowImage); 6782007c8b2Snia XFreePixmap (dpy, shadowPixmap); 6792007c8b2Snia return shadowPicture; 6802007c8b2Snia} 6812007c8b2Snia 6822007c8b2Sniastatic Picture 6832007c8b2Sniasolid_picture (Display *dpy, Bool argb, double a, double r, double g, double b) 6842007c8b2Snia{ 6852007c8b2Snia Pixmap pixmap; 6862007c8b2Snia Picture picture; 6872007c8b2Snia XRenderPictureAttributes pa; 6882007c8b2Snia XRenderColor c; 6892007c8b2Snia 6902007c8b2Snia pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8); 6912007c8b2Snia if (!pixmap) 6922007c8b2Snia return None; 6932007c8b2Snia 6942007c8b2Snia pa.repeat = True; 6952007c8b2Snia picture = XRenderCreatePicture (dpy, pixmap, 6962007c8b2Snia XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8), 6972007c8b2Snia CPRepeat, 6982007c8b2Snia &pa); 6992007c8b2Snia if (!picture) 7002007c8b2Snia { 7012007c8b2Snia XFreePixmap (dpy, pixmap); 7022007c8b2Snia return None; 7032007c8b2Snia } 7042007c8b2Snia 7052007c8b2Snia c.alpha = a * 0xffff; 7062007c8b2Snia c.red = r * 0xffff; 7072007c8b2Snia c.green = g * 0xffff; 7082007c8b2Snia c.blue = b * 0xffff; 7092007c8b2Snia XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); 7102007c8b2Snia XFreePixmap (dpy, pixmap); 7112007c8b2Snia return picture; 7122007c8b2Snia} 7132007c8b2Snia 7142007c8b2Sniastatic void 7152007c8b2Sniadiscard_ignore (Display *dpy, unsigned long sequence) 7162007c8b2Snia{ 7172007c8b2Snia while (ignore_head) 7182007c8b2Snia { 7192007c8b2Snia if ((long) (sequence - ignore_head->sequence) > 0) 7202007c8b2Snia { 7212007c8b2Snia ignore *next = ignore_head->next; 7222007c8b2Snia free (ignore_head); 7232007c8b2Snia ignore_head = next; 7242007c8b2Snia if (!ignore_head) 7252007c8b2Snia ignore_tail = &ignore_head; 7262007c8b2Snia } 7272007c8b2Snia else 7282007c8b2Snia break; 7292007c8b2Snia } 7302007c8b2Snia} 7312007c8b2Snia 7322007c8b2Sniastatic void 7332007c8b2Sniaset_ignore (Display *dpy, unsigned long sequence) 7342007c8b2Snia{ 7352007c8b2Snia ignore *i = malloc (sizeof (ignore)); 7362007c8b2Snia if (!i) 7372007c8b2Snia return; 7382007c8b2Snia i->sequence = sequence; 7392007c8b2Snia i->next = NULL; 7402007c8b2Snia *ignore_tail = i; 7412007c8b2Snia ignore_tail = &i->next; 7422007c8b2Snia} 7432007c8b2Snia 7442007c8b2Sniastatic int 7452007c8b2Sniashould_ignore (Display *dpy, unsigned long sequence) 7462007c8b2Snia{ 7472007c8b2Snia discard_ignore (dpy, sequence); 7482007c8b2Snia return ignore_head && ignore_head->sequence == sequence; 7492007c8b2Snia} 7502007c8b2Snia 7512007c8b2Sniastatic win * 7522007c8b2Sniafind_win (Display *dpy, Window id) 7532007c8b2Snia{ 7542007c8b2Snia win *w; 7552007c8b2Snia 7562007c8b2Snia for (w = list; w; w = w->next) 7572007c8b2Snia if (w->id == id) 7582007c8b2Snia return w; 7592007c8b2Snia return NULL; 7602007c8b2Snia} 7612007c8b2Snia 7622007c8b2Sniastatic const char *backgroundProps[] = { 7632007c8b2Snia "_XROOTPMAP_ID", 7642007c8b2Snia "_XSETROOT_ID", 7652007c8b2Snia NULL, 7662007c8b2Snia}; 7672007c8b2Snia 7682007c8b2Sniastatic Picture 7692007c8b2Sniaroot_tile (Display *dpy) 7702007c8b2Snia{ 7712007c8b2Snia Picture picture; 7722007c8b2Snia Atom actual_type; 7732007c8b2Snia Pixmap pixmap; 7742007c8b2Snia int actual_format; 7752007c8b2Snia unsigned long nitems; 7762007c8b2Snia unsigned long bytes_after; 7772007c8b2Snia unsigned char *prop; 7782007c8b2Snia Bool fill; 7792007c8b2Snia XRenderPictureAttributes pa; 7802007c8b2Snia int p; 7812007c8b2Snia 7822007c8b2Snia pixmap = None; 7832007c8b2Snia for (p = 0; backgroundProps[p]; p++) 7842007c8b2Snia { 7852007c8b2Snia if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False), 7862007c8b2Snia 0, 4, False, AnyPropertyType, 7872007c8b2Snia &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success && 7882007c8b2Snia actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1) 7892007c8b2Snia { 7902007c8b2Snia memcpy (&pixmap, prop, 4); 7912007c8b2Snia XFree (prop); 7922007c8b2Snia fill = False; 7932007c8b2Snia break; 7942007c8b2Snia } 7952007c8b2Snia } 7962007c8b2Snia if (!pixmap) 7972007c8b2Snia { 7982007c8b2Snia pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr)); 7992007c8b2Snia fill = True; 8002007c8b2Snia } 8012007c8b2Snia pa.repeat = True; 8022007c8b2Snia picture = XRenderCreatePicture (dpy, pixmap, 8032007c8b2Snia XRenderFindVisualFormat (dpy, 8042007c8b2Snia DefaultVisual (dpy, scr)), 8052007c8b2Snia CPRepeat, &pa); 8062007c8b2Snia if (fill) 8072007c8b2Snia { 8082007c8b2Snia XRenderColor c; 8092007c8b2Snia 8102007c8b2Snia c.red = c.green = c.blue = 0x8080; 8112007c8b2Snia c.alpha = 0xffff; 8122007c8b2Snia XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 8132007c8b2Snia 0, 0, 1, 1); 8142007c8b2Snia } 8152007c8b2Snia return picture; 8162007c8b2Snia} 8172007c8b2Snia 8182007c8b2Sniastatic void 8192007c8b2Sniapaint_root (Display *dpy) 8202007c8b2Snia{ 8212007c8b2Snia if (!rootTile) 8222007c8b2Snia rootTile = root_tile (dpy); 8232007c8b2Snia 8242007c8b2Snia XRenderComposite (dpy, PictOpSrc, 8252007c8b2Snia rootTile, None, rootBuffer, 8262007c8b2Snia 0, 0, 0, 0, 0, 0, root_width, root_height); 8272007c8b2Snia} 8282007c8b2Snia 8292007c8b2Sniastatic XserverRegion 8302007c8b2Sniawin_extents (Display *dpy, win *w) 8312007c8b2Snia{ 8322007c8b2Snia XRectangle r; 8332007c8b2Snia 8342007c8b2Snia r.x = w->a.x; 8352007c8b2Snia r.y = w->a.y; 8362007c8b2Snia r.width = w->a.width + w->a.border_width * 2; 8372007c8b2Snia r.height = w->a.height + w->a.border_width * 2; 8382007c8b2Snia if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) 8392007c8b2Snia { 8402007c8b2Snia if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) 8412007c8b2Snia { 8422007c8b2Snia XRectangle sr; 8432007c8b2Snia 8442007c8b2Snia if (compMode == CompServerShadows) 8452007c8b2Snia { 8462007c8b2Snia w->shadow_dx = 2; 8472007c8b2Snia w->shadow_dy = 7; 8482007c8b2Snia w->shadow_width = w->a.width; 8492007c8b2Snia w->shadow_height = w->a.height; 8502007c8b2Snia } 8512007c8b2Snia else 8522007c8b2Snia { 8532007c8b2Snia w->shadow_dx = shadowOffsetX; 8542007c8b2Snia w->shadow_dy = shadowOffsetY; 8552007c8b2Snia if (!w->shadow) 8562007c8b2Snia { 8572007c8b2Snia double opacity = shadowOpacity; 8582007c8b2Snia if (w->mode == WINDOW_TRANS) 8592007c8b2Snia opacity = opacity * ((double)w->opacity)/((double)OPAQUE); 8602007c8b2Snia w->shadow = shadow_picture (dpy, opacity, w->alphaPict, 8612007c8b2Snia w->a.width + w->a.border_width * 2, 8622007c8b2Snia w->a.height + w->a.border_width * 2, 8632007c8b2Snia &w->shadow_width, &w->shadow_height); 8642007c8b2Snia } 8652007c8b2Snia } 8662007c8b2Snia sr.x = w->a.x + w->shadow_dx; 8672007c8b2Snia sr.y = w->a.y + w->shadow_dy; 8682007c8b2Snia sr.width = w->shadow_width; 8692007c8b2Snia sr.height = w->shadow_height; 8702007c8b2Snia if (sr.x < r.x) 8712007c8b2Snia { 8722007c8b2Snia r.width = (r.x + r.width) - sr.x; 8732007c8b2Snia r.x = sr.x; 8742007c8b2Snia } 8752007c8b2Snia if (sr.y < r.y) 8762007c8b2Snia { 8772007c8b2Snia r.height = (r.y + r.height) - sr.y; 8782007c8b2Snia r.y = sr.y; 8792007c8b2Snia } 8802007c8b2Snia if (sr.x + sr.width > r.x + r.width) 8812007c8b2Snia r.width = sr.x + sr.width - r.x; 8822007c8b2Snia if (sr.y + sr.height > r.y + r.height) 8832007c8b2Snia r.height = sr.y + sr.height - r.y; 8842007c8b2Snia } 8852007c8b2Snia } 8862007c8b2Snia return XFixesCreateRegion (dpy, &r, 1); 8872007c8b2Snia} 8882007c8b2Snia 8892007c8b2Sniastatic XserverRegion 8902007c8b2Sniaborder_size (Display *dpy, win *w) 8912007c8b2Snia{ 8922007c8b2Snia XserverRegion border; 8932007c8b2Snia /* 8942007c8b2Snia * if window doesn't exist anymore, this will generate an error 8952007c8b2Snia * as well as not generate a region. Perhaps a better XFixes 8962007c8b2Snia * architecture would be to have a request that copies instead 8972007c8b2Snia * of creates, that way you'd just end up with an empty region 8982007c8b2Snia * instead of an invalid XID. 8992007c8b2Snia */ 9002007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 9012007c8b2Snia border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding); 9022007c8b2Snia /* translate this */ 9032007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 9042007c8b2Snia XFixesTranslateRegion (dpy, border, 9052007c8b2Snia w->a.x + w->a.border_width, 9062007c8b2Snia w->a.y + w->a.border_width); 9072007c8b2Snia return border; 9082007c8b2Snia} 9092007c8b2Snia 9102007c8b2Sniastatic void 9112007c8b2Sniapaint_all (Display *dpy, XserverRegion region) 9122007c8b2Snia{ 9132007c8b2Snia win *w; 9142007c8b2Snia win *t = NULL; 9152007c8b2Snia 9162007c8b2Snia if (!region) 9172007c8b2Snia { 9182007c8b2Snia XRectangle r; 9192007c8b2Snia r.x = 0; 9202007c8b2Snia r.y = 0; 9212007c8b2Snia r.width = root_width; 9222007c8b2Snia r.height = root_height; 9232007c8b2Snia region = XFixesCreateRegion (dpy, &r, 1); 9242007c8b2Snia } 9252007c8b2Snia#if MONITOR_REPAINT 9262007c8b2Snia rootBuffer = rootPicture; 9272007c8b2Snia#else 9282007c8b2Snia if (!rootBuffer) 9292007c8b2Snia { 9302007c8b2Snia Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height, 9312007c8b2Snia DefaultDepth (dpy, scr)); 9322007c8b2Snia rootBuffer = XRenderCreatePicture (dpy, rootPixmap, 9332007c8b2Snia XRenderFindVisualFormat (dpy, 9342007c8b2Snia DefaultVisual (dpy, scr)), 9352007c8b2Snia 0, NULL); 9362007c8b2Snia XFreePixmap (dpy, rootPixmap); 9372007c8b2Snia } 9382007c8b2Snia#endif 9392007c8b2Snia XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region); 9402007c8b2Snia#if MONITOR_REPAINT 9412007c8b2Snia XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture, 9422007c8b2Snia 0, 0, 0, 0, 0, 0, root_width, root_height); 9432007c8b2Snia#endif 9442007c8b2Snia#if DEBUG_REPAINT 9452007c8b2Snia printf ("paint:"); 9462007c8b2Snia#endif 9472007c8b2Snia for (w = list; w; w = w->next) 9482007c8b2Snia { 9492007c8b2Snia#if CAN_DO_USABLE 9502007c8b2Snia if (!w->usable) 9512007c8b2Snia continue; 9522007c8b2Snia#endif 9532007c8b2Snia /* never painted, ignore it */ 9542007c8b2Snia if (!w->damaged) 9552007c8b2Snia continue; 9562007c8b2Snia /* if invisible, ignore it */ 9572007c8b2Snia if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 9582007c8b2Snia || w->a.x >= root_width || w->a.y >= root_height) 9592007c8b2Snia continue; 9602007c8b2Snia if (!w->picture) 9612007c8b2Snia { 9622007c8b2Snia XRenderPictureAttributes pa; 9632007c8b2Snia XRenderPictFormat *format; 9642007c8b2Snia Drawable draw = w->id; 9652007c8b2Snia 9662007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 9672007c8b2Snia if (hasNamePixmap && !w->pixmap) 9682007c8b2Snia w->pixmap = XCompositeNameWindowPixmap (dpy, w->id); 9692007c8b2Snia if (w->pixmap) 9702007c8b2Snia draw = w->pixmap; 9712007c8b2Snia#endif 9722007c8b2Snia format = XRenderFindVisualFormat (dpy, w->a.visual); 9732007c8b2Snia pa.subwindow_mode = IncludeInferiors; 9742007c8b2Snia w->picture = XRenderCreatePicture (dpy, draw, 9752007c8b2Snia format, 9762007c8b2Snia CPSubwindowMode, 9772007c8b2Snia &pa); 9782007c8b2Snia } 9792007c8b2Snia#if DEBUG_REPAINT 9802007c8b2Snia printf (" 0x%x", w->id); 9812007c8b2Snia#endif 9822007c8b2Snia if (clipChanged) 9832007c8b2Snia { 9842007c8b2Snia if (w->borderSize) 9852007c8b2Snia { 9862007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 9872007c8b2Snia XFixesDestroyRegion (dpy, w->borderSize); 9882007c8b2Snia w->borderSize = None; 9892007c8b2Snia } 9902007c8b2Snia if (w->extents) 9912007c8b2Snia { 9922007c8b2Snia XFixesDestroyRegion (dpy, w->extents); 9932007c8b2Snia w->extents = None; 9942007c8b2Snia } 9952007c8b2Snia if (w->borderClip) 9962007c8b2Snia { 9972007c8b2Snia XFixesDestroyRegion (dpy, w->borderClip); 9982007c8b2Snia w->borderClip = None; 9992007c8b2Snia } 10002007c8b2Snia } 10012007c8b2Snia if (!w->borderSize) 10022007c8b2Snia w->borderSize = border_size (dpy, w); 10032007c8b2Snia if (!w->extents) 10042007c8b2Snia w->extents = win_extents (dpy, w); 10052007c8b2Snia if (w->mode == WINDOW_SOLID) 10062007c8b2Snia { 10072007c8b2Snia int x, y, wid, hei; 10082007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 10092007c8b2Snia x = w->a.x; 10102007c8b2Snia y = w->a.y; 10112007c8b2Snia wid = w->a.width + w->a.border_width * 2; 10122007c8b2Snia hei = w->a.height + w->a.border_width * 2; 10132007c8b2Snia#else 10142007c8b2Snia x = w->a.x + w->a.border_width; 10152007c8b2Snia y = w->a.y + w->a.border_width; 10162007c8b2Snia wid = w->a.width; 10172007c8b2Snia hei = w->a.height; 10182007c8b2Snia#endif 10192007c8b2Snia XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region); 10202007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 10212007c8b2Snia XFixesSubtractRegion (dpy, region, region, w->borderSize); 10222007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 10232007c8b2Snia XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer, 10242007c8b2Snia 0, 0, 0, 0, 10252007c8b2Snia x, y, wid, hei); 10262007c8b2Snia } 10272007c8b2Snia if (!w->borderClip) 10282007c8b2Snia { 10292007c8b2Snia w->borderClip = XFixesCreateRegion (dpy, NULL, 0); 10302007c8b2Snia XFixesCopyRegion (dpy, w->borderClip, region); 10312007c8b2Snia } 10322007c8b2Snia w->prev_trans = t; 10332007c8b2Snia t = w; 10342007c8b2Snia } 10352007c8b2Snia#if DEBUG_REPAINT 10362007c8b2Snia printf ("\n"); 10372007c8b2Snia fflush (stdout); 10382007c8b2Snia#endif 10392007c8b2Snia XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region); 10402007c8b2Snia paint_root (dpy); 10412007c8b2Snia for (w = t; w; w = w->prev_trans) 10422007c8b2Snia { 10432007c8b2Snia XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip); 10442007c8b2Snia switch (compMode) { 10452007c8b2Snia case CompSimple: 10462007c8b2Snia break; 10472007c8b2Snia case CompServerShadows: 10482007c8b2Snia /* dont' bother drawing shadows on desktop windows */ 10492007c8b2Snia if (w->windowType == winDesktopAtom) 10502007c8b2Snia break; 10512007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 10522007c8b2Snia if (w->opacity != OPAQUE && !w->shadowPict) 10532007c8b2Snia w->shadowPict = solid_picture (dpy, True, 10542007c8b2Snia (double) w->opacity / OPAQUE * 0.3, 10552007c8b2Snia 0, 0, 0); 10562007c8b2Snia XRenderComposite (dpy, PictOpOver, 10572007c8b2Snia w->shadowPict ? w->shadowPict : transBlackPicture, 10582007c8b2Snia w->picture, rootBuffer, 10592007c8b2Snia 0, 0, 0, 0, 10602007c8b2Snia w->a.x + w->shadow_dx, 10612007c8b2Snia w->a.y + w->shadow_dy, 10622007c8b2Snia w->shadow_width, w->shadow_height); 10632007c8b2Snia break; 10642007c8b2Snia case CompClientShadows: 10652007c8b2Snia /* don't bother drawing shadows on desktop windows */ 10662007c8b2Snia if (w->shadow && w->windowType != winDesktopAtom) 10672007c8b2Snia { 10682007c8b2Snia XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer, 10692007c8b2Snia 0, 0, 0, 0, 10702007c8b2Snia w->a.x + w->shadow_dx, 10712007c8b2Snia w->a.y + w->shadow_dy, 10722007c8b2Snia w->shadow_width, w->shadow_height); 10732007c8b2Snia } 10742007c8b2Snia break; 10752007c8b2Snia } 10762007c8b2Snia if (w->opacity != OPAQUE && !w->alphaPict) 10772007c8b2Snia w->alphaPict = solid_picture (dpy, False, 10782007c8b2Snia (double) w->opacity / OPAQUE, 0, 0, 0); 10792007c8b2Snia if (w->mode == WINDOW_TRANS) 10802007c8b2Snia { 10812007c8b2Snia int x, y, wid, hei; 10822007c8b2Snia XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); 10832007c8b2Snia XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); 10842007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 10852007c8b2Snia x = w->a.x; 10862007c8b2Snia y = w->a.y; 10872007c8b2Snia wid = w->a.width + w->a.border_width * 2; 10882007c8b2Snia hei = w->a.height + w->a.border_width * 2; 10892007c8b2Snia#else 10902007c8b2Snia x = w->a.x + w->a.border_width; 10912007c8b2Snia y = w->a.y + w->a.border_width; 10922007c8b2Snia wid = w->a.width; 10932007c8b2Snia hei = w->a.height; 10942007c8b2Snia#endif 10952007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 10962007c8b2Snia XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 10972007c8b2Snia 0, 0, 0, 0, 10982007c8b2Snia x, y, wid, hei); 10992007c8b2Snia } 11002007c8b2Snia else if (w->mode == WINDOW_ARGB) 11012007c8b2Snia { 11022007c8b2Snia int x, y, wid, hei; 11032007c8b2Snia XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); 11042007c8b2Snia XFixesSetPictureClipRegion(dpy, rootBuffer, 0, 0, w->borderClip); 11052007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 11062007c8b2Snia x = w->a.x; 11072007c8b2Snia y = w->a.y; 11082007c8b2Snia wid = w->a.width + w->a.border_width * 2; 11092007c8b2Snia hei = w->a.height + w->a.border_width * 2; 11102007c8b2Snia#else 11112007c8b2Snia x = w->a.x + w->a.border_width; 11122007c8b2Snia y = w->a.y + w->a.border_width; 11132007c8b2Snia wid = w->a.width; 11142007c8b2Snia hei = w->a.height; 11152007c8b2Snia#endif 11162007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 11172007c8b2Snia XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, 11182007c8b2Snia 0, 0, 0, 0, 11192007c8b2Snia x, y, wid, hei); 11202007c8b2Snia } 11212007c8b2Snia XFixesDestroyRegion (dpy, w->borderClip); 11222007c8b2Snia w->borderClip = None; 11232007c8b2Snia } 11242007c8b2Snia XFixesDestroyRegion (dpy, region); 11252007c8b2Snia if (rootBuffer != rootPicture) 11262007c8b2Snia { 11272007c8b2Snia XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None); 11282007c8b2Snia XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture, 11292007c8b2Snia 0, 0, 0, 0, 0, 0, root_width, root_height); 11302007c8b2Snia } 11312007c8b2Snia} 11322007c8b2Snia 11332007c8b2Sniastatic void 11342007c8b2Sniaadd_damage (Display *dpy, XserverRegion damage) 11352007c8b2Snia{ 11362007c8b2Snia if (allDamage) 11372007c8b2Snia { 11382007c8b2Snia XFixesUnionRegion (dpy, allDamage, allDamage, damage); 11392007c8b2Snia XFixesDestroyRegion (dpy, damage); 11402007c8b2Snia } 11412007c8b2Snia else 11422007c8b2Snia allDamage = damage; 11432007c8b2Snia} 11442007c8b2Snia 11452007c8b2Sniastatic void 11462007c8b2Sniarepair_win (Display *dpy, win *w) 11472007c8b2Snia{ 11482007c8b2Snia XserverRegion parts; 11492007c8b2Snia 11502007c8b2Snia if (!w->damaged) 11512007c8b2Snia { 11522007c8b2Snia parts = win_extents (dpy, w); 11532007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 11542007c8b2Snia XDamageSubtract (dpy, w->damage, None, None); 11552007c8b2Snia } 11562007c8b2Snia else 11572007c8b2Snia { 11582007c8b2Snia XserverRegion o; 11592007c8b2Snia parts = XFixesCreateRegion (dpy, NULL, 0); 11602007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 11612007c8b2Snia XDamageSubtract (dpy, w->damage, None, parts); 11622007c8b2Snia XFixesTranslateRegion (dpy, parts, 11632007c8b2Snia w->a.x + w->a.border_width, 11642007c8b2Snia w->a.y + w->a.border_width); 11652007c8b2Snia if (compMode == CompServerShadows) 11662007c8b2Snia { 11672007c8b2Snia o = XFixesCreateRegion (dpy, NULL, 0); 11682007c8b2Snia XFixesCopyRegion (dpy, o, parts); 11692007c8b2Snia XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy); 11702007c8b2Snia XFixesUnionRegion (dpy, parts, parts, o); 11712007c8b2Snia XFixesDestroyRegion (dpy, o); 11722007c8b2Snia } 11732007c8b2Snia } 11742007c8b2Snia add_damage (dpy, parts); 11752007c8b2Snia w->damaged = 1; 11762007c8b2Snia} 11772007c8b2Snia 11782007c8b2Sniastatic unsigned int 11792007c8b2Sniaget_opacity_prop (Display *dpy, win *w, unsigned int def); 11802007c8b2Snia 11812007c8b2Sniastatic void 11822007c8b2Sniamap_win (Display *dpy, Window id, unsigned long sequence, Bool fade) 11832007c8b2Snia{ 11842007c8b2Snia win *w = find_win (dpy, id); 11852007c8b2Snia 11862007c8b2Snia if (!w) 11872007c8b2Snia return; 11882007c8b2Snia 11892007c8b2Snia w->a.map_state = IsViewable; 11902007c8b2Snia 11912007c8b2Snia /* This needs to be here or else we lose transparency messages */ 11922007c8b2Snia XSelectInput (dpy, id, PropertyChangeMask); 11932007c8b2Snia 11942007c8b2Snia /* This needs to be here since we don't get PropertyNotify when unmapped */ 11952007c8b2Snia w->opacity = get_opacity_prop (dpy, w, OPAQUE); 11962007c8b2Snia determine_mode (dpy, w); 11972007c8b2Snia 11982007c8b2Snia#if CAN_DO_USABLE 11992007c8b2Snia w->damage_bounds.x = w->damage_bounds.y = 0; 12002007c8b2Snia w->damage_bounds.width = w->damage_bounds.height = 0; 12012007c8b2Snia#endif 12022007c8b2Snia w->damaged = 0; 12032007c8b2Snia 12042007c8b2Snia if (fade && fadeWindows) 12052007c8b2Snia set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, NULL, False, True, True); 12062007c8b2Snia} 12072007c8b2Snia 12082007c8b2Sniastatic void 12092007c8b2Sniafinish_unmap_win (Display *dpy, win *w) 12102007c8b2Snia{ 12112007c8b2Snia w->damaged = 0; 12122007c8b2Snia#if CAN_DO_USABLE 12132007c8b2Snia w->usable = False; 12142007c8b2Snia#endif 12152007c8b2Snia if (w->extents != None) 12162007c8b2Snia { 12172007c8b2Snia add_damage (dpy, w->extents); /* destroys region */ 12182007c8b2Snia w->extents = None; 12192007c8b2Snia } 12202007c8b2Snia 12212007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 12222007c8b2Snia if (w->pixmap) 12232007c8b2Snia { 12242007c8b2Snia XFreePixmap (dpy, w->pixmap); 12252007c8b2Snia w->pixmap = None; 12262007c8b2Snia } 12272007c8b2Snia#endif 12282007c8b2Snia 12292007c8b2Snia if (w->picture) 12302007c8b2Snia { 12312007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 12322007c8b2Snia XRenderFreePicture (dpy, w->picture); 12332007c8b2Snia w->picture = None; 12342007c8b2Snia } 12352007c8b2Snia 12362007c8b2Snia /* don't care about properties anymore */ 12372007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 12382007c8b2Snia XSelectInput(dpy, w->id, 0); 12392007c8b2Snia 12402007c8b2Snia if (w->borderSize) 12412007c8b2Snia { 12422007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 12432007c8b2Snia XFixesDestroyRegion (dpy, w->borderSize); 12442007c8b2Snia w->borderSize = None; 12452007c8b2Snia } 12462007c8b2Snia if (w->shadow) 12472007c8b2Snia { 12482007c8b2Snia XRenderFreePicture (dpy, w->shadow); 12492007c8b2Snia w->shadow = None; 12502007c8b2Snia } 12512007c8b2Snia if (w->borderClip) 12522007c8b2Snia { 12532007c8b2Snia XFixesDestroyRegion (dpy, w->borderClip); 12542007c8b2Snia w->borderClip = None; 12552007c8b2Snia } 12562007c8b2Snia 12572007c8b2Snia clipChanged = True; 12582007c8b2Snia} 12592007c8b2Snia 12602007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 12612007c8b2Sniastatic void 12622007c8b2Sniaunmap_callback (Display *dpy, win *w, Bool gone) 12632007c8b2Snia{ 12642007c8b2Snia finish_unmap_win (dpy, w); 12652007c8b2Snia} 12662007c8b2Snia#endif 12672007c8b2Snia 12682007c8b2Sniastatic void 12692007c8b2Sniaunmap_win (Display *dpy, Window id, Bool fade) 12702007c8b2Snia{ 12712007c8b2Snia win *w = find_win (dpy, id); 12722007c8b2Snia if (!w) 12732007c8b2Snia return; 12742007c8b2Snia w->a.map_state = IsUnmapped; 12752007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 12762007c8b2Snia if (w->pixmap && fade && fadeWindows) 12772007c8b2Snia set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True); 12782007c8b2Snia else 12792007c8b2Snia#endif 12802007c8b2Snia finish_unmap_win (dpy, w); 12812007c8b2Snia} 12822007c8b2Snia 12832007c8b2Snia/* Get the opacity prop from window 12842007c8b2Snia not found: default 12852007c8b2Snia otherwise the value 12862007c8b2Snia */ 12872007c8b2Sniastatic unsigned int 12882007c8b2Sniaget_opacity_prop(Display *dpy, win *w, unsigned int def) 12892007c8b2Snia{ 12902007c8b2Snia Atom actual; 12912007c8b2Snia int format; 12922007c8b2Snia unsigned long n, left; 12932007c8b2Snia 12942007c8b2Snia unsigned char *data; 12952007c8b2Snia int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False, 12962007c8b2Snia XA_CARDINAL, &actual, &format, 12972007c8b2Snia &n, &left, &data); 12982007c8b2Snia if (result == Success && data != NULL) 12992007c8b2Snia { 13002007c8b2Snia unsigned int i; 13012007c8b2Snia memcpy (&i, data, sizeof (unsigned int)); 13022007c8b2Snia XFree( (void *) data); 13032007c8b2Snia return i; 13042007c8b2Snia } 13052007c8b2Snia return def; 13062007c8b2Snia} 13072007c8b2Snia 13082007c8b2Snia/* Get the opacity property from the window in a percent format 13092007c8b2Snia not found: default 13102007c8b2Snia otherwise: the value 13112007c8b2Snia*/ 13122007c8b2Sniastatic double 13132007c8b2Sniaget_opacity_percent(Display *dpy, win *w, double def) 13142007c8b2Snia{ 13152007c8b2Snia unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def)); 13162007c8b2Snia 13172007c8b2Snia return opacity*1.0/OPAQUE; 13182007c8b2Snia} 13192007c8b2Snia 13202007c8b2Snia/* determine mode for window all in one place. 13212007c8b2Snia Future might check for menu flag and other cool things 13222007c8b2Snia*/ 13232007c8b2Snia 13242007c8b2Sniastatic Atom 13252007c8b2Sniaget_wintype_prop(Display * dpy, Window w) 13262007c8b2Snia{ 13272007c8b2Snia Atom actual; 13282007c8b2Snia int format; 13292007c8b2Snia unsigned long n, left; 13302007c8b2Snia 13312007c8b2Snia unsigned char *data; 13322007c8b2Snia int result = XGetWindowProperty (dpy, w, winTypeAtom, 0L, 1L, False, 13332007c8b2Snia XA_ATOM, &actual, &format, 13342007c8b2Snia &n, &left, &data); 13352007c8b2Snia 13362007c8b2Snia if (result == Success && data != (unsigned char *)None) 13372007c8b2Snia { 13382007c8b2Snia Atom a; 13392007c8b2Snia memcpy (&a, data, sizeof (Atom)); 13402007c8b2Snia XFree ( (void *) data); 13412007c8b2Snia return a; 13422007c8b2Snia } 13432007c8b2Snia return winNormalAtom; 13442007c8b2Snia} 13452007c8b2Snia 13462007c8b2Sniastatic void 13472007c8b2Sniadetermine_mode(Display *dpy, win *w) 13482007c8b2Snia{ 13492007c8b2Snia int mode; 13502007c8b2Snia XRenderPictFormat *format; 13512007c8b2Snia 13522007c8b2Snia /* if trans prop == -1 fall back on previous tests*/ 13532007c8b2Snia 13542007c8b2Snia if (w->alphaPict) 13552007c8b2Snia { 13562007c8b2Snia XRenderFreePicture (dpy, w->alphaPict); 13572007c8b2Snia w->alphaPict = None; 13582007c8b2Snia } 13592007c8b2Snia if (w->shadowPict) 13602007c8b2Snia { 13612007c8b2Snia XRenderFreePicture (dpy, w->shadowPict); 13622007c8b2Snia w->shadowPict = None; 13632007c8b2Snia } 13642007c8b2Snia 13652007c8b2Snia if (w->a.class == InputOnly) 13662007c8b2Snia { 13672007c8b2Snia format = NULL; 13682007c8b2Snia } 13692007c8b2Snia else 13702007c8b2Snia { 13712007c8b2Snia format = XRenderFindVisualFormat (dpy, w->a.visual); 13722007c8b2Snia } 13732007c8b2Snia 13742007c8b2Snia if (format && format->type == PictTypeDirect && format->direct.alphaMask) 13752007c8b2Snia { 13762007c8b2Snia mode = WINDOW_ARGB; 13772007c8b2Snia } 13782007c8b2Snia else if (w->opacity != OPAQUE) 13792007c8b2Snia { 13802007c8b2Snia mode = WINDOW_TRANS; 13812007c8b2Snia } 13822007c8b2Snia else 13832007c8b2Snia { 13842007c8b2Snia mode = WINDOW_SOLID; 13852007c8b2Snia } 13862007c8b2Snia w->mode = mode; 13872007c8b2Snia if (w->extents) 13882007c8b2Snia { 13892007c8b2Snia XserverRegion damage; 13902007c8b2Snia damage = XFixesCreateRegion (dpy, NULL, 0); 13912007c8b2Snia XFixesCopyRegion (dpy, damage, w->extents); 13922007c8b2Snia add_damage (dpy, damage); 13932007c8b2Snia } 13942007c8b2Snia} 13952007c8b2Snia 13962007c8b2Sniastatic Atom 13972007c8b2Sniadetermine_wintype (Display *dpy, Window w) 13982007c8b2Snia{ 13992007c8b2Snia Window root_return, parent_return; 14002007c8b2Snia Window *children = NULL; 14012007c8b2Snia unsigned int nchildren, i; 14022007c8b2Snia Atom type; 14032007c8b2Snia 14042007c8b2Snia type = get_wintype_prop (dpy, w); 14052007c8b2Snia if (type != winNormalAtom) 14062007c8b2Snia return type; 14072007c8b2Snia 14082007c8b2Snia if (!XQueryTree (dpy, w, &root_return, &parent_return, &children, 14092007c8b2Snia &nchildren)) 14102007c8b2Snia { 14112007c8b2Snia /* XQueryTree failed. */ 14122007c8b2Snia if (children) 14132007c8b2Snia XFree ((void *)children); 14142007c8b2Snia return winNormalAtom; 14152007c8b2Snia } 14162007c8b2Snia 14172007c8b2Snia for (i = 0;i < nchildren;i++) 14182007c8b2Snia { 14192007c8b2Snia type = determine_wintype (dpy, children[i]); 14202007c8b2Snia if (type != winNormalAtom) 14212007c8b2Snia return type; 14222007c8b2Snia } 14232007c8b2Snia 14242007c8b2Snia if (children) 14252007c8b2Snia XFree ((void *)children); 14262007c8b2Snia 14272007c8b2Snia return winNormalAtom; 14282007c8b2Snia} 14292007c8b2Snia 14302007c8b2Sniastatic void 14312007c8b2Sniaadd_win (Display *dpy, Window id, Window prev) 14322007c8b2Snia{ 14332007c8b2Snia win *new = malloc (sizeof (win)); 14342007c8b2Snia win **p; 14352007c8b2Snia 14362007c8b2Snia if (!new) 14372007c8b2Snia return; 14382007c8b2Snia if (prev) 14392007c8b2Snia { 14402007c8b2Snia for (p = &list; *p; p = &(*p)->next) 14412007c8b2Snia if ((*p)->id == prev) 14422007c8b2Snia break; 14432007c8b2Snia } 14442007c8b2Snia else 14452007c8b2Snia p = &list; 14462007c8b2Snia new->id = id; 14472007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 14482007c8b2Snia if (!XGetWindowAttributes (dpy, id, &new->a)) 14492007c8b2Snia { 14502007c8b2Snia free (new); 14512007c8b2Snia return; 14522007c8b2Snia } 14532007c8b2Snia new->shaped = False; 14542007c8b2Snia new->shape_bounds.x = new->a.x; 14552007c8b2Snia new->shape_bounds.y = new->a.y; 14562007c8b2Snia new->shape_bounds.width = new->a.width; 14572007c8b2Snia new->shape_bounds.height = new->a.height; 14582007c8b2Snia new->damaged = 0; 14592007c8b2Snia#if CAN_DO_USABLE 14602007c8b2Snia new->usable = False; 14612007c8b2Snia#endif 14622007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 14632007c8b2Snia new->pixmap = None; 14642007c8b2Snia#endif 14652007c8b2Snia new->picture = None; 14662007c8b2Snia if (new->a.class == InputOnly) 14672007c8b2Snia { 14682007c8b2Snia new->damage_sequence = 0; 14692007c8b2Snia new->damage = None; 14702007c8b2Snia } 14712007c8b2Snia else 14722007c8b2Snia { 14732007c8b2Snia new->damage_sequence = NextRequest (dpy); 14742007c8b2Snia new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty); 14752007c8b2Snia XShapeSelectInput (dpy, id, ShapeNotifyMask); 14762007c8b2Snia } 14772007c8b2Snia new->alphaPict = None; 14782007c8b2Snia new->shadowPict = None; 14792007c8b2Snia new->borderSize = None; 14802007c8b2Snia new->extents = None; 14812007c8b2Snia new->shadow = None; 14822007c8b2Snia new->shadow_dx = 0; 14832007c8b2Snia new->shadow_dy = 0; 14842007c8b2Snia new->shadow_width = 0; 14852007c8b2Snia new->shadow_height = 0; 14862007c8b2Snia new->opacity = OPAQUE; 14872007c8b2Snia 14882007c8b2Snia new->borderClip = None; 14892007c8b2Snia new->prev_trans = NULL; 14902007c8b2Snia 14912007c8b2Snia new->windowType = determine_wintype (dpy, new->id); 14922007c8b2Snia 14932007c8b2Snia new->next = *p; 14942007c8b2Snia *p = new; 14952007c8b2Snia if (new->a.map_state == IsViewable) 14962007c8b2Snia map_win (dpy, id, new->damage_sequence - 1, True); 14972007c8b2Snia} 14982007c8b2Snia 14992007c8b2Sniastatic void 15002007c8b2Sniarestack_win (Display *dpy, win *w, Window new_above) 15012007c8b2Snia{ 15022007c8b2Snia Window old_above; 15032007c8b2Snia 15042007c8b2Snia if (w->next) 15052007c8b2Snia old_above = w->next->id; 15062007c8b2Snia else 15072007c8b2Snia old_above = None; 15082007c8b2Snia if (old_above != new_above) 15092007c8b2Snia { 15102007c8b2Snia win **prev; 15112007c8b2Snia 15122007c8b2Snia /* unhook */ 15132007c8b2Snia for (prev = &list; *prev; prev = &(*prev)->next) 15142007c8b2Snia if ((*prev) == w) 15152007c8b2Snia break; 15162007c8b2Snia *prev = w->next; 15172007c8b2Snia 15182007c8b2Snia /* rehook */ 15192007c8b2Snia for (prev = &list; *prev; prev = &(*prev)->next) 15202007c8b2Snia { 15212007c8b2Snia if ((*prev)->id == new_above) 15222007c8b2Snia break; 15232007c8b2Snia } 15242007c8b2Snia w->next = *prev; 15252007c8b2Snia *prev = w; 15262007c8b2Snia } 15272007c8b2Snia} 15282007c8b2Snia 15292007c8b2Sniastatic void 15302007c8b2Sniaconfigure_win (Display *dpy, XConfigureEvent *ce) 15312007c8b2Snia{ 15322007c8b2Snia win *w = find_win (dpy, ce->window); 15332007c8b2Snia XserverRegion damage = None; 15342007c8b2Snia 15352007c8b2Snia if (!w) 15362007c8b2Snia { 15372007c8b2Snia if (ce->window == root) 15382007c8b2Snia { 15392007c8b2Snia if (rootBuffer) 15402007c8b2Snia { 15412007c8b2Snia XRenderFreePicture (dpy, rootBuffer); 15422007c8b2Snia rootBuffer = None; 15432007c8b2Snia } 15442007c8b2Snia root_width = ce->width; 15452007c8b2Snia root_height = ce->height; 15462007c8b2Snia } 15472007c8b2Snia return; 15482007c8b2Snia } 15492007c8b2Snia#if CAN_DO_USABLE 15502007c8b2Snia if (w->usable) 15512007c8b2Snia#endif 15522007c8b2Snia { 15532007c8b2Snia damage = XFixesCreateRegion (dpy, NULL, 0); 15542007c8b2Snia if (w->extents != None) 15552007c8b2Snia XFixesCopyRegion (dpy, damage, w->extents); 15562007c8b2Snia } 15572007c8b2Snia w->shape_bounds.x -= w->a.x; 15582007c8b2Snia w->shape_bounds.y -= w->a.y; 15592007c8b2Snia w->a.x = ce->x; 15602007c8b2Snia w->a.y = ce->y; 15612007c8b2Snia if (w->a.width != ce->width || w->a.height != ce->height) 15622007c8b2Snia { 15632007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 15642007c8b2Snia if (w->pixmap) 15652007c8b2Snia { 15662007c8b2Snia XFreePixmap (dpy, w->pixmap); 15672007c8b2Snia w->pixmap = None; 15682007c8b2Snia if (w->picture) 15692007c8b2Snia { 15702007c8b2Snia XRenderFreePicture (dpy, w->picture); 15712007c8b2Snia w->picture = None; 15722007c8b2Snia } 15732007c8b2Snia } 15742007c8b2Snia#endif 15752007c8b2Snia if (w->shadow) 15762007c8b2Snia { 15772007c8b2Snia XRenderFreePicture (dpy, w->shadow); 15782007c8b2Snia w->shadow = None; 15792007c8b2Snia } 15802007c8b2Snia } 15812007c8b2Snia w->a.width = ce->width; 15822007c8b2Snia w->a.height = ce->height; 15832007c8b2Snia w->a.border_width = ce->border_width; 15842007c8b2Snia w->a.override_redirect = ce->override_redirect; 15852007c8b2Snia restack_win (dpy, w, ce->above); 15862007c8b2Snia if (damage) 15872007c8b2Snia { 15882007c8b2Snia XserverRegion extents = win_extents (dpy, w); 15892007c8b2Snia XFixesUnionRegion (dpy, damage, damage, extents); 15902007c8b2Snia XFixesDestroyRegion (dpy, extents); 15912007c8b2Snia add_damage (dpy, damage); 15922007c8b2Snia } 15932007c8b2Snia w->shape_bounds.x += w->a.x; 15942007c8b2Snia w->shape_bounds.y += w->a.y; 15952007c8b2Snia if (!w->shaped) 15962007c8b2Snia { 15972007c8b2Snia w->shape_bounds.width = w->a.width; 15982007c8b2Snia w->shape_bounds.height = w->a.height; 15992007c8b2Snia } 16002007c8b2Snia 16012007c8b2Snia clipChanged = True; 16022007c8b2Snia} 16032007c8b2Snia 16042007c8b2Sniastatic void 16052007c8b2Sniacirculate_win (Display *dpy, XCirculateEvent *ce) 16062007c8b2Snia{ 16072007c8b2Snia win *w = find_win (dpy, ce->window); 16082007c8b2Snia Window new_above; 16092007c8b2Snia 16102007c8b2Snia if (!w) 16112007c8b2Snia return; 16122007c8b2Snia 16132007c8b2Snia if (ce->place == PlaceOnTop) 16142007c8b2Snia new_above = list->id; 16152007c8b2Snia else 16162007c8b2Snia new_above = None; 16172007c8b2Snia restack_win (dpy, w, new_above); 16182007c8b2Snia clipChanged = True; 16192007c8b2Snia} 16202007c8b2Snia 16212007c8b2Sniastatic void 16222007c8b2Sniafinish_destroy_win (Display *dpy, Window id, Bool gone) 16232007c8b2Snia{ 16242007c8b2Snia win **prev, *w; 16252007c8b2Snia 16262007c8b2Snia for (prev = &list; (w = *prev); prev = &w->next) 16272007c8b2Snia if (w->id == id) 16282007c8b2Snia { 16292007c8b2Snia if (gone) 16302007c8b2Snia finish_unmap_win (dpy, w); 16312007c8b2Snia *prev = w->next; 16322007c8b2Snia if (w->picture) 16332007c8b2Snia { 16342007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 16352007c8b2Snia XRenderFreePicture (dpy, w->picture); 16362007c8b2Snia w->picture = None; 16372007c8b2Snia } 16382007c8b2Snia if (w->alphaPict) 16392007c8b2Snia { 16402007c8b2Snia XRenderFreePicture (dpy, w->alphaPict); 16412007c8b2Snia w->alphaPict = None; 16422007c8b2Snia } 16432007c8b2Snia if (w->shadowPict) 16442007c8b2Snia { 16452007c8b2Snia XRenderFreePicture (dpy, w->shadowPict); 16462007c8b2Snia w->shadowPict = None; 16472007c8b2Snia } 16482007c8b2Snia if (w->shadow) 16492007c8b2Snia { 16502007c8b2Snia XRenderFreePicture (dpy, w->shadow); 16512007c8b2Snia w->shadow = None; 16522007c8b2Snia } 16532007c8b2Snia if (w->damage != None) 16542007c8b2Snia { 16552007c8b2Snia set_ignore (dpy, NextRequest (dpy)); 16562007c8b2Snia XDamageDestroy (dpy, w->damage); 16572007c8b2Snia w->damage = None; 16582007c8b2Snia } 16592007c8b2Snia cleanup_fade (dpy, w); 16602007c8b2Snia free (w); 16612007c8b2Snia break; 16622007c8b2Snia } 16632007c8b2Snia} 16642007c8b2Snia 16652007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 16662007c8b2Sniastatic void 16672007c8b2Sniadestroy_callback (Display *dpy, win *w, Bool gone) 16682007c8b2Snia{ 16692007c8b2Snia finish_destroy_win (dpy, w->id, gone); 16702007c8b2Snia} 16712007c8b2Snia#endif 16722007c8b2Snia 16732007c8b2Sniastatic void 16742007c8b2Sniadestroy_win (Display *dpy, Window id, Bool gone, Bool fade) 16752007c8b2Snia{ 16762007c8b2Snia win *w = find_win (dpy, id); 16772007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 16782007c8b2Snia if (w && w->pixmap && fade && fadeWindows) 16792007c8b2Snia set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True); 16802007c8b2Snia else 16812007c8b2Snia#endif 16822007c8b2Snia { 16832007c8b2Snia finish_destroy_win (dpy, id, gone); 16842007c8b2Snia } 16852007c8b2Snia} 16862007c8b2Snia 16872007c8b2Snia/* 16882007c8b2Sniastatic void 16892007c8b2Sniadump_win (win *w) 16902007c8b2Snia{ 16912007c8b2Snia printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id, 16922007c8b2Snia w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width); 16932007c8b2Snia} 16942007c8b2Snia 16952007c8b2Snia 16962007c8b2Sniastatic void 16972007c8b2Sniadump_wins (void) 16982007c8b2Snia{ 16992007c8b2Snia win *w; 17002007c8b2Snia 17012007c8b2Snia printf ("windows:\n"); 17022007c8b2Snia for (w = list; w; w = w->next) 17032007c8b2Snia dump_win (w); 17042007c8b2Snia} 17052007c8b2Snia*/ 17062007c8b2Snia 17072007c8b2Sniastatic void 17082007c8b2Sniadamage_win (Display *dpy, XDamageNotifyEvent *de) 17092007c8b2Snia{ 17102007c8b2Snia win *w = find_win (dpy, de->drawable); 17112007c8b2Snia 17122007c8b2Snia if (!w) 17132007c8b2Snia return; 17142007c8b2Snia#if CAN_DO_USABLE 17152007c8b2Snia if (!w->usable) 17162007c8b2Snia { 17172007c8b2Snia if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0) 17182007c8b2Snia { 17192007c8b2Snia w->damage_bounds = de->area; 17202007c8b2Snia } 17212007c8b2Snia else 17222007c8b2Snia { 17232007c8b2Snia if (de->area.x < w->damage_bounds.x) 17242007c8b2Snia { 17252007c8b2Snia w->damage_bounds.width += (w->damage_bounds.x - de->area.x); 17262007c8b2Snia w->damage_bounds.x = de->area.x; 17272007c8b2Snia } 17282007c8b2Snia if (de->area.y < w->damage_bounds.y) 17292007c8b2Snia { 17302007c8b2Snia w->damage_bounds.height += (w->damage_bounds.y - de->area.y); 17312007c8b2Snia w->damage_bounds.y = de->area.y; 17322007c8b2Snia } 17332007c8b2Snia if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width) 17342007c8b2Snia w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x; 17352007c8b2Snia if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height) 17362007c8b2Snia w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y; 17372007c8b2Snia } 17382007c8b2Snia#if 0 17392007c8b2Snia printf ("unusable damage %d, %d: %d x %d bounds %d, %d: %d x %d\n", 17402007c8b2Snia de->area.x, 17412007c8b2Snia de->area.y, 17422007c8b2Snia de->area.width, 17432007c8b2Snia de->area.height, 17442007c8b2Snia w->damage_bounds.x, 17452007c8b2Snia w->damage_bounds.y, 17462007c8b2Snia w->damage_bounds.width, 17472007c8b2Snia w->damage_bounds.height); 17482007c8b2Snia#endif 17492007c8b2Snia if (w->damage_bounds.x <= 0 && 17502007c8b2Snia w->damage_bounds.y <= 0 && 17512007c8b2Snia w->a.width <= w->damage_bounds.x + w->damage_bounds.width && 17522007c8b2Snia w->a.height <= w->damage_bounds.y + w->damage_bounds.height) 17532007c8b2Snia { 17542007c8b2Snia clipChanged = True; 17552007c8b2Snia if (fadeWindows) 17562007c8b2Snia set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, False, True, True); 17572007c8b2Snia w->usable = True; 17582007c8b2Snia } 17592007c8b2Snia } 17602007c8b2Snia if (w->usable) 17612007c8b2Snia#endif 17622007c8b2Snia repair_win (dpy, w); 17632007c8b2Snia} 17642007c8b2Snia 17652007c8b2Snia#if DEBUG_SHAPE 17662007c8b2Sniastatic const char * 17672007c8b2Sniashape_kind(int kind) 17682007c8b2Snia{ 17692007c8b2Snia static char buf[128]; 17702007c8b2Snia 17712007c8b2Snia switch(kind){ 17722007c8b2Snia case ShapeBounding: 17732007c8b2Snia return "ShapeBounding"; 17742007c8b2Snia case ShapeClip: 17752007c8b2Snia return "ShapeClip"; 17762007c8b2Snia case ShapeInput: 17772007c8b2Snia return "ShapeInput"; 17782007c8b2Snia default: 17792007c8b2Snia sprintf (buf, "Shape %d", kind); 17802007c8b2Snia return buf; 17812007c8b2Snia } 17822007c8b2Snia} 17832007c8b2Snia#endif 17842007c8b2Snia 17852007c8b2Sniastatic void 17862007c8b2Sniashape_win (Display *dpy, XShapeEvent *se) 17872007c8b2Snia{ 17882007c8b2Snia win *w = find_win (dpy, se->window); 17892007c8b2Snia 17902007c8b2Snia if (!w) 17912007c8b2Snia return; 17922007c8b2Snia 17932007c8b2Snia if (se->kind == ShapeClip || se->kind == ShapeBounding) 17942007c8b2Snia { 17952007c8b2Snia XserverRegion region0; 17962007c8b2Snia XserverRegion region1; 17972007c8b2Snia 17982007c8b2Snia#if DEBUG_SHAPE 17992007c8b2Snia printf("win 0x%lx %s:%s %ux%u+%d+%d\n", 18002007c8b2Snia (unsigned long) se->window, 18012007c8b2Snia shape_kind(se->kind), 18022007c8b2Snia (se->shaped == True) ? "true" : "false", 18032007c8b2Snia se->width, se->height, 18042007c8b2Snia se->x, se->y); 18052007c8b2Snia#endif 18062007c8b2Snia 18072007c8b2Snia clipChanged = True; 18082007c8b2Snia 18092007c8b2Snia region0 = XFixesCreateRegion (dpy, &w->shape_bounds, 1); 18102007c8b2Snia 18112007c8b2Snia if (se->shaped == True) 18122007c8b2Snia { 18132007c8b2Snia w->shaped = True; 18142007c8b2Snia w->shape_bounds.x = w->a.x + se->x; 18152007c8b2Snia w->shape_bounds.y = w->a.y + se->y; 18162007c8b2Snia w->shape_bounds.width = se->width; 18172007c8b2Snia w->shape_bounds.height = se->height; 18182007c8b2Snia } 18192007c8b2Snia else 18202007c8b2Snia { 18212007c8b2Snia w->shaped = False; 18222007c8b2Snia w->shape_bounds.x = w->a.x; 18232007c8b2Snia w->shape_bounds.y = w->a.y; 18242007c8b2Snia w->shape_bounds.width = w->a.width; 18252007c8b2Snia w->shape_bounds.height = w->a.height; 18262007c8b2Snia } 18272007c8b2Snia 18282007c8b2Snia region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1); 18292007c8b2Snia XFixesUnionRegion (dpy, region0, region0, region1); 18302007c8b2Snia XFixesDestroyRegion (dpy, region1); 18312007c8b2Snia 18322007c8b2Snia /* ask for repaint of the old and new region */ 18332007c8b2Snia paint_all (dpy, region0); 18342007c8b2Snia } 18352007c8b2Snia} 18362007c8b2Snia 18372007c8b2Sniastatic int 18382007c8b2Sniaerror (Display *dpy, XErrorEvent *ev) 18392007c8b2Snia{ 18402007c8b2Snia int o; 18412007c8b2Snia const char *name = NULL; 18422007c8b2Snia static char buffer[256]; 18432007c8b2Snia 18442007c8b2Snia if (should_ignore (dpy, ev->serial)) 18452007c8b2Snia return 0; 18462007c8b2Snia 18472007c8b2Snia if (ev->request_code == composite_opcode && 18482007c8b2Snia ev->minor_code == X_CompositeRedirectSubwindows) 18492007c8b2Snia { 18502007c8b2Snia fprintf (stderr, "Another composite manager is already running\n"); 18512007c8b2Snia exit (1); 18522007c8b2Snia } 18532007c8b2Snia 18542007c8b2Snia o = ev->error_code - xfixes_error; 18552007c8b2Snia switch (o) { 18562007c8b2Snia case BadRegion: name = "BadRegion"; break; 18572007c8b2Snia default: break; 18582007c8b2Snia } 18592007c8b2Snia o = ev->error_code - damage_error; 18602007c8b2Snia switch (o) { 18612007c8b2Snia case BadDamage: name = "BadDamage"; break; 18622007c8b2Snia default: break; 18632007c8b2Snia } 18642007c8b2Snia o = ev->error_code - render_error; 18652007c8b2Snia switch (o) { 18662007c8b2Snia case BadPictFormat: name ="BadPictFormat"; break; 18672007c8b2Snia case BadPicture: name ="BadPicture"; break; 18682007c8b2Snia case BadPictOp: name ="BadPictOp"; break; 18692007c8b2Snia case BadGlyphSet: name ="BadGlyphSet"; break; 18702007c8b2Snia case BadGlyph: name ="BadGlyph"; break; 18712007c8b2Snia default: break; 18722007c8b2Snia } 18732007c8b2Snia 18742007c8b2Snia if (name == NULL) 18752007c8b2Snia { 18762007c8b2Snia buffer[0] = '\0'; 18772007c8b2Snia XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer)); 18782007c8b2Snia name = buffer; 18792007c8b2Snia } 18802007c8b2Snia 18812007c8b2Snia fprintf (stderr, "error %d: %s request %d minor %d serial %lu\n", 18822007c8b2Snia ev->error_code, (strlen (name) > 0) ? name : "unknown", 18832007c8b2Snia ev->request_code, ev->minor_code, ev->serial); 18842007c8b2Snia 18852007c8b2Snia/* abort (); this is just annoying to most people */ 18862007c8b2Snia return 0; 18872007c8b2Snia} 18882007c8b2Snia 18892007c8b2Sniastatic void 18902007c8b2Sniaexpose_root (Display *dpy, Window root, XRectangle *rects, int nrects) 18912007c8b2Snia{ 18922007c8b2Snia XserverRegion region = XFixesCreateRegion (dpy, rects, nrects); 18932007c8b2Snia 18942007c8b2Snia add_damage (dpy, region); 18952007c8b2Snia} 18962007c8b2Snia 18972007c8b2Snia#if DEBUG_EVENTS 18982007c8b2Sniastatic int 18992007c8b2Sniaev_serial (XEvent *ev) 19002007c8b2Snia{ 19012007c8b2Snia if (ev->type & 0x7f != KeymapNotify) 19022007c8b2Snia return ev->xany.serial; 19032007c8b2Snia return NextRequest (ev->xany.display); 19042007c8b2Snia} 19052007c8b2Snia 19062007c8b2Sniastatic char * 19072007c8b2Sniaev_name (XEvent *ev) 19082007c8b2Snia{ 19092007c8b2Snia static char buf[128]; 19102007c8b2Snia switch (ev->type & 0x7f) { 19112007c8b2Snia case Expose: 19122007c8b2Snia return "Expose"; 19132007c8b2Snia case MapNotify: 19142007c8b2Snia return "Map"; 19152007c8b2Snia case UnmapNotify: 19162007c8b2Snia return "Unmap"; 19172007c8b2Snia case ReparentNotify: 19182007c8b2Snia return "Reparent"; 19192007c8b2Snia case CirculateNotify: 19202007c8b2Snia return "Circulate"; 19212007c8b2Snia default: 19222007c8b2Snia if (ev->type == damage_event + XDamageNotify) 19232007c8b2Snia { 19242007c8b2Snia return "Damage"; 19252007c8b2Snia } 19262007c8b2Snia else if (ev->type == xshape_event + ShapeNotify) 19272007c8b2Snia { 19282007c8b2Snia return "Shape"; 19292007c8b2Snia } 19302007c8b2Snia sprintf (buf, "Event %d", ev->type); 19312007c8b2Snia return buf; 19322007c8b2Snia } 19332007c8b2Snia} 19342007c8b2Snia 19352007c8b2Sniastatic Window 19362007c8b2Sniaev_window (XEvent *ev) 19372007c8b2Snia{ 19382007c8b2Snia switch (ev->type) { 19392007c8b2Snia case Expose: 19402007c8b2Snia return ev->xexpose.window; 19412007c8b2Snia case MapNotify: 19422007c8b2Snia return ev->xmap.window; 19432007c8b2Snia case UnmapNotify: 19442007c8b2Snia return ev->xunmap.window; 19452007c8b2Snia case ReparentNotify: 19462007c8b2Snia return ev->xreparent.window; 19472007c8b2Snia case CirculateNotify: 19482007c8b2Snia return ev->xcirculate.window; 19492007c8b2Snia default: 19502007c8b2Snia if (ev->type == damage_event + XDamageNotify) 19512007c8b2Snia { 19522007c8b2Snia return ((XDamageNotifyEvent *) ev)->drawable; 19532007c8b2Snia } 19542007c8b2Snia else if (ev->type == xshape_event + ShapeNotify) 19552007c8b2Snia { 19562007c8b2Snia return ((XShapeEvent *) ev)->window; 19572007c8b2Snia } 19582007c8b2Snia return 0; 19592007c8b2Snia } 19602007c8b2Snia} 19612007c8b2Snia#endif 19622007c8b2Snia 19632007c8b2Sniastatic void 19642007c8b2Sniausage (const char *program) 19652007c8b2Snia{ 19662007c8b2Snia fprintf (stderr, "%s v%s\n", program, PACKAGE_VERSION); 19672007c8b2Snia fprintf (stderr, "usage: %s [options]\n%s\n", program, 19682007c8b2Snia "Options:\n" 19692007c8b2Snia " -d display\n" 19702007c8b2Snia " Specifies which display should be managed.\n" 19712007c8b2Snia " -r radius\n" 19722007c8b2Snia " Specifies the blur radius for client-side shadows. (default 12)\n" 19732007c8b2Snia " -o opacity\n" 19742007c8b2Snia " Specifies the translucency for client-side shadows. (default .75)\n" 19752007c8b2Snia " -l left-offset\n" 19762007c8b2Snia " Specifies the left offset for client-side shadows. (default -15)\n" 19772007c8b2Snia " -t top-offset\n" 19782007c8b2Snia " Specifies the top offset for clinet-side shadows. (default -15)\n" 19792007c8b2Snia " -I fade-in-step\n" 19802007c8b2Snia " Specifies the opacity change between steps while fading in. (default 0.028)\n" 19812007c8b2Snia " -O fade-out-step\n" 19822007c8b2Snia " Specifies the opacity change between steps while fading out. (default 0.03)\n" 19832007c8b2Snia " -D fade-delta-time\n" 19842007c8b2Snia " Specifies the time between steps in a fade in milliseconds. (default 10)\n" 19852007c8b2Snia " -a\n" 19862007c8b2Snia " Use automatic server-side compositing. Faster, but no special effects.\n" 19872007c8b2Snia " -c\n" 19882007c8b2Snia " Draw client-side shadows with fuzzy edges.\n" 19892007c8b2Snia " -C\n" 19902007c8b2Snia " Avoid drawing shadows on dock/panel windows.\n" 19912007c8b2Snia " -f\n" 19922007c8b2Snia " Fade windows in/out when opening/closing.\n" 19932007c8b2Snia " -F\n" 19942007c8b2Snia " Fade windows during opacity changes.\n" 19952007c8b2Snia " -n\n" 19962007c8b2Snia " Normal client-side compositing with transparency support\n" 19972007c8b2Snia " -s\n" 19982007c8b2Snia " Draw server-side shadows with sharp edges.\n" 19992007c8b2Snia " -S\n" 20002007c8b2Snia " Enable synchronous operation (for debugging).\n" 20012007c8b2Snia ); 20022007c8b2Snia exit (1); 20032007c8b2Snia} 20042007c8b2Snia 20052007c8b2Sniastatic Bool 20062007c8b2Sniaregister_cm (Display *dpy) 20072007c8b2Snia{ 20082007c8b2Snia Window w; 20092007c8b2Snia Atom a; 20102007c8b2Snia static char net_wm_cm[] = "_NET_WM_CM_Sxx"; 20112007c8b2Snia 20122007c8b2Snia snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr); 20132007c8b2Snia a = XInternAtom (dpy, net_wm_cm, False); 20142007c8b2Snia 20152007c8b2Snia w = XGetSelectionOwner (dpy, a); 20162007c8b2Snia if (w != None) 20172007c8b2Snia { 20182007c8b2Snia XTextProperty tp; 20192007c8b2Snia char **strs; 20202007c8b2Snia int count; 20212007c8b2Snia Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False); 20222007c8b2Snia 20232007c8b2Snia if (!XGetTextProperty (dpy, w, &tp, winNameAtom) && 20242007c8b2Snia !XGetTextProperty (dpy, w, &tp, XA_WM_NAME)) 20252007c8b2Snia { 20262007c8b2Snia fprintf (stderr, 20272007c8b2Snia "Another composite manager is already running (0x%lx)\n", 20282007c8b2Snia (unsigned long) w); 20292007c8b2Snia return False; 20302007c8b2Snia } 20312007c8b2Snia if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success) 20322007c8b2Snia { 20332007c8b2Snia fprintf (stderr, 20342007c8b2Snia "Another composite manager is already running (%s)\n", 20352007c8b2Snia strs[0]); 20362007c8b2Snia 20372007c8b2Snia XFreeStringList (strs); 20382007c8b2Snia } 20392007c8b2Snia 20402007c8b2Snia XFree (tp.value); 20412007c8b2Snia 20422007c8b2Snia return False; 20432007c8b2Snia } 20442007c8b2Snia 20452007c8b2Snia w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None, 20462007c8b2Snia None); 20472007c8b2Snia 20482007c8b2Snia Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, 20492007c8b2Snia NULL); 20502007c8b2Snia 20512007c8b2Snia XSetSelectionOwner (dpy, a, w, 0); 20522007c8b2Snia 20532007c8b2Snia return True; 20542007c8b2Snia} 20552007c8b2Snia 20562007c8b2Sniaint 20572007c8b2Sniamain (int argc, char **argv) 20582007c8b2Snia{ 20592007c8b2Snia Display *dpy; 20602007c8b2Snia XEvent ev; 20612007c8b2Snia Window root_return, parent_return; 20622007c8b2Snia Window *children; 20632007c8b2Snia unsigned int nchildren; 20642007c8b2Snia int i; 20652007c8b2Snia XRenderPictureAttributes pa; 20662007c8b2Snia XRectangle *expose_rects = NULL; 20672007c8b2Snia int size_expose = 0; 20682007c8b2Snia int n_expose = 0; 20692007c8b2Snia struct pollfd ufd; 20702007c8b2Snia int p; 20712007c8b2Snia int composite_major, composite_minor; 20722007c8b2Snia char *display = NULL; 20732007c8b2Snia int o; 20742007c8b2Snia 20752007c8b2Snia while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1) 20762007c8b2Snia { 20772007c8b2Snia switch (o) { 20782007c8b2Snia case 'd': 20792007c8b2Snia display = optarg; 20802007c8b2Snia break; 20812007c8b2Snia case 'D': 20822007c8b2Snia fade_delta = atoi (optarg); 20832007c8b2Snia if (fade_delta < 1) 20842007c8b2Snia fade_delta = 10; 20852007c8b2Snia break; 20862007c8b2Snia case 'I': 20872007c8b2Snia fade_in_step = atof (optarg); 20882007c8b2Snia if (fade_in_step <= 0) 20892007c8b2Snia fade_in_step = 0.01; 20902007c8b2Snia break; 20912007c8b2Snia case 'O': 20922007c8b2Snia fade_out_step = atof (optarg); 20932007c8b2Snia if (fade_out_step <= 0) 20942007c8b2Snia fade_out_step = 0.01; 20952007c8b2Snia break; 20962007c8b2Snia case 's': 20972007c8b2Snia compMode = CompServerShadows; 20982007c8b2Snia break; 20992007c8b2Snia case 'c': 21002007c8b2Snia compMode = CompClientShadows; 21012007c8b2Snia break; 21022007c8b2Snia case 'C': 21032007c8b2Snia excludeDockShadows = True; 21042007c8b2Snia break; 21052007c8b2Snia case 'n': 21062007c8b2Snia compMode = CompSimple; 21072007c8b2Snia break; 21082007c8b2Snia case 'f': 21092007c8b2Snia fadeWindows = True; 21102007c8b2Snia break; 21112007c8b2Snia case 'F': 21122007c8b2Snia fadeTrans = True; 21132007c8b2Snia break; 21142007c8b2Snia case 'a': 21152007c8b2Snia autoRedirect = True; 21162007c8b2Snia break; 21172007c8b2Snia case 'S': 21182007c8b2Snia synchronize = True; 21192007c8b2Snia break; 21202007c8b2Snia case 'r': 21212007c8b2Snia shadowRadius = atoi (optarg); 21222007c8b2Snia break; 21232007c8b2Snia case 'o': 21242007c8b2Snia shadowOpacity = atof (optarg); 21252007c8b2Snia break; 21262007c8b2Snia case 'l': 21272007c8b2Snia shadowOffsetX = atoi (optarg); 21282007c8b2Snia break; 21292007c8b2Snia case 't': 21302007c8b2Snia shadowOffsetY = atoi (optarg); 21312007c8b2Snia break; 21322007c8b2Snia default: 21332007c8b2Snia usage (argv[0]); 21342007c8b2Snia break; 21352007c8b2Snia } 21362007c8b2Snia } 21372007c8b2Snia 21382007c8b2Snia dpy = XOpenDisplay (display); 21392007c8b2Snia if (!dpy) 21402007c8b2Snia { 21412007c8b2Snia fprintf (stderr, "Can't open display\n"); 21422007c8b2Snia exit (1); 21432007c8b2Snia } 21442007c8b2Snia XSetErrorHandler (error); 21452007c8b2Snia if (synchronize) 21462007c8b2Snia XSynchronize (dpy, 1); 21472007c8b2Snia scr = DefaultScreen (dpy); 21482007c8b2Snia root = RootWindow (dpy, scr); 21492007c8b2Snia 21502007c8b2Snia if (!XRenderQueryExtension (dpy, &render_event, &render_error)) 21512007c8b2Snia { 21522007c8b2Snia fprintf (stderr, "No render extension\n"); 21532007c8b2Snia exit (1); 21542007c8b2Snia } 21552007c8b2Snia if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode, 21562007c8b2Snia &composite_event, &composite_error)) 21572007c8b2Snia { 21582007c8b2Snia fprintf (stderr, "No composite extension\n"); 21592007c8b2Snia exit (1); 21602007c8b2Snia } 21612007c8b2Snia XCompositeQueryVersion (dpy, &composite_major, &composite_minor); 21622007c8b2Snia#if HAS_NAME_WINDOW_PIXMAP 21632007c8b2Snia if (composite_major > 0 || composite_minor >= 2) 21642007c8b2Snia hasNamePixmap = True; 21652007c8b2Snia#endif 21662007c8b2Snia 21672007c8b2Snia if (!XDamageQueryExtension (dpy, &damage_event, &damage_error)) 21682007c8b2Snia { 21692007c8b2Snia fprintf (stderr, "No damage extension\n"); 21702007c8b2Snia exit (1); 21712007c8b2Snia } 21722007c8b2Snia if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error)) 21732007c8b2Snia { 21742007c8b2Snia fprintf (stderr, "No XFixes extension\n"); 21752007c8b2Snia exit (1); 21762007c8b2Snia } 21772007c8b2Snia if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error)) 21782007c8b2Snia { 21792007c8b2Snia fprintf (stderr, "No XShape extension\n"); 21802007c8b2Snia exit (1); 21812007c8b2Snia } 21822007c8b2Snia 21832007c8b2Snia if (!register_cm(dpy)) 21842007c8b2Snia { 21852007c8b2Snia exit (1); 21862007c8b2Snia } 21872007c8b2Snia 21882007c8b2Snia /* get atoms */ 21892007c8b2Snia opacityAtom = XInternAtom (dpy, OPACITY_PROP, False); 21902007c8b2Snia winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False); 21912007c8b2Snia winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); 21922007c8b2Snia winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); 21932007c8b2Snia winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); 21942007c8b2Snia winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False); 21952007c8b2Snia winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); 21962007c8b2Snia winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); 21972007c8b2Snia winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); 21982007c8b2Snia winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); 21992007c8b2Snia 22002007c8b2Snia pa.subwindow_mode = IncludeInferiors; 22012007c8b2Snia 22022007c8b2Snia if (compMode == CompClientShadows) 22032007c8b2Snia { 22042007c8b2Snia gaussianMap = make_gaussian_map(dpy, shadowRadius); 22052007c8b2Snia presum_gaussian (gaussianMap); 22062007c8b2Snia } 22072007c8b2Snia 22082007c8b2Snia root_width = DisplayWidth (dpy, scr); 22092007c8b2Snia root_height = DisplayHeight (dpy, scr); 22102007c8b2Snia 22112007c8b2Snia rootPicture = XRenderCreatePicture (dpy, root, 22122007c8b2Snia XRenderFindVisualFormat (dpy, 22132007c8b2Snia DefaultVisual (dpy, scr)), 22142007c8b2Snia CPSubwindowMode, 22152007c8b2Snia &pa); 22162007c8b2Snia blackPicture = solid_picture (dpy, True, 1, 0, 0, 0); 22172007c8b2Snia if (compMode == CompServerShadows) 22182007c8b2Snia transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0); 22192007c8b2Snia allDamage = None; 22202007c8b2Snia clipChanged = True; 22212007c8b2Snia XGrabServer (dpy); 22222007c8b2Snia if (autoRedirect) 22232007c8b2Snia XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic); 22242007c8b2Snia else 22252007c8b2Snia { 22262007c8b2Snia XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual); 22272007c8b2Snia XSelectInput (dpy, root, 22282007c8b2Snia SubstructureNotifyMask| 22292007c8b2Snia ExposureMask| 22302007c8b2Snia StructureNotifyMask| 22312007c8b2Snia PropertyChangeMask); 22322007c8b2Snia XShapeSelectInput (dpy, root, ShapeNotifyMask); 22332007c8b2Snia XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren); 22342007c8b2Snia for (i = 0; i < nchildren; i++) 22352007c8b2Snia add_win (dpy, children[i], i ? children[i-1] : None); 22362007c8b2Snia XFree (children); 22372007c8b2Snia } 22382007c8b2Snia XUngrabServer (dpy); 22392007c8b2Snia ufd.fd = ConnectionNumber (dpy); 22402007c8b2Snia ufd.events = POLLIN; 22412007c8b2Snia if (!autoRedirect) 22422007c8b2Snia paint_all (dpy, None); 22432007c8b2Snia for (;;) 22442007c8b2Snia { 22452007c8b2Snia /* dump_wins (); */ 22462007c8b2Snia do { 22472007c8b2Snia if (autoRedirect) 22482007c8b2Snia XFlush (dpy); 22492007c8b2Snia if (!QLength (dpy)) 22502007c8b2Snia { 22512007c8b2Snia if (poll (&ufd, 1, fade_timeout()) == 0) 22522007c8b2Snia { 22532007c8b2Snia run_fades (dpy); 22542007c8b2Snia break; 22552007c8b2Snia } 22562007c8b2Snia } 22572007c8b2Snia 22582007c8b2Snia XNextEvent (dpy, &ev); 22592007c8b2Snia if ((ev.type & 0x7f) != KeymapNotify) 22602007c8b2Snia discard_ignore (dpy, ev.xany.serial); 22612007c8b2Snia#if DEBUG_EVENTS 22622007c8b2Snia printf ("event %10.10s serial 0x%08x window 0x%08x\n", 22632007c8b2Snia ev_name(&ev), ev_serial (&ev), ev_window (&ev)); 22642007c8b2Snia#endif 22652007c8b2Snia if (!autoRedirect) switch (ev.type) { 22662007c8b2Snia case CreateNotify: 22672007c8b2Snia add_win (dpy, ev.xcreatewindow.window, 0); 22682007c8b2Snia break; 22692007c8b2Snia case ConfigureNotify: 22702007c8b2Snia configure_win (dpy, &ev.xconfigure); 22712007c8b2Snia break; 22722007c8b2Snia case DestroyNotify: 22732007c8b2Snia destroy_win (dpy, ev.xdestroywindow.window, True, True); 22742007c8b2Snia break; 22752007c8b2Snia case MapNotify: 22762007c8b2Snia map_win (dpy, ev.xmap.window, ev.xmap.serial, True); 22772007c8b2Snia break; 22782007c8b2Snia case UnmapNotify: 22792007c8b2Snia unmap_win (dpy, ev.xunmap.window, True); 22802007c8b2Snia break; 22812007c8b2Snia case ReparentNotify: 22822007c8b2Snia if (ev.xreparent.parent == root) 22832007c8b2Snia add_win (dpy, ev.xreparent.window, 0); 22842007c8b2Snia else 22852007c8b2Snia destroy_win (dpy, ev.xreparent.window, False, True); 22862007c8b2Snia break; 22872007c8b2Snia case CirculateNotify: 22882007c8b2Snia circulate_win (dpy, &ev.xcirculate); 22892007c8b2Snia break; 22902007c8b2Snia case Expose: 22912007c8b2Snia if (ev.xexpose.window == root) 22922007c8b2Snia { 22932007c8b2Snia int more = ev.xexpose.count + 1; 22942007c8b2Snia if (n_expose == size_expose) 22952007c8b2Snia { 22962007c8b2Snia if (expose_rects) 22972007c8b2Snia { 22982007c8b2Snia expose_rects = realloc (expose_rects, 22992007c8b2Snia (size_expose + more) * 23002007c8b2Snia sizeof (XRectangle)); 23012007c8b2Snia size_expose += more; 23022007c8b2Snia } 23032007c8b2Snia else 23042007c8b2Snia { 23052007c8b2Snia expose_rects = malloc (more * sizeof (XRectangle)); 23062007c8b2Snia size_expose = more; 23072007c8b2Snia } 23082007c8b2Snia } 23092007c8b2Snia expose_rects[n_expose].x = ev.xexpose.x; 23102007c8b2Snia expose_rects[n_expose].y = ev.xexpose.y; 23112007c8b2Snia expose_rects[n_expose].width = ev.xexpose.width; 23122007c8b2Snia expose_rects[n_expose].height = ev.xexpose.height; 23132007c8b2Snia n_expose++; 23142007c8b2Snia if (ev.xexpose.count == 0) 23152007c8b2Snia { 23162007c8b2Snia expose_root (dpy, root, expose_rects, n_expose); 23172007c8b2Snia n_expose = 0; 23182007c8b2Snia } 23192007c8b2Snia } 23202007c8b2Snia break; 23212007c8b2Snia case PropertyNotify: 23222007c8b2Snia for (p = 0; backgroundProps[p]; p++) 23232007c8b2Snia { 23242007c8b2Snia if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False)) 23252007c8b2Snia { 23262007c8b2Snia if (rootTile) 23272007c8b2Snia { 23282007c8b2Snia XClearArea (dpy, root, 0, 0, 0, 0, True); 23292007c8b2Snia XRenderFreePicture (dpy, rootTile); 23302007c8b2Snia rootTile = None; 23312007c8b2Snia break; 23322007c8b2Snia } 23332007c8b2Snia } 23342007c8b2Snia } 23352007c8b2Snia /* check if Trans property was changed */ 23362007c8b2Snia if (ev.xproperty.atom == opacityAtom) 23372007c8b2Snia { 23382007c8b2Snia /* reset mode and redraw window */ 23392007c8b2Snia win * w = find_win(dpy, ev.xproperty.window); 23402007c8b2Snia if (w) 23412007c8b2Snia { 23422007c8b2Snia if (fadeTrans) 23432007c8b2Snia { 23442007c8b2Snia double start, finish, step; 23452007c8b2Snia start = w->opacity*1.0/OPAQUE; 23462007c8b2Snia finish = get_opacity_percent (dpy, w, 1.0); 23472007c8b2Snia if(start > finish) 23482007c8b2Snia step = fade_in_step; 23492007c8b2Snia else 23502007c8b2Snia step = fade_out_step; 23512007c8b2Snia set_fade (dpy, w, start, finish, step, 23522007c8b2Snia NULL, False, True, False); 23532007c8b2Snia } 23542007c8b2Snia else 23552007c8b2Snia { 23562007c8b2Snia w->opacity = get_opacity_prop(dpy, w, OPAQUE); 23572007c8b2Snia determine_mode(dpy, w); 23582007c8b2Snia if (w->shadow) 23592007c8b2Snia { 23602007c8b2Snia XRenderFreePicture (dpy, w->shadow); 23612007c8b2Snia w->shadow = None; 23622007c8b2Snia w->extents = win_extents (dpy, w); 23632007c8b2Snia } 23642007c8b2Snia } 23652007c8b2Snia } 23662007c8b2Snia } 23672007c8b2Snia break; 23682007c8b2Snia default: 23692007c8b2Snia if (ev.type == damage_event + XDamageNotify) 23702007c8b2Snia { 23712007c8b2Snia damage_win (dpy, (XDamageNotifyEvent *) &ev); 23722007c8b2Snia } 23732007c8b2Snia else if (ev.type == xshape_event + ShapeNotify) 23742007c8b2Snia { 23752007c8b2Snia shape_win (dpy, (XShapeEvent *) &ev); 23762007c8b2Snia } 23772007c8b2Snia break; 23782007c8b2Snia } 23792007c8b2Snia } while (QLength (dpy)); 23802007c8b2Snia if (allDamage && !autoRedirect) 23812007c8b2Snia { 23822007c8b2Snia static int paint; 23832007c8b2Snia paint_all (dpy, allDamage); 23842007c8b2Snia paint++; 23852007c8b2Snia XSync (dpy, False); 23862007c8b2Snia allDamage = None; 23872007c8b2Snia clipChanged = False; 23882007c8b2Snia } 23892007c8b2Snia } 23902007c8b2Snia} 2391