]> Pileus Git - ~andy/gtk/blob - modules/engines/ms-windows/xp_theme.c
MS Windows engine: draw elements in the right place.
[~andy/gtk] / modules / engines / ms-windows / xp_theme.c
1 /* MS-Windows Engine (aka GTK-Wimp)
2  *
3  * Copyright (C) 2003, 2004 Raymond Penners <raymond@dotsphinx.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #define _WIN32_WINNT 0x0501
22
23 #include "xp_theme.h"
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <windows.h>
30 #include <math.h>
31 #include <string.h>
32 #include <stdio.h>
33
34 #ifdef BUILDING_STANDALONE
35 #include "gdk/gdkwin32.h"
36 #else
37 #include "gdk/win32/gdkwin32.h"
38 #endif
39
40 #include <cairo-win32.h>
41 #include <gdk/gdk.h>
42
43 #include "xp_theme_defs.h"
44
45 #ifndef TMT_CAPTIONFONT
46
47 /* These aren't in mingw's "w32api" headers, nor in the Platform SDK
48  * headers.
49  */
50 #define TMT_CAPTIONFONT   801
51 #define TMT_MENUFONT      803
52 #define TMT_STATUSFONT    804
53 #define TMT_MSGBOXFONT    805
54 #endif
55
56 #define GP_LINEHORZ       2
57 #define GP_LINEVERT       3
58 #define TP_SEPARATOR      5
59 #define TP_SEPARATORVERT  6
60
61 /* GLOBALS LINEHORZ states */
62 #define LHS_FLAT          1
63 #define LHS_RAISED        2
64 #define LHS_SUNKEN        3
65
66 /* GLOBAL LINEVERT states */
67 #define LVS_FLAT          1
68 #define LVS_RAISED        2
69 #define LVS_SUNKEN        3
70
71 /* TRACKBAR parts */
72 #define TKP_TRACK         1
73 #define TKP_TRACKVERT     2
74 #define TKP_THUMB         3
75 #define TKP_THUMBBOTTOM   4
76 #define TKP_THUMBTOP      5
77 #define TKP_THUMBVERT     6
78 #define TKP_THUMBLEFT     7
79 #define TKP_THUMBRIGHT    8
80 #define TKP_TICS          9
81 #define TKP_TICSVERT      10
82
83 #define TRS_NORMAL        1
84
85 #define MBI_NORMAL         1
86 #define MBI_HOT            2
87 #define MBI_PUSHED         3
88 #define MBI_DISABLED       4
89 #define MBI_DISABLEDHOT    5
90 #define MBI_DISABLEDPUSHED 6
91
92 #define MENU_POPUPGUTTER    13
93 #define MENU_POPUPITEM      14
94 #define MENU_POPUPSEPARATOR 15
95
96 static const LPCWSTR class_descriptors[] = {
97   L"Scrollbar",                 /* XP_THEME_CLASS_SCROLLBAR */
98   L"Button",                    /* XP_THEME_CLASS_BUTTON */
99   L"Header",                    /* XP_THEME_CLASS_HEADER */
100   L"ComboBox",                  /* XP_THEME_CLASS_COMBOBOX */
101   L"Tab",                       /* XP_THEME_CLASS_TAB */
102   L"Edit",                      /* XP_THEME_CLASS_EDIT */
103   L"TreeView",                  /* XP_THEME_CLASS_TREEVIEW */
104   L"Spin",                      /* XP_THEME_CLASS_SPIN */
105   L"Progress",                  /* XP_THEME_CLASS_PROGRESS */
106   L"Tooltip",                   /* XP_THEME_CLASS_TOOLTIP */
107   L"Rebar",                     /* XP_THEME_CLASS_REBAR */
108   L"Toolbar",                   /* XP_THEME_CLASS_TOOLBAR */
109   L"Globals",                   /* XP_THEME_CLASS_GLOBALS */
110   L"Menu",                      /* XP_THEME_CLASS_MENU */
111   L"Window",                    /* XP_THEME_CLASS_WINDOW */
112   L"Status",                    /* XP_THEME_CLASS_STATUS */
113   L"Trackbar"                   /* XP_THEME_CLASS_TRACKBAR */
114 };
115
116 static const short element_part_map[XP_THEME_ELEMENT__SIZEOF] = {
117   BP_CHECKBOX,
118   BP_CHECKBOX,
119   BP_CHECKBOX,
120   BP_PUSHBUTTON,
121   HP_HEADERITEM,
122   CP_DROPDOWNBUTTON,
123   TABP_BODY,
124   TABP_TABITEM,
125   TABP_TABITEMLEFTEDGE,
126   TABP_TABITEMRIGHTEDGE,
127   TABP_PANE,
128   SBP_THUMBBTNHORZ,
129   SBP_THUMBBTNVERT,
130   SBP_ARROWBTN,
131   SBP_ARROWBTN,
132   SBP_ARROWBTN,
133   SBP_ARROWBTN,
134   SBP_GRIPPERHORZ,
135   SBP_GRIPPERVERT,
136   SBP_LOWERTRACKHORZ,
137   SBP_LOWERTRACKVERT,
138   EP_EDITTEXT,
139   BP_PUSHBUTTON,
140   SPNP_UP,
141   SPNP_DOWN,
142   BP_RADIOBUTTON,
143   BP_RADIOBUTTON,
144   TVP_GLYPH,
145   TVP_GLYPH,
146   PP_CHUNK,
147   PP_CHUNKVERT,
148   PP_BAR,
149   PP_BARVERT,
150   TTP_STANDARD,
151   0 /* RP_BAND */ ,
152   RP_GRIPPER,
153   RP_GRIPPERVERT,
154   RP_CHEVRON,
155   TP_BUTTON,
156   MENU_POPUPITEM, /*MP_MENUITEM,*/
157   MENU_POPUPSEPARATOR,  /*MP_SEPARATOR,*/
158   SP_GRIPPER,
159   SP_PANE,
160   GP_LINEHORZ,
161   GP_LINEVERT,
162   TP_SEPARATOR,
163   TP_SEPARATORVERT,
164   TKP_TRACK,
165   TKP_TRACKVERT,
166   TKP_THUMB,
167   TKP_THUMBVERT,
168   TKP_TICS,
169   TKP_TICSVERT
170 };
171
172 #define UXTHEME_DLL "uxtheme.dll"
173
174 static HINSTANCE uxtheme_dll = NULL;
175 static HTHEME open_themes[XP_THEME_CLASS__SIZEOF];
176 static gboolean use_xp_theme = FALSE;
177
178 typedef HRESULT (FAR PASCAL *GetThemeSysFontFunc)           (HTHEME hTheme, int iFontID, OUT LOGFONTW *plf);
179 typedef int (FAR PASCAL *GetThemeSysSizeFunc)               (HTHEME hTheme, int iSizeId);
180 typedef COLORREF (FAR PASCAL *GetThemeSysColorFunc)         (HTHEME hTheme,
181                                                              int iColorID);
182 typedef HTHEME (FAR PASCAL *OpenThemeDataFunc)              (HWND hwnd,
183                                                              LPCWSTR pszClassList);
184 typedef HRESULT (FAR PASCAL *CloseThemeDataFunc)            (HTHEME theme);
185 typedef HRESULT (FAR PASCAL *DrawThemeBackgroundFunc)       (HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
186                                                              const RECT *pRect, const RECT *pClipRect);
187 typedef HRESULT (FAR PASCAL *EnableThemeDialogTextureFunc)  (HWND hwnd,
188                                                              DWORD dwFlags);
189 typedef BOOL (FAR PASCAL *IsThemeActiveFunc)                (VOID);
190 typedef BOOL (FAR PASCAL *IsAppThemedFunc)                  (VOID);
191 typedef BOOL (FAR PASCAL *IsThemeBackgroundPartiallyTransparentFunc) (HTHEME hTheme,
192                                                                       int iPartId,
193                                                                       int iStateId);
194 typedef HRESULT (FAR PASCAL *DrawThemeParentBackgroundFunc) (HWND hwnd,
195                                                              HDC hdc,
196                                                              RECT *prc);
197 typedef HRESULT (FAR PASCAL *GetThemePartSizeFunc)          (HTHEME hTheme,
198                                                              HDC hdc,
199                                                              int iPartId,
200                                                              int iStateId,
201                                                              RECT *prc,
202                                                              int eSize,
203                                                              SIZE *psz);
204
205 static GetThemeSysFontFunc get_theme_sys_font_func = NULL;
206 static GetThemeSysColorFunc get_theme_sys_color_func = NULL;
207 static GetThemeSysSizeFunc get_theme_sys_metric_func = NULL;
208 static OpenThemeDataFunc open_theme_data_func = NULL;
209 static CloseThemeDataFunc close_theme_data_func = NULL;
210 static DrawThemeBackgroundFunc draw_theme_background_func = NULL;
211 static EnableThemeDialogTextureFunc enable_theme_dialog_texture_func = NULL;
212 static IsThemeActiveFunc is_theme_active_func = NULL;
213 static IsAppThemedFunc is_app_themed_func = NULL;
214 static IsThemeBackgroundPartiallyTransparentFunc is_theme_partially_transparent_func = NULL;
215 static DrawThemeParentBackgroundFunc draw_theme_parent_background_func = NULL;
216 static GetThemePartSizeFunc get_theme_part_size_func = NULL;
217
218 static void
219 xp_theme_close_open_handles (void)
220 {
221   int i;
222
223   for (i = 0; i < XP_THEME_CLASS__SIZEOF; i++)
224     {
225       if (open_themes[i])
226         {
227           close_theme_data_func (open_themes[i]);
228           open_themes[i] = NULL;
229         }
230     }
231 }
232
233 void
234 xp_theme_init (void)
235 {
236   char *buf;
237   char dummy;
238   int n, k;
239
240   if (uxtheme_dll)
241     return;
242
243   memset (open_themes, 0, sizeof (open_themes));
244
245   n = GetSystemDirectory (&dummy, 0);
246
247   if (n <= 0)
248     return;
249
250   buf = g_malloc (n + 1 + strlen (UXTHEME_DLL));
251   k = GetSystemDirectory (buf, n);
252   
253   if (k == 0 || k > n)
254     {
255       g_free (buf);
256       return;
257     }
258
259   if (!G_IS_DIR_SEPARATOR (buf[strlen (buf) -1]))
260     strcat (buf, G_DIR_SEPARATOR_S);
261   strcat (buf, UXTHEME_DLL);
262
263   uxtheme_dll = LoadLibrary (buf);
264   g_free (buf);
265
266   if (!uxtheme_dll)
267     return;
268
269   is_app_themed_func = (IsAppThemedFunc) GetProcAddress (uxtheme_dll, "IsAppThemed");
270
271   if (is_app_themed_func)
272     {
273       is_theme_active_func = (IsThemeActiveFunc) GetProcAddress (uxtheme_dll, "IsThemeActive");
274       open_theme_data_func = (OpenThemeDataFunc) GetProcAddress (uxtheme_dll, "OpenThemeData");
275       close_theme_data_func = (CloseThemeDataFunc) GetProcAddress (uxtheme_dll, "CloseThemeData");
276       draw_theme_background_func = (DrawThemeBackgroundFunc) GetProcAddress (uxtheme_dll, "DrawThemeBackground");
277       enable_theme_dialog_texture_func = (EnableThemeDialogTextureFunc) GetProcAddress (uxtheme_dll, "EnableThemeDialogTexture");
278       get_theme_sys_font_func = (GetThemeSysFontFunc) GetProcAddress (uxtheme_dll, "GetThemeSysFont");
279       get_theme_sys_color_func = (GetThemeSysColorFunc) GetProcAddress (uxtheme_dll, "GetThemeSysColor");
280       get_theme_sys_metric_func = (GetThemeSysSizeFunc) GetProcAddress (uxtheme_dll, "GetThemeSysSize");
281       is_theme_partially_transparent_func = (IsThemeBackgroundPartiallyTransparentFunc) GetProcAddress (uxtheme_dll, "IsThemeBackgroundPartiallyTransparent");
282       draw_theme_parent_background_func = (DrawThemeParentBackgroundFunc) GetProcAddress (uxtheme_dll, "DrawThemeParentBackground");
283       get_theme_part_size_func = (GetThemePartSizeFunc) GetProcAddress (uxtheme_dll, "GetThemePartSize");
284     }
285
286   if (is_app_themed_func && is_theme_active_func)
287     {
288       use_xp_theme = (is_app_themed_func () && is_theme_active_func ());
289     }
290   else
291     {
292       use_xp_theme = FALSE;
293     }
294 }
295
296 void
297 xp_theme_reset (void)
298 {
299   xp_theme_close_open_handles ();
300
301   if (is_app_themed_func && is_theme_active_func)
302     {
303       use_xp_theme = (is_app_themed_func () && is_theme_active_func ());
304     }
305   else
306     {
307       use_xp_theme = FALSE;
308     }
309 }
310
311 void
312 xp_theme_exit (void)
313 {
314   if (!uxtheme_dll)
315     return;
316
317   xp_theme_close_open_handles ();
318
319   FreeLibrary (uxtheme_dll);
320   uxtheme_dll = NULL;
321   use_xp_theme = FALSE;
322
323   is_app_themed_func = NULL;
324   is_theme_active_func = NULL;
325   open_theme_data_func = NULL;
326   close_theme_data_func = NULL;
327   draw_theme_background_func = NULL;
328   enable_theme_dialog_texture_func = NULL;
329   get_theme_sys_font_func = NULL;
330   get_theme_sys_color_func = NULL;
331   get_theme_sys_metric_func = NULL;
332   is_theme_partially_transparent_func = NULL;
333   draw_theme_parent_background_func = NULL;
334   get_theme_part_size_func = NULL;
335 }
336
337 static HTHEME
338 xp_theme_get_handle_by_class (XpThemeClass klazz)
339 {
340   if (!open_themes[klazz] && open_theme_data_func)
341     {
342       open_themes[klazz] = open_theme_data_func (NULL, class_descriptors[klazz]);
343     }
344
345   return open_themes[klazz];
346 }
347
348 static HTHEME
349 xp_theme_get_handle_by_element (XpThemeElement element)
350 {
351   HTHEME ret = NULL;
352   XpThemeClass klazz = XP_THEME_CLASS__SIZEOF;
353
354   switch (element)
355     {
356     case XP_THEME_ELEMENT_TOOLTIP:
357       klazz = XP_THEME_CLASS_TOOLTIP;
358       break;
359
360     case XP_THEME_ELEMENT_REBAR:
361     case XP_THEME_ELEMENT_REBAR_GRIPPER_H:
362     case XP_THEME_ELEMENT_REBAR_GRIPPER_V:
363     case XP_THEME_ELEMENT_REBAR_CHEVRON:
364       klazz = XP_THEME_CLASS_REBAR;
365       break;
366
367     case XP_THEME_ELEMENT_SCALE_TROUGH_H:
368     case XP_THEME_ELEMENT_SCALE_TROUGH_V:
369     case XP_THEME_ELEMENT_SCALE_SLIDER_H:
370     case XP_THEME_ELEMENT_SCALE_SLIDER_V:
371     case XP_THEME_ELEMENT_SCALE_TICS_H:
372     case XP_THEME_ELEMENT_SCALE_TICS_V:
373       klazz = XP_THEME_CLASS_TRACKBAR;
374       break;
375
376     case XP_THEME_ELEMENT_STATUS_GRIPPER:
377     case XP_THEME_ELEMENT_STATUS_PANE:
378       klazz = XP_THEME_CLASS_STATUS;
379       break;
380
381     case XP_THEME_ELEMENT_TOOLBAR_BUTTON:
382     case XP_THEME_ELEMENT_TOOLBAR_SEPARATOR_H:
383     case XP_THEME_ELEMENT_TOOLBAR_SEPARATOR_V:
384       klazz = XP_THEME_CLASS_TOOLBAR;
385       break;
386
387     case XP_THEME_ELEMENT_MENU_ITEM:
388     case XP_THEME_ELEMENT_MENU_SEPARATOR:
389       klazz = XP_THEME_CLASS_MENU;
390       break;
391
392     case XP_THEME_ELEMENT_PRESSED_CHECKBOX:
393     case XP_THEME_ELEMENT_INCONSISTENT_CHECKBOX:
394     case XP_THEME_ELEMENT_CHECKBOX:
395     case XP_THEME_ELEMENT_BUTTON:
396     case XP_THEME_ELEMENT_DEFAULT_BUTTON:
397     case XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON:
398     case XP_THEME_ELEMENT_RADIO_BUTTON:
399       klazz = XP_THEME_CLASS_BUTTON;
400       break;
401
402     case XP_THEME_ELEMENT_LIST_HEADER:
403       klazz = XP_THEME_CLASS_HEADER;
404       break;
405
406     case XP_THEME_ELEMENT_COMBOBUTTON:
407       klazz = XP_THEME_CLASS_COMBOBOX;
408       break;
409
410     case XP_THEME_ELEMENT_BODY:
411     case XP_THEME_ELEMENT_TAB_ITEM:
412     case XP_THEME_ELEMENT_TAB_ITEM_LEFT_EDGE:
413     case XP_THEME_ELEMENT_TAB_ITEM_RIGHT_EDGE:
414     case XP_THEME_ELEMENT_TAB_PANE:
415       klazz = XP_THEME_CLASS_TAB;
416       break;
417
418     case XP_THEME_ELEMENT_SCROLLBAR_V:
419     case XP_THEME_ELEMENT_SCROLLBAR_H:
420     case XP_THEME_ELEMENT_ARROW_UP:
421     case XP_THEME_ELEMENT_ARROW_DOWN:
422     case XP_THEME_ELEMENT_ARROW_LEFT:
423     case XP_THEME_ELEMENT_ARROW_RIGHT:
424     case XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_V:
425     case XP_THEME_ELEMENT_SCROLLBAR_GRIPPER_H:
426     case XP_THEME_ELEMENT_TROUGH_V:
427     case XP_THEME_ELEMENT_TROUGH_H:
428       klazz = XP_THEME_CLASS_SCROLLBAR;
429       break;
430
431     case XP_THEME_ELEMENT_EDIT_TEXT:
432       klazz = XP_THEME_CLASS_EDIT;
433       break;
434
435     case XP_THEME_ELEMENT_SPIN_BUTTON_UP:
436     case XP_THEME_ELEMENT_SPIN_BUTTON_DOWN:
437       klazz = XP_THEME_CLASS_SPIN;
438       break;
439
440     case XP_THEME_ELEMENT_PROGRESS_BAR_H:
441     case XP_THEME_ELEMENT_PROGRESS_BAR_V:
442     case XP_THEME_ELEMENT_PROGRESS_TROUGH_H:
443     case XP_THEME_ELEMENT_PROGRESS_TROUGH_V:
444       klazz = XP_THEME_CLASS_PROGRESS;
445       break;
446
447     case XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED:
448     case XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED:
449       klazz = XP_THEME_CLASS_TREEVIEW;
450       break;
451
452     case XP_THEME_ELEMENT_LINE_H:
453     case XP_THEME_ELEMENT_LINE_V:
454       klazz = XP_THEME_CLASS_GLOBALS;
455       break;
456
457     default:
458       break;
459     }
460
461   if (klazz != XP_THEME_CLASS__SIZEOF)
462     {
463       ret = xp_theme_get_handle_by_class (klazz);
464     }
465
466   return ret;
467 }
468
469 static int
470 xp_theme_map_gtk_state (XpThemeElement element, GtkStateType state)
471 {
472   int ret = 0;
473
474   switch (element)
475     {
476     case XP_THEME_ELEMENT_TOOLTIP:
477       ret = TTSS_NORMAL;
478       break;
479
480     case XP_THEME_ELEMENT_REBAR:
481       ret = 0;
482       break;
483
484     case XP_THEME_ELEMENT_REBAR_GRIPPER_H:
485     case XP_THEME_ELEMENT_REBAR_GRIPPER_V:
486       ret = 0;
487       break;
488
489     case XP_THEME_ELEMENT_STATUS_GRIPPER:
490     case XP_THEME_ELEMENT_STATUS_PANE:
491       ret = 1;
492       break;
493
494     case XP_THEME_ELEMENT_REBAR_CHEVRON:
495       switch (state)
496         {
497         case GTK_STATE_PRELIGHT:
498           ret = CHEVS_HOT;
499           break;
500
501         case GTK_STATE_SELECTED:
502         case GTK_STATE_ACTIVE:
503           ret = CHEVS_PRESSED;
504           break;
505
506         default:
507           ret = CHEVS_NORMAL;
508         }
509       break;
510
511     case XP_THEME_ELEMENT_TOOLBAR_SEPARATOR_H:
512     case XP_THEME_ELEMENT_TOOLBAR_SEPARATOR_V:
513       ret = TS_NORMAL;
514       break;
515
516     case XP_THEME_ELEMENT_TOOLBAR_BUTTON:
517       switch (state)
518         {
519         case GTK_STATE_ACTIVE:
520           ret = TS_PRESSED;
521           break;
522
523         case GTK_STATE_PRELIGHT:
524           ret = TS_HOT;
525           break;
526
527         case GTK_STATE_INSENSITIVE:
528           ret = TS_DISABLED;
529           break;
530
531         default:
532           ret = TS_NORMAL;
533         }
534       break;
535
536     case XP_THEME_ELEMENT_TAB_PANE:
537       ret = 1;
538       break;
539
540     case XP_THEME_ELEMENT_TAB_ITEM_LEFT_EDGE:
541     case XP_THEME_ELEMENT_TAB_ITEM_RIGHT_EDGE:
542     case XP_THEME_ELEMENT_TAB_ITEM:
543       switch (state)
544         {
545         case GTK_STATE_PRELIGHT:
546           ret = TIS_HOT;
547           break;
548
549         case GTK_STATE_INSENSITIVE:
550           ret = TIS_DISABLED;
551           break;
552
553         case GTK_STATE_SELECTED:
554         case GTK_STATE_ACTIVE:
555           ret = TIS_NORMAL;
556           break;
557
558         default:
559           ret = TIS_SELECTED;
560         }
561       break;
562
563     case XP_THEME_ELEMENT_EDIT_TEXT:
564       switch (state)
565         {
566         case GTK_STATE_PRELIGHT:
567           ret = ETS_FOCUSED;
568           break;
569
570         case GTK_STATE_INSENSITIVE:
571           ret = ETS_READONLY;
572           break;
573
574         case GTK_STATE_SELECTED:
575         case GTK_STATE_ACTIVE:
576         default:
577           ret = ETS_NORMAL;
578         }
579       break;
580
581     case XP_THEME_ELEMENT_TROUGH_H:
582     case XP_THEME_ELEMENT_TROUGH_V:
583       ret = SCRBS_NORMAL;
584       break;
585
586     case XP_THEME_ELEMENT_SCROLLBAR_H:
587     case XP_THEME_ELEMENT_SCROLLBAR_V:
588       switch (state)
589         {
590         case GTK_STATE_SELECTED:
591         case GTK_STATE_ACTIVE:
592           ret = SCRBS_PRESSED;
593           break;
594
595         case GTK_STATE_PRELIGHT:
596           ret = SCRBS_HOT;
597           break;
598
599         case GTK_STATE_INSENSITIVE:
600           ret = SCRBS_DISABLED;
601           break;
602
603         default:
604           ret = SCRBS_NORMAL;
605         }
606       break;
607
608     case XP_THEME_ELEMENT_ARROW_DOWN:
609       switch (state)
610         {
611         case GTK_STATE_ACTIVE:
612           ret = ABS_DOWNPRESSED;
613           break;
614
615         case GTK_STATE_PRELIGHT:
616           ret = ABS_DOWNHOT;
617           break;
618
619         case GTK_STATE_INSENSITIVE:
620           ret = ABS_DOWNDISABLED;
621           break;
622
623         default:
624           ret = ABS_DOWNNORMAL;
625         }
626       break;
627
628     case XP_THEME_ELEMENT_ARROW_UP:
629       switch (state)
630         {
631         case GTK_STATE_ACTIVE:
632           ret = ABS_UPPRESSED;
633           break;
634
635         case GTK_STATE_PRELIGHT:
636           ret = ABS_UPHOT;
637           break;
638
639         case GTK_STATE_INSENSITIVE:
640           ret = ABS_UPDISABLED;
641           break;
642
643         default:
644           ret = ABS_UPNORMAL;
645         }
646       break;
647
648     case XP_THEME_ELEMENT_ARROW_LEFT:
649       switch (state)
650         {
651         case GTK_STATE_ACTIVE:
652           ret = ABS_LEFTPRESSED;
653           break;
654
655         case GTK_STATE_PRELIGHT:
656           ret = ABS_LEFTHOT;
657           break;
658
659         case GTK_STATE_INSENSITIVE:
660           ret = ABS_LEFTDISABLED;
661           break;
662
663         default:
664           ret = ABS_LEFTNORMAL;
665         }
666       break;
667
668     case XP_THEME_ELEMENT_ARROW_RIGHT:
669       switch (state)
670         {
671         case GTK_STATE_ACTIVE:
672           ret = ABS_RIGHTPRESSED;
673           break;
674
675         case GTK_STATE_PRELIGHT:
676           ret = ABS_RIGHTHOT;
677           break;
678
679         case GTK_STATE_INSENSITIVE:
680           ret = ABS_RIGHTDISABLED;
681           break;
682
683         default:
684           ret = ABS_RIGHTNORMAL;
685         }
686       break;
687
688     case XP_THEME_ELEMENT_CHECKBOX:
689     case XP_THEME_ELEMENT_RADIO_BUTTON:
690       switch (state)
691         {
692         case GTK_STATE_SELECTED:
693           ret = CBS_UNCHECKEDPRESSED;
694           break;
695
696         case GTK_STATE_PRELIGHT:
697           ret = CBS_UNCHECKEDHOT;
698           break;
699
700         case GTK_STATE_INSENSITIVE:
701           ret = CBS_UNCHECKEDDISABLED;
702           break;
703
704         default:
705           ret = CBS_UNCHECKEDNORMAL;
706         }
707       break;
708
709     case XP_THEME_ELEMENT_INCONSISTENT_CHECKBOX:
710       switch (state)
711         {
712         case GTK_STATE_SELECTED:
713           ret = CBS_MIXEDPRESSED;
714           break;
715
716         case GTK_STATE_PRELIGHT:
717           ret = CBS_MIXEDHOT;
718           break;
719
720         case GTK_STATE_INSENSITIVE:
721           ret = CBS_MIXEDDISABLED;
722           break;
723
724         default:
725           ret = CBS_MIXEDNORMAL;
726         }
727       break;
728
729     case XP_THEME_ELEMENT_PRESSED_CHECKBOX:
730     case XP_THEME_ELEMENT_PRESSED_RADIO_BUTTON:
731       switch (state)
732         {
733         case GTK_STATE_SELECTED:
734           ret = CBS_CHECKEDPRESSED;
735           break;
736
737         case GTK_STATE_PRELIGHT:
738           ret = CBS_CHECKEDHOT;
739           break;
740
741         case GTK_STATE_INSENSITIVE:
742           ret = CBS_CHECKEDDISABLED;
743           break;
744
745         default:
746           ret = CBS_CHECKEDNORMAL;
747         }
748       break;
749
750     case XP_THEME_ELEMENT_DEFAULT_BUTTON:
751       switch (state)
752         {
753         case GTK_STATE_ACTIVE:
754           ret = PBS_PRESSED;
755           break;
756
757         case GTK_STATE_PRELIGHT:
758           ret = PBS_HOT;
759           break;
760
761         case GTK_STATE_INSENSITIVE:
762           ret = PBS_DISABLED;
763           break;
764
765         default:
766           ret = PBS_DEFAULTED;
767         }
768       break;
769
770     case XP_THEME_ELEMENT_SPIN_BUTTON_DOWN:
771       switch (state)
772         {
773         case GTK_STATE_ACTIVE:
774           ret = DNS_PRESSED;
775           break;
776
777         case GTK_STATE_PRELIGHT:
778           ret = DNS_HOT;
779           break;
780
781         case GTK_STATE_INSENSITIVE:
782           ret = DNS_DISABLED;
783           break;
784
785         default:
786           ret = DNS_NORMAL;
787         }
788       break;
789
790     case XP_THEME_ELEMENT_SPIN_BUTTON_UP:
791       switch (state)
792         {
793         case GTK_STATE_ACTIVE:
794           ret = UPS_PRESSED;
795           break;
796
797         case GTK_STATE_PRELIGHT:
798           ret = UPS_HOT;
799           break;
800
801         case GTK_STATE_INSENSITIVE:
802           ret = UPS_DISABLED;
803           break;
804
805         default:
806           ret = UPS_NORMAL;
807         }
808       break;
809
810     case XP_THEME_ELEMENT_TREEVIEW_EXPANDER_OPENED:
811       ret = GLPS_OPENED;
812       break;
813
814     case XP_THEME_ELEMENT_TREEVIEW_EXPANDER_CLOSED:
815       ret = GLPS_CLOSED;
816       break;
817
818     case XP_THEME_ELEMENT_PROGRESS_BAR_H:
819     case XP_THEME_ELEMENT_PROGRESS_BAR_V:
820     case XP_THEME_ELEMENT_PROGRESS_TROUGH_H:
821     case XP_THEME_ELEMENT_PROGRESS_TROUGH_V:
822       ret = 1;
823       break;
824
825     case XP_THEME_ELEMENT_MENU_SEPARATOR:
826       ret = TS_NORMAL;
827       break;
828
829     case XP_THEME_ELEMENT_MENU_ITEM:
830       switch (state)
831         {
832         case GTK_STATE_SELECTED:
833           ret = MS_SELECTED;
834           break;
835
836         case GTK_STATE_PRELIGHT:
837           ret = MBI_HOT;
838           break;
839
840         case GTK_STATE_INSENSITIVE:
841           ret = MBI_DISABLED;
842           break;
843
844         default:
845           ret = MBI_NORMAL;
846         }
847       break;
848
849     case XP_THEME_ELEMENT_LINE_H:
850       switch (state)
851         {
852           /* LHS_FLAT, LHS_RAISED, LHS_SUNKEN */
853           ret = LHS_RAISED;
854           break;
855         }
856       break;
857
858     case XP_THEME_ELEMENT_LINE_V:
859       switch (state)
860         {
861           /* LVS_FLAT, LVS_RAISED, LVS_SUNKEN */
862           ret = LVS_RAISED;
863           break;
864         }
865       break;
866
867     case XP_THEME_ELEMENT_SCALE_TROUGH_H:
868     case XP_THEME_ELEMENT_SCALE_TROUGH_V:
869       ret = TRS_NORMAL;
870       break;
871
872     default:
873       switch (state)
874         {
875         case GTK_STATE_ACTIVE:
876           ret = PBS_PRESSED;
877           break;
878
879         case GTK_STATE_PRELIGHT:
880           ret = PBS_HOT;
881           break;
882
883         case GTK_STATE_INSENSITIVE:
884           ret = PBS_DISABLED;
885           break;
886
887         default:
888           ret = PBS_NORMAL;
889         }
890     }
891
892   return ret;
893 }
894
895 HDC
896 get_window_dc (GtkStyle *style,
897                GdkWindow *window,
898                GtkStateType state_type,
899                XpDCInfo *dc_info_out,
900                gint x, gint y, gint width, gint height,
901                RECT *rect_out)
902 {
903   cairo_t *cr;
904   cairo_surface_t *surface;
905   HDC dc;
906   gint x_offset = 0, y_offset = 0;
907   double x_off, y_off;
908
909   dc_info_out->cr = NULL;
910   dc_info_out->dc = NULL;
911   
912   cr = gdk_cairo_create (window);
913   if (!cr)
914     return NULL;
915
916   surface = cairo_get_target (cr);
917   cairo_surface_get_device_offset (surface, &x_off, &y_off);
918   cairo_surface_flush (surface);
919   
920   dc = cairo_win32_surface_get_dc (surface);
921   if (!dc)
922    return NULL;
923   
924   x_offset = -x_off;
925   y_offset = -y_off;
926
927   rect_out->left = x - x_offset;
928   rect_out->top = y - y_offset;
929   rect_out->right = rect_out->left + width;
930   rect_out->bottom = rect_out->top + height;
931   
932   dc_info_out->cr = cr;
933   dc_info_out->dc = dc;
934   dc_info_out->x_offset = x_offset;
935   dc_info_out->y_offset = y_offset;
936   
937   return dc;
938 }
939
940 void
941 release_window_dc (XpDCInfo *dc_info)
942 {
943   if (!dc_info->cr || !dc_info->dc)
944     return;
945
946   ReleaseDC (NULL, dc_info->dc);
947   cairo_destroy (dc_info->cr);
948   
949   dc_info->cr = NULL;
950   dc_info->dc = NULL;
951 }
952
953 gboolean
954 xp_theme_draw (GdkWindow *win, XpThemeElement element, GtkStyle *style,
955                int x, int y, int width, int height,
956                GtkStateType state_type, GdkRectangle *area)
957 {
958   HTHEME theme;
959   RECT rect, clip, *pClip;
960   HDC dc;
961   XpDCInfo dc_info;
962   int part_state;
963
964   if (!xp_theme_is_drawable (element))
965     return FALSE;
966
967   theme = xp_theme_get_handle_by_element (element);
968   if (!theme)
969     return FALSE;
970
971   /* FIXME: Recheck its function */
972   if (GDK_IS_WINDOW (win) && gdk_win32_window_is_win32 (win))
973     enable_theme_dialog_texture_func (GDK_WINDOW_HWND (win), ETDT_ENABLETAB);
974
975   dc = get_window_dc (style, win, state_type, &dc_info,
976                       x, y, width, height,
977                       &rect);
978   if (!dc)
979     return FALSE;
980
981   if (area)
982     {
983       clip.left = area->x - dc_info.x_offset;
984       clip.top = area->y - dc_info.y_offset;
985       clip.right = clip.left + area->width;
986       clip.bottom = clip.top + area->height;
987
988       pClip = &clip;
989     }
990   else
991     {
992       pClip = NULL;
993     }
994
995   part_state = xp_theme_map_gtk_state (element, state_type);
996
997   /* Support transparency */
998   if (is_theme_partially_transparent_func (theme, element_part_map[element], part_state))
999     draw_theme_parent_background_func (GDK_WINDOW_HWND (win), dc, pClip);
1000
1001   draw_theme_background_func (theme, dc, element_part_map[element],
1002                               part_state, &rect, pClip);
1003
1004   release_window_dc (&dc_info);
1005
1006   return TRUE;
1007 }
1008
1009 gboolean
1010 xp_theme_is_active (void)
1011 {
1012   return use_xp_theme;
1013 }
1014
1015 gboolean
1016 xp_theme_is_drawable (XpThemeElement element)
1017 {
1018   if (xp_theme_is_active ())
1019     return (xp_theme_get_handle_by_element (element) != NULL);
1020
1021   return FALSE;
1022 }
1023
1024 gboolean
1025 xp_theme_get_element_dimensions (XpThemeElement element,
1026                                  GtkStateType state_type,
1027                                  gint *cx, gint *cy)
1028 {
1029   HTHEME theme;
1030   SIZE part_size;
1031   int part_state;
1032
1033   if (!xp_theme_is_active ())
1034     return FALSE;
1035
1036   theme = xp_theme_get_handle_by_element (element);
1037   if (!theme)
1038     return FALSE;
1039
1040   part_state = xp_theme_map_gtk_state (element, state_type);
1041
1042   get_theme_part_size_func (theme,
1043                             NULL,
1044                             element_part_map[element],
1045                             part_state,
1046                             NULL,
1047                             TS_MIN,
1048                             &part_size);
1049
1050   *cx = part_size.cx;
1051   *cy = part_size.cy;
1052
1053   if (element == XP_THEME_ELEMENT_MENU_ITEM ||
1054       element == XP_THEME_ELEMENT_MENU_SEPARATOR)
1055   {
1056     SIZE gutter_size;
1057
1058     get_theme_part_size_func (theme,
1059                               NULL,
1060                               MENU_POPUPGUTTER,
1061                               0,
1062                               NULL,
1063                               TS_MIN,
1064                               &gutter_size);
1065
1066         *cx += gutter_size.cx * 2;
1067         *cy += gutter_size.cy * 2;
1068   }
1069
1070   return TRUE;
1071 }
1072
1073 gboolean
1074 xp_theme_get_system_font (XpThemeClass klazz, XpThemeFont fontId,
1075                           OUT LOGFONTW *lf)
1076 {
1077   if (xp_theme_is_active () && get_theme_sys_font_func != NULL)
1078     {
1079       HTHEME theme = xp_theme_get_handle_by_class (klazz);
1080       int themeFont;
1081
1082       if (!theme)
1083         return FALSE;
1084
1085       switch (fontId)
1086         {
1087         case XP_THEME_FONT_CAPTION:
1088           themeFont = TMT_CAPTIONFONT;
1089           break;
1090
1091         case XP_THEME_FONT_MENU:
1092           themeFont = TMT_MENUFONT;
1093           break;
1094
1095         case XP_THEME_FONT_STATUS:
1096           themeFont = TMT_STATUSFONT;
1097           break;
1098
1099         case XP_THEME_FONT_MESSAGE:
1100         default:
1101           themeFont = TMT_MSGBOXFONT;
1102           break;
1103         }
1104
1105       /* if theme is NULL, it will just return the GetSystemFont()
1106          value */
1107       return ((*get_theme_sys_font_func) (theme, themeFont, lf) == S_OK);
1108     }
1109
1110   return FALSE;
1111 }
1112
1113 gboolean
1114 xp_theme_get_system_color (XpThemeClass klazz, int colorId,
1115                            OUT DWORD *pColor)
1116 {
1117   if (xp_theme_is_active () && get_theme_sys_color_func != NULL)
1118     {
1119       HTHEME theme = xp_theme_get_handle_by_class (klazz);
1120
1121       /* if theme is NULL, it will just return the GetSystemColor()
1122          value */
1123       *pColor = (*get_theme_sys_color_func) (theme, colorId);
1124       return TRUE;
1125     }
1126
1127   return FALSE;
1128 }
1129
1130 gboolean
1131 xp_theme_get_system_metric (XpThemeClass klazz, int metricId, OUT int *pVal)
1132 {
1133   if (xp_theme_is_active () && get_theme_sys_metric_func != NULL)
1134     {
1135       HTHEME theme = xp_theme_get_handle_by_class (klazz);
1136
1137       /* if theme is NULL, it will just return the GetSystemMetrics()
1138          value */
1139       *pVal = (*get_theme_sys_metric_func) (theme, metricId);
1140       return TRUE;
1141     }
1142
1143   return FALSE;
1144 }