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