compositor.c 153 KB
Newer Older
Olivier Fourdan's avatar
Olivier Fourdan committed
1
/*      $Id$
2

Olivier Fourdan's avatar
Olivier Fourdan committed
3 4 5 6
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2, or (at your option)
        any later version.
7

Olivier Fourdan's avatar
Olivier Fourdan committed
8 9 10 11
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
12

Olivier Fourdan's avatar
Olivier Fourdan committed
13 14
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
Olivier Fourdan's avatar
Olivier Fourdan committed
15 16 17
        Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
        MA 02110-1301, USA.

18

Olivier Fourdan's avatar
Olivier Fourdan committed
19
        xcompmgr - (c) 2003 Keith Packard
20
        metacity - (c) 2003, 2004 Red Hat, Inc.
21
        xfwm4    - (c) 2005-2020 Olivier Fourdan
22 23

*/
Olivier Fourdan's avatar
Olivier Fourdan committed
24 25

#ifdef HAVE_CONFIG_H
Olivier Fourdan's avatar
Cleanup  
Olivier Fourdan committed
26
#include "config.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
27 28 29
#endif

#include <X11/Xlib.h>
30 31 32 33
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/shape.h>

Olivier Fourdan's avatar
Olivier Fourdan committed
34 35
#include <glib.h>
#include <math.h>
36
#include <string.h>
37
#include <libxfce4util/libxfce4util.h>
Olivier Fourdan's avatar
Olivier Fourdan committed
38

Olivier Fourdan's avatar
Olivier Fourdan committed
39 40 41
#ifdef HAVE_EPOXY
#include <epoxy/gl.h>
#include <epoxy/glx.h>
42 43 44
#ifdef HAVE_XSYNC_EXTENSION
#include <X11/extensions/sync.h>
#endif /* HAVE_XSYNC_EXTENSION */
Olivier Fourdan's avatar
Olivier Fourdan committed
45
#endif /* HAVE_EPOXY */
46

47
#ifdef HAVE_PRESENT_EXTENSION
48
#ifndef PRESENT_FUTURE_VERSION
49
#define PRESENT_FUTURE_VERSION 0
50
#endif /* PRESENT_FUTURE_VERSION */
51 52 53
#include <X11/extensions/Xpresent.h>
#endif /* HAVE_PRESENT_EXTENSION */

Olivier Fourdan's avatar
Olivier Fourdan committed
54 55 56 57 58
#include "display.h"
#include "screen.h"
#include "client.h"
#include "frame.h"
#include "hints.h"
59
#include "compositor.h"
Olivier Fourdan's avatar
Olivier Fourdan committed
60 61

#ifdef HAVE_COMPOSITOR
62 63
#include "common/xfwm-common.h"

64 65 66 67
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>

Olivier Fourdan's avatar
Olivier Fourdan committed
68
#ifndef SHADOW_RADIUS
69
#define SHADOW_RADIUS   12
Olivier Fourdan's avatar
Olivier Fourdan committed
70 71
#endif /* SHADOW_RADIUS */

Olivier Fourdan's avatar
Olivier Fourdan committed
72
#ifndef SHADOW_OFFSET_X
73
#define SHADOW_OFFSET_X (-3 * SHADOW_RADIUS / 2)
Olivier Fourdan's avatar
Olivier Fourdan committed
74 75 76
#endif /* SHADOW_OFFSET_X */

#ifndef SHADOW_OFFSET_Y
77
#define SHADOW_OFFSET_Y (-3 * SHADOW_RADIUS / 2)
Olivier Fourdan's avatar
Olivier Fourdan committed
78
#endif /* SHADOW_OFFSET_Y */
Olivier Fourdan's avatar
Olivier Fourdan committed
79

Olivier Fourdan's avatar
Olivier Fourdan committed
80
/* Some convenient macros */
81
#define WIN_HAS_CLIENT(cw)              (cw->c)
82
#define WIN_HAS_FRAME(cw)               (WIN_HAS_CLIENT(cw) && CLIENT_HAS_FRAME(cw->c))
83 84
#define WIN_NO_SHADOW(cw)               ((cw->c) && \
                                           (FLAG_TEST (cw->c->flags, CLIENT_FLAG_FULLSCREEN | CLIENT_FLAG_BELOW) || \
85 86
                                            (cw->c->type & WINDOW_DESKTOP)))
#define WIN_IS_DOCK(cw)                 (WIN_HAS_CLIENT(cw) && (cw->c->type & WINDOW_DOCK))
87
#define WIN_IS_OVERRIDE(cw)             (cw->attr.override_redirect)
88
#define WIN_IS_ARGB(cw)                 (cw->argb)
89
#define WIN_IS_OPAQUE(cw)               ((cw->opacity == NET_WM_OPAQUE) && !WIN_IS_ARGB(cw))
90
#define WIN_IS_NATIVE_OPAQUE(cw)        ((cw->native_opacity) && !WIN_IS_ARGB(cw))
91 92 93 94
#define WIN_IS_FULLSCREEN(cw)           ((cw->attr.x <= 0) && \
                                           (cw->attr.y <= 0) && \
                                           (cw->attr.width + 2 * cw->attr.border_width >= cw->screen_info->width) && \
                                           (cw->attr.height + 2 * cw->attr.border_width >= cw->screen_info->height))
