~ucl-cs-study-devs/activityfinder/xfwm4

« back to all changes in this revision

Viewing changes to .pc/ucl_sandbox_visibility.diff/src/mypixmap.c

  • Committer: Steve Dodier-Lazaro
  • Date: 2015-12-12 19:13:20 UTC
  • Revision ID: sidnioulz@gmail.com-20151212191320-it6xp5idwhskcg33
Adding sandboxed window visualisation (untrusted n protected)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $Id$
 
2
 
 
3
        This program is free software; you can redistribute it and/or modify
 
4
        it under the terms of the GNU General Public License as published by
 
5
        the Free Software Foundation; either version 2, or (at your option)
 
6
        any later version.
 
7
 
 
8
        This program is distributed in the hope that it will be useful,
 
9
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
        GNU General Public License for more details.
 
12
 
 
13
        You should have received a copy of the GNU General Public License
 
14
        along with this program; if not, write to the Free Software
 
15
        Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
 
16
        MA 02110-1301, USA.
 
17
 
 
18
 
 
19
        Original XPM load routines from gdk-pixbuf:
 
20
 
 
21
        Copyright (C) 1999 Mark Crichton
 
22
        Copyright (C) 1999 The Free Software Foundation
 
23
 
 
24
        Authors: Mark Crichton <crichton@gimp.org>
 
25
                 Federico Mena-Quintero <federico@gimp.org>
 
26
 
 
27
        A specific version of the gdk-pixbuf routines are required to support
 
28
        XPM color substitution used by the themes to apply gtk+ colors.
 
29
 
 
30
        oroborus - (c) 2001 Ken Lynch
 
31
        xfwm4    - (c) 2002-2011 Olivier Fourdan
 
32
 
 
33
 */
 
34
 
 
35
#ifdef HAVE_CONFIG_H
 
36
#include "config.h"
 
37
#endif
 
38
 
 
39
#include <X11/Xlib.h>
 
40
#include <X11/Xutil.h>
 
41
#include <glib.h>
 
42
#include <glib/gstdio.h>
 
43
#include <gdk/gdk.h>
 
44
#include <gdk/gdkx.h>
 
45
#include <libxfce4util/libxfce4util.h>
 
46
#include <stdlib.h>
 
47
#include <stdio.h>
 
48
 
 
49
#include "mypixmap.h"
 
50
#include "xpm-color-table.h"
 
51
 
 
52
enum buf_op
 
53
{
 
54
    op_header,
 
55
    op_cmap,
 
56
    op_body
 
57
};
 
58
 
 
59
typedef struct
 
60
{
 
61
    gchar *color_string;
 
62
    guint16 red;
 
63
    guint16 green;
 
64
    guint16 blue;
 
65
    gint transparent;
 
66
}
 
67
XPMColor;
 
68
 
 
69
struct file_handle
 
70
{
 
71
    FILE *infile;
 
72
    gchar *buffer;
 
73
    guint buffer_size;
 
74
};
 
75
 
 
76
/* The following 2 routines (parse_color, find_color) come from Tk, via the Win32
 
77
 * port of GDK. The licensing terms on these (longer than the functions) is:
 
78
 *
 
79
 * This software is copyrighted by the Regents of the University of
 
80
 * California, Sun Microsystems, Inc., and other parties.  The following
 
81
 * terms apply to all files associated with the software unless explicitly
 
82
 * disclaimed in individual files.
 
83
 *
 
84
 * The authors hereby grant permission to use, copy, modify, distribute,
 
85
 * and license this software and its documentation for any purpose, provided
 
86
 * that existing copyright notices are retained in all copies and that this
 
87
 * notice is included verbatim in any distributions. No written agreement,
 
88
 * license, or royalty fee is required for any of the authorized uses.
 
89
 * Modifications to this software may be copyrighted by their authors
 
90
 * and need not follow the licensing terms described here, provided that
 
91
 * the new terms are clearly indicated on the first page of each file where
 
92
 * they apply.
 
93
 *
 
94
 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
 
95
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 
96
 * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
 
97
 * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
 
98
 * POSSIBILITY OF SUCH DAMAGE.
 
99
 *
 
100
 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
 
101
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 
102
 * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
 
103
 * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
 
104
 * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
 
105
 * MODIFICATIONS.
 
106
 *
 
107
 * GOVERNMENT USE: If you are acquiring this software on behalf of the
 
108
 * U.S. government, the Government shall have only "Restricted Rights"
 
109
 * in the software and related documentation as defined in the Federal
 
110
 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
 
111
 * are acquiring the software on behalf of the Department of Defense, the
 
112
 * software shall be classified as "Commercial Computer Software" and the
 
113
 * Government shall have only "Restricted Rights" as defined in Clause
 
114
 * 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
 
115
 * authors grant the U.S. Government and others acting in its behalf
 
116
 * permission to use and distribute the software in accordance with the
 
117
 * terms specified in this license.
 
118
 */
 
119
 
 
120
static int
 
121
compare_xcolor_entries (const void *a, const void *b)
 
122
{
 
123
    return g_ascii_strcasecmp ((const char *) a,
 
124
                               color_names + ((const XPMColorEntry *) b)->name_offset);
 
125
}
 
126
 
 
127
static gboolean
 
128
find_color(const char *name, XPMColor *colorPtr)
 
