Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd55af95

Browse files
committed
feat(icon): enhance window icon fetching with DPI support and caching improvements
- Updated get_window_icon function to dynamically determine bitmap size based on system metrics.- Introduced DPI handling in ActiveWindowWidget and TaskbarWidget for accurate icon rendering.- Improved icon caching mechanism to use a composite key including DPI for better performance.- Refactored error logging for improved clarity in icon fetching failures.
1 parent8e2b32e commitd55af95

File tree

3 files changed

+63
-45
lines changed

3 files changed

+63
-45
lines changed

‎src/core/utils/win32/app_icons.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
importlogging
55
importwin32ui
66
importwin32con
7+
importwin32api
8+
importctypes
9+
importctypes.wintypes
710
fromcore.utils.win32.app_uwpimportget_package
811
importxml.etree.ElementTreeasET
912
frompathlibimportPath
@@ -17,7 +20,7 @@
1720

1821
TARGETSIZE_REGEX=re.compile(r'targetsize-([0-9]+)')
1922

20-
defget_window_icon(hwnd,dpi):
23+
defget_window_icon(hwnd,dpi=1.0):
2124
"""Fetch the icon of the window."""
2225
try:
2326
hicon=win32gui.SendMessage(hwnd,win32con.WM_GETICON,win32con.ICON_BIG,0)
@@ -38,7 +41,8 @@ def get_window_icon(hwnd, dpi):
3841
try:
3942
hdc=win32ui.CreateDCFromHandle(hdc_handle)
4043
hbmp=win32ui.CreateBitmap()
41-
bitmap_size=int(32*dpi)
44+
system_icon_size=win32api.GetSystemMetrics(win32con.SM_CXICON)
45+
bitmap_size=int(system_icon_size)
4246
hbmp.CreateCompatibleBitmap(hdc,bitmap_size,bitmap_size)
4347
memdc=hdc.CreateCompatibleDC()
4448
# Select the bitmap into the memory device context
@@ -50,12 +54,15 @@ def get_window_icon(hwnd, dpi):
5054

5155
bmpinfo=hbmp.GetInfo()
5256
bmpstr=hbmp.GetBitmapBits(True)
53-
57+
58+
raw_data=bytes(bmpstr)
5459
img=Image.frombuffer(
5560
'RGBA',
5661
(bmpinfo['bmWidth'],bmpinfo['bmHeight']),
57-
bmpstr,'raw','BGRA',0,1
58-
)
62+
raw_data,'raw','BGRA',0,1
63+
).convert('RGBA')
64+
target_size=48# target size (48x48) wihout DPI, most of uwps are also 44x44
65+
img=img.resize((target_size,target_size),Image.LANCZOS)
5966
returnimg
6067
finally:
6168
# Cleaning up resources
@@ -89,13 +96,8 @@ def get_window_icon(hwnd, dpi):
8996
#logging.debug("Released device context handle.")
9097
exceptExceptionase:
9198
#logging.debug(f"Error releasing device context handle: {e}")
92-
pass
93-
99+
pass
94100
else:
95-
importwin32api
96-
importctypes
97-
importctypes.wintypes
98-
importwin32process
99101
try:
100102
class_name=win32gui.GetClassName(hwnd)
101103
except:
@@ -126,7 +128,7 @@ def cb(hwnd, b):
126128
manifest_path=os.path.join(package.package_path,"AppXManifest.xml")
127129
ifnotos.path.exists(manifest_path):
128130
ifDEBUG:
129-
print(f"manifest not found{manifest_path}")
131+
logging.error(f"manifest not found{manifest_path}")
130132
returnNone
131133
root=ET.parse(manifest_path)
132134
velement=root.find(".//VisualElements")
@@ -187,6 +189,5 @@ def target_size_sort(s):
187189
returnNone
188190
returnimg
189191
exceptExceptionase:
190-
logging.exception("")
191-
print(f"Error fetching icon:{e}")
192+
logging.error(f"Error fetching icon:{e}")
192193
returnNone

