]> Pileus Git - ~andy/gtk/blobdiff - modules/engines/ms-windows/xp_theme.c
win32: Fall back to raleigh with the classic theme
[~andy/gtk] / modules / engines / ms-windows / xp_theme.c
index 6847369605c35b1fb78969750ff33a1eb7452992..b715f8517a10b322227b9e2b0beadd8aede086d5 100755 (executable)
@@ -13,9 +13,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #define _WIN32_WINNT 0x0501
 #include <string.h>
 #include <stdio.h>
 
-/* #include "gdk/gdkwin32.h" */
+#ifdef BUILDING_STANDALONE
+#include "gdk/gdkwin32.h"
+#else
 #include "gdk/win32/gdkwin32.h"
+#endif
+
+#include <cairo-win32.h>
+#include <gdk/gdk.h>
 
 #include "xp_theme_defs.h"
 
 
 #define TRS_NORMAL        1
 
+#define MBI_NORMAL         1
+#define MBI_HOT            2
+#define MBI_PUSHED         3
+#define MBI_DISABLED       4
+#define MBI_DISABLEDHOT    5
+#define MBI_DISABLEDPUSHED 6
+
+#define MENU_POPUPGUTTER    13
+#define MENU_POPUPITEM      14
+#define MENU_POPUPSEPARATOR 15
+
 static const LPCWSTR class_descriptors[] = {
   L"Scrollbar",                        /* XP_THEME_CLASS_SCROLLBAR */
   L"Button",                   /* XP_THEME_CLASS_BUTTON */
@@ -136,8 +151,8 @@ static const short element_part_map[XP_THEME_ELEMENT__SIZEOF] = {
   RP_GRIPPERVERT,
   RP_CHEVRON,
   TP_BUTTON,
-  MP_MENUITEM,
-  MP_SEPARATOR,
+  MENU_POPUPITEM, /*MP_MENUITEM,*/
+  MENU_POPUPSEPARATOR,  /*MP_SEPARATOR,*/
   SP_GRIPPER,
   SP_PANE,
   GP_LINEHORZ,
@@ -152,11 +167,13 @@ static const short element_part_map[XP_THEME_ELEMENT__SIZEOF] = {
   TKP_TICSVERT
 };
 
+#define UXTHEME_DLL "uxtheme.dll"
+
 static HINSTANCE uxtheme_dll = NULL;
 static HTHEME open_themes[XP_THEME_CLASS__SIZEOF];
 static gboolean use_xp_theme = FALSE;
 
-typedef HRESULT (FAR PASCAL *GetThemeSysFontFunc)           (HTHEME hTheme, int iFontID, OUT LOGFONT *plf);
+typedef HRESULT (FAR PASCAL *GetThemeSysFontFunc)           (HTHEME hTheme, int iFontID, OUT LOGFONTW *plf);
 typedef int (FAR PASCAL *GetThemeSysSizeFunc)               (HTHEME hTheme, int iSizeId);
 typedef COLORREF (FAR PASCAL *GetThemeSysColorFunc)         (HTHEME hTheme,
                                                             int iColorID);
@@ -175,6 +192,13 @@ typedef BOOL (FAR PASCAL *IsThemeBackgroundPartiallyTransparentFunc) (HTHEME hTh
 typedef HRESULT (FAR PASCAL *DrawThemeParentBackgroundFunc) (HWND hwnd,
                                                             HDC hdc,
                                                             RECT *prc);
+typedef HRESULT (FAR PASCAL *GetThemePartSizeFunc)          (HTHEME hTheme,
+                                                            HDC hdc,
+                                                            int iPartId,
+                                                            int iStateId,
+                                                            RECT *prc,
+                                                            int eSize,
+                                                            SIZE *psz);
 
 static GetThemeSysFontFunc get_theme_sys_font_func = NULL;
 static GetThemeSysColorFunc get_theme_sys_color_func = NULL;
@@ -187,6 +211,7 @@ static IsThemeActiveFunc is_theme_active_func = NULL;
 static IsAppThemedFunc is_app_themed_func = NULL;
 static IsThemeBackgroundPartiallyTransparentFunc is_theme_partially_transparent_func = NULL;
 static DrawThemeParentBackgroundFunc draw_theme_parent_background_func = NULL;
+static GetThemePartSizeFunc get_theme_part_size_func = NULL;
 
 static void
 xp_theme_close_open_handles (void)
@@ -206,12 +231,36 @@ xp_theme_close_open_handles (void)
 void
 xp_theme_init (void)
 {
+  char *buf;
+  char dummy;
+  int n, k;
+
   if (uxtheme_dll)
     return;
 
   memset (open_themes, 0, sizeof (open_themes));
 
-  uxtheme_dll = LoadLibrary ("uxtheme.dll");
+  n = GetSystemDirectory (&dummy, 0);
+
+  if (n <= 0)
+    return;
+
+  buf = g_malloc (n + 1 + strlen (UXTHEME_DLL));
+  k = GetSystemDirectory (buf, n);
+  
+  if (k == 0 || k > n)
+    {
+      g_free (buf);
+      return;
+    }
+
+  if (!G_IS_DIR_SEPARATOR (buf[strlen (buf) -1]))
+    strcat (buf, G_DIR_SEPARATOR_S);
+  strcat (buf, UXTHEME_DLL);
+
+  uxtheme_dll = LoadLibrary (buf);
+  g_free (buf);
+
   if (!uxtheme_dll)
     return;
 
@@ -229,6 +278,7 @@ xp_theme_init (void)
       get_theme_sys_metric_func = (GetThemeSysSizeFunc) GetProcAddress (uxtheme_dll, "GetThemeSysSize");
       is_theme_partially_transparent_func = (IsThemeBackgroundPartiallyTransparentFunc) GetProcAddress (uxtheme_dll, "IsThemeBackgroundPartiallyTransparent");
       draw_theme_parent_background_func = (DrawThemeParentBackgroundFunc) GetProcAddress (uxtheme_dll, "DrawThemeParentBackground");
+      get_theme_part_size_func = (GetThemePartSizeFunc) GetProcAddress (uxtheme_dll, "GetThemePartSize");
     }
 
   if (is_app_themed_func && is_theme_active_func)
@@ -279,6 +329,7 @@ xp_theme_exit (void)
   get_theme_sys_metric_func = NULL;
   is_theme_partially_transparent_func = NULL;
   draw_theme_parent_background_func = NULL;
+  get_theme_part_size_func = NULL;
 }
 
 static HTHEME
@@ -769,20 +820,27 @@ xp_theme_map_gtk_state (XpThemeElement element, GtkStateType state)
       ret = 1;
       break;
 
-    case XP_THEME_ELEMENT_MENU_ITEM:
     case XP_THEME_ELEMENT_MENU_SEPARATOR:
+      ret = TS_NORMAL;
+      break;
+
+    case XP_THEME_ELEMENT_MENU_ITEM:
       switch (state)
        {
        case GTK_STATE_SELECTED:
          ret = MS_SELECTED;
          break;
 
+       case GTK_STATE_PRELIGHT:
+         ret = MBI_HOT;
+         break;
+
        case GTK_STATE_INSENSITIVE:
-         ret = MS_DEMOTED;
+         ret = MBI_DISABLED;
          break;
 
        default:
-         ret = MS_NORMAL;
+         ret = MBI_NORMAL;
        }
       break;
 
@@ -832,16 +890,106 @@ xp_theme_map_gtk_state (XpThemeElement element, GtkStateType state)
   return ret;
 }
 
+HDC
+get_window_dc (GtkStyle *style,
+              cairo_t *cr,
+              GtkStateType state_type,
+              XpDCInfo *dc_info_out,
+              gint x, gint y, gint width, gint height,
+              RECT *rect_out)
+{
+  HDC hDC, hTempDC;
+  HBITMAP hBitmap, hOldBitmap;
+  cairo_surface_t *sourceCS, *tempCS;
+  cairo_t *tempCR;
+  double x_off = 0, y_off = 0;
+
+  dc_info_out->hdc = NULL;
+  
+  hDC = GetDC(NULL);
+  hTempDC = CreateCompatibleDC(hDC);
+  hBitmap = CreateCompatibleBitmap(hDC, x + width, y + height);
+  hOldBitmap = (HBITMAP)SelectObject(hTempDC, hBitmap);
+  ReleaseDC(NULL, hDC);
+
+  tempCS = cairo_win32_surface_create (hTempDC);
+  if (!tempCS)
+    return NULL;
+
+  sourceCS = cairo_get_target (cr);
+  tempCR = cairo_create (tempCS);
+  
+  /* FIXME: I am missing something here - why is it needed to have device
+   *        for cairo_set_source_surface() ? */
+  cairo_surface_get_device_offset (sourceCS, &x_off, &y_off);
+  cairo_set_source_surface (tempCR, sourceCS, x_off, y_off);
+  cairo_set_operator (tempCR, CAIRO_OPERATOR_OVER);
+  /* FIXME: Something is not quit right here - seems the CR or SURFACE do
+   *        not always have the correct data. Hovering on a GtkToolbar from
+   *        left to right draws the previous button over the next for ex. */
+  cairo_rectangle (tempCR, x, y, width, height);
+  cairo_fill (tempCR);
+  
+  cairo_destroy (tempCR);
+
+  cairo_surface_flush (tempCS);
+  cairo_surface_destroy (tempCS);
+  
+  rect_out->left = x;
+  rect_out->top = y;
+  rect_out->right = rect_out->left + width;
+  rect_out->bottom = rect_out->top + height;
+  
+  dc_info_out->hdc = hTempDC;
+  dc_info_out->hBitmap = hBitmap;
+  dc_info_out->hOldBitmap = hOldBitmap;
+  dc_info_out->cr = cr;
+  dc_info_out->x = x;
+  dc_info_out->y = y;
+  dc_info_out->width = width;
+  dc_info_out->height = height;
+  
+  return hTempDC;
+}
+
+void
+release_window_dc (XpDCInfo *dc_info)
+{
+  cairo_surface_t *tempCS, *target;
+
+  if (!dc_info->hdc)
+    return;
+
+  tempCS = cairo_win32_surface_create (dc_info->hdc);
+  target = cairo_get_target (dc_info->cr);
+
+  cairo_save (dc_info->cr);
+  
+  cairo_set_source_surface (dc_info->cr, tempCS, 0, 0);
+  cairo_set_operator (dc_info->cr, CAIRO_OPERATOR_OVER);
+  cairo_rectangle (dc_info->cr, dc_info->x, dc_info->y, dc_info->width, dc_info->height);
+  cairo_fill (dc_info->cr);
+  
+  cairo_restore (dc_info->cr);
+  
+  cairo_surface_destroy (tempCS);
+
+  SelectObject(dc_info->hdc, dc_info->hOldBitmap);
+  DeleteDC(dc_info->hdc);
+  DeleteObject(dc_info->hBitmap);
+  
+  dc_info->hdc = NULL;
+}
+
 gboolean
-xp_theme_draw (GdkWindow *win, XpThemeElement element, GtkStyle *style,
+xp_theme_draw (cairo_t *cr, XpThemeElement element, GtkStyle *style,
               int x, int y, int width, int height,
-              GtkStateType state_type, GdkRectangle *area)
+              GtkStateType state_type)
 {
   HTHEME theme;
-  RECT rect, clip, *pClip;
-  int xoff, yoff;
+  RECT rect;
   HDC dc;
-  GdkDrawable *drawable;
+  XpDCInfo dc_info;
   int part_state;
 
   if (!xp_theme_is_drawable (element))
@@ -852,49 +1000,26 @@ xp_theme_draw (GdkWindow *win, XpThemeElement element, GtkStyle *style,
     return FALSE;
 
   /* FIXME: Recheck its function */
-  enable_theme_dialog_texture_func (GDK_WINDOW_HWND (win), ETDT_ENABLETAB);
+//  if (GDK_IS_WINDOW (win) && gdk_win32_window_is_win32 (win))
+//    enable_theme_dialog_texture_func (GDK_WINDOW_HWND (win), ETDT_ENABLETAB);
 
-  if (!GDK_IS_WINDOW (win))
-    {
-      xoff = 0;
-      yoff = 0;
-      drawable = win;
-    }
-  else
-    {
-      gdk_window_get_internal_paint_info (win, &drawable, &xoff, &yoff);
-    }
-
-  rect.left = x - xoff;
-  rect.top = y - yoff;
-  rect.right = rect.left + width;
-  rect.bottom = rect.top + height;
-
-  if (area)
-    {
-      clip.left = area->x - xoff;
-      clip.top = area->y - yoff;
-      clip.right = clip.left + area->width;
-      clip.bottom = clip.top + area->height;
-
-      pClip = &clip;
-    }
-  else
-    {
-      pClip = NULL;
-    }
-
-  gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL);
-  dc = gdk_win32_hdc_get (drawable, style->dark_gc[state_type], 0);
+  dc = get_window_dc (style, cr, state_type, &dc_info,
+                     x, y, width, height,
+                     &rect);
   if (!dc)
     return FALSE;
 
   part_state = xp_theme_map_gtk_state (element, state_type);
 
+  /* Support transparency */
+//  if (is_theme_partially_transparent_func (theme, element_part_map[element], part_state))
+//    draw_theme_parent_background_func (GDK_WINDOW_HWND (win), dc, pClip);
+
+  /* FIXME: Should we get and handle clipping (check it on the CR?) ? */
   draw_theme_background_func (theme, dc, element_part_map[element],
-                             part_state, &rect, pClip);
+                             part_state, &rect, NULL);
 
-  gdk_win32_hdc_release (drawable, style->dark_gc[state_type], 0);
+  release_window_dc (&dc_info);
 
   return TRUE;
 }
