~bratsche/ubuntu/maverick/gtk+2.0/menu-activation-fix

« back to all changes in this revision

Viewing changes to gdk-pixbuf/io-ico.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-07-22 21:41:30 UTC
  • mfrom: (1.11.7 upstream) (72.1.16 experimental)
  • Revision ID: james.westby@ubuntu.com-20100722214130-5uzyvpb9g4m0ts2c
Tags: 2.21.5-1ubuntu1
* Merge with Debian experimental, Ubuntu changes:
* debian/control.in:
  - Add introspection build-depends
  - Add Vcs-Bzr link
  - Add gir1.0-gtk-2.0 package
  - libgtk2.0-dev replaces gir-repository-dev
  - Conflict with appmenu-gtk (<< 0.1.3) to prevent menu proxy breakage
* debian/rules:
  - Build with --enable-introspection
  - Add gir1.0-gtk-2.0 package to BINARY_ARCH_PKGS
  - Add dh_girepository call
  - Disable devhelp files
* debian/dh_gtkmodules.in:
  - Remove obsolete script content
* debian/libgtk2.0-0.symbols:
  - Add Ubuntu specific symbols
* debian/libgtk2.0-dev.install.in:
  - Add gir files
* debian/libgtk2.0-doc.install.in
  - Disable devhelp files
* debian/gir1.0-gtk-2.0.install.in
  - Introspection package
* debian/patches/043_menu_proxy.patch
  - Add GtkMenuProxy support for remoting menus.
* debian/patches/062_dnd_menubar.patch:
  - Allow click on menubars for dnd
* debian/patches/063_treeview_almost_fixed.patch:
  - Add an ubuntu-almost-fixed-height-mode property, (required for
    software-center)
* debian/patches/071_no_offscreen_widgets_grabbing.patch:
  - Don't let offscreen widgets do grabbing
* debian/patches/072_indicator_menu_update.patch:
  - change by Cody Russell to send an update event on menu changes,
    should make the bluetooth indicator refresh correctly
* debian/patches/091_bugzilla_tooltip_refresh.patch:
  - Upstream bugzilla change to have better looking tooltips the gtk theme
    need to set "new-tooltip-style" to use those
* debian/watch:
  - Watch for unstable versions

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C; c-file-style: "linux" -*- */
2
 
/* GdkPixbuf library - Windows Icon/Cursor image loader
3
 
 *
4
 
 * Copyright (C) 1999 The Free Software Foundation
5
 
 *
6
 
 * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
7
 
 *          Federico Mena-Quintero <federico@gimp.org>
8
 
 *
9
 
 * Based on io-bmp.c
10
 
 *
11
 
 * This library is free software; you can redistribute it and/or
12
 
 * modify it under the terms of the GNU Lesser General Public
13
 
 * License as published by the Free Software Foundation; either
14
 
 * version 2 of the License, or (at your option) any later version.
15
 
 *
16
 
 * This library is distributed in the hope that it will be useful,
17
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
 
 * Lesser General Public License for more details.
20
 
 *
21
 
 * You should have received a copy of the GNU Lesser General Public
22
 
 * License along with this library; if not, write to the
23
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24
 
 * Boston, MA 02111-1307, USA.
25
 
 */
26
 
 
27
 
#undef DUMPBIH
28
 
/*
29
 
 
30
 
Icons are just like BMP's, except for the header.
31
 
 
32
 
Known bugs:
33
 
        * bi-tonal files aren't tested 
34
 
 
35
 
*/
36
 
 
37
 
#include "config.h"
38
 
#include <stdio.h>
39
 
#include <stdlib.h>
40
 
#ifdef HAVE_UNISTD_H
41
 
#include <unistd.h>
42
 
#endif
43
 
#include <string.h>
44
 
#include "gdk-pixbuf-private.h"
45
 
#include "gdk-pixbuf-io.h"
46
 
#include <errno.h>
47
 
 
48
 
 
49
 
 
50
 
/* 
51
 
 
52
 
These structures are actually dummies. These are according to
53
 
the "Windows API reference guide volume II" as written by 
54
 
Borland International, but GCC fiddles with the alignment of
55
 
the internal members.
56
 
 
57
 
*/
58
 
 
59
 
struct BitmapFileHeader {
60
 
        gushort bfType;
61
 
        guint bfSize;
62
 
        guint reserverd;
63
 
        guint bfOffbits;
64
 
};
65
 
 
66
 
struct BitmapInfoHeader {
67
 
        guint biSize;
68
 
        guint biWidth;
69
 
        guint biHeight;
70
 
        gushort biPlanes;
71
 
        gushort biBitCount;
72
 
        guint biCompression;
73
 
        guint biSizeImage;
74
 
        guint biXPelsPerMeter;
75
 
        guint biYPelsPerMeter;
76
 
        guint biClrUsed;
77
 
        guint biClrImportant;
78
 
};
79
 
 
80
 
#ifdef DUMPBIH
81
 
/* 
82
 
 
83
 
DumpBIH printf's the values in a BitmapInfoHeader to the screen, for 
84
 
debugging purposes.
85
 
 
86
 
*/
87
 
static void DumpBIH(unsigned char *BIH)
88
 