95
#define WIN_IS_SHAPED(cw)               ((WIN_HAS_CLIENT(cw) && FLAG_TEST (cw->c->flags, CLIENT_FLAG_HAS_SHAPE)) || \
96
                                           (WIN_IS_OVERRIDE(cw) && (cw->shaped)))
97
#define WIN_IS_MAXIMIZED(cw)            (WIN_HAS_CLIENT(cw) && FLAG_TEST_ALL (cw->c->flags, CLIENT_FLAG_MAXIMIZED))
98 99 100
#define WIN_IS_VIEWABLE(cw)             (cw->viewable)
#define WIN_HAS_DAMAGE(cw)              (cw->damage)
#define WIN_IS_VISIBLE(cw)              (WIN_IS_VIEWABLE(cw) && WIN_HAS_DAMAGE(cw))
101 102
#define WIN_IS_DAMAGED(cw)              (cw->damaged)
#define WIN_IS_REDIRECTED(cw)           (cw->redirected)
103
#define WIN_IS_SHADED(cw)               (WIN_HAS_CLIENT(cw) && FLAG_TEST (cw->c->flags, CLIENT_FLAG_SHADED))
Olivier Fourdan's avatar
 
Olivier Fourdan committed
104

105
#ifndef TIMEOUT_REPAINT_PRIORITY
106
#define TIMEOUT_REPAINT_PRIORITY   G_PRIORITY_DEFAULT
107
#endif /* TIMEOUT_REPAINT_PRIORITY */
108

109 110 111 112
#ifndef TIMEOUT_THROTTLED_REPAINT_PRIORITY
#define TIMEOUT_THROTTLED_REPAINT_PRIORITY   G_PRIORITY_LOW
#endif /* TIMEOUT_THROTTLED_REPAINT_PRIORITY */

113 114 115 116
#ifndef TIMEOUT_REPAINT_MS
#define TIMEOUT_REPAINT_MS   1
#endif /* TIMEOUT_REPAINT_MS */

117 118 119
#ifndef TIMEOUT_THROTTLED_REPAINT_MS
#define TIMEOUT_THROTTLED_REPAINT_MS   500
#endif /* TIMEOUT_THROTTLED_REPAINT_MS */
120

121 122 123 124
#ifndef MONITOR_ROOT_PIXMAP
#define MONITOR_ROOT_PIXMAP   1
#endif /* MONITOR_ROOT_PIXMAP */

Olivier Fourdan's avatar
Olivier Fourdan committed
125 126 127 128 129 130 131 132 133 134
typedef struct _CWindow CWindow;
struct _CWindow
{
    ScreenInfo *screen_info;
    Client *c;
    Window id;
    XWindowAttributes attr;

    gboolean damaged;
    gboolean viewable;
135
    gboolean shaped;
Olivier Fourdan's avatar
Olivier Fourdan committed
136
    gboolean redirected;
137
    gboolean fulloverlay;
Olivier Fourdan's avatar
Olivier Fourdan committed
138 139
    gboolean argb;
    gboolean skipped;
140
    gboolean native_opacity;
141
    gboolean opacity_locked;
Olivier Fourdan's avatar
Olivier Fourdan committed
142

Olivier Fourdan's avatar
Olivier Fourdan committed
143
    Damage damage;
Olivier Fourdan's avatar
Olivier Fourdan committed
144 145
#if HAVE_NAME_WINDOW_PIXMAP
    Pixmap name_window_pixmap;
146
#endif /* HAVE_NAME_WINDOW_PIXMAP */
Olivier Fourdan's avatar
Olivier Fourdan committed
147
    Picture picture;
148
    Picture saved_picture;
Olivier Fourdan's avatar
Olivier Fourdan committed
149
    Picture shadow;
Olivier Fourdan's avatar
Olivier Fourdan committed
150 151
    Picture alphaPict;
    Picture shadowPict;
152
    Picture alphaBorderPict;
Olivier Fourdan's avatar
Olivier Fourdan committed
153

Olivier Fourdan's avatar
Olivier Fourdan committed
154
    XserverRegion borderSize;
155
    XserverRegion clientSize;
Olivier Fourdan's avatar
Olivier Fourdan committed
156
    XserverRegion borderClip;
Olivier Fourdan's avatar
Olivier Fourdan committed
157
    XserverRegion extents;
158
    XserverRegion opaque_region;
Olivier Fourdan's avatar
Olivier Fourdan committed
159

160 161 162 163
    gint shadow_dx;
    gint shadow_dy;
    gint shadow_width;
    gint shadow_height;
164

165
    guint32 opacity;
166
    guint32 bypass_compositor;
Olivier Fourdan's avatar
Olivier Fourdan committed
167 168 169 170 171 172 173
};

