]> Pileus Git - ~andy/gtk/blob - modules/engines/ms-windows/msw_style.c
Revert most of previous patch, as it didn't work as expected; Some work
[~andy/gtk] / modules / engines / ms-windows / msw_style.c
1 /* MS-Windows Engine (aka GTK-Wimp)
2  *
3  * Copyright (C) 2003, 2004 Raymond Penners <raymond@dotsphinx.com>
4  * Copyright (C) 2006 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
5  * Includes code adapted from redmond95 by Owen Taylor, and
6  * gtk-nativewin by Evan Martin
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /*
25  * Useful resources:
26  *
27  *  http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsNativeThemeWin.cpp
28  *  http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsLookAndFeel.cpp
29  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/functions/drawthemebackground.asp
30  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_4b3g.asp
31  */
32
33 #include "msw_style.h"
34 #include "xp_theme.h"
35
36 #include <windows.h>
37 #include <math.h>
38 #include <string.h>
39 #include <stdio.h>
40
41 #include "gtk/gtk.h"
42 #include "gtk/gtk.h"
43
44 #ifdef BUILDING_STANDALONE
45 #include "gdk/gdkwin32.h"
46 #else
47 #include "gdk/win32/gdkwin32.h"
48 #endif
49
50 static HDC get_window_dc (GtkStyle *style, GdkWindow *window,
51                           GtkStateType state_type, gint x, gint y, gint width,
52                           gint height, RECT *rect);
53 static void release_window_dc (GtkStyle *style, GdkWindow *window,
54                                GtkStateType state_type);
55
56
57 /* Default values, not normally used
58  */
59 static const GtkRequisition default_option_indicator_size = { 9, 8 };
60 static const GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
61
62 static GtkStyleClass *parent_class;
63 static HBRUSH g_dither_brush = NULL;
64
65 static HPEN g_light_pen = NULL;
66 static HPEN g_dark_pen = NULL;
67
68 typedef enum
69 {
70   CHECK_AA,
71   CHECK_BASE,
72   CHECK_BLACK,
73   CHECK_DARK,
74   CHECK_LIGHT,
75   CHECK_MID,
76   CHECK_TEXT,
77   CHECK_INCONSISTENT,
78   RADIO_BASE,
79   RADIO_BLACK,
80   RADIO_DARK,
81   RADIO_LIGHT,
82   RADIO_MID,
83   RADIO_TEXT
84 } Part;
85
86 #define PART_SIZE 13
87
88 static const guint8 check_aa_bits[] = {
89   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90   0x00, 0x00, 0x00,
91   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
92 };
93 static const guint8 check_base_bits[] = {
94   0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07,
95   0xfc, 0x07, 0xfc,
96   0x07, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00
97 };
98 static const guint8 check_black_bits[] = {
99   0x00, 0x00, 0xfe, 0x0f, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
100   0x02, 0x00, 0x02,
101   0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00
102 };
103 static const guint8 check_dark_bits[] = {
104   0xff, 0x1f, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
105   0x01, 0x00, 0x01,
106   0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00
107 };
108 static const guint8 check_light_bits[] = {
109   0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
110   0x00, 0x10, 0x00,
111   0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0xfe, 0x1f
112 };
113 static const guint8 check_mid_bits[] = {
114   0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
115   0x00, 0x08, 0x00,
116   0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0xfc, 0x0f, 0x00, 0x00
117 };
118 static const guint8 check_text_bits[] = {
119   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x88, 0x03,
120   0xd8, 0x01, 0xf8,
121   0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
122 };
123 static const char check_inconsistent_bits[] = {
124   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125     0xf0, 0x03, 0xf0,
126   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
127 };
128 static const guint8 radio_base_bits[] = {
129   0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07,
130   0xfc, 0x07, 0xfc,
131   0x07, 0xfc, 0x07, 0xf8, 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00
132 };
133 static const guint8 radio_black_bits[] = {
134   0x00, 0x00, 0xf0, 0x01, 0x0c, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
135   0x02, 0x00, 0x02,
136   0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
137 };
138 static const guint8 radio_dark_bits[] = {
139   0xf0, 0x01, 0x0c, 0x06, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
140   0x01, 0x00, 0x01,
141   0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
142 };
143 static const guint8 radio_light_bits[] = {
144   0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x10,
145   0x00, 0x10, 0x00,
146   0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x08, 0x0c, 0x06, 0xf0, 0x01
147 };
148 static const guint8 radio_mid_bits[] = {
149   0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08,
150   0x00, 0x08, 0x00,
151   0x08, 0x00, 0x08, 0x00, 0x04, 0x0c, 0x06, 0xf0, 0x01, 0x00, 0x00
152 };
153 static const guint8 radio_text_bits[] = {
154   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf0, 0x01,
155   0xf0, 0x01, 0xf0,
156   0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
157 };
158
159 static struct
160 {
161   const guint8 *bits;
162   GdkBitmap *bmap;
163 } parts[] = {
164   { check_aa_bits, NULL           },
165   { check_base_bits, NULL         },
166   { check_black_bits, NULL        },
167   { check_dark_bits, NULL         },
168   { check_light_bits, NULL        },
169   { check_mid_bits, NULL          },
170   { check_text_bits, NULL         },
171   { check_inconsistent_bits, NULL },
172   { radio_base_bits, NULL         },
173   { radio_black_bits, NULL        },
174   { radio_dark_bits, NULL         },
175   { radio_light_bits, NULL        },
176   { radio_mid_bits, NULL          },
177   { radio_text_bits, NULL         }
178 };
179
180 static gboolean
181 get_system_font (XpThemeClass klazz, XpThemeFont type, LOGFONT *out_lf)
182 {
183 #if 0
184   /* TODO: this causes crashes later because the font name is in UCS2, and
185      the pango fns don't deal with that gracefully */
186   if (xp_theme_get_system_font (klazz, type, out_lf))
187     {
188       return TRUE;
189     }
190   else
191 #endif
192     {
193       NONCLIENTMETRICS ncm;
194
195       ncm.cbSize = sizeof (NONCLIENTMETRICS);
196
197       if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,
198                                 sizeof (NONCLIENTMETRICS), &ncm, 0))
199         {
200           if (type == XP_THEME_FONT_CAPTION)
201             *out_lf = ncm.lfCaptionFont;
202           else if (type == XP_THEME_FONT_MENU)
203             *out_lf = ncm.lfMenuFont;
204           else if (type == XP_THEME_FONT_STATUS)
205             *out_lf = ncm.lfStatusFont;
206           else
207             *out_lf = ncm.lfMessageFont;
208
209           return TRUE;
210         }
211     }
212
213   return FALSE;
214 }
215
216 /***************************** BEGIN STOLEN FROM PANGO *****************************/
217
218 /*
219         This code is stolen from Pango 1.4. It attempts to address the following problems:
220
221         http://bugzilla.gnome.org/show_bug.cgi?id=135098
222         http://sourceforge.net/tracker/index.php?func=detail&aid=895762&group_id=76416&atid=547655
223
224         As Owen suggested in bug 135098, once Pango 1.6 is released, we need to get rid of this code.
225 */
226
227 #define PING(printlist)
228
229 /* TrueType defines: */
230
231 #define MAKE_TT_TABLE_NAME(c1, c2, c3, c4) \
232    (((guint32)c4) << 24 | ((guint32)c3) << 16 | ((guint32)c2) << 8 | ((guint32)c1))
233
234 #define CMAP (MAKE_TT_TABLE_NAME('c','m','a','p'))
235 #define CMAP_HEADER_SIZE 4
236
237 #define NAME (MAKE_TT_TABLE_NAME('n','a','m','e'))
238 #define NAME_HEADER_SIZE 6
239
240 #define ENCODING_TABLE_SIZE 8
241
242 #define APPLE_UNICODE_PLATFORM_ID 0
243 #define MACINTOSH_PLATFORM_ID 1
244 #define ISO_PLATFORM_ID 2
245 #define MICROSOFT_PLATFORM_ID 3
246
247 #define SYMBOL_ENCODING_ID 0
248 #define UNICODE_ENCODING_ID 1
249 #define UCS4_ENCODING_ID 10
250
251 struct name_header
252 {
253   guint16 format_selector;
254   guint16 num_records;
255   guint16 string_storage_offset;
256 };
257
258 struct name_record
259 {
260   guint16 platform_id;
261   guint16 encoding_id;
262   guint16 language_id;
263   guint16 name_id;
264   guint16 string_length;
265   guint16 string_offset;
266 };
267
268 static gboolean
269 pango_win32_get_name_header (HDC hdc, struct name_header *header)
270 {
271   if (GetFontData (hdc, NAME, 0, header, sizeof (*header)) != sizeof (*header))
272     return FALSE;
273
274   header->num_records = GUINT16_FROM_BE (header->num_records);
275   header->string_storage_offset = GUINT16_FROM_BE (header->string_storage_offset);
276
277   return TRUE;
278 }
279
280 static gboolean
281 pango_win32_get_name_record (HDC hdc, gint i, struct name_record *record)
282 {
283   if (GetFontData (hdc, NAME, 6 + i * sizeof (*record),
284                    record, sizeof (*record)) != sizeof (*record))
285     {
286       return FALSE;
287     }
288
289   record->platform_id = GUINT16_FROM_BE (record->platform_id);
290   record->encoding_id = GUINT16_FROM_BE (record->encoding_id);
291   record->language_id = GUINT16_FROM_BE (record->language_id);
292   record->name_id = GUINT16_FROM_BE (record->name_id);
293   record->string_length = GUINT16_FROM_BE (record->string_length);
294   record->string_offset = GUINT16_FROM_BE (record->string_offset);
295
296   return TRUE;
297 }
298
299 static gchar *
300 get_family_name (LOGFONT *lfp, HDC pango_win32_hdc)
301 {
302   HFONT hfont;
303   HFONT oldhfont;
304
305   struct name_header header;
306   struct name_record record;
307
308   gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1;
309   gint name_ix;
310   gchar *codeset;
311
312   gchar *string = NULL;
313   gchar *name;
314
315   size_t i, l, nbytes;
316
317   /* If lfFaceName is ASCII, assume it is the common (English) name for the
318      font. Is this valid? Do some TrueType fonts have different names in
319      French, German, etc, and does the system return these if the locale is
320      set to use French, German, etc? */
321   l = strlen (lfp->lfFaceName);
322   for (i = 0; i < l; i++)
323     {
324       if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~')
325         {
326           break;
327         }
328     }
329
330   if (i == l)
331     return g_strdup (lfp->lfFaceName);
332
333   if ((hfont = CreateFontIndirect (lfp)) == NULL)
334     goto fail0;
335
336   if ((oldhfont = (HFONT) SelectObject (pango_win32_hdc, hfont)) == NULL)
337     goto fail1;
338
339   if (!pango_win32_get_name_header (pango_win32_hdc, &header))
340     goto fail2;
341
342   PING (("%d name records", header.num_records));
343
344   for (i = 0; i < header.num_records; i++)
345     {
346       if (!pango_win32_get_name_record (pango_win32_hdc, i, &record))
347         goto fail2;
348
349       if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0)
350         continue;
351
352       PING (("platform:%d encoding:%d language:%04x name_id:%d",
353              record.platform_id, record.encoding_id, record.language_id,
354              record.name_id));
355
356       if (record.platform_id == APPLE_UNICODE_PLATFORM_ID ||
357           record.platform_id == ISO_PLATFORM_ID)
358         {
359           unicode_ix = i;
360         }
361       else if (record.platform_id == MACINTOSH_PLATFORM_ID && record.encoding_id == 0 &&        /* Roman
362                                                                                                  */
363                record.language_id == 0) /* English */
364         {
365           mac_ix = i;
366         }
367       else if (record.platform_id == MICROSOFT_PLATFORM_ID)
368         {
369           if ((microsoft_ix == -1 ||
370                PRIMARYLANGID (record.language_id) == LANG_ENGLISH) &&
371               (record.encoding_id == SYMBOL_ENCODING_ID ||
372                record.encoding_id == UNICODE_ENCODING_ID ||
373                record.encoding_id == UCS4_ENCODING_ID))
374             {
375               microsoft_ix = i;
376             }
377         }
378     }
379
380   if (microsoft_ix >= 0)
381     name_ix = microsoft_ix;
382   else if (mac_ix >= 0)
383     name_ix = mac_ix;
384   else if (unicode_ix >= 0)
385     name_ix = unicode_ix;
386   else
387     goto fail2;
388
389   if (!pango_win32_get_name_record (pango_win32_hdc, name_ix, &record))
390     goto fail2;
391
392   string = g_malloc (record.string_length + 1);
393   if (GetFontData (pango_win32_hdc, NAME,
394                    header.string_storage_offset + record.string_offset,
395                    string, record.string_length) != record.string_length)
396     goto fail2;
397
398   string[record.string_length] = '\0';
399
400   if (name_ix == microsoft_ix)
401     {
402       if (record.encoding_id == SYMBOL_ENCODING_ID ||
403           record.encoding_id == UNICODE_ENCODING_ID)
404         {
405           codeset = "UTF-16BE";
406         }
407       else
408         {
409           codeset = "UCS-4BE";
410         }
411     }
412   else if (name_ix == mac_ix)
413     {
414       codeset = "MacRoman";
415     }
416   else                          /* name_ix == unicode_ix */
417     {
418       codeset = "UCS-4BE";
419     }
420
421
422   name = g_convert (string, record.string_length, "UTF-8", codeset, NULL,
423                     &nbytes, NULL);
424   if (name == NULL)
425     goto fail2;
426
427   g_free (string);
428
429   PING (("%s", name));
430
431   SelectObject (pango_win32_hdc, oldhfont);
432   DeleteObject (hfont);
433
434   return name;
435
436 fail2:
437   g_free (string);
438   SelectObject (pango_win32_hdc, oldhfont);
439
440 fail1:
441   DeleteObject (hfont);
442
443 fail0:
444   return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
445 }
446
447 /***************************** END STOLEN FROM PANGO *****************************/
448
449 static char *
450 sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char *buf,
451                         size_t bufsiz)
452 {
453   HDC hDC;
454   HWND hwnd;
455   LOGFONT lf;
456   int pt_size;
457   const char *weight;
458   const char *style;
459   char *font;
460
461   if (get_system_font (klazz, type, &lf))
462     {
463       switch (lf.lfWeight)
464         {
465         case FW_THIN:
466         case FW_EXTRALIGHT:
467           weight = "Ultra-Light";
468           break;
469
470         case FW_LIGHT:
471           weight = "Light";
472           break;
473
474         case FW_BOLD:
475           weight = "Bold";
476           break;
477
478         case FW_SEMIBOLD:
479           weight = "Semi-Bold";
480           break;
481
482         case FW_ULTRABOLD:
483           weight = "Ultra-Bold";
484           break;
485
486         case FW_HEAVY:
487           weight = "Heavy";
488           break;
489
490         default:
491           weight = "";
492           break;
493         }
494
495       if (lf.lfItalic)
496         style = "Italic";
497       else
498         style = "";
499
500       hwnd = GetDesktopWindow ();
501       hDC = GetDC (hwnd);
502       if (hDC)
503         {
504           pt_size = -MulDiv (lf.lfHeight, 72,
505                              GetDeviceCaps (hDC, LOGPIXELSY));
506         }
507       else
508         {
509           pt_size = 10;
510         }
511
512       font = get_family_name (&lf, hDC);
513
514       if (hDC)
515         ReleaseDC (hwnd, hDC);
516
517       if (!(font && *font))
518         return NULL;
519
520       g_snprintf (buf, bufsiz, "%s %s %s %d", font, style, weight, pt_size);
521       g_free (font);
522
523       return buf;
524     }
525
526   return NULL;
527 }
528
529 /* missing from ms's header files */
530 #ifndef SPI_GETMENUSHOWDELAY
531 #define SPI_GETMENUSHOWDELAY 106
532 #endif
533
534 /* I don't know the proper XP theme class for things like
535    HIGHLIGHTTEXT, so we'll just define it to be "BUTTON"
536    for now */
537 #define XP_THEME_CLASS_TEXT XP_THEME_CLASS_BUTTON
538
539 static void
540 setup_menu_settings (GtkSettings *settings)
541 {
542   int menu_delay;
543   gboolean win95 = FALSE;
544   OSVERSIONINFOEX osvi;
545   GObjectClass *klazz = G_OBJECT_GET_CLASS (G_OBJECT (settings));
546
547   ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX));
548   osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
549
550   if (!GetVersionEx ((OSVERSIONINFO *) & osvi))
551     win95 = TRUE;               /* assume the worst */
552
553   if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
554     {
555       if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
556         {
557           win95 = TRUE;
558         }
559     }
560
561   if (!win95)
562     {
563       if (SystemParametersInfo (SPI_GETMENUSHOWDELAY, 0, &menu_delay, 0))
564         {
565           if (klazz)
566             {
567               if (g_object_class_find_property
568                   (klazz, "gtk-menu-bar-popup-delay"))
569                 {
570                   g_object_set (settings,
571                                 "gtk-menu-bar-popup-delay", 0, NULL);
572                 }
573               if (g_object_class_find_property
574                   (klazz, "gtk-menu-popup-delay"))
575                 {
576                   g_object_set (settings,
577                                 "gtk-menu-popup-delay", menu_delay, NULL);
578                 }
579               if (g_object_class_find_property
580                   (klazz, "gtk-menu-popdown-delay"))
581                 {
582                   g_object_set (settings,
583                                 "gtk-menu-popdown-delay", menu_delay, NULL);
584                 }
585             }
586         }
587     }
588 }
589
590 void
591 msw_style_setup_system_settings (void)
592 {
593   GtkSettings *settings;
594   int cursor_blink_time;
595
596   settings = gtk_settings_get_default ();
597   if (!settings)
598     return;
599
600   cursor_blink_time = GetCaretBlinkTime ();
601   g_object_set (settings, "gtk-cursor-blink", cursor_blink_time > 0, NULL);
602
603   if (cursor_blink_time > 0)
604     {
605       g_object_set (settings, "gtk-cursor-blink-time",
606                     2 * cursor_blink_time, NULL);
607     }
608
609   g_object_set (settings, "gtk-double-click-distance",
610                 GetSystemMetrics (SM_CXDOUBLECLK), NULL);
611   g_object_set (settings, "gtk-double-click-time", GetDoubleClickTime (),
612                 NULL);
613   g_object_set (settings, "gtk-dnd-drag-threshold",
614                 GetSystemMetrics (SM_CXDRAG), NULL);
615
616   setup_menu_settings (settings);
617
618   /*
619      http://developer.gnome.org/doc/API/2.0/gtk/GtkSettings.html
620      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/systemparametersinfo.asp
621      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getsystemmetrics.asp */
622 }
623
624 static void
625 setup_system_font (GtkStyle *style)
626 {
627   char buf[256], *font;         /* It's okay, lfFaceName is smaller than 32
628                                    chars */
629
630   if ((font = sys_font_to_pango_font (XP_THEME_CLASS_TEXT,
631                                       XP_THEME_FONT_MESSAGE,
632                                       buf, sizeof (buf))) != NULL)
633     {
634       if (style->font_desc)
635         {
636           pango_font_description_free (style->font_desc);
637         }
638
639       style->font_desc = pango_font_description_from_string (font);
640     }
641 }
642
643 static void
644 sys_color_to_gtk_color (XpThemeClass klazz, int id, GdkColor * pcolor)
645 {
646   DWORD color;
647
648   if (!xp_theme_get_system_color (klazz, id, &color))
649     color = GetSysColor (id);
650
651   pcolor->pixel = color;
652   pcolor->red = (GetRValue (color) << 8) | GetRValue (color);
653   pcolor->green = (GetGValue (color) << 8) | GetGValue (color);
654   pcolor->blue = (GetBValue (color) << 8) | GetBValue (color);
655 }
656
657 static int
658 get_system_metric (XpThemeClass klazz, int id)
659 {
660   int rval;
661
662   if (!xp_theme_get_system_metric (klazz, id, &rval))
663     rval = GetSystemMetrics (id);
664
665   return rval;
666 }
667
668 static void
669 setup_msw_rc_style (void)
670 {
671   char buf[1024], font_buf[256], *font_ptr;
672   char menu_bar_prelight_str[128];
673
674   GdkColor menu_color;
675   GdkColor menu_text_color;
676   GdkColor tooltip_back;
677   GdkColor tooltip_fore;
678   GdkColor btn_fore;
679   GdkColor btn_face;
680   GdkColor progress_back;
681
682   GdkColor fg_prelight;
683   GdkColor bg_prelight;
684   GdkColor base_prelight;
685   GdkColor text_prelight;
686
687   /* Prelight */
688   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
689                           &fg_prelight);
690   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT, &bg_prelight);
691   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
692                           &base_prelight);
693   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
694                           &text_prelight);
695
696   sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENUTEXT,
697                           &menu_text_color);
698   sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENU, &menu_color);
699
700   /* tooltips */
701   sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOTEXT,
702                           &tooltip_fore);
703   sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOBK,
704                           &tooltip_back);
705
706   /* text on push buttons. TODO: button shadows, backgrounds, and
707      highlights */
708   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &btn_fore);
709   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &btn_face);
710
711   /* progress bar background color */
712   sys_color_to_gtk_color (XP_THEME_CLASS_PROGRESS, COLOR_HIGHLIGHT,
713                           &progress_back);
714
715   /* Enable coloring for menus. */
716   font_ptr =
717     sys_font_to_pango_font (XP_THEME_CLASS_MENU, XP_THEME_FONT_MENU,
718                             font_buf, sizeof (font_buf));
719   g_snprintf (buf, sizeof (buf),
720               "style \"msw-menu\" = \"msw-default\"\n" "{\n"
721               "GtkMenuItem::toggle-spacing = 8\n"
722               "fg[PRELIGHT] = { %d, %d, %d }\n"
723               "bg[PRELIGHT] = { %d, %d, %d }\n"
724               "text[PRELIGHT] = { %d, %d, %d }\n"
725               "base[PRELIGHT] = { %d, %d, %d }\n"
726               "fg[NORMAL] = { %d, %d, %d }\n"
727               "bg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n"
728               "}widget_class \"*MenuItem*\" style \"msw-menu\"\n"
729               "widget_class \"*GtkMenu\" style \"msw-menu\"\n"
730               "widget_class \"*GtkMenuShell*\" style \"msw-menu\"\n",
731               fg_prelight.red, fg_prelight.green, fg_prelight.blue,
732               bg_prelight.red, bg_prelight.green, bg_prelight.blue,
733               text_prelight.red, text_prelight.green, text_prelight.blue,
734               base_prelight.red, base_prelight.green, base_prelight.blue,
735               menu_text_color.red, menu_text_color.green,
736               menu_text_color.blue, menu_color.red, menu_color.green,
737               menu_color.blue, (font_ptr ? "font_name" : "#"),
738               (font_ptr ? font_ptr : " font name should go here"));
739   gtk_rc_parse_string (buf);
740
741   if (xp_theme_is_active ())
742     {
743       *menu_bar_prelight_str = '\0';
744     }
745   else
746     {
747       g_snprintf (menu_bar_prelight_str, sizeof (menu_bar_prelight_str),
748                   "fg[PRELIGHT] = { %d, %d, %d }\n",
749                   menu_text_color.red, menu_text_color.green,
750                   menu_text_color.blue);
751     }
752
753   /* Enable coloring for menu bars. */
754   g_snprintf (buf, sizeof (buf),
755               "style \"msw-menu-bar\" = \"msw-menu\"\n"
756               "{\n"
757               "bg[NORMAL] = { %d, %d, %d }\n"
758               "%s" "GtkMenuBar::shadow-type = %d\n"
759               /*
760                  FIXME: This should be enabled once gtk+ support
761                  GtkMenuBar::prelight-item style property.
762                */
763               /* "GtkMenuBar::prelight-item = 1\n" */
764               "}widget_class \"*MenuBar*\" style \"msw-menu-bar\"\n",
765               btn_face.red, btn_face.green, btn_face.blue,
766               menu_bar_prelight_str, xp_theme_is_active ()? 0 : 2);
767   gtk_rc_parse_string (buf);
768
769   g_snprintf (buf, sizeof (buf),
770               "style \"msw-toolbar\" = \"msw-default\"\n"
771               "{\n"
772               "GtkHandleBox::shadow-type = %s\n"
773               "GtkToolbar::shadow-type = %s\n"
774               "}widget_class \"*HandleBox*\" style \"msw-toolbar\"\n",
775               "etched-in", "etched-in");
776   gtk_rc_parse_string (buf);
777
778   /* enable tooltip fonts */
779   font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,
780                                      font_buf, sizeof (font_buf));
781   g_snprintf (buf, sizeof (buf),
782               "style \"msw-tooltips-caption\" = \"msw-default\"\n"
783               "{fg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n"
784               "}widget \"gtk-tooltips.GtkLabel\" style \"msw-tooltips-caption\"\n"
785               "widget \"gtk-tooltip.GtkLabel\" style \"msw-tooltips-caption\"\n",
786               tooltip_fore.red, tooltip_fore.green, tooltip_fore.blue,
787               (font_ptr ? "font_name" : "#"),
788               (font_ptr ? font_ptr : " font name should go here"));
789   gtk_rc_parse_string (buf);
790
791   g_snprintf (buf, sizeof (buf),
792               "style \"msw-tooltips\" = \"msw-default\"\n"
793               "{bg[NORMAL] = { %d, %d, %d }\n"
794               "}widget \"gtk-tooltips*\" style \"msw-tooltips\"\n"
795               "widget \"gtk-tooltip*\" style \"msw-tooltips\"\n",
796               tooltip_back.red, tooltip_back.green, tooltip_back.blue);
797   gtk_rc_parse_string (buf);
798
799   /* enable font theming for status bars */
800   font_ptr = sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,
801                                      font_buf, sizeof (font_buf));
802   g_snprintf (buf, sizeof (buf),
803               "style \"msw-status\" = \"msw-default\"\n" "{%s = \"%s\"\n"
804               "bg[NORMAL] = { %d, %d, %d }\n"
805               "}widget_class \"*Status*\" style \"msw-status\"\n",
806               (font_ptr ? "font_name" : "#"),
807               (font_ptr ? font_ptr : " font name should go here"),
808               btn_face.red, btn_face.green, btn_face.blue);
809   gtk_rc_parse_string (buf);
810
811   /* enable coloring for text on buttons TODO: use GetThemeMetric for the
812      border and outside border */
813   g_snprintf (buf, sizeof (buf),
814               "style \"msw-button\" = \"msw-default\"\n"
815               "{\n"
816               "bg[NORMAL] = { %d, %d, %d }\n"
817               "bg[PRELIGHT] = { %d, %d, %d }\n"
818               "bg[INSENSITIVE] = { %d, %d, %d }\n"
819               "fg[PRELIGHT] = { %d, %d, %d }\n"
820               "GtkButton::default-border = { 0, 0, 0, 0 }\n"
821               "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
822               "GtkButton::child-displacement-x = 1\n"
823               "GtkButton::child-displacement-y = 1\n"
824               "GtkButton::focus-padding = %d\n"
825               "}widget_class \"*Button*\" style \"msw-button\"\n",
826               btn_face.red, btn_face.green, btn_face.blue,
827               btn_face.red, btn_face.green, btn_face.blue,
828               btn_face.red, btn_face.green, btn_face.blue,
829               btn_fore.red, btn_fore.green, btn_fore.blue,
830               xp_theme_is_active ()? 1 : 2);
831   gtk_rc_parse_string (buf);
832
833   /* enable coloring for progress bars */
834   g_snprintf (buf, sizeof (buf),
835               "style \"msw-progress\" = \"msw-default\"\n"
836               "{bg[PRELIGHT] = { %d, %d, %d }\n"
837               "bg[NORMAL] = { %d, %d, %d }\n"
838               "}widget_class \"*Progress*\" style \"msw-progress\"\n",
839               progress_back.red,
840               progress_back.green,
841               progress_back.blue,
842               btn_face.red, btn_face.green, btn_face.blue);
843   gtk_rc_parse_string (buf);
844
845   /* scrollbar thumb width and height */
846   g_snprintf (buf, sizeof (buf),
847               "style \"msw-vscrollbar\" = \"msw-default\"\n"
848               "{GtkRange::slider-width = %d\n"
849               "GtkRange::stepper-size = %d\n"
850               "GtkRange::stepper-spacing = 0\n"
851               "GtkRange::trough_border = 0\n"
852               "GtkScale::slider-length = %d\n"
853               "GtkScrollbar::min-slider-length = 8\n"
854               "}widget_class \"*VScrollbar*\" style \"msw-vscrollbar\"\n"
855               "widget_class \"*VScale*\" style \"msw-vscrollbar\"\n",
856               GetSystemMetrics (SM_CYVTHUMB),
857               get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CXVSCROLL), 11);
858   gtk_rc_parse_string (buf);
859
860   g_snprintf (buf, sizeof (buf),
861               "style \"msw-hscrollbar\" = \"msw-default\"\n"
862               "{GtkRange::slider-width = %d\n"
863               "GtkRange::stepper-size = %d\n"
864               "GtkRange::stepper-spacing = 0\n"
865               "GtkRange::trough_border = 0\n"
866               "GtkScale::slider-length = %d\n"
867               "GtkScrollbar::min-slider-length = 8\n"
868               "}widget_class \"*HScrollbar*\" style \"msw-hscrollbar\"\n"
869               "widget_class \"*HScale*\" style \"msw-hscrollbar\"\n",
870               GetSystemMetrics (SM_CXHTHUMB),
871               get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CYHSCROLL), 11);
872   gtk_rc_parse_string (buf);
873
874   gtk_rc_parse_string ("style \"msw-scrolled-window\" = \"msw-default\"\n"
875                        "{GtkScrolledWindow::scrollbars-within-bevel = 1}\n"
876                        "class \"GtkScrolledWindow\" style \"msw-scrolled-window\"\n");
877
878   /* radio/check button sizes */
879   g_snprintf (buf, sizeof (buf),
880               "style \"msw-checkbutton\" = \"msw-button\"\n"
881               "{GtkCheckButton::indicator-size = 13\n"
882               "}widget_class \"*CheckButton*\" style \"msw-checkbutton\"\n"
883               "widget_class \"*RadioButton*\" style \"msw-checkbutton\"\n");
884   gtk_rc_parse_string (buf);
885
886   /* size of combo box toggle button */
887   g_snprintf (buf, sizeof (buf),
888               "style \"msw-combobox-button\" = \"msw-default\"\n"
889               "{\n"
890               "xthickness = 0\n"
891               "ythickness = 0\n"
892               "GtkButton::default-border = { 0, 0, 0, 0 }\n"
893               "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
894               "GtkButton::child-displacement-x = 0\n"
895               "GtkButton::child-displacement-y = 0\n"
896               "GtkWidget::focus-padding = 0\n"
897               "GtkWidget::focus-line-width = 0\n"
898               "}\n"
899               "widget_class \"*ComboBox*ToggleButton*\" style \"msw-combobox-button\"\n");
900   gtk_rc_parse_string (buf);
901
902   g_snprintf (buf, sizeof (buf),
903               "style \"msw-combobox\" = \"msw-default\"\n"
904               "{\n"
905               "GtkComboBox::shadow-type = in\n"
906               "xthickness = %d\n"
907               "ythickness = %d\n"
908               "}\n"
909               "class \"GtkComboBox\" style \"msw-combobox\"\n",
910         xp_theme_is_active()? 1 : GetSystemMetrics (SM_CXEDGE),
911         xp_theme_is_active()? 1 : GetSystemMetrics (SM_CYEDGE));
912   gtk_rc_parse_string (buf);
913
914   /* size of tree view header */
915   g_snprintf (buf, sizeof (buf),
916               "style \"msw-header-button\" = \"msw-default\"\n"
917               "{\n"
918               "xthickness = 0\n"
919               "ythickness = 0\n"
920               "GtkWidget::draw-border = {0, 0, 0, 0}\n"
921         "GtkButton::default-border = { 0, 0, 0, 0 }\n"
922               "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
923               "GtkButton::child-displacement-x = 0\n"
924               "GtkButton::child-displacement-y = 0\n"
925               "GtkWidget::focus-padding = 0\n"
926               "GtkWidget::focus-line-width = 0\n"
927               "}\n"
928               "widget_class \"*TreeView*Button*\" style \"msw-header-button\"\n");
929   gtk_rc_parse_string (buf);
930
931   /* FIXME: This should be enabled once gtk+ support GtkNotebok::prelight-tab */
932   /* enable prelight tab of GtkNotebook */
933   /*
934      g_snprintf (buf, sizeof (buf),
935      "style \"msw-notebook\" = \"msw-default\"\n"
936      "{GtkNotebook::prelight-tab=1\n"
937      "}widget_class \"*Notebook*\" style \"msw-notebook\"\n");
938      gtk_rc_parse_string (buf);
939    */
940
941   /* FIXME: This should be enabled once gtk+ support GtkTreeView::full-row-focus */
942   /*
943      g_snprintf (buf, sizeof (buf),
944      "style \"msw-treeview\" = \"msw-default\"\n"
945      "{GtkTreeView::full-row-focus=0\n"
946      "}widget_class \"*TreeView*\" style \"msw-treeview\"\n");
947      gtk_rc_parse_string (buf);
948    */
949 }
950
951 static void
952 setup_system_styles (GtkStyle *style)
953 {
954   int i;
955
956   /* Default background */
957   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
958                           &style->bg[GTK_STATE_NORMAL]);
959   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
960                           &style->bg[GTK_STATE_SELECTED]);
961   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
962                           &style->bg[GTK_STATE_INSENSITIVE]);
963   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
964                           &style->bg[GTK_STATE_ACTIVE]);
965   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
966                           &style->bg[GTK_STATE_PRELIGHT]);
967
968   /* Default base */
969   sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW,
970                           &style->base[GTK_STATE_NORMAL]);
971   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
972                           &style->base[GTK_STATE_SELECTED]);
973   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
974                           &style->base[GTK_STATE_INSENSITIVE]);
975   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
976                           &style->base[GTK_STATE_ACTIVE]);
977   sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW,
978                           &style->base[GTK_STATE_PRELIGHT]);
979
980   /* Default text */
981   sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
982                           &style->text[GTK_STATE_NORMAL]);
983   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
984                           &style->text[GTK_STATE_SELECTED]);
985   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_GRAYTEXT,
986                           &style->text[GTK_STATE_INSENSITIVE]);
987   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
988                           &style->text[GTK_STATE_ACTIVE]);
989   sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
990                           &style->text[GTK_STATE_PRELIGHT]);
991
992   /* Default foreground */
993   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
994                           &style->fg[GTK_STATE_NORMAL]);
995   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
996                           &style->fg[GTK_STATE_SELECTED]);
997   sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_GRAYTEXT,
998                           &style->fg[GTK_STATE_INSENSITIVE]);
999   sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
1000                           &style->fg[GTK_STATE_ACTIVE]);
1001   sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
1002                           &style->fg[GTK_STATE_PRELIGHT]);
1003
1004   for (i = 0; i < 5; i++)
1005     {
1006       sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DSHADOW,
1007                               &style->dark[i]);
1008       sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DHILIGHT,
1009                               &style->light[i]);
1010
1011       style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
1012       style->mid[i].green =
1013         (style->light[i].green + style->dark[i].green) / 2;
1014       style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;
1015
1016       style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2;
1017       style->text_aa[i].green =
1018         (style->text[i].green + style->base[i].green) / 2;
1019       style->text_aa[i].blue =
1020         (style->text[i].blue + style->base[i].blue) / 2;
1021     }
1022 }
1023
1024 static gboolean
1025 sanitize_size (GdkWindow *window, gint *width, gint *height)
1026 {
1027   gboolean set_bg = FALSE;
1028
1029   if ((*width == -1) && (*height == -1))
1030     {
1031       set_bg = GDK_IS_WINDOW (window);
1032       gdk_drawable_get_size (window, width, height);
1033     }
1034   else if (*width == -1)
1035     {
1036       gdk_drawable_get_size (window, width, NULL);
1037     }
1038   else if (*height == -1)
1039     {
1040       gdk_drawable_get_size (window, NULL, height);
1041     }
1042
1043   return set_bg;
1044 }
1045
1046 static XpThemeElement
1047 map_gtk_progress_bar_to_xp (GtkProgressBar *progress_bar, gboolean trough)
1048 {
1049   XpThemeElement ret;
1050
1051   switch (progress_bar->orientation)
1052     {
1053     case GTK_PROGRESS_LEFT_TO_RIGHT:
1054     case GTK_PROGRESS_RIGHT_TO_LEFT:
1055       ret = trough
1056         ? XP_THEME_ELEMENT_PROGRESS_TROUGH_H
1057         : XP_THEME_ELEMENT_PROGRESS_BAR_H;
1058       break;
1059
1060     default:
1061       ret = trough
1062         ? XP_THEME_ELEMENT_PROGRESS_TROUGH_V
1063         : XP_THEME_ELEMENT_PROGRESS_BAR_V;
1064       break;
1065     }
1066
1067   return ret;
1068 }
1069
1070 static gboolean
1071 is_combo_box_child (GtkWidget *w)
1072 {
1073   GtkWidget *tmp;
1074
1075   if (w == NULL)
1076     return FALSE;
1077
1078   for (tmp = w->parent; tmp; tmp = tmp->parent)
1079     {
1080       if (GTK_IS_COMBO_BOX (tmp))
1081         return TRUE;
1082     }
1083
1084   return FALSE;
1085 }
1086
1087 /* This function is not needed anymore */
1088 /* static gboolean
1089 combo_box_draw_arrow (GtkStyle *style,
1090                       GdkWindow *window,
1091                       GtkStateType state,
1092                       GdkRectangle *area, GtkWidget *widget)
1093 {
1094   if (xp_theme_is_active ())
1095     return TRUE;
1096
1097   if (widget && GTK_IS_TOGGLE_BUTTON (widget->parent))
1098     {
1099       DWORD border;
1100       RECT rect;
1101       HDC dc;
1102
1103       dc = get_window_dc (style, window, state, area->x, area->y, area->width,
1104                           area->height, &rect);
1105       border = (GTK_TOGGLE_BUTTON (widget->parent)->
1106                 active ? DFCS_PUSHED | DFCS_FLAT : 0);
1107
1108       InflateRect (&rect, 1, 1);
1109       DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | border);
1110
1111       release_window_dc (style, window, state);
1112
1113       return TRUE;
1114     }
1115
1116   return FALSE;
1117 }*/
1118
1119 static void
1120 draw_part (GdkDrawable *drawable,
1121            GdkGC *gc, GdkRectangle *area, gint x, gint y, Part part)
1122 {
1123   if (area)
1124     gdk_gc_set_clip_rectangle (gc, area);
1125
1126   if (!parts[part].bmap)
1127     {
1128       parts[part].bmap = gdk_bitmap_create_from_data (drawable,
1129                                                       parts[part].bits,
1130                                                       PART_SIZE, PART_SIZE);
1131     }
1132
1133   gdk_gc_set_ts_origin (gc, x, y);
1134   gdk_gc_set_stipple (gc, parts[part].bmap);
1135   gdk_gc_set_fill (gc, GDK_STIPPLED);
1136
1137   gdk_draw_rectangle (drawable, gc, TRUE, x, y, PART_SIZE, PART_SIZE);
1138
1139   gdk_gc_set_fill (gc, GDK_SOLID);
1140
1141   if (area)
1142     gdk_gc_set_clip_rectangle (gc, NULL);
1143 }
1144
1145 static void
1146 draw_check (GtkStyle *style,
1147             GdkWindow *window,
1148             GtkStateType state,
1149             GtkShadowType shadow,
1150             GdkRectangle *area,
1151             GtkWidget *widget,
1152             const gchar *detail, gint x, gint y, gint width, gint height)
1153 {
1154   x -= (1 + PART_SIZE - width) / 2;
1155   y -= (1 + PART_SIZE - height) / 2;
1156
1157   if (detail && strcmp (detail, "check") == 0)  /* Menu item */
1158     {
1159       if (shadow == GTK_SHADOW_IN)
1160         {
1161           draw_part (window, style->black_gc, area, x, y, CHECK_TEXT);
1162           draw_part (window, style->dark_gc[state], area, x, y, CHECK_AA);
1163         }
1164     }
1165   else
1166     {
1167       XpThemeElement theme_elt = XP_THEME_ELEMENT_CHECKBOX;
1168       switch (shadow)
1169         {
1170         case GTK_SHADOW_ETCHED_IN:
1171           theme_elt = XP_THEME_ELEMENT_INCONSISTENT_CHECKBOX;
1172           break;
1173
1174         case GTK_SHADOW_IN:
1175           theme_elt = XP_THEME_ELEMENT_PRESSED_CHECKBOX;
1176           break;
1177
1178         default:
1179           break;
1180         }
1181
1182       if (!xp_theme_draw (window, theme_elt,
1183                           style, x, y, width, height, state, area))
1184         {
1185           if (detail && !strcmp (detail, "cellcheck"))
1186             state = GTK_STATE_NORMAL;
1187
1188           draw_part (window, style->black_gc, area, x, y, CHECK_BLACK);
1189           draw_part (window, style->dark_gc[state], area, x, y, CHECK_DARK);
1190           draw_part (window, style->mid_gc[state], area, x, y, CHECK_MID);
1191           draw_part (window, style->light_gc[state], area, x, y, CHECK_LIGHT);
1192           draw_part (window, style->base_gc[state], area, x, y, CHECK_BASE);
1193
1194           if (shadow == GTK_SHADOW_IN)
1195             {
1196               draw_part (window, style->text_gc[state], area, x,
1197                          y, CHECK_TEXT);
1198               draw_part (window, style->text_aa_gc[state], area,
1199                          x, y, CHECK_AA);
1200             }
1201           else if (shadow == GTK_SHADOW_ETCHED_IN)
1202             {
1203               draw_part (window, style->text_gc[state], area, x, y,
1204                          CHECK_INCONSISTENT);
1205               draw_part (window, style->text_aa_gc[state], area, x, y,
1206                          CHECK_AA);
1207             }
1208         }
1209     }
1210 }
1211
1212 static void
1213 draw_expander (GtkStyle *style,
1214                GdkWindow *window,
1215                GtkStateType state,
1216                GdkRectangle *area,
1217                GtkWidget *widget,
1218                const gchar *detail,
1219                gint x, gint y, GtkExpanderStyle expander_style)
1220 {
1221   gint expander_size;
1222   gint expander_semi_size;
1223   XpThemeElement xp_expander;
1224
1225   gtk_widget_style_get (widget, "expander_size", &expander_size, NULL);
1226
1227   switch (expander_style)
1228     {
1229     case GTK_EXPANDER_COLLAPSED:
1230     case GTK_EXPANDER_SEMI_COLLAPSED:
1231       xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED;
1232       break;
1233
1234     default:
1235       xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED;
1236       break;
1237     }
1238
1239   if ((expander_size % 2) == 0)
1240     expander_size--;
1241
1242   if (expander_size > 2)
1243     expander_size -= 2;
1244
1245   if (area)
1246     gdk_gc_set_clip_rectangle (style->fg_gc[state], area);
1247
1248   expander_semi_size = expander_size / 2;
1249   x -= expander_semi_size;
1250   y -= expander_semi_size;
1251
1252   if (!xp_theme_draw (window, xp_expander, style,
1253                       x, y, expander_size, expander_size, state, area))
1254     {
1255       HDC dc;
1256       RECT rect;
1257       HPEN pen;
1258       HGDIOBJ old_pen;
1259
1260       dc = get_window_dc (style, window, state, x, y, expander_size,
1261                           expander_size, &rect);
1262       FrameRect (dc, &rect, GetSysColorBrush (COLOR_GRAYTEXT));
1263       InflateRect (&rect, -1, -1);
1264       FillRect (dc, &rect,
1265                 GetSysColorBrush (state ==
1266                                   GTK_STATE_INSENSITIVE ? COLOR_BTNFACE :
1267                                   COLOR_WINDOW));
1268
1269       InflateRect (&rect, -1, -1);
1270
1271       pen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_WINDOWTEXT));
1272       old_pen = SelectObject (dc, pen);
1273
1274       MoveToEx (dc, rect.left, rect.top - 2 + expander_semi_size, NULL);
1275       LineTo (dc, rect.right, rect.top - 2 + expander_semi_size);
1276
1277       if (expander_style == GTK_EXPANDER_COLLAPSED ||
1278           expander_style == GTK_EXPANDER_SEMI_COLLAPSED)
1279         {
1280           MoveToEx (dc, rect.left - 2 + expander_semi_size, rect.top, NULL);
1281           LineTo (dc, rect.left - 2 + expander_semi_size, rect.bottom);
1282         }
1283
1284       SelectObject (dc, old_pen);
1285       DeleteObject (pen);
1286       release_window_dc (style, window, state);
1287     }
1288
1289   if (area)
1290     gdk_gc_set_clip_rectangle (style->fg_gc[state], NULL);
1291 }
1292
1293 static void
1294 draw_option (GtkStyle *style,
1295              GdkWindow *window,
1296              GtkStateType state,
1297              GtkShadowType shadow,
1298              GdkRectangle *area,
1299              GtkWidget *widget,
1300              const gchar *detail, gint x, gint y, gint width, gint height)
1301 {
1302   x -= (1 + PART_SIZE - width) / 2;
1303   y -= (1 + PART_SIZE - height) / 2;
1304
1305   if (detail && strcmp (detail, "option") == 0) /* Menu item */
1306     {
1307       if (shadow == GTK_SHADOW_IN)
1308         {
1309           draw_part (window, style->fg_gc[state], area, x, y, RADIO_TEXT);
1310         }
1311     }
1312   else
1313     {
1314       if (xp_theme_draw (window, shadow == GTK_SHADOW_IN
1315                          ? XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON
1316                          : XP_THEME_ELEMENT_RADIO_BUTTON,
1317                          style, x, y, width, height, state, area))
1318         {
1319         }
1320       else
1321         {
1322           if (detail && !strcmp (detail, "cellradio"))
1323             state = GTK_STATE_NORMAL;
1324
1325           draw_part (window, style->black_gc, area, x, y, RADIO_BLACK);
1326           draw_part (window, style->dark_gc[state], area, x, y, RADIO_DARK);
1327           draw_part (window, style->mid_gc[state], area, x, y, RADIO_MID);
1328           draw_part (window, style->light_gc[state], area, x, y, RADIO_LIGHT);
1329           draw_part (window, style->base_gc[state], area, x, y, RADIO_BASE);
1330
1331           if (shadow == GTK_SHADOW_IN)
1332             draw_part (window, style->text_gc[state], area, x, y, RADIO_TEXT);
1333         }
1334     }
1335 }
1336
1337 static void
1338 draw_varrow (GdkWindow *window,
1339              GdkGC *gc,
1340              GtkShadowType shadow_type,
1341              GdkRectangle *area,
1342              GtkArrowType arrow_type, gint x, gint y, gint width, gint height)
1343 {
1344   gint steps, extra;
1345   gint y_start, y_increment;
1346   gint i;
1347
1348   if (area)
1349     gdk_gc_set_clip_rectangle (gc, area);
1350
1351   width = width + width % 2 - 1;        /* Force odd */
1352   steps = 1 + width / 2;
1353   extra = height - steps;
1354
1355   if (arrow_type == GTK_ARROW_DOWN)
1356     {
1357       y_start = y;
1358       y_increment = 1;
1359     }
1360   else
1361     {
1362       y_start = y + height - 1;
1363       y_increment = -1;
1364     }
1365
1366   for (i = extra; i < height; i++)
1367     {
1368       gdk_draw_line (window, gc,
1369                      x + (i - extra), y_start + i * y_increment,
1370                      x + width - (i - extra) - 1, y_start + i * y_increment);
1371     }
1372
1373   if (area)
1374     gdk_gc_set_clip_rectangle (gc, NULL);
1375 }
1376
1377 static void
1378 draw_harrow (GdkWindow *window,
1379              GdkGC *gc,
1380              GtkShadowType shadow_type,
1381              GdkRectangle *area,
1382              GtkArrowType arrow_type, gint x, gint y, gint width, gint height)
1383 {
1384   gint steps, extra;
1385   gint x_start, x_increment;
1386   gint i;
1387
1388   if (area)
1389     gdk_gc_set_clip_rectangle (gc, area);
1390
1391   height = height + height % 2 - 1;     /* Force odd */
1392   steps = 1 + height / 2;
1393   extra = width - steps;
1394
1395   if (arrow_type == GTK_ARROW_RIGHT)
1396     {
1397       x_start = x;
1398       x_increment = 1;
1399     }
1400   else
1401     {
1402       x_start = x + width - 1;
1403       x_increment = -1;
1404     }
1405
1406   for (i = extra; i < width; i++)
1407     {
1408       gdk_draw_line (window, gc,
1409                      x_start + i * x_increment, y + (i - extra),
1410                      x_start + i * x_increment, y + height - (i - extra) - 1);
1411     }
1412
1413
1414   if (area)
1415     gdk_gc_set_clip_rectangle (gc, NULL);
1416 }
1417
1418 /* This function makes up for some brokeness in gtkrange.c
1419  * where we never get the full arrow of the stepper button
1420  * and the type of button in a single drawing function.
1421  *
1422  * It doesn't work correctly when the scrollbar is squished
1423  * to the point we don't have room for full-sized steppers.
1424  */
1425 static void
1426 reverse_engineer_stepper_box (GtkWidget *range,
1427                               GtkArrowType arrow_type,
1428                               gint *x, gint *y, gint *width, gint *height)
1429 {
1430   gint slider_width = 14, stepper_size = 14;
1431   gint box_width;
1432   gint box_height;
1433
1434   if (range)
1435     {
1436       gtk_widget_style_get (range,
1437                             "slider_width", &slider_width,
1438                             "stepper_size", &stepper_size, NULL);
1439     }
1440
1441   if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
1442     {
1443       box_width = slider_width;
1444       box_height = stepper_size;
1445     }
1446   else
1447     {
1448       box_width = stepper_size;
1449       box_height = slider_width;
1450     }
1451
1452   *x = *x - (box_width - *width) / 2;
1453   *y = *y - (box_height - *height) / 2;
1454   *width = box_width;
1455   *height = box_height;
1456 }
1457
1458 static XpThemeElement
1459 to_xp_arrow (GtkArrowType arrow_type)
1460 {
1461   XpThemeElement xp_arrow;
1462
1463   switch (arrow_type)
1464     {
1465     case GTK_ARROW_UP:
1466       xp_arrow = XP_THEME_ELEMENT_ARROW_UP;
1467       break;
1468
1469     case GTK_ARROW_DOWN:
1470       xp_arrow = XP_THEME_ELEMENT_ARROW_DOWN;
1471       break;
1472
1473     case GTK_ARROW_LEFT:
1474       xp_arrow = XP_THEME_ELEMENT_ARROW_LEFT;
1475       break;
1476
1477     default:
1478       xp_arrow = XP_THEME_ELEMENT_ARROW_RIGHT;
1479       break;
1480     }
1481
1482   return xp_arrow;
1483 }
1484
1485 static void
1486 draw_arrow (GtkStyle *style,
1487             GdkWindow *window,
1488             GtkStateType state,
1489             GtkShadowType shadow,
1490             GdkRectangle *area,
1491             GtkWidget *widget,
1492             const gchar *detail,
1493             GtkArrowType arrow_type,
1494             gboolean fill, gint x, gint y, gint width, gint height)
1495 {
1496   const gchar *name;
1497   HDC dc;
1498   RECT rect;
1499
1500   name = gtk_widget_get_name (widget);
1501
1502   sanitize_size (window, &width, &height);
1503
1504   if (GTK_IS_ARROW (widget) && is_combo_box_child (widget) && xp_theme_is_active ())
1505     return;
1506
1507   if (detail && strcmp (detail, "spinbutton") == 0)
1508     {
1509       if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP))
1510         {
1511           return;
1512         }
1513
1514       width -= 2;
1515       --height;
1516       if (arrow_type == GTK_ARROW_DOWN)
1517         ++y;
1518       ++x;
1519
1520       if (state == GTK_STATE_ACTIVE)
1521         {
1522           ++x;
1523           ++y;
1524         }
1525
1526       draw_varrow (window, style->fg_gc[state], shadow, area,
1527                    arrow_type, x, y, width, height);
1528
1529       return;
1530     }
1531   else if (detail && (!strcmp (detail, "vscrollbar")
1532                       || !strcmp (detail, "hscrollbar")))
1533     {
1534       gboolean is_disabled = FALSE;
1535       UINT btn_type = 0;
1536       GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget);
1537
1538       gint box_x = x;
1539       gint box_y = y;
1540       gint box_width = width;
1541       gint box_height = height;
1542
1543       reverse_engineer_stepper_box (widget, arrow_type,
1544                                     &box_x, &box_y, &box_width, &box_height);
1545
1546       if (scrollbar->range.adjustment->page_size >=
1547           (scrollbar->range.adjustment->upper -
1548            scrollbar->range.adjustment->lower))
1549         {
1550           is_disabled = TRUE;
1551         }
1552
1553       if (xp_theme_draw (window, to_xp_arrow (arrow_type), style, box_x, box_y,
1554                          box_width, box_height, state, area))
1555         {
1556         }
1557       else
1558         {
1559           switch (arrow_type)
1560             {
1561             case GTK_ARROW_UP:
1562               btn_type = DFCS_SCROLLUP;
1563               break;
1564
1565             case GTK_ARROW_DOWN:
1566               btn_type = DFCS_SCROLLDOWN;
1567               break;
1568
1569             case GTK_ARROW_LEFT:
1570               btn_type = DFCS_SCROLLLEFT;
1571               break;
1572
1573             case GTK_ARROW_RIGHT:
1574               btn_type = DFCS_SCROLLRIGHT;
1575               break;
1576
1577             case GTK_ARROW_NONE:
1578               break;
1579             }
1580
1581           if (state == GTK_STATE_INSENSITIVE)
1582             {
1583               btn_type |= DFCS_INACTIVE;
1584             }
1585
1586           if (widget)
1587             {
1588               sanitize_size (window, &width, &height);
1589
1590               dc = get_window_dc (style, window, state,
1591                                   box_x, box_y, box_width, box_height, &rect);
1592               DrawFrameControl (dc, &rect, DFC_SCROLL,
1593                                 btn_type | (shadow ==
1594                                             GTK_SHADOW_IN ? (DFCS_PUSHED |
1595                                                              DFCS_FLAT) : 0));
1596               release_window_dc (style, window, state);
1597             }
1598         }
1599     }
1600   else
1601     {
1602       /* draw the toolbar chevrons - waiting for GTK 2.4 */
1603       if (name && !strcmp (name, "gtk-toolbar-arrow"))
1604         {
1605           if (xp_theme_draw
1606               (window, XP_THEME_ELEMENT_REBAR_CHEVRON, style, x, y,
1607                width, height, state, area))
1608             {
1609               return;
1610             }
1611         }
1612       /* probably a gtk combo box on a toolbar */
1613       else if (0                /* widget->parent && GTK_IS_BUTTON
1614                                    (widget->parent) */ )
1615         {
1616           if (xp_theme_draw
1617               (window, XP_THEME_ELEMENT_COMBOBUTTON, style, x - 3,
1618                widget->allocation.y + 1, width + 5,
1619                widget->allocation.height - 4, state, area))
1620             {
1621               return;
1622             }
1623         }
1624
1625       if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
1626         {
1627           x += (width - 7) / 2;
1628           y += (height - 5) / 2;
1629
1630           draw_varrow (window, style->fg_gc[state], shadow, area,
1631                        arrow_type, x, y, 7, 5);
1632         }
1633       else
1634         {
1635           x += (width - 5) / 2;
1636           y += (height - 7) / 2;
1637
1638           draw_harrow (window, style->fg_gc[state], shadow, area,
1639                        arrow_type, x, y, 5, 7);
1640         }
1641     }
1642 }
1643
1644 static void
1645 option_menu_get_props (GtkWidget *widget,
1646                        GtkRequisition *indicator_size,
1647                        GtkBorder *indicator_spacing)
1648 {
1649   GtkRequisition *tmp_size = NULL;
1650   GtkBorder *tmp_spacing = NULL;
1651
1652   if (widget)
1653     gtk_widget_style_get (widget,
1654                           "indicator_size", &tmp_size,
1655                           "indicator_spacing", &tmp_spacing, NULL);
1656
1657   if (tmp_size)
1658     {
1659       *indicator_size = *tmp_size;
1660       gtk_requisition_free (tmp_size);
1661     }
1662   else
1663     {
1664       *indicator_size = default_option_indicator_size;
1665     }
1666
1667   if (tmp_spacing)
1668     {
1669       *indicator_spacing = *tmp_spacing;
1670       gtk_border_free (tmp_spacing);
1671     }
1672   else
1673     {
1674       *indicator_spacing = default_option_indicator_spacing;
1675     }
1676 }
1677
1678 static gboolean
1679 is_toolbar_child (GtkWidget *wid)
1680 {
1681   while (wid)
1682     {
1683       if (GTK_IS_TOOLBAR (wid) || GTK_IS_HANDLE_BOX (wid))
1684         return TRUE;
1685       else
1686         wid = wid->parent;
1687     }
1688
1689   return FALSE;
1690 }
1691
1692 static gboolean
1693 is_menu_tool_button_child (GtkWidget *wid)
1694 {
1695   while (wid)
1696     {
1697       if (GTK_IS_MENU_TOOL_BUTTON (wid))
1698         return TRUE;
1699       else
1700         wid = wid->parent;
1701     }
1702   return FALSE;
1703 }
1704
1705 HDC
1706 get_window_dc (GtkStyle *style, GdkWindow *window, GtkStateType state_type,
1707                gint x, gint y, gint width, gint height, RECT *rect)
1708 {
1709   int xoff, yoff;
1710   GdkDrawable *drawable;
1711
1712   if (!GDK_IS_WINDOW (window))
1713     {
1714       xoff = 0;
1715       yoff = 0;
1716       drawable = window;
1717     }
1718   else
1719     {
1720       gdk_window_get_internal_paint_info (window, &drawable, &xoff, &yoff);
1721     }
1722
1723   rect->left = x - xoff;
1724   rect->top = y - yoff;
1725   rect->right = rect->left + width;
1726   rect->bottom = rect->top + height;
1727
1728   return gdk_win32_hdc_get (drawable, style->dark_gc[state_type], 0);
1729 }
1730
1731 void
1732 release_window_dc (GtkStyle *style, GdkWindow *window,
1733                    GtkStateType state_type)
1734 {
1735   GdkDrawable *drawable;
1736
1737   if (!GDK_IS_WINDOW (window))
1738     {
1739       drawable = window;
1740     }
1741   else
1742     {
1743       gdk_window_get_internal_paint_info (window, &drawable, NULL, NULL);
1744     }
1745
1746   gdk_win32_hdc_release (drawable, style->dark_gc[state_type], 0);
1747 }
1748
1749 static HPEN
1750 get_light_pen ()
1751 {
1752   if (!g_light_pen)
1753     {
1754       g_light_pen = CreatePen (PS_SOLID | PS_INSIDEFRAME, 1,
1755                                GetSysColor (COLOR_BTNHIGHLIGHT));
1756     }
1757
1758   return g_light_pen;
1759 }
1760
1761 static HPEN
1762 get_dark_pen ()
1763 {
1764   if (!g_dark_pen)
1765     {
1766       g_dark_pen = CreatePen (PS_SOLID | PS_INSIDEFRAME, 1,
1767                               GetSysColor (COLOR_BTNSHADOW));
1768     }
1769
1770   return g_dark_pen;
1771 }
1772
1773 static void
1774 draw_3d_border (HDC hdc, RECT *rc, gboolean sunken)
1775 {
1776   HPEN pen1, pen2;
1777   HGDIOBJ old_pen;
1778
1779   if (sunken)
1780     {
1781       pen1 = get_dark_pen ();
1782       pen2 = get_light_pen ();
1783     }
1784   else
1785     {
1786       pen1 = get_light_pen ();
1787       pen2 = get_dark_pen ();
1788     }
1789
1790   MoveToEx (hdc, rc->left, rc->bottom - 1, NULL);
1791
1792   old_pen = SelectObject (hdc, pen1);
1793   LineTo (hdc, rc->left, rc->top);
1794   LineTo (hdc, rc->right - 1, rc->top);
1795   SelectObject (hdc, old_pen);
1796
1797   old_pen = SelectObject (hdc, pen2);
1798   LineTo (hdc, rc->right - 1, rc->bottom - 1);
1799   LineTo (hdc, rc->left, rc->bottom - 1);
1800   SelectObject (hdc, old_pen);
1801 }
1802
1803 static gboolean
1804 draw_menu_item (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
1805                 gint x, gint y, gint width, gint height,
1806                 GtkStateType state_type, GdkRectangle *area)
1807 {
1808   GtkWidget *parent;
1809   GtkMenuShell *bar;
1810   HDC dc;
1811   RECT rect;
1812
1813   if ((parent = gtk_widget_get_parent (widget))
1814       && GTK_IS_MENU_BAR (parent) && !xp_theme_is_active ())
1815     {
1816       bar = GTK_MENU_SHELL (parent);
1817
1818       dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
1819
1820       if (state_type == GTK_STATE_PRELIGHT)
1821         {
1822           draw_3d_border (dc, &rect, bar->active);
1823         }
1824
1825       release_window_dc (style, window, state_type);
1826
1827       return TRUE;
1828     }
1829
1830   return FALSE;
1831 }
1832
1833 static HBRUSH
1834 get_dither_brush (void)
1835 {
1836   WORD pattern[8];
1837   HBITMAP pattern_bmp;
1838   int i;
1839
1840   if (g_dither_brush)
1841     return g_dither_brush;
1842
1843   for (i = 0; i < 8; i++)
1844     {
1845       pattern[i] = (WORD) (0x5555 << (i & 1));
1846     }
1847
1848   pattern_bmp = CreateBitmap (8, 8, 1, 1, &pattern);
1849
1850   if (pattern_bmp)
1851     {
1852       g_dither_brush = CreatePatternBrush (pattern_bmp);
1853       DeleteObject (pattern_bmp);
1854     }
1855
1856   return g_dither_brush;
1857 }
1858
1859 static gboolean
1860 draw_tool_button (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
1861                   gint x, gint y, gint width, gint height,
1862                   GtkStateType state_type, GdkRectangle *area)
1863 {
1864   HDC dc;
1865   RECT rect;
1866   gboolean is_toggled = FALSE;
1867
1868   if (xp_theme_is_active ())
1869     {
1870       return (xp_theme_draw (window, XP_THEME_ELEMENT_TOOLBAR_BUTTON, style,
1871                              x, y, width, height, state_type, area));
1872     }
1873
1874   if (GTK_IS_TOGGLE_BUTTON (widget))
1875     {
1876       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
1877         {
1878           is_toggled = TRUE;
1879         }
1880     }
1881
1882   if (state_type != GTK_STATE_PRELIGHT
1883       && state_type != GTK_STATE_ACTIVE && !is_toggled)
1884     {
1885       return FALSE;
1886     }
1887
1888   dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
1889   if (state_type == GTK_STATE_PRELIGHT)
1890     {
1891       if (is_toggled)
1892         {
1893           FillRect (dc, &rect, GetSysColorBrush (COLOR_BTNFACE));
1894         }
1895
1896       draw_3d_border (dc, &rect, is_toggled);
1897     }
1898   else if (state_type == GTK_STATE_ACTIVE)
1899     {
1900       if (is_toggled && !is_menu_tool_button_child (widget->parent))
1901         {
1902           SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT));
1903           SetBkColor (dc, GetSysColor (COLOR_BTNFACE));
1904           FillRect (dc, &rect, get_dither_brush ());
1905         }
1906
1907       draw_3d_border (dc, &rect, TRUE);
1908     }
1909
1910   release_window_dc (style, window, state_type);
1911
1912   return TRUE;
1913 }
1914
1915 static void
1916 draw_push_button (GdkWindow *window, GtkWidget *widget, GtkStyle *style,
1917                   gint x, gint y, gint width, gint height,
1918                   GtkStateType state_type, gboolean is_default)
1919 {
1920   HDC dc;
1921   RECT rect;
1922
1923   dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
1924
1925   if (GTK_IS_TOGGLE_BUTTON (widget))
1926     {
1927       if (state_type == GTK_STATE_PRELIGHT &&
1928           gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
1929         {
1930           state_type = GTK_STATE_ACTIVE;
1931         }
1932     }
1933
1934   if (state_type == GTK_STATE_ACTIVE)
1935     {
1936       if (GTK_IS_TOGGLE_BUTTON (widget))
1937         {
1938           DrawEdge (dc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1939           SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT));
1940           SetBkColor (dc, GetSysColor (COLOR_BTNFACE));
1941           FillRect (dc, &rect, get_dither_brush ());
1942         }
1943       else
1944         {
1945           FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME));
1946           InflateRect (&rect, -1, -1);
1947           FrameRect (dc, &rect, GetSysColorBrush (COLOR_BTNSHADOW));
1948           InflateRect (&rect, -1, -1);
1949           FillRect (dc, &rect, GetSysColorBrush (COLOR_BTNFACE));
1950         }
1951     }
1952   else
1953     {
1954       if (is_default || GTK_WIDGET_HAS_FOCUS (widget))
1955         {
1956           FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME));
1957           InflateRect (&rect, -1, -1);
1958         }
1959
1960       DrawFrameControl (dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
1961     }
1962
1963   release_window_dc (style, window, state_type);
1964 }
1965
1966 static void
1967 draw_box (GtkStyle *style,
1968           GdkWindow *window,
1969           GtkStateType state_type,
1970           GtkShadowType shadow_type,
1971           GdkRectangle *area,
1972           GtkWidget *widget,
1973           const gchar *detail, gint x, gint y, gint width, gint height)
1974 {
1975   if (is_combo_box_child (widget) && detail && !strcmp (detail, "button"))
1976     {
1977       RECT rect;
1978       DWORD border;
1979       HDC dc;
1980       int cx;
1981
1982       border = (GTK_TOGGLE_BUTTON (widget)->active ? DFCS_PUSHED | DFCS_FLAT : 0);
1983
1984       dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
1985       DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLDOWN | border);
1986       release_window_dc (style, window, state_type);
1987
1988       if (xp_theme_is_active ()
1989           && xp_theme_draw (window, XP_THEME_ELEMENT_COMBOBUTTON, style, x, y,
1990                             width, height, state_type, area))
1991         {
1992       cx = GetSystemMetrics(SM_CXVSCROLL);
1993       x += width - cx;
1994       width = cx;
1995
1996
1997       dc = get_window_dc (style, window, state_type, x, y, width - cx, height, &rect);
1998       FillRect (dc, &rect, GetSysColorBrush (COLOR_WINDOW));
1999       release_window_dc (style, window, state_type);
2000       return;
2001         }
2002     }
2003
2004   if (detail &&
2005       (!strcmp (detail, "button") || !strcmp (detail, "buttondefault")))
2006     {
2007       if (GTK_IS_TREE_VIEW (widget->parent) || GTK_IS_CLIST (widget->parent))
2008       {
2009         if (xp_theme_draw
2010               (window, XP_THEME_ELEMENT_LIST_HEADER, style, x, y,
2011                width, height, state_type, area))
2012             {
2013               return;
2014             }
2015           else
2016             {
2017               HDC dc;
2018               RECT rect;
2019               dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
2020
2021               DrawFrameControl (dc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH |
2022                                 (state_type ==
2023                                  GTK_STATE_ACTIVE ? (DFCS_PUSHED | DFCS_FLAT)
2024                                  : 0));
2025               release_window_dc (style, window, state_type);
2026             }
2027         }
2028       else if (is_toolbar_child (widget->parent)
2029                || (!GTK_IS_BUTTON (widget) ||
2030                    (GTK_RELIEF_NONE == gtk_button_get_relief (GTK_BUTTON (widget)))))
2031         {
2032           if (draw_tool_button (window, widget, style, x, y,
2033                                 width, height, state_type, area))
2034             {
2035               return;
2036             }
2037         }
2038       else
2039         {
2040           gboolean is_default = GTK_WIDGET_HAS_DEFAULT (widget);
2041           if (xp_theme_draw
2042               (window,
2043                is_default ? XP_THEME_ELEMENT_DEFAULT_BUTTON :
2044                XP_THEME_ELEMENT_BUTTON, style, x, y, width, height,
2045                state_type, area))
2046             {
2047               return;
2048             }
2049
2050           draw_push_button (window, widget, style,
2051                             x, y, width, height, state_type, is_default);
2052
2053           return;
2054         }
2055
2056       return;
2057     }
2058   else if (detail && !strcmp (detail, "spinbutton"))
2059     {
2060       if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP))
2061         {
2062           return;
2063         }
2064     }
2065   else if (detail && (!strcmp (detail, "spinbutton_up")
2066                       || !strcmp (detail, "spinbutton_down")))
2067     {
2068       if (!xp_theme_draw (window,
2069                           (!strcmp (detail, "spinbutton_up"))
2070                           ? XP_THEME_ELEMENT_SPIN_BUTTON_UP
2071                           : XP_THEME_ELEMENT_SPIN_BUTTON_DOWN,
2072                           style, x, y, width, height, state_type, area))
2073         {
2074           RECT rect;
2075           HDC dc;
2076
2077           dc = get_window_dc (style, window, state_type,
2078                               x, y, width, height, &rect);
2079           DrawEdge (dc, &rect,
2080                     state_type ==
2081                     GTK_STATE_ACTIVE ? EDGE_SUNKEN : EDGE_RAISED, BF_RECT);
2082           release_window_dc (style, window, state_type);
2083         }
2084       return;
2085     }
2086   else if (detail && !strcmp (detail, "slider"))
2087     {
2088       if (GTK_IS_SCROLLBAR (widget))
2089         {
2090           GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget);
2091           gboolean is_v = GTK_IS_VSCROLLBAR (widget);
2092
2093           if (xp_theme_draw (window,
2094                              is_v
2095                              ? XP_THEME_ELEMENT_SCROLLBAR_V
2096                              : XP_THEME_ELEMENT_SCROLLBAR_H,
2097                              style, x, y, width, height, state_type, area))
2098             {
2099               XpThemeElement gripper =
2100                 (is_v ? XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V :
2101                  XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H);
2102
2103               /* Do not display grippers on tiny scroll bars,
2104                  the limit imposed is rather arbitrary, perhaps
2105                  we can fetch the gripper geometry from
2106                  somewhere and use that... */
2107               if ((gripper ==
2108                    XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H
2109                    && width < 16)
2110                   || (gripper ==
2111                       XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V && height < 16))
2112                 {
2113                   return;
2114                 }
2115
2116               xp_theme_draw (window, gripper, style, x, y,
2117                              width, height, state_type, area);
2118               return;
2119             }
2120           else
2121             {
2122               if (scrollbar->range.adjustment->page_size >=
2123                   (scrollbar->range.adjustment->upper -
2124                    scrollbar->range.adjustment->lower))
2125                 {
2126                   return;
2127                 }
2128             }
2129         }
2130     }
2131   else if (detail && !strcmp (detail, "bar"))
2132     {
2133       if (widget && GTK_IS_PROGRESS_BAR (widget))
2134         {
2135           GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget);
2136           XpThemeElement xp_progress_bar =
2137             map_gtk_progress_bar_to_xp (progress_bar, FALSE);
2138
2139           if (xp_theme_draw (window, xp_progress_bar, style, x, y,
2140                              width, height, state_type, area))
2141             {
2142               return;
2143             }
2144
2145           shadow_type = GTK_SHADOW_NONE;
2146         }
2147     }
2148   else if (detail && strcmp (detail, "menuitem") == 0)
2149     {
2150       shadow_type = GTK_SHADOW_NONE;
2151       if (draw_menu_item (window, widget, style,
2152                           x, y, width, height, state_type, area))
2153         {
2154           return;
2155         }
2156     }
2157   else if (detail && !strcmp (detail, "trough"))
2158     {
2159       if (widget && GTK_IS_PROGRESS_BAR (widget))
2160         {
2161           GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget);
2162           XpThemeElement xp_progress_bar =
2163             map_gtk_progress_bar_to_xp (progress_bar, TRUE);
2164           if (xp_theme_draw
2165               (window, xp_progress_bar, style, x, y, width, height,
2166                state_type, area))
2167             {
2168               return;
2169             }
2170           else
2171             {
2172               /* Blank in classic Windows */
2173             }
2174         }
2175       else if (widget && GTK_IS_SCROLLBAR (widget))
2176         {
2177           gboolean is_vertical = GTK_IS_VSCROLLBAR (widget);
2178
2179           if (xp_theme_draw (window,
2180                              is_vertical
2181                              ? XP_THEME_ELEMENT_TROUGH_V
2182                              : XP_THEME_ELEMENT_TROUGH_H,
2183                              style, x, y, width, height, state_type, area))
2184             {
2185               return;
2186             }
2187           else
2188             {
2189               HDC dc;
2190               RECT rect;
2191
2192               sanitize_size (window, &width, &height);
2193               dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
2194
2195               SetTextColor (dc, GetSysColor (COLOR_3DHILIGHT));
2196               SetBkColor (dc, GetSysColor (COLOR_BTNFACE));
2197               FillRect (dc, &rect, get_dither_brush ());
2198
2199               release_window_dc (style, window, state_type);
2200
2201               return;
2202             }
2203         }
2204       else if (widget && GTK_IS_SCALE (widget))
2205         {
2206           gboolean is_vertical = GTK_IS_VSCALE (widget);
2207
2208           if (!xp_theme_is_active ())
2209             {
2210               parent_class->draw_box (style, window, state_type,
2211                                       GTK_SHADOW_NONE, area,
2212                                       widget, detail, x, y, width, height);
2213             }
2214
2215           if (is_vertical)
2216             {
2217               if (xp_theme_draw
2218                   (window, XP_THEME_ELEMENT_SCALE_TROUGH_V,
2219                    style, (2 * x + width) / 2, y, 2, height,
2220                    state_type, area))
2221                 {
2222                   return;
2223                 }
2224
2225               parent_class->draw_box (style, window, state_type,
2226                                       GTK_SHADOW_ETCHED_IN,
2227                                       area, NULL, NULL,
2228                                       (2 * x + width) / 2, y, 1, height);
2229             }
2230           else
2231             {
2232               if (xp_theme_draw
2233                   (window, XP_THEME_ELEMENT_SCALE_TROUGH_H,
2234                    style, x, (2 * y + height) / 2, width, 2,
2235                    state_type, area))
2236                 {
2237                   return;
2238                 }
2239
2240               parent_class->draw_box (style, window, state_type,
2241                                       GTK_SHADOW_ETCHED_IN,
2242                                       area, NULL, NULL, x,
2243                                       (2 * y + height) / 2, width, 1);
2244             }
2245
2246           return;
2247         }
2248     }
2249   else if (detail && strcmp (detail, "optionmenu") == 0)
2250     {
2251       if (xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT,
2252                          style, x, y, width, height, state_type, area))
2253         {
2254           return;
2255         }
2256     }
2257   else if (detail
2258            && (strcmp (detail, "vscrollbar") == 0
2259                || strcmp (detail, "hscrollbar") == 0))
2260     {
2261       return;
2262     }
2263   else if (detail
2264            && (strcmp (detail, "handlebox_bin") == 0
2265                || strcmp (detail, "toolbar") == 0
2266                || strcmp (detail, "menubar") == 0))
2267     {
2268       sanitize_size (window, &width, &height);
2269       if (xp_theme_draw (window, XP_THEME_ELEMENT_REBAR,
2270                          style, x, y, width, height, state_type, area))
2271         {
2272           return;
2273         }
2274     }
2275   else if (detail && (!strcmp (detail, "handlebox")))   /* grip */
2276     {
2277       if (!xp_theme_is_active ())
2278         {
2279           return;
2280         }
2281     }
2282   else if (detail && !strcmp (detail, "notebook") && GTK_IS_NOTEBOOK (widget))
2283     {
2284       GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2285
2286       if (xp_theme_draw (window, XP_THEME_ELEMENT_TAB_PANE, style,
2287                          x, y, width, height, state_type, area))
2288         {
2289           return;
2290         }
2291     }
2292
2293   else
2294     {
2295       const gchar *name = gtk_widget_get_name (widget);
2296
2297       if (name && !strcmp (name, "gtk-tooltips"))
2298         {
2299           if (xp_theme_draw
2300               (window, XP_THEME_ELEMENT_TOOLTIP, style, x, y, width,
2301                height, state_type, area))
2302             {
2303               return;
2304             }
2305           else
2306             {
2307               HBRUSH brush;
2308               RECT rect;
2309               HDC hdc;
2310
2311               hdc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
2312
2313               brush = GetSysColorBrush (COLOR_3DDKSHADOW);
2314
2315               if (brush)
2316                 {
2317                   FrameRect (hdc, &rect, brush);
2318                 }
2319
2320               InflateRect (&rect, -1, -1);
2321               FillRect (hdc, &rect, (HBRUSH) (COLOR_INFOBK + 1));
2322
2323               release_window_dc (style, window, state_type);
2324
2325               return;
2326             }
2327         }
2328     }
2329
2330   parent_class->draw_box (style, window, state_type, shadow_type, area,
2331                           widget, detail, x, y, width, height);
2332
2333   if (detail && strcmp (detail, "optionmenu") == 0)
2334     {
2335       GtkRequisition indicator_size;
2336       GtkBorder indicator_spacing;
2337       gint vline_x;
2338
2339       option_menu_get_props (widget, &indicator_size, &indicator_spacing);
2340
2341       sanitize_size (window, &width, &height);
2342
2343       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
2344         {
2345           vline_x =
2346             x + indicator_size.width + indicator_spacing.left +
2347             indicator_spacing.right;
2348         }
2349       else
2350         {
2351           vline_x = x + width - (indicator_size.width +
2352                                  indicator_spacing.left +
2353                                  indicator_spacing.right) - style->xthickness;
2354
2355           parent_class->draw_vline (style, window, state_type, area, widget,
2356                                     detail,
2357                                     y + style->ythickness + 1,
2358                                     y + height - style->ythickness - 3, vline_x);
2359         }
2360     }
2361 }
2362
2363 static void
2364 draw_tab (GtkStyle *style,
2365           GdkWindow *window,
2366           GtkStateType state,
2367           GtkShadowType shadow,
2368           GdkRectangle *area,
2369           GtkWidget *widget,
2370           const gchar *detail, gint x, gint y, gint width, gint height)
2371 {
2372   GtkRequisition indicator_size;
2373   GtkBorder indicator_spacing;
2374
2375   gint arrow_height;
2376
2377   g_return_if_fail (style != NULL);
2378   g_return_if_fail (window != NULL);
2379
2380   if (detail && !strcmp (detail, "optionmenutab"))
2381     {
2382       if (xp_theme_draw (window, XP_THEME_ELEMENT_COMBOBUTTON,
2383                          style, x - 5, widget->allocation.y + 1,
2384                          width + 10, widget->allocation.height - 2,
2385                          state, area))
2386         {
2387           return;
2388         }
2389     }
2390
2391   option_menu_get_props (widget, &indicator_size, &indicator_spacing);
2392
2393   x += (width - indicator_size.width) / 2;
2394   arrow_height = (indicator_size.width + 1) / 2;
2395
2396   y += (height - arrow_height) / 2;
2397
2398   draw_varrow (window, style->black_gc, shadow, area, GTK_ARROW_DOWN,
2399                x, y, indicator_size.width, arrow_height);
2400 }
2401
2402 /* Draw classic Windows tab - thanks Mozilla!
2403   (no system API for this, but DrawEdge can draw all the parts of a tab) */
2404 static void
2405 DrawTab (HDC hdc, const RECT R, gint32 aPosition, gboolean aSelected,
2406          gboolean aDrawLeft, gboolean aDrawRight)
2407 {
2408   gint32 leftFlag, topFlag, rightFlag, lightFlag, shadeFlag;
2409   RECT topRect, sideRect, bottomRect, lightRect, shadeRect;
2410   gint32 selectedOffset, lOffset, rOffset;
2411
2412   selectedOffset = aSelected ? 1 : 0;
2413   lOffset = aDrawLeft ? 2 : 0;
2414   rOffset = aDrawRight ? 2 : 0;
2415
2416   /* Get info for tab orientation/position (Left, Top, Right, Bottom) */
2417   switch (aPosition)
2418     {
2419     case BF_LEFT:
2420       leftFlag = BF_TOP;
2421       topFlag = BF_LEFT;
2422       rightFlag = BF_BOTTOM;
2423       lightFlag = BF_DIAGONAL_ENDTOPRIGHT;
2424       shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT;
2425
2426       SetRect (&topRect, R.left, R.top + lOffset, R.right,
2427                R.bottom - rOffset);
2428       SetRect (&sideRect, R.left + 2, R.top, R.right - 2 + selectedOffset,
2429                R.bottom);
2430       SetRect (&bottomRect, R.right - 2, R.top, R.right, R.bottom);
2431       SetRect (&lightRect, R.left, R.top, R.left + 3, R.top + 3);
2432       SetRect (&shadeRect, R.left + 1, R.bottom - 2, R.left + 2,
2433                R.bottom - 1);
2434       break;
2435
2436     case BF_TOP:
2437       leftFlag = BF_LEFT;
2438       topFlag = BF_TOP;
2439       rightFlag = BF_RIGHT;
2440       lightFlag = BF_DIAGONAL_ENDTOPRIGHT;
2441       shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT;
2442
2443       SetRect (&topRect, R.left + lOffset, R.top, R.right - rOffset,
2444                R.bottom);
2445       SetRect (&sideRect, R.left, R.top + 2, R.right,
2446                R.bottom - 1 + selectedOffset);
2447       SetRect (&bottomRect, R.left, R.bottom - 1, R.right, R.bottom);
2448       SetRect (&lightRect, R.left, R.top, R.left + 3, R.top + 3);
2449       SetRect (&shadeRect, R.right - 2, R.top + 1, R.right - 1, R.top + 2);
2450       break;
2451
2452     case BF_RIGHT:
2453       leftFlag = BF_TOP;
2454       topFlag = BF_RIGHT;
2455       rightFlag = BF_BOTTOM;
2456       lightFlag = BF_DIAGONAL_ENDTOPLEFT;
2457       shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT;
2458
2459       SetRect (&topRect, R.left, R.top + lOffset, R.right,
2460                R.bottom - rOffset);
2461       SetRect (&sideRect, R.left + 2 - selectedOffset, R.top, R.right - 2,
2462                R.bottom);
2463       SetRect (&bottomRect, R.left, R.top, R.left + 2, R.bottom);
2464       SetRect (&lightRect, R.right - 3, R.top, R.right - 1, R.top + 2);
2465       SetRect (&shadeRect, R.right - 2, R.bottom - 3, R.right, R.bottom - 1);
2466       break;
2467
2468     case BF_BOTTOM:
2469       leftFlag = BF_LEFT;
2470       topFlag = BF_BOTTOM;
2471       rightFlag = BF_RIGHT;
2472       lightFlag = BF_DIAGONAL_ENDTOPLEFT;
2473       shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT;
2474
2475       SetRect (&topRect, R.left + lOffset, R.top, R.right - rOffset,
2476                R.bottom);
2477       SetRect (&sideRect, R.left, R.top + 2 - selectedOffset, R.right,
2478                R.bottom - 2);
2479       SetRect (&bottomRect, R.left, R.top, R.right, R.top + 2);
2480       SetRect (&lightRect, R.left, R.bottom - 3, R.left + 2, R.bottom - 1);
2481       SetRect (&shadeRect, R.right - 2, R.bottom - 3, R.right, R.bottom - 1);
2482       break;
2483
2484     default:
2485       g_return_if_reached ();
2486     }
2487
2488   /* Background */
2489   FillRect (hdc, &R, (HBRUSH) (COLOR_3DFACE + 1));
2490
2491   /* Tab "Top" */
2492   DrawEdge (hdc, &topRect, EDGE_RAISED, BF_SOFT | topFlag);
2493
2494   /* Tab "Bottom" */
2495   if (!aSelected)
2496     DrawEdge (hdc, &bottomRect, EDGE_RAISED, BF_SOFT | topFlag);
2497
2498   /* Tab "Sides" */
2499   if (!aDrawLeft)
2500     leftFlag = 0;
2501   if (!aDrawRight)
2502     rightFlag = 0;
2503
2504   DrawEdge (hdc, &sideRect, EDGE_RAISED, BF_SOFT | leftFlag | rightFlag);
2505
2506   /* Tab Diagonal Corners */
2507   if (aDrawLeft)
2508     DrawEdge (hdc, &lightRect, EDGE_RAISED, BF_SOFT | lightFlag);
2509
2510   if (aDrawRight)
2511     DrawEdge (hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag);
2512 }
2513
2514 static gboolean
2515 draw_themed_tab_button (GtkStyle *style,
2516                         GdkWindow *window,
2517                         GtkStateType state_type,
2518                         GtkNotebook *notebook,
2519                         gint x, gint y,
2520                         gint width, gint height, gint gap_side)
2521 {
2522   GdkPixmap *pixmap = NULL;
2523   gint border_width =
2524     gtk_container_get_border_width (GTK_CONTAINER (notebook));
2525   GtkWidget *widget = GTK_WIDGET (notebook);
2526   GdkRectangle draw_rect, clip_rect;
2527   GdkPixbufRotation rotation = GDK_PIXBUF_ROTATE_NONE;
2528
2529   if (gap_side == GTK_POS_TOP)
2530     {
2531       int widget_right;
2532
2533       if (state_type == GTK_STATE_NORMAL)
2534         {
2535           draw_rect.x = x;
2536           draw_rect.y = y;
2537           draw_rect.width = width + 2;
2538           draw_rect.height = height;
2539
2540           clip_rect = draw_rect;
2541           clip_rect.height--;
2542         }
2543       else
2544         {
2545           draw_rect.x = x + 2;
2546           draw_rect.y = y;
2547           draw_rect.width = width - 2;
2548           draw_rect.height = height - 2;
2549           clip_rect = draw_rect;
2550         }
2551
2552       /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */
2553       widget_right = widget->allocation.x + widget->allocation.width - border_width - 2;
2554
2555       if (draw_rect.x + draw_rect.width >= widget_right)
2556         {
2557           draw_rect.width = clip_rect.width = widget_right - draw_rect.x;
2558         }
2559     }
2560   if (gap_side == GTK_POS_BOTTOM)
2561     {
2562       int widget_right;
2563
2564       if (state_type == GTK_STATE_NORMAL)
2565         {
2566           draw_rect.x = x;
2567           draw_rect.y = y;
2568           draw_rect.width = width + 2;
2569           draw_rect.height = height;
2570
2571           clip_rect = draw_rect;
2572         }
2573       else
2574         {
2575           draw_rect.x = x + 2;
2576           draw_rect.y = y + 2;
2577           draw_rect.width = width - 2;
2578           draw_rect.height = height - 2;
2579           clip_rect = draw_rect;
2580         }
2581
2582       /* If we are currently drawing the right-most tab, and if that tab is the selected tab... */
2583       widget_right = widget->allocation.x + widget->allocation.width - border_width - 2;
2584
2585       if (draw_rect.x + draw_rect.width >= widget_right)
2586         {
2587           draw_rect.width = clip_rect.width = widget_right - draw_rect.x;
2588         }
2589
2590       rotation = GDK_PIXBUF_ROTATE_UPSIDEDOWN;
2591     }
2592   else if (gap_side == GTK_POS_LEFT)
2593     {
2594       int widget_bottom;
2595
2596       if (state_type == GTK_STATE_NORMAL)
2597         {
2598           draw_rect.x = x;
2599           draw_rect.y = y;
2600           draw_rect.width = width;
2601           draw_rect.height = height + 2;
2602
2603           clip_rect = draw_rect;
2604           clip_rect.width--;
2605         }
2606       else
2607         {
2608           draw_rect.x = x;
2609           draw_rect.y = y + 2;
2610           draw_rect.width = width - 2;
2611           draw_rect.height = height - 2;
2612           clip_rect = draw_rect;
2613         }
2614
2615       /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */
2616       widget_bottom = widget->allocation.x + widget->allocation.height - border_width - 2;
2617
2618       if (draw_rect.y + draw_rect.height >= widget_bottom)
2619         {
2620           draw_rect.height = clip_rect.height = widget_bottom - draw_rect.y;
2621         }
2622
2623       rotation = GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE;
2624     }
2625   else if (gap_side == GTK_POS_RIGHT)
2626     {
2627       int widget_bottom;
2628
2629       if (state_type == GTK_STATE_NORMAL)
2630         {
2631           draw_rect.x = x + 1;
2632           draw_rect.y = y;
2633           draw_rect.width = width;
2634           draw_rect.height = height + 2;
2635
2636           clip_rect = draw_rect;
2637           clip_rect.width--;
2638         }
2639       else
2640         {
2641           draw_rect.x = x + 2;
2642           draw_rect.y = y + 2;
2643           draw_rect.width = width - 2;
2644           draw_rect.height = height - 2;
2645           clip_rect = draw_rect;
2646         }
2647
2648       /* If we are currently drawing the bottom-most tab, and if that tab is the selected tab... */
2649       widget_bottom = widget->allocation.x + widget->allocation.height - border_width - 2;
2650
2651       if (draw_rect.y + draw_rect.height >= widget_bottom)
2652         {
2653           draw_rect.height = clip_rect.height = widget_bottom - draw_rect.y;
2654         }
2655
2656       rotation = GDK_PIXBUF_ROTATE_CLOCKWISE;
2657     }
2658
2659   if (gap_side == GTK_POS_TOP)
2660     {
2661       if (!xp_theme_draw (window, XP_THEME_ELEMENT_TAB_ITEM, style,
2662                           draw_rect.x, draw_rect.y,
2663                           draw_rect.width, draw_rect.height,
2664                           state_type, &clip_rect))
2665         {
2666           return FALSE;
2667         }
2668     }
2669   else
2670     {
2671       GdkPixbuf *pixbuf;
2672       GdkPixbuf *rotated;
2673
2674       if (gap_side == GTK_POS_LEFT || gap_side == GTK_POS_RIGHT)
2675         {
2676           pixmap = gdk_pixmap_new (window, clip_rect.height, clip_rect.width, -1);
2677
2678           if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style,
2679                               draw_rect.y - clip_rect.y, draw_rect.x - clip_rect.x,
2680                               draw_rect.height, draw_rect.width, state_type, 0))
2681             {
2682               g_object_unref (pixmap);
2683               return FALSE;
2684             }
2685
2686           pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0,
2687                                                  clip_rect.height, clip_rect.width);
2688           g_object_unref (pixmap);
2689         }
2690       else
2691         {
2692           pixmap = gdk_pixmap_new (window, clip_rect.width, clip_rect.height, -1);
2693
2694           if (!xp_theme_draw (pixmap, XP_THEME_ELEMENT_TAB_ITEM, style,
2695                               draw_rect.x - clip_rect.x, draw_rect.y - clip_rect.y,
2696                               draw_rect.width, draw_rect.height, state_type, 0))
2697             {
2698               g_object_unref (pixmap);
2699               return FALSE;
2700             }
2701
2702           pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0,
2703                                                  clip_rect.width, clip_rect.height);
2704           g_object_unref (pixmap);
2705         }
2706
2707       rotated = gdk_pixbuf_rotate_simple (pixbuf, rotation);
2708       g_object_unref (pixbuf);
2709       pixbuf = rotated;
2710
2711       // XXX - This is really hacky and evil.  When we're drawing the left-most tab
2712       //       while it is active on a bottom-oriented notebook, there is one white
2713       //       pixel at the top.  There may be a better solution than this if someone
2714       //       has time to discover it.
2715       if (gap_side == GTK_POS_BOTTOM && state_type == GTK_STATE_NORMAL
2716           && x == widget->allocation.x)
2717         {
2718           int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
2719           int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
2720           int psub = 0;
2721
2722           guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
2723           guchar *p = pixels + rowstride;
2724
2725           for (psub = 0; psub < n_channels; psub++)
2726             {
2727               pixels[psub] = p[psub];
2728             }
2729         }
2730
2731       gdk_draw_pixbuf (window, NULL, pixbuf, 0, 0, clip_rect.x, clip_rect.y,
2732                        clip_rect.width, clip_rect.height, GDK_RGB_DITHER_NONE,
2733                        0, 0);
2734       g_object_unref (pixbuf);
2735     }
2736
2737   return TRUE;
2738 }
2739
2740 static gboolean
2741 draw_tab_button (GtkStyle *style,
2742                  GdkWindow *window,
2743                  GtkStateType state_type,
2744                  GtkShadowType shadow_type,
2745                  GdkRectangle *area,
2746                  GtkWidget *widget,
2747                  const gchar *detail,
2748                  gint x, gint y, gint width, gint height, gint gap_side)
2749 {
2750   if (gap_side == GTK_POS_TOP || gap_side == GTK_POS_BOTTOM)
2751     {
2752       /* experimental tab-drawing code from mozilla */
2753       RECT rect;
2754       HDC dc;
2755       gint32 aPosition;
2756
2757       dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
2758
2759       if (gap_side == GTK_POS_TOP)
2760         aPosition = BF_TOP;
2761       else if (gap_side == GTK_POS_BOTTOM)
2762         aPosition = BF_BOTTOM;
2763       else if (gap_side == GTK_POS_LEFT)
2764         aPosition = BF_LEFT;
2765       else
2766         aPosition = BF_RIGHT;
2767
2768       if (state_type == GTK_STATE_PRELIGHT)
2769         state_type = GTK_STATE_NORMAL;
2770       if (area)
2771         gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
2772
2773       DrawTab (dc, rect, aPosition,
2774                state_type != GTK_STATE_PRELIGHT,
2775                (gap_side != GTK_POS_LEFT), (gap_side != GTK_POS_RIGHT));
2776
2777       if (area)
2778         gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
2779
2780       release_window_dc (style, window, state_type);
2781       return TRUE;
2782     }
2783
2784   return FALSE;
2785 }
2786
2787 static void
2788 draw_extension (GtkStyle *style,
2789                 GdkWindow *window,
2790                 GtkStateType state_type,
2791                 GtkShadowType shadow_type,
2792                 GdkRectangle *area,
2793                 GtkWidget *widget,
2794                 const gchar *detail,
2795                 gint x, gint y,
2796                 gint width, gint height, GtkPositionType gap_side)
2797 {
2798   if (widget && GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "tab"))
2799     {
2800       GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2801
2802       /* Why this differs from gap_side, I have no idea.. */
2803       int real_gap_side = gtk_notebook_get_tab_pos (notebook);
2804
2805       if (!draw_themed_tab_button (style, window, state_type,
2806                                    GTK_NOTEBOOK (widget), x, y,
2807                                    width, height, real_gap_side))
2808         {
2809           if (!draw_tab_button (style, window, state_type,
2810                                 shadow_type, area, widget,
2811                                 detail, x, y, width, height, real_gap_side))
2812             {
2813               parent_class->draw_extension (style, window, state_type,
2814                                             shadow_type, area, widget, detail,
2815                                             x, y, width, height,
2816                                             real_gap_side);
2817             }
2818         }
2819     }
2820 }
2821
2822 static void
2823 draw_box_gap (GtkStyle *style, GdkWindow *window, GtkStateType state_type,
2824               GtkShadowType shadow_type, GdkRectangle *area,
2825               GtkWidget *widget, const gchar *detail, gint x,
2826               gint y, gint width, gint height, GtkPositionType gap_side,
2827               gint gap_x, gint gap_width)
2828 {
2829   if (GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "notebook"))
2830     {
2831       GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2832       int side = gtk_notebook_get_tab_pos (notebook);
2833       int x2 = x, y2 = y, w2 = width, h2 = height;
2834
2835       if (side == GTK_POS_TOP)
2836         {
2837           x2 = x;
2838           y2 = y - notebook->tab_vborder;
2839           w2 = width;
2840           h2 = height + notebook->tab_vborder * 2;
2841         }
2842       else if (side == GTK_POS_BOTTOM)
2843         {
2844           x2 = x;
2845           y2 = y;
2846           w2 = width;
2847           h2 = height + notebook->tab_vborder * 2;
2848         }
2849       else if (side == GTK_POS_LEFT)
2850         {
2851           x2 = x - notebook->tab_hborder;
2852           y2 = y;
2853           w2 = width + notebook->tab_hborder;
2854           h2 = height;
2855         }
2856       else if (side == GTK_POS_RIGHT)
2857         {
2858           x2 = x;
2859           y2 = y;
2860           w2 = width + notebook->tab_hborder * 2;
2861           h2 = height;
2862         }
2863
2864       if (xp_theme_draw (window, XP_THEME_ELEMENT_TAB_PANE, style,
2865                          x2, y2, w2, h2, state_type, area))
2866         {
2867           return;
2868         }
2869     }
2870
2871   parent_class->draw_box_gap (style, window, state_type, shadow_type,
2872                               area, widget, detail, x, y, width, height,
2873                               gap_side, gap_x, gap_width);
2874 }
2875
2876 static gboolean
2877 is_popup_window_child (GtkWidget *widget)
2878 {
2879   GtkWidget *top;
2880   GtkWindowType type = -1;
2881
2882   top = gtk_widget_get_toplevel (widget);
2883
2884   if (top && GTK_IS_WINDOW (top))
2885     {
2886       g_object_get (top, "type", &type, NULL);
2887
2888       if (type == GTK_WINDOW_POPUP)
2889         {                       /* Hack for combo boxes */
2890           return TRUE;
2891         }
2892     }
2893
2894   return FALSE;
2895 }
2896
2897 static void
2898 draw_flat_box (GtkStyle *style, GdkWindow *window,
2899                GtkStateType state_type, GtkShadowType shadow_type,
2900                GdkRectangle *area, GtkWidget *widget,
2901                const gchar *detail, gint x, gint y, gint width, gint height)
2902 {
2903   if (detail)
2904     {
2905       if (!strcmp (detail, "checkbutton"))
2906         {
2907           if (state_type == GTK_STATE_PRELIGHT)
2908             {
2909               return;
2910             }
2911         }
2912     }
2913
2914   parent_class->draw_flat_box (style, window, state_type, shadow_type,
2915                                area, widget, detail, x, y, width, height);
2916 }
2917
2918 static gboolean
2919 draw_menu_border (GdkWindow *win, GtkStyle *style,
2920                   gint x, gint y, gint width, gint height)
2921 {
2922   RECT rect;
2923   HDC dc;
2924
2925   dc = get_window_dc (style, win, GTK_STATE_NORMAL, x, y, width, height, &rect);
2926
2927   if (!dc)
2928     return FALSE;
2929
2930   if (xp_theme_is_active ())
2931     {
2932       FrameRect (dc, &rect, GetSysColorBrush (COLOR_3DSHADOW));
2933     }
2934   else
2935     {
2936       DrawEdge (dc, &rect, EDGE_RAISED, BF_RECT);
2937     }
2938
2939   release_window_dc (style, win, GTK_STATE_NORMAL);
2940
2941   return TRUE;
2942 }
2943
2944 static void
2945 draw_shadow (GtkStyle *style,
2946              GdkWindow *window,
2947              GtkStateType state_type,
2948              GtkShadowType shadow_type,
2949              GdkRectangle *area,
2950              GtkWidget *widget,
2951              const gchar *detail, gint x, gint y, gint width, gint height)
2952 {
2953   gboolean is_handlebox;
2954   gboolean is_toolbar;
2955
2956   if (detail && !strcmp (detail, "frame"))
2957     {
2958  
2959       HDC dc;
2960       RECT rect;
2961
2962
2963
2964       dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
2965       if (is_combo_box_child (widget))
2966         {
2967           FillRect (dc, &rect, GetSysColorBrush (COLOR_WINDOW));
2968         }
2969       else if (is_popup_window_child (widget))
2970         {
2971           FrameRect (dc, &rect, GetSysColorBrush (COLOR_WINDOWFRAME));
2972         }
2973       else
2974         {
2975           switch (shadow_type)
2976             {
2977             case GTK_SHADOW_IN:
2978               draw_3d_border (dc, &rect, TRUE);
2979               break;
2980
2981             case GTK_SHADOW_OUT:
2982               draw_3d_border (dc, &rect, FALSE);
2983               break;
2984
2985             case GTK_SHADOW_ETCHED_IN:
2986               draw_3d_border (dc, &rect, TRUE);
2987               InflateRect (&rect, -1, -1);
2988               draw_3d_border (dc, &rect, FALSE);
2989               break;
2990
2991             case GTK_SHADOW_ETCHED_OUT:
2992               draw_3d_border (dc, &rect, FALSE);
2993               InflateRect (&rect, -1, -1);
2994               draw_3d_border (dc, &rect, TRUE);
2995               break;
2996
2997             case GTK_SHADOW_NONE:
2998               break;
2999             }
3000         }
3001
3002       release_window_dc (style, window, state_type);
3003
3004       return;
3005     }
3006   if (detail && (!strcmp (detail, "entry") || !strcmp (detail, "combobox")))
3007     {
3008       if (shadow_type != GTK_SHADOW_IN)
3009         return;
3010
3011       if (!xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style,
3012                           x, y, width, height, state_type, area))
3013         {
3014           HDC dc;
3015           RECT rect;
3016
3017           dc = get_window_dc (style, window, state_type,
3018                               x, y, width, height, &rect);
3019
3020           DrawEdge (dc, &rect, EDGE_SUNKEN, BF_RECT);
3021           release_window_dc (style, window, state_type);
3022         }
3023
3024       return;
3025     }
3026
3027   if (detail && !strcmp (detail, "scrolled_window") &&
3028       xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style,
3029                      x, y, width, height, state_type, area))
3030     {
3031       return;
3032     }
3033
3034   if (detail && !strcmp (detail, "spinbutton"))
3035     return;
3036
3037   if (detail && !strcmp (detail, "menu"))
3038     {
3039       if (draw_menu_border (window, style, x, y, width, height))
3040         {
3041           return;
3042         }
3043     }
3044
3045   if (detail && !strcmp (detail, "handlebox"))
3046     return;
3047
3048   is_handlebox = (detail && !strcmp (detail, "handlebox_bin"));
3049   is_toolbar = (detail
3050                 && (!strcmp (detail, "toolbar")
3051                     || !strcmp (detail, "menubar")));
3052
3053   if (is_toolbar || is_handlebox)
3054     {
3055       if (shadow_type == GTK_SHADOW_NONE)
3056         {
3057           return;
3058         }
3059
3060       if (widget)
3061         {
3062           HDC dc;
3063           RECT rect;
3064           HGDIOBJ old_pen = NULL;
3065           GtkPositionType pos;
3066
3067           sanitize_size (window, &width, &height);
3068
3069           if (is_handlebox)
3070             {
3071               pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (widget));
3072               /*
3073                  If the handle box is at left side, 
3074                  we shouldn't draw its right border.
3075                  The same holds true for top, right, and bottom.
3076                */
3077               switch (pos)
3078                 {
3079                 case GTK_POS_LEFT:
3080                   pos = GTK_POS_RIGHT;
3081                   break;
3082
3083                 case GTK_POS_RIGHT:
3084                   pos = GTK_POS_LEFT;
3085                   break;
3086
3087                 case GTK_POS_TOP:
3088                   pos = GTK_POS_BOTTOM;
3089                   break;
3090
3091                 case GTK_POS_BOTTOM:
3092                   pos = GTK_POS_TOP;
3093                   break;
3094                 }
3095             }
3096           else
3097             {
3098               GtkWidget *parent = gtk_widget_get_parent (widget);
3099
3100               /* Dirty hack for toolbars contained in handle boxes */
3101               if (GTK_IS_HANDLE_BOX (parent))
3102                 {
3103                   pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (parent));
3104                 }
3105               else
3106                 {
3107                   /*
3108                      Dirty hack:
3109                      Make pos != all legal enum vaules of GtkPositionType.
3110                      So every border will be draw.
3111                    */
3112                   pos = (GtkPositionType) - 1;
3113                 }
3114             }
3115
3116           dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
3117
3118           if (pos != GTK_POS_LEFT)
3119             {
3120               old_pen = SelectObject (dc, get_light_pen ());
3121               MoveToEx (dc, rect.left, rect.top, NULL);
3122               LineTo (dc, rect.left, rect.bottom);
3123             }
3124           if (pos != GTK_POS_TOP)
3125             {
3126               old_pen = SelectObject (dc, get_light_pen ());
3127               MoveToEx (dc, rect.left, rect.top, NULL);
3128               LineTo (dc, rect.right, rect.top);
3129             }
3130           if (pos != GTK_POS_RIGHT)
3131             {
3132               old_pen = SelectObject (dc, get_dark_pen ());
3133               MoveToEx (dc, rect.right - 1, rect.top, NULL);
3134               LineTo (dc, rect.right - 1, rect.bottom);
3135             }
3136           if (pos != GTK_POS_BOTTOM)
3137             {
3138               old_pen = SelectObject (dc, get_dark_pen ());
3139               MoveToEx (dc, rect.left, rect.bottom - 1, NULL);
3140               LineTo (dc, rect.right, rect.bottom - 1);
3141             }
3142           if (old_pen)
3143             SelectObject (dc, old_pen);
3144           release_window_dc (style, window, state_type);
3145         }
3146
3147       return;
3148     }
3149
3150   if (detail && !strcmp (detail, "statusbar"))
3151     {
3152       return;
3153     }
3154
3155   parent_class->draw_shadow (style, window, state_type, shadow_type, area,
3156                              widget, detail, x, y, width, height);
3157 }
3158
3159 static void
3160 draw_hline (GtkStyle *style,
3161             GdkWindow *window,
3162             GtkStateType state_type,
3163             GdkRectangle *area,
3164             GtkWidget *widget,
3165             const gchar *detail, gint x1, gint x2, gint y)
3166 {
3167   if (xp_theme_is_active () && detail && !strcmp (detail, "menuitem"))
3168     {
3169       if (xp_theme_draw
3170           (window, XP_THEME_ELEMENT_MENU_SEPARATOR, style, x1, y, x2, 1,
3171            state_type, area))
3172         {
3173           return;
3174         }
3175       else
3176         {
3177           if (area)
3178             {
3179               gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
3180             }
3181
3182           gdk_draw_line (window, style->dark_gc[state_type], x1, y, x2, y);
3183
3184           if (area)
3185             {
3186               gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
3187             }
3188         }
3189     }
3190   else
3191     {
3192       if (style->ythickness == 2)
3193         {
3194           if (area)
3195             {
3196               gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
3197               gdk_gc_set_clip_rectangle (style->light_gc[state_type], area);
3198             }
3199
3200           gdk_draw_line (window, style->dark_gc[state_type], x1, y, x2, y);
3201           ++y;
3202           gdk_draw_line (window, style->light_gc[state_type], x1, y, x2, y);
3203
3204           if (area)
3205             {
3206               gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
3207               gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL);
3208             }
3209         }
3210       else
3211         {
3212           parent_class->draw_hline (style, window, state_type, area, widget,
3213                                     detail, x1, x2, y);
3214         }
3215     }
3216 }
3217
3218 static void
3219 draw_vline (GtkStyle *style,
3220             GdkWindow *window,
3221             GtkStateType state_type,
3222             GdkRectangle *area,
3223             GtkWidget *widget,
3224             const gchar *detail, gint y1, gint y2, gint x)
3225 {
3226   if (style->xthickness == 2)
3227     {
3228       if (area)
3229         {
3230           gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
3231           gdk_gc_set_clip_rectangle (style->light_gc[state_type], area);
3232         }
3233
3234       gdk_draw_line (window, style->dark_gc[state_type], x, y1, x, y2);
3235       ++x;
3236       gdk_draw_line (window, style->light_gc[state_type], x, y1, x, y2);
3237
3238       if (area)
3239         {
3240           gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
3241           gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL);
3242         }
3243     }
3244   else
3245     {
3246       parent_class->draw_vline (style, window, state_type, area, widget,
3247                                 detail, y1, y2, x);
3248     }
3249 }
3250
3251 static void
3252 draw_slider (GtkStyle *style,
3253              GdkWindow *window,
3254              GtkStateType state_type,
3255              GtkShadowType shadow_type,
3256              GdkRectangle *area,
3257              GtkWidget *widget,
3258              const gchar *detail,
3259              gint x,
3260              gint y, gint width, gint height, GtkOrientation orientation)
3261 {
3262   if (GTK_IS_SCALE (widget) &&
3263       xp_theme_draw (window, ((orientation == GTK_ORIENTATION_VERTICAL) ?
3264                               XP_THEME_ELEMENT_SCALE_SLIDER_V :
3265                               XP_THEME_ELEMENT_SCALE_SLIDER_H), style, x, y, width,
3266                      height, state_type, area))
3267     {
3268       return;
3269     }
3270
3271   parent_class->draw_slider (style, window, state_type, shadow_type, area,
3272                              widget, detail, x, y, width, height,
3273                              orientation);
3274 }
3275
3276 static void
3277 draw_resize_grip (GtkStyle *style,
3278                   GdkWindow *window,
3279                   GtkStateType state_type,
3280                   GdkRectangle *area,
3281                   GtkWidget *widget,
3282                   const gchar *detail,
3283                   GdkWindowEdge edge, gint x, gint y, gint width, gint height)
3284 {
3285   if (detail && !strcmp (detail, "statusbar"))
3286     {
3287       if (xp_theme_draw
3288           (window, XP_THEME_ELEMENT_STATUS_GRIPPER, style, x, y, width,
3289            height, state_type, area))
3290         {
3291           return;
3292         }
3293       else
3294         {
3295           RECT rect;
3296           HDC dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
3297
3298           if (area)
3299             gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);
3300
3301           DrawFrameControl (dc, &rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
3302           release_window_dc (style, window, state_type);
3303
3304           if (area)
3305             gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
3306
3307           return;
3308         }
3309     }
3310
3311   parent_class->draw_resize_grip (style, window, state_type, area,
3312                                   widget, detail, edge, x, y, width, height);
3313 }
3314
3315 static void
3316 draw_handle (GtkStyle *style,
3317              GdkWindow *window,
3318              GtkStateType state_type,
3319              GtkShadowType shadow_type,
3320              GdkRectangle *area,
3321              GtkWidget *widget,
3322              const gchar *detail,
3323              gint x,
3324              gint y, gint width, gint height, GtkOrientation orientation)
3325 {
3326   HDC dc;
3327   RECT rect;
3328
3329   if (is_toolbar_child (widget))
3330     {
3331       XpThemeElement hndl;
3332
3333       sanitize_size (window, &width, &height);
3334
3335       if (GTK_IS_HANDLE_BOX (widget))
3336         {
3337           GtkPositionType pos;
3338           pos = gtk_handle_box_get_handle_position (GTK_HANDLE_BOX (widget));
3339
3340           if (pos == GTK_POS_TOP || pos == GTK_POS_BOTTOM)
3341             {
3342               orientation = GTK_ORIENTATION_HORIZONTAL;
3343             }
3344           else
3345             {
3346               orientation = GTK_ORIENTATION_VERTICAL;
3347             }
3348         }
3349
3350       if (orientation == GTK_ORIENTATION_VERTICAL)
3351         hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_V;
3352       else
3353         hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_H;
3354
3355       if (xp_theme_draw (window, hndl, style, x, y, width, height,
3356                          state_type, area))
3357         {
3358           return;
3359         }
3360
3361       dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
3362
3363       if (orientation == GTK_ORIENTATION_VERTICAL)
3364         {
3365           rect.left += 3;
3366           rect.right = rect.left + 3;
3367           rect.bottom -= 3;
3368           rect.top += 3;
3369         }
3370       else
3371         {
3372           rect.top += 3;
3373           rect.bottom = rect.top + 3;
3374           rect.right -= 3;
3375           rect.left += 3;
3376         }
3377
3378       draw_3d_border (dc, &rect, FALSE);
3379       release_window_dc (style, window, state_type);
3380       return;
3381     }
3382
3383   if (!GTK_IS_PANED (widget))
3384     {
3385       gint xthick, ythick;
3386       GdkGC *light_gc, *dark_gc, *shadow_gc;
3387       GdkRectangle dest;
3388
3389       sanitize_size (window, &width, &height);
3390
3391       gtk_paint_box (style, window, state_type, shadow_type, area,
3392                      widget, detail, x, y, width, height);
3393
3394       light_gc = style->light_gc[state_type];
3395       dark_gc = style->dark_gc[state_type];
3396       shadow_gc = style->mid_gc[state_type];
3397
3398       xthick = style->xthickness;
3399       ythick = style->ythickness;
3400
3401       dest.x = x + xthick;
3402       dest.y = y + ythick;
3403       dest.width = width - (xthick * 2);
3404       dest.height = height - (ythick * 2);
3405
3406       if (dest.width < dest.height)
3407         dest.x += 2;
3408       else
3409         dest.y += 2;
3410
3411       gdk_gc_set_clip_rectangle (light_gc, &dest);
3412       gdk_gc_set_clip_rectangle (dark_gc, &dest);
3413       gdk_gc_set_clip_rectangle (shadow_gc, &dest);
3414
3415       if (dest.width < dest.height)
3416         {
3417           gdk_draw_line (window, light_gc, dest.x, dest.y, dest.x,
3418                          dest.height);
3419           gdk_draw_line (window, dark_gc, dest.x + (dest.width / 2),
3420                          dest.y, dest.x + (dest.width / 2), dest.height);
3421           gdk_draw_line (window, shadow_gc, dest.x + dest.width,
3422                          dest.y, dest.x + dest.width, dest.height);
3423         }
3424       else
3425         {
3426           gdk_draw_line (window, light_gc, dest.x, dest.y,
3427                          dest.x + dest.width, dest.y);
3428           gdk_draw_line (window, dark_gc, dest.x,
3429                          dest.y + (dest.height / 2),
3430                          dest.x + dest.width, dest.y + (dest.height / 2));
3431           gdk_draw_line (window, shadow_gc, dest.x,
3432                          dest.y + dest.height, dest.x + dest.width,
3433                          dest.y + dest.height);
3434         }
3435
3436       gdk_gc_set_clip_rectangle (shadow_gc, NULL);
3437       gdk_gc_set_clip_rectangle (light_gc, NULL);
3438       gdk_gc_set_clip_rectangle (dark_gc, NULL);
3439     }
3440 }
3441
3442 static void
3443 draw_focus (GtkStyle *style,
3444             GdkWindow *window,
3445             GtkStateType state_type,
3446             GdkRectangle *area,
3447             GtkWidget *widget,
3448             const gchar *detail, gint x, gint y, gint width, gint height)
3449 {
3450   HDC dc;
3451   RECT rect;
3452
3453   if (!GTK_WIDGET_CAN_FOCUS (widget))
3454     {
3455       return;
3456     }
3457
3458   if (is_combo_box_child (widget)
3459       && (GTK_IS_ARROW (widget) || GTK_IS_BUTTON (widget)))
3460     {
3461       return;
3462     }
3463   if (GTK_IS_TREE_VIEW (widget->parent) /* list view bheader */
3464       || GTK_IS_CLIST (widget->parent))
3465     {
3466       return;
3467     }
3468
3469   dc = get_window_dc (style, window, state_type, x, y, width, height, &rect);
3470   DrawFocusRect (dc, &rect);
3471   release_window_dc (style, window, state_type);
3472 /*
3473     parent_class->draw_focus (style, window, state_type,
3474                                                      area, widget, detail, x, y, width, height);
3475 */
3476 }
3477
3478 static void
3479 draw_layout (GtkStyle *style,
3480              GdkWindow *window,
3481              GtkStateType state_type,
3482              gboolean use_text,
3483              GdkRectangle *area,
3484              GtkWidget *widget,
3485              const gchar *detail,
3486              gint old_x, gint old_y, PangoLayout *layout)
3487 {
3488   GtkNotebook *notebook = NULL;
3489   gint x = old_x;
3490   gint y = old_y;
3491
3492   /* In the XP theme, labels don't appear correctly centered inside
3493    * notebook tabs, so we give them a gentle nudge two pixels to the
3494    * right.  A little hackish, but what are 'ya gonna do?  -- Cody
3495    */
3496   if (xp_theme_is_active () && detail && !strcmp (detail, "label"))
3497     {
3498       if (widget->parent != NULL)
3499         {
3500           if (GTK_IS_NOTEBOOK (widget->parent))
3501             {
3502               int side;
3503               notebook = GTK_NOTEBOOK (widget->parent);
3504               side = gtk_notebook_get_tab_pos (notebook);
3505
3506               if (side == GTK_POS_TOP || side == GTK_POS_BOTTOM)
3507                 {
3508                   x += 2;
3509                 }
3510             }
3511         }
3512     }
3513
3514   parent_class->draw_layout (style, window, state_type,
3515                              use_text, area, widget, detail, x, y, layout);
3516 }
3517
3518 static void
3519 msw_style_init_from_rc (GtkStyle *style, GtkRcStyle *rc_style)
3520 {
3521   setup_system_font (style);
3522   setup_menu_settings (gtk_settings_get_default ());
3523   setup_system_styles (style);
3524   parent_class->init_from_rc (style, rc_style);
3525 }
3526
3527 static GdkPixmap *
3528 load_bg_image (GdkColormap *colormap,
3529                GdkColor *bg_color, const gchar *filename)
3530 {
3531   if (strcmp (filename, "<parent>") == 0)
3532     {
3533       return (GdkPixmap *) GDK_PARENT_RELATIVE;
3534     }
3535   else
3536     {
3537       return gdk_pixmap_colormap_create_from_xpm (NULL, colormap, NULL,
3538                                                   bg_color, filename);
3539     }
3540 }
3541
3542 static void
3543 msw_style_realize (GtkStyle *style)
3544 {
3545   GdkGCValues gc_values;
3546   GdkGCValuesMask gc_values_mask;
3547
3548   gint i;
3549
3550   for (i = 0; i < 5; i++)
3551     {
3552       style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
3553       style->mid[i].green =
3554         (style->light[i].green + style->dark[i].green) / 2;
3555       style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;
3556
3557       style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2;
3558       style->text_aa[i].green =
3559         (style->text[i].green + style->base[i].green) / 2;
3560       style->text_aa[i].blue =
3561         (style->text[i].blue + style->base[i].blue) / 2;
3562     }
3563
3564   style->black.red = 0x0000;
3565   style->black.green = 0x0000;
3566   style->black.blue = 0x0000;
3567   gdk_colormap_alloc_color (style->colormap, &style->black, FALSE, TRUE);
3568
3569   style->white.red = 0xffff;
3570   style->white.green = 0xffff;
3571   style->white.blue = 0xffff;
3572   gdk_colormap_alloc_color (style->colormap, &style->white, FALSE, TRUE);
3573
3574   gc_values_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND;
3575
3576   gc_values.foreground = style->black;
3577   gc_values.background = style->white;
3578   style->black_gc =
3579     gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3580
3581   gc_values.foreground = style->white;
3582   gc_values.background = style->black;
3583   style->white_gc =
3584     gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3585
3586   gc_values_mask = GDK_GC_FOREGROUND;
3587
3588   for (i = 0; i < 5; i++)
3589     {
3590       if (style->rc_style && style->rc_style->bg_pixmap_name[i])
3591         {
3592           style->bg_pixmap[i] = load_bg_image (style->colormap,
3593                                                &style->bg[i],
3594                                                style->rc_style->
3595                                                bg_pixmap_name[i]);
3596         }
3597
3598       if (!gdk_colormap_alloc_color (style->colormap, &style->fg[i], FALSE, TRUE))
3599         {
3600           g_warning ("unable to allocate color: ( %d %d %d )", style->fg[i].red,
3601                      style->fg[i].green, style->fg[i].blue);
3602         }
3603
3604       if (!gdk_colormap_alloc_color (style->colormap, &style->bg[i], FALSE, TRUE))
3605         {
3606           g_warning ("unable to allocate color: ( %d %d %d )", style->bg[i].red,
3607                      style->bg[i].green, style->bg[i].blue);
3608         }
3609
3610       if (!gdk_colormap_alloc_color (style->colormap, &style->light[i], FALSE, TRUE))
3611         {
3612           g_warning ("unable to allocate color: ( %d %d %d )",
3613                      style->light[i].red, style->light[i].green,
3614                      style->light[i].blue);
3615         }
3616
3617       if (!gdk_colormap_alloc_color (style->colormap, &style->dark[i], FALSE, TRUE))
3618         {
3619           g_warning ("unable to allocate color: ( %d %d %d )",
3620                      style->dark[i].red, style->dark[i].green,
3621                      style->dark[i].blue);
3622         }
3623
3624       if (!gdk_colormap_alloc_color (style->colormap, &style->mid[i], FALSE, TRUE))
3625         {
3626           g_warning ("unable to allocate color: ( %d %d %d )",
3627                      style->mid[i].red, style->mid[i].green,
3628                      style->mid[i].blue);
3629         }
3630
3631       if (!gdk_colormap_alloc_color (style->colormap, &style->text[i], FALSE, TRUE))
3632         {
3633           g_warning ("unable to allocate color: ( %d %d %d )",
3634                      style->text[i].red, style->text[i].green,
3635                      style->text[i].blue);
3636         }
3637
3638       if (!gdk_colormap_alloc_color (style->colormap, &style->base[i], FALSE, TRUE))
3639         {
3640           g_warning ("unable to allocate color: ( %d %d %d )",
3641                      style->base[i].red, style->base[i].green,
3642                      style->base[i].blue);
3643         }
3644
3645       if (!gdk_colormap_alloc_color (style->colormap, &style->text_aa[i], FALSE, TRUE))
3646         {
3647           g_warning ("unable to allocate color: ( %d %d %d )",
3648                      style->text_aa[i].red, style->text_aa[i].green,
3649                      style->text_aa[i].blue);
3650         }
3651
3652       gc_values.foreground = style->fg[i];
3653       style->fg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3654
3655       gc_values.foreground = style->bg[i];
3656       style->bg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3657
3658       gc_values.foreground = style->light[i];
3659       style->light_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3660
3661       gc_values.foreground = style->dark[i];
3662       style->dark_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3663
3664       gc_values.foreground = style->mid[i];
3665       style->mid_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3666
3667       gc_values.foreground = style->text[i];
3668       style->text_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3669
3670       gc_values.foreground = style->base[i];
3671       style->base_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3672
3673       gc_values.foreground = style->text_aa[i];
3674       style->text_aa_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask);
3675     }
3676 }
3677
3678 static void
3679 msw_style_unrealize (GtkStyle *style)
3680 {
3681   parent_class->unrealize (style);
3682 }
3683
3684 static void
3685 msw_style_class_init (MswStyleClass *klass)
3686 {
3687   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
3688
3689   parent_class = g_type_class_peek_parent (klass);
3690
3691   style_class->init_from_rc = msw_style_init_from_rc;
3692   style_class->draw_arrow = draw_arrow;
3693   style_class->draw_box = draw_box;
3694   style_class->draw_check = draw_check;
3695   style_class->draw_option = draw_option;
3696   style_class->draw_tab = draw_tab;
3697   style_class->draw_flat_box = draw_flat_box;
3698   style_class->draw_expander = draw_expander;
3699   style_class->draw_extension = draw_extension;
3700   style_class->draw_box_gap = draw_box_gap;
3701   style_class->draw_shadow = draw_shadow;
3702   style_class->draw_hline = draw_hline;
3703   style_class->draw_vline = draw_vline;
3704   style_class->draw_handle = draw_handle;
3705   style_class->draw_resize_grip = draw_resize_grip;
3706   style_class->draw_slider = draw_slider;
3707   style_class->draw_focus = draw_focus;
3708   style_class->draw_layout = draw_layout;
3709
3710   style_class->realize = msw_style_realize;
3711   style_class->unrealize = msw_style_unrealize;
3712 }
3713
3714 GType msw_type_style = 0;
3715
3716 void
3717 msw_style_register_type (GTypeModule *module)
3718 {
3719   static const GTypeInfo object_info = {
3720     sizeof (MswStyleClass),
3721     (GBaseInitFunc) NULL,
3722     (GBaseFinalizeFunc) NULL,
3723     (GClassInitFunc) msw_style_class_init,
3724     NULL,                       /* class_finalize */
3725     NULL,                       /* class_data */
3726     sizeof (MswStyle),
3727     0,                          /* n_preallocs */
3728     (GInstanceInitFunc) NULL,
3729   };
3730
3731   msw_type_style = g_type_module_register_type (module,
3732                                                 GTK_TYPE_STYLE,
3733                                                 "MswStyle", &object_info, 0);
3734 }
3735
3736 void
3737 msw_style_init (void)
3738 {
3739   xp_theme_init ();
3740   msw_style_setup_system_settings ();
3741   setup_msw_rc_style ();
3742
3743   if (g_light_pen)
3744     {
3745       DeleteObject (g_light_pen);
3746       g_light_pen = NULL;
3747     }
3748
3749   if (g_dark_pen)
3750     {
3751       DeleteObject (g_dark_pen);
3752       g_dark_pen = NULL;
3753     }
3754 }
3755
3756 void
3757 msw_style_finalize (void)
3758 {
3759   if (g_dither_brush)
3760     {
3761       DeleteObject (g_dither_brush);
3762     }
3763
3764   if (g_light_pen)
3765     {
3766       DeleteObject (g_light_pen);
3767     }
3768
3769   if (g_dark_pen)
3770     {
3771       DeleteObject (g_dark_pen);
3772     }
3773 }