Hi folks,as you may have noticed, old Gtk# versions (< 2.12.8) did not use XP's visual styles. Later versions have a workaround: they call System.WIndows.Forms.Application.DoEvents which seems to enable XP's theming. This workaround is far from optimal as it created a Winforms dependency.
That's why I tried to integrate the code of Application.DoEvents into Gtk# directly. As I do not have a Windows XP machine to test, I cannot verify if it works. I have attached an assembly and it's source code (change extension to .exe; GMail does not allow executables as attachments) that can be run with any Gtk# 2.12 version on XP. It uses a tweaked Gtk.Application class with a new mechanism to enable theming.
I would really appreciate some feedback from the community as to whether the new approach works (that is, if the attached application appears with visual styles enabled). Just reply with a screenshot of the running app on XP if you're not sure what I mean :-) .
Christian Mike Kestner wrote:
On Sat, 2009-09-05 at 09:15 +0200, Christian Hoff wrote:In Windows I use 'mkbundle' [1]We should probably put that code in a try-block. What do you think, Mike?My question would be, what do you do in the catch block?The winforms reflection thing is a huge hack, we know that, and the poster is tripping over it because of using mkbundle instead of depending on mono or .Net. We could also take the stance that if somebody wants to do this sort of minimal packaging, they are required to add an artificial ref to swf to ensure it gets bundled. But they won't have any clue that's required if we just silently fallback to unthemed windows when we can't find swf. According to Robert Jordan on this thread, it's a PeekMessage/GetMessage loop that's required to happen before the first handle is created. We should try a pinvoke solution like that and see if it works so we can remove the hack altogether instead of figuring out ways to make the hack more palatable. Mike
// ButtonApp.cs - Gtk.Button class Test implementation // // Author: Mike Kestner <mkest...@speakeasy.net> // // (c) 2001-2002 Mike Kestner namespace GtkSamples { using Gtk; using System; public class ButtonApp { public static int Main (string[] args) { GtkTuned.Application.Init (); // Our own implementation of Gtk.Application.Init Window win = new Window ("Button Tester"); win.DefaultWidth = 200; win.DefaultHeight = 150; win.DeleteEvent += new DeleteEventHandler (Window_Delete); Button btn = new Button ("Click Me"); btn.Clicked += new EventHandler (btn_click); win.Add (btn); win.ShowAll (); GtkTuned.Application.Run (); return 0; } static void btn_click (object obj, EventArgs args) { Console.WriteLine ("Button Clicked"); } static void Window_Delete (object obj, DeleteEventArgs args) { GtkTuned.Application.Quit (); args.RetVal = true; } } } // GTK.Application.cs - GTK Main Event Loop class implementation // // Author: Mike Kestner <mkest...@speakeasy.net> // // Copyright (c) 2001 Mike Kestner // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the Lesser GNU General // Public License as published by the Free Software Foundation. // // This program 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 program; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. namespace GtkTuned { using System; using System.Reflection; using System.Runtime.InteropServices; using Gdk; public class Application { // // Disables creation of instances. // private Application () { } static Application () { if (!GLib.Thread.Supported) GLib.Thread.Init (); switch (Environment.OSVersion.Platform) { case PlatformID.Win32NT: case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.WinCE: // Comment the WinDoEvents call to disable the visual styles hack Console.WriteLine ("Running visual styles hack"); WinDoEvents (); break; default: break; } } [StructLayout(LayoutKind.Sequential)] internal struct POINT { int x; int y; } [StructLayout(LayoutKind.Sequential)] internal struct MSG { IntPtr hwnd; int message; IntPtr wParam; IntPtr lParam; uint time; POINT pt; object refobject; } const uint PM_REMOVE = 1; [DllImport ("user32.dll", EntryPoint="PeekMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] extern static bool Win32PeekMessage(IntPtr msg, IntPtr hWnd, int wFilterMin, int wFilterMax, uint flags); [DllImport ("user32.dll", EntryPoint="TranslateMessage", CallingConvention=CallingConvention.StdCall)] extern static bool Win32TranslateMessage(IntPtr msg); [DllImport ("user32.dll", EntryPoint="DispatchMessageW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)] extern static IntPtr Win32DispatchMessage(IntPtr msg); internal static void WinDoEvents () { IntPtr msg_ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (MSG))); while (Win32PeekMessage (msg_ptr, IntPtr.Zero, 0, 0, PM_REMOVE)) { Console.WriteLine ("Got a message"); Win32TranslateMessage (msg_ptr); Win32DispatchMessage (msg_ptr); } Marshal.FreeHGlobal (msg_ptr); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern void gtk_init (ref int argc, ref IntPtr argv); [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern bool gtk_init_check (ref int argc, ref IntPtr argv); static void SetPrgname () { GLib.Global.ProgramName = System.IO.Path.GetFileNameWithoutExtension (Environment.GetCommandLineArgs () [0]); } public static void Init () { SetPrgname (); IntPtr argv = new IntPtr(0); int argc = 0; gtk_init (ref argc, ref argv); } static bool do_init (string progname, ref string[] args, bool check) { SetPrgname (); bool res = false; string[] progargs = new string[args.Length + 1]; progargs[0] = progname; args.CopyTo (progargs, 1); GLib.Argv argv = new GLib.Argv (progargs); IntPtr buf = argv.Handle; int argc = progargs.Length; if (check) res = gtk_init_check (ref argc, ref buf); else gtk_init (ref argc, ref buf); if (buf != argv.Handle) throw new Exception ("init returned new argv handle"); // copy back the resulting argv, minus argv[0], which we're // not interested in. if (argc <= 1) args = new string[0]; else { progargs = argv.GetArgs (argc); args = new string[argc - 1]; Array.Copy (progargs, 1, args, 0, argc - 1); } return res; } public static void Init (string progname, ref string[] args) { do_init (progname, ref args, false); } public static bool InitCheck (string progname, ref string[] args) { return do_init (progname, ref args, true); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern void gtk_main (); public static void Run () { gtk_main (); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern bool gtk_events_pending (); public static bool EventsPending () { return gtk_events_pending (); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern void gtk_main_iteration (); [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern bool gtk_main_iteration_do (bool blocking); public static void RunIteration () { gtk_main_iteration (); } public static bool RunIteration (bool blocking) { return gtk_main_iteration_do (blocking); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern void gtk_main_quit (); public static void Quit () { gtk_main_quit (); } [DllImport ("libgtk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr gtk_get_current_event (); public static Gdk.Event CurrentEvent { get { return Gdk.Event.GetEvent (gtk_get_current_event ()); } } internal class InvokeCB { EventHandler d; object sender; EventArgs args; internal InvokeCB (EventHandler d) { this.d = d; args = EventArgs.Empty; sender = this; } internal InvokeCB (EventHandler d, object sender, EventArgs args) { this.d = d; this.args = args; this.sender = sender; } internal bool Invoke () { d (sender, args); return false; } } public static void Invoke (EventHandler d) { InvokeCB icb = new InvokeCB (d); GLib.Timeout.Add (0, new GLib.TimeoutHandler (icb.Invoke)); } public static void Invoke (object sender, EventArgs args, EventHandler d) { InvokeCB icb = new InvokeCB (d, sender, args); GLib.Timeout.Add (0, new GLib.TimeoutHandler (icb.Invoke)); } } }
ThemingTest.runme
Description: Binary data
_______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list