129
{
 
130
    XPMColorEntry *found;
 
131
 
 
132
    found = bsearch (name, xColors, G_N_ELEMENTS (xColors), sizeof (XPMColorEntry),
 
133
                     compare_xcolor_entries);
 
134
    if (found == NULL)
 
135
    {
 
136
        return FALSE;
 
137
    }
 
138
 
 
139
    colorPtr->red   = (found->red   * 0xFFFF) / 0xFF;
 
140
    colorPtr->green = (found->green * 0xFFFF) / 0xFF;
 
141
    colorPtr->blue  = (found->blue  * 0xFFFF) / 0xFF;
 
142
 
 
143
    return TRUE;
 
144
}
 
145
 
 
146
static gboolean
 
147
parse_color (const char *spec, XPMColor   *colorPtr)
 
148
{
 
149
    if (spec[0] == '#')
 
150
    {
 
151
        char fmt[16];
 
152
        int i, red, green, blue;
 
153
 
 
154
        if ((i = strlen (spec + 1)) % 3)
 
155
        {
 
156
                return FALSE;
 
157
        }
 
158
        i /= 3;
 
159
 
 
160
        g_snprintf (fmt, 16, "%%%dx%%%dx%%%dx", i, i, i);
 
161
 
 
162
        if (sscanf (spec + 1, fmt, &red, &green, &blue) != 3)
 
163
        {
 
164
            return FALSE;
 
165
        }
 
166
        if (i == 4)
 
167
        {
 
168
            colorPtr->red   = red;
 
169
            colorPtr->green = green;
 
170
            colorPtr->blue  = blue;
 
171
        }
 
172
        else if (i == 1)
 
173
        {
 
174
            colorPtr->red   = (red   * 0xFFFF) / 0xF;
 
175
            colorPtr->green = (green * 0xFFFF) / 0xF;
 
176
            colorPtr->blue  = (blue  * 0xFFFF) / 0xF;
 
177
        }
 
178
        else if (i == 2)
 
179
        {
 
180
            colorPtr->red   = (red   * 0xFFFF) / 0xFF;
 
181
            colorPtr->green = (green * 0xFFFF) / 0xFF;
 
182
            colorPtr->blue  = (blue  * 0xFFFF) / 0xFF;
 
183
        }
 
184
        else /* if (i == 3) */
 
185
        {
 
186
            colorPtr->red   = (red   * 0xFFFF) / 0xFFF;
 
187
            colorPtr->green = (green * 0xFFFF) / 0xFFF;
 
188
            colorPtr->blue  = (blue  * 0xFFFF) / 0xFFF;
 
189
        }
 
190
    }
 
191
    else
 
192
    {
 
193
        if (!find_color(spec, colorPtr))
 
194
        {
 
195
            return FALSE;
 
196
        }
 
197
    }
 
198
    return TRUE;
 
199
}
 
200
 
 
201
static gint
 
202
xpm_seek_string (FILE *infile, const gchar *str)
 
203
{
 
204
    char instr[1024];
 
205
 
 
206
    while (!feof (infile))
 
207
    {
 
208
        if (fscanf (infile, "%1023s", instr) < 0)
 
209
        {
 
210
                return FALSE;
 
211
        }
 
212
        if (strcmp (instr, str) == 0)
 
213
        {
 
214
                return TRUE;
 
215
        }
 
216
    }
 
217
 
 
218
    return FALSE;
 
219
}
 
220
 
 
221
static gint
 
222
xpm_seek_char (FILE *infile, gchar c)
 
223
{
 
224
    gint b, oldb;
 
225
 
 
226
    while ((b = getc (infile)) != EOF)
 
227
    {
 
228
        if (c != b && b == '/')
 
229
        {
 
230
            b = getc (infile);
 
231
            if (b == EOF)
 
232
            {
 
233
                return FALSE;
 
234
            }
 
235
            else if (b == '*')
 
236
            {   /* we have a comment */
 
237
                 b = -1;
 
238
                 do
 
239
                 {
 
240
                     oldb = b;
 
241
                     b = getc (infile);
 
242
                     if (b == EOF)
 
243
                     {
 
244
                             return FALSE;
 
245
                     }
 
246
                 }
 
247
                 while (!(oldb == '*' && b == '/'));
 
248
            }
 
249
        }
 
250
        else if (c == b)
 
251
        {
 
252
            return TRUE;
 
253
        }
 
254
    }
 
255
 
 
256
    return FALSE;
 
257
}
 
258
 
 
259
static gint
 
260
xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size)
 
261
{
 
262
    gint c;
 
263
    guint cnt = 0, bufsiz, ret;
 
264
    gchar *buf;
 
265
 
 
266
    buf = *buffer;
 
267
    bufsiz = *buffer_size;
 
268
    ret = FALSE;
 
269
 
 
270
    if (buf == NULL)
 
271
    {
 
272
        bufsiz = 10 * sizeof (gchar);
 
273
        buf = g_new (gchar, bufsiz);
 
274
    }
 
275
 
 
276
    do
 
277
    {
 
278
        c = getc (infile);
 
279
    }
 
280
    while (c != EOF && c != '"');
 
281
 
 
282
    if (c != '"')
 
283
    {
 
284
        goto out;
 
285
    }
 
286
    while ((c = getc (infile)) != EOF)
 
287
    {
 
288
        if (cnt == bufsiz)
 
289
        {
 
290
            guint new_size = bufsiz * 2;
 
291
 
 
292
            if (new_size > bufsiz)
 
293
            {
 
294
                bufsiz = new_size;
 
295
            }
 
296
            else
 
297
            {
 
298
                goto out;
 
299
            }
 
300
            buf = g_realloc (buf, bufsiz);
 
301
            buf[bufsiz - 1] = '\0';
 
302
        }
 
303
 
 
304
        if (c != '"')
 
305
        {
 
306
            buf[cnt++] = c;
 
307
        }
 
308
        else
 
309
        {
 
310
            buf[cnt] = 0;
 
311
            ret = TRUE;
 
312
            break;
 
313
        }
 
314
    }
 
315
 
 
316
out:
 
317
    buf[bufsiz - 1] = '\0';     /* ensure null termination for errors */
 
318
    *buffer = buf;
 
319
    *buffer_size = bufsiz;
 
320
    return ret;
 
321
}
 
322
 
 
323
static const gchar *
 
324
search_color_symbol (gchar *symbol, xfwmColorSymbol *color_sym)
 
325
{
 
326
    xfwmColorSymbol *i;
 
327
 
 
328
    i = color_sym;
 
329
    while (i && i->name)
 
330
    {
 
331
        if (!g_ascii_strcasecmp (i->name, symbol))
 
332
        {
 
333
            return i->value;
 
334
        }
 
335
        ++i;
 
336
    }
 
337
    return NULL;
 
338
}
 
339
 
 
340
static gchar *
 
341
xpm_extract_color (const gchar *buffer, xfwmColorSymbol *color_sym)
 
342
{
 
343
    const gchar *p;
 
344
    gchar word[129], color[129], current_color[129];
 
345
    gchar *r;
 
346
    gint new_key;
 
347
    gint key;
 
348
    gint current_key;
 
349
    gint space;
 
350
 
 
351
    p = &buffer[0];
 
352
    space = 128;
 
353
    word[0] = '\0';
 
354
    color[0] = '\0';
 
355
    current_color[0] = '\0';
 
356
    current_key = 1;
 
357
    new_key = 0;
 
358
    key = 0;
 
359
 
 
360
    while (1)
 
361
    {
 
362
        /* skip whitespace */
 
363
        for (; *p != '\0' && g_ascii_isspace (*p); p++)
 
364
        {
 
365
        }
 
366
        /* copy word */
 
367
        for (r = word;
 
368
                 (*p != '\0') &&
 
369
                 (!g_ascii_isspace (*p)) &&
 
370
                 (r - word < (gint) sizeof (word) - 1);
 
371
             p++, r++)
 
372
        {
 
373
                *r = *p;
 
374
        }
 
375
        *r = '\0';
 
376
        if (*word == '\0')
 
377
        {
 
378
            if (color[0] == '\0')  /* incomplete colormap entry */
 
379
            {
 
380
                return NULL;
 
381
            }
 
382
            else  /* end of entry, still store the last color */
 
383
            {
 
384
                new_key = 1;
 
385
            }
 
386
        }
 
387
        else if (key > 0 && color[0] == '\0')  /* next word must be a color name part */
 
388
        {
 
389
                new_key = 0;
 
390
        }
 
391
        else
 
392
        {
 
393
            if (strcmp (word, "s") == 0)
 
394
            {
 
395
                new_key = 5;
 
396
            }
 
397
            else if (strcmp (word, "c") == 0)
 
398
            {
 
399
                new_key = 4;
 
400
            }
 
401
            else if (strcmp (word, "g") == 0)
 
402
            {
 
403
                new_key = 3;
 
404
            }
 
405
            else if (strcmp (word, "g4") == 0)
 
406
            {
 
407
                new_key = 2;
 
408
            }
 
409
            else if (strcmp (word, "m") == 0)
 
410
            {
 
411
                new_key = 1;
 
412
            }
 
413
            else
 
414
            {
 
415
                new_key = 0;
 
416
            }
 
417
        }
 
418
        if (new_key == 0)
 
419
        {  /* word is a color name part */
 
420
            if (key == 0)  /* key expected */
 
421
            {
 
422
                return NULL;
 
423
            }
 
424
            /* accumulate color name */
 
425
            if (color[0] != '\0')
 
426
            {
 
427
                strncat (color, " ", space);
 
428
                space -= MIN (space, 1);
 
429
            }
 
430
            strncat (color, word, space);
 
431
            space -= MIN (space, (gint) strlen (word));
 
432
        }
 
433
        else if (key == 5)
 
434
        {
 
435
            const gchar *new_color = NULL;
 
436
            new_color = search_color_symbol (color, color_sym);
 
437
            if (new_color)
 
438
            {
 
439
                current_key = key;
 
440
                strcpy (current_color, new_color);
 
441
            }
 
442
            space = 128;
 
443
            color[0] = '\0';
 
444
            key = new_key;
 
445
            if (*p == '\0')
 
446
            {
 
447
                break;
 
448
            }
 
449
        }
 
450
        else
 
451
        {  /* word is a key */
 
452
            if (key > current_key)
 
453
            {
 
454
                current_key = key;
 
455
                strcpy (current_color, color);
 
456
            }
 
457
            space = 128;
 
458
            color[0] = '\0';
 
459
            key = new_key;
 
460
            if (*p == '\0')
 
461
            {
 
462
                break;
 
463
            }
 
464
        }
 
465
    }
 
466
    if (current_key > 1)
 
467
    {
 
468
        return g_strdup (current_color);
 
469
    }
 
470
    else
 
471
    {
 
472
        return NULL;
 
473
    }
 
474
}
 