static CWindow*
find_cwindow_in_screen (ScreenInfo *screen_info, Window id)
{
    g_return_val_if_fail (id != None, NULL);
    g_return_val_if_fail (screen_info != NULL, NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
174
    TRACE ("window 0x%lx", id);
Olivier Fourdan's avatar
Olivier Fourdan committed
175

176
    return g_hash_table_lookup(screen_info->cwindow_hash, (gpointer) id);
Olivier Fourdan's avatar
Olivier Fourdan committed
177 178 179 180 181
}

static CWindow*
find_cwindow_in_display (DisplayInfo *display_info, Window id)
{
182
    GSList *list;
Olivier Fourdan's avatar
Olivier Fourdan committed
183 184 185

    g_return_val_if_fail (id != None, NULL);
    g_return_val_if_fail (display_info != NULL, NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
186
    TRACE ("window 0x%lx", id);
Olivier Fourdan's avatar
Olivier Fourdan committed
187

188
    for (list = display_info->screens; list; list = g_slist_next (list))
Olivier Fourdan's avatar
Olivier Fourdan committed
189
    {
190
        ScreenInfo *screen_info = (ScreenInfo *) list->data;
191
        CWindow *cw;
192 193 194 195 196 197

        if (!compositorIsActive (screen_info))
        {
            continue;
        }

198
        cw = find_cwindow_in_screen (screen_info, id);
Olivier Fourdan's avatar
Olivier Fourdan committed
199 200 201 202 203 204 205 206
        if (cw)
        {
            return (cw);
        }
    }
    return NULL;
}

207 208 209 210 211 212 213
static gboolean
is_output (DisplayInfo *display_info, Window id)
{
    GSList *list;

    g_return_val_if_fail (id != None, FALSE);
    g_return_val_if_fail (display_info != NULL, FALSE);
Olivier Fourdan's avatar
Olivier Fourdan committed
214
    TRACE ("window 0x%lx", id);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

    for (list = display_info->screens; list; list = g_slist_next (list))
    {
        ScreenInfo *screen_info = (ScreenInfo *) list->data;
#if HAVE_OVERLAYS
        if (id == screen_info->output || id == screen_info->overlay)
#else
        if (id == screen_info->output)
#endif
        {
            return TRUE;
        }
    }
    return FALSE;
}

231 232 233 234 235 236
static gboolean
is_shaped (DisplayInfo *display_info, Window id)
{
    int xws, yws, xbs, ybs;
    unsigned wws, hws, wbs, hbs;
    int boundingShaped, clipShaped;
237
    int result;
238 239 240 241 242

    g_return_val_if_fail (display_info != NULL, FALSE);

    if (display_info->have_shape)
    {
243
        myDisplayErrorTrapPush (display_info);
244 245
        XShapeQueryExtents (display_info->dpy, id, &boundingShaped, &xws, &yws, &wws,
                            &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs);
246 247 248
        result = myDisplayErrorTrapPop (display_info);

        return ((result == Success) && (boundingShaped != 0));
249 250 251 252
    }
    return FALSE;
}

253 254 255 256 257 258
static gboolean
is_fullscreen (CWindow *cw)
{
    GdkRectangle rect;

    /* First, check the good old way, the window is larger than the screen size */
259
    if (WIN_IS_FULLSCREEN(cw))
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    {
        return TRUE;
    }

    /* Next check against the monitors which compose the entire screen */
    myScreenFindMonitorAtPoint (cw->screen_info,
                                cw->attr.x + (cw->attr.width + 2 * cw->attr.border_width) / 2,
                                cw->attr.y + (cw->attr.height + 2 * cw->attr.border_width) / 2,
                                &rect);

    return ((cw->attr.x == rect.x) &&
            (cw->attr.y == rect.y) &&
            (cw->attr.width + 2 * cw->attr.border_width == rect.width) &&
            (cw->attr.height + 2 * cw->attr.border_width == rect.height));
}

276 277 278 279 280 281
static gboolean
is_on_compositor (CWindow *cw)
{
    return (cw && compositorIsActive (cw->screen_info));
}

Olivier Fourdan's avatar
Olivier Fourdan committed
282 283 284 285 286 287 288 289 290 291 292
static gdouble
gaussian (gdouble r, gdouble x, gdouble y)
{
    return ((1 / (sqrt (2 * G_PI * r))) *
            exp ((- (x * x + y * y)) / (2 * r * r)));
}

static gaussian_conv *
make_gaussian_map (gdouble r)
{
    gaussian_conv *c;
Olivier Fourdan's avatar
Olivier Fourdan committed
293
    gint size, center;
Olivier Fourdan's avatar
Olivier Fourdan committed
294 295 296 297
    gint x, y;
    gdouble t;
    gdouble g;

Olivier Fourdan's avatar
Olivier Fourdan committed
298
    TRACE ("entering");
299

Olivier Fourdan's avatar
Olivier Fourdan committed
300 301
    size = ((gint) ceil ((r * 3)) + 1) & ~1;
    center = size / 2;
302
    c = g_malloc0 (sizeof (gaussian_conv) + size * size * sizeof (gdouble));
Olivier Fourdan's avatar
Olivier Fourdan committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    c->size = size;
    c->data = (gdouble *) (c + 1);
    t = 0.0;

    for (y = 0; y < size; y++)
    {
        for (x = 0; x < size; x++)
        {
            g = gaussian (r, (gdouble) (x - center), (gdouble) (y - center));
            t += g;
            c->data[y * size + x] = g;
        }
    }

    for (y = 0; y < size; y++)
    {
        for (x = 0; x < size; x++)
        {
            c->data[y*size + x] /= t;
        }
323
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
324 325 326 327 328

    return c;
}

/*
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
* A picture will help
*
*      -center   0                width  width+center
*  -center +-----+-------------------+-----+
*          |     |                   |     |
*          |     |                   |     |
*        0 +-----+-------------------+-----+
*          |     |                   |     |
*          |     |                   |     |
*          |     |                   |     |
*   height +-----+-------------------+-----+
*          |     |                   |     |
* height+  |     |                   |     |
*  center  +-----+-------------------+-----+
*/

345
static guchar
Olivier Fourdan's avatar
Olivier Fourdan committed
346 347
sum_gaussian (gaussian_conv *map, gdouble opacity, gint x, gint y, gint width, gint height)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
348 349
    gdouble *g_data, *g_line;
    gdouble v;
Olivier Fourdan's avatar
Olivier Fourdan committed
350 351 352
    gint fx, fy;
    gint fx_start, fx_end;
    gint fy_start, fy_end;
Olivier Fourdan's avatar
Olivier Fourdan committed
353
    gint g_size, center;
354

Olivier Fourdan's avatar
Olivier Fourdan committed
355
    g_return_val_if_fail (map != NULL, (guchar) 255.0);
Olivier Fourdan's avatar
Olivier Fourdan committed
356
    TRACE ("(%i,%i) [%i×%i]", x, y, width, height);
357

Olivier Fourdan's avatar
Olivier Fourdan committed
358 359 360
    g_line = map->data;
    g_size = map->size;
    center = g_size / 2;
Olivier Fourdan's avatar
Olivier Fourdan committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    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;
383

Olivier Fourdan's avatar
Olivier Fourdan committed
384 385 386 387 388
    v = 0;
    for (fy = fy_start; fy < fy_end; fy++)
    {
        g_data = g_line;
        g_line += g_size;
389

Olivier Fourdan's avatar
Olivier Fourdan committed
390 391 392 393 394 395 396 397 398
        for (fx = fx_start; fx < fx_end; fx++)
        {
            v += *g_data++;
        }
    }
    if (v > 1)
    {
        v = 1;
    }
399

400 401 402 403 404 405 406 407 408 409
    return ((guchar) (v * opacity * 255.0));
}

/* precompute shadow corners and sides to save time for large windows */
static void
presum_gaussian (ScreenInfo *screen_info)
{
    gint center;
    gint opacity, x, y;
    gaussian_conv * map;
410

Olivier Fourdan's avatar
Olivier Fourdan committed
411 412
    g_return_if_fail (screen_info != NULL);
    g_return_if_fail (screen_info->gaussianMap != NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
413
    TRACE ("entering");
414

415
    map = screen_info->gaussianMap;
416
    screen_info->gaussianSize = map->size;
417 418 419 420 421 422 423 424 425 426 427
    center = map->size / 2;

    if (screen_info->shadowCorner)
    {
        g_free (screen_info->shadowCorner);
    }
    if (screen_info->shadowTop)
    {
        g_free (screen_info->shadowTop);
    }

428
    screen_info->shadowCorner = (guchar *) (g_malloc0 ((screen_info->gaussianSize + 1)
429
                                                    * (screen_info->gaussianSize + 1) * 26));
430
    screen_info->shadowTop = (guchar *) (g_malloc0 ((screen_info->gaussianSize + 1) * 26));
431

432
    for (x = 0; x <= screen_info->gaussianSize; x++)
433
    {
434
        screen_info->shadowTop[25 * (screen_info->gaussianSize + 1) + x] =
435
            sum_gaussian (map, 1, x - center, center,
436 437
                          screen_info->gaussianSize * 2,
                          screen_info->gaussianSize * 2);
438

439 440
        for(opacity = 0; opacity < 25; opacity++)
        {
441 442
            screen_info->shadowTop[opacity * (screen_info->gaussianSize + 1) + x] =
                screen_info->shadowTop[25 * (screen_info->gaussianSize + 1) + x] * opacity / 25;
443
        }
444

445 446
        for(y = 0; y <= x; y++)
        {
447 448 449
            screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
                                         * (screen_info->gaussianSize + 1)
                                     + y * (screen_info->gaussianSize + 1) + x]
450 451
                = sum_gaussian (map, 1, x - center,
                                        y - center,
452 453 454 455 456 457 458 459
                                        screen_info->gaussianSize * 2,
                                        screen_info->gaussianSize * 2);
            screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
                                         * (screen_info->gaussianSize + 1)
                                     + x * (screen_info->gaussianSize + 1) + y]
                = screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
                                               * (screen_info->gaussianSize + 1)
                                           + y * (screen_info->gaussianSize + 1) + x];
460

461 462
            for(opacity = 0; opacity < 25; opacity++)
            {
463 464 465 466 467 468 469 470 471
                screen_info->shadowCorner[opacity * (screen_info->gaussianSize + 1)
                                                  * (screen_info->gaussianSize + 1)
                                              + y * (screen_info->gaussianSize + 1) + x]
                    = screen_info->shadowCorner[opacity * (screen_info->gaussianSize + 1)
                                                        * (screen_info->gaussianSize + 1)
                                                    + x * (screen_info->gaussianSize + 1) + y]
                    = screen_info->shadowCorner[25 * (screen_info->gaussianSize + 1)
                                                   * (screen_info->gaussianSize + 1)
                                               + y * (screen_info->gaussianSize + 1) + x] * opacity / 25;
472 473 474
            }
        }
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
475 476 477 478 479
}

static XImage *
make_shadow (ScreenInfo *screen_info, gdouble opacity, gint width, gint height)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
480
    DisplayInfo *display_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
481
    XImage *ximage;
482 483
    guchar *data;
    guchar d;
484
    gint gaussianSize;
Olivier Fourdan's avatar
Olivier Fourdan committed
485
    gint ylimit, xlimit;
486 487 488
    gint swidth;
    gint sheight;
    gint center;
Olivier Fourdan's avatar
Olivier Fourdan committed
489 490
    gint x, y;
    gint x_diff;
Olivier Fourdan's avatar
Olivier Fourdan committed
491
    gint opacity_int;
492 493
    gint x_swidth;
    gint y_swidth;
494

Olivier Fourdan's avatar
Olivier Fourdan committed
495
    g_return_val_if_fail (screen_info != NULL, NULL);
Olivier Fourdan's avatar
Olivier Fourdan committed
496
    TRACE ("entering");
497

Olivier Fourdan's avatar
Olivier Fourdan committed
498
    display_info = screen_info->display_info;
499 500 501 502
    gaussianSize = screen_info->gaussianMap->size;
    swidth = width + gaussianSize - screen_info->params->shadow_delta_width - screen_info->params->shadow_delta_x;
    sheight = height + gaussianSize - screen_info->params->shadow_delta_height - screen_info->params->shadow_delta_y;
    center = gaussianSize / 2;
Olivier Fourdan's avatar
Olivier Fourdan committed
503
    opacity_int = (gint) (opacity * 25);
504

505 506 507 508
    if ((swidth < 1) || (sheight < 1))
    {
        return NULL;
    }
509

510
    data = g_malloc0 (swidth * sheight * sizeof (guchar));
511

Olivier Fourdan's avatar
Olivier Fourdan committed
512 513
    ximage = XCreateImage (display_info->dpy,
                        DefaultVisual(display_info->dpy, screen_info->screen),
514 515
                        8, ZPixmap, 0, (char *) data,
                        swidth, sheight, 8, swidth * sizeof (guchar));
Olivier Fourdan's avatar
Olivier Fourdan committed
516
    if (ximage == NULL)
Olivier Fourdan's avatar
Olivier Fourdan committed
517
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
518 519
        g_free (data);
        g_warning ("(ximage != NULL) failed");
Olivier Fourdan's avatar
Olivier Fourdan committed
520 521
        return NULL;
    }
