]> Pileus Git - ~andy/gtk/blob - modules/engines/ms-windows/msw_style.c
Bug #313627. Make win32 theme's handling of toolbars, handleboxes, and
[~andy/gtk] / modules / engines / ms-windows / msw_style.c
1 /* MS-Windows Engine (aka GTK-Wimp)
2  *
3  * Copyright (C) 2003, 2004 Raymond Penners <raymond@dotsphinx.com>
4  * Includes code adapted from redmond95 by Owen Taylor, and
5  * gtk-nativewin by Evan Martin
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Useful resources:
25  *
26  *  http://lxr.mozilla.org/mozilla/source/gfx/src/windows/nsNativeThemeWin.cpp
27  *  http://lxr.mozilla.org/seamonkey/source/widget/src/windows/nsLookAndFeel.cpp
28  *  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/userex/functions/drawthemebackground.asp
29  */
30
31 #include "msw_style.h"
32 #include "xp_theme.h"
33
34 #include <windows.h>
35 #include <math.h>
36 #include <string.h>
37 #include <stdio.h>
38
39 #include "gtk/gtk.h"
40 #include "gtk/gtk.h"
41 /* #include <gdk/gdkwin32.h> */
42
43 #include "gdk/win32/gdkwin32.h"
44
45
46 /* Default values, not normally used
47  */
48 static const GtkRequisition default_option_indicator_size = { 9, 8 };
49 static const GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
50
51 static GtkStyleClass *parent_class;
52
53 typedef enum
54 {
55     CHECK_AA,
56     CHECK_BASE,
57     CHECK_BLACK,
58     CHECK_DARK,
59     CHECK_LIGHT,
60     CHECK_MID,
61     CHECK_TEXT,
62     RADIO_BASE,
63     RADIO_BLACK,
64     RADIO_DARK,
65     RADIO_LIGHT,
66     RADIO_MID,
67     RADIO_TEXT
68 } Part;
69
70 #define PART_SIZE 13
71
72 static const guint8 check_aa_bits[] = {
73     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74     0x00, 0x00, 0x00,
75     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
76 };
77 static const guint8 check_base_bits[] = {
78     0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07,
79     0xfc, 0x07, 0xfc,
80     0x07, 0xfc, 0x07, 0xfc, 0x07, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00
81 };
82 static const guint8 check_black_bits[] = {
83     0x00, 0x00, 0xfe, 0x0f, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
84     0x02, 0x00, 0x02,
85     0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00
86 };
87 static const guint8 check_dark_bits[] = {
88     0xff, 0x1f, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
89     0x01, 0x00, 0x01,
90     0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00
91 };
92 static const guint8 check_light_bits[] = {
93     0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10,
94     0x00, 0x10, 0x00,
95     0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0xfe, 0x1f
96 };
97 static const guint8 check_mid_bits[] = {
98     0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
99     0x00, 0x08, 0x00,
100     0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0xfc, 0x0f, 0x00, 0x00
101 };
102 static const guint8 check_text_bits[] = {
103     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x88, 0x03,
104     0xd8, 0x01, 0xf8,
105     0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
106 };
107 static const guint8 radio_base_bits[] = {
108     0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xf8, 0x03, 0xfc, 0x07, 0xfc, 0x07,
109     0xfc, 0x07, 0xfc,
110     0x07, 0xfc, 0x07, 0xf8, 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00
111 };
112 static const guint8 radio_black_bits[] = {
113     0x00, 0x00, 0xf0, 0x01, 0x0c, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
114     0x02, 0x00, 0x02,
115     0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
116 };
117 static const guint8 radio_dark_bits[] = {
118     0xf0, 0x01, 0x0c, 0x06, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
119     0x01, 0x00, 0x01,
120     0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
121 };
122 static const guint8 radio_light_bits[] = {
123     0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x10,
124     0x00, 0x10, 0x00,
125     0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x08, 0x0c, 0x06, 0xf0, 0x01
126 };
127 static const guint8 radio_mid_bits[] = {
128     0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08,
129     0x00, 0x08, 0x00,
130     0x08, 0x00, 0x08, 0x00, 0x04, 0x0c, 0x06, 0xf0, 0x01, 0x00, 0x00
131 };
132 static const guint8 radio_text_bits[] = {
133     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xf0, 0x01,
134     0xf0, 0x01, 0xf0,
135     0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
136 };
137
138 static struct
139 {
140     const guint8 *bits;
141     GdkBitmap *bmap;
142 } parts[] =
143 {
144     {check_aa_bits, NULL},
145     {check_base_bits, NULL},
146     {check_black_bits, NULL},
147     {check_dark_bits, NULL},
148     {check_light_bits, NULL},
149     {check_mid_bits, NULL},
150     {check_text_bits, NULL},
151     {radio_base_bits, NULL},
152     {radio_black_bits, NULL},
153     {radio_dark_bits, NULL},
154     {radio_light_bits, NULL},
155     {radio_mid_bits, NULL},
156     {radio_text_bits, NULL}
157 };
158
159 static gboolean
160 get_system_font (XpThemeClass klazz, XpThemeFont type, LOGFONT * out_lf)
161 {
162 #if 0
163     /* TODO: this causes crashes later because the font name is in UCS2, and
164        the pango fns don't deal with that gracefully */
165     if (xp_theme_get_system_font (klazz, type, out_lf))
166         return TRUE;
167     else
168 #endif
169         {
170             NONCLIENTMETRICS ncm;
171
172             ncm.cbSize = sizeof (NONCLIENTMETRICS);
173
174             if (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,
175                                       sizeof (NONCLIENTMETRICS), &ncm, 0))
176                 {
177                     if (type == XP_THEME_FONT_CAPTION)
178                         *out_lf = ncm.lfCaptionFont;
179                     else if (type == XP_THEME_FONT_MENU)
180                         *out_lf = ncm.lfMenuFont;
181                     else if (type == XP_THEME_FONT_STATUS)
182                         *out_lf = ncm.lfStatusFont;
183                     else
184                         *out_lf = ncm.lfMessageFont;
185
186                     return TRUE;
187                 }
188         }
189     return FALSE;
190 }
191
192 /***************************** BEGIN STOLEN FROM PANGO *****************************/
193
194 /*
195         This code is stolen from Pango 1.4. It attempts to address the following problems:
196
197         http://bugzilla.gnome.org/show_bug.cgi?id=135098
198         http://sourceforge.net/tracker/index.php?func=detail&aid=895762&group_id=76416&atid=547655
199
200         As Owen suggested in bug 135098, once Pango 1.6 is released, we need to get rid of this code.
201 */
202
203 #define PING(printlist)
204
205 /* TrueType defines: */
206
207 #define MAKE_TT_TABLE_NAME(c1, c2, c3, c4) \
208    (((guint32)c4) << 24 | ((guint32)c3) << 16 | ((guint32)c2) << 8 | ((guint32)c1))
209
210 #define CMAP (MAKE_TT_TABLE_NAME('c','m','a','p'))
211 #define CMAP_HEADER_SIZE 4
212
213 #define NAME (MAKE_TT_TABLE_NAME('n','a','m','e'))
214 #define NAME_HEADER_SIZE 6
215
216 #define ENCODING_TABLE_SIZE 8
217
218 #define APPLE_UNICODE_PLATFORM_ID 0
219 #define MACINTOSH_PLATFORM_ID 1
220 #define ISO_PLATFORM_ID 2
221 #define MICROSOFT_PLATFORM_ID 3
222
223 #define SYMBOL_ENCODING_ID 0
224 #define UNICODE_ENCODING_ID 1
225 #define UCS4_ENCODING_ID 10
226
227 struct name_header
228 {
229     guint16 format_selector;
230     guint16 num_records;
231     guint16 string_storage_offset;
232 };
233
234 struct name_record
235 {
236     guint16 platform_id;
237     guint16 encoding_id;
238     guint16 language_id;
239     guint16 name_id;
240     guint16 string_length;
241     guint16 string_offset;
242 };
243
244 static gboolean
245 pango_win32_get_name_header (HDC hdc, struct name_header *header)
246 {
247     if (GetFontData (hdc, NAME, 0, header, sizeof (*header)) !=
248         sizeof (*header))
249         return FALSE;
250
251     header->num_records = GUINT16_FROM_BE (header->num_records);
252     header->string_storage_offset =
253         GUINT16_FROM_BE (header->string_storage_offset);
254
255     return TRUE;
256 }
257
258 static gboolean
259 pango_win32_get_name_record (HDC hdc, gint i, struct name_record *record)
260 {
261     if (GetFontData (hdc, NAME, 6 + i * sizeof (*record),
262                      record, sizeof (*record)) != sizeof (*record))
263         return FALSE;
264
265     record->platform_id = GUINT16_FROM_BE (record->platform_id);
266     record->encoding_id = GUINT16_FROM_BE (record->encoding_id);
267     record->language_id = GUINT16_FROM_BE (record->language_id);
268     record->name_id = GUINT16_FROM_BE (record->name_id);
269     record->string_length = GUINT16_FROM_BE (record->string_length);
270     record->string_offset = GUINT16_FROM_BE (record->string_offset);
271
272     return TRUE;
273 }
274
275 static gchar *
276 get_family_name (LOGFONT * lfp, HDC pango_win32_hdc)
277 {
278     HFONT hfont;
279     HFONT oldhfont;
280
281     struct name_header header;
282     struct name_record record;
283
284     gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1;
285     gint name_ix;
286     gchar *codeset;
287
288     gchar *string = NULL;
289     gchar *name;
290
291     size_t i, l, nbytes;
292
293     /* If lfFaceName is ASCII, assume it is the common (English) name for the 
294        font. Is this valid? Do some TrueType fonts have different names in
295        French, German, etc, and does the system return these if the locale is 
296        set to use French, German, etc? */
297     l = strlen (lfp->lfFaceName);
298     for (i = 0; i < l; i++)
299         if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~')
300             break;
301
302     if (i == l)
303         return g_strdup (lfp->lfFaceName);
304
305     if ((hfont = CreateFontIndirect (lfp)) == NULL)
306         goto fail0;
307
308     if ((oldhfont = (HFONT) SelectObject (pango_win32_hdc, hfont)) == NULL)
309         goto fail1;
310
311     if (!pango_win32_get_name_header (pango_win32_hdc, &header))
312         goto fail2;
313
314     PING (("%d name records", header.num_records));
315
316     for (i = 0; i < header.num_records; i++)
317         {
318             if (!pango_win32_get_name_record (pango_win32_hdc, i, &record))
319                 goto fail2;
320
321             if ((record.name_id != 1 && record.name_id != 16)
322                 || record.string_length <= 0)
323                 continue;
324
325             PING (("platform:%d encoding:%d language:%04x name_id:%d",
326                    record.platform_id, record.encoding_id, record.language_id,
327                    record.name_id));
328
329             if (record.platform_id == APPLE_UNICODE_PLATFORM_ID ||
330                 record.platform_id == ISO_PLATFORM_ID)
331                 unicode_ix = i;
332             else if (record.platform_id == MACINTOSH_PLATFORM_ID && record.encoding_id == 0 &&  /* Roman 
333                                                                                                  */
334                      record.language_id == 0)   /* English */
335                 mac_ix = i;
336             else if (record.platform_id == MICROSOFT_PLATFORM_ID)
337                 if ((microsoft_ix == -1 ||
338                      PRIMARYLANGID (record.language_id) == LANG_ENGLISH) &&
339                     (record.encoding_id == SYMBOL_ENCODING_ID ||
340                      record.encoding_id == UNICODE_ENCODING_ID ||
341                      record.encoding_id == UCS4_ENCODING_ID))
342                     microsoft_ix = i;
343         }
344
345     if (microsoft_ix >= 0)
346         name_ix = microsoft_ix;
347     else if (mac_ix >= 0)
348         name_ix = mac_ix;
349     else if (unicode_ix >= 0)
350         name_ix = unicode_ix;
351     else
352         goto fail2;
353
354     if (!pango_win32_get_name_record (pango_win32_hdc, name_ix, &record))
355         goto fail2;
356
357     string = g_malloc (record.string_length + 1);
358     if (GetFontData (pango_win32_hdc, NAME,
359                      header.string_storage_offset + record.string_offset,
360                      string, record.string_length) != record.string_length)
361         goto fail2;
362
363     string[record.string_length] = '\0';
364
365     if (name_ix == microsoft_ix)
366         if (record.encoding_id == SYMBOL_ENCODING_ID ||
367             record.encoding_id == UNICODE_ENCODING_ID)
368             codeset = "UTF-16BE";
369         else
370             codeset = "UCS-4BE";
371     else if (name_ix == mac_ix)
372         codeset = "MacRoman";
373     else                        /* name_ix == unicode_ix */
374         codeset = "UCS-4BE";
375
376     name =
377         g_convert (string, record.string_length, "UTF-8", codeset, NULL,
378                    &nbytes, NULL);
379     if (name == NULL)
380         goto fail2;
381     g_free (string);
382
383     PING (("%s", name));
384
385     SelectObject (pango_win32_hdc, oldhfont);
386     DeleteObject (hfont);
387
388     return name;
389
390   fail2:
391     g_free (string);
392     SelectObject (pango_win32_hdc, oldhfont);
393
394   fail1:
395     DeleteObject (hfont);
396
397   fail0:
398     return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
399 }
400
401 /***************************** END STOLEN FROM PANGO *****************************/
402
403 static char *
404 sys_font_to_pango_font (XpThemeClass klazz, XpThemeFont type, char *buf,
405                         size_t bufsiz)
406 {
407     HDC hDC;
408     HWND hwnd;
409     LOGFONT lf;
410     int pt_size;
411     const char *weight;
412     const char *style;
413     char *font;
414
415     if (get_system_font (klazz, type, &lf))
416         {
417             switch (lf.lfWeight)
418                 {
419                 case FW_THIN:
420                 case FW_EXTRALIGHT:
421                     weight = "Ultra-Light";
422                     break;
423
424                 case FW_LIGHT:
425                     weight = "Light";
426                     break;
427
428                 case FW_BOLD:
429                     weight = "Bold";
430                     break;
431
432                 case FW_SEMIBOLD:
433                     weight = "Semi-Bold";
434                     break;
435
436                 case FW_ULTRABOLD:
437                     weight = "Ultra-Bold";
438                     break;
439
440                 case FW_HEAVY:
441                     weight = "Heavy";
442                     break;
443
444                 default:
445                     weight = "";
446                     break;
447                 }
448
449             if (lf.lfItalic)
450                 style = "Italic";
451             else
452                 style = "";
453
454             hwnd = GetDesktopWindow ();
455             hDC = GetDC (hwnd);
456             if (hDC)
457                 {
458                     pt_size = -MulDiv (lf.lfHeight, 72,
459                                        GetDeviceCaps (hDC, LOGPIXELSY));
460                     ReleaseDC (hwnd, hDC);
461                 }
462             else
463                 pt_size = 10;
464
465             font = get_family_name (&lf, hDC);
466             g_snprintf (buf, bufsiz, "%s %s %s %d", font, style, weight,
467                         pt_size);
468             g_free (font);
469
470             return buf;
471         }
472
473     return NULL;
474 }
475
476 /* missing from ms's header files */
477 #ifndef SPI_GETMENUSHOWDELAY
478 #define SPI_GETMENUSHOWDELAY 106
479 #endif
480
481 /* I don't know the proper XP theme class for things like
482    HIGHLIGHTTEXT, so we'll just define it to be "BUTTON"
483    for now */
484 #define XP_THEME_CLASS_TEXT XP_THEME_CLASS_BUTTON
485
486 static void
487 setup_menu_settings (GtkSettings * settings)
488 {
489     int menu_delay;
490     gboolean win95 = FALSE;
491     OSVERSIONINFOEX osvi;
492     GObjectClass *klazz = G_OBJECT_GET_CLASS (G_OBJECT (settings));
493
494     ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX));
495     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
496
497     if (!GetVersionEx ((OSVERSIONINFO *) & osvi))
498         win95 = TRUE;           /* assume the worst */
499
500     if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
501         if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
502             win95 = TRUE;
503
504     if (!win95)
505         {
506             if (SystemParametersInfo
507                 (SPI_GETMENUSHOWDELAY, 0, &menu_delay, 0))
508                 {
509                     if (klazz)
510                         {
511                             if (g_object_class_find_property
512                                 (klazz, "gtk-menu-bar-popup-delay"))
513                                 {
514                                     g_object_set (settings,
515                                                   "gtk-menu-bar-popup-delay",
516                                                   0, NULL);
517                                 }
518                             if (g_object_class_find_property
519                                 (klazz, "gtk-menu-popup-delay"))
520                                 {
521                                     g_object_set (settings,
522                                                   "gtk-menu-popup-delay",
523                                                   menu_delay, NULL);
524                                 }
525                             if (g_object_class_find_property
526                                 (klazz, "gtk-menu-popdown-delay"))
527                                 {
528                                     g_object_set (settings,
529                                                   "gtk-menu-popdown-delay",
530                                                   menu_delay, NULL);
531                                 }
532                         }
533                 }
534         }
535 }
536
537 void
538 msw_style_setup_system_settings (void)
539 {
540     GtkSettings *settings;
541     int cursor_blink_time;
542
543     settings = gtk_settings_get_default ();
544     if (!settings)
545         return;
546
547     cursor_blink_time = GetCaretBlinkTime ();
548     g_object_set (settings, "gtk-cursor-blink", cursor_blink_time > 0, NULL);
549
550     if (cursor_blink_time > 0)
551         g_object_set (settings, "gtk-cursor-blink-time",
552                       2 * cursor_blink_time, NULL);
553
554     g_object_set (settings, "gtk-double-click-distance",
555                   GetSystemMetrics (SM_CXDOUBLECLK), NULL);
556     g_object_set (settings, "gtk-double-click-time", GetDoubleClickTime (),
557                   NULL);
558     g_object_set (settings, "gtk-dnd-drag-threshold",
559                   GetSystemMetrics (SM_CXDRAG), NULL);
560
561     setup_menu_settings (settings);
562
563     /* 
564        http://developer.gnome.org/doc/API/2.0/gtk/GtkSettings.html
565        http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/systemparametersinfo.asp
566        http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getsystemmetrics.asp */
567 }
568
569 static void
570 setup_system_font (GtkStyle * style)
571 {
572     char buf[256], *font;       /* It's okay, lfFaceName is smaller than 32
573                                    chars */
574
575     if ((font = sys_font_to_pango_font (XP_THEME_CLASS_TEXT,
576                                         XP_THEME_FONT_MESSAGE,
577                                         buf, sizeof (buf))) != NULL)
578         {
579             if (style->font_desc)
580                 pango_font_description_free (style->font_desc);
581
582             style->font_desc = pango_font_description_from_string (font);
583         }
584 }
585
586 static void
587 sys_color_to_gtk_color (XpThemeClass klazz, int id, GdkColor * pcolor)
588 {
589     DWORD color;
590
591     if (!xp_theme_get_system_color (klazz, id, &color))
592         color = GetSysColor (id);
593
594     pcolor->pixel = color;
595     pcolor->red = (GetRValue (color) << 8) | GetRValue (color);
596     pcolor->green = (GetGValue (color) << 8) | GetGValue (color);
597     pcolor->blue = (GetBValue (color) << 8) | GetBValue (color);
598 }
599
600 static int
601 get_system_metric (XpThemeClass klazz, int id)
602 {
603     int rval;
604
605     if (!xp_theme_get_system_metric (klazz, id, &rval))
606         rval = GetSystemMetrics (id);
607
608     return rval;
609 }
610
611 static void
612 setup_msw_rc_style (void)
613 {
614     char buf[1024], font_buf[256], *font_ptr;
615
616     GdkColor menu_color;
617     GdkColor menu_text_color;
618     GdkColor tooltip_back;
619     GdkColor tooltip_fore;
620     GdkColor btn_fore;
621     GdkColor btn_face;
622     GdkColor progress_back;
623
624     GdkColor fg_prelight;
625     GdkColor bg_prelight;
626     GdkColor base_prelight;
627     GdkColor text_prelight;
628
629     /* Prelight */
630     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
631                             &fg_prelight);
632     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
633                             &bg_prelight);
634     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
635                             &base_prelight);
636     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
637                             &text_prelight);
638
639     sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENUTEXT,
640                             &menu_text_color);
641     sys_color_to_gtk_color (XP_THEME_CLASS_MENU, COLOR_MENU, &menu_color);
642
643     /* tooltips */
644     sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOTEXT,
645                             &tooltip_fore);
646     sys_color_to_gtk_color (XP_THEME_CLASS_TOOLTIP, COLOR_INFOBK,
647                             &tooltip_back);
648
649     /* text on push buttons. TODO: button shadows, backgrounds, and
650        highlights */
651     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT, &btn_fore);
652     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE, &btn_face);
653
654     /* progress bar background color */
655     sys_color_to_gtk_color (XP_THEME_CLASS_PROGRESS, COLOR_HIGHLIGHT,
656                             &progress_back);
657
658     /* Enable coloring for menus. */
659     font_ptr =
660         sys_font_to_pango_font (XP_THEME_CLASS_MENU, XP_THEME_FONT_MENU,
661                                 font_buf, sizeof (font_buf));
662     g_snprintf (buf, sizeof (buf),
663                 "style \"msw-menu\" = \"msw-default\"\n" "{\n"
664                 "fg[PRELIGHT] = { %d, %d, %d }\n"
665                 "bg[PRELIGHT] = { %d, %d, %d }\n"
666                 "text[PRELIGHT] = { %d, %d, %d }\n"
667                 "base[PRELIGHT] = { %d, %d, %d }\n"
668                 "fg[NORMAL] = { %d, %d, %d }\n"
669                 "bg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n"
670                 "}widget_class \"*MenuItem*\" style \"msw-menu\"\n"
671                 "widget_class \"*GtkMenu\" style \"msw-menu\"\n"
672                 "widget_class \"*GtkMenuShell*\" style \"msw-menu\"\n",
673                 fg_prelight.red, fg_prelight.green, fg_prelight.blue,
674                 bg_prelight.red, bg_prelight.green, bg_prelight.blue,
675                 text_prelight.red, text_prelight.green, text_prelight.blue,
676                 base_prelight.red, base_prelight.green, base_prelight.blue,
677                 menu_text_color.red, menu_text_color.green,
678                 menu_text_color.blue, menu_color.red, menu_color.green,
679                 menu_color.blue, (font_ptr ? "font_name" : "#"),
680                 (font_ptr ? font_ptr : " font name should go here"));
681     gtk_rc_parse_string (buf);
682
683     /* Enable coloring for menu bars. */
684     g_snprintf (buf, sizeof (buf),
685                 "style \"msw-menu-bar\" = \"msw-menu\"\n"
686                 "{\n"
687                 "bg[NORMAL] = { %d, %d, %d }\n"
688                 "GtkMenuBar::shadow-type = %s\n"
689                 "}widget_class \"*MenuBar*\" style \"msw-menu-bar\"\n",
690                 btn_face.red, btn_face.green, btn_face.blue, "etched-in");
691     gtk_rc_parse_string (buf);
692
693     g_snprintf (buf, sizeof (buf),
694                 "style \"msw-toolbar\" = \"msw-default\"\n"
695                 "{\n"
696                 "GtkHandleBox::shadow-type = %s\n"
697                 "GtkToolbar::shadow-type = %s\n"
698                 "}widget_class \"*HandleBox*\" style \"msw-toolbar\"\n",
699                 "etched-in", "etched-in");
700     gtk_rc_parse_string (buf);
701
702     /* enable tooltip fonts */
703     font_ptr =
704         sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,
705                                 font_buf, sizeof (font_buf));
706     g_snprintf (buf, sizeof (buf),
707                 "style \"msw-tooltips-caption\" = \"msw-default\"\n"
708                 "{fg[NORMAL] = { %d, %d, %d }\n" "%s = \"%s\"\n"
709                 "}widget \"gtk-tooltips.GtkLabel\" style \"msw-tooltips-caption\"\n",
710                 tooltip_fore.red, tooltip_fore.green, tooltip_fore.blue,
711                 (font_ptr ? "font_name" : "#"),
712                 (font_ptr ? font_ptr : " font name should go here"));
713     gtk_rc_parse_string (buf);
714
715     g_snprintf (buf, sizeof (buf),
716                 "style \"msw-tooltips\" = \"msw-default\"\n"
717                 "{bg[NORMAL] = { %d, %d, %d }\n"
718                 "}widget \"gtk-tooltips*\" style \"msw-tooltips\"\n",
719                 tooltip_back.red, tooltip_back.green, tooltip_back.blue);
720     gtk_rc_parse_string (buf);
721
722     /* enable font theming for status bars */
723     font_ptr =
724         sys_font_to_pango_font (XP_THEME_CLASS_STATUS, XP_THEME_FONT_STATUS,
725                                 font_buf, sizeof (font_buf));
726     g_snprintf (buf, sizeof (buf),
727                 "style \"msw-status\" = \"msw-default\"\n" "{%s = \"%s\"\n"
728                 "bg[NORMAL] = { %d, %d, %d }\n"
729                 "}widget_class \"*Status*\" style \"msw-status\"\n",
730                 (font_ptr ? "font_name" : "#"),
731                 (font_ptr ? font_ptr : " font name should go here"),
732                 btn_face.red, btn_face.green, btn_face.blue);
733     gtk_rc_parse_string (buf);
734
735     /* enable coloring for text on buttons TODO: use GetThemeMetric for the
736        border and outside border */
737     g_snprintf (buf, sizeof (buf),
738                 "style \"msw-button\" = \"msw-default\"\n"
739                 "{\n"
740                 "bg[NORMAL] = { %d, %d, %d }\n"
741                 "bg[PRELIGHT] = { %d, %d, %d }\n"
742                 "bg[INSENSITIVE] = { %d, %d, %d }\n"
743                 "fg[PRELIGHT] = { %d, %d, %d }\n"
744                 "GtkButton::default-border = { 1, 1, 1, 1 }\n"
745                 "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
746                 "GtkButton::child-displacement-x = 1\n"
747                 "GtkButton::child-displacement-y = 1\n"
748                 "}widget_class \"*Button*\" style \"msw-button\"\n",
749                 btn_face.red, btn_face.green, btn_face.blue,
750                 btn_face.red, btn_face.green, btn_face.blue,
751                 btn_face.red, btn_face.green, btn_face.blue,
752                 btn_fore.red, btn_fore.green, btn_fore.blue);
753     gtk_rc_parse_string (buf);
754
755     /* enable coloring for progress bars */
756     g_snprintf (buf, sizeof (buf),
757                 "style \"msw-progress\" = \"msw-default\"\n"
758                 "{bg[PRELIGHT] = { %d, %d, %d }\n"
759                 "bg[NORMAL] = { %d, %d, %d }\n"
760                 "}widget_class \"*Progress*\" style \"msw-progress\"\n",
761                 progress_back.red,
762                 progress_back.green,
763                 progress_back.blue,
764                 btn_face.red, btn_face.green, btn_face.blue);
765     gtk_rc_parse_string (buf);
766
767     /* scrollbar thumb width and height */
768     g_snprintf (buf, sizeof (buf),
769                 "style \"msw-vscrollbar\" = \"msw-default\"\n"
770                 "{GtkRange::slider-width = %d\n"
771                 "GtkRange::stepper-size = %d\n"
772                 "GtkRange::stepper-spacing = 0\n"
773                 "GtkRange::trough_border = 0\n"
774                 "GtkScale::slider-length = %d\n"
775                 "GtkScrollbar::min-slider-length = 8\n"
776                 "}widget_class \"*VScrollbar*\" style \"msw-vscrollbar\"\n"
777                 "widget_class \"*VScale*\" style \"msw-vscrollbar\"\n",
778                 GetSystemMetrics (SM_CYVTHUMB),
779                 get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CXVSCROLL),
780                 11);
781     gtk_rc_parse_string (buf);
782
783     g_snprintf (buf, sizeof (buf),
784                 "style \"msw-hscrollbar\" = \"msw-default\"\n"
785                 "{GtkRange::slider-width = %d\n"
786                 "GtkRange::stepper-size = %d\n"
787                 "GtkRange::stepper-spacing = 0\n"
788                 "GtkRange::trough_border = 0\n"
789                 "GtkScale::slider-length = %d\n"
790                 "GtkScrollbar::min-slider-length = 8\n"
791                 "}widget_class \"*HScrollbar*\" style \"msw-hscrollbar\"\n"
792                 "widget_class \"*HScale*\" style \"msw-hscrollbar\"\n",
793                 GetSystemMetrics (SM_CXHTHUMB),
794                 get_system_metric (XP_THEME_CLASS_SCROLLBAR, SM_CYHSCROLL),
795                 11);
796     gtk_rc_parse_string (buf);
797
798     /* radio/check button sizes */
799     g_snprintf (buf, sizeof (buf),
800                 "style \"msw-checkbutton\" = \"msw-button\"\n"
801                 "{GtkCheckButton::indicator-size = 13\n"
802                 "}widget_class \"*CheckButton*\" style \"msw-checkbutton\"\n"
803                 "widget_class \"*RadioButton*\" style \"msw-checkbutton\"\n");
804     gtk_rc_parse_string (buf);
805 }
806
807 static void
808 setup_system_styles (GtkStyle * style)
809 {
810     int i;
811
812     /* Default background */
813     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
814                             &style->bg[GTK_STATE_NORMAL]);
815     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
816                             &style->bg[GTK_STATE_SELECTED]);
817     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
818                             &style->bg[GTK_STATE_INSENSITIVE]);
819     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
820                             &style->bg[GTK_STATE_ACTIVE]);
821     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
822                             &style->bg[GTK_STATE_PRELIGHT]);
823
824     /* Default base */
825     sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW,
826                             &style->base[GTK_STATE_NORMAL]);
827     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHT,
828                             &style->base[GTK_STATE_SELECTED]);
829     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
830                             &style->base[GTK_STATE_INSENSITIVE]);
831     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNFACE,
832                             &style->base[GTK_STATE_ACTIVE]);
833     sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOW,
834                             &style->base[GTK_STATE_PRELIGHT]);
835
836     /* Default text */
837     sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
838                             &style->text[GTK_STATE_NORMAL]);
839     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
840                             &style->text[GTK_STATE_SELECTED]);
841     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_GRAYTEXT,
842                             &style->text[GTK_STATE_INSENSITIVE]);
843     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
844                             &style->text[GTK_STATE_ACTIVE]);
845     sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
846                             &style->text[GTK_STATE_PRELIGHT]);
847
848     /* Default foreground */
849     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
850                             &style->fg[GTK_STATE_NORMAL]);
851     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_HIGHLIGHTTEXT,
852                             &style->fg[GTK_STATE_SELECTED]);
853     sys_color_to_gtk_color (XP_THEME_CLASS_TEXT, COLOR_GRAYTEXT,
854                             &style->fg[GTK_STATE_INSENSITIVE]);
855     sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_BTNTEXT,
856                             &style->fg[GTK_STATE_ACTIVE]);
857     sys_color_to_gtk_color (XP_THEME_CLASS_WINDOW, COLOR_WINDOWTEXT,
858                             &style->fg[GTK_STATE_PRELIGHT]);
859
860     for (i = 0; i < 5; i++)
861         {
862             sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DSHADOW,
863                                     &style->dark[i]);
864             sys_color_to_gtk_color (XP_THEME_CLASS_BUTTON, COLOR_3DHILIGHT,
865                                     &style->light[i]);
866
867             style->mid[i].red =
868                 (style->light[i].red + style->dark[i].red) / 2;
869             style->mid[i].green =
870                 (style->light[i].green + style->dark[i].green) / 2;
871             style->mid[i].blue =
872                 (style->light[i].blue + style->dark[i].blue) / 2;
873
874             style->text_aa[i].red =
875                 (style->text[i].red + style->base[i].red) / 2;
876             style->text_aa[i].green =
877                 (style->text[i].green + style->base[i].green) / 2;
878             style->text_aa[i].blue =
879                 (style->text[i].blue + style->base[i].blue) / 2;
880         }
881 }
882
883 static gboolean
884 sanitize_size (GdkWindow * window, gint * width, gint * height)
885 {
886     gboolean set_bg = FALSE;
887
888     if ((*width == -1) && (*height == -1))
889         {
890             set_bg = GDK_IS_WINDOW (window);
891             gdk_drawable_get_size (window, width, height);
892         }
893     else if (*width == -1)
894         gdk_drawable_get_size (window, width, NULL);
895     else if (*height == -1)
896         gdk_drawable_get_size (window, NULL, height);
897
898     return set_bg;
899 }
900
901 static XpThemeElement
902 map_gtk_progress_bar_to_xp (GtkProgressBar * progress_bar, gboolean trough)
903 {
904     XpThemeElement ret;
905
906     switch (progress_bar->orientation)
907         {
908         case GTK_PROGRESS_LEFT_TO_RIGHT:
909         case GTK_PROGRESS_RIGHT_TO_LEFT:
910             ret = trough
911                 ? XP_THEME_ELEMENT_PROGRESS_TROUGH_H
912                 : XP_THEME_ELEMENT_PROGRESS_BAR_H;
913             break;
914         default:
915             ret = trough
916                 ? XP_THEME_ELEMENT_PROGRESS_TROUGH_V
917                 : XP_THEME_ELEMENT_PROGRESS_BAR_V;
918             break;
919         }
920     return ret;
921 }
922
923 static void
924 draw_part (GdkDrawable * drawable,
925            GdkGC * gc, GdkRectangle * area, gint x, gint y, Part part)
926 {
927     if (area)
928         gdk_gc_set_clip_rectangle (gc, area);
929
930     if (!parts[part].bmap)
931         parts[part].bmap = gdk_bitmap_create_from_data (drawable,
932                                                         parts[part].bits,
933                                                         PART_SIZE, PART_SIZE);
934
935     gdk_gc_set_ts_origin (gc, x, y);
936     gdk_gc_set_stipple (gc, parts[part].bmap);
937     gdk_gc_set_fill (gc, GDK_STIPPLED);
938
939     gdk_draw_rectangle (drawable, gc, TRUE, x, y, PART_SIZE, PART_SIZE);
940
941     gdk_gc_set_fill (gc, GDK_SOLID);
942
943     if (area)
944         gdk_gc_set_clip_rectangle (gc, NULL);
945 }
946
947 static void
948 draw_check (GtkStyle * style,
949             GdkWindow * window,
950             GtkStateType state,
951             GtkShadowType shadow,
952             GdkRectangle * area,
953             GtkWidget * widget,
954             const gchar * detail, gint x, gint y, gint width, gint height)
955 {
956     x -= (1 + PART_SIZE - width) / 2;
957     y -= (1 + PART_SIZE - height) / 2;
958
959     if (detail && strcmp (detail, "check") == 0)        /* Menu item */
960         {
961             if (shadow == GTK_SHADOW_IN)
962                 {
963                     draw_part (window, style->black_gc, area, x, y,
964                                CHECK_TEXT);
965                     draw_part (window, style->dark_gc[state], area, x, y,
966                                CHECK_AA);
967                 }
968         }
969     else
970         {
971             if (!xp_theme_draw (window, shadow == GTK_SHADOW_IN
972                                 ? XP_THEME_ELEMENT_PRESSED_CHECKBOX
973                                 : XP_THEME_ELEMENT_CHECKBOX,
974                                 style, x, y, width, height, state, area))
975                 {
976                     draw_part (window, style->black_gc, area, x, y,
977                                CHECK_BLACK);
978                     draw_part (window, style->dark_gc[state], area, x, y,
979                                CHECK_DARK);
980                     draw_part (window, style->mid_gc[state], area, x, y,
981                                CHECK_MID);
982                     draw_part (window, style->light_gc[state], area, x, y,
983                                CHECK_LIGHT);
984                     draw_part (window, style->base_gc[state], area, x, y,
985                                CHECK_BASE);
986
987                     if (shadow == GTK_SHADOW_IN)
988                         {
989                             draw_part (window, style->text_gc[state], area, x,
990                                        y, CHECK_TEXT);
991                             draw_part (window, style->text_aa_gc[state], area,
992                                        x, y, CHECK_AA);
993                         }
994                 }
995         }
996 }
997
998 static void
999 draw_expander (GtkStyle * style,
1000                GdkWindow * window,
1001                GtkStateType state,
1002                GdkRectangle * area,
1003                GtkWidget * widget,
1004                const gchar * detail,
1005                gint x, gint y, GtkExpanderStyle expander_style)
1006 {
1007     gint expander_size;
1008     gint expander_semi_size;
1009     GdkColor color;
1010     GdkGCValues values;
1011     gboolean success;
1012     XpThemeElement xp_expander;
1013
1014     gtk_widget_style_get (widget, "expander_size", &expander_size, NULL);
1015
1016     switch (expander_style)
1017         {
1018         case GTK_EXPANDER_COLLAPSED:
1019         case GTK_EXPANDER_SEMI_COLLAPSED:
1020             xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED;
1021             break;
1022         default:
1023             xp_expander = XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED;
1024             break;
1025         }
1026
1027     if ((expander_size % 2) == 0)
1028         expander_size--;
1029
1030     if (expander_size > 2)
1031         expander_size -= 2;
1032
1033     if (area)
1034         gdk_gc_set_clip_rectangle (style->fg_gc[state], area);
1035
1036     expander_semi_size = expander_size / 2;
1037     x -= expander_semi_size;
1038     y -= expander_semi_size;
1039
1040     gdk_gc_get_values (style->fg_gc[state], &values);
1041
1042     if (!xp_theme_draw (window, xp_expander, style,
1043                         x, y, expander_size, expander_size, state, area))
1044         {
1045             /* RGB values to emulate Windows Classic style */
1046             color.red = color.green = color.blue = 128 << 8;
1047
1048             success = gdk_colormap_alloc_color
1049                 (gtk_widget_get_default_colormap (), &color, FALSE, TRUE);
1050
1051             if (success)
1052                 gdk_gc_set_foreground (style->fg_gc[state], &color);
1053
1054             gdk_draw_rectangle
1055                 (window, style->fg_gc[state], FALSE, x, y,
1056                  expander_size - 1, expander_size - 1);
1057
1058             gdk_draw_line
1059                 (window, style->fg_gc[state], x + 2, y + expander_semi_size,
1060                  x + expander_size - 2, y + expander_semi_size);
1061
1062             switch (expander_style)
1063                 {
1064                 case GTK_EXPANDER_COLLAPSED:
1065                 case GTK_EXPANDER_SEMI_COLLAPSED:
1066                     gdk_draw_line
1067                         (window, style->fg_gc[state], x + expander_semi_size,
1068                          y + 2, x + expander_semi_size,
1069                          y + expander_size - 2);
1070                     break;
1071
1072                 default:
1073                     break;
1074                 }
1075
1076             if (success)
1077                 gdk_gc_set_foreground (style->fg_gc[state],
1078                                        &values.foreground);
1079         }
1080
1081     if (area)
1082         gdk_gc_set_clip_rectangle (style->fg_gc[state], NULL);
1083 }
1084
1085 static void
1086 draw_option (GtkStyle * style,
1087              GdkWindow * window,
1088              GtkStateType state,
1089              GtkShadowType shadow,
1090              GdkRectangle * area,
1091              GtkWidget * widget,
1092              const gchar * detail, gint x, gint y, gint width, gint height)
1093 {
1094     x -= (1 + PART_SIZE - width) / 2;
1095     y -= (1 + PART_SIZE - height) / 2;
1096
1097     if (detail && strcmp (detail, "option") == 0)       /* Menu item */
1098         {
1099             if (shadow == GTK_SHADOW_IN)
1100                 draw_part (window, style->fg_gc[state], area, x, y,
1101                            RADIO_TEXT);
1102         }
1103     else
1104         {
1105             if (xp_theme_draw (window, shadow == GTK_SHADOW_IN
1106                                ? XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON
1107                                : XP_THEME_ELEMENT_RADIO_BUTTON,
1108                                style, x, y, width, height, state, area))
1109                 {
1110                 }
1111             else
1112                 {
1113                     draw_part (window, style->black_gc, area, x, y,
1114                                RADIO_BLACK);
1115                     draw_part (window, style->dark_gc[state], area, x, y,
1116                                RADIO_DARK);
1117                     draw_part (window, style->mid_gc[state], area, x, y,
1118                                RADIO_MID);
1119                     draw_part (window, style->light_gc[state], area, x, y,
1120                                RADIO_LIGHT);
1121                     draw_part (window, style->base_gc[state], area, x, y,
1122                                RADIO_BASE);
1123
1124                     if (shadow == GTK_SHADOW_IN)
1125                         draw_part (window, style->text_gc[state], area, x, y,
1126                                    RADIO_TEXT);
1127                 }
1128         }
1129 }
1130
1131 static void
1132 draw_varrow (GdkWindow * window,
1133              GdkGC * gc,
1134              GtkShadowType shadow_type,
1135              GdkRectangle * area,
1136              GtkArrowType arrow_type, gint x, gint y, gint width, gint height)
1137 {
1138     gint steps, extra;
1139     gint y_start, y_increment;
1140     gint i;
1141
1142     if (area)
1143         gdk_gc_set_clip_rectangle (gc, area);
1144
1145     width = width + width % 2 - 1;      /* Force odd */
1146     steps = 1 + width / 2;
1147     extra = height - steps;
1148
1149     if (arrow_type == GTK_ARROW_DOWN)
1150         {
1151             y_start = y;
1152             y_increment = 1;
1153         }
1154     else
1155         {
1156             y_start = y + height - 1;
1157             y_increment = -1;
1158         }
1159
1160     for (i = extra; i < height; i++)
1161         {
1162             gdk_draw_line (window, gc,
1163                            x + (i - extra), y_start + i * y_increment,
1164                            x + width - (i - extra) - 1,
1165                            y_start + i * y_increment);
1166         }
1167
1168     if (area)
1169         gdk_gc_set_clip_rectangle (gc, NULL);
1170 }
1171
1172 static void
1173 draw_harrow (GdkWindow * window,
1174              GdkGC * gc,
1175              GtkShadowType shadow_type,
1176              GdkRectangle * area,
1177              GtkArrowType arrow_type, gint x, gint y, gint width, gint height)
1178 {
1179     gint steps, extra;
1180     gint x_start, x_increment;
1181     gint i;
1182
1183     if (area)
1184         gdk_gc_set_clip_rectangle (gc, area);
1185
1186     height = height + height % 2 - 1;   /* Force odd */
1187     steps = 1 + height / 2;
1188     extra = width - steps;
1189
1190     if (arrow_type == GTK_ARROW_RIGHT)
1191         {
1192             x_start = x;
1193             x_increment = 1;
1194         }
1195     else
1196         {
1197             x_start = x + width - 1;
1198             x_increment = -1;
1199         }
1200
1201     for (i = extra; i < width; i++)
1202         {
1203             gdk_draw_line (window, gc,
1204                            x_start + i * x_increment, y + (i - extra),
1205                            x_start + i * x_increment,
1206                            y + height - (i - extra) - 1);
1207         }
1208
1209
1210     if (area)
1211         gdk_gc_set_clip_rectangle (gc, NULL);
1212 }
1213
1214 /* This function makes up for some brokeness in gtkrange.c
1215  * where we never get the full arrow of the stepper button
1216  * and the type of button in a single drawing function.
1217  *
1218  * It doesn't work correctly when the scrollbar is squished
1219  * to the point we don't have room for full-sized steppers.
1220  */
1221 static void
1222 reverse_engineer_stepper_box (GtkWidget * range,
1223                               GtkArrowType arrow_type,
1224                               gint * x, gint * y, gint * width, gint * height)
1225 {
1226     gint slider_width = 14, stepper_size = 14;
1227     gint box_width;
1228     gint box_height;
1229
1230     if (range)
1231         {
1232             gtk_widget_style_get (range,
1233                                   "slider_width", &slider_width,
1234                                   "stepper_size", &stepper_size, NULL);
1235         }
1236
1237     if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
1238         {
1239             box_width = slider_width;
1240             box_height = stepper_size;
1241         }
1242     else
1243         {
1244             box_width = stepper_size;
1245             box_height = slider_width;
1246         }
1247
1248     *x = *x - (box_width - *width) / 2;
1249     *y = *y - (box_height - *height) / 2;
1250     *width = box_width;
1251     *height = box_height;
1252 }
1253
1254 static XpThemeElement
1255 to_xp_arrow (GtkArrowType arrow_type)
1256 {
1257     XpThemeElement xp_arrow;
1258
1259     switch (arrow_type)
1260         {
1261         case GTK_ARROW_UP:
1262             xp_arrow = XP_THEME_ELEMENT_ARROW_UP;
1263             break;
1264         case GTK_ARROW_DOWN:
1265             xp_arrow = XP_THEME_ELEMENT_ARROW_DOWN;
1266             break;
1267         case GTK_ARROW_LEFT:
1268             xp_arrow = XP_THEME_ELEMENT_ARROW_LEFT;
1269             break;
1270         default:
1271             xp_arrow = XP_THEME_ELEMENT_ARROW_RIGHT;
1272             break;
1273         }
1274
1275     return xp_arrow;
1276 }
1277
1278 static void
1279 draw_arrow (GtkStyle * style,
1280             GdkWindow * window,
1281             GtkStateType state,
1282             GtkShadowType shadow,
1283             GdkRectangle * area,
1284             GtkWidget * widget,
1285             const gchar * detail,
1286             GtkArrowType arrow_type,
1287             gboolean fill, gint x, gint y, gint width, gint height)
1288 {
1289     const gchar *name;
1290
1291     name = gtk_widget_get_name (widget);
1292
1293     sanitize_size (window, &width, &height);
1294
1295     if (detail && strcmp (detail, "spinbutton") == 0)
1296         {
1297             if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP))
1298                 {
1299                     return;
1300                 }
1301             else
1302                 {
1303                     x += (width - 7) / 2;
1304
1305                     if (arrow_type == GTK_ARROW_UP)
1306                         y += (height - 4) / 2;
1307                     else
1308                         y += (1 + height - 4) / 2;
1309                     draw_varrow (window, style->fg_gc[state], shadow, area,
1310                                  arrow_type, x, y, 7, 4);
1311                 }
1312         }
1313     else if (detail && (!strcmp (detail, "vscrollbar")
1314                         || !strcmp (detail, "hscrollbar")))
1315         {
1316             gboolean is_disabled = FALSE;
1317             GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget);
1318             gint box_x = x;
1319             gint box_y = y;
1320             gint box_width = width;
1321             gint box_height = height;
1322
1323             reverse_engineer_stepper_box (widget, arrow_type,
1324                                           &box_x, &box_y, &box_width,
1325                                           &box_height);
1326
1327             if (scrollbar->range.adjustment->page_size >=
1328                 (scrollbar->range.adjustment->upper -
1329                  scrollbar->range.adjustment->lower))
1330                 is_disabled = TRUE;
1331
1332             if (xp_theme_draw
1333                 (window, to_xp_arrow (arrow_type), style, box_x, box_y,
1334                  box_width, box_height, state, area))
1335                 {
1336                 }
1337             else if (arrow_type == GTK_ARROW_UP
1338                      || arrow_type == GTK_ARROW_DOWN)
1339                 {
1340                     x += (width - 7) / 2;
1341                     y += (height - 5) / 2;
1342
1343                     draw_varrow (window,
1344                                  is_disabled ? style->
1345                                  text_aa_gc[state] : style->fg_gc[state],
1346                                  shadow, area, arrow_type, x, y, 7, 5);
1347                 }
1348             else
1349                 {
1350                     y += (height - 7) / 2;
1351                     x += (width - 5) / 2;
1352
1353                     draw_harrow (window,
1354                                  is_disabled ? style->
1355                                  text_aa_gc[state] : style->fg_gc[state],
1356                                  shadow, area, arrow_type, x, y, 5, 7);
1357                 }
1358         }
1359     else
1360         {
1361             /* draw the toolbar chevrons - waiting for GTK 2.4 */
1362             if (name && !strcmp (name, "gtk-toolbar-arrow"))
1363                 {
1364                     if (xp_theme_draw
1365                         (window, XP_THEME_ELEMENT_REBAR_CHEVRON, style, x, y,
1366                          width, height, state, area))
1367                         return;
1368                 }
1369             /* probably a gtk combo box on a toolbar */
1370             else if (0          /* widget->parent && GTK_IS_BUTTON
1371                                    (widget->parent) */ )
1372                 {
1373                     if (xp_theme_draw
1374                         (window, XP_THEME_ELEMENT_COMBOBUTTON, style, x - 3,
1375                          widget->allocation.y + 1, width + 5,
1376                          widget->allocation.height - 4, state, area))
1377                         return;
1378                 }
1379
1380             if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
1381                 {
1382                     x += (width - 7) / 2;
1383                     y += (height - 5) / 2;
1384
1385                     draw_varrow (window, style->fg_gc[state], shadow, area,
1386                                  arrow_type, x, y, 7, 5);
1387                 }
1388             else
1389                 {
1390                     x += (width - 5) / 2;
1391                     y += (height - 7) / 2;
1392
1393                     draw_harrow (window, style->fg_gc[state], shadow, area,
1394                                  arrow_type, x, y, 5, 7);
1395                 }
1396         }
1397 }
1398
1399 static void
1400 option_menu_get_props (GtkWidget * widget,
1401                        GtkRequisition * indicator_size,
1402                        GtkBorder * indicator_spacing)
1403 {
1404     GtkRequisition *tmp_size = NULL;
1405     GtkBorder *tmp_spacing = NULL;
1406
1407     if (widget)
1408         gtk_widget_style_get (widget,
1409                               "indicator_size", &tmp_size,
1410                               "indicator_spacing", &tmp_spacing, NULL);
1411
1412     if (tmp_size)
1413         {
1414             *indicator_size = *tmp_size;
1415             g_free (tmp_size);
1416         }
1417     else
1418         *indicator_size = default_option_indicator_size;
1419
1420     if (tmp_spacing)
1421         {
1422             *indicator_spacing = *tmp_spacing;
1423             g_free (tmp_spacing);
1424         }
1425     else
1426         *indicator_spacing = default_option_indicator_spacing;
1427 }
1428
1429 static gboolean
1430 is_toolbar_child (GtkWidget * wid)
1431 {
1432     while (wid)
1433         {
1434             if (GTK_IS_TOOLBAR (wid) || GTK_IS_HANDLE_BOX (wid))
1435                 return TRUE;
1436             else
1437                 wid = wid->parent;
1438         }
1439
1440     return FALSE;
1441 }
1442
1443 static void
1444 draw_box (GtkStyle * style,
1445           GdkWindow * window,
1446           GtkStateType state_type,
1447           GtkShadowType shadow_type,
1448           GdkRectangle * area,
1449           GtkWidget * widget,
1450           const gchar * detail, gint x, gint y, gint width, gint height)
1451 {
1452     if (detail &&
1453         (!strcmp (detail, "button") || !strcmp (detail, "buttondefault")))
1454         {
1455             if (GTK_IS_TREE_VIEW (widget->parent)
1456                 || GTK_IS_CLIST (widget->parent))
1457                 {
1458                     if (xp_theme_draw
1459                         (window, XP_THEME_ELEMENT_LIST_HEADER, style, x, y,
1460                          width, height, state_type, area))
1461                         return;
1462                 }
1463             else if (is_toolbar_child (widget->parent))
1464                 {
1465                     if (xp_theme_draw
1466                         (window, XP_THEME_ELEMENT_TOOLBAR_BUTTON, style, x, y,
1467                          width, height, state_type, area))
1468                         return;
1469                 }
1470             else
1471                 {
1472                     gboolean is_default = !strcmp (detail, "buttondefault");
1473
1474                     if (xp_theme_draw
1475                         (window,
1476                          is_default ? XP_THEME_ELEMENT_DEFAULT_BUTTON :
1477                          XP_THEME_ELEMENT_BUTTON, style, x, y, width, height,
1478                          state_type, area))
1479                         return;
1480                 }
1481         }
1482     else if (detail && !strcmp (detail, "spinbutton"))
1483         {
1484             if (xp_theme_is_drawable (XP_THEME_ELEMENT_SPIN_BUTTON_UP))
1485                 {
1486                     return;
1487                 }
1488         }
1489     else if (detail && (!strcmp (detail, "spinbutton_up")
1490                         || !strcmp (detail, "spinbutton_down")))
1491         {
1492             if (xp_theme_draw (window,
1493                                (!strcmp (detail, "spinbutton_up"))
1494                                ? XP_THEME_ELEMENT_SPIN_BUTTON_UP
1495                                : XP_THEME_ELEMENT_SPIN_BUTTON_DOWN,
1496                                style, x, y, width, height, state_type, area))
1497                 {
1498                     return;
1499                 }
1500         }
1501     else if (detail && !strcmp (detail, "slider"))
1502         {
1503             if (GTK_IS_SCROLLBAR (widget))
1504                 {
1505                     GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget);
1506                     gboolean is_v = GTK_IS_VSCROLLBAR (widget);
1507
1508                     if (xp_theme_draw (window,
1509                                        is_v
1510                                        ? XP_THEME_ELEMENT_SCROLLBAR_V
1511                                        : XP_THEME_ELEMENT_SCROLLBAR_H,
1512                                        style, x, y, width, height, state_type,
1513                                        area))
1514                         {
1515                             XpThemeElement gripper =
1516                                 (is_v ? XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V :
1517                                  XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H);
1518
1519                             /* Do not display grippers on tiny scroll bars,
1520                                the limit imposed is rather arbitrary, perhaps 
1521                                we can fetch the gripper geometry from
1522                                somewhere and use that... */
1523                             if ((gripper ==
1524                                  XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H
1525                                  && width < 16)
1526                                 || (gripper ==
1527                                     XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V
1528                                     && height < 16))
1529                                 {
1530                                     return;
1531                                 }
1532
1533                             xp_theme_draw (window, gripper, style, x, y,
1534                                            width, height, state_type, area);
1535                             return;
1536                         }
1537                     else
1538                         {
1539                             if (scrollbar->range.adjustment->page_size >=
1540                                 (scrollbar->range.adjustment->upper -
1541                                  scrollbar->range.adjustment->lower))
1542                                 return;
1543                         }
1544                 }
1545         }
1546     else if (detail && !strcmp (detail, "bar"))
1547         {
1548             if (widget && GTK_IS_PROGRESS_BAR (widget))
1549                 {
1550                     GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget);
1551                     XpThemeElement xp_progress_bar =
1552                         map_gtk_progress_bar_to_xp (progress_bar, FALSE);
1553                     if (xp_theme_draw
1554                         (window, xp_progress_bar, style, x, y, width, height,
1555                          state_type, area))
1556                         {
1557                             return;
1558                         }
1559                 }
1560         }
1561     else if (detail && strcmp (detail, "menuitem") == 0)
1562         {
1563             shadow_type = GTK_SHADOW_NONE;
1564             if (xp_theme_draw
1565                 (window, XP_THEME_ELEMENT_MENU_ITEM, style, x, y, width,
1566                  height, state_type, area))
1567                 {
1568                     return;
1569                 }
1570         }
1571     else if (detail && !strcmp (detail, "trough"))
1572         {
1573             if (widget && GTK_IS_PROGRESS_BAR (widget))
1574                 {
1575                     GtkProgressBar *progress_bar = GTK_PROGRESS_BAR (widget);
1576                     XpThemeElement xp_progress_bar =
1577                         map_gtk_progress_bar_to_xp (progress_bar, TRUE);
1578                     if (xp_theme_draw
1579                         (window, xp_progress_bar, style, x, y, width, height,
1580                          state_type, area))
1581                         {
1582                             return;
1583                         }
1584                     else
1585                         {
1586                             /* Blank in classic Windows */
1587                         }
1588                 }
1589             else if (widget && GTK_IS_SCROLLBAR (widget))
1590                 {
1591                     gboolean is_vertical = GTK_IS_VSCROLLBAR (widget);
1592
1593                     if (xp_theme_draw (window,
1594                                        is_vertical
1595                                        ? XP_THEME_ELEMENT_TROUGH_V
1596                                        : XP_THEME_ELEMENT_TROUGH_H,
1597                                        style,
1598                                        x, y, width, height, state_type, area))
1599                         {
1600                             return;
1601                         }
1602                     else
1603                         {
1604                             GdkGCValues gc_values;
1605                             GdkGC *gc;
1606                             GdkPixmap *pixmap;
1607
1608                             sanitize_size (window, &width, &height);
1609
1610                             pixmap = gdk_pixmap_new (window, 2, 2, -1);
1611
1612                             gdk_draw_point (pixmap,
1613                                             style->bg_gc[GTK_STATE_NORMAL], 0,
1614                                             0);
1615                             gdk_draw_point (pixmap,
1616                                             style->bg_gc[GTK_STATE_NORMAL], 1,
1617                                             1);
1618                             gdk_draw_point (pixmap,
1619                                             style->light_gc[GTK_STATE_NORMAL],
1620                                             1, 0);
1621                             gdk_draw_point (pixmap,
1622                                             style->light_gc[GTK_STATE_NORMAL],
1623                                             0, 1);
1624
1625                             gc_values.fill = GDK_TILED;
1626                             gc_values.tile = pixmap;
1627                             gc_values.ts_x_origin = x;
1628                             gc_values.ts_y_origin = y;
1629                             gc = gdk_gc_new_with_values (window, &gc_values,
1630                                                          GDK_GC_TS_X_ORIGIN |
1631                                                          GDK_GC_TS_Y_ORIGIN |
1632                                                          GDK_GC_FILL |
1633                                                          GDK_GC_TILE);
1634
1635                             if (area)
1636                                 gdk_gc_set_clip_rectangle (gc, area);
1637
1638                             gdk_draw_rectangle (window, gc, TRUE, x, y, width,
1639                                                 height);
1640
1641                             g_object_unref (gc);
1642                             g_object_unref (pixmap);
1643
1644                             return;
1645                         }
1646                 }
1647             else if (widget && GTK_IS_SCALE (widget))
1648                 {
1649                     gboolean is_vertical = GTK_IS_VSCALE (widget);
1650
1651                     if (!xp_theme_is_active ())
1652                         {
1653                             parent_class->draw_box (style, window, state_type,
1654                                                     GTK_SHADOW_NONE, area,
1655                                                     widget, detail, x, y,
1656                                                     width, height);
1657                         }
1658
1659                     if (is_vertical)
1660                         {
1661                             if (xp_theme_draw
1662                                 (window, XP_THEME_ELEMENT_SCALE_TROUGH_V,
1663                                  style, (2 * x + width) / 2, y, 2, height,
1664                                  state_type, area))
1665                                 return;
1666
1667                             parent_class->draw_box (style, window, state_type,
1668                                                     GTK_SHADOW_ETCHED_IN,
1669                                                     area, NULL, NULL,
1670                                                     (2 * x + width) / 2, y, 1,
1671                                                     height);
1672                         }
1673                     else
1674                         {
1675                             if (xp_theme_draw
1676                                 (window, XP_THEME_ELEMENT_SCALE_TROUGH_H,
1677                                  style, x, (2 * y + height) / 2, width, 2,
1678                                  state_type, area))
1679                                 return;
1680
1681                             parent_class->draw_box (style, window, state_type,
1682                                                     GTK_SHADOW_ETCHED_IN,
1683                                                     area, NULL, NULL, x,
1684                                                     (2 * y + height) / 2,
1685                                                     width, 1);
1686                         }
1687                     return;
1688                 }
1689         }
1690     else if (detail && strcmp (detail, "optionmenu") == 0)
1691         {
1692             if (xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT,
1693                                style, x, y, width, height, state_type, area))
1694                 {
1695                     return;
1696                 }
1697         }
1698     else if (detail
1699              && (strcmp (detail, "vscrollbar") == 0
1700                  || strcmp (detail, "hscrollbar") == 0))
1701         {
1702             GtkScrollbar *scrollbar = GTK_SCROLLBAR (widget);
1703
1704             if (shadow_type == GTK_SHADOW_IN)
1705                 shadow_type = GTK_SHADOW_ETCHED_IN;
1706             if (scrollbar->range.adjustment->page_size >=
1707                 (scrollbar->range.adjustment->upper -
1708                  scrollbar->range.adjustment->lower))
1709                 shadow_type = GTK_SHADOW_OUT;
1710         }
1711     else if (detail
1712              && (strcmp (detail, "handlebox_bin") == 0
1713                  || strcmp (detail, "toolbar") == 0
1714                  || strcmp (detail, "menubar") == 0))
1715         {
1716             if (xp_theme_draw (window, XP_THEME_ELEMENT_REBAR,
1717                                style, x, y, width, height, state_type, area))
1718                 {
1719                     return;
1720                 }
1721         }
1722     else if (detail && (!strcmp (detail, "handlebox"))) /* grip */
1723         {
1724         }
1725     else
1726         {
1727             const gchar *name = gtk_widget_get_name (widget);
1728
1729             if (name && !strcmp (name, "gtk-tooltips"))
1730                 {
1731                     if (xp_theme_draw
1732                         (window, XP_THEME_ELEMENT_TOOLTIP, style, x, y, width,
1733                          height, state_type, area))
1734                         {
1735                             return;
1736                         }
1737                     else
1738                         {
1739                             HBRUSH brush;
1740                             gint xoff, yoff;
1741                             GdkDrawable *drawable;
1742                             RECT rect;
1743                             HDC hdc;
1744
1745                             if (!GDK_IS_WINDOW (window))
1746                                 {
1747                                     xoff = 0;
1748                                     yoff = 0;
1749                                     drawable = window;
1750                                 }
1751                             else
1752                                 {
1753                                     gdk_window_get_internal_paint_info
1754                                         (window, &drawable, &xoff, &yoff);
1755                                 }
1756
1757                             rect.left = x - xoff;
1758                             rect.top = y - yoff;
1759                             rect.right = rect.left + width;
1760                             rect.bottom = rect.top + height;
1761
1762                             hdc =
1763                                 gdk_win32_hdc_get (window,
1764                                                    style->dark_gc[state_type],
1765                                                    0);
1766                             brush = GetSysColorBrush (COLOR_3DDKSHADOW);
1767                             if (brush)
1768                                 FrameRect (hdc, &rect, brush);
1769                             InflateRect (&rect, -1, -1);
1770                             FillRect (hdc, &rect,
1771                                       (HBRUSH) (COLOR_INFOBK + 1));
1772
1773                             return;
1774                         }
1775
1776                 }
1777         }
1778
1779     parent_class->draw_box (style, window, state_type, shadow_type, area,
1780                             widget, detail, x, y, width, height);
1781
1782     if (detail && strcmp (detail, "optionmenu") == 0)
1783         {
1784             GtkRequisition indicator_size;
1785             GtkBorder indicator_spacing;
1786             gint vline_x;
1787
1788             option_menu_get_props (widget, &indicator_size,
1789                                    &indicator_spacing);
1790
1791             sanitize_size (window, &width, &height);
1792
1793             if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1794                 vline_x =
1795                     x + indicator_size.width + indicator_spacing.left +
1796                     indicator_spacing.right;
1797             else
1798                 vline_x =
1799                     x + width - (indicator_size.width +
1800                                  indicator_spacing.left +
1801                                  indicator_spacing.right) - style->xthickness;
1802
1803             parent_class->draw_vline (style, window, state_type, area, widget,
1804                                       detail,
1805                                       y + style->ythickness + 1,
1806                                       y + height - style->ythickness - 3,
1807                                       vline_x);
1808         }
1809 }
1810
1811 static void
1812 draw_tab (GtkStyle * style,
1813           GdkWindow * window,
1814           GtkStateType state,
1815           GtkShadowType shadow,
1816           GdkRectangle * area,
1817           GtkWidget * widget,
1818           const gchar * detail, gint x, gint y, gint width, gint height)
1819 {
1820     GtkRequisition indicator_size;
1821     GtkBorder indicator_spacing;
1822
1823     gint arrow_height;
1824
1825     g_return_if_fail (style != NULL);
1826     g_return_if_fail (window != NULL);
1827
1828     if (detail && !strcmp (detail, "optionmenutab"))
1829         {
1830             if (xp_theme_draw (window, XP_THEME_ELEMENT_COMBOBUTTON,
1831                                style, x - 5, widget->allocation.y + 1,
1832                                width + 10, widget->allocation.height - 2,
1833                                state, area))
1834                 {
1835                     return;
1836                 }
1837         }
1838
1839     if (widget)
1840         gtk_widget_style_get (widget, "indicator_size", &indicator_size,
1841                               NULL);
1842
1843     option_menu_get_props (widget, &indicator_size, &indicator_spacing);
1844
1845     x += (width - indicator_size.width) / 2;
1846     arrow_height = (indicator_size.width + 1) / 2;
1847
1848     y += (height - arrow_height) / 2;
1849
1850     draw_varrow (window, style->black_gc, shadow, area, GTK_ARROW_DOWN,
1851                  x, y, indicator_size.width, arrow_height);
1852 }
1853
1854 /* this is an undefined magic value that, according to the mozilla folks,
1855    worked for all the various themes that they tried */
1856 #define XP_EDGE_SIZE 2
1857
1858 static void
1859 draw_extension (GtkStyle * style,
1860                 GdkWindow * window,
1861                 GtkStateType state_type,
1862                 GtkShadowType shadow_type,
1863                 GdkRectangle * area,
1864                 GtkWidget * widget,
1865                 const gchar * detail,
1866                 gint x,
1867                 gint y, gint width, gint height, GtkPositionType gap_side)
1868 {
1869     if (GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "tab"))
1870         {
1871             GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1872             gint x2, y2, w2, h2;
1873
1874             x2 = x;
1875             y2 = y;
1876             w2 = width;
1877             h2 = height;
1878             if (gap_side == GTK_POS_TOP && state_type == GTK_STATE_NORMAL)
1879                 {
1880                     /* h2 += XP_EDGE_SIZE; */
1881                 }
1882             else if (gap_side == GTK_POS_BOTTOM
1883                      && state_type == GTK_STATE_NORMAL)
1884                 {
1885                     /* h2 += XP_EDGE_SIZE; */
1886                 }
1887             else if (gap_side == GTK_POS_LEFT
1888                      && state_type == GTK_STATE_NORMAL)
1889                 {
1890                     x2 += 1;
1891                     w2 -= XP_EDGE_SIZE;
1892                 }
1893             else if (gap_side == GTK_POS_RIGHT
1894                      && state_type == GTK_STATE_NORMAL)
1895                 {
1896                     w2 -= (XP_EDGE_SIZE + 1);
1897                 }
1898
1899             if (xp_theme_draw
1900                 (window, gtk_notebook_get_current_page (notebook) == 0
1901                  ? XP_THEME_ELEMENT_TAB_ITEM_LEFT_EDGE
1902                  : XP_THEME_ELEMENT_TAB_ITEM,
1903                  style, x2, y2, w2, h2, state_type, area))
1904                 {
1905                     return;
1906                 }
1907         }
1908     parent_class->draw_extension
1909         (style, window, state_type, shadow_type, area, widget, detail,
1910          x, y, width, height, gap_side);
1911 }
1912
1913 static void
1914 draw_box_gap (GtkStyle * style, GdkWindow * window, GtkStateType state_type,
1915               GtkShadowType shadow_type, GdkRectangle * area,
1916               GtkWidget * widget, const gchar * detail, gint x,
1917               gint y, gint width, gint height, GtkPositionType gap_side,
1918               gint gap_x, gint gap_width)
1919 {
1920     if (GTK_IS_NOTEBOOK (widget) && detail && !strcmp (detail, "notebook"))
1921         {
1922             /* FIXME: pos != TOP to be implemented */
1923             if (gap_side == GTK_POS_TOP
1924                 && xp_theme_draw (window, XP_THEME_ELEMENT_TAB_PANE, style, x,
1925                                   y, width, height, state_type, area))
1926                 {
1927                     return;
1928                 }
1929         }
1930     parent_class->draw_box_gap (style, window, state_type, shadow_type,
1931                                 area, widget, detail, x, y, width, height,
1932                                 gap_side, gap_x, gap_width);
1933 }
1934
1935 static void
1936 draw_flat_box (GtkStyle * style, GdkWindow * window,
1937                GtkStateType state_type, GtkShadowType shadow_type,
1938                GdkRectangle * area, GtkWidget * widget,
1939                const gchar * detail, gint x, gint y, gint width, gint height)
1940 {
1941     if (detail && !strcmp (detail, "checkbutton"))
1942         {
1943             if (state_type == GTK_STATE_PRELIGHT)
1944                 {
1945                     return;
1946                 }
1947         }
1948
1949     parent_class->draw_flat_box (style, window, state_type, shadow_type,
1950                                  area, widget, detail, x, y, width, height);
1951 }
1952
1953 static void
1954 draw_shadow (GtkStyle * style,
1955              GdkWindow * window,
1956              GtkStateType state_type,
1957              GtkShadowType shadow_type,
1958              GdkRectangle * area,
1959              GtkWidget * widget,
1960              const gchar * detail, gint x, gint y, gint width, gint height)
1961 {
1962     gboolean is_handlebox_grippie = (detail && !strcmp (detail, "handlebox"));
1963
1964     if (detail && !strcmp (detail, "entry"))
1965         {
1966             if (xp_theme_draw (window, XP_THEME_ELEMENT_EDIT_TEXT, style,
1967                                x, y, width, height, state_type, area))
1968                 {
1969                     return;
1970                 }
1971         }
1972
1973     if (is_handlebox_grippie
1974         || (widget && (shadow_type == GTK_SHADOW_ETCHED_IN)
1975             && (GTK_IS_MENU_BAR (widget) || GTK_IS_TOOLBAR (widget)
1976                 || GTK_IS_HANDLE_BOX (widget))))
1977         {
1978             GdkGC *gc1 = NULL;
1979             GdkGC *gc2 = NULL;
1980             gint thickness_light;
1981             gint thickness_dark;
1982             gint i;
1983
1984             gc1 = style->light_gc[state_type];
1985             gc2 = style->dark_gc[state_type];
1986
1987             sanitize_size (window, &width, &height);
1988
1989             if (area)
1990                 {
1991                     gdk_gc_set_clip_rectangle (gc1, area);
1992                     gdk_gc_set_clip_rectangle (gc2, area);
1993                     if (shadow_type == GTK_SHADOW_IN ||
1994                         shadow_type == GTK_SHADOW_OUT)
1995                         {
1996                             gdk_gc_set_clip_rectangle (style->black_gc, area);
1997                             gdk_gc_set_clip_rectangle (style->
1998                                                        bg_gc[state_type],
1999                                                        area);
2000                         }
2001                 }
2002
2003             if (style->xthickness > 0)
2004                 {
2005                     if (style->xthickness > 1)
2006                         {
2007                             thickness_light = 1;
2008                             thickness_dark = 1;
2009
2010                             for (i = 0; i < thickness_dark; i++)
2011                                 {
2012                                     if (!is_handlebox_grippie)
2013                                         gdk_draw_line (window, gc1,
2014                                                        x + width - i - 1,
2015                                                        y + i,
2016                                                        x + width - i - 1,
2017                                                        y + height - i - 1);
2018                                     if (is_handlebox_grippie
2019                                         || (widget
2020                                             && GTK_IS_MENU_BAR (widget)))
2021                                         gdk_draw_line (window, gc2, x + i,
2022                                                        y + i, x + i,
2023                                                        y + height - i - 1);
2024                                 }
2025
2026                             for (i = 0; i < thickness_light; i++)
2027                                 {
2028                                     if (is_handlebox_grippie
2029                                         || (widget
2030                                             && GTK_IS_MENU_BAR (widget)))
2031                                         gdk_draw_line (window, gc1,
2032                                                        x + thickness_dark + i,
2033                                                        y + thickness_dark + i,
2034                                                        x + thickness_dark + i,
2035                                                        y + height -
2036                                                        thickness_dark - i -
2037                                                        1);
2038                                     if (!is_handlebox_grippie)
2039                                         gdk_draw_line (window, gc2,
2040                                                        x + width -
2041                                                        thickness_light - i -
2042                                                        1,
2043                                                        y + thickness_dark + i,
2044                                                        x + width -
2045                                                        thickness_light - i -
2046                                                        1,
2047                                                        y + height -
2048                                                        thickness_light - 1);
2049                                 }
2050                         }
2051                     else
2052                         {
2053                             gdk_draw_line (window,
2054                                            style->dark_gc[state_type],
2055                                            x, y, x, y + height);
2056                             gdk_draw_line (window,
2057                                            style->dark_gc[state_type],
2058                                            x + width, y, x + width,
2059                                            y + height);
2060                         }
2061                 }
2062
2063             if (style->ythickness > 0)
2064                 {
2065                     if (style->ythickness > 1)
2066                         {
2067                             thickness_light = 1;
2068                             thickness_dark = 1;
2069
2070                             for (i = 0; i < thickness_dark; i++)
2071                                 {
2072                                     gdk_draw_line (window, gc1,
2073                                                    x + i,
2074                                                    y + height - i - 1,
2075                                                    x + width - i - 1,
2076                                                    y + height - i - 1);
2077
2078                                     if (widget && GTK_IS_MENU_BAR (widget))
2079                                         gdk_draw_line (window, gc2,
2080                                                        x + i,
2081                                                        y + i,
2082                                                        x + width - i - 2,
2083                                                        y + i);
2084                                 }
2085
2086                             for (i = 0; i < thickness_light; i++)
2087                                 {
2088                                     gdk_draw_line (window, gc2,
2089                                                    x + thickness_dark + i,
2090                                                    y + height -
2091                                                    thickness_light - i - 1,
2092                                                    x + width -
2093                                                    thickness_light - 1,
2094                                                    y + height -
2095                                                    thickness_light - i - 1);
2096
2097                                     if (widget && GTK_IS_MENU_BAR (widget))
2098                                         gdk_draw_line (window, gc1,
2099                                                        x + thickness_dark + i,
2100                                                        y + thickness_dark + i,
2101                                                        x + width -
2102                                                        thickness_dark - i - 2,
2103                                                        y + thickness_dark +
2104                                                        i);
2105                                 }
2106                         }
2107                     else
2108                         {
2109                             gdk_draw_line (window,
2110                                            style->dark_gc[state_type],
2111                                            x, y, x + width, y);
2112
2113                             gdk_draw_line (window,
2114                                            style->dark_gc[state_type],
2115                                            x, y + height, x + width,
2116                                            y + height);
2117
2118                         }
2119                 }
2120
2121             if (area)
2122                 {
2123                     gdk_gc_set_clip_rectangle (gc1, NULL);
2124                     gdk_gc_set_clip_rectangle (gc2, NULL);
2125                     if (shadow_type == GTK_SHADOW_IN ||
2126                         shadow_type == GTK_SHADOW_OUT)
2127                         {
2128                             gdk_gc_set_clip_rectangle (style->black_gc, NULL);
2129                             gdk_gc_set_clip_rectangle (style->
2130                                                        bg_gc[state_type],
2131                                                        NULL);
2132                         }
2133                 }
2134
2135             return;
2136         }
2137     parent_class->draw_shadow (style, window, state_type, shadow_type, area,
2138                                widget, detail, x, y, width, height);
2139 }
2140
2141 static void
2142 draw_hline (GtkStyle * style,
2143             GdkWindow * window,
2144             GtkStateType state_type,
2145             GdkRectangle * area,
2146             GtkWidget * widget,
2147             const gchar * detail, gint x1, gint x2, gint y)
2148 {
2149     parent_class->draw_hline (style, window, state_type, area, widget,
2150                               detail, x1, x2, y);
2151 }
2152
2153 static void
2154 draw_vline (GtkStyle * style,
2155             GdkWindow * window,
2156             GtkStateType state_type,
2157             GdkRectangle * area,
2158             GtkWidget * widget,
2159             const gchar * detail, gint y1, gint y2, gint x)
2160 {
2161     parent_class->draw_vline (style, window, state_type, area, widget,
2162                               detail, y1, y2, x);
2163 }
2164
2165 static void
2166 draw_slider (GtkStyle * style,
2167              GdkWindow * window,
2168              GtkStateType state_type,
2169              GtkShadowType shadow_type,
2170              GdkRectangle * area,
2171              GtkWidget * widget,
2172              const gchar * detail,
2173              gint x,
2174              gint y, gint width, gint height, GtkOrientation orientation)
2175 {
2176     if (GTK_IS_SCALE (widget) &&
2177         xp_theme_draw (window,
2178                        ((orientation ==
2179                          GTK_ORIENTATION_VERTICAL) ?
2180                         XP_THEME_ELEMENT_SCALE_SLIDER_V :
2181                         XP_THEME_ELEMENT_SCALE_SLIDER_H), style, x, y, width,
2182                        height, state_type, area))
2183         {
2184             return;
2185         }
2186
2187     parent_class->draw_slider (style, window, state_type, shadow_type, area,
2188                                widget, detail, x, y, width, height,
2189                                orientation);
2190 }
2191
2192 static void
2193 draw_resize_grip (GtkStyle * style,
2194                   GdkWindow * window,
2195                   GtkStateType state_type,
2196                   GdkRectangle * area,
2197                   GtkWidget * widget,
2198                   const gchar * detail,
2199                   GdkWindowEdge edge, gint x, gint y, gint width, gint height)
2200 {
2201     if (detail && !strcmp (detail, "statusbar"))
2202         {
2203             if (xp_theme_draw
2204                 (window, XP_THEME_ELEMENT_STATUS_GRIPPER, style, x, y, width,
2205                  height, state_type, area))
2206                 return;
2207         }
2208
2209     parent_class->draw_resize_grip (style, window, state_type, area,
2210                                     widget, detail, edge, x, y, width,
2211                                     height);
2212 }
2213
2214 static void
2215 draw_handle (GtkStyle * style,
2216              GdkWindow * window,
2217              GtkStateType state_type,
2218              GtkShadowType shadow_type,
2219              GdkRectangle * area,
2220              GtkWidget * widget,
2221              const gchar * detail,
2222              gint x,
2223              gint y, gint width, gint height, GtkOrientation orientation)
2224 {
2225     if (is_toolbar_child (widget))
2226         {
2227             XpThemeElement hndl;
2228
2229             sanitize_size (window, &width, &height);
2230
2231             if (orientation == GTK_ORIENTATION_VERTICAL)
2232                 hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_V;
2233             else
2234                 hndl = XP_THEME_ELEMENT_REBAR_GRIPPER_H;
2235
2236             if (xp_theme_draw (window, hndl, style, x, y, width, height,
2237                                state_type, area))
2238                 {
2239                     return;
2240                 }
2241         }
2242
2243     if (!GTK_IS_PANED (widget))
2244         {
2245             gint xthick, ythick;
2246             GdkGC *light_gc, *dark_gc, *shadow_gc;
2247             GdkRectangle dest;
2248
2249             sanitize_size (window, &width, &height);
2250
2251             gtk_paint_box (style, window, state_type, shadow_type, area,
2252                            widget, detail, x, y, width, height);
2253
2254             light_gc = style->light_gc[state_type];
2255             dark_gc = style->dark_gc[state_type];
2256             shadow_gc = style->mid_gc[state_type];
2257
2258             xthick = style->xthickness;
2259             ythick = style->ythickness;
2260
2261             dest.x = x + xthick;
2262             dest.y = y + ythick;
2263             dest.width = width - (xthick * 2);
2264             dest.height = height - (ythick * 2);
2265
2266             if (dest.width < dest.height)
2267                 dest.x += 2;
2268             else
2269                 dest.y += 2;
2270
2271             gdk_gc_set_clip_rectangle (light_gc, &dest);
2272             gdk_gc_set_clip_rectangle (dark_gc, &dest);
2273             gdk_gc_set_clip_rectangle (shadow_gc, &dest);
2274
2275             if (dest.width < dest.height)
2276                 {
2277                     gdk_draw_line (window, light_gc, dest.x, dest.y, dest.x,
2278                                    dest.height);
2279                     gdk_draw_line (window, dark_gc, dest.x + (dest.width / 2),
2280                                    dest.y, dest.x + (dest.width / 2),
2281                                    dest.height);
2282                     gdk_draw_line (window, shadow_gc, dest.x + dest.width,
2283                                    dest.y, dest.x + dest.width, dest.height);
2284                 }
2285             else
2286                 {
2287                     gdk_draw_line (window, light_gc, dest.x, dest.y,
2288                                    dest.x + dest.width, dest.y);
2289                     gdk_draw_line (window, dark_gc, dest.x,
2290                                    dest.y + (dest.height / 2),
2291                                    dest.x + dest.width,
2292                                    dest.y + (dest.height / 2));
2293                     gdk_draw_line (window, shadow_gc, dest.x,
2294                                    dest.y + dest.height, dest.x + dest.width,
2295                                    dest.y + dest.height);
2296                 }
2297
2298             gdk_gc_set_clip_rectangle (shadow_gc, NULL);
2299             gdk_gc_set_clip_rectangle (light_gc, NULL);
2300             gdk_gc_set_clip_rectangle (dark_gc, NULL);
2301         }
2302 }
2303
2304 static void
2305 msw_style_init_from_rc (GtkStyle * style, GtkRcStyle * rc_style)
2306 {
2307     setup_system_font (style);
2308     setup_menu_settings (gtk_settings_get_default ());
2309     setup_system_styles (style);
2310     parent_class->init_from_rc (style, rc_style);
2311 }
2312
2313 static void
2314 msw_style_class_init (MswStyleClass * klass)
2315 {
2316     GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
2317
2318     parent_class = g_type_class_peek_parent (klass);
2319
2320     style_class->init_from_rc = msw_style_init_from_rc;
2321     style_class->draw_arrow = draw_arrow;
2322     style_class->draw_box = draw_box;
2323     style_class->draw_check = draw_check;
2324     style_class->draw_option = draw_option;
2325     style_class->draw_tab = draw_tab;
2326     style_class->draw_flat_box = draw_flat_box;
2327     style_class->draw_expander = draw_expander;
2328     style_class->draw_extension = draw_extension;
2329     style_class->draw_box_gap = draw_box_gap;
2330     style_class->draw_shadow = draw_shadow;
2331     style_class->draw_hline = draw_hline;
2332     style_class->draw_vline = draw_vline;
2333     style_class->draw_handle = draw_handle;
2334     style_class->draw_resize_grip = draw_resize_grip;
2335     style_class->draw_slider = draw_slider;
2336 }
2337
2338 GType msw_type_style = 0;
2339
2340 void
2341 msw_style_register_type (GTypeModule * module)
2342 {
2343     static const GTypeInfo object_info = {
2344         sizeof (MswStyleClass),
2345         (GBaseInitFunc) NULL,
2346         (GBaseFinalizeFunc) NULL,
2347         (GClassInitFunc) msw_style_class_init,
2348         NULL,                   /* class_finalize */
2349         NULL,                   /* class_data */
2350         sizeof (MswStyle),
2351         0,                      /* n_preallocs */
2352         (GInstanceInitFunc) NULL,
2353     };
2354
2355     msw_type_style = g_type_module_register_type (module,
2356                                                   GTK_TYPE_STYLE,
2357                                                   "MswStyle",
2358                                                   &object_info, 0);
2359 }
2360
2361 void
2362 msw_style_init (void)
2363 {
2364     xp_theme_init ();
2365     msw_style_setup_system_settings ();
2366     setup_msw_rc_style ();
2367 }