Ignore:
Timestamp:
6/3/2009 5:57:55 AM (5 years ago)
Author:
lowjoel
Message:

Handle theme changes so when Comctl32.dll v6 is unloaded we revert to .NET rendering (and through the DWM APIs we restore UxTheme? rendering when UxTheme? is reloaded - may not always work but this should suffice)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser6/Eraser.Util/UxThemeApi.cs

    r1099 r1105  
    2626using System.Windows.Forms; 
    2727using System.Drawing; 
     28using System.IO; 
    2829 
    2930namespace Eraser.Util 
     
    7677        public static void UpdateControlTheme(ToolStrip menu) 
    7778        { 
     79            //Register for Theme changed messages 
     80            if (ThemeMessageFilter.Instance == null) 
     81            { 
     82                ThemeMessageFilter filter = new ThemeMessageFilter(); 
     83                ThemeMessageFilter.Instance.ThemeChanged += OnThemeChanged; 
     84            } 
     85 
    7886            if (Environment.OSVersion.Version.Major >= 6) 
     87            { 
     88                //Assign our themed renderer for non-custom renderers 
     89                UXThemeMenuRenderer renderer = new UXThemeMenuRenderer(); 
    7990                if (menu.Renderer is ToolStripProfessionalRenderer) 
    80                     menu.Renderer = new UXThemeMenuRenderer(); 
     91                { 
     92                    menu.Disposed += OnThemedMenuDisposed; 
     93                    ThemedMenus.Add(menu, renderer); 
     94                    if (NativeMethods.ThemesActive) 
     95                        menu.Renderer = renderer; 
     96                } 
     97            } 
    8198 
    8299            foreach (ToolStripItem item in menu.Items) 
     
    98115 
    99116        /// <summary> 
     117        /// Handles the theme changed event - reassigning the renderers to managed 
     118        /// context menus. 
     119        /// </summary> 
     120        private static void OnThemeChanged(object sender, EventArgs e) 
     121        { 
     122            bool themesActive = NativeMethods.ThemesActive; 
     123            foreach (KeyValuePair<ToolStrip, UXThemeMenuRenderer> value in ThemedMenus) 
     124            { 
     125                if (themesActive) 
     126                    value.Key.Renderer = value.Value; 
     127                else 
     128                    value.Key.RenderMode = ToolStripRenderMode.ManagerRenderMode; 
     129            } 
     130        } 
     131 
     132        /// <summary> 
     133        /// Clean up the reference to the menu when the menu is disposed so we no 
     134        /// longer track the menu for theme changes. 
     135        /// </summary> 
     136        private static void OnThemedMenuDisposed(object sender, EventArgs e) 
     137        { 
     138            ThemedMenus.Remove(sender as ToolStrip); 
     139        } 
     140 
     141        /// <summary> 
     142        /// The private list of menus which has their render changed to the UxTheme renderer. 
     143        /// This allows us to revert the renderer back to the default Professional 
     144        /// renderer when we get a theme changed message. 
     145        /// </summary> 
     146        private static Dictionary<ToolStrip, UXThemeMenuRenderer> ThemedMenus = 
     147            new Dictionary<ToolStrip,UXThemeMenuRenderer>(); 
     148 
     149        /// <summary> 
     150        /// Filters the Application message loop for WM_THEMECHANGED messages 
     151        /// and broadcasts them to the event handlers. 
     152        /// </summary> 
     153        private class ThemeMessageFilter : IMessageFilter 
     154        { 
     155            public ThemeMessageFilter() 
     156            { 
     157                if (Instance != null) 
     158                    throw new InvalidOperationException("Only one instance of the " + 
     159                        "ThemeMessageFilter can exist at any one time,"); 
     160                Instance = this; 
     161                ThemesActive = NativeMethods.ThemesActive; 
     162                Application.AddMessageFilter(this); 
     163            } 
     164 
     165            #region IMessageFilter Members 
     166            public bool PreFilterMessage(ref Message m) 
     167            { 
     168                if (m.Msg == WM_THEMECHANGED) 
     169                { 
     170                    ThemesActive = NativeMethods.ThemesActive; 
     171                    ThemeChanged(null, EventArgs.Empty); 
     172                } 
     173                else if (m.Msg == WM_DWMCOMPOSITIONCHANGED) 
     174                { 
     175                    if (ThemesActive != NativeMethods.ThemesActive) 
     176                    { 
     177                        ThemesActive = NativeMethods.ThemesActive; 
     178                        ThemeChanged(null, EventArgs.Empty); 
     179                    } 
     180                } 
     181 
     182                return false;            
     183            } 
     184            #endregion 
     185 
     186            /// <summary> 
     187            /// The global ThemeMessageFilter instance. 
     188            /// </summary> 
     189            public static ThemeMessageFilter Instance 
     190            { 
     191                get; 
     192                private set; 
     193            } 
     194 
     195            /// <summary> 
     196            /// Called when a WM_THEMECHANGED message is sent. 
     197            /// </summary> 
     198            public EventHandler<EventArgs> ThemeChanged 
     199            { 
     200                get; 
     201                set; 
     202            } 
     203 
     204            private const int WM_THEMECHANGED = 0x031A; 
     205            private const int WM_DWMCOMPOSITIONCHANGED = 0x031E; 
     206            private bool ThemesActive; 
     207        } 
     208 
     209        /// <summary> 
    100210        /// Stores functions, structs and constants from UxTheme.dll and User32.dll 
    101211        /// </summary> 
    102212        internal static class NativeMethods 
    103213        { 
     214            [DllImport("UxTheme.dll", CharSet = CharSet.Unicode)] 
     215            [return: MarshalAs(UnmanagedType.Bool)] 
     216            private static extern bool IsThemeActive(); 
     217 
     218            public static bool ThemesActive 
     219            { 
     220                get 
     221                { 
     222                    try 
     223                    { 
     224                        return IsThemeActive(); 
     225                    } 
     226                    catch (FileLoadException) 
     227                    { 
     228                        return false; 
     229                    } 
     230                } 
     231            } 
     232 
    104233            /// <summary> 
    105234            /// Causes a window to use a different set of visual style information 
     
    125254        ~UXThemeMenuRenderer() 
    126255        { 
    127             hTheme.Close(); 
     256            if (hTheme != null) 
     257                hTheme.Close(); 
    128258        } 
    129259 
Note: See TracChangeset for help on using the changeset viewer.