522

Olivier Fourdan's avatar
Olivier Fourdan committed
523
    /*
524 525
    * Build the gaussian in sections
    */
Olivier Fourdan's avatar
Olivier Fourdan committed
526

527
    if (screen_info->gaussianSize > 0)
528
    {
529
        d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + screen_info->gaussianSize];
530 531 532 533 534 535
    }
    else
    {
        d = sum_gaussian (screen_info->gaussianMap, opacity, center, center, width, height);
    }
    memset(data, d, sheight * swidth);
536

Olivier Fourdan's avatar
Olivier Fourdan committed
537
    /*
538 539
    * corners
    */
540

541
    ylimit = gaussianSize;
Olivier Fourdan's avatar
Olivier Fourdan committed
542 543 544
    if (ylimit > sheight / 2)
    {
        ylimit = (sheight + 1) / 2;
545
    }
546
    xlimit = gaussianSize;
Olivier Fourdan's avatar
Olivier Fourdan committed
547 548 549 550 551 552 553 554
    if (xlimit > swidth / 2)
    {
        xlimit = (swidth + 1) / 2;
    }
    for (y = 0; y < ylimit; y++)
    {
        for (x = 0; x < xlimit; x++)
        {
555
            if ((xlimit == screen_info->gaussianSize) && (ylimit == screen_info->gaussianSize))
556
            {
557 558 559
                d = screen_info->shadowCorner[opacity_int * (screen_info->gaussianSize + 1)
                                                        * (screen_info->gaussianSize + 1)
                                                    + y * (screen_info->gaussianSize + 1) + x];
560 561 562
            }
            else
            {
563
                d = sum_gaussian (screen_info->gaussianMap, opacity,
564
                                x - center, y - center, width, height);
565
            }
566

Olivier Fourdan's avatar
Olivier Fourdan committed
567 568 569 570 571 572 573 574
            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;
        }
    }

    /*
575 576
    * top/bottom
    */
