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)
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.
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,
19
Original XPM load routines from gdk-pixbuf:
21
Copyright (C) 1999 Mark Crichton
22
Copyright (C) 1999 The Free Software Foundation
24
Authors: Mark Crichton <crichton@gimp.org>
25
Federico Mena-Quintero <federico@gimp.org>
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.
30
oroborus - (c) 2001 Ken Lynch
31
xfwm4 - (c) 2002-2011 Olivier Fourdan
40
#include <X11/Xutil.h>
42
#include <glib/gstdio.h>
45
#include <libxfce4util/libxfce4util.h>
50
#include "xpm-color-table.h"
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:
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.
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
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.
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
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.
121
compare_xcolor_entries (const void *a, const void *b)
123
return g_ascii_strcasecmp ((const char *) a,
124
color_names + ((const XPMColorEntry *) b)->name_offset);
128
find_color(const char *name, XPMColor *colorPtr)
130
XPMColorEntry *found;
132
found = bsearch (name, xColors, G_N_ELEMENTS (xColors), sizeof (XPMColorEntry),
133
compare_xcolor_entries);
139
colorPtr->red = (found->red * 0xFFFF) / 0xFF;
140
colorPtr->green = (found->green * 0xFFFF) / 0xFF;
141
colorPtr->blue = (found->blue * 0xFFFF) / 0xFF;
147
parse_color (const char *spec, XPMColor *colorPtr)
152
int i, red, green, blue;
154
if ((i = strlen (spec + 1)) % 3)
160
g_snprintf (fmt, 16, "%%%dx%%%dx%%%dx", i, i, i);
162
if (sscanf (spec + 1, fmt, &red, &green, &blue) != 3)
169
colorPtr->green = green;
170
colorPtr->blue = blue;
174
colorPtr->red = (red * 0xFFFF) / 0xF;
175
colorPtr->green = (green * 0xFFFF) / 0xF;
176
colorPtr->blue = (blue * 0xFFFF) / 0xF;
180
colorPtr->red = (red * 0xFFFF) / 0xFF;
181
colorPtr->green = (green * 0xFFFF) / 0xFF;
182
colorPtr->blue = (blue * 0xFFFF) / 0xFF;
184
else /* if (i == 3) */
186
colorPtr->red = (red * 0xFFFF) / 0xFFF;
187
colorPtr->green = (green * 0xFFFF) / 0xFFF;
188
colorPtr->blue = (blue * 0xFFFF) / 0xFFF;
193
if (!find_color(spec, colorPtr))
202
xpm_seek_string (FILE *infile, const gchar *str)
206
while (!feof (infile))
208
if (fscanf (infile, "%1023s", instr) < 0)
212
if (strcmp (instr, str) == 0)
222
xpm_seek_char (FILE *infile, gchar c)
226
while ((b = getc (infile)) != EOF)
228
if (c != b && b == '/')
236
{ /* we have a comment */
247
while (!(oldb == '*' && b == '/'));
260
xpm_read_string (FILE *infile, gchar **buffer, guint *buffer_size)
263
guint cnt = 0, bufsiz, ret;
267
bufsiz = *buffer_size;
272
bufsiz = 10 * sizeof (gchar);
273
buf = g_new (gchar, bufsiz);
280
while (c != EOF && c != '"');
286
while ((c = getc (infile)) != EOF)
290
guint new_size = bufsiz * 2;
292
if (new_size > bufsiz)
300
buf = g_realloc (buf, bufsiz);
301
buf[bufsiz - 1] = '\0';
317
buf[bufsiz - 1] = '\0'; /* ensure null termination for errors */
319
*buffer_size = bufsiz;
324
search_color_symbol (gchar *symbol, xfwmColorSymbol *color_sym)
331
if (!g_ascii_strcasecmp (i->name, symbol))
341
xpm_extract_color (const gchar *buffer, xfwmColorSymbol *color_sym)
344
gchar word[129], color[129], current_color[129];
355
current_color[0] = '\0';
362
/* skip whitespace */
363
for (; *p != '\0' && g_ascii_isspace (*p); p++)
369
(!g_ascii_isspace (*p)) &&
370
(r - word < (gint) sizeof (word) - 1);
378
if (color[0] == '\0') /* incomplete colormap entry */
382
else /* end of entry, still store the last color */
387
else if (key > 0 && color[0] == '\0') /* next word must be a color name part */
393
if (strcmp (word, "s") == 0)
397
else if (strcmp (word, "c") == 0)
401
else if (strcmp (word, "g") == 0)
405
else if (strcmp (word, "g4") == 0)
409
else if (strcmp (word, "m") == 0)
419
{ /* word is a color name part */
420
if (key == 0) /* key expected */
424
/* accumulate color name */
425
if (color[0] != '\0')
427
strncat (color, " ", space);
428
space -= MIN (space, 1);
430
strncat (color, word, space);
431
space -= MIN (space, (gint) strlen (word));
435
const gchar *new_color = NULL;
436
new_color = search_color_symbol (color, color_sym);
440
strcpy (current_color, new_color);
451
{ /* word is a key */
452
if (key > current_key)
455
strcpy (current_color, color);
468
return g_strdup (current_color);
477
file_buffer (enum buf_op op, gpointer handle)
479
struct file_handle *h;
485
if (xpm_seek_string (h->infile, "XPM") != TRUE)
489
if (xpm_seek_char (h->infile, '{') != TRUE)
493
/* Fall through to the next xpm_seek_char. */
496
xpm_seek_char (h->infile, '"');
497
fseek (h->infile, -1, SEEK_CUR);
498
/* Fall through to the xpm_read_string. */
501
if(!xpm_read_string (h->infile, &h->buffer, &h->buffer_size))
508
g_assert_not_reached ();
514
/* This function does all the work. */
516
pixbuf_create_from_xpm (gpointer handle, xfwmColorSymbol *color_sym)
521
gint w, h, n_col, cpp, items;
522
gint cnt, xcnt, ycnt, wbytes, n;
523
GHashTable *color_hash;
524
XPMColor *colors, *color, *fallbackcolor;
528
fallbackcolor = NULL;
530
buffer = file_buffer (op_header, handle);
533
g_warning ("Cannot read Pixmap header");
536
items = sscanf (buffer, "%d %d %d %d", &w, &h, &n_col, &cpp);
540
g_warning ("Pixmap definition contains invalid number attributes (expecting at least 4, got %i)", items);
549
(n_col >= G_MAXINT / (cpp + 1)) ||
550
(n_col >= G_MAXINT / (gint) sizeof (XPMColor)))
552
g_warning ("Pixmap definition contains invalid attributes");
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);
559
name_buf = g_try_malloc (n_col * (cpp + 1));
561
g_hash_table_destroy (color_hash);
562
g_warning ("Cannot allocate buffer");
566
colors = (XPMColor *) g_try_malloc (sizeof (XPMColor) * n_col);
569
g_hash_table_destroy (color_hash);
571
g_warning ("Cannot allocate colors for Pixmap");
575
for (cnt = 0; cnt < n_col; cnt++)
579
buffer = file_buffer (op_cmap, handle);
582
g_hash_table_destroy (color_hash);
585
g_warning ("Cannot load colormap attributes");
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;
596
color_name = xpm_extract_color (buffer, color_sym);
598
if ((color_name == NULL) ||
599
(g_ascii_strcasecmp (color_name, "None") == 0) ||
600
(parse_color (color_name, color) == FALSE))
602
color->transparent = TRUE;
609
g_hash_table_insert (color_hash, color->color_string, color);
613
fallbackcolor = color;
617
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
621
g_hash_table_destroy (color_hash);
624
g_warning ("Cannot allocate Pixbuf");
630
for (ycnt = 0; ycnt < h; ycnt++)
632
pixtmp = gdk_pixbuf_get_pixels (pixbuf) + ycnt * gdk_pixbuf_get_rowstride(pixbuf);
634
buffer = file_buffer (op_body, handle);
635
if ((!buffer) || (wbytes > (gint) strlen (buffer)))
640
for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
642
strncpy (pixel_str, &buffer[n], cpp);
645
color = g_hash_table_lookup (color_hash, pixel_str);
650
color = fallbackcolor;
653
*pixtmp++ = color->red >> 8;
654
*pixtmp++ = color->green >> 8;
655
*pixtmp++ = color->blue >> 8;
657
if (color->transparent)
668
g_hash_table_destroy (color_hash);
677
xpm_image_load (const char *filename, xfwmColorSymbol *color_sym)
681
struct file_handle h;
685
f = g_fopen (filename, "rb");
691
size = fread (&buffer, 1, sizeof (buffer), f);
698
fseek (f, 0, SEEK_SET);
699
memset (&h, 0, sizeof (h));
701
pixbuf = pixbuf_create_from_xpm (&h, color_sym);
710
xfwmPixmapRefreshPict (xfwmPixmap * pm)
712
ScreenInfo * screen_info;
714
screen_info = pm->screen_info;
715
if (!pm->pict_format)
717
pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
718
screen_info->visual);
721
if (pm->pict != None)
723
XRenderFreePicture (myScreenGetXDisplay(pm->screen_info), pm->pict);
727
if ((pm->pixmap) && (pm->pict_format))
729
pm->pict = XRenderCreatePicture (myScreenGetXDisplay (screen_info),
730
pm->pixmap, pm->pict_format, 0, NULL);
736
xfwmPixmapCompose (GdkPixbuf *pixbuf, const gchar * dir, const gchar * file)
744
static const char* image_types[] = {
755
while ((image_types[i]) && (!alpha))
757
filepng = g_strdup_printf ("%s.%s", file, image_types[i]);
758
filename = g_build_filename (dir, filepng, NULL);
761
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
763
alpha = gdk_pixbuf_new_from_file (filename, NULL);
771
/* We have no suitable image to layer on top of the XPM, stop here... */
777
/* We have no XPM canvas and found a suitable image, use it... */
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));
786
gdk_pixbuf_composite (alpha, pixbuf, 0, 0, width, height,
787
0, 0, 1.0, 1.0, GDK_INTERP_BILINEAR, 0xFF);
789
g_object_unref (alpha);
795
xfwmPixmapDrawFromGdkPixbuf (xfwmPixmap * pm, GdkPixbuf *pixbuf)
797
GdkPixmap *dest_pixmap;
798
GdkPixmap *dest_bitmap;
803
gint alpha_threshold;
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);
809
dest_pixmap = gdk_xid_table_lookup (pm->pixmap);
812
g_object_ref (G_OBJECT (dest_pixmap));
816
dest_pixmap = gdk_pixmap_foreign_new (pm->pixmap);
821
g_warning ("Cannot get pixmap");
825
dest_bitmap = gdk_xid_table_lookup (pm->mask);
828
g_object_ref (G_OBJECT (dest_bitmap));
832
dest_bitmap = gdk_pixmap_foreign_new (pm->mask);
837
g_warning ("Cannot get bitmap");
838
g_object_unref (dest_pixmap);
842
gvisual = gdk_screen_get_system_visual (pm->screen_info->gscr);
843
cmap = gdk_x11_colormap_foreign_new (gvisual, pm->screen_info->cmap);
847
g_warning ("Cannot create colormap");
848
g_object_unref (dest_pixmap);
849
g_object_unref (dest_bitmap);
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;
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);
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);
867
g_object_unref (cmap);
868
g_object_unref (dest_pixmap);
869
g_object_unref (dest_bitmap);
875
xfwmPixmapRenderGdkPixbuf (xfwmPixmap * pm, GdkPixbuf *pixbuf)
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);
888
destw = gdk_xid_table_lookup (pm->pixmap);
891
g_object_ref (G_OBJECT (destw));
895
destw = gdk_pixmap_foreign_new (pm->pixmap);
900
g_warning ("Cannot get pixmap");
904
gvisual = gdk_screen_get_system_visual (pm->screen_info->gscr);
905
cmap = gdk_x11_colormap_foreign_new (gvisual, pm->screen_info->cmap);
909
g_warning ("Cannot create colormap");
910
g_object_unref (destw);
914
width = MIN (gdk_pixbuf_get_width (pixbuf), pm->width);
915
height = MIN (gdk_pixbuf_get_height (pixbuf), pm->height);
917
/* Add 1 for rounding */
918
dest_x = (pm->width - width + 1) / 2;
919
dest_y = (pm->height - height + 1) / 2;
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);
928
g_object_unref (cmap);
929
g_object_unref (src);
930
g_object_unref (destw);
936
xfwmPixmapLoad (ScreenInfo * screen_info, xfwmPixmap * pm, const gchar * dir, const gchar * file, xfwmColorSymbol * cs)
942
TRACE ("entering xfwmPixmapLoad(%s)", file);
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);
948
xfwmPixmapInit (screen_info, pm);
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).
954
filexpm = g_strdup_printf ("%s.%s", file, "xpm");
955
filename = g_build_filename (dir, filexpm, NULL);
957
pixbuf = xpm_image_load (filename, cs);
960
/* Compose with other image formats, if any available. */
961
pixbuf = xfwmPixmapCompose (pixbuf, dir, file);
965
* Cannot find a suitable image format for some part,
966
* it's not critical though as most themes are missing
971
xfwmPixmapCreate (screen_info, pm,
972
gdk_pixbuf_get_width (pixbuf),
973
gdk_pixbuf_get_height (pixbuf));
974
xfwmPixmapDrawFromGdkPixbuf (pm, pixbuf);
977
xfwmPixmapRefreshPict (pm);
979
g_object_unref (pixbuf);
985
xfwmPixmapCreate (ScreenInfo * screen_info, xfwmPixmap * pm,
986
gint width, gint height)
988
TRACE ("entering xfwmPixmapCreate, width=%i, height=%i", width, height);
989
g_return_if_fail (screen_info != NULL);
991
if ((width < 1) || (height < 1))
993
xfwmPixmapInit (screen_info, pm);
997
pm->screen_info = screen_info;
998
pm->pixmap = XCreatePixmap (myScreenGetXDisplay (screen_info),
1000
width, height, screen_info->depth);
1001
pm->mask = XCreatePixmap (myScreenGetXDisplay (screen_info),
1002
pm->pixmap, width, height, 1);
1004
pm->height = height;
1006
pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
1007
screen_info->visual);
1014
xfwmPixmapInit (ScreenInfo * screen_info, xfwmPixmap * pm)
1016
pm->screen_info = screen_info;
1022
pm->pict_format = XRenderFindVisualFormat (myScreenGetXDisplay (screen_info),
1023
screen_info->visual);
1029
xfwmPixmapFree (xfwmPixmap * pm)
1032
TRACE ("entering xfwmPixmapFree");
1036
if (pm->pixmap != None)
1038
XFreePixmap (myScreenGetXDisplay(pm->screen_info), pm->pixmap);
1041
if (pm->mask != None)
1043
XFreePixmap (myScreenGetXDisplay(pm->screen_info), pm->mask);
1047
if (pm->pict != None)
1049
XRenderFreePicture (myScreenGetXDisplay(pm->screen_info), pm->pict);
1056
xfwmPixmapNone (xfwmPixmap * pm)
1058
TRACE ("entering xfwmPixmapEmpty");
1060
g_return_val_if_fail (pm != NULL, FALSE);
1061
return (pm->pixmap == None);
1065
xfwmPixmapFillRectangle (Display *dpy, int screen, Pixmap pm, Drawable d,
1066
int x, int y, int width, int height)
1072
TRACE ("entering fillRectangle");
1074
if ((width < 1) || (height < 1))
1078
gv.fill_style = FillTiled;
1082
gv.foreground = WhitePixel (dpy, screen);
1083
if (gv.tile != None)
1085
mask = GCTile | GCFillStyle | GCTileStipXOrigin;
1089
mask = GCForeground;
1091
gc = XCreateGC (dpy, d, mask, &gv);
1092
XFillRectangle (dpy, d, gc, x, y, width, height);
1097
xfwmPixmapFill (xfwmPixmap * src, xfwmPixmap * dst,
1098
gint x, gint y, gint width, gint height)
1100
TRACE ("entering xfwmWindowFill");
1102
if ((width < 1) || (height < 1))
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);
1114
xfwmPixmapRefreshPict (dst);
1119
xfwmPixmapDuplicate (xfwmPixmap * src, xfwmPixmap * dst)
1121
g_return_if_fail (src != NULL);
1122
TRACE ("entering xfwmPixmapDuplicate, width=%i, height=%i", src->width, src->height);
1124
xfwmPixmapCreate (src->screen_info, dst, src->width, src->height);
1125
xfwmPixmapFill (src, dst, 0, 0, src->width, src->height);