475
 
 
476
static const gchar *
 
477
file_buffer (enum buf_op op, gpointer handle)
 
478
{
 
479
    struct file_handle *h;
 
480
 
 
481
    h = handle;
 
482
    switch (op)
 
483
    {
 
484
        case op_header:
 
485
            if (xpm_seek_string (h->infile, "XPM") != TRUE)
 
486
            {
 
487
                break;
 
488
            }
 
489
            if (xpm_seek_char (h->infile, '{') != TRUE)
 
490
            {
 
491
                break;
 
492
            }
 
493
            /* Fall through to the next xpm_seek_char. */
 
494
 
 
495
        case op_cmap:
 
496
            xpm_seek_char (h->infile, '"');
 
497
            fseek (h->infile, -1, SEEK_CUR);
 
498
            /* Fall through to the xpm_read_string. */
 
499
 
 
500
        case op_body:
 
501
            if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size))
 
502
            {
 
503
                return NULL;
 
504
            }
 
505
            return h->buffer;
 
506
 
 
507
        default:
 
508
            g_assert_not_reached ();
 
509
    }
 
510
 
 
511
    return NULL;
 
512
}
 
513
 
 
514
/* This function does all the work. */
 
515
static GdkPixbuf *
 
516
pixbuf_create_from_xpm (gpointer handle, xfwmColorSymbol *color_sym)
 
517
{
 
518
    gchar pixel_str[32];
 
519
    const gchar *buffer;
 
520
    gchar *name_buf;
 
521
    gint w, h, n_col, cpp, items;
 
522
    gint cnt, xcnt, ycnt, wbytes, n;
 
523
    GHashTable *color_hash;
 
524
    XPMColor *colors, *color, *fallbackcolor;
 
525
    guchar *pixtmp;
 
526
    GdkPixbuf *pixbuf;
 
527
 
 
528
    fallbackcolor = NULL;
 
529
 
 
530
    buffer = file_buffer (op_header, handle);
 
531
    if (!buffer)
 
532
    {
 
533
        g_warning ("Cannot read Pixmap header");
 
534
        return NULL;
 
535
    }
 
536
    items = sscanf (buffer, "%d %d %d %d", &w, &h, &n_col, &cpp);
 
537
 
 
538
    if (items != 4)
 
539
    {
 
540
        g_warning ("Pixmap definition contains invalid number attributes (expecting at least 4, got %i)", items);
 
541
        return NULL;
 
542
    }
 
543
 
 
544
    if ((w <= 0) ||
 
545
        (h <= 0) ||
 
546
        (cpp <= 0) ||
 
547
        (cpp >= 32) ||
 
548
        (n_col <= 0) ||
 
549
        (n_col >= G_MAXINT / (cpp + 1)) ||
 
550
        (n_col >= G_MAXINT / (gint) sizeof (XPMColor)))
 
551
    {
 
552
        g_warning ("Pixmap definition contains invalid attributes");
 
553
        return NULL;
 
554
    }
 
555
 
 
556
    /* The hash is used for fast lookups of color from chars */
 
557
    color_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
558
 
 
559
    name_buf = g_try_malloc (n_col * (cpp + 1));
 
560
    if (!name_buf) {
 
561
        g_hash_table_destroy (color_hash);
 
562
        g_warning ("Cannot allocate buffer");
 
563
        return NULL;
 
564
    }
 
565
 
 
566
    colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col);
 
567
    if (!colors)
 
568
    {
 
569
        g_hash_table_destroy (color_hash);
 
570
        g_free (name_buf);
 
571
        g_warning ("Cannot allocate colors for Pixmap");
 
572
        return NULL;
 
573
    }
 
574
 
 
575
    for (cnt = 0; cnt < n_col; cnt++)
 
576
    {
 
577
        gchar *color_name;
 
578
 
 
579
        buffer = file_buffer (op_cmap, handle);
 
580
        if (!buffer)
 
581
        {
 
582
            g_hash_table_destroy (color_hash);
 
583
            g_free (name_buf);
 
584
            g_free (colors);
 
585
            g_warning ("Cannot load colormap attributes");
 
586
            return NULL;
 
587
        }
 
588
 
 
589
        color = &colors[cnt];
 
590
        color->color_string = &name_buf[cnt * (cpp + 1)];
 
591
        strncpy (color->color_string, buffer, cpp);
 
592
        color->color_string[cpp] = 0;
 
593
        buffer += strlen (color->color_string);
 
594
        color->transparent = FALSE;
 
595
 
 
596
        color_name = xpm_extract_color (buffer, color_sym);
 
597
 
 
598
        if ((color_name == NULL) ||
 
599
            (g_ascii_strcasecmp (color_name, "None") == 0) ||
 
600
            (parse_color (color_name, color) == FALSE))
 
601
        {
 
602
            color->transparent = TRUE;
 
603
            color->red = 0;
 
604
            color->green = 0;
 
605
            color->blue = 0;
 
606
        }
 
607
 
 
608
        g_free (color_name);
 
609
        g_hash_table_insert (color_hash, color->color_string, color);
 
610
 
 
611
        if (cnt == 0)
 
612
        {
 
613
            fallbackcolor = color;
 
614
        }
 
615
    }
 