{                               
89
 
        printf("biSize      = %i \n",
90
 
               (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
91
 
        printf("biWidth     = %i \n",
92
 
               (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
93
 
        printf("biHeight    = %i \n",
94
 
               (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
95
 
               (BIH[8]));
96
 
        printf("biPlanes    = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
97
 
        printf("biBitCount  = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
98
 
        printf("biCompress  = %i \n",
99
 
               (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
100
 
               (BIH[16]));
101
 
        printf("biSizeImage = %i \n",
102
 
               (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
103
 
               (BIH[20]));
104
 
        printf("biXPels     = %i \n",
105
 
               (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
106
 
               (BIH[24]));
107
 
        printf("biYPels     = %i \n",
108
 
               (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
109
 
               (BIH[28]));
110
 
        printf("biClrUsed   = %i \n",
111
 
               (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
112
 
               (BIH[32]));
113
 
        printf("biClrImprtnt= %i \n",
114
 
               (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
115
 
               (BIH[36]));
116
 
}
117
 
#endif
118
 
 
119
 
/* Progressive loading */
120
 
struct headerpair {
121
 
        gint width;
122
 
        gint height;
123
 
        guint depth;
124
 
        guint Negative;         /* Negative = 1 -> top down BMP,  
125
 
                                   Negative = 0 -> bottom up BMP */
126
 
};
127
 
 
128
 
struct ico_progressive_state {
129
 
        GdkPixbufModuleSizeFunc size_func;
130
 
        GdkPixbufModulePreparedFunc prepared_func;
131
 
        GdkPixbufModuleUpdatedFunc updated_func;
132
 
        gpointer user_data;
133
 
 
134
 
        gint HeaderSize;        /* The size of the header-part (incl colormap) */
135
 
        guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
136
 
        gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
137
 
        gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
138
 
 
139
 
        gint LineWidth;         /* The width of a line in bytes */
140
 
        guchar *LineBuf;        /* Buffer for 1 line */
141
 
        gint LineDone;          /* # of bytes in LineBuf */
142
 
        gint Lines;             /* # of finished lines */
143
 
 
144
 
        gint Type;              /*  
145
 
                                   32 = RGBA
146
 
                                   24 = RGB
147
 
                                   16 = 555 RGB
148
 
                                   8 = 8 bit colormapped
149
 
                                   4 = 4 bpp colormapped
150
 
                                   1  = 1 bit bitonal 
151
 
                                 */
152
 
        gboolean cursor;
153
 
        gint x_hot;
154
 
        gint y_hot;
155
 
 
156
 
        struct headerpair Header;       /* Decoded (BE->CPU) header */
157
 
        
158
 
        gint                    DIBoffset;
159
 
        gint                    ImageScore;
160
 
 
161
 
 
162
 
        GdkPixbuf *pixbuf;      /* Our "target" */
163
 
};
164
 
 
165
 
static gpointer
166
 
gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
167
 
                                 GdkPixbufModulePreparedFunc prepared_func,
168
 
                                 GdkPixbufModuleUpdatedFunc updated_func,
169
 
                                 gpointer user_data,
170
 
                                 GError **error);
171
 
static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
172
 
static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
173
 
                                                     const guchar * buf, guint size,
174
 
                                                     GError **error);
175
 
 
176
 
static void 
177
 
context_free (struct ico_progressive_state *context)
178
 
{
179
 
        g_free (context->LineBuf);
180
 
        context->LineBuf = NULL;
181
 
        g_free (context->HeaderBuf);
182
 
 
183
 
        if (context->pixbuf)
184
 
                g_object_unref (context->pixbuf);
185
 
 
186
 
        g_free (context);
187
 
}
188
 
 
189
 
static void DecodeHeader(guchar *Data, gint Bytes,
190
 
                         struct ico_progressive_state *State,
191
 
                         GError **error)
192
 
{
193
 
/* For ICO's we have to be very clever. There are multiple images possible
194
 
   in an .ICO. As a simple heuristic, we select the image which occupies the 
195
 
   largest number of bytes.
196
 
 */   
197
 
 
198
 
        gint IconCount = 0; /* The number of icon-versions in the file */
199
 
        guchar *BIH; /* The DIB for the used icon */
200
 
        guchar *Ptr;
201
 
        gint I;
202
 
        guint16 imgtype; /* 1 = icon, 2 = cursor */
203
 
 
204
 
        /* Step 1: The ICO header */
205
 
 
206
 
        /* First word should be 0 according to specs */
207
 
        if (((Data[1] << 8) + Data[0]) != 0) {
208
 
                g_set_error_literal (error,
209
 
                                     GDK_PIXBUF_ERROR,
210
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
211
 
                                     _("Invalid header in icon"));
212
 
                return;
213
 
 
214
 
        }
215
 
 
216
 
        imgtype = (Data[3] << 8) + Data[2];
217
 
 
218
 
        State->cursor = (imgtype == 2) ? TRUE : FALSE;
219
 
 
220
 
        /* If it is not a cursor make sure it is actually an icon */
221
 
        if (!State->cursor && imgtype != 1) {
222
 
                g_set_error_literal (error,
223
 
                                     GDK_PIXBUF_ERROR,
224
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
225
 
                                     _("Invalid header in icon"));
226
 
                return;
227
 
        }
228
 
 
229
 
 
230
 
        IconCount = (Data[5] << 8) + (Data[4]);
231
 
        
232
 
        State->HeaderSize = 6 + IconCount*16;
233
 
 
234
 
        if (State->HeaderSize>State->BytesInHeaderBuf) {
235
 
                guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
236
 
                if (!tmp) {
237
 
                        g_set_error_literal (error,
238
 
                                             GDK_PIXBUF_ERROR,
239
 
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
240
 
                                             _("Not enough memory to load icon"));
241
 
                        return;
242
 
                }
243
 
                State->HeaderBuf = tmp;
244
 
                State->BytesInHeaderBuf = State->HeaderSize;
245
 
        }
246
 
        if (Bytes < State->HeaderSize)
247
 
                return;
248
 
        
249
 
        /* We now have all the "short-specs" of the versions 
250
 
           So we iterate through them and select the best one */
251
 
           
252
 
        State->ImageScore = 0;
253
 
        State->DIBoffset  = 0;
254
 
        Ptr = Data + 6;
255
 
        for (I=0;I<IconCount;I++) {
256
 
                int ThisScore;
257
 
                
258
 
                ThisScore = (Ptr[11] << 24) + (Ptr[10] << 16) + (Ptr[9] << 8) + (Ptr[8]);
259
 
 
260
 
                if (ThisScore>=State->ImageScore) {
261
 
                        State->ImageScore = ThisScore;
262
 
                        State->x_hot = (Ptr[5] << 8) + Ptr[4];
263
 
                        State->y_hot = (Ptr[7] << 8) + Ptr[6];
264
 
                        State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
265
 
                                           (Ptr[13]<<8) + (Ptr[12]);
266
 
                                                                 
267
 
                }
268
 
                
269
 
                
270
 
                Ptr += 16;      
271
 
        } 
272
 
 
273
 
        if (State->DIBoffset < 0) {
274
 
                g_set_error_literal (error,
275
 
                                     GDK_PIXBUF_ERROR,
276
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
277
 
                                     _("Invalid header in icon"));
278
 
                return;
279
 
        }
280
 
 
281
 
        /* We now have a winner, pointed to in State->DIBoffset,
282
 
           so we know how many bytes are in the "header" part. */
283
 
              
284
 
        State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
285
 
 
286
 
        if (State->HeaderSize < 0) {
287
 
                g_set_error_literal (error,
288
 
                                     GDK_PIXBUF_ERROR,
289
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
290
 
                                     _("Invalid header in icon"));
291
 
                return;
292
 
        }
293
 
 
294
 
        if (State->HeaderSize>State->BytesInHeaderBuf) {
295
 
                guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
296
 
                if (!tmp) {
297
 
                        g_set_error_literal (error,
298
 
                                             GDK_PIXBUF_ERROR,
299
 
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
300
 
                                             _("Not enough memory to load icon"));
301
 
                        return;
302
 
                }
303
 
                State->HeaderBuf = tmp;
304
 
                State->BytesInHeaderBuf = State->HeaderSize;
305
 
        }
306
 
        if (Bytes<State->HeaderSize) 
307
 
                return;   
308
 
        
309
 
        BIH = Data+State->DIBoffset;
310
 
 
311
 
#ifdef DUMPBIH
312
 
        DumpBIH(BIH);
313
 
#endif  
314
 
        /* Add the palette to the headersize */
315
 
                
316
 
        State->Header.width =
317
 
            (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
318
 
        if (State->Header.width == 0) {
319
 
                g_set_error_literal (error,
320
 
                                     GDK_PIXBUF_ERROR,
321
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
322
 
                                     _("Icon has zero width"));
323
 
                return;
324
 
        }
325
 
        State->Header.height =
326
 
            (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2;
327
 
            /* /2 because the BIH height includes the transparency mask */
328
 
        if (State->Header.height == 0) {
329
 
                g_set_error_literal (error,
330
 
                                     GDK_PIXBUF_ERROR,
331
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
332
 
                                     _("Icon has zero height"));
333
 
                return;
334
 
        }
335
 
        State->Header.depth = (BIH[15] << 8) + (BIH[14]);
336
 
 
337
 
        State->Type = State->Header.depth;      
338
 
        if (State->Lines>=State->Header.height)
339
 
                State->Type = 1; /* The transparency mask is 1 bpp */
340
 
        
341
 
        /* Determine the  palette size. If the header indicates 0, it
342
 
           is actually the maximum for the bpp. You have to love the
343
 
           guys who made the spec. */
344
 
        I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
345
 
        I = I*4;
346
 
        if ((I==0)&&(State->Type==1))
347
 
                I = 2*4;
348
 
        if ((I==0)&&(State->Type==4))
349
 
                I = 16*4;
350
 
        if ((I==0)&&(State->Type==8))
351
 
                I = 256*4;
352
 
        
353
 
        State->HeaderSize+=I;
354
 
        
355
 
        if (State->HeaderSize < 0) {
356
 
                g_set_error_literal (error,
357
 
                                     GDK_PIXBUF_ERROR,
358
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
359
 
                                     _("Invalid header in icon"));
360
 
                return;
361
 
        }
362
 
 
363
 
        if (State->HeaderSize>State->BytesInHeaderBuf) {
364
 
                guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
365
 
                if (!tmp) {
366
 
                        g_set_error_literal (error,
367
 
                                             GDK_PIXBUF_ERROR,
368
 
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
369
 
                                             _("Not enough memory to load icon"));
370
 
                        return;
371
 
                }
372
 
                State->HeaderBuf = tmp;
373
 
                State->BytesInHeaderBuf = State->HeaderSize;
374
 
        }
375
 
        if (Bytes < State->HeaderSize)
376
 
                return;
377
 
 
378
 
        if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
379
 
            || (BIH[19] != 0)) {
380
 
                /* FIXME: is this the correct message? */
381
 
                g_set_error_literal (error,
382
 
                                     GDK_PIXBUF_ERROR,
383
 
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
384
 
                                     _("Compressed icons are not supported"));
385
 
                return;
386
 
        }
387
 
 
388
 
        /* Negative heights mean top-down pixel-order */
389
 
        if (State->Header.height < 0) {
390
 
                State->Header.height = -State->Header.height;
391
 
                State->Header.Negative = 1;
392
 
        }
393
 
        if (State->Header.width < 0) {
394
 
                State->Header.width = -State->Header.width;
395
 
        }
396
 
        g_assert (State->Header.width > 0);
397
 
        g_assert (State->Header.height > 0);
398
 
 
399
 
        if (State->Type == 32)
400
 
                State->LineWidth = State->Header.width * 4;
401
 
        else if (State->Type == 24)
402
 
                State->LineWidth = State->Header.width * 3;
403
 
        else if (State->Type == 16)
404
 
                State->LineWidth = State->Header.width * 2;
405
 
        else if (State->Type == 8)
406
 
                State->LineWidth = State->Header.width * 1;
407
 
        else if (State->Type == 4)
408
 
                State->LineWidth = (State->Header.width+1)/2;
409
 
        else if (State->Type == 1) {
410
 
                State->LineWidth = State->Header.width / 8;
411
 
                if ((State->Header.width & 7) != 0)
412
 
                        State->LineWidth++;
413
 
        } else {
414
 
          g_set_error_literal (error,
415
 
                               GDK_PIXBUF_ERROR,
416
 
                               GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
417
 
                               _("Unsupported icon type"));
418
 
          return;
419
 
        }
420
 
 
421
 
        /* Pad to a 32 bit boundary */
422
 
        if (((State->LineWidth % 4) > 0))
423
 
                State->LineWidth = (State->LineWidth / 4) * 4 + 4;
424
 
 
425
 
 
426
 
        if (State->LineBuf == NULL) {
427
 
                State->LineBuf = g_try_malloc(State->LineWidth);
428
 
                if (!State->LineBuf) {
429
 
                        g_set_error_literal (error,
430
 
                                             GDK_PIXBUF_ERROR,
431
 
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
432
 
                                             _("Not enough memory to load icon"));
433
 
                        return;
434
 
                }
435
 
        }
436
 
 
437
 
        g_assert(State->LineBuf != NULL);
438
 
 
439
 
 
440
 
        if (State->pixbuf == NULL) {
441
 
#if 1
442
 
                if (State->size_func) {
443
 
                        gint width = State->Header.width;
444
 
                        gint height = State->Header.height;
445
 
 
446
 
                        (*State->size_func) (&width, &height, State->user_data);
447
 
                        if (width == 0 || height == 0) {
448
 
                                State->LineWidth = 0;
449
 
                                return;
450
 
                        }
451
 
                }
452
 
#endif
453
 
 
454
 
                State->pixbuf =
455
 
                    gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
456
 
                                   State->Header.width,
457
 
                                   State->Header.height);
458
 
                if (!State->pixbuf) {
459
 
                        g_set_error_literal (error,
460
 
                                             GDK_PIXBUF_ERROR,
461
 
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
462
 
                                             _("Not enough memory to load icon"));
463
 
                        return;
464
 
                }
465
 
                if (State->cursor) {
466
 
                        gchar hot[10];
467
 
                        g_snprintf (hot, 10, "%d", State->x_hot);
468
 
                        gdk_pixbuf_set_option (State->pixbuf, "x_hot", hot);
469
 
                        g_snprintf (hot, 10, "%d", State->y_hot);
470
 
                        gdk_pixbuf_set_option (State->pixbuf, "y_hot", hot);
471
 
                }
472
 
 
473
 
                if (State->prepared_func != NULL)
474
 
                        /* Notify the client that we are ready to go */
475
 
                        (*State->prepared_func) (State->pixbuf,
476
 
                                                 NULL,
477
 
                                                 State->user_data);
478
 
 
479
 
        }
480
 
 
481
 
}
482
 
 
483
 
/* 
484
 
 * func - called when we have pixmap created (but no image data)
485
 
 * user_data - passed as arg 1 to func
486
 
 * return context (opaque to user)
487
 
 */
488
 
 
489
 
static gpointer
490
 
gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
491
 
                                 GdkPixbufModulePreparedFunc prepared_func,
492
 
                                 GdkPixbufModuleUpdatedFunc updated_func,
493
 
                                 gpointer user_data,
494
 
                                 GError **error)
495
 
{
496
 
        struct ico_progressive_state *context;
497
 
 
498
 
        context = g_new0(struct ico_progressive_state, 1);
499
 
        context->size_func = size_func;
500
 
        context->prepared_func = prepared_func;
501
 
        context->updated_func = updated_func;
502
 
        context->user_data = user_data;
503
 
 
504
 
        context->HeaderSize = 54;
505
 
        context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
506
 
        if (!context->HeaderBuf) {
507
 
                g_free (context);
508
 
                g_set_error_literal (error,
509
 
                                     GDK_PIXBUF_ERROR,
510
 
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
511
 
                                     _("Not enough memory to load ICO file"));
512
 
                return NULL;
513
 
        }
514
 
        /* 4*256 for the colormap */
515
 
        context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
516
 
        context->HeaderDone = 0;
517
 
 
518
 
        context->LineWidth = 0;
519
 
        context->LineBuf = NULL;
520
 
        context->LineDone = 0;
521
 
        context->Lines = 0;
522
 
 
523
 
        context->Type = 0;
524
 
 
525
 
        memset(&context->Header, 0, sizeof(struct headerpair));
526
 
 
527
 
 
528
 
        context->pixbuf = NULL;
529
 
 
530
 
 
531
 
        return (gpointer) context;
532
 
}
533
 
 
534
 
/*
535
 
 * context - returned from image_begin_load
536
 
 *
537
 
 * free context, unref gdk_pixbuf
538
 
 */
539
 
static gboolean 
540
 
gdk_pixbuf__ico_image_stop_load(gpointer data,
541
 
                                GError **error)
542
 
{
543
 
        struct ico_progressive_state *context =
544
 
            (struct ico_progressive_state *) data;
545
 
 
546
 
        /* FIXME this thing needs to report errors if
547
 
         * we have unused image data
548
 
         */
549
 
 
550
 
        g_return_val_if_fail(context != NULL, TRUE);
551
 
 
552
 
        context_free (context);
553
 
        return TRUE;
554
 
}
555
 
 
556
 
static void
557
 
OneLine32 (struct ico_progressive_state *context)
558
 
{
559
 
        gint X;
560
 
        guchar *Pixels;
561
 
 
562
 
        X = 0;
563
 
        if (context->Header.Negative == 0)
564
 
                Pixels = (context->pixbuf->pixels +
565
 
                          context->pixbuf->rowstride *
566
 
                          (context->Header.height - context->Lines - 1));
567
 
        else
568
 
                Pixels = (context->pixbuf->pixels +
569
 
                          context->pixbuf->rowstride *
570
 
                          context->Lines);
571
 
        while (X < context->Header.width) {
572
 
                Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
573
 
                Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
574
 
                Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
575
 
                Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
576
 
                X++;
577
 
        }
578
 
}
579
 
 
580
 
static void OneLine24(struct ico_progressive_state *context)
581
 
{
582
 
        gint X;
583
 
        guchar *Pixels;
584
 
 
585
 
        X = 0;
586
 
        if (context->Header.Negative == 0)
587
 
                Pixels = (context->pixbuf->pixels +
588
 
                          context->pixbuf->rowstride *
589
 
                          (context->Header.height - context->Lines - 1));
590
 
        else
591
 
                Pixels = (context->pixbuf->pixels +
592
 
                          context->pixbuf->rowstride *
593
 
                          context->Lines);
594
 
        while (X < context->Header.width) {
595
 
                Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
596
 
                Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
597
 
                Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
598
 
                X++;
599
 
        }
600
 
 
601
 
}
602
 
 
603
 
static void
604
 
OneLine16 (struct ico_progressive_state *context)
605
 
{
606
 
        int i;
607
 
        guchar *pixels;
608
 
        guchar *src;
609
 
 
610
 
        if (context->Header.Negative == 0)
611
 
                pixels = (context->pixbuf->pixels +
612
 
                          context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
613
 
        else
614
 
                pixels = (context->pixbuf->pixels +
615
 
                          context->pixbuf->rowstride * context->Lines);
616
 
 
617
 
        src = context->LineBuf;
618
 
 
619
 
        for (i = 0; i < context->Header.width; i++) {
620
 
                int v, r, g, b;
621
 
 
622
 
                v = (int) src[0] | ((int) src[1] << 8);
623
 
                src += 2;
624
 
 
625
 
                /* Extract 5-bit RGB values */
626
 
 
627
 
                r = (v >> 10) & 0x1f;
628
 
                g = (v >> 5) & 0x1f;
629
 
                b = v & 0x1f;
630
 
 
631
 
                /* Fill the rightmost bits to form 8-bit values */
632
 
 
633
 
                *pixels++ = (r << 3) | (r >> 2);
634
 
                *pixels++ = (g << 3) | (g >> 2);
635
 
                *pixels++ = (b << 3) | (b >> 2);
636
 
                pixels++; /* skip alpha channel */
637
 
        }
638
 
}
639
 
 
640
 
 
641
 
static void OneLine8(struct ico_progressive_state *context)
642
 
{
643
 
        gint X;
644
 
        guchar *Pixels;
645
 
 
646
 
        X = 0;
647
 
        if (context->Header.Negative == 0)
648
 
                Pixels = (context->pixbuf->pixels +
649
 
                          context->pixbuf->rowstride *
650
 
                          (context->Header.height - context->Lines - 1));
651
 
        else
652
 
                Pixels = (context->pixbuf->pixels +
653
 
                          context->pixbuf->rowstride *
654
 
                          context->Lines);
655
 
        while (X < context->Header.width) {
656
 
                /* The joys of having a BGR byteorder */
657
 
                Pixels[X * 4 + 0] =
658
 
                    context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
659
 
                Pixels[X * 4 + 1] =
660
 
                    context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
661
 
                Pixels[X * 4 + 2] =
662
 
                    context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
663
 
                X++;
664
 
        }
665
 
}
666
 
static void OneLine4(struct ico_progressive_state *context)
667
 
{
668
 
        gint X;
669
 
        guchar *Pixels;
670
 
 
671
 
        X = 0;
672
 
        if (context->Header.Negative == 0)
673
 
                Pixels = (context->pixbuf->pixels +
674
 
                          context->pixbuf->rowstride *
675
 
                          (context->Header.height - context->Lines - 1));
676
 
        else
677
 
                Pixels = (context->pixbuf->pixels +
678
 
                          context->pixbuf->rowstride *
679
 
                          context->Lines);
680
 
        
681
 
        while (X < context->Header.width) {
682
 
                guchar Pix;
683
 
                
684
 
                Pix = context->LineBuf[X/2];
685
 
 
686
 
                Pixels[X * 4 + 0] =
687
 
                    context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
688
 
                Pixels[X * 4 + 1] =
689
 
                    context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
690
 
                Pixels[X * 4 + 2] =
691
 
                    context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
692
 
                X++;
693
 
                if (X<context->Header.width) { 
694
 
                        /* Handle the other 4 bit pixel only when there is one */
695
 
                        Pixels[X * 4 + 0] =
696
 
                            context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
697
 
                        Pixels[X * 4 + 1] =
698
 
                            context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
699
 
                        Pixels[X * 4 + 2] =
700
 
                            context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
701
 
                        X++;
702
 
                }
703
 
        }
704
 
        
705
 
}
706
 
 
707
 
static void OneLine1(struct ico_progressive_state *context)
708
 
{
709
 
        gint X;
710
 
        guchar *Pixels;
711
 
 
712
 
        X = 0;
713
 
        if (context->Header.Negative == 0)
714
 
                Pixels = (context->pixbuf->pixels +
715
 
                          context->pixbuf->rowstride *
716
 
                          (context->Header.height - context->Lines - 1));
717
 
        else
718
 
                Pixels = (context->pixbuf->pixels +
719
 
                          context->pixbuf->rowstride *
720
 
                          context->Lines);
721
 
        while (X < context->Header.width) {
722
 
                int Bit;
723
 
 
724
 
                Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
725
 
                Bit = Bit & 1;
726
 
                /* The joys of having a BGR byteorder */
727
 
                Pixels[X * 4 + 0] = Bit*255;
728
 
                Pixels[X * 4 + 1] = Bit*255;
729
 
                Pixels[X * 4 + 2] = Bit*255;
730
 
                X++;
731
 
        }
732
 
}
733
 
 
734
 
static void OneLineTransp(struct ico_progressive_state *context)
735
 
{
736
 
        gint X;
737
 
        guchar *Pixels;
738
 
 
739
 
        /* Ignore the XOR mask for XP style 32-bpp icons with alpha */ 
740
 
        if (context->Header.depth == 32)
741
 
                return;
742
 
 
743
 
        X = 0;
744
 
        if (context->Header.Negative == 0)
745
 
                Pixels = (context->pixbuf->pixels +
746
 
                          context->pixbuf->rowstride *
747
 
                          (2*context->Header.height - context->Lines - 1));
748
 
        else
749
 
                Pixels = (context->pixbuf->pixels +
750
 
                          context->pixbuf->rowstride *
751
 
                          (context->Lines-context->Header.height));
752
 
        while (X < context->Header.width) {
753
 
                int Bit;
754
 
 
755
 
                Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
756
 
                Bit = Bit & 1;
757
 
                /* The joys of having a BGR byteorder */
758
 
                Pixels[X * 4 + 3] = 255-Bit*255;
759
 
#if 0
760
 
                if (Bit){
761
 
                  Pixels[X*4+0] = 255;
762
 
                  Pixels[X*4+1] = 255;
763
 
                } else {
764
 
                  Pixels[X*4+0] = 0;
765
 
                  Pixels[X*4+1] = 0;
766
 
                }
767
 
#endif          
768
 
                X++;
769
 
        }
770
 
}
771
 
 
772
 
 
773
 
static void OneLine(struct ico_progressive_state *context)
774
 
{
775
 
        context->LineDone = 0;
776
 
        
777
 
        if (context->Lines >= context->Header.height*2) {
778
 
                return;
779
 
        }
780
 
                
781
 
        if (context->Lines <context->Header.height) {           
782
 
                if (context->Type == 32)
783
 
                        OneLine32 (context);
784
 
                else if (context->Type == 24)
785
 
                        OneLine24(context);
786
 
                else if (context->Type == 16)
787
 
                        OneLine16 (context);
788
 
                else if (context->Type == 8)
789
 
                        OneLine8(context);
790
 
                else if (context->Type == 4)
791
 
                        OneLine4(context);
792
 
                else if (context->Type == 1)
793
 
                        OneLine1(context);
794
 
                else 
795
 
                        g_assert_not_reached ();
796
 
        } else
797
 
                OneLineTransp(context);
798
 
        
799
 
        context->Lines++;
800
 
        if (context->Lines>=context->Header.height) {
801
 
                context->Type = 1;
802
 
                context->LineWidth = context->Header.width / 8;
803
 
                if ((context->Header.width & 7) != 0)
804
 
                        context->LineWidth++;
805
 
                /* Pad to a 32 bit boundary */
806
 
                if (((context->LineWidth % 4) > 0))
807
 
                        context->LineWidth = (context->LineWidth / 4) * 4 + 4;
808
 
                        
809
 
        }
810
 
          
811
 
 
812
 
        if (context->updated_func != NULL) {
813
 
                (*context->updated_func) (context->pixbuf,
814
 
                                          0,
815
 
                                          context->Lines % context->Header.height,
816
 
                                          context->Header.width,
817
 
                                          1,
818
 
                                          context->user_data);
819
 
 
820
 
        }
821
 
}
822
 
 
823
 
/*
824
 
 * context - from image_begin_load
825
 
 * buf - new image data
826
 
 * size - length of new image data
827
 
 *
828
 
 * append image data onto inrecrementally built output image
829
 
 */
830
 
static gboolean
831
 
gdk_pixbuf__ico_image_load_increment(gpointer data,
832
 
                                     const guchar * buf,
833
 
                                     guint size,
834
 
                                     GError **error)
835
 
{
836
 
        struct ico_progressive_state *context =
837
 
            (struct ico_progressive_state *) data;
838
 
 
839
 
        gint BytesToCopy;
840
 
 
841
 
        while (size > 0) {
842
 
                g_assert(context->LineDone >= 0);
843
 
                if (context->HeaderDone < context->HeaderSize) {        /* We still 
844
 
                                                                           have headerbytes to do */
845
 
                        BytesToCopy =
846
 
                            context->HeaderSize - context->HeaderDone;
847
 
                        if (BytesToCopy > size)
848
 
                                BytesToCopy = size;
849
 
 
850
 
                        memmove(context->HeaderBuf + context->HeaderDone,
851
 
                               buf, BytesToCopy);
852
 
 
853
 
                        size -= BytesToCopy;
854
 
                        buf += BytesToCopy;
855
 
                        context->HeaderDone += BytesToCopy;
856
 
                } 
857
 
                else {
858
 
                        BytesToCopy =
859
 
                            context->LineWidth - context->LineDone;
860
 
                        if (BytesToCopy > size)
861
 
                                BytesToCopy = size;
862
 
 
863
 
                        if (BytesToCopy > 0) {
864
 
                                memmove(context->LineBuf +
865
 
                                       context->LineDone, buf,
866
 
                                       BytesToCopy);
867
 
 
868
 
                                size -= BytesToCopy;
869
 
                                buf += BytesToCopy;
870
 
                                context->LineDone += BytesToCopy;
871
 
                        }
872
 
                        if ((context->LineDone >= context->LineWidth) &&
873
 
                            (context->LineWidth > 0))
874
 
                                OneLine(context);
875
 
 
876
 
 
877
 
                }
878
 
 
879
 
                if (context->HeaderDone >= 6 && context->pixbuf == NULL) {
880
 
                        GError *decode_err = NULL;
881
 
                        DecodeHeader(context->HeaderBuf,
882
 
                                     context->HeaderDone, context, &decode_err);
883
 
                        if (context->LineBuf != NULL && context->LineWidth == 0)
884
 
                                return TRUE;
885
 
 
886
 
                        if (decode_err) {
887
 
                                g_propagate_error (error, decode_err);
888
 
                                return FALSE;
889
 
                        }
890
 
                }
891
 
        }
892
 
 
893
 
        return TRUE;
894
 
}
895
 
 
896
 
/* saving ICOs */ 
897
 
 
898
 
static gint
899
 
write8 (FILE     *f,
900
 
        guint8   *data,
901
 
        gint      count)
902
 
{
903
 
  gint bytes;
904
 
  gint written;
905
 
 
906
 
  written = 0;
907
 
  while (count > 0)
908
 
    {
909
 
      bytes = fwrite ((char*) data, sizeof (char), count, f);
910
 
      if (bytes <= 0)
911
 
        break;
912
 
      count -= bytes;
913
 
      data += bytes;
914
 
      written += bytes;
915
 
    }
916
 
 
917
 
  return written;
918
 
}
919
 
 
920
 
static gint
921
 
write16 (FILE     *f,
922
 
         guint16  *data,
923
 
         gint      count)
924
 
{
925
 
  gint i;
926
 
 
927
 
  for (i = 0; i < count; i++)
928
 
          data[i] = GUINT16_TO_LE (data[i]);
929
 
 
930
 
  return write8 (f, (guint8*) data, count * 2);
931
 
}
932
 
 
933
 
static gint
934
 
write32 (FILE     *f,
935
 
         guint32  *data,
936
 
         gint      count)
937
 
{
938
 
  gint i;
939
 
 
940
 
  for (i = 0; i < count; i++)
941
 
          data[i] = GUINT32_TO_LE (data[i]);
942
 
  
943
 
  return write8 (f, (guint8*) data, count * 4);
944
 
}
945
 
 
946
 
typedef struct _IconEntry IconEntry;
947
 
struct _IconEntry {
948
 
        gint width;
949
 
        gint height;
950
 
        gint depth;
951
 
        gint hot_x;
952
 
        gint hot_y;
953
 
 
954
 
        guint8 n_colors;
955
 
        guint32 *colors;
956
 
        guint xor_rowstride;
957
 
        guint8 *xor;
958
 
        guint and_rowstride;
959
 
        guint8 *and;
960
 
};
961
 
 
962
 
static gboolean
963
 
fill_entry (IconEntry *icon, 
964
 
            GdkPixbuf *pixbuf, 
965
 
            gint       hot_x, 
966
 
            gint       hot_y, 
967
 
            GError   **error) 
968
 
 {
969
 
        guchar *p, *pixels, *and, *xor;
970
 
        gint n_channels, v, x, y;
971
 
 
972
 
        if (icon->width > 255 || icon->height > 255) {
973
 
                g_set_error_literal (error,
974
 
                                     GDK_PIXBUF_ERROR,
975
 
                                     GDK_PIXBUF_ERROR_BAD_OPTION,
976
 
                                     _("Image too large to be saved as ICO"));
977
 
                return FALSE;
978
 
        } 
979
 
        
980
 
        if (hot_x > -1 && hot_y > -1) {
981
 
                icon->hot_x = hot_x;
982
 
                icon->hot_y = hot_y;
983
 
                if (icon->hot_x >= icon->width || icon->hot_y >= icon->height) {
984
 
                        g_set_error_literal (error,
985
 
                                             GDK_PIXBUF_ERROR,
986
 
                                             GDK_PIXBUF_ERROR_BAD_OPTION,
987
 
                                             _("Cursor hotspot outside image"));
988
 
                        return FALSE;
989
 
                }
990
 
        }
991
 
        else {
992
 
                icon->hot_x = -1;
993
 
                icon->hot_y = -1;
994
 
        }
995
 
        
996
 
        switch (icon->depth) {
997
 
        case 32:
998
 
                icon->xor_rowstride = icon->width * 4;
999
 
                break;
1000
 
        case 24:
1001
 
                icon->xor_rowstride = icon->width * 3;
1002
 
                break;
1003
 
        case 16:
1004
 
                icon->xor_rowstride = icon->width * 2;
1005
 
                break;
1006
 
        default:
1007
 
                g_set_error (error,
1008
 
                             GDK_PIXBUF_ERROR,
1009
 
                             GDK_PIXBUF_ERROR_BAD_OPTION,
1010
 
                             _("Unsupported depth for ICO file: %d"), icon->depth);
1011
 
                return FALSE;
1012
 
        }
1013
 
 
1014
 
        if ((icon->xor_rowstride % 4) != 0)
1015
 
                icon->xor_rowstride = 4 * ((icon->xor_rowstride / 4) + 1);
1016
 
        icon->xor = g_new0 (guchar, icon->xor_rowstride * icon->height);
1017
 
 
1018
 
        icon->and_rowstride = (icon->width + 7) / 8;
1019
 
        if ((icon->and_rowstride % 4) != 0)
1020
 
                icon->and_rowstride = 4 * ((icon->and_rowstride / 4) + 1);
1021
 
        icon->and = g_new0 (guchar, icon->and_rowstride * icon->height);
1022
 
 
1023
 
        pixels = gdk_pixbuf_get_pixels (pixbuf);
1024
 
        n_channels = gdk_pixbuf_get_n_channels (pixbuf);
1025
 
        for (y = 0; y < icon->height; y++) {
1026
 
                p = pixels + gdk_pixbuf_get_rowstride (pixbuf) * (icon->height - 1 - y);
1027
 
                and = icon->and + icon->and_rowstride * y;
1028
 
                xor = icon->xor + icon->xor_rowstride * y;
1029
 
                for (x = 0; x < icon->width; x++) {
1030
 
                        switch (icon->depth) {
1031
 
                        case 32:
1032
 
                                xor[0] = p[2];
1033
 
                                xor[1] = p[1];
1034
 
                                xor[2] = p[0];
1035
 
                                xor[3] = 0xff;
1036
 
                                if (n_channels == 4) {
1037
 
                                        xor[3] = p[3];
1038
 
                                        if (p[3] < 0x80)
1039
 
                                                *and |= 1 << (7 - x % 8);
1040
 
                                }
1041
 
                                xor += 4;
1042
 
                                break;
1043
 
                        case 24:
1044
 
                                xor[0] = p[2];
1045
 
                                xor[1] = p[1];
1046
 
                                xor[2] = p[0];
1047
 
                                if (n_channels == 4 && p[3] < 0x80)
1048
 
                                        *and |= 1 << (7 - x % 8);
1049
 
                                xor += 3;
1050
 
                                break;
1051
 
                        case 16:
1052
 
                                v = ((p[0] >> 3) << 10) | ((p[1] >> 3) << 5) | (p[2] >> 3);
1053
 
                                xor[0] = v & 0xff;
1054
 
                                xor[1] = v >> 8;
1055
 
                                if (n_channels == 4 && p[3] < 0x80)
1056
 
                                        *and |= 1 << (7 - x % 8);
1057
 
                                xor += 2;
1058
 
                                break;
1059
 
                        }
1060
 
                        
1061
 
                        p += n_channels;
1062
 
                        if (x % 8 == 7) 
1063
 
                                and++;
1064
 
                }
1065
 
        }
1066
 
 
1067
 
        return TRUE;
1068
 
}
1069
 
 
1070
 
static void
1071
 
free_entry (IconEntry *icon)
1072
 
{
1073
 
        g_free (icon->colors);
1074
 
        g_free (icon->and);
1075
 
        g_free (icon->xor);
1076
 
        g_free (icon);
1077
 
}
1078
 
 
1079
 
static void
1080
 
write_icon (FILE *f, GSList *entries)
1081
 
{
1082
 
        IconEntry *icon;
1083
 
        GSList *entry;
1084
 
        guint8 bytes[4];
1085
 
        guint16 words[4];
1086
 
        guint32 dwords[6];
1087
 
        gint type;
1088
 
        gint n_entries;
1089
 
        gint offset;
1090
 
        gint size;
1091
 
 
1092
 
        if (((IconEntry *)entries->data)->hot_x > -1)
1093
 
                type = 2;
1094
 
        else 
1095
 
                type = 1;
1096
 
        n_entries = g_slist_length (entries);
1097
 
 
1098
 
        /* header */
1099
 
        words[0] = 0;
1100
 
        words[1] = type;
1101
 
        words[2] = n_entries;
1102
 
        write16 (f, words, 3);
1103
 
        
1104
 
        offset = 6 + 16 * n_entries;
1105
 
 
1106
 
        for (entry = entries; entry; entry = entry->next) {
1107
 
                icon = (IconEntry *)entry->data;
1108
 
                size = 40 + icon->height * (icon->and_rowstride + icon->xor_rowstride);
1109
 
                
1110
 
                /* directory entry */
1111
 
                bytes[0] = icon->width;
1112
 
                bytes[1] = icon->height;
1113
 
                bytes[2] = icon->n_colors;
1114
 
                bytes[3] = 0;
1115
 
                write8 (f, bytes, 4);
1116
 
                if (type == 1) {
1117
 
                        words[0] = 1;
1118
 
                        words[1] = icon->depth;
1119
 
                }
1120
 
                else {
1121
 
                        words[0] = icon->hot_x;
1122
 
                        words[1] = icon->hot_y;
1123
 
                }
1124
 
                write16 (f, words, 2);
1125
 
                dwords[0] = size;
1126
 
                dwords[1] = offset;
1127
 
                write32 (f, dwords, 2);
1128
 
 
1129
 
                offset += size;
1130
 
        }
1131
 
 
1132
 
        for (entry = entries; entry; entry = entry->next) {
1133
 
                icon = (IconEntry *)entry->data;
1134
 
 
1135
 
                /* bitmap header */
1136
 
                dwords[0] = 40;
1137
 
                dwords[1] = icon->width;
1138
 
                dwords[2] = icon->height * 2;
1139
 
                write32 (f, dwords, 3);
1140
 
                words[0] = 1;
1141
 
                words[1] = icon->depth;
1142
 
                write16 (f, words, 2);
1143
 
                dwords[0] = 0;
1144
 
                dwords[1] = 0;
1145
 
                dwords[2] = 0;
1146
 
                dwords[3] = 0;
1147
 
                dwords[4] = 0;
1148
 
                dwords[5] = 0;
1149
 
                write32 (f, dwords, 6);
1150
 
 
1151
 
                /* image data */
1152
 
                write8 (f, icon->xor, icon->xor_rowstride * icon->height);
1153
 
                write8 (f, icon->and, icon->and_rowstride * icon->height);
1154
 
        }
1155
 
}
1156
 
 
1157
 
static gboolean
1158
 
gdk_pixbuf__ico_image_save (FILE          *f, 
1159
 
                            GdkPixbuf     *pixbuf, 
1160
 
                            gchar        **keys,
1161
 
                            gchar        **values,
1162
 
                            GError       **error)
1163
 
{
1164
 
        gint hot_x, hot_y;
1165
 
        IconEntry *icon;
1166
 
        GSList *entries = NULL;
1167
 
 
1168
 
        /* support only single-image ICOs for now */
1169
 
        icon = g_new0 (IconEntry, 1);
1170
 
        icon->width = gdk_pixbuf_get_width (pixbuf);
1171
 
        icon->height = gdk_pixbuf_get_height (pixbuf);
1172
 
        icon->depth = gdk_pixbuf_get_has_alpha (pixbuf) ? 32 : 24;
1173
 
        hot_x = -1;
1174
 
        hot_y = -1;
1175
 
        
1176
 
        /* parse options */
1177
 
        if (keys && *keys) {
1178
 
                gchar **kiter;
1179
 
                gchar **viter;
1180
 
                
1181
 
                for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) {
1182
 
                        char *endptr;
1183
 
                        if (strcmp (*kiter, "depth") == 0) {
1184
 
                                sscanf (*viter, "%d", &icon->depth);
1185
 
                        }
1186
 
                        else if (strcmp (*kiter, "x_hot") == 0) {
1187
 
                                hot_x = strtol (*viter, &endptr, 10);
1188
 
                        }
1189
 
                        else if (strcmp (*kiter, "y_hot") == 0) {
1190
 
                                hot_y = strtol (*viter, &endptr, 10);
1191
 
                        }
1192
 
 
1193
 
                }
1194
 
        }
1195
 
 
1196
 
        if (!fill_entry (icon, pixbuf, hot_x, hot_y, error)) {
1197
 
                free_entry (icon);
1198
 
                return FALSE;
1199
 
        }
1200
 
 
1201
 
        entries = g_slist_append (entries, icon); 
1202
 
        write_icon (f, entries);
1203
 
 
1204
 
        g_slist_foreach (entries, (GFunc)free_entry, NULL);
1205
 
        g_slist_free (entries);
1206
 
 
1207
 
        return TRUE;
1208
 
}
1209
 
 
1210
 
#ifndef INCLUDE_ico
1211
 
#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1212
 
#else
1213
 
#define MODULE_ENTRY(function) void _gdk_pixbuf__ico_ ## function
1214
 
#endif
1215
 
 
1216
 
MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1217
 
{
1218
 
        module->begin_load = gdk_pixbuf__ico_image_begin_load;
1219
 
        module->stop_load = gdk_pixbuf__ico_image_stop_load;
1220
 
        module->load_increment = gdk_pixbuf__ico_image_load_increment;
1221
 
        module->save = gdk_pixbuf__ico_image_save;
1222
 
}
1223
 
 
1224
 
MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1225
 
{
1226
 
        static GdkPixbufModulePattern signature[] = {
1227
 
                { "  \x1   ", "zz znz", 100 }, 
1228
 
                { "  \x2   ", "zz znz", 100 },
1229
 
                { NULL, NULL, 0 }
1230
 
        };
1231
 
        static gchar * mime_types[] = {
1232
 
                "image/x-icon",
1233
 
                "image/x-ico",
1234
 
                "image/x-win-bitmap",
1235
 
                NULL
1236
 
        };
1237
 
        static gchar * extensions[] = {
1238
 
                "ico",
1239
 
                "cur",
1240
 
                NULL
1241
 
        };
1242
 
 
1243
 
        info->name = "ico";
1244
 
        info->signature = signature;
1245
 
        info->description = N_("The ICO image format");
1246
 
        info->mime_types = mime_types;
1247
 
        info->extensions = extensions;
1248
 
        info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1249
 
        info->license = "LGPL";
1250
 
}
1251
 
 
1252
 
 
1253
 
 
1254