577

578
    x_diff = swidth - (gaussianSize * 2);
Olivier Fourdan's avatar
Olivier Fourdan committed
579 580 581 582
    if (x_diff > 0 && ylimit > 0)
    {
        for (y = 0; y < ylimit; y++)
        {
583
            if (ylimit == screen_info->gaussianSize)
584
            {
585
                d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + y];
586 587
            }
            else
588
            {
589 590
                d = sum_gaussian (screen_info->gaussianMap, opacity, center, y - center, width, height);
            }
591 592
            memset (&data[y * swidth + gaussianSize], d, x_diff);
            memset (&data[(sheight - y - 1) * swidth + gaussianSize], d, x_diff);
Olivier Fourdan's avatar
Olivier Fourdan committed
593 594 595 596
        }
    }

    /*
597 598
    * sides
    */
599

Olivier Fourdan's avatar
Olivier Fourdan committed
600 601
    for (x = 0; x < xlimit; x++)
    {
602
        if (xlimit == screen_info->gaussianSize)
603
        {
604
            d = screen_info->shadowTop[opacity_int * (screen_info->gaussianSize + 1) + x];
605 606 607 608 609
        }
        else
        {
            d = sum_gaussian (screen_info->gaussianMap, opacity, x - center, center, width, height);
        }
610
        x_swidth = swidth - x - 1;
611
        for (y = gaussianSize; y < sheight - gaussianSize; y++)
Olivier Fourdan's avatar
Olivier Fourdan committed
612
        {
613 614 615
            y_swidth = y * swidth;
            data[y_swidth + x] = d;
            data[y_swidth + x_swidth] = d;
Olivier Fourdan's avatar
Olivier Fourdan committed
616 617 618 619 620 621 622
        }
    }

    return ximage;
}

