1
1
import logging
2
+ from typing import Optional
2
3
from settings import DEBUG
3
4
from core .widgets .base import BaseWidget
4
5
from core .utils .win32 .windows import WinEvent
21
22
SystemEventListener = None
22
23
logging .warning ("Failed to load Win32 System Event Listener" )
23
24
24
-
25
+ # Missing from win32con
26
+ WS_EX_NOREDIRECTIONBITMAP = 0x20_0000
27
+
25
28
class TaskbarWidget (BaseWidget ):
26
29
validation_schema = VALIDATION_SCHEMA
27
30
update_event = pyqtSignal (int ,WinEvent )
@@ -54,7 +57,7 @@ def __init__(
54
57
self ._padding = container_padding
55
58
self ._win_info = None
56
59
self ._update_retry_count = 0
57
-
60
+
58
61
self ._icon_cache = dict ()
59
62
self .window_buttons = {}
60
63
self ._event_service = EventService ()
@@ -186,18 +189,15 @@ def _update_label(self, hwnd: int, win_info: dict, event: WinEvent) -> None:
186
189
if self ._animation ['enabled' ]:
187
190
self ._animate_icon (icon_label ,start_width = 0 ,end_width = icon_label .sizeHint ().width ())
188
191
189
-
192
+
190
193
def _get_app_icon (self ,hwnd :int ,title :str ,process :dict ,event :WinEvent )-> QPixmap | None :
191
194
try :
192
- if hwnd != win32gui .GetForegroundWindow ():
193
- return None
194
-
195
195
pid = process ["pid" ]
196
196
cache_key = (hwnd ,title ,pid ,self .dpi )
197
-
197
+
198
198
if event != WinEvent .WinEventOutOfContext :
199
199
self ._update_retry_count = 0
200
-
200
+
201
201
if cache_key in self ._icon_cache :
202
202
icon_img = self ._icon_cache [cache_key ]
203
203
else :
@@ -212,7 +212,7 @@ def _get_app_icon(self, hwnd: int, title: str, process: dict, event: WinEvent) -
212
212
if self ._update_retry_count < 10 :
213
213
self ._update_retry_count += 1
214
214
QTimer .singleShot (
215
- 500 ,
215
+ 500 ,
216
216
lambda :self ._get_app_icon (hwnd ,title ,process ,WinEvent .WinEventOutOfContext )
217
217
)
218
218
return None
@@ -232,24 +232,25 @@ def _get_app_icon(self, hwnd: int, title: str, process: dict, event: WinEvent) -
232
232
if DEBUG :
233
233
logging .exception (f"Failed to get icons for window with HWND{ hwnd } emitted by event{ event } " )
234
234
return None
235
-
236
-
237
- def get_visible_windows (self ,hwnd :int ,win_info :dict ,event :WinEvent )-> None :
235
+
236
+
237
+ def get_visible_windows (self ,_ :int ,win_info :dict ,event :WinEvent )-> list [ tuple [ str , int , Optional [ QPixmap ], WinEvent ]] :
238
238
process = win_info ['process' ]
239
239
def is_window_visible_on_taskbar (hwnd ):
240
- if win32gui .IsWindowVisible (hwnd )and win32gui . GetWindowText ( hwnd ) :
240
+ if win32gui .IsWindowVisible (hwnd ):
241
241
ex_style = win32gui .GetWindowLong (hwnd ,win32con .GWL_EXSTYLE )
242
- if not (ex_style & win32con .WS_EX_TOOLWINDOW ):
242
+ if not (ex_style & win32con .WS_EX_TOOLWINDOW or ex_style == WS_EX_NOREDIRECTIONBITMAP ):
243
243
return True
244
244
return False
245
245
246
246
visible_windows = []
247
247
248
- def enum_windows_proc (hwnd ,lParam ):
248
+ def enum_windows_proc (hwnd ,_ ):
249
249
if is_window_visible_on_taskbar (hwnd ):
250
250
title = win32gui .GetWindowText (hwnd )
251
251
icon = self ._get_app_icon (hwnd ,title ,process ,event )
252
- visible_windows .append ((title ,hwnd ,icon ,process ))
252
+ if title and icon :
253
+ visible_windows .append ((title ,hwnd ,icon ,process ))
253
254
return True
254
255
win32gui .EnumWindows (enum_windows_proc ,None )
255
256
return visible_windows