‎src/core/widgets/yasb/active_window.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def __init__(
5555
container_padding:dict[str,int],
5656
):
5757
super().__init__(class_name="active-window-widget")
58+
self.dpi=None
5859
self._win_info=None
5960
self._show_alt=False
6061
self._label=label
@@ -63,7 +64,6 @@ def __init__(
6364
self._label_no_window=label_no_window
6465
self._label_icon=label_icon
6566
self._label_icon_size=label_icon_size
66-
self.dpi=self.screen().devicePixelRatio()
6767
self._monitor_exclusive=monitor_exclusive
6868
self._max_length=max_length
6969
self._max_length_ellipsis=max_length_ellipsis
@@ -185,16 +185,21 @@ def _update_window_title(self, hwnd: int, win_info: dict, event: WinEvent) -> No
185185
process=win_info['process']
186186
pid=process["pid"]
187187
class_name=win_info['class_name']
188-
188+
cache_key= (hwnd,title,pid,self.dpi)
189+
189190
ifself._label_icon:
190191
ifevent!=WinEvent.WinEventOutOfContext:
191192
self._update_retry_count=0
192-
if(hwnd,title,pid)inself._icon_cache:
193-
icon_img=self._icon_cache[(hwnd,title,pid)]
193+
ifcache_keyinself._icon_cache:
194+
icon_img=self._icon_cache[cache_key]
194195
else:
195-
icon_img=get_window_icon(hwnd,self.dpi)
196+
self.dpi=self.screen().devicePixelRatio()
197+
icon_img=get_window_icon(hwnd)
196198
ificon_img:
197-
icon_img=icon_img.resize((int(self._label_icon_size*self.dpi),int(self._label_icon_size*self.dpi)),Image.LANCZOS).convert("RGBA")
199+
icon_img=icon_img.resize(
200+
(int(self._label_icon_size*self.dpi),int(self._label_icon_size*self.dpi)),
201+
Image.LANCZOS
202+
).convert("RGBA")
198203
else:
199204
# UWP apps might need a moment to start under ApplicationFrameHost
200205
# So we delay the detection, but only do it once.
@@ -207,10 +212,11 @@ def _update_window_title(self, hwnd: int, win_info: dict, event: WinEvent) -> No
207212
self._update_retry_count=0
208213

209214
ifnotDEBUG:
210-
self._icon_cache[(hwnd,title,pid)]=icon_img
215+
self._icon_cache[cache_key]=icon_img
211216
ificon_img:
212217
qimage=QImage(icon_img.tobytes(),icon_img.width,icon_img.height,QImage.Format.Format_RGBA8888)
213218
self.pixmap=QPixmap.fromImage(qimage)
219+
self.pixmap.setDevicePixelRatio(self.dpi)
214220
else:
215221
self.pixmap=None
216222

‎src/core/widgets/yasb/taskbar.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __init__(
3737
callbacks:dict[str,str]
3838
):
3939
super().__init__(class_name="taskbar-widget")
40-
40+
self.dpi=None# Initial DPI value
4141
self.icon_label=QLabel()
4242
self._label_icon_size=icon_size
4343
ifisinstance(animation,bool):
@@ -55,7 +55,6 @@ def __init__(
5555
self._win_info=None
5656
self._update_retry_count=0
5757

58-
self.dpi=self.screen().devicePixelRatio()
5958
self._icon_cache=dict()
6059
self.window_buttons= {}
6160
self._event_service=EventService()
@@ -187,41 +186,53 @@ def _update_label(self, hwnd: int, win_info: dict, event: WinEvent) -> None:
187186
ifself._animation['enabled']:
188187
self._animate_icon(icon_label,start_width=0,end_width=icon_label.sizeHint().width())
189188

190-
def_get_app_icon(self,hwnd:int,title:str,process:dict,event:WinEvent)->None:
189+
190+
def_get_app_icon(self,hwnd:int,title:str,process:dict,event:WinEvent)->QPixmap|None:
191191
try:
192192
ifhwnd!=win32gui.GetForegroundWindow():
193-
return
193+
returnNone
194+
194195
pid=process["pid"]
196+
cache_key= (hwnd,title,pid,self.dpi)
195197

196198
ifevent!=WinEvent.WinEventOutOfContext:
197199
self._update_retry_count=0
198-
199-
if(hwnd,title,pid)inself._icon_cache:
200-
icon_img=self._icon_cache[(hwnd,title,pid)]
200+
201+
ifcache_keyinself._icon_cache:
202+
icon_img=self._icon_cache[cache_key]
201203
else:
202-
icon_img=get_window_icon(hwnd,self.dpi)
204+
self.dpi=self.screen().devicePixelRatio()
205+
icon_img=get_window_icon(hwnd)
203206
ificon_img:
204-
icon_img=icon_img.resize((int(self._label_icon_size*self.dpi),int(self._label_icon_size*self.dpi)),Image.LANCZOS).convert("RGBA")
205-
else:
206-
# UWP apps I hate it
207-
ifprocess["name"]=="ApplicationFrameHost.exe":
208-
ifself._update_retry_count<10:
209-
self._update_retry_count+=1
210-
QTimer.singleShot(500,lambda:self._get_app_icon(hwnd,title,process,WinEvent.WinEventOutOfContext))
211-
return
212-
else:
213-
self._update_retry_count=0
207+
icon_img=icon_img.resize(
208+
(int(self._label_icon_size*self.dpi),int(self._label_icon_size*self.dpi)),
209+
Image.LANCZOS
210+
).convert("RGBA")
211+
elifprocess["name"]=="ApplicationFrameHost.exe":
212+
ifself._update_retry_count<10:
213+
self._update_retry_count+=1
214+
QTimer.singleShot(
215+
500,
216+
lambda:self._get_app_icon(hwnd,title,process,WinEvent.WinEventOutOfContext)
217+
)
218+
returnNone
219+
self._update_retry_count=0
220+
214221
ifnotDEBUG:
215-
self._icon_cache[(hwnd,title,pid)]=icon_img
216-
ificon_img:
217-
qimage=QImage(icon_img.tobytes(),icon_img.width,icon_img.height,QImage.Format.Format_RGBA8888)
218-
pixmap=QPixmap.fromImage(qimage)
219-
else:
220-
pixmap=None
222+
self._icon_cache[cache_key]=icon_img
223+
224+
ifnoticon_img:
225+
returnNone
226+
qimage=QImage(icon_img.tobytes(),icon_img.width,icon_img.height,QImage.Format.Format_RGBA8888)
227+
pixmap=QPixmap.fromImage(qimage)
228+
pixmap.setDevicePixelRatio(self.dpi)
221229
returnpixmap
230+
222231
exceptException:
223232
ifDEBUG:
224233
logging.exception(f"Failed to get icons for window with HWND{hwnd} emitted by event{event}")
234+
returnNone
235+
225236

226237
defget_visible_windows(self,hwnd:int,win_info:dict,event:WinEvent)->None:
227238
process=win_info['process']

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp