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