There is an annoying flicker that happens on all the icons in the taskbar once in a while (sometimes all the time). This can be reproduced on demand by moving a file to the recycle bin, when nothing else is in the recycle bin, such as demonstrated here:
After doing much research, I discovered that the flickering comes about when a program requests that the icons on the system be redrawn (for example, due to a file association change). The specific request is a 'SHChangeNotify' call made to shell32.dll. For example, the following ahk script will reproduce the very flickering that is so annoying:
Code: Select all
DllCall("Shell32\SHChangeNotify", Int, 0x8000000, UInt,0, Ptr,0, Ptr,0)
Code: Select all
ControlGet, rebar, hwnd,, MSTaskListWClass1, ahk_class Shell_TrayWnd
WinSet, Style, 0x16000000, ahk_id %rebar%
Now - when it comes to the SHChangeNotify part, I found a very useful ahk script by forum user SKAN ( https://autohotkey.com/board/topic/8413 ... ation-spy/ ) that actively listens for SHChangeNotify calls made to shell32 and outputs the messages to a box, live as they happen.
I figured the two could maybe be combined - so that when a request is made to shell32 to do some kind of redrawing, ahk could quickly trigger the dropping of WM_CHILD on the taskbar, and then re-instating it about 500ms later, after the flickering had finished, so visually, you wouldn't see the flickering happen.
I attempted to do so and.. it works -- but not all of the time. It looks like it's some kind of race condition. The system performs the redrawing pretty much the exact same time my script attempts to freeze the taskbar, so it either:
1) freezes it in time (so you dont see any transition)
2) freezes it a few milliseconds too late (so you see the flicker)
3) freezes mid-way during a flicker, so the taskbar icons disappear, and my script freezes it, so you end up with 500ms of no icons, then back to normal.
I've tried all I could think of messing with putting 'critical' in different places in the script, and running the script with 'real time' priority, attempting to prioritize what I'm trying to do, but I simply do not know if it is even possible to perform the WinSet taskbar freeze faster than shell32 performs the icon redrawing. My only thoughts left are either to somehow truly intercept the call being made to shell32, doing the WinSet command, and then passing on the real request to shell32 (i dont think this is possible) - or something like, using the https://github.com/tariqporter/Gdip library to occasionally create a hidden bitmap clone of the taskbar, waiting in memory, then temporarily paint it on top of the taskbar in-place when the SHChangeNotify call is made, and drop it a few milliseconds later, covering up the flickering (maybe it would be faster than WinSet? Not sure - sort of doubtful).
Below is a basic script that can be used to trigger a temporary freezing (yet still clickable) state of the taskbar.. I made it in such a way that the request to the initial function quickly returns, without using sleep or anything to trigger the secondary function which un-freezes the taskbar:
Code: Select all
#SingleInstance, Force
#Persistent
OnExit("recovershell")
global snubflashingactive := 0
ControlGet, controlrebar, hwnd,, MSTaskListWClass1, ahk_class Shell_TrayWnd
global rebar := controlrebar
recovershell() {
if (snubflashingactive = 1) {
taskbarunfreeze()
ExitApp
}
}
taskbarunfreeze() {
SetTimer, taskbarunfreeze, Off
WinSet, Style, 0x56000000, ahk_id %rebar%
global snubflashingactive := 0
}
snubflashingicons() {
if (snubflashingactive = 0) {
global snubflashingactive := 1
WinSet, Style, 0x16000000, ahk_id %rebar%
SetTimer, taskbarunfreeze, 500
return
}
else {
return
}
}
; call this to freeze the taskbar
snubflashingicons()
https://autohotkey.com/board/topic/8413 ... ation-spy/
Code: Select all
; Shell Change Notification Spy - By SKAN Created : 24-Aug-2012
; http://dl.dropbox.com/u/6428211/AutoHotkey/ShellChangeNotification/ShChangeNotifySpy.ahk
#SingleInstance, Force
SetWorkingDir, %A_ScriptDir%
OnExit, QuitScript
Gui +AlwaysOnTop +LastFound
hGui := WinExist()
Gui, Font, S8
Gui, Add, ListView, +Grid w600 r50, EVENT|Values
LV_SetImageList( DllCall( "ImageList_Create", Int,2, Int,20, Int,0x18, Int,1, Int,1 ), 1 )
LV_ModifyCol( 1, 150 )
Gui, Show, y150, Shell Change Notification Spy
MsgNo := DllCall( "RegisterWindowMessage", Str,"SHCHANGENOTIFY" )
OnMessage( MsgNo, "ShChangeNotify" )
DriveGet, DriveList, List, Fixed
Entries := StrLen( DriveList )
VarSetCapacity( $SHChangeNotifyEntry, 8 * Entries, 0 )
Loop, Parse, DriveList
Off := ( A_Index - 1 ) * 8
, PIDL := PathGetPIDL( A_LoopField ":" )
, NumPut( PIDL, $SHChangeNotifyEntry, Off+0 )
, NumPut( True, $SHChangeNotifyEntry, Off+4 )
SHCNR_ID := DllCall( "Shell32\SHChangeNotifyRegister", UInt,hGui
, UInt, 0x8000|0x1000|0x2|0x1
, Int, 0xC0581E0|0x7FFFFFFF|0x80000000
, UInt, MsgNo
, Int, Entries
, UInt, &$SHChangeNotifyEntry )
Return
GuiClose:
GuiEscape:
QuitScript:
OnExit
DllCall( "Shell32\SHChangeNotifyDeregister", UInt,SHCNR_ID )
ExitApp
ShChangeNotify( wParam, lParam, msg, hwnd ) {
hLock := DllCall( "Shell32\SHChangeNotification_Lock"
, UInt,wParam, UInt,lParam, UIntP,pppidl, UIntP,plEvent )
Event := "SHCNE_UNDEFINED"
IfEqual,plEvent,0x7FFFFFFF ,SetEnv,Event, SHCNE_ALLEVENTS
IfEqual,plEvent,0x08000000 ,SetEnv,Event, SHCNE_ASSOCCHANGED
IfEqual,plEvent,0x00000800 ,SetEnv,Event, SHCNE_ATTRIBUTES
IfEqual,plEvent,0x00000002 ,SetEnv,Event, SHCNE_CREATE
IfEqual,plEvent,0x00000004 ,SetEnv,Event, SHCNE_DELETE
IfEqual,plEvent,0x0002381F ,SetEnv,Event, SHCNE_DISKEVENTS
IfEqual,plEvent,0x00000100 ,SetEnv,Event, SHCNE_DRIVEADD
IfEqual,plEvent,0x00010000 ,SetEnv,Event, SHCNE_DRIVEADDGUI
IfEqual,plEvent,0x00000080 ,SetEnv,Event, SHCNE_DRIVEREMOVED
IfEqual,plEvent,0x04000000 ,SetEnv,Event, SHCNE_EXTENDED_EVENT
IfEqual,plEvent,0x00040000 ,SetEnv,Event, SHCNE_FREESPACE
IfEqual,plEvent,0x0C0581E0 ,SetEnv,Event, SHCNE_GLOBALEVENTS
IfEqual,plEvent,0x80000000 ,SetEnv,Event, SHCNE_INTERRUPT
IfEqual,plEvent,0x00000020 ,SetEnv,Event, SHCNE_MEDIAINSERTED
IfEqual,plEvent,0x00000040 ,SetEnv,Event, SHCNE_MEDIAREMOVED
IfEqual,plEvent,0x00000008 ,SetEnv,Event, SHCNE_MKDIR
IfEqual,plEvent,0x00000200 ,SetEnv,Event, SHCNE_NETSHARE
IfEqual,plEvent,0x00000400 ,SetEnv,Event, SHCNE_NETUNSHARE
IfEqual,plEvent,0x00020000 ,SetEnv,Event, SHCNE_RENAMEFOLDER
IfEqual,plEvent,0x00000001 ,SetEnv,Event, SHCNE_RENAMEITEM
IfEqual,plEvent,0x00000010 ,SetEnv,Event, SHCNE_RMDIR
IfEqual,plEvent,0x00004000 ,SetEnv,Event, SHCNE_SERVERDISCONNECT
IfEqual,plEvent,0x00001000 ,SetEnv,Event, SHCNE_UPDATEDIR
IfEqual,plEvent,0x00008000 ,SetEnv,Event, SHCNE_UPDATEIMAGE
IfEqual,plEvent,0x00002000 ,SetEnv,Event, SHCNE_UPDATEITEM
If Val2 := PIDLGetPath( NumGet( pppidl+4 ) )
LV_Insert( 1, "", "", Val2 )
Val1 := PIDLGetPath( NumGet( pppidl+0 ) )
LV_Insert( 1, "", Event, Val1 )
DllCall( "Shell32\SHChangeNotification_Unlock", UInt,hLock )
}
PathGetPIDL( sPath ) {
Return DllCall( "Shell32\ILCreateFromPath" ( A_IsUnicode ? "W":"A" ), Str,sPath, UInt )
}
PIDLGetPath( PIDL ) {
VarSetCapacity( sPath, 520, 0 )
DllCall( "Shell32\SHGetPathFromIDList" ( A_IsUnicode ? "W":"A" ), UInt,PIDL, Str,sPath )
Return sPath
}
Code: Select all
MsgNo := DllCall( "RegisterWindowMessage", Str,"SHCHANGENOTIFY" )
OnMessage( MsgNo, "ShChangeNotify" )
Code: Select all
OnMessage( MsgNo, "snubflashingicons" )