static Picture
Olivier Fourdan's avatar
Olivier Fourdan committed
623
shadow_picture (ScreenInfo *screen_info, gdouble opacity,
Olivier Fourdan's avatar
Olivier Fourdan committed
624 625
                gint width, gint height, gint *wp, gint *hp)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
626
    DisplayInfo *display_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
627 628 629 630 631
    XImage *shadowImage;
    Pixmap shadowPixmap;
    Picture shadowPicture;
    XRenderPictFormat *render_format;
    GC gc;
632

Olivier Fourdan's avatar
Olivier Fourdan committed
633
    g_return_val_if_fail (screen_info != NULL, None);
Olivier Fourdan's avatar
Olivier Fourdan committed
634
    TRACE ("entering");
Olivier Fourdan's avatar
Olivier Fourdan committed
635

Olivier Fourdan's avatar
Olivier Fourdan committed
636 637
    display_info = screen_info->display_info;
    render_format = XRenderFindStandardFormat (display_info->dpy, PictStandardA8);
Olivier Fourdan's avatar
Olivier Fourdan committed
638
    g_return_val_if_fail (render_format != NULL, None);
Olivier Fourdan's avatar
Olivier Fourdan committed
639

640
    shadowImage = make_shadow (screen_info, opacity, width, height);
641 642 643
    if (shadowImage == NULL)
    {
        *wp = *hp = 0;
Olivier Fourdan's avatar
Olivier Fourdan committed
644
        g_warning ("(shadowImage != NULL) failed");
645
        return (None);
646
    }
Olivier Fourdan's avatar
Olivier Fourdan committed
647

648
    shadowPixmap = XCreatePixmap (display_info->dpy, screen_info->output,
649
                                shadowImage->width, shadowImage->height, 8);
650
    if (shadowPixmap == None)
Olivier Fourdan's avatar
Olivier Fourdan committed
651 652
    {
        XDestroyImage (shadowImage);
Olivier Fourdan's avatar
Olivier Fourdan committed
653
        g_warning ("(shadowPixmap != None) failed");
Olivier Fourdan's avatar
Olivier Fourdan committed
654 655
        return None;
    }
656

Olivier Fourdan's avatar
Olivier Fourdan committed
657
    shadowPicture = XRenderCreatePicture (display_info->dpy,
658
                                        shadowPixmap, render_format, 0, NULL);
659
    if (shadowPicture == None)
