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