]> 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 f86451570dcd95385f2b64338e0bd599db0bbcd0..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
@@ -37,6 +35,9 @@
 #include "gdk/win32/gdkwin32.h"
 #endif
 
+#include <cairo-win32.h>
+#include <gdk/gdk.h>
+
 #include "xp_theme_defs.h"
 
 #ifndef TMT_CAPTIONFONT
@@ -86,6 +87,7 @@
 #define MBI_DISABLEDHOT    5
 #define MBI_DISABLEDPUSHED 6
 
+#define MENU_POPUPGUTTER    13
 #define MENU_POPUPITEM      14
 #define MENU_POPUPSEPARATOR 15
 
@@ -165,6 +167,8 @@ 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;
@@ -188,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;
@@ -200,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)
@@ -219,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;
 
@@ -242,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)
@@ -292,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
@@ -782,8 +820,11 @@ 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:
@@ -851,52 +892,102 @@ xp_theme_map_gtk_state (XpThemeElement element, GtkStateType state)
 
 HDC
 get_window_dc (GtkStyle *style,
-              GdkWindow *window,
+              cairo_t *cr,
               GtkStateType state_type,
               XpDCInfo *dc_info_out,
               gint x, gint y, gint width, gint height,
               RECT *rect_out)
 {
-  GdkDrawable *drawable = NULL;
-  GdkGC *gc = style->dark_gc[state_type];
-  gint x_offset, y_offset;
-  
-  dc_info_out->data = NULL;
+  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;
   
-  drawable = gdk_win32_begin_direct_draw_libgtk_only (window,
-                                                     gc, &dc_info_out->data,
-                                                     &x_offset, &y_offset);
-  if (!drawable)
+  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;
 
-  rect_out->left = x - x_offset;
-  rect_out->top = y - y_offset;
+  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->drawable = drawable;
-  dc_info_out->gc = gc;
-  dc_info_out->x_offset = x_offset;
-  dc_info_out->y_offset = y_offset;
+  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 gdk_win32_hdc_get (drawable, gc, 0);
+  return hTempDC;
 }
 
 void
 release_window_dc (XpDCInfo *dc_info)
 {
-  gdk_win32_hdc_release (dc_info->drawable, dc_info->gc, 0);
+  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);
 
-  gdk_win32_end_direct_draw_libgtk_only (dc_info->data);
+  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;
+  RECT rect;
   HDC dc;
   XpDCInfo dc_info;
   int part_state;
@@ -909,36 +1000,27 @@ xp_theme_draw (GdkWindow *win, XpThemeElement element, GtkStyle *style,
     return FALSE;
 
   /* FIXME: Recheck its function */
-  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) && gdk_win32_window_is_win32 (win))
+//    enable_theme_dialog_texture_func (GDK_WINDOW_HWND (win), ETDT_ENABLETAB);
 
-  dc = get_window_dc (style, win, state_type, &dc_info,
+  dc = get_window_dc (style, cr, state_type, &dc_info,
                      x, y, width, height,
                      &rect);
   if (!dc)
     return FALSE;
 
-  if (area)
-    {
-      clip.left = area->x - dc_info.x_offset;
-      clip.top = area->y - dc_info.y_offset;
-      clip.right = clip.left + area->width;
-      clip.bottom = clip.top + area->height;
-
-      pClip = &clip;
-    }
-  else
-    {
-      pClip = NULL;
-    }
-
   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);
 
   release_window_dc (&dc_info);
-  
+
   return TRUE;
 }
 
@@ -957,6 +1039,55 @@ 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 LOGFONTW *lf)