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