From e0f59eb16602a5f0ada0af9a02db157a248dad9d Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Mon, 30 Dec 2013 06:00:29 +0100 Subject: [PATCH] window: fix bad looking icon on Windows 7 by using native win32 API and set different icon for SMALL and BIG profile. You need to provide a .ico along the .png, and must contain at a 16x16 and 48x48 image. Closes #1667 --- MANIFEST.in | 2 +- kivy/core/window/window_pygame.py | 73 +++++++++++++++++++++++------- kivy/data/logo/kivy-icon-64.ico | Bin 0 -> 20867 bytes 3 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 kivy/data/logo/kivy-icon-64.ico diff --git a/MANIFEST.in b/MANIFEST.in index 1aaa4e171..e9dff0858 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ include *AUTHORS *LICENSE recursive-include doc * recursive-include examples * -recursive-include kivy/data *.png *.jpg *.ttf *.kv *.fs *.vs *.json *.gif *.atlas +recursive-include kivy/data *.png *.jpg *.ttf *.kv *.fs *.vs *.json *.gif *.atlas *.ico recursive-include kivy/tools *.png *.txt *.bat *.sh *.py recursive-include kivy/tests *.py *.png recursive-include kivy *.pyd *.pyx *.c *.pxi *.h *.pxd diff --git a/kivy/core/window/window_pygame.py b/kivy/core/window/window_pygame.py index a7a137b14..3bf2ac312 100644 --- a/kivy/core/window/window_pygame.py +++ b/kivy/core/window/window_pygame.py @@ -13,11 +13,12 @@ from kivy.core import CoreCriticalException from os import environ from os.path import exists, join from kivy.config import Config -from kivy import kivy_home_dir +from kivy import kivy_data_dir from kivy.base import ExceptionManager from kivy.logger import Logger from kivy.base import stopTouchApp, EventLoop from kivy.utils import platform +from kivy.resources import resource_find # When we are generating documentation, Config doesn't exist _exit_on_escape = True @@ -106,12 +107,16 @@ class WindowPygame(WindowBase): # set window icon before calling set_mode try: - #filename_icon = Config.get('kivy', 'window_icon') filename_icon = self.icon or Config.get('kivy', 'window_icon') if filename_icon == '': - logo_size = 512 if platform == 'macosx' else 32 - filename_icon = join(kivy_home_dir, - 'icon', 'kivy-icon-%d.png' % logo_size) + logo_size = 32 + if platform == 'macosx': + logo_size = 512 + elif platform == 'win': + logo_size = 64 + filename_icon = 'kivy-icon-{}.png'.format(logo_size) + filename_icon = resource_find( + join(kivy_data_dir, 'logo', filename_icon)) self.set_icon(filename_icon) except: Logger.exception('Window: cannot set icon') @@ -183,23 +188,59 @@ class WindowPygame(WindowBase): pygame.display.set_caption(self.title) def set_icon(self, filename): + if not exists(filename): + return False try: - if not exists(filename): - return False - if PY2: + if platform == 'win': try: - im = pygame.image.load(filename) - except UnicodeEncodeError: - im = pygame.image.load(filename.encode('utf8')) - else: - im = pygame.image.load(filename) - if im is None: - raise Exception('Unable to load window icon (not found)') - pygame.display.set_icon(im) + if self._set_icon_win(filename): + return True + except: + # fallback on standard loading then. + pass + + # for all others platform, or if the ico is not available, use the + # default way to set it. + self._set_icon_standard(filename) super(WindowPygame, self).set_icon(filename) except: Logger.exception('WinPygame: unable to set icon') + def _set_icon_standard(self, filename): + if PY2: + try: + im = pygame.image.load(filename) + except UnicodeEncodeError: + im = pygame.image.load(filename.encode('utf8')) + else: + im = pygame.image.load(filename) + if im is None: + raise Exception('Unable to load window icon (not found)') + pygame.display.set_icon(im) + + def _set_icon_win(self, filename): + # ensure the window ico is ended by ico + if not filename.endswith('.ico'): + filename = '{}.ico'.format(filename.rsplit('.', 1)[0]) + if not exists(filename): + return False + + import win32api + import win32gui + import win32con + hwnd = pygame.display.get_wm_info()['window'] + icon_big = win32gui.LoadImage( + None, filename, win32con.IMAGE_ICON, + 48, 48, win32con.LR_LOADFROMFILE) + icon_small = win32gui.LoadImage( + None, filename, win32con.IMAGE_ICON, + 16, 16, win32con.LR_LOADFROMFILE) + win32api.SendMessage( + hwnd, win32con.WM_SETICON, win32con.ICON_SMALL, icon_small) + win32api.SendMessage( + hwnd, win32con.WM_SETICON, win32con.ICON_BIG, icon_big) + return True + def screenshot(self, *largs, **kwargs): global glReadPixels, GL_RGBA, GL_UNSIGNED_BYTE filename = super(WindowPygame, self).screenshot(*largs, **kwargs) diff --git a/kivy/data/logo/kivy-icon-64.ico b/kivy/data/logo/kivy-icon-64.ico new file mode 100644 index 0000000000000000000000000000000000000000..b598cd5618abab67b1968124a1203f892e177eb8 GIT binary patch literal 20867 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 NTdPsc4Za=6{~rpLJ4pZl literal 0 HcmV?d00001