Olivier Fourdan's avatar
Olivier Fourdan committed
660 661
    {
        XDestroyImage (shadowImage);
Olivier Fourdan's avatar
Olivier Fourdan committed
662
        XFreePixmap (display_info->dpy, shadowPixmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
663
        g_warning ("(shadowPicture != None) failed");
Olivier Fourdan's avatar
Olivier Fourdan committed
664 665 666
        return None;
    }

Olivier Fourdan's avatar
Olivier Fourdan committed
667 668
    gc = XCreateGC (display_info->dpy, shadowPixmap, 0, NULL);
    XPutImage (display_info->dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0,
669
            shadowImage->width, shadowImage->height);
Olivier Fourdan's avatar
Olivier Fourdan committed
670 671 672 673

    *wp = shadowImage->width;
    *hp = shadowImage->height;

Olivier Fourdan's avatar
Olivier Fourdan committed
674
    XFreeGC (display_info->dpy, gc);
Olivier Fourdan's avatar
Olivier Fourdan committed
675
    XDestroyImage (shadowImage);
Olivier Fourdan's avatar
Olivier Fourdan committed
676
    XFreePixmap (display_info->dpy, shadowPixmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
677 678 679 680 681

    return shadowPicture;
}

static Picture
682 683
solid_picture (ScreenInfo *screen_info, gboolean argb,
               gdouble a, gdouble r, gdouble g, gdouble b)
Olivier Fourdan's avatar
Olivier Fourdan committed
684
{
Olivier Fourdan's avatar
Olivier Fourdan committed
685
    DisplayInfo *display_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
686 687 688 689 690 691
    Pixmap pixmap;
    Picture picture;
    XRenderPictureAttributes pa;
    XRenderPictFormat *render_format;
    XRenderColor c;

Olivier Fourdan's avatar
Olivier Fourdan committed
692
    g_return_val_if_fail (screen_info, None);
Olivier Fourdan's avatar
Olivier Fourdan committed
693
    TRACE ("entering");
694

Olivier Fourdan's avatar
Olivier Fourdan committed
695 696
    display_info = screen_info->display_info;
    render_format = XRenderFindStandardFormat (display_info->dpy,
697
                                    argb ? PictStandardARGB32 : PictStandardA8);
Olivier Fourdan's avatar
Olivier Fourdan committed
698
    g_return_val_if_fail (render_format != NULL , None);
699

Olivier Fourdan's avatar
Olivier Fourdan committed
700
    pixmap = XCreatePixmap (display_info->dpy,
701
                            screen_info->output, 1, 1, argb ? 32 : 8);
Olivier Fourdan's avatar
Olivier Fourdan committed
702
    g_return_val_if_fail (pixmap != None, None);
703

Olivier Fourdan's avatar
Olivier Fourdan committed
704
    pa.repeat = TRUE;
Olivier Fourdan's avatar
Olivier Fourdan committed
705
    picture = XRenderCreatePicture (display_info->dpy, pixmap,
706
                                    render_format, CPRepeat, &pa);
707
    if (picture == None)
Olivier Fourdan's avatar
Olivier Fourdan committed
708
    {
Olivier Fourdan's avatar
Olivier Fourdan committed
709
        XFreePixmap (display_info->dpy, pixmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
710
        g_warning ("(picture != None) failed");
Olivier Fourdan's avatar
Olivier Fourdan committed
711 712 713 714
        return None;
    }

    c.alpha = a * 0xffff;
715
    c.red   = r * 0xffff;
Olivier Fourdan's avatar
Olivier Fourdan committed
716
    c.green = g * 0xffff;
717
    c.blue  = b * 0xffff;
Olivier Fourdan's avatar
Olivier Fourdan committed
718

Olivier Fourdan's avatar
Olivier Fourdan committed
719
    XRenderFillRectangle (display_info->dpy, PictOpSrc,
720
                          picture, &c, 0, 0, 1, 1);
Olivier Fourdan's avatar
Olivier Fourdan committed
721
    XFreePixmap (display_info->dpy, pixmap);
Olivier Fourdan's avatar
Olivier Fourdan committed
722 723 724 725

    return picture;
}

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
static void
translate_to_client_region (CWindow *cw, XserverRegion region)
{
    DisplayInfo *display_info;
    ScreenInfo *screen_info;
    int x, y;

    g_return_if_fail (cw != NULL);
    TRACE ("window 0x%lx", cw->id);

    screen_info = cw->screen_info;
    display_info = screen_info->display_info;

    if (WIN_HAS_FRAME(cw))
    {
        x = frameX (cw->c) + frameLeft (cw->c);
        y = frameY (cw->c) + frameTop (cw->c);
    }
    else
    {
        x = cw->attr.x + cw->attr.border_width;
        y = cw->attr.y + cw->attr.border_width;
    }

    XFixesTranslateRegion (display_info->dpy, region, x, y);
}

Olivier Fourdan's avatar
Olivier Fourdan committed
753
static XserverRegion
754
client_size (CWindow *cw)
Olivier Fourdan's avatar
Olivier Fourdan committed
755
{
Olivier Fourdan's avatar
Olivier Fourdan committed
756 757
    DisplayInfo *display_info;
    ScreenInfo *screen_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
758 759 760
    XserverRegion border;

    g_return_val_if_fail (cw != NULL, None);
Olivier Fourdan's avatar
Olivier Fourdan committed
761
    TRACE ("window 0x%lx", cw->id);
762

Olivier Fourdan's avatar
Olivier Fourdan committed
763 764
    screen_info = cw->screen_info;
    display_info = screen_info->display_info;
765
    border = None;
766

767
    if (WIN_HAS_FRAME(cw))
Olivier Fourdan's avatar
Olivier Fourdan committed
768
    {
769
        XRectangle  r;
Olivier Fourdan's avatar
Olivier Fourdan committed
770
        Client *c;
771

Olivier Fourdan's avatar
Olivier Fourdan committed
772
        c = cw->c;
773 774 775 776
        r.x = frameX (c) + frameLeft (c);
        r.y = frameY (c) + frameTop (c);
        r.width = frameWidth (c) - frameLeft (c) - frameRight (c);
        r.height = frameHeight (c) - frameTop (c) - frameBottom (c);
Olivier Fourdan's avatar
Olivier Fourdan committed
777
        border = XFixesCreateRegion (display_info->dpy, &r, 1);
Olivier Fourdan's avatar
Olivier Fourdan committed
778 779
    }

780 781
    return border;
}
Olivier Fourdan's avatar
Olivier Fourdan committed
782

783 784 785
static XserverRegion
border_size (CWindow *cw)
{
Olivier Fourdan's avatar
Olivier Fourdan committed
786 787
    DisplayInfo *display_info;
    ScreenInfo *screen_info;
788
    XserverRegion border;
Olivier Fourdan's avatar
Olivier Fourdan committed
789

790
    g_return_val_if_fail (cw != NULL, None);
Olivier Fourdan's avatar
Olivier Fourdan committed
791
    TRACE ("window 0x%lx", cw->id);
792

Olivier Fourdan's avatar
Olivier Fourdan committed
793 794
    screen_info = cw->screen_info;
    display_info = screen_info->display_info;
Olivier Fourdan's avatar
Olivier Fourdan committed
795
    myDisplayErrorTrapPush (display_info);
796
    border = XFixesCreateRegionFromWindow (display_info->dpy,
797
                                           cw->id, WindowRegionBounding);
798
    XFixesSetPictureClipRegion (display_info->dpy, cw->picture, 0, 0, border);
799 800
    XFixesTranslateRegion (display_info->dpy, border,
                           cw->attr.x + cw->attr.border_width,
801
                           cw->attr.y + cw->attr.border_width);
Olivier Fourdan's avatar
Olivier Fourdan committed
802

803 804 805 806 807
    if (myDisplayErrorTrapPop (display_info) != Success)
    {
        return None;
    }

Olivier Fourdan's avatar
Olivier Fourdan committed
808 809 810
    return border;
}

811 812 813 814 815 816 817 818 819
static void
free_win_data (CWindow *cw, gboolean delete)
{
    DisplayInfo *display_info;
    ScreenInfo *screen_info;

    screen_info = cw->screen_info;
    display_info = screen_info->display_info;

Olivier Fourdan's avatar
Olivier Fourdan committed
820
    myDisplayErrorTrapPush (display_info);
821 822 823
#if HAVE_NAME_WINDOW_PIXMAP
    if (cw->name_window_pixmap)
    {
824
        XFreePixmap (display_info->dpy, cw->name_window_pixmap);
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
        cw->name_window_pixmap = None;
    }
#endif

    if (cw->shadow)
    {
        XRenderFreePicture (display_info->dpy, cw->shadow);
        cw->shadow = None;
    }

    if (cw->alphaPict)
    {
        XRenderFreePicture (display_info->dpy, cw->alphaPict);
        cw->alphaPict = None;
    }

    if (cw->shadowPict)
    {
        XRenderFreePicture (display_info->dpy, cw->shadowPict);
        cw->shadowPict = None;
    }

    if (cw->alphaBorderPict)
    {
        XRenderFreePicture (display_info->dpy, cw->alphaBorderPict);
        cw->alphaBorderPict = None;
    }

    if (cw->borderSize)
    {
        XFixesDestroyRegion (display_info->dpy, cw->borderSize);
        cw->borderSize = None;
    }

859
    if (cw->clientSize)
860
    {
861 862
        XFixesDestroyRegion (display_info->dpy, cw->clientSize);
        cw->clientSize = None;
863 864 865 866 867 868 869 870
    }

    if (cw->borderClip)
    {
        XFixesDestroyRegion (display_info->dpy, cw->borderClip);
        cw->borderClip = None;
    }

871 872 873 874 875 876
    if (cw->extents)
    {
        XFixesDestroyRegion (display_info->dpy, cw->extents);
        cw->extents = None;
    }

877 878
    if (delete)
    {
879 880 881 882 883
        if (cw->picture)
        {
            XRenderFreePicture (display_info->dpy, cw->picture);
            cw->picture = None;
        }
884 885 886 887 888 889 890
        /* No need to keep this around */
        if (cw->saved_picture)
        {
            XRenderFreePicture (display_info->dpy, cw->saved_picture);
            cw->saved_picture = None;
        }

891
        if (cw->damage)
Olivier Fourdan's avatar