616
 
 
617
    pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
 
618
 
 
619
    if (!pixbuf)
 
620
    {
 
621
        g_hash_table_destroy (color_hash);
 
622
        g_free (colors);
 
623
        g_free (name_buf);
 
624
        g_warning ("Cannot allocate Pixbuf");
 
625
        return NULL;
 
626
    }
 
627
 
 
628
    wbytes = w * cpp;
 
629
 
 
630
    for (ycnt = 0; ycnt < h; ycnt++)
 
631
    {
 
632
        pixtmp = gdk_pixbuf_get_pixels (pixbuf) + ycnt * gdk_pixbuf_get_rowstride(pixbuf);
 
633
 
 
634
        buffer = file_buffer (op_body, handle);
 
635
        if ((!buffer) || (wbytes > (gint) strlen (buffer)))
 
636
        {
 
637
            continue;
 
638
        }
 
639
 
 
640
        for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
 
641
        {
 
642
            strncpy (pixel_str, &buffer[n], cpp);
 
643
            pixel_str[cpp] = 0;
 
644
 
 
645
            color = g_hash_table_lookup (color_hash, pixel_str);
 
646
 
 
647
            /* Bad XPM...punt */
 
648
            if (!color)
 
649
            {
 
650
                color = fallbackcolor;
 
651
            }
 
652
 
 
653
            *pixtmp++ = color->red   >> 8;
 
654
            *pixtmp++ = color->green >> 8;
 
655
            *pixtmp++ = color->blue  >> 8;
 
656
 
 
657
            if (color->transparent)
 
658
            {
 
659
                *pixtmp++ = 0;
 
660
            }
 
661
            else
 
662
            {
 
663
                *pixtmp++ = 0xFF;
 
664
            }
 
665
        }
 
666
    }
 
667
 
 
668
    g_hash_table_destroy (color_hash);
 
669
    g_free (colors);
 
670
    g_free (name_buf);
 
671
 
 
672
    return pixbuf;
 
673
}
 
674
 
 
675
 
 
676
static GdkPixbuf *
 
677
xpm_image_load (const char *filename, xfwmColorSymbol *color_sym)
 
678
{
 
679
    guchar buffer[1024];
 
680
    GdkPixbuf *pixbuf;
 
681
    struct file_handle h;
 
682
    int size;
 
683
    FILE *f;
 
684
 
 
685
    f = g_fopen (filename, "rb");
 
686
    if (!f)
 
687
    {
 
688
        return NULL;
 
689
    }
 
690
 
 
691
    size = fread (&buffer, 1, sizeof (buffer), f);
 
692
    if (size == 0)
 
693
    {
 
694
        fclose (f);
 
695
        return NULL;
 
696
    }
 
697
 
 
698
    fseek (f, 0, SEEK_SET);
 
699
    memset (&h, 0, sizeof (h));
 
700
    h.infile = f;
 
701
    pixbuf = pixbuf_create_from_xpm (&h, color_sym);
 
702
    g_free (h.buffer);
 
703
    fclose (f);
 
704
 
 
705
    return pixbuf;
 
706
}
 
707
 
 
708
#ifdef HAVE_RENDER
 
709
static void
 
710
xfwmPixmapRefreshPict (xfwmPixmap * pm)
 
711
{
 
712
    ScreenInfo * screen_info;
 
713
 
 
714
    screen_info = pm->screen_info;
 
715
    if (!pm->pict_format)
 
716
    {
 
717
        pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
 
718
                                                   screen_info->visual);
 
719
    }
 
720
 
 
721
    if (pm->pict != None)
 
722
    {
 
723
        XRenderFreePicture (myScreenGetXDisplay(pm->screen_info), pm->pict);
 
724
        pm->pict = None;
 
725
    }
 
726
 
 
727
    if ((pm->pixmap) && (pm->pict_format))
 
728
    {
 
729
        pm->pict = XRenderCreatePicture (myScreenGetXDisplay (screen_info),
 
730
                                         pm->pixmap, pm->pict_format, 0, NULL);
 
731
    }
 
732
}
 
733
#endif
 
734
 
 
735
static GdkPixbuf *
 
736
xfwmPixmapCompose (GdkPixbuf *pixbuf, const gchar * dir, const gchar * file)
 
