From ec3715b113dcb4209ccbcfb77dcf52bb8dc5e2d0 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 9 Aug 2015 17:59:13 +0200 Subject: [PATCH] Added patch for native GTK3 theming support by Ivan Akulinchev. --- README.md | 3 +- debian/changelog | 1 + patches/patchinstall.sh | 130 +- ...gtk-Add-configure-check-and-stub-dll.patch | 467 +++ ...02-uxthemegtk-Initial-implementation.patch | 3568 +++++++++++++++++ ...ment-enumeration-of-themes-color-and.patch | 308 ++ patches/uxtheme-GTK_Theming/definition | 4 + 7 files changed, 4427 insertions(+), 54 deletions(-) create mode 100644 patches/uxtheme-GTK_Theming/0001-uxthemegtk-Add-configure-check-and-stub-dll.patch create mode 100644 patches/uxtheme-GTK_Theming/0002-uxthemegtk-Initial-implementation.patch create mode 100644 patches/uxtheme-GTK_Theming/0003-uxthemegtk-Implement-enumeration-of-themes-color-and.patch create mode 100644 patches/uxtheme-GTK_Theming/definition diff --git a/README.md b/README.md index c622bb6e..ea2acd64 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,11 @@ Wine. All those differences are also documented on the Included bug fixes and improvements ----------------------------------- -**Bug fixes and features included in the next upcoming release [8]:** +**Bug fixes and features included in the next upcoming release [9]:** * Add stub dlls required for MSVC 2015 runtime library (Windows 10) * Add stubs for additional wininet options in InternetSetOption +* Add support for GTK3 theming * Fake success in IViewObject::Draw stub ([Wine Bug #30611](https://bugs.winehq.org/show_bug.cgi?id=30611)) * Fix possible integer overflow in VarR4FromDec ([Wine Bug #38988](https://bugs.winehq.org/show_bug.cgi?id=38988)) * Implement stub for vcomp._vcomp_flush ([Wine Bug #39058](https://bugs.winehq.org/show_bug.cgi?id=39058)) diff --git a/debian/changelog b/debian/changelog index b38a4555..85abfeea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ wine-staging (1.7.49) UNRELEASED; urgency=low * Added patch to fix possible integer overflow in VarR4FromDec. * Added patch to make sure Winhttp raw request headers are terminated using double \r\n. + * Added patch for native GTK3 theming support by Ivan Akulinchev. * Removed patch to avoid race-conditions with long running threadpool tasks (accepted upstream). * Removed patch to add support for ThreadQuerySetWin32StartAddress info class diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 86d0f764..3998d291 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -241,6 +241,7 @@ patch_enable_all () enable_user32_Painting="$1" enable_user32_ScrollWindowEx="$1" enable_user32_WndProc="$1" + enable_uxtheme_GTK_Theming="$1" enable_vcomp_Functions="$1" enable_version_VerQueryValue="$1" enable_wbemdisp_ISWbemSecurity="$1" @@ -805,6 +806,9 @@ patch_enable () user32-WndProc) enable_user32_WndProc="$2" ;; + uxtheme-GTK_Theming) + enable_uxtheme_GTK_Theming="$2" + ;; vcomp-Functions) enable_vcomp_Functions="$2" ;; @@ -4781,6 +4785,26 @@ if test "$enable_user32_WndProc" -eq 1; then ) >> "$patchlist" fi +# Patchset uxtheme-GTK_Theming +# | +# | Modified files: +# | * aclocal.m4, configure.ac, dlls/uxtheme-gtk/Makefile.in, dlls/uxtheme-gtk/button.c, dlls/uxtheme-gtk/combobox.c, dlls +# | /uxtheme-gtk/edit.c, dlls/uxtheme-gtk/header.c, dlls/uxtheme-gtk/listbox.c, dlls/uxtheme-gtk/listview.c, dlls/uxtheme- +# | gtk/menu.c, dlls/uxtheme-gtk/rebar.c, dlls/uxtheme-gtk/status.c, dlls/uxtheme-gtk/tab.c, dlls/uxtheme-gtk/toolbar.c, +# | dlls/uxtheme-gtk/trackbar.c, dlls/uxtheme-gtk/uxtheme-gtk.spec, dlls/uxtheme-gtk/uxtheme.c, dlls/uxtheme- +# | gtk/uxthemegtk.h, dlls/uxtheme-gtk/version.rc, dlls/uxtheme-gtk/window.c +# | +if test "$enable_uxtheme_GTK_Theming" -eq 1; then + patch_apply uxtheme-GTK_Theming/0001-uxthemegtk-Add-configure-check-and-stub-dll.patch + patch_apply uxtheme-GTK_Theming/0002-uxthemegtk-Initial-implementation.patch + patch_apply uxtheme-GTK_Theming/0003-uxthemegtk-Implement-enumeration-of-themes-color-and.patch + ( + echo '+ { "Michael Müller", "uxthemegtk: Add configure check and stub dll.", 1 },'; + echo '+ { "Ivan Akulinchev", "uxthemegtk: Initial implementation.", 1 },'; + echo '+ { "Michael Müller", "uxthemegtk: Implement enumeration of themes, color and sizes.", 1 },'; + ) >> "$patchlist" +fi + # Patchset vcomp-Functions # | # | This patchset fixes the following Wine bugs: @@ -4998,15 +5022,51 @@ if test "$enable_wined3d_CSMT_Helper" -eq 1; then ) >> "$patchlist" fi -# Patchset wined3d-MESA_GPU_Info +# Patchset wined3d-Geforce_425M +# | +# | This patchset fixes the following Wine bugs: +# | * [#35054] Add wined3d detection for GeForce GT 425M # | # | Modified files: -# | * dlls/wined3d/directx.c, dlls/wined3d/wined3d_gl.h, dlls/winex11.drv/opengl.c, include/wine/wgl_driver.h +# | * dlls/wined3d/directx.c, dlls/wined3d/wined3d_private.h # | -if test "$enable_wined3d_MESA_GPU_Info" -eq 1; then - patch_apply wined3d-MESA_GPU_Info/0001-wined3d-Use-pci-and-memory-information-from-MESA-if-.patch +if test "$enable_wined3d_Geforce_425M" -eq 1; then + patch_apply wined3d-Geforce_425M/0001-wined3d-Add-detection-for-NVIDIA-GeForce-425M.patch ( - echo '+ { "Michael Müller", "wined3d: Use pci and memory information from MESA if possible.", 2 },'; + echo '+ { "Jarkko Korpi", "wined3d: Add detection for NVIDIA GeForce 425M.", 1 },'; + ) >> "$patchlist" +fi + +# Patchset wined3d-Revert_PixelFormat +# | +# | This patchset fixes the following Wine bugs: +# | * [#35655] Fix wined3d performance drop introduced by pixelformat changes. +# | * [#35718] Fix flickering introduced by pixelformat changes. +# | * [#35975] Fix gray screen on startup introduced by pixelformat changes. +# | * [#36900] Fix missing video introduced by pixelformat changes. +# | +# | Modified files: +# | * dlls/d3d8/tests/device.c, dlls/d3d9/tests/device.c, dlls/ddraw/tests/ddraw1.c, dlls/ddraw/tests/ddraw2.c, +# | dlls/ddraw/tests/ddraw4.c, dlls/ddraw/tests/ddraw7.c, dlls/wined3d/context.c, dlls/wined3d/wined3d_private.h +# | +if test "$enable_wined3d_Revert_PixelFormat" -eq 1; then + patch_apply wined3d-Revert_PixelFormat/0001-Revert-wined3d-Track-if-a-context-s-private-hdc-has-.patch + patch_apply wined3d-Revert_PixelFormat/0002-Revert-wined3d-Track-if-a-context-s-hdc-is-private-s.patch + patch_apply wined3d-Revert_PixelFormat/0003-Revert-wined3d-When-restoring-pixel-format-in-contex.patch + patch_apply wined3d-Revert_PixelFormat/0004-Revert-wined3d-Don-t-call-GetPixelFormat-to-set-a-fl.patch + patch_apply wined3d-Revert_PixelFormat/0005-Revert-wined3d-Restore-the-pixel-format-of-the-windo.patch + patch_apply wined3d-Revert_PixelFormat/0006-d3d8-Mark-tests-which-no-longer-pass-due-to-reverts-.patch + patch_apply wined3d-Revert_PixelFormat/0007-d3d9-Mark-tests-which-no-longer-pass-due-to-reverts-.patch + patch_apply wined3d-Revert_PixelFormat/0008-ddraw-Mark-tests-which-no-longer-pass-due-to-reverts.patch + ( + echo '+ { "Ken Thomases", "Revert \"wined3d: Track if a context'\''s private hdc has had its pixel format set, so we don'\''t need to check it.\".", 1 },'; + echo '+ { "Ken Thomases", "Revert \"wined3d: Track if a context'\''s hdc is private so we never need to restore its pixel format.\".", 1 },'; + echo '+ { "Ken Thomases", "Revert \"wined3d: When restoring pixel format in context_release(), mark the context as needing to be set on the next context_acquire().\".", 1 },'; + echo '+ { "Ken Thomases", "Revert \"wined3d: Don'\''t call GetPixelFormat() to set a flag that'\''s already set.\".", 1 },'; + echo '+ { "Ken Thomases", "Revert \"wined3d: Restore the pixel format of the window whose pixel format was actually changed.\".", 1 },'; + echo '+ { "Ken Thomases", "d3d8: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; + echo '+ { "Ken Thomases", "d3d9: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; + echo '+ { "Ken Thomases", "ddraw: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; ) >> "$patchlist" fi @@ -5046,6 +5106,18 @@ if test "$enable_wined3d_wined3d_swapchain_present" -eq 1; then ) >> "$patchlist" fi +# Patchset wined3d-MESA_GPU_Info +# | +# | Modified files: +# | * dlls/wined3d/directx.c, dlls/wined3d/wined3d_gl.h, dlls/winex11.drv/opengl.c, include/wine/wgl_driver.h +# | +if test "$enable_wined3d_MESA_GPU_Info" -eq 1; then + patch_apply wined3d-MESA_GPU_Info/0001-wined3d-Use-pci-and-memory-information-from-MESA-if-.patch + ( + echo '+ { "Michael Müller", "wined3d: Use pci and memory information from MESA if possible.", 2 },'; + ) >> "$patchlist" +fi + # Patchset wined3d-Multisampling # | # | This patchset fixes the following Wine bugs: @@ -5061,54 +5133,6 @@ if test "$enable_wined3d_Multisampling" -eq 1; then ) >> "$patchlist" fi -# Patchset wined3d-Revert_PixelFormat -# | -# | This patchset fixes the following Wine bugs: -# | * [#35655] Fix wined3d performance drop introduced by pixelformat changes. -# | * [#35718] Fix flickering introduced by pixelformat changes. -# | * [#35975] Fix gray screen on startup introduced by pixelformat changes. -# | * [#36900] Fix missing video introduced by pixelformat changes. -# | -# | Modified files: -# | * dlls/d3d8/tests/device.c, dlls/d3d9/tests/device.c, dlls/ddraw/tests/ddraw1.c, dlls/ddraw/tests/ddraw2.c, -# | dlls/ddraw/tests/ddraw4.c, dlls/ddraw/tests/ddraw7.c, dlls/wined3d/context.c, dlls/wined3d/wined3d_private.h -# | -if test "$enable_wined3d_Revert_PixelFormat" -eq 1; then - patch_apply wined3d-Revert_PixelFormat/0001-Revert-wined3d-Track-if-a-context-s-private-hdc-has-.patch - patch_apply wined3d-Revert_PixelFormat/0002-Revert-wined3d-Track-if-a-context-s-hdc-is-private-s.patch - patch_apply wined3d-Revert_PixelFormat/0003-Revert-wined3d-When-restoring-pixel-format-in-contex.patch - patch_apply wined3d-Revert_PixelFormat/0004-Revert-wined3d-Don-t-call-GetPixelFormat-to-set-a-fl.patch - patch_apply wined3d-Revert_PixelFormat/0005-Revert-wined3d-Restore-the-pixel-format-of-the-windo.patch - patch_apply wined3d-Revert_PixelFormat/0006-d3d8-Mark-tests-which-no-longer-pass-due-to-reverts-.patch - patch_apply wined3d-Revert_PixelFormat/0007-d3d9-Mark-tests-which-no-longer-pass-due-to-reverts-.patch - patch_apply wined3d-Revert_PixelFormat/0008-ddraw-Mark-tests-which-no-longer-pass-due-to-reverts.patch - ( - echo '+ { "Ken Thomases", "Revert \"wined3d: Track if a context'\''s private hdc has had its pixel format set, so we don'\''t need to check it.\".", 1 },'; - echo '+ { "Ken Thomases", "Revert \"wined3d: Track if a context'\''s hdc is private so we never need to restore its pixel format.\".", 1 },'; - echo '+ { "Ken Thomases", "Revert \"wined3d: When restoring pixel format in context_release(), mark the context as needing to be set on the next context_acquire().\".", 1 },'; - echo '+ { "Ken Thomases", "Revert \"wined3d: Don'\''t call GetPixelFormat() to set a flag that'\''s already set.\".", 1 },'; - echo '+ { "Ken Thomases", "Revert \"wined3d: Restore the pixel format of the window whose pixel format was actually changed.\".", 1 },'; - echo '+ { "Ken Thomases", "d3d8: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; - echo '+ { "Ken Thomases", "d3d9: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; - echo '+ { "Ken Thomases", "ddraw: Mark tests which no longer pass due to reverts as todo_wine.", 1 },'; - ) >> "$patchlist" -fi - -# Patchset wined3d-Geforce_425M -# | -# | This patchset fixes the following Wine bugs: -# | * [#35054] Add wined3d detection for GeForce GT 425M -# | -# | Modified files: -# | * dlls/wined3d/directx.c, dlls/wined3d/wined3d_private.h -# | -if test "$enable_wined3d_Geforce_425M" -eq 1; then - patch_apply wined3d-Geforce_425M/0001-wined3d-Add-detection-for-NVIDIA-GeForce-425M.patch - ( - echo '+ { "Jarkko Korpi", "wined3d: Add detection for NVIDIA GeForce 425M.", 1 },'; - ) >> "$patchlist" -fi - # Patchset wined3d-CSMT_Main # | # | This patchset fixes the following Wine bugs: diff --git a/patches/uxtheme-GTK_Theming/0001-uxthemegtk-Add-configure-check-and-stub-dll.patch b/patches/uxtheme-GTK_Theming/0001-uxthemegtk-Add-configure-check-and-stub-dll.patch new file mode 100644 index 00000000..3160d6c7 --- /dev/null +++ b/patches/uxtheme-GTK_Theming/0001-uxthemegtk-Add-configure-check-and-stub-dll.patch @@ -0,0 +1,467 @@ +From 01290dd262f7cfc9ee7799fb8f20c5b43ce60e86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sun, 9 Aug 2015 02:38:18 +0200 +Subject: uxthemegtk: Add configure check and stub dll. + +List of functions updated by Ivan Akulinchev . +--- + aclocal.m4 | 20 ++++ + configure.ac | 22 ++++ + dlls/uxtheme-gtk/Makefile.in | 7 ++ + dlls/uxtheme-gtk/uxtheme-gtk.spec | 1 + + dlls/uxtheme-gtk/uxtheme.c | 218 ++++++++++++++++++++++++++++++++++++++ + dlls/uxtheme-gtk/uxthemegtk.h | 88 +++++++++++++++ + dlls/uxtheme-gtk/version.rc | 21 ++++ + 7 files changed, 377 insertions(+) + create mode 100644 dlls/uxtheme-gtk/Makefile.in + create mode 100644 dlls/uxtheme-gtk/uxtheme-gtk.spec + create mode 100644 dlls/uxtheme-gtk/uxtheme.c + create mode 100644 dlls/uxtheme-gtk/uxthemegtk.h + create mode 100644 dlls/uxtheme-gtk/version.rc + +diff --git a/aclocal.m4 b/aclocal.m4 +index f7a12f1..770a0d8 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -109,6 +109,26 @@ test -z "$ac_libs" || ac_libs=`echo " $ac_libs" | sed 's/ -L\([[^/]]\)/ -L\$(top + AS_VAR_POPDEF([ac_libs])dnl + AS_VAR_POPDEF([ac_cflags])])dnl + ++dnl **** Get include path from pkg-config **** ++dnl ++dnl Usage: WINE_PACKAGE_INCLUDE_FLAGS(var,pkg-name,[cflags-alternate,[checks]]]) ++dnl ++AC_DEFUN([WINE_PACKAGE_INCLUDE_FLAGS], ++[AC_REQUIRE([WINE_PATH_PKG_CONFIG])dnl ++AS_VAR_PUSHDEF([ac_cflags],[[$1]_CFLAGS])dnl ++AC_ARG_VAR(ac_cflags, [C compiler flags for $2, overriding pkg-config])dnl ++AS_VAR_IF([ac_cflags],[], ++ [AS_VAR_SET_IF([PKG_CONFIG], ++ [ac_cflags=`$PKG_CONFIG --cflags-only-I [$2] 2>/dev/null`])]) ++m4_ifval([$3],[test "$cross_compiling" = yes || ac_cflags=[$]{ac_cflags:-[$3]}]) ++AS_ECHO(["$as_me:${as_lineno-$LINENO}: $2 cflags: $ac_cflags"]) >&AS_MESSAGE_LOG_FD ++ac_save_CPPFLAGS=$CPPFLAGS ++CPPFLAGS="$CPPFLAGS $ac_cflags" ++$4 ++CPPFLAGS=$ac_save_CPPFLAGS ++test -z "$ac_cflags" || ac_cflags=`echo " $ac_cflags" | sed 's/ -I\([[^/]]\)/ -I\$(top_builddir)\/\1/g'` ++AS_VAR_POPDEF([ac_cflags])])dnl ++ + dnl **** Link C code with an assembly file **** + dnl + dnl Usage: WINE_TRY_ASM_LINK(asm-code,includes,function,[action-if-found,[action-if-not-found]]) +diff --git a/configure.ac b/configure.ac +index 1329786..6fb4ad0 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -54,6 +54,7 @@ AC_ARG_WITH(gnutls, AS_HELP_STRING([--without-gnutls],[do not use GnuTLS (sch + AC_ARG_WITH(gsm, AS_HELP_STRING([--without-gsm],[do not use libgsm (GSM 06.10 codec support)]), + [if test "x$withval" = "xno"; then ac_cv_header_gsm_h=no; ac_cv_header_gsm_gsm_h=no; fi]) + AC_ARG_WITH(gstreamer, AS_HELP_STRING([--without-gstreamer],[do not use GStreamer (codecs support)])) ++AC_ARG_WITH(gtk3, AS_HELP_STRING([--without-gtk3],[do not use gtk3 (gtk3 theming support)])) + AC_ARG_WITH(hal, AS_HELP_STRING([--without-hal],[do not use HAL (dynamic device support)])) + AC_ARG_WITH(jpeg, AS_HELP_STRING([--without-jpeg],[do not use JPEG])) + AC_ARG_WITH(ldap, AS_HELP_STRING([--without-ldap],[do not use LDAP]), +@@ -1486,6 +1487,26 @@ fi + WINE_NOTICE_WITH(cms,[test "$ac_cv_lib_lcms2_cmsOpenProfileFromFile" != "yes"], + [liblcms2 ${notice_platform}development files not found, Color Management won't be supported.]) + ++dnl **** Check for GTK3 **** ++if test "x$with_gtk3" != "xno"; ++then ++ WINE_PACKAGE_INCLUDE_FLAGS(GTK3, [gtk+-3.0],, ++ [AC_CHECK_HEADERS([gtk/gtk.h]) ++ if test "$ac_cv_header_gtk_gtk_h" = "yes" ++ then ++ WINE_CHECK_SONAME(gobject-2.0,g_object_unref, ++ [WINE_CHECK_SONAME(cairo,cairo_destroy, ++ [WINE_CHECK_SONAME(gtk-3,gtk_style_context_save, ++ [AC_DEFINE(HAVE_GTK3, 1, [Define if GTK 3 is installed])])])]) ++ test "x$ac_cv_lib_soname_gtk_3" != "x" || GTK3_CFLAGS="" ++ else ++ GTK3_CFLAGS="" ++ fi]) ++fi ++WINE_NOTICE_WITH(gtk3,[test "x$ac_cv_lib_soname_gtk_3" = x], ++ [GTK3 ${notice_platform}development files not found, GTK themes won't be supported.]) ++test "x$ac_cv_lib_soname_gtk_3" != "x" || enable_uxtheme_gtk=${enable_uxtheme_gtk:-no} ++ + dnl **** Check for FreeType 2 **** + if test "x$with_freetype" != "xno" + then +@@ -3319,6 +3340,7 @@ WINE_CONFIG_TEST(dlls/usp10/tests) + WINE_CONFIG_LIB(uuid) + WINE_CONFIG_DLL(uxtheme,,[implib]) + WINE_CONFIG_TEST(dlls/uxtheme/tests) ++WINE_CONFIG_DLL(uxtheme-gtk) + WINE_CONFIG_DLL(vbscript,,[clean]) + WINE_CONFIG_TEST(dlls/vbscript/tests,[clean]) + WINE_CONFIG_DLL(vcomp) +diff --git a/dlls/uxtheme-gtk/Makefile.in b/dlls/uxtheme-gtk/Makefile.in +new file mode 100644 +index 0000000..07cf3a0f +--- /dev/null ++++ b/dlls/uxtheme-gtk/Makefile.in +@@ -0,0 +1,7 @@ ++MODULE = uxtheme-gtk.dll ++EXTRAINCL = $(GTK3_CFLAGS) ++ ++C_SRCS = \ ++ uxtheme.c ++ ++RC_SRCS = version.rc +diff --git a/dlls/uxtheme-gtk/uxtheme-gtk.spec b/dlls/uxtheme-gtk/uxtheme-gtk.spec +new file mode 100644 +index 0000000..b7db254 +--- /dev/null ++++ b/dlls/uxtheme-gtk/uxtheme-gtk.spec +@@ -0,0 +1 @@ ++# Empty +diff --git a/dlls/uxtheme-gtk/uxtheme.c b/dlls/uxtheme-gtk/uxtheme.c +new file mode 100644 +index 0000000..cd5e3c0 +--- /dev/null ++++ b/dlls/uxtheme-gtk/uxtheme.c +@@ -0,0 +1,218 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Michael Müller ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "config.h" ++#include "wine/port.h" ++#include "wine/library.h" ++ ++#include "wine/debug.h" ++#include "uxthemegtk.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++static void *libgtk3 = NULL; ++static void *libcairo = NULL; ++static void *libgobject2 = NULL; ++ ++#define MAKE_FUNCPTR(f) typeof(f) * p##f = NULL ++MAKE_FUNCPTR(cairo_create); ++MAKE_FUNCPTR(cairo_destroy); ++MAKE_FUNCPTR(cairo_image_surface_create); ++MAKE_FUNCPTR(cairo_image_surface_get_data); ++MAKE_FUNCPTR(cairo_image_surface_get_stride); ++MAKE_FUNCPTR(cairo_surface_destroy); ++MAKE_FUNCPTR(cairo_surface_flush); ++MAKE_FUNCPTR(g_type_check_instance_is_a); ++MAKE_FUNCPTR(gtk_bin_get_child); ++MAKE_FUNCPTR(gtk_button_new); ++MAKE_FUNCPTR(gtk_check_button_new); ++MAKE_FUNCPTR(gtk_combo_box_new_with_entry); ++MAKE_FUNCPTR(gtk_container_add); ++MAKE_FUNCPTR(gtk_container_forall); ++MAKE_FUNCPTR(gtk_entry_new); ++MAKE_FUNCPTR(gtk_fixed_new); ++MAKE_FUNCPTR(gtk_frame_new); ++MAKE_FUNCPTR(gtk_init); ++MAKE_FUNCPTR(gtk_label_new); ++MAKE_FUNCPTR(gtk_menu_bar_new); ++MAKE_FUNCPTR(gtk_menu_item_new); ++MAKE_FUNCPTR(gtk_menu_item_set_submenu); ++MAKE_FUNCPTR(gtk_menu_new); ++MAKE_FUNCPTR(gtk_menu_shell_append); ++MAKE_FUNCPTR(gtk_notebook_new); ++MAKE_FUNCPTR(gtk_radio_button_new); ++MAKE_FUNCPTR(gtk_render_arrow); ++MAKE_FUNCPTR(gtk_render_background); ++MAKE_FUNCPTR(gtk_render_check); ++MAKE_FUNCPTR(gtk_render_frame); ++MAKE_FUNCPTR(gtk_render_handle); ++MAKE_FUNCPTR(gtk_render_line); ++MAKE_FUNCPTR(gtk_render_option); ++MAKE_FUNCPTR(gtk_render_slider); ++MAKE_FUNCPTR(gtk_scale_new); ++MAKE_FUNCPTR(gtk_scrolled_window_new); ++MAKE_FUNCPTR(gtk_separator_tool_item_new); ++MAKE_FUNCPTR(gtk_style_context_add_class); ++MAKE_FUNCPTR(gtk_style_context_add_region); ++MAKE_FUNCPTR(gtk_style_context_get_background_color); ++MAKE_FUNCPTR(gtk_style_context_get_border_color); ++MAKE_FUNCPTR(gtk_style_context_get_color); ++MAKE_FUNCPTR(gtk_style_context_remove_class); ++MAKE_FUNCPTR(gtk_style_context_restore); ++MAKE_FUNCPTR(gtk_style_context_save); ++MAKE_FUNCPTR(gtk_style_context_set_junction_sides); ++MAKE_FUNCPTR(gtk_style_context_set_state); ++MAKE_FUNCPTR(gtk_toggle_button_get_type); ++MAKE_FUNCPTR(gtk_toolbar_new); ++MAKE_FUNCPTR(gtk_tree_view_append_column); ++MAKE_FUNCPTR(gtk_tree_view_column_get_button); ++MAKE_FUNCPTR(gtk_tree_view_column_new); ++MAKE_FUNCPTR(gtk_tree_view_get_column); ++MAKE_FUNCPTR(gtk_tree_view_new); ++MAKE_FUNCPTR(gtk_widget_destroy); ++MAKE_FUNCPTR(gtk_widget_get_style_context); ++MAKE_FUNCPTR(gtk_widget_style_get); ++MAKE_FUNCPTR(gtk_window_new); ++#undef MAKE_FUNCPTR ++ ++static void free_gtk3_libs(void) ++{ ++ if (libgtk3) wine_dlclose(libgtk3, NULL, 0); ++ if (libcairo) wine_dlclose(libcairo, NULL, 0); ++ if (libgobject2) wine_dlclose(libgobject2, NULL, 0); ++ libgtk3 = libcairo = libgobject2 = NULL; ++} ++ ++#define LOAD_FUNCPTR(lib, f) \ ++ if(!(p##f = wine_dlsym(lib, #f, NULL, 0))) \ ++ { \ ++ WARN("Can't find symbol %s.\n", #f); \ ++ goto error; \ ++ } ++ ++static BOOL load_gtk3_libs(void) ++{ ++ libgtk3 = wine_dlopen(SONAME_LIBGTK_3, RTLD_NOW, NULL, 0); ++ if (!libgtk3) ++ { ++ FIXME("Wine cannot find the %s library.\n", SONAME_LIBGTK_3); ++ goto error; ++ } ++ ++ LOAD_FUNCPTR(libgtk3, gtk_bin_get_child) ++ LOAD_FUNCPTR(libgtk3, gtk_button_new) ++ LOAD_FUNCPTR(libgtk3, gtk_check_button_new) ++ LOAD_FUNCPTR(libgtk3, gtk_combo_box_new_with_entry) ++ LOAD_FUNCPTR(libgtk3, gtk_container_add) ++ LOAD_FUNCPTR(libgtk3, gtk_container_forall) ++ LOAD_FUNCPTR(libgtk3, gtk_entry_new) ++ LOAD_FUNCPTR(libgtk3, gtk_fixed_new) ++ LOAD_FUNCPTR(libgtk3, gtk_frame_new) ++ LOAD_FUNCPTR(libgtk3, gtk_init) ++ LOAD_FUNCPTR(libgtk3, gtk_label_new) ++ LOAD_FUNCPTR(libgtk3, gtk_menu_bar_new) ++ LOAD_FUNCPTR(libgtk3, gtk_menu_item_new) ++ LOAD_FUNCPTR(libgtk3, gtk_menu_item_set_submenu) ++ LOAD_FUNCPTR(libgtk3, gtk_menu_new) ++ LOAD_FUNCPTR(libgtk3, gtk_menu_shell_append) ++ LOAD_FUNCPTR(libgtk3, gtk_notebook_new) ++ LOAD_FUNCPTR(libgtk3, gtk_radio_button_new) ++ LOAD_FUNCPTR(libgtk3, gtk_render_arrow) ++ LOAD_FUNCPTR(libgtk3, gtk_render_background) ++ LOAD_FUNCPTR(libgtk3, gtk_render_check) ++ LOAD_FUNCPTR(libgtk3, gtk_render_frame) ++ LOAD_FUNCPTR(libgtk3, gtk_render_handle) ++ LOAD_FUNCPTR(libgtk3, gtk_render_line) ++ LOAD_FUNCPTR(libgtk3, gtk_render_option) ++ LOAD_FUNCPTR(libgtk3, gtk_render_slider) ++ LOAD_FUNCPTR(libgtk3, gtk_scale_new) ++ LOAD_FUNCPTR(libgtk3, gtk_scrolled_window_new) ++ LOAD_FUNCPTR(libgtk3, gtk_separator_tool_item_new) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_add_class) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_add_region) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_get_background_color) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_get_border_color) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_get_color) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_remove_class) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_restore) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_save) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_set_junction_sides) ++ LOAD_FUNCPTR(libgtk3, gtk_style_context_set_state) ++ LOAD_FUNCPTR(libgtk3, gtk_toggle_button_get_type) ++ LOAD_FUNCPTR(libgtk3, gtk_toolbar_new) ++ LOAD_FUNCPTR(libgtk3, gtk_tree_view_append_column) ++ LOAD_FUNCPTR(libgtk3, gtk_tree_view_column_get_button) ++ LOAD_FUNCPTR(libgtk3, gtk_tree_view_column_new) ++ LOAD_FUNCPTR(libgtk3, gtk_tree_view_get_column) ++ LOAD_FUNCPTR(libgtk3, gtk_tree_view_new) ++ LOAD_FUNCPTR(libgtk3, gtk_widget_destroy) ++ LOAD_FUNCPTR(libgtk3, gtk_widget_get_style_context) ++ LOAD_FUNCPTR(libgtk3, gtk_widget_style_get) ++ LOAD_FUNCPTR(libgtk3, gtk_window_new) ++ ++ libcairo = wine_dlopen(SONAME_LIBCAIRO, RTLD_NOW, NULL, 0); ++ if (!libcairo) ++ { ++ FIXME("Wine cannot find the %s library.\n", SONAME_LIBCAIRO); ++ goto error; ++ } ++ ++ LOAD_FUNCPTR(libcairo, cairo_create) ++ LOAD_FUNCPTR(libcairo, cairo_destroy) ++ LOAD_FUNCPTR(libcairo, cairo_image_surface_create) ++ LOAD_FUNCPTR(libcairo, cairo_image_surface_get_data) ++ LOAD_FUNCPTR(libcairo, cairo_image_surface_get_stride) ++ LOAD_FUNCPTR(libcairo, cairo_surface_destroy) ++ LOAD_FUNCPTR(libcairo, cairo_surface_flush) ++ ++ libgobject2 = wine_dlopen(SONAME_LIBGOBJECT_2_0, RTLD_NOW, NULL, 0); ++ if (!libgobject2) ++ { ++ FIXME("Wine cannot find the %s library.\n", SONAME_LIBGOBJECT_2_0); ++ goto error; ++ } ++ ++ LOAD_FUNCPTR(libgobject2, g_type_check_instance_is_a) ++ return TRUE; ++ ++error: ++ free_gtk3_libs(); ++ return FALSE; ++} ++ ++BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) ++{ ++ TRACE("(%p, %d, %p)\n", instance, reason, reserved); ++ ++ switch (reason) ++ { ++ case DLL_PROCESS_ATTACH: ++ DisableThreadLibraryCalls(instance); ++ if (!load_gtk3_libs()) return FALSE; ++ break; ++ ++ case DLL_PROCESS_DETACH: ++ if (reserved) break; ++ free_gtk3_libs(); ++ break; ++ } ++ ++ return TRUE; ++} +diff --git a/dlls/uxtheme-gtk/uxthemegtk.h b/dlls/uxtheme-gtk/uxthemegtk.h +new file mode 100644 +index 0000000..42e4784 +--- /dev/null ++++ b/dlls/uxtheme-gtk/uxthemegtk.h +@@ -0,0 +1,88 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Michael Müller ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#ifndef UXTHEMEGTK_H ++#define UXTHEMEGTK_H ++ ++#define GDK_DISABLE_DEPRECATION_WARNINGS ++#include ++ ++#define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN ++MAKE_FUNCPTR(cairo_create); ++MAKE_FUNCPTR(cairo_destroy); ++MAKE_FUNCPTR(cairo_image_surface_create); ++MAKE_FUNCPTR(cairo_image_surface_get_data); ++MAKE_FUNCPTR(cairo_image_surface_get_stride); ++MAKE_FUNCPTR(cairo_surface_destroy); ++MAKE_FUNCPTR(cairo_surface_flush); ++MAKE_FUNCPTR(g_type_check_instance_is_a); ++MAKE_FUNCPTR(gtk_bin_get_child); ++MAKE_FUNCPTR(gtk_button_new); ++MAKE_FUNCPTR(gtk_check_button_new); ++MAKE_FUNCPTR(gtk_combo_box_new_with_entry); ++MAKE_FUNCPTR(gtk_container_add); ++MAKE_FUNCPTR(gtk_container_forall); ++MAKE_FUNCPTR(gtk_entry_new); ++MAKE_FUNCPTR(gtk_fixed_new); ++MAKE_FUNCPTR(gtk_frame_new); ++MAKE_FUNCPTR(gtk_init); ++MAKE_FUNCPTR(gtk_label_new); ++MAKE_FUNCPTR(gtk_menu_bar_new); ++MAKE_FUNCPTR(gtk_menu_item_new); ++MAKE_FUNCPTR(gtk_menu_item_set_submenu); ++MAKE_FUNCPTR(gtk_menu_new); ++MAKE_FUNCPTR(gtk_menu_shell_append); ++MAKE_FUNCPTR(gtk_notebook_new); ++MAKE_FUNCPTR(gtk_radio_button_new); ++MAKE_FUNCPTR(gtk_render_arrow); ++MAKE_FUNCPTR(gtk_render_background); ++MAKE_FUNCPTR(gtk_render_check); ++MAKE_FUNCPTR(gtk_render_frame); ++MAKE_FUNCPTR(gtk_render_handle); ++MAKE_FUNCPTR(gtk_render_line); ++MAKE_FUNCPTR(gtk_render_option); ++MAKE_FUNCPTR(gtk_render_slider); ++MAKE_FUNCPTR(gtk_scale_new); ++MAKE_FUNCPTR(gtk_scrolled_window_new); ++MAKE_FUNCPTR(gtk_separator_tool_item_new); ++MAKE_FUNCPTR(gtk_style_context_add_class); ++MAKE_FUNCPTR(gtk_style_context_add_region); ++MAKE_FUNCPTR(gtk_style_context_get_background_color); ++MAKE_FUNCPTR(gtk_style_context_get_border_color); ++MAKE_FUNCPTR(gtk_style_context_get_color); ++MAKE_FUNCPTR(gtk_style_context_remove_class); ++MAKE_FUNCPTR(gtk_style_context_restore); ++MAKE_FUNCPTR(gtk_style_context_save); ++MAKE_FUNCPTR(gtk_style_context_set_junction_sides); ++MAKE_FUNCPTR(gtk_style_context_set_state); ++MAKE_FUNCPTR(gtk_toggle_button_get_type); ++MAKE_FUNCPTR(gtk_toolbar_new); ++MAKE_FUNCPTR(gtk_tree_view_append_column); ++MAKE_FUNCPTR(gtk_tree_view_column_get_button); ++MAKE_FUNCPTR(gtk_tree_view_column_new); ++MAKE_FUNCPTR(gtk_tree_view_get_column); ++MAKE_FUNCPTR(gtk_tree_view_new); ++MAKE_FUNCPTR(gtk_widget_destroy); ++MAKE_FUNCPTR(gtk_widget_get_style_context); ++MAKE_FUNCPTR(gtk_widget_style_get); ++MAKE_FUNCPTR(gtk_window_new); ++#undef MAKE_FUNCPTR ++ ++#endif /* UXTHEMEGTK_H */ +diff --git a/dlls/uxtheme-gtk/version.rc b/dlls/uxtheme-gtk/version.rc +new file mode 100644 +index 0000000..38db521 +--- /dev/null ++++ b/dlls/uxtheme-gtk/version.rc +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2015 Michael Müller ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#define WINE_FILENAME_STR "uxtheme.dll" ++ ++#include +-- +2.5.0 + diff --git a/patches/uxtheme-GTK_Theming/0002-uxthemegtk-Initial-implementation.patch b/patches/uxtheme-GTK_Theming/0002-uxthemegtk-Initial-implementation.patch new file mode 100644 index 00000000..226b1b5f --- /dev/null +++ b/patches/uxtheme-GTK_Theming/0002-uxthemegtk-Initial-implementation.patch @@ -0,0 +1,3568 @@ +From 33b66bb01ef63fe6a2c140d19961f1e213ac2af1 Mon Sep 17 00:00:00 2001 +From: Ivan Akulinchev +Date: Sun, 9 Aug 2015 03:15:30 +0200 +Subject: uxthemegtk: Initial implementation. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Additional changes by Michael Müller : + * Various style cleanup. + * Replace malloc/free with HeapAlloc/HeapFree. + +Additional changes by Sebastian Lackner : + * Various style cleanup. + * Avoid casts, use impl_from_uxgtk_theme wrappers. + * Avoid declarations by moving vtables to the end of the file. + * Avoid unnecessary uninit() function. + * Merge init(), apply_style() and fix_sys_params() into a single function. + * Fix incorrect class enumaration in OpenThemeData(). + * Avoid unnecessary goto in DrawThemeBackgroundEx(). +--- + dlls/uxtheme-gtk/Makefile.in | 17 +- + dlls/uxtheme-gtk/button.c | 510 +++++++++++++++++++++++ + dlls/uxtheme-gtk/combobox.c | 236 +++++++++++ + dlls/uxtheme-gtk/edit.c | 205 +++++++++ + dlls/uxtheme-gtk/header.c | 122 ++++++ + dlls/uxtheme-gtk/listbox.c | 113 +++++ + dlls/uxtheme-gtk/listview.c | 32 ++ + dlls/uxtheme-gtk/menu.c | 183 ++++++++ + dlls/uxtheme-gtk/rebar.c | 96 +++++ + dlls/uxtheme-gtk/status.c | 151 +++++++ + dlls/uxtheme-gtk/tab.c | 201 +++++++++ + dlls/uxtheme-gtk/toolbar.c | 165 ++++++++ + dlls/uxtheme-gtk/trackbar.c | 182 ++++++++ + dlls/uxtheme-gtk/uxtheme-gtk.spec | 56 ++- + dlls/uxtheme-gtk/uxtheme.c | 853 +++++++++++++++++++++++++++++++++++++- + dlls/uxtheme-gtk/uxthemegtk.h | 53 +++ + dlls/uxtheme-gtk/window.c | 166 ++++++++ + 17 files changed, 3336 insertions(+), 5 deletions(-) + create mode 100644 dlls/uxtheme-gtk/button.c + create mode 100644 dlls/uxtheme-gtk/combobox.c + create mode 100644 dlls/uxtheme-gtk/edit.c + create mode 100644 dlls/uxtheme-gtk/header.c + create mode 100644 dlls/uxtheme-gtk/listbox.c + create mode 100644 dlls/uxtheme-gtk/listview.c + create mode 100644 dlls/uxtheme-gtk/menu.c + create mode 100644 dlls/uxtheme-gtk/rebar.c + create mode 100644 dlls/uxtheme-gtk/status.c + create mode 100644 dlls/uxtheme-gtk/tab.c + create mode 100644 dlls/uxtheme-gtk/toolbar.c + create mode 100644 dlls/uxtheme-gtk/trackbar.c + create mode 100644 dlls/uxtheme-gtk/window.c + +diff --git a/dlls/uxtheme-gtk/Makefile.in b/dlls/uxtheme-gtk/Makefile.in +index 07cf3a0f..8cefd51 100644 +--- a/dlls/uxtheme-gtk/Makefile.in ++++ b/dlls/uxtheme-gtk/Makefile.in +@@ -1,7 +1,22 @@ + MODULE = uxtheme-gtk.dll ++IMPORTS = user32 gdi32 advapi32 ++DELAYIMPORTS = msimg32 + EXTRAINCL = $(GTK3_CFLAGS) + + C_SRCS = \ +- uxtheme.c ++ button.c \ ++ combobox.c \ ++ edit.c \ ++ header.c \ ++ listbox.c \ ++ listview.c \ ++ menu.c \ ++ rebar.c \ ++ status.c \ ++ tab.c \ ++ toolbar.c \ ++ trackbar.c \ ++ uxtheme.c \ ++ window.c + + RC_SRCS = version.rc +diff --git a/dlls/uxtheme-gtk/button.c b/dlls/uxtheme-gtk/button.c +new file mode 100644 +index 0000000..b4b2d02 +--- /dev/null ++++ b/dlls/uxtheme-gtk/button.c +@@ -0,0 +1,510 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "vssym32.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _button_theme ++{ ++ uxgtk_theme_t base; ++ ++ int indicator_size; ++ ++ GtkWidget *button; ++ GtkWidget *check; ++ GtkWidget *radio; ++ GtkWidget *frame; ++ GtkWidget *label; ++ GtkWidget *button_label; ++ GtkWidget *check_label; ++ GtkWidget *radio_label; ++} button_theme_t; ++ ++static inline button_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, button_theme_t, base); ++} ++ ++static GtkWidget *get_button(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->button == NULL) ++ { ++ theme->button = pgtk_button_new(); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->button); ++ } ++ ++ return theme->button; ++} ++ ++static GtkWidget *get_radio(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->radio == NULL) ++ { ++ theme->radio = pgtk_radio_button_new(NULL); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->radio); ++ } ++ ++ return theme->radio; ++} ++ ++static GtkWidget *get_frame(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->frame == NULL) ++ { ++ theme->frame = pgtk_frame_new(NULL); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->frame); ++ } ++ ++ return theme->frame; ++} ++ ++static GtkWidget *get_label(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->label == NULL) ++ { ++ theme->label = pgtk_label_new(NULL); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->label); ++ } ++ ++ return theme->label; ++} ++ ++static GtkWidget *get_button_label(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->button_label == NULL) ++ { ++ GtkWidget *button = get_button(theme); ++ theme->button_label = pgtk_label_new(NULL); ++ pgtk_container_add((GtkContainer *)button, theme->button_label); ++ } ++ ++ return theme->button_label; ++} ++ ++static GtkWidget *get_check_label(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->check_label == NULL) ++ { ++ theme->check_label = pgtk_label_new(NULL); ++ pgtk_container_add((GtkContainer *)theme->check, theme->check_label); ++ } ++ ++ return theme->check_label; ++} ++ ++static GtkWidget *get_radio_label(button_theme_t *theme) ++{ ++ assert(theme != NULL); ++ ++ if (theme->radio_label == NULL) ++ { ++ GtkWidget *radio = get_radio(theme); ++ theme->radio_label = pgtk_label_new(NULL); ++ pgtk_container_add((GtkContainer *)radio, theme->radio_label); ++ } ++ ++ return theme->radio_label; ++} ++ ++static GtkStateFlags get_push_button_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case PBS_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case PBS_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case PBS_PRESSED: ++ return GTK_STATE_FLAG_ACTIVE; ++ ++ case PBS_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ ++ case PBS_DEFAULTED: ++ return GTK_STATE_FLAG_FOCUSED; ++ } ++ ++ FIXME("Unsupported push button state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static GtkStateFlags get_radio_button_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case RBS_UNCHECKEDNORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case RBS_UNCHECKEDHOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case RBS_UNCHECKEDPRESSED: ++ return GTK_STATE_FLAG_ACTIVE; ++ ++ case RBS_UNCHECKEDDISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ ++ case RBS_CHECKEDNORMAL: ++ return GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_ACTIVE; ++ ++ case RBS_CHECKEDHOT: ++ return GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE; ++ ++ case RBS_CHECKEDPRESSED: ++ return GTK_STATE_FLAG_ACTIVE; ++ ++ case RBS_CHECKEDDISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_ACTIVE; ++ } ++ ++ ERR("Unknown radio button state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static GtkStateFlags get_checkbox_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case CBS_UNCHECKEDNORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case CBS_UNCHECKEDHOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case CBS_UNCHECKEDPRESSED: ++ return GTK_STATE_FLAG_SELECTED; ++ ++ case CBS_UNCHECKEDDISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ ++ case CBS_CHECKEDNORMAL: ++ return GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_ACTIVE; ++ ++ case CBS_CHECKEDHOT: ++ return GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE; ++ ++ case CBS_CHECKEDPRESSED: ++ return GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_ACTIVE; ++ ++ case CBS_CHECKEDDISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_ACTIVE; ++ ++ case CBS_MIXEDNORMAL: ++ return GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_INCONSISTENT; ++ ++ case CBS_MIXEDHOT: ++ return GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_INCONSISTENT; ++ ++ case CBS_MIXEDPRESSED: ++ return GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_INCONSISTENT; ++ ++ case CBS_MIXEDDISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_INCONSISTENT; ++ } ++ ++ FIXME("Unsupported checkbox state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static GtkStateFlags get_groupbox_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case GBS_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case GBS_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ } ++ ++ ERR("Unknown groupbox state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static HRESULT get_border_color(button_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ switch (part_id) ++ { ++ case BP_PUSHBUTTON: ++ state = get_push_button_state_flags(state_id); ++ break; ++ ++ case BP_RADIOBUTTON: ++ state = get_radio_button_state_flags(state_id); ++ break; ++ ++ case BP_CHECKBOX: ++ state = get_checkbox_state_flags(state_id); ++ break; ++ ++ case BP_GROUPBOX: ++ state = get_groupbox_state_flags(state_id); ++ break; ++ ++ default: ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ context = pgtk_widget_get_style_context(get_frame(theme)); ++ ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME); ++ pgtk_style_context_get_border_color(context, state, rgba); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT get_text_color(button_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkWidget *widget; ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ switch (part_id) ++ { ++ case BP_PUSHBUTTON: ++ widget = get_button_label(theme); ++ state = get_push_button_state_flags(state_id); ++ break; ++ ++ case BP_RADIOBUTTON: ++ widget = get_radio_label(theme); ++ state = get_radio_button_state_flags(state_id); ++ break; ++ ++ case BP_CHECKBOX: ++ widget = get_check_label(theme); ++ state = get_checkbox_state_flags(state_id); ++ break; ++ ++ case BP_GROUPBOX: ++ widget = get_label(theme); ++ state = get_groupbox_state_flags(state_id); ++ break; ++ ++ default: ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ context = pgtk_widget_get_style_context(widget); ++ pgtk_style_context_get_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_color(uxgtk_theme_t *theme, int part_id, int state_id, ++ int prop_id, GdkRGBA *rgba) ++{ ++ button_theme_t *button_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (prop_id) ++ { ++ case TMT_BORDERCOLOR: ++ return get_border_color(button_theme, part_id, state_id, rgba); ++ ++ case TMT_TEXTCOLOR: ++ return get_text_color(button_theme, part_id, state_id, rgba); ++ } ++ ++ FIXME("Unsupported button color %d.\n", prop_id); ++ return E_NOTIMPL; ++} ++ ++static HRESULT draw_button(button_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStateFlags state = get_push_button_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(get_button(theme)); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ if (state_id == PBS_DEFAULTED) ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_DEFAULT); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_radio(button_theme_t *theme, cairo_t *cr, int state_id) ++{ ++ GtkStateFlags state = get_radio_button_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(get_radio(theme)); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_RADIO); ++ ++ pgtk_render_option(context, cr, 0, 0, theme->indicator_size, theme->indicator_size); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_checkbox(button_theme_t *theme, cairo_t *cr, int state_id) ++{ ++ GtkStateFlags state = get_checkbox_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->check); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_CHECK); ++ ++ pgtk_render_check(context, cr, 0, 0, theme->indicator_size, theme->indicator_size); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ button_theme_t *button_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case BP_PUSHBUTTON: ++ return draw_button(button_theme, cr, state_id, width, height); ++ ++ case BP_RADIOBUTTON: ++ return draw_radio(button_theme, cr, state_id); ++ ++ case BP_CHECKBOX: ++ return draw_checkbox(button_theme, cr, state_id); ++ ++ case BP_GROUPBOX: ++ /* GNOME applications don't draw a group box. Return some error code ++ * to avoid useless painting operations. */ ++ return E_ABORT; ++ } ++ ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static HRESULT get_part_size(uxgtk_theme_t *theme, int part_id, int state_id, ++ RECT *rect, SIZE *size) ++{ ++ button_theme_t *button_theme = impl_from_uxgtk_theme_t(theme); ++ ++ assert(theme != NULL); ++ assert(size != NULL); ++ ++ switch (part_id) ++ { ++ case BP_CHECKBOX: ++ case BP_RADIOBUTTON: ++ size->cx = button_theme->indicator_size; ++ size->cy = button_theme->indicator_size; ++ return S_OK; ++ } ++ ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ if (part_id == BP_CHECKBOX) ++ return (state_id < CBS_IMPLICITNORMAL); ++ ++ return (part_id > 0 && part_id < BP_COMMANDLINK); ++} ++ ++static const uxgtk_theme_vtable_t button_vtable = ++{ ++ get_color, ++ draw_background, ++ get_part_size, ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_button_theme_create(void) ++{ ++ button_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &button_vtable); ++ ++ /* Other widgets will be created on demand */ ++ theme->check = pgtk_check_button_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->check); ++ ++ /* Used for both check- and radiobuttons */ ++ pgtk_widget_style_get(theme->check, "indicator-size", &theme->indicator_size, NULL); ++ ++ TRACE("-GtkCheckButton-indicator-size: %d\n", theme->indicator_size); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/combobox.c b/dlls/uxtheme-gtk/combobox.c +new file mode 100644 +index 0000000..38abb82 +--- /dev/null ++++ b/dlls/uxtheme-gtk/combobox.c +@@ -0,0 +1,236 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _combobox_theme ++{ ++ uxgtk_theme_t base; ++ ++ int arrow_size; ++ float arrow_scaling; ++ ++ GtkWidget *combobox; ++ GtkWidget *button; ++ GtkWidget *entry; ++ GtkWidget *arrow; ++} combobox_theme_t; ++ ++static inline combobox_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, combobox_theme_t, base); ++} ++ ++static GtkStateFlags get_border_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case CBB_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case CBB_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case CBB_FOCUSED: ++ return GTK_STATE_FLAG_FOCUSED; ++ ++ case CBB_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ } ++ ++ ERR("Unknown combobox border state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static GtkStateFlags get_dropdown_button_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case CBXS_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case CBXS_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case CBXS_PRESSED: ++ return GTK_STATE_FLAG_ACTIVE; ++ ++ case CBXS_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ } ++ ++ ERR("Unknown combobox dropdown button state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static void iter_callback(GtkWidget *widget, gpointer data) ++{ ++ assert(data != NULL); ++ ++ if (pg_type_check_instance_is_a((GTypeInstance *)widget, pgtk_toggle_button_get_type())) ++ ((combobox_theme_t *)data)->button = widget; ++} ++ ++static HRESULT draw_border(combobox_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStateFlags state = get_border_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->entry); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_button(combobox_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ GtkStateFlags state = get_dropdown_button_state_flags(state_id); ++ GtkStyleContext *context; ++ int arrow_x, arrow_y, arrow_width; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->button); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ /* Render with another size to remove a gap */ ++ if (part_id == CP_DROPDOWNBUTTONLEFT) ++ { ++ pgtk_render_background(context, cr, -2, -2, width + 2, height + 4); ++ pgtk_render_frame(context, cr, -2, -2, width + 2, height + 4); ++ } ++ else ++ { ++ pgtk_render_background(context, cr, 0, -2, width + 2, height + 4); ++ pgtk_render_frame(context, cr, 0, -2, width + 2, height + 4); ++ } ++ ++ pgtk_style_context_restore(context); ++ ++ context = pgtk_widget_get_style_context(theme->arrow); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ arrow_width = theme->arrow_size * theme->arrow_scaling; ++ arrow_x = (width - arrow_width + 3) / 2; ++ arrow_y = (height - arrow_width) / 2; ++ ++ pgtk_render_arrow(context, cr, G_PI, arrow_x, arrow_y, arrow_width); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ combobox_theme_t *combobox_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case 0: ++ case CP_BORDER: ++ return draw_border(combobox_theme, cr, state_id, width, height); ++ ++ case CP_DROPDOWNBUTTON: ++ case CP_DROPDOWNBUTTONLEFT: ++ case CP_DROPDOWNBUTTONRIGHT: ++ return draw_button(combobox_theme, cr, part_id, state_id, width, height); ++ } ++ ++ FIXME("Unsupported combobox part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == 0 || part_id == CP_BORDER || part_id == CP_DROPDOWNBUTTON || ++ part_id == CP_DROPDOWNBUTTONLEFT || part_id == CP_DROPDOWNBUTTONRIGHT); ++} ++ ++static const uxgtk_theme_vtable_t combobox_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_combobox_theme_create(void) ++{ ++ combobox_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &combobox_vtable); ++ ++ /* I use a simple entry because .combobox-entry has no right border sometimes */ ++ theme->entry = pgtk_entry_new(); ++ theme->combobox = pgtk_combo_box_new_with_entry(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->entry); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->combobox); ++ ++ /* Extract button */ ++ pgtk_container_forall((GtkContainer *)theme->combobox, iter_callback, theme); ++ ++ theme->arrow = pgtk_bin_get_child((GtkBin *)theme->button); ++ ++ pgtk_widget_style_get(theme->combobox, ++ "arrow-size", &theme->arrow_size, ++ "arrow-scaling", &theme->arrow_scaling, ++ NULL); ++ ++ /* A workaround for old themes like Ambiance */ ++ if (theme->arrow_scaling == 1) ++ theme->arrow_scaling = 0.6; ++ ++ TRACE("-GtkComboBox-arrow-scaling: %f\n", theme->arrow_scaling); ++ TRACE("-GtkComboBox-arrow-size: %d\n", theme->arrow_size); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/edit.c b/dlls/uxtheme-gtk/edit.c +new file mode 100644 +index 0000000..eb5f108 +--- /dev/null ++++ b/dlls/uxtheme-gtk/edit.c +@@ -0,0 +1,205 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "vssym32.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _edit_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *entry; ++} edit_theme_t; ++ ++static inline edit_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, edit_theme_t, base); ++} ++ ++static GtkStateFlags get_text_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case ETS_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case ETS_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case ETS_SELECTED: ++ return GTK_STATE_FLAG_SELECTED; ++ ++ case ETS_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ ++ case ETS_FOCUSED: ++ return GTK_STATE_FLAG_FOCUSED; ++ ++ case ETS_READONLY: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ } ++ ++ FIXME("Unknown edit text state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static HRESULT get_fill_color(edit_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case EP_EDITTEXT: ++ state = get_text_state_flags(state_id); ++ context = pgtk_widget_get_style_context(theme->entry); ++ break; ++ ++ default: ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW); ++ pgtk_style_context_get_background_color(context, state, rgba); ++ pgtk_style_context_remove_class(context, GTK_STYLE_CLASS_VIEW); ++ ++ return S_OK; ++} ++ ++static HRESULT get_text_color(edit_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case EP_EDITTEXT: ++ state = get_text_state_flags(state_id); ++ context = pgtk_widget_get_style_context(theme->entry); ++ break; ++ ++ default: ++ FIXME("Unsupported button part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_get_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_color(uxgtk_theme_t *theme, int part_id, int state_id, ++ int prop_id, GdkRGBA *rgba) ++{ ++ edit_theme_t *edit_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (prop_id) ++ { ++ case TMT_FILLCOLOR: ++ return get_fill_color(edit_theme, part_id, state_id, rgba); ++ ++ case TMT_TEXTCOLOR: ++ return get_text_color(edit_theme, part_id, state_id, rgba); ++ } ++ ++ FIXME("Unsupported edit color %d.\n", prop_id); ++ return E_NOTIMPL; ++} ++ ++static HRESULT draw_text(edit_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStateFlags state = get_text_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->entry); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ edit_theme_t *edit_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case EP_EDITTEXT: ++ return draw_text(edit_theme, cr, state_id, width, height); ++ } ++ ++ FIXME("Unsupported edit part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == EP_EDITTEXT && state_id < ETS_ASSIST); ++} ++ ++static const uxgtk_theme_vtable_t edit_vtable = ++{ ++ get_color, ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_edit_theme_create(void) ++{ ++ edit_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &edit_vtable); ++ ++ theme->entry = pgtk_entry_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->entry); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/header.c b/dlls/uxtheme-gtk/header.c +new file mode 100644 +index 0000000..11c0245 +--- /dev/null ++++ b/dlls/uxtheme-gtk/header.c +@@ -0,0 +1,122 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _header_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *treeview; ++} header_theme_t; ++ ++static inline header_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, header_theme_t, base); ++} ++ ++static HRESULT draw_item(header_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStyleContext *context; ++ GtkStateFlags state; ++ GtkWidget *widget; ++ ++ assert(theme != NULL); ++ ++ widget = pgtk_tree_view_column_get_button( ++ pgtk_tree_view_get_column((GtkTreeView *)theme->treeview, 1)); ++ context = pgtk_widget_get_style_context(widget); ++ pgtk_style_context_save(context); ++ ++ if (state_id == HIS_HOT) ++ state = GTK_STATE_FLAG_PRELIGHT; ++ else if (state_id == HIS_PRESSED) ++ state = GTK_STATE_FLAG_ACTIVE; ++ else ++ state = GTK_STATE_FLAG_NORMAL; ++ ++ pgtk_style_context_set_state(context, state); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ header_theme_t *header_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case HP_HEADERITEM: ++ return draw_item(header_theme, cr, state_id, width, height); ++ } ++ ++ FIXME("Unsupported header part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == HP_HEADERITEM); ++} ++ ++static const uxgtk_theme_vtable_t header_vtable = { ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_header_theme_create(void) ++{ ++ header_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &header_vtable); ++ ++ theme->treeview = pgtk_tree_view_new(); ++ ++ pgtk_tree_view_append_column((GtkTreeView *)theme->treeview, pgtk_tree_view_column_new()); ++ pgtk_tree_view_append_column((GtkTreeView *)theme->treeview, pgtk_tree_view_column_new()); ++ pgtk_tree_view_append_column((GtkTreeView *)theme->treeview, pgtk_tree_view_column_new()); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->treeview); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/listbox.c b/dlls/uxtheme-gtk/listbox.c +new file mode 100644 +index 0000000..53e1391 +--- /dev/null ++++ b/dlls/uxtheme-gtk/listbox.c +@@ -0,0 +1,113 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _listbox_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *scrolled_window; ++} listbox_theme_t; ++ ++static inline listbox_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, listbox_theme_t, base); ++} ++ ++static HRESULT draw_border(listbox_theme_t *theme, cairo_t *cr, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->scrolled_window); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ listbox_theme_t *listbox_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case 0: ++ case LBCP_BORDER_HSCROLL: ++ case LBCP_BORDER_HVSCROLL: ++ case LBCP_BORDER_NOSCROLL: ++ case LBCP_BORDER_VSCROLL: ++ return draw_border(listbox_theme, cr, width, height); ++ } ++ ++ FIXME("Unsupported listbox part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id >= 0 && part_id < LBCP_ITEM); ++} ++ ++static const uxgtk_theme_vtable_t listbox_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_listbox_theme_create(void) ++{ ++ listbox_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &listbox_vtable); ++ ++ theme->scrolled_window = pgtk_scrolled_window_new(NULL, NULL); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->scrolled_window); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/listview.c b/dlls/uxtheme-gtk/listview.c +new file mode 100644 +index 0000000..673bc4b +--- /dev/null ++++ b/dlls/uxtheme-gtk/listview.c +@@ -0,0 +1,32 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++uxgtk_theme_t *uxgtk_listview_theme_create(void) ++{ ++ TRACE("()\n"); ++ ++ return uxgtk_listbox_theme_create(); ++} +diff --git a/dlls/uxtheme-gtk/menu.c b/dlls/uxtheme-gtk/menu.c +new file mode 100644 +index 0000000..b24a085 +--- /dev/null ++++ b/dlls/uxtheme-gtk/menu.c +@@ -0,0 +1,183 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "vssym32.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _menu_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *menubar; ++ GtkWidget *menuitem; ++ GtkWidget *menu; ++} menu_theme_t; ++ ++static inline menu_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, menu_theme_t, base); ++} ++ ++static GtkStateFlags get_popup_item_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case MPI_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case MPI_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case MPI_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ ++ case MPI_DISABLEDHOT: ++ return GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_PRELIGHT; ++ } ++ ++ ERR("Unknown menu popup item state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static HRESULT get_fill_color(menu_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case MENU_BARBACKGROUND: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->menubar); ++ break; ++ ++ case MENU_POPUPBACKGROUND: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->menu); ++ break; ++ ++ case MENU_POPUPITEM: ++ state = get_popup_item_state_flags(state_id); ++ context = pgtk_widget_get_style_context(theme->menuitem); ++ break; ++ ++ default: ++ FIXME("Unsupported menu part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_get_background_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_text_color(menu_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStateFlags state; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case MENU_BARBACKGROUND: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->menubar); ++ break; ++ ++ case MENU_POPUPBACKGROUND: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->menu); ++ break; ++ ++ case MENU_POPUPITEM: ++ state = get_popup_item_state_flags(state_id); ++ context = pgtk_widget_get_style_context(theme->menuitem); ++ break; ++ ++ default: ++ FIXME("Unsupported menu part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_get_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_color(uxgtk_theme_t *theme, int part_id, int state_id, ++ int prop_id, GdkRGBA *rgba) ++{ ++ menu_theme_t *menu_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (prop_id) ++ { ++ case TMT_FILLCOLOR: ++ return get_fill_color(menu_theme, part_id, state_id, rgba); ++ ++ case TMT_TEXTCOLOR: ++ return get_text_color(menu_theme, part_id, state_id, rgba); ++ } ++ ++ FIXME("Unsupported menu color %d.\n", prop_id); ++ return E_NOTIMPL; ++} ++ ++static const uxgtk_theme_vtable_t menu_vtable = ++{ ++ get_color, ++ NULL, /* draw_background */ ++ NULL, /* get_part_size */ ++ NULL /* is_part_defined */ ++}; ++ ++uxgtk_theme_t *uxgtk_menu_theme_create(void) ++{ ++ menu_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &menu_vtable); ++ ++ theme->menubar = pgtk_menu_bar_new(); ++ theme->menuitem = pgtk_menu_item_new(); ++ theme->menu = pgtk_menu_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->menubar); ++ pgtk_menu_shell_append((GtkMenuShell *)theme->menubar, theme->menuitem); ++ pgtk_menu_item_set_submenu((GtkMenuItem *)theme->menuitem, theme->menu); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/rebar.c b/dlls/uxtheme-gtk/rebar.c +new file mode 100644 +index 0000000..03650ae +--- /dev/null ++++ b/dlls/uxtheme-gtk/rebar.c +@@ -0,0 +1,96 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _rebar_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *toolbar; ++} rebar_theme_t; ++ ++static inline rebar_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, rebar_theme_t, base); ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ rebar_theme_t *rebar_theme = impl_from_uxgtk_theme_t(theme); ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case 0: ++ case RP_BACKGROUND: ++ { ++ GtkStyleContext *context = pgtk_widget_get_style_context(rebar_theme->toolbar); ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ return S_OK; ++ } ++ } ++ ++ FIXME("Unsupported rebar part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == 0 || part_id == RP_BACKGROUND); ++} ++ ++static const uxgtk_theme_vtable_t rebar_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_rebar_theme_create(void) ++{ ++ rebar_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &rebar_vtable); ++ ++ theme->toolbar = pgtk_toolbar_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->toolbar); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/status.c b/dlls/uxtheme-gtk/status.c +new file mode 100644 +index 0000000..e2a937a +--- /dev/null ++++ b/dlls/uxtheme-gtk/status.c +@@ -0,0 +1,151 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _status_theme ++{ ++ uxgtk_theme_t base; ++ ++ int grip_width; ++ int grip_height; ++} status_theme_t; ++ ++static inline status_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, status_theme_t, base); ++} ++ ++static HRESULT draw_pane(uxgtk_theme_t *theme, cairo_t *cr, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->window); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_BACKGROUND); ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_gripper(uxgtk_theme_t *theme, cairo_t *cr, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->window); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_GRIP); ++ pgtk_style_context_set_junction_sides(context, GTK_JUNCTION_CORNER_BOTTOMRIGHT); ++ pgtk_render_handle(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ TRACE("(%p, %p, %d, %d, %d, %d)\n", theme, cr, part_id, state_id, width, height); ++ ++ switch (part_id) ++ { ++ case 0: ++ case SP_PANE: ++ case SP_GRIPPERPANE: ++ return draw_pane(theme, cr, width, height); ++ ++ case SP_GRIPPER: ++ return draw_gripper(theme, cr, width, height); ++ } ++ ++ ERR("Unknown status part %d.\n", part_id); ++ return E_FAIL; ++} ++ ++static HRESULT get_part_size(uxgtk_theme_t *theme, int part_id, int state_id, ++ RECT *rect, SIZE *size) ++{ ++ status_theme_t *status_theme = impl_from_uxgtk_theme_t(theme); ++ ++ assert(theme != NULL); ++ assert(size != NULL); ++ ++ switch (part_id) ++ { ++ case SP_GRIPPER: ++ size->cx = status_theme->grip_width; ++ size->cy = status_theme->grip_height; ++ return S_OK; ++ } ++ ++ FIXME("Unsupported status part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id >= 0 && part_id <= SP_GRIPPER); ++} ++ ++static const uxgtk_theme_vtable_t status_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ get_part_size, ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_status_theme_create(void) ++{ ++ status_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &status_vtable); ++ ++ pgtk_widget_style_get(theme->base.window, ++ "resize-grip-width", &theme->grip_width, ++ "resize-grip-height", &theme->grip_height, ++ NULL); ++ ++ TRACE("-GtkWindow-resize-grip-width: %d\n", theme->grip_width); ++ TRACE("-GtkWindow-resize-grip-height: %d\n", theme->grip_height); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/tab.c b/dlls/uxtheme-gtk/tab.c +new file mode 100644 +index 0000000..31bdc0e +--- /dev/null ++++ b/dlls/uxtheme-gtk/tab.c +@@ -0,0 +1,201 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _tab_theme ++{ ++ uxgtk_theme_t base; ++ ++ int tab_overlap; ++ ++ GtkWidget *notebook; ++} tab_theme_t; ++ ++static inline tab_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, tab_theme_t, base); ++} ++ ++static HRESULT draw_tab_item(tab_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ int x = 0, new_width = width, new_height = height; ++ GtkRegionFlags region = 0; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->notebook); ++ pgtk_style_context_save(context); ++ ++ /* Emulate the "-GtkNotebook-tab-overlap" style property */ ++ if (part_id == TABP_TABITEM || part_id == TABP_TABITEMRIGHTEDGE) ++ { ++ x = -theme->tab_overlap; ++ new_width += theme->tab_overlap; ++ } ++ ++ /* Provide GTK a little bit more information about the tab position */ ++ if (part_id == TABP_TABITEMLEFTEDGE || part_id == TABP_TOPTABITEMLEFTEDGE) ++ region = GTK_REGION_FIRST; ++ else if (part_id == TABP_TABITEMRIGHTEDGE || part_id == TABP_TOPTABITEMRIGHTEDGE) ++ region = GTK_REGION_LAST; ++ else if (part_id == TABP_TABITEMBOTHEDGE || part_id == TABP_TOPTABITEMBOTHEDGE) ++ region = GTK_REGION_ONLY; ++ pgtk_style_context_add_region(context, GTK_STYLE_REGION_TAB, region); ++ ++ /* Some themes are not friendly with the TCS_MULTILINE tabs */ ++ pgtk_style_context_set_junction_sides(context, GTK_JUNCTION_BOTTOM); ++ ++ /* Active tabs have their own parts */ ++ if (part_id > TABP_TABITEMBOTHEDGE && part_id < TABP_PANE) { ++ new_height--; /* Fix the active tab height */ ++ pgtk_style_context_set_state(context, GTK_STATE_FLAG_ACTIVE); ++ } ++ ++ pgtk_render_background(context, cr, x, 0, new_width, new_height); ++ pgtk_render_frame(context, cr, x, 0, new_width, new_height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_tab_pane(tab_theme_t *theme, cairo_t *cr, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->notebook); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_FRAME); ++ pgtk_style_context_set_junction_sides(context, GTK_JUNCTION_TOP); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_tab_body(tab_theme_t *theme, cairo_t *cr, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->notebook); ++ ++ /* Some borders are already drawned by draw_tab_pane */ ++ pgtk_render_background(context, cr, -4, -4, width + 4, height + 4); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ tab_theme_t *tab_theme = impl_from_uxgtk_theme_t(theme); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ /* Draw a dialog background to fix some themes like Ambiance */ ++ context = pgtk_widget_get_style_context(theme->window); ++ pgtk_render_background(context, cr, 0, 0, width, height - 1); ++ ++ switch (part_id) ++ { ++ case TABP_TABITEM: ++ case TABP_TABITEMLEFTEDGE: ++ case TABP_TABITEMRIGHTEDGE: ++ case TABP_TABITEMBOTHEDGE: ++ case TABP_TOPTABITEM: ++ case TABP_TOPTABITEMLEFTEDGE: ++ case TABP_TOPTABITEMRIGHTEDGE: ++ case TABP_TOPTABITEMBOTHEDGE: ++ return draw_tab_item(tab_theme, cr, part_id, state_id, width, height); ++ ++ case TABP_PANE: ++ return draw_tab_pane(tab_theme, cr, width, height); ++ ++ case TABP_BODY: ++ case TABP_AEROWIZARDBODY: ++ return draw_tab_body(tab_theme, cr, width, height); ++ } ++ ++ ERR("Unknown tab part %d.\n", part_id); ++ return E_FAIL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id > 0 && part_id <= TABP_AEROWIZARDBODY); ++} ++ ++static const uxgtk_theme_vtable_t tab_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_tab_theme_create(void) ++{ ++ tab_theme_t *theme; ++ GtkStyleContext *context; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &tab_vtable); ++ ++ theme->notebook = pgtk_notebook_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->notebook); ++ ++ context = pgtk_widget_get_style_context(theme->notebook); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_NOTEBOOK); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_TOP); ++ ++ pgtk_widget_style_get(theme->notebook, "tab-overlap", &theme->tab_overlap, NULL); ++ ++ TRACE("-GtkNotebook-tab-overlap: %d\n", theme->tab_overlap); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/toolbar.c b/dlls/uxtheme-gtk/toolbar.c +new file mode 100644 +index 0000000..be8fbae +--- /dev/null ++++ b/dlls/uxtheme-gtk/toolbar.c +@@ -0,0 +1,165 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _toolbar_theme ++{ ++ uxgtk_theme_t base; ++ ++ GtkWidget *button; ++ GtkWidget *separator; ++} toolbar_theme_t; ++ ++static inline toolbar_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, toolbar_theme_t, base); ++} ++ ++static GtkStateFlags get_state_flags(int state_id) ++{ ++ switch (state_id) ++ { ++ case TS_NORMAL: ++ return GTK_STATE_FLAG_NORMAL; ++ ++ case TS_HOT: ++ return GTK_STATE_FLAG_PRELIGHT; ++ ++ case TS_PRESSED: ++ return GTK_STATE_FLAG_ACTIVE; ++ ++ case TS_DISABLED: ++ return GTK_STATE_FLAG_INSENSITIVE; ++ } ++ ++ FIXME("Unsupported toolbar state %d.\n", state_id); ++ return GTK_STATE_FLAG_NORMAL; ++} ++ ++static HRESULT draw_button(toolbar_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStateFlags state = get_state_flags(state_id); ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->button); ++ pgtk_style_context_save(context); ++ ++ pgtk_style_context_set_state(context, state); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ pgtk_render_frame(context, cr, 0, 0, width, height); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_separator(toolbar_theme_t *theme, cairo_t *cr, int part_id, ++ int width, int height) ++{ ++ int x1, x2, y1, y2; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->separator); ++ ++ if (part_id == TP_SEPARATOR) /* TP_SEPARATORVERT ? */ ++ { ++ y1 = 0; ++ y2 = height; ++ x1 = x2 = width/2; ++ } ++ else ++ { ++ x1 = 0; ++ x2 = width; ++ y1 = y2 = height/2; ++ } ++ ++ pgtk_render_line(context, cr, x1, y1, x2, y2); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ toolbar_theme_t *toolbar_theme = impl_from_uxgtk_theme_t(theme); ++ ++ switch (part_id) ++ { ++ case TP_BUTTON: ++ return draw_button(toolbar_theme, cr, state_id, width, height); ++ ++ case TP_SEPARATOR: ++ case TP_SEPARATORVERT: ++ return draw_separator(toolbar_theme, cr, part_id, width, height); ++ } ++ ++ FIXME("Unsupported toolbar part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == TP_BUTTON || part_id == TP_SEPARATOR || part_id == TP_SEPARATORVERT); ++} ++ ++static const uxgtk_theme_vtable_t toolbar_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_toolbar_theme_create(void) ++{ ++ toolbar_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &toolbar_vtable); ++ ++ theme->button = pgtk_button_new(); ++ theme->separator = (GtkWidget *)pgtk_separator_tool_item_new(); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->button); ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->separator); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/trackbar.c b/dlls/uxtheme-gtk/trackbar.c +new file mode 100644 +index 0000000..58df246 +--- /dev/null ++++ b/dlls/uxtheme-gtk/trackbar.c +@@ -0,0 +1,182 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _trackbar_theme ++{ ++ uxgtk_theme_t base; ++ ++ int slider_length; ++ int slider_width; ++ ++ GtkWidget *scale; ++} trackbar_theme_t; ++ ++static inline trackbar_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, trackbar_theme_t, base); ++} ++ ++static HRESULT draw_track(trackbar_theme_t *theme, cairo_t *cr, int part_id, int width, int height) ++{ ++ int x1, x2, y1, y2; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->scale); ++ pgtk_style_context_save(context); ++ ++ if (part_id == TKP_TRACKVERT) ++ { ++ y1 = 0; ++ y2 = height; ++ x1 = x2 = width/2; ++ } ++ else ++ { ++ x1 = 0; ++ x2 = width; ++ y1 = y2 = height/2; ++ } ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_SEPARATOR); ++ ++ pgtk_render_line(context, cr, x1, y1, x2, y2); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_thumb(trackbar_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStateFlags state = GTK_STATE_FLAG_NORMAL; ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->scale); ++ pgtk_style_context_save(context); ++ ++ if (state_id == TUS_HOT) ++ state = GTK_STATE_FLAG_PRELIGHT; ++ else if (state_id == TUBS_PRESSED) ++ state = GTK_STATE_FLAG_ACTIVE; ++ ++ pgtk_style_context_set_state(context, state); ++ ++ if (width > height) ++ if (theme->slider_length > theme->slider_width) ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_HORIZONTAL); ++ else ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_VERTICAL); ++ else ++ if (theme->slider_length > theme->slider_width) ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_VERTICAL); ++ else ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_HORIZONTAL); ++ ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_SCALE); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_SLIDER); ++ ++ pgtk_render_slider(context, cr, 0, 0, theme->slider_length, theme->slider_width, ++ GTK_ORIENTATION_HORIZONTAL); ++ ++ pgtk_style_context_restore(context); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ trackbar_theme_t *trackbar_theme = impl_from_uxgtk_theme_t(theme); ++ ++ TRACE("(%p, %p, %d, %d, %d, %d)\n", theme, cr, part_id, state_id, width, height); ++ ++ switch (part_id) ++ { ++ case TKP_THUMB: ++ case TKP_THUMBBOTTOM: ++ case TKP_THUMBTOP: ++ case TKP_THUMBVERT: ++ case TKP_THUMBLEFT: ++ case TKP_THUMBRIGHT: ++ return draw_thumb(trackbar_theme, cr, state_id, width, height); ++ ++ case TKP_TRACK: ++ case TKP_TRACKVERT: ++ return draw_track(trackbar_theme, cr, part_id, width, height); ++ } ++ ++ FIXME("Unsupported trackbar part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id > 0 && part_id < TKP_TICS); ++} ++ ++static const uxgtk_theme_vtable_t trackbar_vtable = ++{ ++ NULL, /* get_color */ ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_trackbar_theme_create(void) ++{ ++ trackbar_theme_t *theme; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &trackbar_vtable); ++ ++ theme->scale = pgtk_scale_new(GTK_ORIENTATION_HORIZONTAL, NULL); ++ ++ pgtk_container_add((GtkContainer *)theme->base.layout, theme->scale); ++ ++ pgtk_widget_style_get(theme->scale, ++ "slider-length", &theme->slider_length, ++ "slider-width", &theme->slider_width, ++ NULL); ++ ++ TRACE("-GtkScale-slider-length: %d\n", theme->slider_length); ++ TRACE("-GtkScale-slider-width: %d\n", theme->slider_width); ++ ++ return &theme->base; ++} +diff --git a/dlls/uxtheme-gtk/uxtheme-gtk.spec b/dlls/uxtheme-gtk/uxtheme-gtk.spec +index b7db254..70cd7ff 100644 +--- a/dlls/uxtheme-gtk/uxtheme-gtk.spec ++++ b/dlls/uxtheme-gtk/uxtheme-gtk.spec +@@ -1 +1,55 @@ +-# Empty ++# System ++@ stdcall CloseThemeData(ptr) ++@ stdcall EnableThemeDialogTexture(ptr long) ++@ stdcall EnableTheming(long) ++@ stdcall GetCurrentThemeName(wstr long wstr long wstr long) ++@ stdcall GetThemeAppProperties() ++@ stdcall GetWindowTheme(ptr) ++@ stdcall IsAppThemed() ++@ stdcall IsThemeActive() ++@ stdcall IsThemeDialogTextureEnabled(ptr) ++@ stdcall OpenThemeData(ptr wstr) ++@ stdcall SetThemeAppProperties(long) ++@ stdcall SetWindowTheme(ptr wstr wstr) ++ ++# Properties ++@ stdcall GetThemeBool(ptr long long long ptr) ++@ stdcall GetThemeColor(ptr long long long ptr) ++@ stdcall GetThemeEnumValue(ptr long long long ptr) ++@ stdcall GetThemeFilename(ptr long long long wstr long) ++@ stdcall GetThemeFont(ptr ptr long long long ptr) ++@ stdcall GetThemeInt(ptr long long long ptr) ++@ stdcall GetThemeIntList(ptr long long long ptr) ++@ stdcall GetThemeMargins(ptr ptr long long long ptr ptr) ++@ stdcall GetThemeMetric(ptr ptr long long long ptr) ++@ stdcall GetThemePosition(ptr long long long ptr) ++@ stdcall GetThemePropertyOrigin(ptr long long long ptr) ++@ stdcall GetThemeRect(ptr long long long ptr) ++@ stdcall GetThemeString(ptr long long long wstr long) ++@ stdcall GetThemeTransitionDuration(ptr long long long long ptr) ++ ++# Metrics ++@ stdcall GetThemeSysBool(ptr long) ++@ stdcall GetThemeSysColor(ptr long) ++@ stdcall GetThemeSysColorBrush(ptr long) ++@ stdcall GetThemeSysFont(ptr long ptr) ++@ stdcall GetThemeSysInt(ptr long ptr) ++@ stdcall GetThemeSysSize(ptr long) ++@ stdcall GetThemeSysString(ptr long wstr long) ++ ++# Drawing ++@ stdcall DrawThemeBackground(ptr ptr long long ptr ptr) ++@ stdcall DrawThemeBackgroundEx(ptr ptr long long ptr ptr) ++@ stdcall DrawThemeEdge(ptr ptr long long ptr long long ptr) ++@ stdcall DrawThemeIcon(ptr ptr long long ptr ptr long) ++@ stdcall DrawThemeParentBackground(ptr ptr ptr) ++@ stdcall DrawThemeText(ptr ptr long long wstr long long long ptr) ++@ stdcall GetThemeBackgroundContentRect(ptr ptr long long ptr ptr) ++@ stdcall GetThemeBackgroundExtent(ptr ptr long long ptr ptr) ++@ stdcall GetThemeBackgroundRegion(ptr ptr long long ptr ptr) ++@ stdcall GetThemePartSize(ptr ptr long long ptr long ptr) ++@ stdcall GetThemeTextExtent(ptr ptr long long wstr long long ptr ptr) ++@ stdcall GetThemeTextMetrics(ptr ptr long long ptr) ++@ stdcall HitTestThemeBackground(ptr long long long long ptr long int64 ptr) ++@ stdcall IsThemeBackgroundPartiallyTransparent(ptr long long) ++@ stdcall IsThemePartDefined(ptr long long) +diff --git a/dlls/uxtheme-gtk/uxtheme.c b/dlls/uxtheme-gtk/uxtheme.c +index cd5e3c0..22285df 100644 +--- a/dlls/uxtheme-gtk/uxtheme.c ++++ b/dlls/uxtheme-gtk/uxtheme.c +@@ -1,6 +1,7 @@ + /* + * GTK uxtheme implementation + * ++ * Copyright (C) 2015 Ivan Akulinchev + * Copyright (C) 2015 Michael Müller + * + * This library is free software; you can redistribute it and/or +@@ -22,7 +23,19 @@ + #include "wine/port.h" + #include "wine/library.h" + ++#include ++ ++#include "windef.h" ++#include "winbase.h" ++#include "wingdi.h" ++#include "winuser.h" ++#include "winerror.h" ++#include "uxtheme.h" ++#include "vsstyle.h" ++#include "vssym32.h" ++ + #include "wine/debug.h" ++ + #include "uxthemegtk.h" + + WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); +@@ -31,6 +44,28 @@ static void *libgtk3 = NULL; + static void *libcairo = NULL; + static void *libgobject2 = NULL; + ++static const struct ++{ ++ const WCHAR *classname; ++ uxgtk_theme_t *(*create)(void); ++} ++classes[] = ++{ ++ { VSCLASS_BUTTON, uxgtk_button_theme_create }, ++ { VSCLASS_COMBOBOX, uxgtk_combobox_theme_create }, ++ { VSCLASS_EDIT, uxgtk_edit_theme_create }, ++ { VSCLASS_HEADER, uxgtk_header_theme_create }, ++ { VSCLASS_LISTBOX, uxgtk_listbox_theme_create }, ++ { VSCLASS_LISTVIEW, uxgtk_listview_theme_create }, ++ { VSCLASS_MENU, uxgtk_menu_theme_create }, ++ { VSCLASS_REBAR, uxgtk_rebar_theme_create }, ++ { VSCLASS_STATUS, uxgtk_status_theme_create }, ++ { VSCLASS_TAB, uxgtk_tab_theme_create }, ++ { VSCLASS_TOOLBAR, uxgtk_toolbar_theme_create }, ++ { VSCLASS_TRACKBAR, uxgtk_trackbar_theme_create }, ++ { VSCLASS_WINDOW, uxgtk_window_theme_create } ++}; ++ + #define MAKE_FUNCPTR(f) typeof(f) * p##f = NULL + MAKE_FUNCPTR(cairo_create); + MAKE_FUNCPTR(cairo_destroy); +@@ -92,6 +127,12 @@ MAKE_FUNCPTR(gtk_widget_style_get); + MAKE_FUNCPTR(gtk_window_new); + #undef MAKE_FUNCPTR + ++#define NUM_SYS_COLORS (COLOR_MENUBAR + 1) ++#define MENU_HEIGHT 20 ++#define CLASSLIST_MAXLEN 128 ++ ++static const WCHAR THEME_PROPERTY[] = {'u','x','g','t','k','_','t','h','e','m','e',0}; ++ + static void free_gtk3_libs(void) + { + if (libgtk3) wine_dlclose(libgtk3, NULL, 0); +@@ -197,6 +238,812 @@ error: + return FALSE; + } + ++static void process_attach(void) ++{ ++ int i, colors[NUM_SYS_COLORS]; ++ COLORREF refs[NUM_SYS_COLORS]; ++ NONCLIENTMETRICSW metrics; ++ ++ if (!load_gtk3_libs()) ++ return; ++ ++ pgtk_init(0, NULL); /* Otherwise every call to GTK will fail */ ++ ++ /* apply colors */ ++ for (i = 0; i < NUM_SYS_COLORS; i++) ++ { ++ colors[i] = i; ++ refs[i] = GetThemeSysColor(NULL, i); ++ } ++ SetSysColors(NUM_SYS_COLORS, colors, refs); ++ ++ /* fix sys params */ ++ memset(&metrics, 0, sizeof(metrics)); ++ metrics.cbSize = sizeof(metrics); ++ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0); ++ metrics.iMenuHeight = MENU_HEIGHT; ++ SystemParametersInfoW(SPI_SETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0); ++ ++ SystemParametersInfoW(SPI_SETCLEARTYPE, 0, (LPVOID)TRUE, 0); ++ SystemParametersInfoW(SPI_SETFONTSMOOTHING, 0, (LPVOID)TRUE, 0); ++ SystemParametersInfoW(SPI_SETFLATMENU, 0, (LPVOID)TRUE, 0); ++} ++ ++void uxgtk_theme_init(uxgtk_theme_t *theme, const uxgtk_theme_vtable_t *vtable) ++{ ++ theme->vtable = vtable; ++ theme->window = pgtk_window_new(GTK_WINDOW_TOPLEVEL); ++ theme->layout = pgtk_fixed_new(); ++ pgtk_container_add((GtkContainer *)theme->window, theme->layout); ++} ++ ++static void paint_cairo_surface(cairo_surface_t *surface, HDC target_hdc, ++ int x, int y, int width, int height) ++{ ++ unsigned char *bitmap_data, *surface_data; ++ int i, dib_stride, cairo_stride; ++ HDC bitmap_hdc; ++ HBITMAP bitmap; ++ BITMAPINFO info; ++ BLENDFUNCTION bf; ++ ++ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); ++ info.bmiHeader.biWidth = width; ++ info.bmiHeader.biHeight = -height; /* top-down, see MSDN */ ++ info.bmiHeader.biPlanes = 1; ++ info.bmiHeader.biBitCount = 32; ++ info.bmiHeader.biCompression = BI_RGB; /* no compression */ ++ info.bmiHeader.biSizeImage = 0; ++ info.bmiHeader.biXPelsPerMeter = 1; ++ info.bmiHeader.biYPelsPerMeter = 1; ++ info.bmiHeader.biClrUsed = 0; ++ info.bmiHeader.biClrImportant = 0; ++ ++ bf.BlendOp = AC_SRC_OVER; ++ bf.BlendFlags = 0; ++ bf.SourceConstantAlpha = 0xff; ++ bf.AlphaFormat = AC_SRC_ALPHA; ++ ++ bitmap_hdc = CreateCompatibleDC(target_hdc); ++ bitmap = CreateDIBSection(bitmap_hdc, &info, DIB_RGB_COLORS, ++ (void **)&bitmap_data, NULL, 0); ++ ++ pcairo_surface_flush(surface); ++ ++ surface_data = pcairo_image_surface_get_data(surface); ++ cairo_stride = pcairo_image_surface_get_stride(surface); ++ dib_stride = width * 4; ++ ++ for (i = 0; i < height; i++) ++ memcpy(bitmap_data + i * dib_stride, surface_data + i * cairo_stride, width * 4); ++ ++ SelectObject(bitmap_hdc, bitmap); ++ ++ GdiAlphaBlend(target_hdc, x, y, width, height, ++ bitmap_hdc, 0, 0, width, height, bf); ++ ++ DeleteObject(bitmap); ++ DeleteDC(bitmap_hdc); ++} ++ ++HRESULT WINAPI CloseThemeData(HTHEME htheme) ++{ ++ uxgtk_theme_t *theme = (uxgtk_theme_t *)htheme; ++ ++ TRACE("(%p)\n", htheme); ++ ++ if (libgtk3 == NULL) ++ return E_NOTIMPL; ++ ++ if (theme == NULL) ++ return E_HANDLE; ++ ++ /* Destroy the toplevel widget */ ++ pgtk_widget_destroy(theme->window); ++ HeapFree(GetProcessHeap(), 0, theme); ++ return S_OK; ++} ++ ++HRESULT WINAPI EnableThemeDialogTexture(HWND hwnd, DWORD flags) ++{ ++ HTHEME htheme; ++ ++ TRACE("(%p, %u)\n", hwnd, flags); ++ ++ if (libgtk3 == NULL) ++ return E_NOTIMPL; ++ ++ if (flags & ETDT_USETABTEXTURE) ++ { ++ htheme = GetWindowTheme(hwnd); ++ OpenThemeData(hwnd, VSCLASS_TAB); ++ CloseThemeData(htheme); ++ } ++ ++ return S_OK; /* Always enabled */ ++} ++ ++HRESULT WINAPI EnableTheming(BOOL enable) ++{ ++ TRACE("(%u)\n", enable); ++ ++ return S_OK; /* Always enabled */ ++} ++ ++HRESULT WINAPI GetCurrentThemeName(LPWSTR filename, int filename_maxlen, ++ LPWSTR color, int color_maxlen, ++ LPWSTR size, int size_maxlen) ++{ ++ TRACE("(%p, %d, %p, %d, %p, %d)\n", filename, filename_maxlen, ++ color, color_maxlen, size, size_maxlen); ++ ++ return E_FAIL; /* To prevent calling EnumThemeColors and so on */ ++} ++ ++DWORD WINAPI GetThemeAppProperties(void) ++{ ++ TRACE("()\n"); ++ ++ return STAP_ALLOW_CONTROLS; /* Non-client drawing is not supported */ ++} ++ ++HTHEME WINAPI GetWindowTheme(HWND hwnd) ++{ ++ TRACE("(%p)\n", hwnd); ++ ++ return GetPropW(hwnd, THEME_PROPERTY); ++} ++ ++BOOL WINAPI IsAppThemed(void) ++{ ++ TRACE("()\n"); ++ ++ return IsThemeActive(); ++} ++ ++BOOL WINAPI IsThemeActive(void) ++{ ++ TRACE("()\n"); ++ ++ if (libgtk3 == NULL) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++BOOL WINAPI IsThemeDialogTextureEnabled(HWND hwnd) ++{ ++ TRACE("(%p)\n", hwnd); ++ ++ return TRUE; /* Always enabled */ ++} ++ ++HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR classlist) ++{ ++ WCHAR *start, *tok, buf[CLASSLIST_MAXLEN]; ++ uxgtk_theme_t *theme; ++ int i; ++ ++ TRACE("(%p, %s)\n", hwnd, debugstr_w(classlist)); ++ ++ if (libgtk3 == NULL) ++ { ++ SetLastError(ERROR_NOT_SUPPORTED); ++ return NULL; ++ } ++ ++ /* comctl32.dll likes to send NULL */ ++ if (classlist == NULL) ++ { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return NULL; ++ } ++ ++ lstrcpynW(buf, classlist, CLASSLIST_MAXLEN - 1); ++ buf[CLASSLIST_MAXLEN - 1] = L'\0'; ++ ++ /* search for the first match */ ++ start = buf; ++ for (tok = buf; *tok; tok++) ++ { ++ if (*tok != ';') continue; ++ *tok = 0; ++ ++ for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) ++ if (lstrcmpiW(start, classes[i].classname) == 0) goto found; ++ ++ start = tok + 1; ++ } ++ if (start != tok) ++ { ++ for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) ++ if (lstrcmpiW(start, classes[i].classname) == 0) goto found; ++ } ++ ++ FIXME("No matching theme for %s.\n", debugstr_w(classlist)); ++ SetLastError(ERROR_NOT_FOUND); ++ return NULL; ++ ++found: ++ TRACE("Using %s for %s.\n", debugstr_w(classes[i].classname), ++ debugstr_w(classlist)); ++ ++ theme = classes[i].create(); ++ if (theme && IsWindow(hwnd)) ++ SetPropW(hwnd, THEME_PROPERTY, theme); ++ ++ return theme; ++} ++ ++void WINAPI SetThemeAppProperties(DWORD flags) ++{ ++ TRACE("(%u)\n", flags); ++} ++ ++HRESULT WINAPI SetWindowTheme(HWND hwnd, LPCWSTR sub_app_name, ++ LPCWSTR sub_id_list) ++{ ++ FIXME("(%p, %s, %s)\n", hwnd, debugstr_w(sub_app_name), ++ debugstr_w(sub_id_list)); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeBool(HTHEME htheme, int part_id, int state_id, ++ int prop_id, BOOL *value) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, value); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeColor(HTHEME htheme, int part_id, int state_id, ++ int prop_id, COLORREF *color) ++{ ++ HRESULT hr; ++ GdkRGBA rgba = {0, 0, 0, 0}; ++ uxgtk_theme_t *theme = (uxgtk_theme_t *)htheme; ++ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, color); ++ ++ if (libgtk3 == NULL) ++ return E_NOTIMPL; ++ ++ if (theme == NULL || theme->vtable == NULL) ++ return E_HANDLE; ++ ++ if (theme->vtable->get_color == NULL) ++ return E_NOTIMPL; ++ ++ if (color == NULL) ++ return E_INVALIDARG; ++ ++ hr = theme->vtable->get_color(theme, part_id, state_id, prop_id, &rgba); ++ ++ if (SUCCEEDED(hr) && rgba.alpha > 0) ++ { ++ *color = RGB((int)(0.5 + CLAMP(rgba.red, 0.0, 1.0) * 255.0), ++ (int)(0.5 + CLAMP(rgba.green, 0.0, 1.0) * 255.0), ++ (int)(0.5 + CLAMP(rgba.blue, 0.0, 1.0) * 255.0)); ++ return S_OK; ++ } ++ ++ return E_FAIL; ++} ++ ++HRESULT WINAPI GetThemeEnumValue(HTHEME htheme, int part_id, int state_id, ++ int prop_id, int *value) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, value); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeFilename(HTHEME htheme, int part_id, int state_id, ++ int prop_id, LPWSTR filename, int maxlen) ++{ ++ TRACE("(%p, %d, %d, %d, %p, %d)\n", htheme, part_id, state_id, prop_id, ++ filename, maxlen); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeFont(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ int prop_id, LOGFONTW *font) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, font); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeInt(HTHEME htheme, int part_id, int state_id, ++ int prop_id, int *value) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, value); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeIntList(HTHEME htheme, int part_id, int state_id, ++ int prop_id, INTLIST *intlist) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, intlist); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeMargins(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ int prop_id, LPRECT rect, MARGINS *margins) ++{ ++ TRACE("(%p, %d, %d, %d, %p, %p)\n", htheme, part_id, state_id, prop_id, rect, margins); ++ ++ memset(margins, 0, sizeof(MARGINS)); /* Set all margins to 0 */ ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI GetThemeMetric(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ int prop_id, int *value) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, value); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemePosition(HTHEME htheme, int part_id, int state_id, ++ int prop_id, POINT *point) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, point); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemePropertyOrigin(HTHEME htheme, int part_id, int state_id, ++ int prop_id, PROPERTYORIGIN *origin) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, origin); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeRect(HTHEME htheme, int part_id, int state_id, ++ int prop_id, RECT *rect) ++{ ++ TRACE("(%p, %d, %d, %d, %p)\n", htheme, part_id, state_id, prop_id, rect); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeString(HTHEME htheme, int part_id, int state_id, ++ int prop_id, LPWSTR buffer, int maxlen) ++{ ++ TRACE("(%p, %d, %d, %d, %p, %d)\n", htheme, part_id, state_id, prop_id, buffer, ++ maxlen); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeTransitionDuration(HTHEME htheme, int part_id, int state_id_from, ++ int state_id_to, int prop_id, DWORD *duration) ++{ ++ TRACE("(%p, %d, %d, %d, %d, %p)\n", htheme, part_id, state_id_from, state_id_to, prop_id, ++ duration); ++ ++ return E_NOTIMPL; ++} ++ ++BOOL WINAPI GetThemeSysBool(HTHEME htheme, int bool_id) ++{ ++ TRACE("(%p, %d)\n", htheme, bool_id); ++ ++ SetLastError(ERROR_NOT_SUPPORTED); ++ ++ return FALSE; ++} ++ ++COLORREF WINAPI GetThemeSysColor(HTHEME htheme, int color_id) ++{ ++ HRESULT hr = S_OK; ++ COLORREF color = 0; ++ ++ static HTHEME window_htheme = NULL; ++ static HTHEME button_htheme = NULL; ++ static HTHEME edit_htheme = NULL; ++ static HTHEME menu_htheme = NULL; ++ ++ TRACE("(%p, %d)\n", htheme, color_id); ++ ++ if (libgtk3 == NULL) ++ return GetSysColor(color_id); ++ ++ if (window_htheme == NULL) ++ { ++ window_htheme = OpenThemeData(NULL, VSCLASS_WINDOW); ++ button_htheme = OpenThemeData(NULL, VSCLASS_BUTTON); ++ edit_htheme = OpenThemeData(NULL, VSCLASS_EDIT); ++ menu_htheme = OpenThemeData(NULL, VSCLASS_MENU); ++ } ++ ++ switch (color_id) ++ { ++ case COLOR_BTNFACE: ++ case COLOR_SCROLLBAR: ++ case COLOR_WINDOWFRAME: ++ case COLOR_INACTIVECAPTION: ++ case COLOR_GRADIENTINACTIVECAPTION: ++ case COLOR_3DDKSHADOW: ++ case COLOR_BTNHIGHLIGHT: ++ case COLOR_ACTIVEBORDER: ++ case COLOR_INACTIVEBORDER: ++ case COLOR_APPWORKSPACE: ++ case COLOR_BACKGROUND: ++ case COLOR_ACTIVECAPTION: ++ case COLOR_GRADIENTACTIVECAPTION: ++ case COLOR_ALTERNATEBTNFACE: ++ case COLOR_INFOBK: /* FIXME */ ++ hr = GetThemeColor(window_htheme, WP_DIALOG, 0, TMT_FILLCOLOR, &color); ++ break; ++ ++ case COLOR_3DLIGHT: ++ case COLOR_BTNSHADOW: ++ hr = GetThemeColor(button_htheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_BORDERCOLOR, &color); ++ break; ++ ++ case COLOR_BTNTEXT: ++ case COLOR_INFOTEXT: ++ case COLOR_WINDOWTEXT: ++ case COLOR_CAPTIONTEXT: ++ hr = GetThemeColor(window_htheme, WP_DIALOG, 0, TMT_TEXTCOLOR, &color); ++ break; ++ ++ case COLOR_HIGHLIGHTTEXT: ++ hr = GetThemeColor(edit_htheme, EP_EDITTEXT, ETS_SELECTED, TMT_TEXTCOLOR, &color); ++ break; ++ ++ case COLOR_GRAYTEXT: ++ case COLOR_INACTIVECAPTIONTEXT: ++ hr = GetThemeColor(button_htheme, BP_PUSHBUTTON, PBS_DISABLED, TMT_TEXTCOLOR, &color); ++ break; ++ ++ case COLOR_HIGHLIGHT: ++ case COLOR_MENUHILIGHT: ++ case COLOR_HOTLIGHT: ++ hr = GetThemeColor(edit_htheme, EP_EDITTEXT, ETS_SELECTED, TMT_FILLCOLOR, &color); ++ break; ++ ++ case COLOR_MENUBAR: ++ hr = GetThemeColor(menu_htheme, MENU_BARBACKGROUND, MB_ACTIVE, TMT_FILLCOLOR, &color); ++ break; ++ ++ case COLOR_MENU: ++ hr = GetThemeColor(menu_htheme, MENU_POPUPBACKGROUND, 0, TMT_FILLCOLOR, &color); ++ break; ++ ++ case COLOR_MENUTEXT: ++ hr = GetThemeColor(menu_htheme, MENU_POPUPITEM, MPI_NORMAL, TMT_TEXTCOLOR, &color); ++ break; ++ ++ case COLOR_WINDOW: ++ hr = GetThemeColor(edit_htheme, EP_EDITTEXT, ETS_NORMAL, TMT_FILLCOLOR, &color); ++ break; ++ ++ default: ++ FIXME("Unknown color %d.\n", color_id); ++ return GetSysColor(color_id); ++ } ++ ++ if (FAILED(hr)) ++ return GetSysColor(color_id); ++ ++ return color; ++} ++ ++HBRUSH WINAPI GetThemeSysColorBrush(HTHEME htheme, int color_id) ++{ ++ TRACE("(%p, %d)\n", htheme, color_id); ++ ++ return CreateSolidBrush(GetThemeSysColor(htheme, color_id)); ++} ++ ++HRESULT WINAPI GetThemeSysFont(HTHEME htheme, int font_id, LOGFONTW *font) ++{ ++ TRACE("(%p, %d, %p)\n", htheme, font_id, font); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeSysInt(HTHEME htheme, int int_id, int *value) ++{ ++ TRACE("(%p, %d, %p)\n", htheme, int_id, value); ++ ++ return E_NOTIMPL; ++} ++ ++int WINAPI GetThemeSysSize(HTHEME htheme, int size_id) ++{ ++ TRACE("(%p, %d)\n", htheme, size_id); ++ ++ SetLastError(ERROR_NOT_SUPPORTED); ++ ++ return -1; ++} ++ ++HRESULT WINAPI GetThemeSysString(HTHEME htheme, int string_id, ++ LPWSTR buffer, int maxlen) ++{ ++ TRACE("(%p, %d, %p, %d)\n", htheme, string_id, buffer, maxlen); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI DrawThemeBackground(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT rect, LPCRECT clip_rect) ++{ ++ DTBGOPTS opts; ++ ++ TRACE("(%p, %p, %d, %d, %p, %p)\n", htheme, hdc, part_id, state_id, rect, clip_rect); ++ ++ opts.dwSize = sizeof(DTBGOPTS); ++ opts.dwFlags = 0; ++ ++ if (clip_rect != NULL) ++ { ++ opts.dwFlags = DTBG_CLIPRECT; ++ CopyRect(&opts.rcClip, clip_rect); ++ } ++ ++ return DrawThemeBackgroundEx(htheme, hdc, part_id, state_id, rect, &opts); ++} ++ ++HRESULT WINAPI DrawThemeBackgroundEx(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT rect, const DTBGOPTS *options) ++{ ++ uxgtk_theme_t *theme = (uxgtk_theme_t *)htheme; ++ cairo_surface_t *surface; ++ int width, height; ++ cairo_t *cr; ++ HRESULT hr; ++ ++ TRACE("(%p, %p, %d, %d, %p, %p)\n", htheme, hdc, part_id, state_id, rect, options); ++ ++ if (libgtk3 == NULL) ++ return E_NOTIMPL; ++ ++ if (theme == NULL || theme->vtable == NULL) ++ return E_HANDLE; ++ ++ if (theme->vtable->draw_background == NULL) ++ return E_NOTIMPL; ++ ++ width = rect->right - rect->left; ++ height = rect->bottom - rect->top; ++ ++ surface = pcairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); ++ cr = pcairo_create(surface); ++ ++ hr = theme->vtable->draw_background(theme, cr, part_id, state_id, width, height); ++ if (SUCCEEDED(hr)) ++ paint_cairo_surface(surface, hdc, rect->left, rect->top, width, height); ++ ++ pcairo_destroy(cr); ++ pcairo_surface_destroy(surface); ++ return hr; ++} ++ ++HRESULT WINAPI DrawThemeEdge(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT dest_rect, UINT edge, UINT flags, ++ LPRECT content_rect) ++{ ++ TRACE("(%p, %p, %d, %d, %p, %u, %u, %p)\n", htheme, hdc, part_id, state_id, ++ dest_rect, edge, flags, content_rect); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI DrawThemeIcon(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT rect, HIMAGELIST list, int index) ++{ ++ TRACE("(%p, %p, %d, %d, %p, %p, %d)\n", htheme, hdc, part_id, state_id, rect, list, index); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *rect) ++{ ++ HWND parent; ++ ++ TRACE("(%p, %p, %p)\n", hwnd, hdc, rect); ++ ++ parent = GetParent(hwnd); ++ if (!parent) ++ { ++ ERR("Window has no parent.\n"); ++ return E_FAIL; ++ } ++ ++ SendMessageW(parent, WM_ERASEBKGND, (WPARAM)hdc, 0); ++ SendMessageW(parent, WM_PRINTCLIENT, (WPARAM)hdc, PRF_CLIENT); ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI DrawThemeText(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCWSTR text, int length, DWORD flags, DWORD flags2, ++ LPCRECT rect) ++{ ++ RECT rt; ++ HRESULT hr; ++ COLORREF color = RGB(0, 0, 0), oldcolor; ++ ++ TRACE("(%p, %p, %d, %d, %s, %u, %u, %p)\n", htheme, hdc, part_id, state_id, ++ wine_dbgstr_wn(text, length), flags, flags2, rect); ++ ++ hr = GetThemeColor(htheme, part_id, state_id, TMT_TEXTCOLOR, &color); ++ if (FAILED(hr)) ++ { ++ FIXME("No color.\n"); ++ /*return hr;*/ ++ } ++ ++ oldcolor = SetTextColor(hdc, color); ++ ++ CopyRect(&rt, rect); ++ ++ SetBkMode(hdc, TRANSPARENT); ++ DrawTextW(hdc, text, length, &rt, flags); ++ ++ SetTextColor(hdc, oldcolor); ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT bounding_rect, LPRECT content_rect) ++{ ++ HRESULT hr; ++ MARGINS margins; ++ ++ TRACE("(%p, %p, %d, %d, %p, %p)\n", htheme, hdc, part_id, state_id, bounding_rect, ++ content_rect); ++ ++ if (bounding_rect == NULL || content_rect == NULL) ++ return E_INVALIDARG; ++ ++ hr = GetThemeMargins(htheme, hdc, part_id, state_id, ++ TMT_CONTENTMARGINS, NULL, &margins); ++ ++ if (FAILED(hr)) ++ return hr; ++ ++ content_rect->left = bounding_rect->left + margins.cxLeftWidth; ++ content_rect->top = bounding_rect->top + margins.cyTopHeight; ++ content_rect->right = bounding_rect->right - margins.cxRightWidth; ++ content_rect->bottom = bounding_rect->bottom - margins.cyBottomHeight; ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI GetThemeBackgroundExtent(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT content_rect, RECT *extent_rect) ++{ ++ HRESULT hr; ++ MARGINS margins; ++ ++ TRACE("(%p, %p, %d, %d, %p, %p)\n", htheme, hdc, part_id, state_id, content_rect, ++ extent_rect); ++ ++ if (content_rect == NULL || extent_rect == NULL) ++ return E_INVALIDARG; ++ ++ hr = GetThemeMargins(htheme, hdc, part_id, state_id, ++ TMT_CONTENTMARGINS, NULL, &margins); ++ ++ if (FAILED(hr)) ++ return hr; ++ ++ extent_rect->left = content_rect->left - margins.cxLeftWidth; ++ extent_rect->top = content_rect->top - margins.cyTopHeight; ++ extent_rect->right = content_rect->right + margins.cxRightWidth; ++ extent_rect->bottom = content_rect->bottom + margins.cyBottomHeight; ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI GetThemeBackgroundRegion(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCRECT rect, HRGN *region) ++{ ++ TRACE("(%p, %p, %d, %d, %p, %p)\n", htheme, hdc, part_id, state_id, rect, region); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemePartSize(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ RECT *rect, THEMESIZE type, SIZE *size) ++{ ++ uxgtk_theme_t *theme = (uxgtk_theme_t *)htheme; ++ ++ TRACE("(%p, %p, %d, %d, %p, %d, %p)\n", htheme, hdc, part_id, state_id, rect, type, size); ++ ++ if (libgtk3 == NULL) ++ return E_NOTIMPL; ++ ++ if (theme == NULL || theme->vtable == NULL) ++ return E_HANDLE; ++ ++ if (theme->vtable->get_part_size == NULL) ++ return E_NOTIMPL; ++ ++ if (rect == NULL || size == NULL) ++ return E_INVALIDARG; ++ ++ return theme->vtable->get_part_size(theme, part_id, state_id, rect, size); ++} ++ ++HRESULT WINAPI GetThemeTextExtent(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ LPCWSTR text, int length, DWORD flags, ++ LPCRECT bounding_rect, LPRECT extent_rect) ++{ ++ TRACE("(%p, %p, %d, %d, %s, %u, %p, %p)\n", htheme, hdc, part_id, state_id, ++ wine_dbgstr_wn(text, length), flags, bounding_rect, extent_rect); ++ ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI GetThemeTextMetrics(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ TEXTMETRICW *metric) ++{ ++ TRACE("(%p, %p, %d, %d, %p)\n", htheme, hdc, part_id, state_id, metric); ++ ++ if (!GetTextMetricsW(hdc, metric)) ++ return HRESULT_FROM_WIN32(GetLastError()); ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI HitTestThemeBackground(HTHEME htheme, HDC hdc, int part_id, int state_id, ++ DWORD options, LPCRECT rect, HRGN hrgn, ++ POINT point, WORD *hit_test_code) ++{ ++ TRACE("(%p, %p, %d, %d, %u, %p, %p, (%d, %d), %p)\n", htheme, hdc, part_id, state_id, options, ++ rect, hrgn, point.x, point.y, hit_test_code); ++ ++ return E_NOTIMPL; ++} ++ ++BOOL WINAPI IsThemeBackgroundPartiallyTransparent(HTHEME htheme, int part_id, int state_id) ++{ ++ TRACE("(%p, %d, %d)\n", htheme, part_id, state_id); ++ ++ return TRUE; /* The most widgets are partially transparent */ ++} ++ ++BOOL WINAPI IsThemePartDefined(HTHEME htheme, int part_id, int state_id) ++{ ++ uxgtk_theme_t *theme = (uxgtk_theme_t *)htheme; ++ ++ TRACE("(%p, %d, %d)\n", htheme, part_id, state_id); ++ ++ if (libgtk3 == NULL) ++ { ++ SetLastError(ERROR_NOT_SUPPORTED); ++ return FALSE; ++ } ++ ++ if (theme == NULL || theme->vtable == NULL) ++ { ++ SetLastError(ERROR_INVALID_HANDLE); ++ return FALSE; ++ } ++ ++ if (theme->vtable->is_part_defined == NULL) ++ { ++ SetLastError(ERROR_NOT_SUPPORTED); ++ return FALSE; ++ } ++ ++ return theme->vtable->is_part_defined(part_id, state_id); ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) + { + TRACE("(%p, %d, %p)\n", instance, reason, reserved); +@@ -205,13 +1052,13 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); +- if (!load_gtk3_libs()) return FALSE; +- break; ++ process_attach(); ++ return TRUE; + + case DLL_PROCESS_DETACH: + if (reserved) break; + free_gtk3_libs(); +- break; ++ return TRUE; + } + + return TRUE; +diff --git a/dlls/uxtheme-gtk/uxthemegtk.h b/dlls/uxtheme-gtk/uxthemegtk.h +index 42e4784..17307f1 100644 +--- a/dlls/uxtheme-gtk/uxthemegtk.h ++++ b/dlls/uxtheme-gtk/uxthemegtk.h +@@ -1,6 +1,7 @@ + /* + * GTK uxtheme implementation + * ++ * Copyright (C) 2015 Ivan Akulinchev + * Copyright (C) 2015 Michael Müller + * + * This library is free software; you can redistribute it and/or +@@ -21,9 +22,45 @@ + #ifndef UXTHEMEGTK_H + #define UXTHEMEGTK_H + ++#include "windef.h" ++ + #define GDK_DISABLE_DEPRECATION_WARNINGS + #include + ++typedef struct _uxgtk_theme uxgtk_theme_t; ++typedef struct _uxgtk_theme_vtable uxgtk_theme_vtable_t; ++ ++struct _uxgtk_theme_vtable ++{ ++ HRESULT (*get_color)(uxgtk_theme_t *theme, int part_id, int state_id, ++ int prop_id, GdkRGBA *rgba); ++ HRESULT (*draw_background)(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height); ++ HRESULT (*get_part_size)(uxgtk_theme_t *theme, int part_id, int state_id, ++ RECT *rect, SIZE *size); ++ BOOL (*is_part_defined)(int part_id, int state_id); ++}; ++ ++struct _uxgtk_theme ++{ ++ const uxgtk_theme_vtable_t *vtable; ++ ++ GtkWidget *window; ++ GtkWidget *layout; ++}; ++ ++typedef HANDLE HTHEMEFILE; ++ ++typedef struct tagTHEMENAMES ++{ ++ WCHAR szName[MAX_PATH+1]; ++ WCHAR szDisplayName[MAX_PATH+1]; ++ WCHAR szTooltip[MAX_PATH+1]; ++} THEMENAMES, *PTHEMENAMES; ++ ++typedef BOOL (CALLBACK *EnumThemeProc)(LPVOID, LPCWSTR, LPCWSTR, LPCWSTR, LPVOID, LPVOID); ++typedef BOOL (CALLBACK *ParseThemeIniFileProc)(DWORD, LPWSTR, LPWSTR, LPWSTR, DWORD, LPVOID); ++ + #define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN + MAKE_FUNCPTR(cairo_create); + MAKE_FUNCPTR(cairo_destroy); +@@ -85,4 +122,20 @@ MAKE_FUNCPTR(gtk_widget_style_get); + MAKE_FUNCPTR(gtk_window_new); + #undef MAKE_FUNCPTR + ++uxgtk_theme_t *uxgtk_button_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_combobox_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_edit_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_header_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_listbox_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_listview_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_menu_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_rebar_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_status_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_tab_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_toolbar_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_trackbar_theme_create(void) DECLSPEC_HIDDEN; ++uxgtk_theme_t *uxgtk_window_theme_create(void) DECLSPEC_HIDDEN; ++ ++void uxgtk_theme_init(uxgtk_theme_t *theme, const uxgtk_theme_vtable_t *vtable) DECLSPEC_HIDDEN; ++ + #endif /* UXTHEMEGTK_H */ +diff --git a/dlls/uxtheme-gtk/window.c b/dlls/uxtheme-gtk/window.c +new file mode 100644 +index 0000000..cf617ef +--- /dev/null ++++ b/dlls/uxtheme-gtk/window.c +@@ -0,0 +1,166 @@ ++/* ++ * GTK uxtheme implementation ++ * ++ * Copyright (C) 2015 Ivan Akulinchev ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "uxthemegtk.h" ++ ++#include ++ ++#include "winbase.h" ++#include "vsstyle.h" ++#include "vssym32.h" ++#include "winerror.h" ++ ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(uxthemegtk); ++ ++typedef struct _window_theme ++{ ++ uxgtk_theme_t base; ++} window_theme_t; ++ ++static inline window_theme_t *impl_from_uxgtk_theme_t(uxgtk_theme_t *theme) ++{ ++ return CONTAINING_RECORD(theme, window_theme_t, base); ++} ++ ++static HRESULT get_fill_color(uxgtk_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStyleContext *context; ++ GtkStateFlags state; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case WP_DIALOG: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->window); ++ break; ++ ++ default: ++ FIXME("Unsupported window part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_get_background_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_text_color(uxgtk_theme_t *theme, int part_id, int state_id, GdkRGBA *rgba) ++{ ++ GtkStyleContext *context; ++ GtkStateFlags state; ++ ++ assert(theme != NULL); ++ ++ switch (part_id) ++ { ++ case WP_DIALOG: ++ state = GTK_STATE_FLAG_NORMAL; ++ context = pgtk_widget_get_style_context(theme->window); ++ break; ++ ++ default: ++ FIXME("Unsupported window part %d.\n", part_id); ++ return E_NOTIMPL; ++ } ++ ++ pgtk_style_context_get_color(context, state, rgba); ++ ++ return S_OK; ++} ++ ++static HRESULT get_color(uxgtk_theme_t *theme, int part_id, int state_id, ++ int prop_id, GdkRGBA *rgba) ++{ ++ switch (prop_id) ++ { ++ case TMT_FILLCOLOR: ++ return get_fill_color(theme, part_id, state_id, rgba); ++ ++ case TMT_TEXTCOLOR: ++ return get_text_color(theme, part_id, state_id, rgba); ++ ++ default: ++ FIXME("Unsupported property %d.\n", prop_id); ++ return E_FAIL; ++ } ++ ++ return S_OK; ++} ++ ++static HRESULT draw_dialog(uxgtk_theme_t *theme, cairo_t *cr, int state_id, int width, int height) ++{ ++ GtkStyleContext *context; ++ ++ assert(theme != NULL); ++ ++ context = pgtk_widget_get_style_context(theme->window); ++ ++ pgtk_render_background(context, cr, 0, 0, width, height); ++ ++ return S_OK; ++} ++ ++static HRESULT draw_background(uxgtk_theme_t *theme, cairo_t *cr, int part_id, int state_id, ++ int width, int height) ++{ ++ switch (part_id) ++ { ++ case WP_DIALOG: ++ return draw_dialog(theme, cr, state_id, width, height); ++ } ++ ++ FIXME("Unsupported window part %d.\n", part_id); ++ return E_NOTIMPL; ++} ++ ++static BOOL is_part_defined(int part_id, int state_id) ++{ ++ return (part_id == WP_DIALOG); ++} ++ ++static const uxgtk_theme_vtable_t window_vtable = ++{ ++ get_color, ++ draw_background, ++ NULL, /* get_part_size */ ++ is_part_defined ++}; ++ ++uxgtk_theme_t *uxgtk_window_theme_create(void) ++{ ++ window_theme_t *theme; ++ GtkStyleContext *context; ++ ++ TRACE("()\n"); ++ ++ theme = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*theme)); ++ if (!theme) return NULL; ++ ++ uxgtk_theme_init(&theme->base, &window_vtable); ++ ++ context = pgtk_widget_get_style_context(theme->base.window); ++ pgtk_style_context_add_class(context, GTK_STYLE_CLASS_BACKGROUND); ++ ++ return &theme->base; ++} +-- +2.5.0 + diff --git a/patches/uxtheme-GTK_Theming/0003-uxthemegtk-Implement-enumeration-of-themes-color-and.patch b/patches/uxtheme-GTK_Theming/0003-uxthemegtk-Implement-enumeration-of-themes-color-and.patch new file mode 100644 index 00000000..1f428136 --- /dev/null +++ b/patches/uxtheme-GTK_Theming/0003-uxthemegtk-Implement-enumeration-of-themes-color-and.patch @@ -0,0 +1,308 @@ +From 2cf0168c9587f0b836a252f6cda65975d5d3cac1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sun, 9 Aug 2015 04:31:32 +0200 +Subject: uxthemegtk: Implement enumeration of themes, color and sizes. + +Various style improvements by Ivan Akulinchev . +--- + dlls/uxtheme-gtk/Makefile.in | 2 +- + dlls/uxtheme-gtk/uxtheme-gtk.spec | 44 +++++++++ + dlls/uxtheme-gtk/uxtheme.c | 181 +++++++++++++++++++++++++++++++++++++- + 3 files changed, 224 insertions(+), 3 deletions(-) + +diff --git a/dlls/uxtheme-gtk/Makefile.in b/dlls/uxtheme-gtk/Makefile.in +index 8cefd51..d1e79fd 100644 +--- a/dlls/uxtheme-gtk/Makefile.in ++++ b/dlls/uxtheme-gtk/Makefile.in +@@ -1,5 +1,5 @@ + MODULE = uxtheme-gtk.dll +-IMPORTS = user32 gdi32 advapi32 ++IMPORTS = user32 gdi32 advapi32 shell32 + DELAYIMPORTS = msimg32 + EXTRAINCL = $(GTK3_CFLAGS) + +diff --git a/dlls/uxtheme-gtk/uxtheme-gtk.spec b/dlls/uxtheme-gtk/uxtheme-gtk.spec +index 70cd7ff..4acc0fa 100644 +--- a/dlls/uxtheme-gtk/uxtheme-gtk.spec ++++ b/dlls/uxtheme-gtk/uxtheme-gtk.spec +@@ -1,3 +1,47 @@ ++# Export by Ordinal ++1 stdcall -noname QueryThemeServices() ++2 stdcall -noname OpenThemeFile(wstr wstr wstr ptr long) ++3 stdcall -noname CloseThemeFile(ptr) ++4 stdcall -noname ApplyTheme(ptr ptr ptr) ++7 stdcall -noname GetThemeDefaults(wstr wstr long wstr long) ++8 stdcall -noname EnumThemes(wstr ptr ptr) ++9 stdcall -noname EnumThemeColors(wstr wstr long ptr) ++10 stdcall -noname EnumThemeSizes(wstr wstr long ptr) ++11 stdcall -noname ParseThemeIniFile(wstr wstr ptr ptr) ++13 stub -noname DrawNCPreview ++14 stub -noname RegisterDefaultTheme ++15 stub -noname DumpLoadedThemeToTextFile ++16 stub -noname OpenThemeDataFromFile ++17 stub -noname OpenThemeFileFromData ++18 stub -noname GetThemeSysSize96 ++19 stub -noname GetThemeSysFont96 ++20 stub -noname SessionAllocate ++21 stub -noname SessionFree ++22 stub -noname ThemeHooksOn ++23 stub -noname ThemeHooksOff ++24 stub -noname AreThemeHooksActive ++25 stub -noname GetCurrentChangeNumber ++26 stub -noname GetNewChangeNumber ++27 stub -noname SetGlobalTheme ++28 stub -noname GetGlobalTheme ++29 stub -noname CheckThemeSignature(wstr) ++30 stub -noname LoadTheme ++31 stub -noname InitUserTheme ++32 stub -noname InitUserRegistry ++33 stub -noname ReestablishServerConnection ++34 stub -noname ThemeHooksInstall ++35 stub -noname ThemeHooksRemove ++36 stub -noname RefreshThemeForTS ++43 stub -noname ClassicGetSystemMetrics ++44 stub -noname ClassicSystemParametersInfoA ++45 stub -noname ClassicSystemParametersInfoW ++46 stub -noname ClassicAdjustWindowRectEx ++48 stub -noname GetThemeParseErrorInfo ++60 stub -noname CreateThemeDataFromObjects ++61 stub OpenThemeDataEx ++62 stub -noname ServerClearStockObjects ++63 stub -noname MarkSelection ++ + # System + @ stdcall CloseThemeData(ptr) + @ stdcall EnableThemeDialogTexture(ptr long) +diff --git a/dlls/uxtheme-gtk/uxtheme.c b/dlls/uxtheme-gtk/uxtheme.c +index 22285df..0050036 100644 +--- a/dlls/uxtheme-gtk/uxtheme.c ++++ b/dlls/uxtheme-gtk/uxtheme.c +@@ -33,6 +33,8 @@ + #include "uxtheme.h" + #include "vsstyle.h" + #include "vssym32.h" ++#include "vfwmsgs.h" ++#include "shlobj.h" + + #include "wine/debug.h" + +@@ -131,7 +133,11 @@ MAKE_FUNCPTR(gtk_window_new); + #define MENU_HEIGHT 20 + #define CLASSLIST_MAXLEN 128 + +-static const WCHAR THEME_PROPERTY[] = {'u','x','g','t','k','_','t','h','e','m','e',0}; ++static const WCHAR THEME_PROPERTY[] = {'u','x','g','t','k','_','t','h','e','m','e',0}; ++static const WCHAR FAKE_THEME_NAME[] = {'G','T','K','-','3',0}; ++static const WCHAR FAKE_THEME_COLOR[] = {'D','e','f','a','u','l','t',' ','C','o','l','o','r',0}; ++static const WCHAR FAKE_THEME_SIZE[] = {'D','e','f','a','u','l','t',' ','S','i','z','e',0}; ++static WCHAR fake_msstyles_file[MAX_PATH]; + + static void free_gtk3_libs(void) + { +@@ -240,9 +246,12 @@ error: + + static void process_attach(void) + { ++ static const WCHAR themes_subdir[] = {'\\','T','h','e','m','e','s','\\', 'g','t','k','3',0}; ++ static const WCHAR style_file[] = {'\\','g','t','k','3','.','m','s','s','t','y','l','e','s',0}; + int i, colors[NUM_SYS_COLORS]; + COLORREF refs[NUM_SYS_COLORS]; + NONCLIENTMETRICSW metrics; ++ HANDLE file; + + if (!load_gtk3_libs()) + return; +@@ -267,6 +276,52 @@ static void process_attach(void) + SystemParametersInfoW(SPI_SETCLEARTYPE, 0, (LPVOID)TRUE, 0); + SystemParametersInfoW(SPI_SETFONTSMOOTHING, 0, (LPVOID)TRUE, 0); + SystemParametersInfoW(SPI_SETFLATMENU, 0, (LPVOID)TRUE, 0); ++ ++ /* create fake msstyles file */ ++ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_RESOURCES|CSIDL_FLAG_CREATE, NULL, ++ SHGFP_TYPE_CURRENT, fake_msstyles_file))) ++ { ++ lstrcatW(fake_msstyles_file, themes_subdir); ++ SHCreateDirectoryExW(NULL, fake_msstyles_file, NULL); ++ ++ lstrcatW(fake_msstyles_file, style_file); ++ file = CreateFileW(fake_msstyles_file, GENERIC_WRITE, 0, NULL, CREATE_NEW, ++ FILE_ATTRIBUTE_NORMAL, NULL); ++ if (file != INVALID_HANDLE_VALUE) CloseHandle(file); ++ return; ++ } ++ fake_msstyles_file[0] = 0; ++} ++ ++static BOOL is_fake_theme(const WCHAR *path) ++{ ++ BY_HANDLE_FILE_INFORMATION fake_info, file_info; ++ HANDLE fake_handle, file_handle; ++ BOOL ret; ++ ++ if (!fake_msstyles_file[0]) return FALSE; ++ ++ fake_handle = CreateFileW(fake_msstyles_file, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | ++ FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ++ if (fake_handle == INVALID_HANDLE_VALUE) return FALSE; ++ ++ file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | ++ FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ++ if (file_handle == INVALID_HANDLE_VALUE) ++ { ++ CloseHandle(fake_handle); ++ return FALSE; ++ } ++ ++ ret = GetFileInformationByHandle(fake_handle, &fake_info) && ++ GetFileInformationByHandle(file_handle, &file_info) && ++ fake_info.dwVolumeSerialNumber == file_info.dwVolumeSerialNumber && ++ fake_info.nFileIndexHigh == file_info.nFileIndexHigh && ++ fake_info.nFileIndexLow == file_info.nFileIndexLow; ++ ++ CloseHandle(file_handle); ++ CloseHandle(fake_handle); ++ return ret; + } + + void uxgtk_theme_init(uxgtk_theme_t *theme, const uxgtk_theme_vtable_t *vtable) +@@ -377,7 +432,10 @@ HRESULT WINAPI GetCurrentThemeName(LPWSTR filename, int filename_maxlen, + TRACE("(%p, %d, %p, %d, %p, %d)\n", filename, filename_maxlen, + color, color_maxlen, size, size_maxlen); + +- return E_FAIL; /* To prevent calling EnumThemeColors and so on */ ++ if (filename) lstrcpynW(filename, fake_msstyles_file, filename_maxlen); ++ if (color) lstrcpynW(color, FAKE_THEME_COLOR, color_maxlen); ++ if (size) lstrcpynW(size, FAKE_THEME_SIZE, size_maxlen); ++ return S_OK; + } + + DWORD WINAPI GetThemeAppProperties(void) +@@ -1044,6 +1102,125 @@ BOOL WINAPI IsThemePartDefined(HTHEME htheme, int part_id, int state_id) + return theme->vtable->is_part_defined(part_id, state_id); + } + ++DWORD WINAPI QueryThemeServices(void) ++{ ++ TRACE("()\n"); ++ return 3; /* This is what is returned under XP in most cases */ ++} ++ ++HRESULT WINAPI OpenThemeFile(LPCWSTR filename, LPCWSTR color, LPCWSTR size, ++ HTHEMEFILE *hthemefile, DWORD unknown) ++{ ++ TRACE("(%s, %s, %s, %p, %d)\n", debugstr_w(filename), debugstr_w(color), debugstr_w(size), ++ hthemefile, unknown); ++ ++ if (!is_fake_theme(filename)) ++ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); ++ ++ if (color && lstrcmpW(FAKE_THEME_COLOR, color) != 0) ++ return HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); ++ ++ if (size && lstrcmpW(FAKE_THEME_SIZE, size) != 0) ++ return HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); ++ ++ *hthemefile = (HTHEMEFILE)0xdeadbeef; ++ return S_OK; ++} ++ ++HRESULT WINAPI CloseThemeFile(HTHEMEFILE hthemefile) ++{ ++ TRACE("(%p)\n", hthemefile); ++ return S_OK; ++} ++ ++HRESULT WINAPI ApplyTheme(HTHEMEFILE hthemefile, char *unknown, HWND hwnd) ++{ ++ TRACE("(%p, %s, %p)\n", hthemefile, unknown, hwnd); ++ return S_OK; ++} ++ ++HRESULT WINAPI GetThemeDefaults(LPCWSTR filename, LPWSTR color, DWORD color_maxlen, ++ LPWSTR size, DWORD size_maxlen) ++{ ++ TRACE("(%s, %p, %d, %p, %d)\n", debugstr_w(filename), color, color_maxlen, size, size_maxlen); ++ ++ if (!is_fake_theme(filename)) ++ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); ++ ++ lstrcpynW(color, FAKE_THEME_COLOR, color_maxlen); ++ lstrcpynW(size, FAKE_THEME_SIZE, size_maxlen); ++ return S_OK; ++} ++ ++HRESULT WINAPI EnumThemes(LPCWSTR themepath, EnumThemeProc callback, LPVOID data) ++{ ++ TRACE("(%s, %p, %p)\n", debugstr_w(themepath), callback, data); ++ ++ /* FIXME: check path */ ++ callback(NULL, fake_msstyles_file, FAKE_THEME_NAME, FAKE_THEME_NAME, NULL, data); ++ ++ return S_OK; ++} ++ ++HRESULT WINAPI EnumThemeColors(LPWSTR filename, LPWSTR size, DWORD color_id, PTHEMENAMES colors) ++{ ++ TRACE("(%s, %s, %d, %p)\n", debugstr_w(filename), debugstr_w(size), color_id, colors); ++ ++ if (!is_fake_theme(filename)) ++ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); ++ ++ if (size && lstrcmpW(FAKE_THEME_SIZE, size) != 0) ++ return E_PROP_ID_UNSUPPORTED; ++ ++ if (color_id != 0) ++ return E_PROP_ID_UNSUPPORTED; ++ ++ lstrcpynW(colors->szName, FAKE_THEME_COLOR, ++ sizeof(colors->szName) / sizeof(WCHAR)); ++ lstrcpynW(colors->szDisplayName, FAKE_THEME_COLOR, ++ sizeof(colors->szDisplayName) / sizeof(WCHAR)); ++ lstrcpynW(colors->szTooltip, FAKE_THEME_COLOR, ++ sizeof(colors->szTooltip) / sizeof(WCHAR)); ++ return S_OK; ++} ++ ++HRESULT WINAPI EnumThemeSizes(LPWSTR filename, LPWSTR color, DWORD size_id, PTHEMENAMES sizes) ++{ ++ TRACE("(%s, %s, %d, %p)\n", debugstr_w(filename), debugstr_w(color), size_id, sizes); ++ ++ if (!is_fake_theme(filename)) ++ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); ++ ++ if (color && lstrcmpW(FAKE_THEME_COLOR, color) != 0) ++ return E_PROP_ID_UNSUPPORTED; ++ ++ if (size_id != 0) ++ return E_PROP_ID_UNSUPPORTED; ++ ++ lstrcpynW(sizes->szName, FAKE_THEME_SIZE, ++ sizeof(sizes->szName) / sizeof(WCHAR)); ++ lstrcpynW(sizes->szDisplayName, FAKE_THEME_SIZE, ++ sizeof(sizes->szDisplayName) / sizeof(WCHAR)); ++ lstrcpynW(sizes->szTooltip, FAKE_THEME_SIZE, ++ sizeof(sizes->szTooltip) / sizeof(WCHAR)); ++ return S_OK; ++} ++ ++HRESULT WINAPI ParseThemeIniFile(LPCWSTR filename, LPWSTR unknown, ++ ParseThemeIniFileProc callback, LPVOID data) ++{ ++ TRACE("(%s, %s, %p, %p)\n", debugstr_w(filename), debugstr_w(unknown), callback, data); ++ return E_NOTIMPL; ++} ++ ++HRESULT WINAPI CheckThemeSignature(LPCWSTR filename) ++{ ++ if (!is_fake_theme(filename)) ++ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); ++ ++ return S_OK; ++} ++ + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) + { + TRACE("(%p, %d, %p)\n", instance, reason, reserved); +-- +2.5.0 + diff --git a/patches/uxtheme-GTK_Theming/definition b/patches/uxtheme-GTK_Theming/definition new file mode 100644 index 00000000..ad66ec1b --- /dev/null +++ b/patches/uxtheme-GTK_Theming/definition @@ -0,0 +1,4 @@ +# based on https://github.com/akulinchev/uxthemegtk +# sha1: ecbca8e848834180092d9078be0762a60617fcd7 + +Fixes: Add support for GTK3 theming