gdkpixmap-win32.c

Go to the documentation of this file.
00001 /* GDK - The GIMP Drawing Kit
00002  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
00003  * Copyright (C) 1998-1999 Tor Lillqvist
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the
00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, USA.
00019  */
00020 
00021 /*
00022  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
00023  * file for a list of people on the GTK+ Team.  See the ChangeLog
00024  * files for a list of changes.  These files are distributed with
00025  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
00026  */
00027 
00028 #include "config.h"
00029 
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 #include "gdkpixmap.h"
00035 #include "gdkprivate.h"
00036 #include "gdkwin32.h"
00037 
00038 typedef struct {
00039    gchar *color_string;
00040    GdkColor color;
00041    gint transparent;
00042 } _GdkPixmapColor;
00043 
00044 typedef struct {
00045    guint ncolors;
00046    GdkColormap *colormap;
00047    gulong pixels[1];
00048 } _GdkPixmapInfo;
00049 
00050 static void gdk_win32_pixmap_destroy(GdkPixmap * pixmap)
00051 {
00052    GdkDrawablePrivate *private = (GdkDrawablePrivate *) pixmap;
00053 
00054    GDK_NOTE(MISC, g_print("gdk_win32_pixmap_destroy: %#x\n",
00055                           GDK_DRAWABLE_XID(pixmap)));
00056 
00057    if (!DeleteObject(GDK_DRAWABLE_XID(pixmap)))
00058       WIN32_GDI_FAILED("DeleteObject");
00059 
00060    gdk_xid_table_remove(GDK_DRAWABLE_XID(pixmap));
00061 
00062    g_free(GDK_DRAWABLE_WIN32DATA(pixmap));
00063 }
00064 
00065 static GdkDrawable *gdk_win32_pixmap_alloc(void)
00066 {
00067    GdkDrawable *drawable;
00068    GdkDrawablePrivate *private;
00069 
00070    static GdkDrawableClass klass;
00071    static gboolean initialized = FALSE;
00072 
00073    if (!initialized) {
00074       initialized = TRUE;
00075 
00076       klass = _gdk_win32_drawable_class;
00077       klass.destroy = gdk_win32_pixmap_destroy;
00078    }
00079 
00080    drawable = gdk_drawable_alloc();
00081    private = (GdkDrawablePrivate *) drawable;
00082 
00083    private->klass = &klass;
00084    private->klass_data = g_new(GdkDrawableWin32Data, 1);
00085    private->window_type = GDK_DRAWABLE_PIXMAP;
00086 
00087    return drawable;
00088 }
00089 
00090 GdkPixmap *gdk_pixmap_new(GdkWindow * window,
00091                           gint width, gint height, gint depth)
00092 {
00093    GdkPixmap *pixmap;
00094    GdkDrawablePrivate *private;
00095    struct {
00096       BITMAPINFOHEADER bmiHeader;
00097       union {
00098          WORD bmiIndices[256];
00099          DWORD bmiMasks[3];
00100          RGBQUAD bmiColors[256];
00101       } u;
00102    } bmi;
00103    UINT iUsage;
00104    HDC hdc;
00105    GdkVisual *visual;
00106    guchar *bits;
00107    gint i;
00108 
00109    g_return_val_if_fail(window == NULL || GDK_IS_WINDOW(window), NULL);
00110    g_return_val_if_fail((window != NULL) || (depth != -1), NULL);
00111    g_return_val_if_fail((width != 0) && (height != 0), NULL);
00112 
00113    if (!window)
00114       window = gdk_parent_root;
00115 
00116    if (GDK_DRAWABLE_DESTROYED(window))
00117       return NULL;
00118 
00119    if (depth == -1)
00120       depth = gdk_drawable_get_visual(window)->depth;
00121 
00122    GDK_NOTE(MISC, g_print("gdk_pixmap_new: %dx%dx%d\n",
00123                           width, height, depth));
00124 
00125    pixmap = gdk_win32_pixmap_alloc();
00126    private = (GdkDrawablePrivate *) pixmap;
00127 
00128    visual = gdk_drawable_get_visual(window);
00129 
00130    if ((hdc = GetDC(GDK_DRAWABLE_XID(window))) == NULL) {
00131       WIN32_GDI_FAILED("GetDC");
00132       g_free(private);
00133       return NULL;
00134    }
00135 
00136    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00137    bmi.bmiHeader.biWidth = width;
00138    bmi.bmiHeader.biHeight = -height;
00139    bmi.bmiHeader.biPlanes = 1;
00140    if (depth == 15)
00141       bmi.bmiHeader.biBitCount = 16;
00142    else
00143       bmi.bmiHeader.biBitCount = depth;
00144 #if 1
00145    if (depth == 16)
00146       bmi.bmiHeader.biCompression = BI_BITFIELDS;
00147    else
00148 #endif
00149       bmi.bmiHeader.biCompression = BI_RGB;
00150    bmi.bmiHeader.biSizeImage = 0;
00151    bmi.bmiHeader.biXPelsPerMeter = bmi.bmiHeader.biYPelsPerMeter = 0;
00152    bmi.bmiHeader.biClrUsed = 0;
00153    bmi.bmiHeader.biClrImportant = 0;
00154 
00155    iUsage = DIB_RGB_COLORS;
00156    if (depth == 1) {
00157       bmi.u.bmiColors[0].rgbBlue =
00158           bmi.u.bmiColors[0].rgbGreen = bmi.u.bmiColors[0].rgbRed = 0x00;
00159       bmi.u.bmiColors[0].rgbReserved = 0x00;
00160 
00161       bmi.u.bmiColors[1].rgbBlue =
00162           bmi.u.bmiColors[1].rgbGreen = bmi.u.bmiColors[1].rgbRed = 0xFF;
00163       bmi.u.bmiColors[1].rgbReserved = 0x00;
00164       private->colormap = NULL;
00165    } else {
00166       private->colormap = ((GdkWindowPrivate *) window)->drawable.colormap;
00167       if (private->colormap == NULL)
00168          private->colormap = gdk_colormap_get_system();
00169 
00170       if (depth == 8) {
00171          iUsage = DIB_PAL_COLORS;
00172          for (i = 0; i < 256; i++)
00173             bmi.u.bmiIndices[i] = i;
00174       } else {
00175          if (depth != visual->depth)
00176             g_warning
00177                 ("gdk_pixmap_new: depth %d doesn't match display depth %d",
00178                  depth, visual->depth);
00179 #if 1
00180          if (depth == 16) {
00181             bmi.u.bmiMasks[0] = visual->red_mask;
00182             bmi.u.bmiMasks[1] = visual->green_mask;
00183             bmi.u.bmiMasks[2] = visual->blue_mask;
00184          }
00185 #endif
00186       }
00187    }
00188    if ((GDK_DRAWABLE_WIN32DATA(pixmap)->xid =
00189         CreateDIBSection(hdc, (BITMAPINFO *) & bmi,
00190                          iUsage, (PVOID *) & bits, NULL, 0)) == NULL) {
00191       WIN32_GDI_FAILED("CreateDIBSection");
00192       ReleaseDC(GDK_DRAWABLE_XID(window), hdc);
00193       g_free(pixmap);
00194       return NULL;
00195    }
00196    ReleaseDC(GDK_DRAWABLE_XID(window), hdc);
00197 
00198    GDK_NOTE(MISC, g_print("... = %#x\n", GDK_DRAWABLE_XID(pixmap)));
00199 
00200    private->width = width;
00201    private->height = height;
00202 
00203    gdk_xid_table_insert(&GDK_DRAWABLE_XID(pixmap), pixmap);
00204 
00205    return pixmap;
00206 }
00207 
00208 GdkPixmap *gdk_pixmap_create_on_shared_image(GdkImage ** image_return,
00209                                              GdkWindow * window,
00210                                              GdkVisual * visual,
00211                                              gint width,
00212                                              gint height, gint depth)
00213 {
00214    GdkPixmap *pixmap;
00215    GdkDrawablePrivate *private;
00216 
00217    g_return_val_if_fail(window != NULL, NULL);
00218 
00219 
00220    if (depth == 1)
00221       *image_return =
00222           gdk_image_bitmap_new(GDK_IMAGE_SHARED_PIXMAP, visual, width,
00223                                height);
00224    else {
00225       g_return_val_if_fail(depth == visual->depth, NULL);
00226       *image_return =
00227           gdk_image_new(GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
00228    }
00229 
00230    g_return_val_if_fail(*image_return != NULL, NULL);
00231 
00232    pixmap = gdk_win32_pixmap_alloc();
00233    private = (GdkDrawablePrivate *) pixmap;
00234 
00235    GDK_DRAWABLE_WIN32DATA(pixmap)->xid =
00236        ((GdkImagePrivateWin32 *) * image_return)->ximage;
00237    private->colormap = ((GdkWindowPrivate *) window)->drawable.colormap;
00238    private->width = width;
00239    private->height = height;
00240 
00241    gdk_xid_table_insert(&GDK_DRAWABLE_XID(pixmap), pixmap);
00242 
00243    GDK_NOTE(MISC,
00244             g_print("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n",
00245                     width, height, depth, GDK_DRAWABLE_XID(pixmap)));
00246 
00247    return pixmap;
00248 }
00249 
00250 static unsigned char mirror[256] = {
00251    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
00252    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
00253    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
00254    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
00255    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
00256    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
00257    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
00258    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
00259    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
00260    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
00261    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
00262    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
00263    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
00264    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
00265    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
00266    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
00267    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
00268    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
00269    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
00270    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
00271    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
00272    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
00273    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
00274    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
00275    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
00276    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
00277    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
00278    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
00279    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
00280    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
00281    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
00282    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
00283 };
00284 
00285 GdkPixmap *gdk_bitmap_create_from_data(GdkWindow * window,
00286                                        const gchar * data,
00287                                        gint width, gint height)
00288 {
00289    GdkPixmap *pixmap;
00290    GdkDrawablePrivate *private;
00291    gint i, j, bpl, aligned_bpl;
00292    guchar *bits;
00293 
00294    g_return_val_if_fail(data != NULL, NULL);
00295    g_return_val_if_fail((width != 0) && (height != 0), NULL);
00296    g_return_val_if_fail(window == NULL || GDK_IS_WINDOW(window), NULL);
00297 
00298    if (!window)
00299       window = gdk_parent_root;
00300 
00301    if (GDK_DRAWABLE_DESTROYED(window))
00302       return NULL;
00303 
00304    pixmap = gdk_win32_pixmap_alloc();
00305    private = (GdkDrawablePrivate *) pixmap;
00306 
00307    private->width = width;
00308    private->height = height;
00309 
00310    bpl = ((width - 1) / 8 + 1);
00311    aligned_bpl = ((bpl - 1) / 2 + 1) * 2;
00312    bits = g_malloc(aligned_bpl * height);
00313    for (i = 0; i < height; i++)
00314       for (j = 0; j < bpl; j++)
00315          bits[i * aligned_bpl + j] = mirror[(guchar) data[i * bpl + j]];
00316 
00317    GDK_DRAWABLE_WIN32DATA(pixmap)->xid =
00318        CreateBitmap(width, height, 1, 1, bits);
00319 
00320    GDK_NOTE(MISC, g_print("gdk_bitmap_create_from_data: %dx%d = %#x\n",
00321                           width, height, GDK_DRAWABLE_XID(pixmap)));
00322 
00323    g_free(bits);
00324 
00325    private->colormap = NULL;
00326    gdk_xid_table_insert(&GDK_DRAWABLE_XID(pixmap), pixmap);
00327 
00328    return pixmap;
00329 }
00330 
00331 GdkPixmap *gdk_pixmap_create_from_data(GdkWindow * window,
00332                                        const gchar * data,
00333                                        gint width,
00334                                        gint height,
00335                                        gint depth,
00336                                        GdkColor * fg, GdkColor * bg)
00337 {
00338    /* Oh wow. I struggled with dozens of lines of code trying to get
00339     * this right using a monochrome Win32 bitmap created from data, and
00340     * a colour DIB section as the result, trying setting pens,
00341     * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
00342     * realized it's much easier to do it using gdk...:
00343     */
00344 
00345    GdkPixmap *result = gdk_pixmap_new(window, width, height, depth);
00346    GdkPixmap *source =
00347        gdk_bitmap_create_from_data(window, data, width, height);
00348    GdkGC *gc = gdk_gc_new(result);
00349    gdk_gc_set_foreground(gc, fg);
00350    gdk_gc_set_background(gc, bg);
00351    gdk_draw_drawable(result, gc, source, 0, 0, 0, 0, width, height);
00352    gdk_drawable_unref(source);
00353    gdk_gc_unref(gc);
00354 
00355    GDK_NOTE(MISC, g_print("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
00356                           width, height, depth, GDK_DRAWABLE_XID(result)));
00357    return result;
00358 }
00359 
00360 static gint
00361 gdk_pixmap_seek_string(FILE * infile,
00362                        const gchar * str, gint skip_comments)
00363 {
00364    char instr[1024];
00365 
00366    while (!feof(infile)) {
00367       fscanf(infile, "%1023s", instr);
00368       if (skip_comments == TRUE && strcmp(instr, "/*") == 0) {
00369          fscanf(infile, "%1023s", instr);
00370          while (!feof(infile) && strcmp(instr, "*/") != 0)
00371             fscanf(infile, "%1023s", instr);
00372          fscanf(infile, "%1023s", instr);
00373       }
00374       if (strcmp(instr, str) == 0)
00375          return TRUE;
00376    }
00377 
00378    return FALSE;
00379 }
00380 
00381 static gint gdk_pixmap_seek_char(FILE * infile, gchar c)
00382 {
00383    gint b, oldb;
00384 
00385    while ((b = getc(infile)) != EOF) {
00386       if (c != b && b == '/') {
00387          b = getc(infile);
00388          if (b == EOF)
00389             return FALSE;
00390          else if (b == '*') {   /* we have a comment */
00391             b = -1;
00392             do {
00393                oldb = b;
00394                b = getc(infile);
00395                if (b == EOF)
00396                   return FALSE;
00397             }
00398             while (!(oldb == '*' && b == '/'));
00399          }
00400       } else if (c == b)
00401          return TRUE;
00402    }
00403    return FALSE;
00404 }
00405 
00406 static gint
00407 gdk_pixmap_read_string(FILE * infile, gchar ** buffer, guint * buffer_size)
00408 {
00409    gint c;
00410    guint cnt = 0, bufsiz, ret = FALSE;
00411    gchar *buf;
00412 
00413    buf = *buffer;
00414    bufsiz = *buffer_size;
00415    if (buf == NULL) {
00416       bufsiz = 10 * sizeof(gchar);
00417       buf = g_new(gchar, bufsiz);
00418    }
00419 
00420    do
00421       c = getc(infile);
00422    while (c != EOF && c != '"');
00423 
00424    if (c != '"')
00425       goto out;
00426 
00427    while ((c = getc(infile)) != EOF) {
00428       if (cnt == bufsiz) {
00429          guint new_size = bufsiz * 2;
00430          if (new_size > bufsiz)
00431             bufsiz = new_size;
00432          else
00433             goto out;
00434 
00435          buf = (gchar *) g_realloc(buf, bufsiz);
00436          buf[bufsiz - 1] = '\0';
00437       }
00438 
00439       if (c != '"')
00440          buf[cnt++] = c;
00441       else {
00442          buf[cnt] = 0;
00443          ret = TRUE;
00444          break;
00445       }
00446    }
00447 
00448  out:
00449    buf[bufsiz - 1] = '\0';      /* ensure null termination for errors */
00450    *buffer = buf;
00451    *buffer_size = bufsiz;
00452    return ret;
00453 }
00454 
00455 static gchar *gdk_pixmap_skip_whitespaces(gchar * buffer)
00456 {
00457    gint32 index = 0;
00458 
00459    while (buffer[index] != 0
00460           && (buffer[index] == 0x20 || buffer[index] == 0x09))
00461       index++;
00462 
00463    return &buffer[index];
00464 }
00465 
00466 static gchar *gdk_pixmap_skip_string(gchar * buffer)
00467 {
00468    gint32 index = 0;
00469 
00470    while (buffer[index] != 0 && buffer[index] != 0x20
00471           && buffer[index] != 0x09)
00472       index++;
00473 
00474    return &buffer[index];
00475 }
00476 
00477 #define MAX_COLOR_LEN 120
00478 
00479 static gchar *gdk_pixmap_extract_color(gchar * buffer)
00480 {
00481    gint counter, numnames;
00482    gchar *ptr = NULL, ch, temp[128];
00483    gchar color[MAX_COLOR_LEN], *retcol;
00484    gint space;
00485 
00486    counter = 0;
00487    while (ptr == NULL) {
00488       if (buffer[counter] == 'c') {
00489          ch = buffer[counter + 1];
00490          if (ch == 0x20 || ch == 0x09)
00491             ptr = &buffer[counter + 1];
00492       } else if (buffer[counter] == 0)
00493          return NULL;
00494 
00495       counter++;
00496    }
00497 
00498    ptr = gdk_pixmap_skip_whitespaces(ptr);
00499 
00500    if (ptr[0] == 0)
00501       return NULL;
00502    else if (ptr[0] == '#') {
00503       counter = 1;
00504       while (ptr[counter] != 0 &&
00505              ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
00506               (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
00507               (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
00508          counter++;
00509 
00510       retcol = g_new(gchar, counter + 1);
00511       strncpy(retcol, ptr, counter);
00512 
00513       retcol[counter] = 0;
00514 
00515       return retcol;
00516    }
00517 
00518    color[0] = 0;
00519    numnames = 0;
00520 
00521    space = MAX_COLOR_LEN - 1;
00522    while (space > 0) {
00523       sscanf(ptr, "%127s", temp);
00524 
00525       if (((gint) ptr[0] == 0) ||
00526           (strcmp("s", temp) == 0) || (strcmp("m", temp) == 0) ||
00527           (strcmp("g", temp) == 0) || (strcmp("g4", temp) == 0)) {
00528          break;
00529       } else {
00530          if (numnames > 0) {
00531             space -= 1;
00532             strcat(color, " ");
00533          }
00534          strncat(color, temp, space);
00535          space -= MIN(space, (gint)strlen(temp));
00536          ptr = gdk_pixmap_skip_string(ptr);
00537          ptr = gdk_pixmap_skip_whitespaces(ptr);
00538          numnames++;
00539       }
00540    }
00541 
00542    retcol = g_strdup(color);
00543    return retcol;
00544 }
00545 
00546 
00547 enum buffer_op {
00548    op_header,
00549    op_cmap,
00550    op_body
00551 };
00552 
00553 
00554 static void gdk_xpm_destroy_notify(gpointer data)
00555 {
00556    _GdkPixmapInfo *info = (_GdkPixmapInfo *) data;
00557    GdkColor color;
00558    guint i;
00559 
00560    for (i = 0; i < info->ncolors; i++) {
00561       color.pixel = info->pixels[i];
00562       gdk_colormap_free_colors(info->colormap, &color, 1);
00563    }
00564 
00565    gdk_colormap_unref(info->colormap);
00566    g_free(info);
00567 }
00568 
00569 static GdkPixmap *_gdk_pixmap_create_from_xpm(GdkWindow * window,
00570                                               GdkColormap * colormap,
00571                                               GdkBitmap ** mask,
00572                                               GdkColor * transparent_color,
00573                                               gchar *
00574                                               (*get_buf) (enum buffer_op
00575                                                           op,
00576                                                           gpointer handle),
00577                                               gpointer handle)
00578 {
00579    GdkPixmap *pixmap = NULL;
00580    GdkImage *image = NULL;
00581    GdkVisual *visual;
00582    GdkGC *gc = NULL;
00583    GdkColor tmp_color;
00584    gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
00585    gchar *buffer, pixel_str[32];
00586    gchar *name_buf;
00587    _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
00588    _GdkPixmapColor *colors = NULL;
00589    gulong index;
00590    GHashTable *color_hash = NULL;
00591    _GdkPixmapInfo *color_info = NULL;
00592 
00593    if ((window == NULL) && (colormap == NULL))
00594       g_warning("Creating pixmap from xpm with NULL window and colormap");
00595 
00596    if (window == NULL)
00597       window = gdk_parent_root;
00598 
00599    if (colormap == NULL) {
00600       colormap = gdk_drawable_get_colormap(window);
00601       visual = gdk_drawable_get_visual(window);
00602    } else
00603       visual = ((GdkColormapPrivate *) colormap)->visual;
00604 
00605    buffer = (*get_buf) (op_header, handle);
00606    if (buffer == NULL)
00607       return NULL;
00608 
00609    sscanf(buffer, "%d %d %d %d", &width, &height, &num_cols, &cpp);
00610    if (cpp >= 32) {
00611       g_warning("Pixmap has more than 31 characters per color");
00612       return NULL;
00613    }
00614 
00615    color_hash = g_hash_table_new(g_str_hash, g_str_equal);
00616 
00617    if (transparent_color == NULL) {
00618       gdk_color_white(colormap, &tmp_color);
00619       transparent_color = &tmp_color;
00620    }
00621 
00622    /* For pseudo-color and grayscale visuals, we have to remember
00623     * the colors we allocated, so we can free them later.
00624     */
00625    if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
00626        (visual->type == GDK_VISUAL_GRAYSCALE)) {
00627       color_info = g_malloc(sizeof(_GdkPixmapInfo) +
00628                             sizeof(gulong) * (num_cols - 1));
00629       color_info->ncolors = num_cols;
00630       color_info->colormap = colormap;
00631       gdk_colormap_ref(colormap);
00632    }
00633 
00634    name_buf = g_new(gchar, num_cols * (cpp + 1));
00635    colors = g_new(_GdkPixmapColor, num_cols);
00636 
00637    for (cnt = 0; cnt < num_cols; cnt++) {
00638       gchar *color_name;
00639 
00640       buffer = (*get_buf) (op_cmap, handle);
00641       if (buffer == NULL)
00642          goto error;
00643 
00644       color = &colors[cnt];
00645       color->color_string = &name_buf[cnt * (cpp + 1)];
00646       strncpy(color->color_string, buffer, cpp);
00647       color->color_string[cpp] = 0;
00648       buffer += strlen(color->color_string);
00649       color->transparent = FALSE;
00650 
00651       color_name = gdk_pixmap_extract_color(buffer);
00652 
00653       if (color_name == NULL ||
00654           gdk_color_parse(color_name, &color->color) == FALSE) {
00655          color->color = *transparent_color;
00656          color->transparent = TRUE;
00657       }
00658 
00659       g_free(color_name);
00660 
00661       /* FIXME: The remaining slowness appears to happen in this
00662          function. */
00663       gdk_color_alloc(colormap, &color->color);
00664 
00665       if (color_info)
00666          color_info->pixels[cnt] = color->color.pixel;
00667 
00668       g_hash_table_insert(color_hash, color->color_string, color);
00669       if (cnt == 0)
00670          fallbackcolor = color;
00671    }
00672 
00673    index = 0;
00674    image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
00675 
00676    if (mask) {
00677       /* The pixmap mask is just a bits pattern.
00678        * Color 0 is used for background and 1 for foreground.
00679        * We don't care about the colormap, we just need 0 and 1.
00680        */
00681       GdkColor mask_pattern;
00682 
00683       *mask = gdk_pixmap_new(window, width, height, 1);
00684       gc = gdk_gc_new(*mask);
00685 
00686       mask_pattern.pixel = 0;
00687       gdk_gc_set_foreground(gc, &mask_pattern);
00688       gdk_draw_rectangle(*mask, gc, TRUE, 0, 0, -1, -1);
00689 
00690       mask_pattern.pixel = 1;
00691       gdk_gc_set_foreground(gc, &mask_pattern);
00692    }
00693 
00694    wbytes = width * cpp;
00695    for (ycnt = 0; ycnt < height; ycnt++) {
00696       buffer = (*get_buf) (op_body, handle);
00697 
00698       /* FIXME: this slows things down a little - it could be
00699        * integrated into the strncpy below, perhaps. OTOH, strlen
00700        * is fast.
00701        */
00702       if ((buffer == NULL) || (gint)strlen(buffer) < wbytes)
00703          continue;
00704 
00705       for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) {
00706          strncpy(pixel_str, &buffer[n], cpp);
00707          pixel_str[cpp] = 0;
00708          ns = 0;
00709 
00710          color = g_hash_table_lookup(color_hash, pixel_str);
00711 
00712          if (!color)            /* screwed up XPM file */
00713             color = fallbackcolor;
00714 
00715          gdk_image_put_pixel(image, xcnt, ycnt, color->color.pixel);
00716 
00717          if (mask && color->transparent) {
00718             if (cnt < xcnt)
00719                gdk_draw_line(*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
00720             cnt = xcnt + 1;
00721          }
00722       }
00723 
00724       if (mask && (cnt < xcnt))
00725          gdk_draw_line(*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
00726    }
00727 
00728  error:
00729 
00730    if (mask)
00731       gdk_gc_unref(gc);
00732 
00733    if (image != NULL) {
00734       pixmap = gdk_pixmap_new(window, width, height, visual->depth);
00735 
00736       if (color_info)
00737          gdk_drawable_set_data(pixmap, "gdk-xpm", color_info,
00738                                gdk_xpm_destroy_notify);
00739 
00740       gc = gdk_gc_new(pixmap);
00741       gdk_gc_set_foreground(gc, transparent_color);
00742       gdk_draw_image(pixmap, gc, image, 0, 0, 0, 0, image->width,
00743                      image->height);
00744       gdk_gc_unref(gc);
00745       gdk_image_unref(image);
00746    } else if (color_info)
00747       gdk_xpm_destroy_notify(color_info);
00748 
00749    if (color_hash != NULL)
00750       g_hash_table_destroy(color_hash);
00751 
00752    if (colors != NULL)
00753       g_free(colors);
00754 
00755    if (name_buf != NULL)
00756       g_free(name_buf);
00757 
00758    return pixmap;
00759 }
00760 
00761 
00762 struct file_handle {
00763    FILE *infile;
00764    gchar *buffer;
00765    guint buffer_size;
00766 };
00767 
00768 
00769 static gchar *file_buffer(enum buffer_op op, gpointer handle)
00770 {
00771    struct file_handle *h = handle;
00772 
00773    switch (op) {
00774    case op_header:
00775       if (gdk_pixmap_seek_string(h->infile, "XPM", FALSE) != TRUE)
00776          break;
00777 
00778       if (gdk_pixmap_seek_char(h->infile, '{') != TRUE)
00779          break;
00780       /* Fall through to the next gdk_pixmap_seek_char. */
00781 
00782    case op_cmap:
00783       gdk_pixmap_seek_char(h->infile, '"');
00784       fseek(h->infile, -1, SEEK_CUR);
00785       /* Fall through to the gdk_pixmap_read_string. */
00786 
00787    case op_body:
00788       gdk_pixmap_read_string(h->infile, &h->buffer, &h->buffer_size);
00789       return h->buffer;
00790    }
00791    return 0;
00792 }
00793 
00794 GdkPixmap *gdk_pixmap_colormap_create_from_xpm(GdkWindow * window,
00795                                                GdkColormap * colormap,
00796                                                GdkBitmap ** mask,
00797                                                GdkColor *
00798                                                transparent_color,
00799                                                const gchar * filename)
00800 {
00801    struct file_handle h;
00802    GdkPixmap *pixmap = NULL;
00803 
00804    memset(&h, 0, sizeof(h));
00805    h.infile = fopen(filename, "rb");
00806    if (h.infile != NULL) {
00807       pixmap = _gdk_pixmap_create_from_xpm(window, colormap, mask,
00808                                            transparent_color,
00809                                            file_buffer, &h);
00810       fclose(h.infile);
00811       g_free(h.buffer);
00812    }
00813 
00814    return pixmap;
00815 }
00816 
00817 GdkPixmap *gdk_pixmap_create_from_xpm(GdkWindow * window,
00818                                       GdkBitmap ** mask,
00819                                       GdkColor * transparent_color,
00820                                       const gchar * filename)
00821 {
00822    return gdk_pixmap_colormap_create_from_xpm(window, NULL, mask,
00823                                               transparent_color, filename);
00824 }
00825 
00826 struct mem_handle {
00827    gchar **data;
00828    int offset;
00829 };
00830 
00831 
00832 static gchar *mem_buffer(enum buffer_op op, gpointer handle)
00833 {
00834    struct mem_handle *h = handle;
00835    switch (op) {
00836    case op_header:
00837    case op_cmap:
00838    case op_body:
00839       if (h->data[h->offset])
00840          return h->data[h->offset++];
00841    }
00842    return 0;
00843 }
00844 
00845 GdkPixmap *gdk_pixmap_colormap_create_from_xpm_d(GdkWindow * window,
00846                                                  GdkColormap * colormap,
00847                                                  GdkBitmap ** mask,
00848                                                  GdkColor *
00849                                                  transparent_color,
00850                                                  gchar ** data)
00851 {
00852    struct mem_handle h;
00853    GdkPixmap *pixmap = NULL;
00854 
00855    memset(&h, 0, sizeof(h));
00856    h.data = data;
00857    pixmap = _gdk_pixmap_create_from_xpm(window, colormap, mask,
00858                                         transparent_color, mem_buffer, &h);
00859    return pixmap;
00860 }
00861 
00862 GdkPixmap *gdk_pixmap_create_from_xpm_d(GdkWindow * window,
00863                                         GdkBitmap ** mask,
00864                                         GdkColor * transparent_color,
00865                                         gchar ** data)
00866 {
00867    return gdk_pixmap_colormap_create_from_xpm_d(window, NULL, mask,
00868                                                 transparent_color, data);
00869 }
00870 
00871 GdkPixmap *gdk_pixmap_foreign_new(guint32 anid)
00872 {
00873    GdkPixmap *pixmap;
00874    GdkDrawablePrivate *private;
00875    HBITMAP xpixmap;
00876    SIZE size;
00877    unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
00878 
00879    /* check to make sure we were passed something at
00880       least a little sane */
00881    g_return_val_if_fail((anid != 0), NULL);
00882 
00883    /* set the pixmap to the passed in value */
00884    xpixmap = (HBITMAP) anid;
00885 
00886    /* get information about the BITMAP to fill in the structure for
00887       the gdk window */
00888    GetBitmapDimensionEx(xpixmap, &size);
00889    w_ret = size.cx;
00890    h_ret = size.cy;
00891 
00892    /* allocate a new gdk pixmap */
00893    pixmap = gdk_win32_pixmap_alloc();
00894    private = (GdkDrawablePrivate *) pixmap;
00895 
00896    GDK_DRAWABLE_WIN32DATA(pixmap)->xid = xpixmap;
00897    private->colormap = NULL;
00898    private->width = w_ret;
00899    private->height = h_ret;
00900 
00901    gdk_xid_table_insert(&GDK_DRAWABLE_XID(pixmap), pixmap);
00902 
00903    return pixmap;
00904 }

Generated on Tue Jul 5 14:14:40 2011 for ROOT_528-00b_version by  doxygen 1.5.1