737
{
 
738
    GdkPixbuf *alpha;
 
739
    gchar *filepng;
 
740
    gchar *filename;
 
741
    gint width, height;
 
742
    int i;
 
743
 
 
744
    static const char* image_types[] = {
 
745
      "svg",
 
746
      "png",
 
747
      "gif",
 
748
      "jpg",
 
749
      "bmp",
 
750
      NULL };
 
751
 
 
752
    i = 0;
 
753
    alpha = NULL;
 
754
 
 
755
    while ((image_types[i]) && (!alpha))
 
756
    {
 
757
        filepng = g_strdup_printf ("%s.%s", file, image_types[i]);
 
758
        filename = g_build_filename (dir, filepng, NULL);
 
759
        g_free (filepng);
 
760
 
 
761
        if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
 
762
        {
 
763
            alpha = gdk_pixbuf_new_from_file (filename, NULL);
 
764
        }
 
765
        g_free (filename);
 
766
        ++i;
 
767
    }
 
768
 
 
769
    if (!alpha)
 
770
    {
 
771
        /* We have no suitable image to layer on top of the XPM, stop here... */
 
772
        return (pixbuf);
 
773
    }
 
774
 
 
775
    if (!pixbuf)
 
776
    {
 
777
        /* We have no XPM canvas and found a suitable image, use it... */
 
778
        return (alpha);
 
779
    }
 
780
 
 
781
    width  = MIN (gdk_pixbuf_get_width (pixbuf),
 
782
                  gdk_pixbuf_get_width (alpha));
 
783
    height = MIN (gdk_pixbuf_get_height (pixbuf),
 
784
                  gdk_pixbuf_get_height (alpha));
 
785
 
 
786
    gdk_pixbuf_composite (alpha, pixbuf, 0, 0, width, height,
 
787
                          0, 0, 1.0, 1.0, GDK_INTERP_BILINEAR, 0xFF);
 
788
 
 
789
    g_object_unref (alpha);
 
790
 
 
791
    return pixbuf;
 
792
}
 
793
 
 
794
static gboolean
 
795
xfwmPixmapDrawFromGdkPixbuf (xfwmPixmap * pm, GdkPixbuf *pixbuf)
 
796
{
 
797
    GdkPixmap *dest_pixmap;
 
798
    GdkPixmap *dest_bitmap;
 
799
    GdkVisual *gvisual;
 
800
    GdkColormap *cmap;
 
801
    gint width, height;
 
802
    gint dest_x, dest_y;
 
803
    gint alpha_threshold;
 
804
 
 
805
    g_return_val_if_fail (pm != NULL, FALSE);
 
806
    g_return_val_if_fail (pm->pixmap != None, FALSE);
 
807
    g_return_val_if_fail (pm->mask != None, FALSE);
 
808
 
 
809
    dest_pixmap = gdk_xid_table_lookup (pm->pixmap);
 
810
    if (dest_pixmap)
 
811
    {
 
812
        g_object_ref (G_OBJECT (dest_pixmap));
 
813
    }
 
814
    else
 
815
    {
 
816
        dest_pixmap = gdk_pixmap_foreign_new (pm->pixmap);
 
817
    }
 
818
 
 
819
    if (!dest_pixmap)
 
820
    {
 
821
        g_warning ("Cannot get pixmap");
 
822
        return FALSE;
 
823
    }
 
824
 
 
825
    dest_bitmap = gdk_xid_table_lookup (pm->mask);
 
826
    if (dest_bitmap)
 
827
    {
 
828
        g_object_ref (G_OBJECT (dest_bitmap));
 
829
    }
 
830
    else
 
831
    {
 
832
        dest_bitmap = gdk_pixmap_foreign_new (pm->mask);
 
833
    }
 
834
 
 
835
    if (!dest_bitmap)
 
836
    {
 
837
        g_warning ("Cannot get bitmap");
 
838
        g_object_unref (dest_pixmap);
 
839
        return FALSE;
 
840
    }
 
841
 
 
842
    gvisual = gdk_screen_get_system_visual (pm->screen_info->gscr);
 
843
    cmap = gdk_x11_colormap_foreign_new (gvisual, pm->screen_info->cmap);
 
844
 
 
845
    if (!cmap)
 
846
    {
 
847
        g_warning ("Cannot create colormap");
 
848
        g_object_unref (dest_pixmap);
 
849
        g_object_unref (dest_bitmap);
 
850
        return FALSE;
 
851
    }
 
852
 
 
853
    width = MIN (gdk_pixbuf_get_width (pixbuf), pm->width);
 
854
    height = MIN (gdk_pixbuf_get_height (pixbuf), pm->height);
 
855
    dest_x = (pm->width - width) / 2;
 
856
    dest_y = (pm->height - height) / 2;
 
857
 
 
858
    gdk_drawable_set_colormap (GDK_DRAWABLE (dest_pixmap), cmap);
 
859
    gdk_draw_pixbuf (GDK_DRAWABLE (dest_pixmap), NULL, pixbuf, 0, 0, dest_x, dest_y,
 
860
                     width, height, GDK_RGB_DITHER_NONE, 0, 0);
 
861
 
 
862
    alpha_threshold = (gdk_pixbuf_get_has_alpha (pixbuf) ? 0xFF : 0);
 
863
    gdk_pixbuf_render_threshold_alpha (pixbuf, dest_bitmap,
 
864
                                       0, 0, dest_x, dest_y,
 
865
                                       width, height, alpha_threshold);
 
866
 
 
867
    g_object_unref (cmap);
 
868
    g_object_unref (dest_pixmap);
 
869
    g_object_unref (dest_bitmap);
 
870
 
 
871
    return TRUE;
 
872
}
 
873
 
 
874
gboolean
 
875
xfwmPixmapRenderGdkPixbuf (xfwmPixmap * pm, GdkPixbuf *pixbuf)
 
