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