@@ -914,9 +1039,58 @@ xp_theme_is_drawable (XpThemeElement element)
   return FALSE;
 }
 
+gboolean
+xp_theme_get_element_dimensions (XpThemeElement element,
+                                GtkStateType state_type,
+                                gint *cx, gint *cy)
+{
+  HTHEME theme;
+  SIZE part_size;
+  int part_state;
+
+  if (!xp_theme_is_active ())
+    return FALSE;
+
+  theme = xp_theme_get_handle_by_element (element);
+  if (!theme)
+    return FALSE;
+
+  part_state = xp_theme_map_gtk_state (element, state_type);
+
+  get_theme_part_size_func (theme,
+                           NULL,
+                           element_part_map[element],
+                           part_state,
+                           NULL,
+                           TS_MIN,
+                           &part_size);
+
+  *cx = part_size.cx;
+  *cy = part_size.cy;
+
+  if (element == XP_THEME_ELEMENT_MENU_ITEM ||
+      element == XP_THEME_ELEMENT_MENU_SEPARATOR)
+  {
+    SIZE gutter_size;
+
+    get_theme_part_size_func (theme,
+                             NULL,
+                             MENU_POPUPGUTTER,
+                             0,
+                             NULL,
+                             TS_MIN,
+                             &gutter_size);
+
+       *cx += gutter_size.cx * 2;
+       *cy += gutter_size.cy * 2;
+  }
+
+  return TRUE;
+}
+
 gboolean
 xp_theme_get_system_font (XpThemeClass klazz, XpThemeFont fontId,
-                         OUT LOGFONT *lf)
+                         OUT LOGFONTW *lf)
 {
   if (xp_theme_is_active () && get_theme_sys_font_func != NULL)
     {