876
{
 
877
    GdkPixbuf *src;
 
878
    GdkPixmap *destw;
 
879
    GdkVisual *gvisual;
 
880
    GdkColormap *cmap;
 
881
    gint width, height;
 
882
    gint dest_x, dest_y;
 
883
 
 
884
    g_return_val_if_fail (pm != NULL, FALSE);
 
885
    g_return_val_if_fail (pm->pixmap != None, FALSE);
 
886
    g_return_val_if_fail (pm->mask != None, FALSE);
 
887
 
 
888
    destw = gdk_xid_table_lookup (pm->pixmap);
 
889
    if (destw)
 
890
    {
 
891
        g_object_ref (G_OBJECT (destw));
 
892
    }
 
893
    else
 
894
    {
 
895
        destw = gdk_pixmap_foreign_new (pm->pixmap);
 
896
    }
 
897
 
 
898
    if (!destw)
 
899
    {
 
900
        g_warning ("Cannot get pixmap");
 
901
        return FALSE;
 
902
    }
 
903
 
 
904
    gvisual = gdk_screen_get_system_visual (pm->screen_info->gscr);
 
905
    cmap = gdk_x11_colormap_foreign_new (gvisual, pm->screen_info->cmap);
 
906
 
 
907
    if (!cmap)
 
908
    {
 
909
        g_warning ("Cannot create colormap");
 
910
        g_object_unref (destw);
 
911
        return FALSE;
 
912
    }
 
913
 
 
914
    width = MIN (gdk_pixbuf_get_width (pixbuf), pm->width);
 
915
    height = MIN (gdk_pixbuf_get_height (pixbuf), pm->height);
 
916
 
 
917
    /* Add 1 for rounding */
 
918
    dest_x = (pm->width - width + 1) / 2;
 
919
    dest_y = (pm->height - height + 1) / 2;
 
920
 
 
921
    src = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE (destw), cmap,
 
922
                                        dest_x, dest_y, 0, 0, width, height);
 
923
    gdk_pixbuf_composite (pixbuf, src, 0, 0, width, height,
 
924
                          0, 0, 1.0, 1.0, GDK_INTERP_BILINEAR, 0xFF);
 
925
    gdk_draw_pixbuf (GDK_DRAWABLE (destw), NULL, src, 0, 0, dest_x, dest_y,
 
926
                     width, height, GDK_RGB_DITHER_NONE, 0, 0);
 
927
 
 
928
    g_object_unref (cmap);
 
929
    g_object_unref (src);
 
930
    g_object_unref (destw);
 
931
 
 
932
    return TRUE;
 
933
}
 
934
 
 
935
gboolean
 
936
xfwmPixmapLoad (ScreenInfo * screen_info, xfwmPixmap * pm, const gchar * dir, const gchar * file, xfwmColorSymbol * cs)
 
937
{
 
938
    gchar *filename;
 
939
    gchar *filexpm;
 
940
    GdkPixbuf *pixbuf;
 
941
 
 
942
    TRACE ("entering xfwmPixmapLoad(%s)", file);
 
943
 
 
944
    g_return_val_if_fail (pm != NULL, FALSE);
 
945
    g_return_val_if_fail (dir != NULL, FALSE);
 
946
    g_return_val_if_fail (file != NULL, FALSE);
 
947
 
 
948
    xfwmPixmapInit (screen_info, pm);
 
949
    /*
 
950
     * Always try to load the XPM first, using our own routine
 
951
     * that supports XPM color symbol susbstitution (used to
 
952
     * apply the gtk+ colors to the pixmaps).
 
953
     */
 
954
    filexpm = g_strdup_printf ("%s.%s", file, "xpm");
 
955
    filename = g_build_filename (dir, filexpm, NULL);
 
956
    g_free (filexpm);
 
957
    pixbuf = xpm_image_load (filename, cs);
 
958
    g_free (filename);
 
959
 
 
960
    /* Compose with other image formats, if any available. */
 
961
    pixbuf = xfwmPixmapCompose (pixbuf, dir, file);
 
962
    if (!pixbuf)
 
963
    {
 
964
        /*
 
965
         * Cannot find a suitable image format for some part,
 
966
         * it's not critical though as most themes are missing
 
967
         * buttons
 
968
         */
 
969
        return FALSE;
 
970
    }
 
971
    xfwmPixmapCreate (screen_info, pm,
 
972
                      gdk_pixbuf_get_width (pixbuf),
 
973
                      gdk_pixbuf_get_height (pixbuf));
 
974
    xfwmPixmapDrawFromGdkPixbuf (pm, pixbuf);
 
975
 
 
976
#ifdef HAVE_RENDER
 
977
    xfwmPixmapRefreshPict (pm);
 
978
#endif
 
979
    g_object_unref (pixbuf);
 
980
 
 
981
    return TRUE;
 
982
}
 
983
 
 
984
void
 
985
xfwmPixmapCreate (ScreenInfo * screen_info, xfwmPixmap * pm,
 
986
                  gint width, gint height)
 
987
{
 
988
    TRACE ("entering xfwmPixmapCreate, width=%i, height=%i", width, height);
 
989
    g_return_if_fail (screen_info != NULL);
 
990
 
 
991
    if ((width < 1) || (height < 1))
 
992
    {
 
993
        xfwmPixmapInit (screen_info, pm);
 
994
    }
 
995
    else
 
996
    {
 
997
        pm->screen_info = screen_info;
 
998
        pm->pixmap = XCreatePixmap (myScreenGetXDisplay (screen_info),
 
999
                                    screen_info->xroot,
 
1000
                                    width, height, screen_info->depth);
 
1001
        pm->mask = XCreatePixmap (myScreenGetXDisplay (screen_info),
 
1002
                                  pm->pixmap, width, height, 1);
 
1003
        pm->width = width;
 
1004
        pm->height = height;
 
1005
#ifdef HAVE_RENDER
 
1006
        pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
 
1007
                                                   screen_info->visual);
 
1008
        pm->pict = None;
 
1009
#endif
 
1010
    }
 
