develop #11
| @@ -26,18 +26,16 @@ class GridMixin: | ||||
|         for file in files: | ||||
|             store.append([None, file[0]]) | ||||
|  | ||||
|         self.load_icons(tab, store, dir, files) | ||||
|         Gtk.main_iteration() | ||||
|         for i, file in enumerate(files): | ||||
|             self.create_icon(i, tab, store, dir, file[0]) | ||||
|  | ||||
|         # NOTE: Not likely called often from here but it could be useful | ||||
|         if save_state and not trace_debug: | ||||
|             self.fm_controller.save_state() | ||||
|  | ||||
|  | ||||
|     @threaded | ||||
|     def load_icons(self, tab, store, dir, files): | ||||
|         for i, file in enumerate(files): | ||||
|             self.create_icon(i, tab, store, dir, file[0]) | ||||
|  | ||||
|     @daemon_threaded | ||||
|     def create_icon(self, i, tab, store, dir, file): | ||||
|         icon = tab.create_icon(dir, file) | ||||
|         GLib.idle_add(self.update_store, *(i, store, icon,)) | ||||
| @@ -46,7 +44,6 @@ class GridMixin: | ||||
|         itr = store.get_iter(i) | ||||
|         store.set_value(itr, 0, icon) | ||||
|  | ||||
|  | ||||
|     def create_tab_widget(self, tab): | ||||
|         return TabHeaderWidget(tab, self.close_tab) | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| # Python imports | ||||
| import os | ||||
| import hashlib | ||||
| from os.path import isfile | ||||
| import hashlib | ||||
| import threading | ||||
|  | ||||
| # Lib imports | ||||
| import gi | ||||
| @@ -12,7 +13,7 @@ from gi.repository import GdkPixbuf | ||||
|  | ||||
| try: | ||||
|     from PIL import Image as PImage | ||||
| except Exception as e: | ||||
| except ModuleNotFoundError as e: | ||||
|     PImage = None | ||||
|  | ||||
| # Application imports | ||||
| @@ -22,6 +23,10 @@ from .mixins.desktopiconmixin import DesktopIconMixin | ||||
|  | ||||
|  | ||||
|  | ||||
| class IconException(Exception): | ||||
|     ... | ||||
|  | ||||
|  | ||||
|  | ||||
| class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|     def create_icon(self, dir, file): | ||||
| @@ -30,7 +35,7 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|  | ||||
|     def get_icon_image(self, dir, file, full_path): | ||||
|         try: | ||||
|             thumbnl = None | ||||
|             thumbnl = self._get_system_thumbnail_gtk_thread(full_path, self.sys_icon_wh[0]) | ||||
|  | ||||
|             if file.lower().endswith(self.fmeshs):               # 3D Mesh icon | ||||
|                 ... | ||||
| @@ -44,13 +49,10 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|                 thumbnl = self.find_thumbnail_from_desktop_file(full_path) | ||||
|  | ||||
|             if not thumbnl: | ||||
|                 thumbnl = self.get_system_thumbnail(full_path, self.sys_icon_wh[0]) | ||||
|  | ||||
|             if not thumbnl: | ||||
|                 thumbnl = self.get_generic_icon() | ||||
|                 raise IconException("No known icons found.") | ||||
|  | ||||
|             return thumbnl | ||||
|         except Exception: | ||||
|         except IconException: | ||||
|             ... | ||||
|  | ||||
|         return self.get_generic_icon() | ||||
| @@ -62,7 +64,7 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|                 self.generate_blender_thumbnail(full_path, hash_img_path) | ||||
|  | ||||
|             return self.create_scaled_image(hash_img_path, self.video_icon_wh) | ||||
|         except Exception as e: | ||||
|         except IconException as e: | ||||
|             print("Blender thumbnail generation issue:") | ||||
|             print( repr(e) ) | ||||
|  | ||||
| @@ -79,7 +81,7 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|                 self.generate_video_thumbnail(full_path, hash_img_path, scrub_percent) | ||||
|  | ||||
|             return self.create_scaled_image(hash_img_path, self.video_icon_wh) | ||||
|         except Exception as e: | ||||
|         except IconException as e: | ||||
|             print("Image/Video thumbnail generation issue:") | ||||
|             print( repr(e) ) | ||||
|  | ||||
| @@ -100,7 +102,7 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|                     return self.image2pixbuf(full_path, wxh) | ||||
|  | ||||
|                 return GdkPixbuf.Pixbuf.new_from_file_at_scale(full_path, wxh[0], wxh[1], True) | ||||
|             except Exception as e: | ||||
|             except IconException as e: | ||||
|                 print("Image Scaling Issue:") | ||||
|                 print( repr(e) ) | ||||
|  | ||||
| @@ -109,21 +111,37 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | ||||
|     def create_from_file(self, full_path): | ||||
|         try: | ||||
|             return GdkPixbuf.Pixbuf.new_from_file(full_path) | ||||
|         except Exception as e: | ||||
|         except IconException as e: | ||||
|             print("Image from file Issue:") | ||||
|             print( repr(e) ) | ||||
|  | ||||
|         return None | ||||
|  | ||||
|     def get_system_thumbnail(self, filename, size): | ||||
|     def _get_system_thumbnail_gtk_thread(self, full_path, size): | ||||
|         def _call_gtk_thread(event, result): | ||||
|             result.append( self.get_system_thumbnail(full_path, size) ) | ||||
|             event.set() | ||||
|  | ||||
|         result  = [] | ||||
|         event   = threading.Event() | ||||
|         GLib.idle_add(_call_gtk_thread, event, result) | ||||
|         event.wait() | ||||
|         return result[0] | ||||
|  | ||||
|  | ||||
|     def get_system_thumbnail(self, full_path, size): | ||||
|         try: | ||||
|             gio_file  = Gio.File.new_for_path(filename) | ||||
|             gio_file  = Gio.File.new_for_path(full_path) | ||||
|             info      = gio_file.query_info('standard::icon' , 0, None) | ||||
|             icon      = info.get_icon().get_names()[0] | ||||
|             icon_path = settings.get_icon_theme().lookup_icon(icon , size , 0).get_filename() | ||||
|             data      = settings.get_icon_theme().lookup_icon(icon , size , 0) | ||||
|  | ||||
|             return GdkPixbuf.Pixbuf.new_from_file(icon_path) | ||||
|         except Exception: | ||||
|             if data: | ||||
|                 icon_path = data.get_filename() | ||||
|                 return GdkPixbuf.Pixbuf.new_from_file(icon_path) | ||||
|  | ||||
|             raise IconException("No system icon found...") | ||||
|         except IconException: | ||||
|             ... | ||||
|  | ||||
|         return None | ||||
|   | ||||
| @@ -24,43 +24,49 @@ class DesktopIconMixin: | ||||
|             alt_icon_path = "" | ||||
|  | ||||
|             if "steam" in icon: | ||||
|                 name         = xdgObj.getName() | ||||
|                 file_hash    = hashlib.sha256(str.encode(name)).hexdigest() | ||||
|                 hash_img_pth = f"{self.STEAM_ICONS_PTH}/{file_hash}.jpg" | ||||
|  | ||||
|                 if isfile(hash_img_pth) == True: | ||||
|                     # Use video sizes since headers are bigger | ||||
|                     return self.create_scaled_image(hash_img_pth, self.video_icon_wh) | ||||
|  | ||||
|                 exec_str  = xdgObj.getExec() | ||||
|                 parts     = exec_str.split("steam://rungameid/") | ||||
|                 id        = parts[len(parts) - 1] | ||||
|                 imageLink = f"{self.STEAM_CDN_URL}{id}/header.jpg" | ||||
|                 proc      = subprocess.Popen(["wget", "-O", hash_img_pth, imageLink]) | ||||
|                 proc.wait() | ||||
|  | ||||
|                 # Use video thumbnail sizes since headers are bigger | ||||
|                 return self.create_scaled_image(hash_img_pth, self.video_icon_wh) | ||||
|                 return self.get_steam_img(xdgObj) | ||||
|             elif os.path.exists(icon): | ||||
|                 return self.create_scaled_image(icon, self.sys_icon_wh) | ||||
|             else: | ||||
|                 gio_icon = Gio.Icon.new_for_string(icon) | ||||
|                 gicon    = Gtk.Image.new_from_gicon(gio_icon, 32) | ||||
|                 pixbuf   = gicon.get_pixbuf() | ||||
|                 pixbuf, alt_icon_path = self.get_icon_from_traversal(icon) | ||||
|                 if pixbuf: | ||||
|                     return pixbuf | ||||
|  | ||||
|                 alt_icon_path = "" | ||||
|                 for dir in self.ICON_DIRS: | ||||
|                     alt_icon_path = self.traverse_icons_folder(dir, icon) | ||||
|                     if alt_icon_path != "": | ||||
|                         break | ||||
|  | ||||
|                 return self.create_scaled_image(alt_icon_path, self.sys_icon_wh) | ||||
|         except Exception as e: | ||||
|             print(".desktop icon generation issue:") | ||||
|             print( repr(e) ) | ||||
|             return None | ||||
|  | ||||
|         return None | ||||
|  | ||||
|  | ||||
|     def get_steam_img(self, xdgObj): | ||||
|         name         = xdgObj.getName() | ||||
|         file_hash    = hashlib.sha256(str.encode(name)).hexdigest() | ||||
|         hash_img_pth = f"{self.STEAM_ICONS_PTH}/{file_hash}.jpg" | ||||
|  | ||||
|         if not isfile(hash_img_pth): | ||||
|             exec_str  = xdgObj.getExec() | ||||
|             parts     = exec_str.split("steam://rungameid/") | ||||
|             id        = parts[len(parts) - 1] | ||||
|             imageLink = f"{self.STEAM_CDN_URL}{id}/header.jpg" | ||||
|             proc      = subprocess.Popen(["wget", "-O", hash_img_pth, imageLink]) | ||||
|             proc.wait() | ||||
|  | ||||
|         return self.create_scaled_image(hash_img_pth, self.video_icon_wh) | ||||
|  | ||||
|     def get_icon_from_traversal(self, icon): | ||||
|         gio_icon = Gio.Icon.new_for_string(icon) | ||||
|         gicon    = Gtk.Image.new_from_gicon(gio_icon, 32) | ||||
|         pixbuf   = gicon.get_pixbuf() | ||||
|  | ||||
|         alt_icon_path = "" | ||||
|         for dir in self.ICON_DIRS: | ||||
|             alt_icon_path = self.traverse_icons_folder(dir, icon) | ||||
|             if alt_icon_path != "": | ||||
|                 break | ||||
|  | ||||
|         return pixbuf, alt_icon_path | ||||
|  | ||||
|     def traverse_icons_folder(self, path, icon): | ||||
|         for (dirpath, dirnames, filenames) in os.walk(path): | ||||
|   | ||||
| @@ -224,10 +224,13 @@ class Tab(Settings, FileHandler, Launcher, Icon, Path): | ||||
|         return self._dir_watcher | ||||
|  | ||||
|     def _atoi(self, text): | ||||
|         return int(text) if text.isdigit() else text | ||||
|         return int(text) if text.isnumeric() else text | ||||
|  | ||||
|     def _atof(self, text): | ||||
|         return float(text) if text.isnumeric() else text | ||||
|  | ||||
|     def _natural_keys(self, text): | ||||
|         return [ self._atoi(c) for c in re.split('(\d+)',text) ] | ||||
|         return [ self._atof(c) for c in re.split('(\d+)', text) ] | ||||
|  | ||||
|     def _hash_text(self, text) -> str: | ||||
|         return hashlib.sha256(str.encode(text)).hexdigest()[:18] | ||||
|   | ||||
| @@ -56,9 +56,12 @@ class IPCServer: | ||||
|     @daemon_threaded | ||||
|     def _run_ipc_loop(self, listener) -> None: | ||||
|         while True: | ||||
|             conn       = listener.accept() | ||||
|             start_time = time.perf_counter() | ||||
|             GLib.idle_add(self._handle_ipc_message, *(conn, start_time,)) | ||||
|             try: | ||||
|                 conn       = listener.accept() | ||||
|                 start_time = time.perf_counter() | ||||
|                 GLib.idle_add(self._handle_ipc_message, *(conn, start_time,)) | ||||
|             except Exception as e: | ||||
|                 ... | ||||
|  | ||||
|         listener.close() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user