Elestriel / TaskbarTools

Grants the ability to set the Windows Taskbar to any opacity and colour desired.
MIT License
343 stars 29 forks source link

After restarting explorer, have to manually click Stop/Start to re-apply #2

Closed WizardCM closed 7 years ago

WizardCM commented 7 years ago

For an unrelated issue, I had to restart Explorer. When my taskbar returned, it was the default accent colour without the adjustments in TaskbarTools.

sylveon commented 7 years ago

Yeah, the HWND is not the same anymore when you restart Explorer. The app would need to check if the window exists before applying settings in the while(true) loop and if it doesn't, try to find the new one

olliecheng commented 7 years ago

You can check using IsWindow.

Elestriel commented 7 years ago

I don't re-check the HWND in the loop, since that would drive CPU usage up pretty high. I'll have it look every 10 or so seconds, though. Once I get a chance to dive back in to coding I'll get this done!

qwerty12 commented 7 years ago

If you register for the TaskbarCreated message (and probably call ChangeWindowMessageFilterEx to ensure the message gets through even if TT happens to be running elevated), you can get Explorer to tell your application that the taskbar has been recreated instead of checking for it yourself.

Elestriel commented 7 years ago

That sounds cool, I'll look into it. If you'd like to make the change yourself, go for it!

qwerty12 commented 7 years ago

I don't know C#, sorry - I'd be at a loss trying to work out how to safely synchronise receiving the message with the HWND(s) the SetWindowCompositionAttribute loop is looking at...

Elestriel commented 7 years ago

Looks like I'll have to create a C++ DLL to do this anyway. Urgh. I'm not great in C++.

qwerty12 commented 7 years ago

I don't think that would be required; even the AutoHotkey script I have running in the background on my system listens for the same message. P/Invoking RegisterWindowMessage and then listening for the message returned by that function using something like this would probably be enough.

(Apologies for half-heartedly bringing this up when I don't know C#, but I figured sharing the idea was better than nothing...)

Elestriel commented 7 years ago

I was thinking I could use a couple of different techniques to try and capture the message, but it might be too low-level to reach. I'm going to try doing it in C# before going to C++, believe me. I'll do some research on the topic and see what comes up.

qwerty12 commented 7 years ago

Alright, this has been enough to reaffirm my love for C and my already-heavily-beloved AutoHotkey, but here's something basic that does, indeed, listen for that message. I'm doing the lazy thing and just pasting a diff because this is unlikely to get applied (if at all) as-is:

diff --git a/TaskbarTool/MainWindow.xaml.cs b/TaskbarTool/MainWindow.xaml.cs
index a9d80e1..2a5c759 100644
--- a/TaskbarTool/MainWindow.xaml.cs
+++ b/TaskbarTool/MainWindow.xaml.cs
@@ -7,6 +7,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Interop;
 using System.Windows.Media;

 namespace TaskbarTool
@@ -25,6 +26,10 @@ namespace TaskbarTool

         [DllImport("user32.dll", CharSet = CharSet.Unicode)]
         static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
+
+        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+        static extern uint RegisterWindowMessage(string msgString);
+
         #endregion Invokes

         #region Enums
@@ -85,6 +90,8 @@ namespace TaskbarTool
         static AccentPolicy accentPolicy = new AccentPolicy();
         static System.Windows.Forms.NotifyIcon SysTrayIcon;
         ContextMenu SysTrayContextMenu;
+        private static readonly uint WM_TASKBARCREATED = RegisterWindowMessage("TaskbarCreated");
+        private const uint WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
         #endregion Declarations

         #region Initializations
@@ -115,6 +122,34 @@ namespace TaskbarTool
             base.OnStateChanged(e);
         }

+        protected override void OnSourceInitialized(EventArgs e)
+        {
+            base.OnSourceInitialized(e);
+
+            IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
+            HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
+            mainWindowSrc.AddHook(WndProc);
+        }
+
+        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+        {
+            if (msg == WM_TASKBARCREATED)
+            {
+                RunApplyTask = false;
+                ApplyTask?.Wait(100);
+                RunApplyTask = true;
+                ApplyTask = new Task(() => ApplyToAllTaskbars());
+                ApplyTask.Start();
+
+                handled = true;
+            } else if (msg == WM_DWMCOLORIZATIONCOLORCHANGED && RunAccentTask) {
+                accentPolicy.GradientColor = WindowsAccentColor.GetColorAsInt(); // TODO: use colour from wParam
+                handled = true;
+            }
+
+            return IntPtr.Zero;
+        }
+
         private void PopulateComboBoxes()
         {
             AccentStateComboBox.ItemsSource = Enum.GetValues(typeof(AccentState)).Cast<AccentState>();
@@ -222,14 +257,6 @@ namespace TaskbarTool
             Marshal.FreeHGlobal(policyPtr);
         }

-        private void GetWindowsAccentColorLoop()
-        {
-            while (RunAccentTask) {
-                accentPolicy.GradientColor = WindowsAccentColor.GetColorAsInt();
-                Thread.Sleep(900);
-            }
-        }
-
         #endregion Functions

         #region Control Handles
@@ -283,8 +310,6 @@ namespace TaskbarTool
             {
                 GradientColorPicker.IsEnabled = false;
                 RunAccentTask = true;
-                WindowsAccentColorTask = new Task(() => GetWindowsAccentColorLoop());
-                WindowsAccentColorTask.Start();
             }
             else
             {
Elestriel commented 7 years ago

I've found a way to detect new processes using WMI, but it requires elevation. It's a pretty simple approach, but I'm not sure if users will want to run elevated.

I could try the RegisterWindowMessage approach and see how that goes!

Droyk commented 7 years ago

but I'm not sure if users will want to run elevated.

I don't see why any user won't run it as elevated if they want the feature they will and if you don't want to give them elevation warning every time they open your program then there is a windows program called task scheduler it will Skip-UAC warning/consent/elevation messages if you set it up user will see the warning message the first time they run your program then they will never see it again there are other methods to skip UAC but first tell me what do you think.

Elestriel commented 7 years ago

Right now I'm playing with qwerty12's solution. It doesn't require administrator privileges, so it could be the right fix. The reason I don't want to require elevation is that some people might want to use this on a work computer, where permissions are restricted.

Droyk commented 7 years ago

some people might want to use this on a work computer, where permissions are restricted.

Okay I didn't thought about that.... see if it work's via qwerty method...

Elestriel commented 7 years ago

Implemented in v1.0.6.

I still don't know how to use Github properly.

Droyk commented 7 years ago

I still don't know how to use Github properly.

you will know with time.

olliecheng commented 7 years ago

I have a version which doesn't require elevation on my fork of @ethanhs' TranslucentTb.

On 12 Jan. 2017, at 3:31 am, Emily Maxwell notifications@github.com wrote:

Implemented in v1.0.6.

I still don't know how to use Github properly.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

Elestriel commented 7 years ago

This one doesn't require elevation! :)

olliecheng commented 7 years ago

Yeah, @qwerty12's solution is pretty neat.