1011
}
 
1012
 
 
1013
void
 
1014
xfwmPixmapInit (ScreenInfo * screen_info, xfwmPixmap * pm)
 
1015
{
 
1016
    pm->screen_info = screen_info;
 
1017
    pm->pixmap = None;
 
1018
    pm->mask = None;
 
1019
    pm->width = 0;
 
1020
    pm->height = 0;
 
1021
#ifdef HAVE_RENDER
 
1022
    pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
 
1023
                                               screen_info->visual);
 
1024
    pm->pict = None;
 
1025
#endif
 
1026
}
 
1027
 
 
1028
void
 
1029
xfwmPixmapFree (xfwmPixmap * pm)
 
1030
{
 
1031
 
 
1032
    TRACE ("entering xfwmPixmapFree");
 
1033
 
 
1034
    pm->width = 0;
 
1035
    pm->height = 0;
 
1036
    if (pm->pixmap != None)
 
1037
    {
 
1038
        XFreePixmap (myScreenGetXDisplay(pm->screen_info), pm->pixmap);
 
1039
        pm->pixmap = None;
 
1040
    }
 
1041
    if (pm->mask != None)
 
1042
    {
 
1043
        XFreePixmap (myScreenGetXDisplay(pm->screen_info), pm->mask);
 
1044
        pm->mask = None;
 
1045
    }
 
1046
#ifdef HAVE_RENDER
 
1047
    if (pm->pict != None)
 
1048
    {
 
1049
        XRenderFreePicture (myScreenGetXDisplay(pm->screen_info), pm->pict);
 
1050
        pm->pict = None;
 
1051
    }
 
1052
#endif
 
1053
}
 
1054
 
 
1055
gboolean
 
1056
xfwmPixmapNone (xfwmPixmap * pm)
 
1057
{
 
1058
    TRACE ("entering xfwmPixmapEmpty");
 
1059
 
 
1060
    g_return_val_if_fail (pm != NULL, FALSE);
 
1061
    return (pm->pixmap == None);
 
1062
}
 
1063
 
 
1064
static void
 
1065
xfwmPixmapFillRectangle (Display *dpy, int screen, Pixmap pm, Drawable d,
 
1066
                         int x, int y, int width, int height)
 
1067
{
 
1068
    XGCValues gv;
 
1069
    GC gc;
 
1070
    unsigned long mask;
 
1071
 
 
1072
    TRACE ("entering fillRectangle");
 
1073
 
 
1074
    if ((width < 1) || (height < 1))
 
1075
    {
 
1076
        return;
 
1077
    }
 
1078
    gv.fill_style = FillTiled;
 
1079
    gv.tile = pm;
 
1080
    gv.ts_x_origin = x;
 
1081
    gv.ts_y_origin = y;
 
1082
    gv.foreground = WhitePixel (dpy, screen);
 
1083
    if (gv.tile != None)
 
1084
    {
 
1085
        mask = GCTile | GCFillStyle | GCTileStipXOrigin;
 
1086
    }
 
1087
    else
 
1088
    {
 
1089
        mask = GCForeground;
 
1090
    }
 
1091
    gc = XCreateGC (dpy, d, mask, &gv);
 
1092
    XFillRectangle (dpy, d, gc, x, y, width, height);
 
1093
    XFreeGC (dpy, gc);
 
1094
}
 
1095
 
 
1096
void
 
1097
xfwmPixmapFill (xfwmPixmap * src, xfwmPixmap * dst,
 
1098
                gint x, gint y, gint width, gint height)
 
1099
{
 
1100
    TRACE ("entering xfwmWindowFill");
 
1101
 
 
1102
    if ((width < 1) || (height < 1))
 
1103
    {
 
1104
        return;
 
1105
    }
 
1106
 
 
1107
    xfwmPixmapFillRectangle (myScreenGetXDisplay (src->screen_info),
 
1108
                             src->screen_info->screen,
 
1109
                             src->pixmap, dst->pixmap, x, y, width, height);
 
1110
    xfwmPixmapFillRectangle (myScreenGetXDisplay (src->screen_info),
 
1111
                             src->screen_info->screen,
 
1112
                             src->mask, dst->mask, x, y, width, height);
 
1113
#ifdef HAVE_RENDER
 
1114
    xfwmPixmapRefreshPict (dst);
 
1115
#endif
 
1116
}
 
1117
 
 
1118
void
 
1119
xfwmPixmapDuplicate (xfwmPixmap * src, xfwmPixmap * dst)
 
1120
{
 
1121
    g_return_if_fail (src != NULL);
 
1122
    TRACE ("entering xfwmPixmapDuplicate, width=%i, height=%i", src->width, src->height);
 
1123
 
 
1124
    xfwmPixmapCreate (src->screen_info, dst, src->width, src->height);
 
1125
    xfwmPixmapFill (src, dst, 0, 0, src->width, src->height);
 
1126
}