# Python imports import os import threading, subprocess, time # Gtk imports import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib, GdkPixbuf # Application imports from .controller_data import Controller_Data from .mixins.tree_view_update_mixin import TreeViewUpdateMixin try: from PIL import Image as PImage except Exception as e: PImage = None def threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs).start() return wrapper class Controller(TreeViewUpdateMixin, Controller_Data): def __init__(self, _settings, args, unknownargs): self.setup_controller_data(_settings) self.window.show_all() self.handle_args(args, unknownargs) def tear_down(self, widget=None, eve=None): event_system.send_ipc_message("close server") time.sleep(event_sleep_time) Gtk.main_quit() @threaded def gui_event_observer(self): while True: time.sleep(event_sleep_time) event = event_system.consume_gui_event() if event: try: type, target, data = event if not type: method = getattr(self.__class__, target) GLib.idle_add(method, *(self, *data,)) else: method = getattr(self.__class__, "hadle_gui_event_and_call_back") GLib.idle_add(method, *(self, type, target, data)) except Exception as e: print(repr(e)) self.logger.debug(e) def hadle_gui_event_and_call_back(self, type, target, parameters): method = getattr(self.__class__, target) data = method(*(self, *parameters)) event_system.push_module_event([type, None, (data,)]) def handle_args(self, args=None, unknownargs=None): print(f"Args: {args}") print(f"Unknownargs: {unknownargs}") if args.dir and os.path.isdir(args.dir): self.load_store(self.view, self.thumbnail_store, arg) if args.file and os.path.isfile(args.file): path = '/'.join(rgs.file.split("/")[:-1]) self.load_store(self.view, self.thumbnail_store, path) self.process_path(args.file) if unknownargs: for arg in unknownargs: if os.path.isdir(arg): self.load_store(self.view, self.thumbnail_store, arg) elif os.path.isfile(arg): path = '/'.join(arg.split("/")[:-1]) self.load_store(self.view, self.thumbnail_store, path) self.process_path(arg) def _on_drag_data_received(self, widget, drag_context, x, y, data, info, time): if info == 80: uri = data.get_uris()[0].split("file://")[1] if os.path.isfile(uri) and uri.endswith(self.images_filter): try: image = Gtk.Image.new_from_pixbuf(self._get_pixbuf(uri)) except Exception as e: image = Gtk.Image.new_from_pixbuf(self._get_pixbuf(self.blank_image)) self._load_image(image) elif os.path.isdir(uri): self.load_store(self.view, self.thumbnail_store, uri) def load_image_from_treeview(self, widget): store, iter = widget.get_selection().get_selected() uri = store.get_value(iter, 1) if uri == self.current_img_uri: return self.process_path(uri) def process_path(self, uri): self.current_img_uri = uri self.current_path_label.set_label(uri) if not uri.endswith(".gif"): self.is_img_gif = False self.current_img = Gtk.Image.new_from_pixbuf(self._get_pixbuf(uri)) self._load_image() else: self.is_img_gif = True self.current_img = Gtk.Image.new_from_file(uri) self.gif_animation = self.current_img.get_animation() self._load_image() def _get_pixbuf(self, uri): geom_rec = self.image_area.get_parent().get_parent().get_allocated_size()[0] width = geom_rec.width - 15 height = geom_rec.height - 15 wxh = [width, height] self.image_area.set_size_request(width, height) if PImage and uri.lower().endswith(".webp"): return self.image2pixbuf(uri, wxh) else: return GdkPixbuf.Pixbuf.new_from_file_at_scale(uri, width, height, True) def image2pixbuf(self, path, wxh): """Convert Pillow image to GdkPixbuf""" im = PImage.open(path) data = im.tobytes() data = GLib.Bytes.new(data) w, h = im.size pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(data, GdkPixbuf.Colorspace.RGB, False, 8, w, h, w * 3) return pixbuf.scale_simple(wxh[0], wxh[1], 2) # BILINEAR = 2 def _load_image(self): self.clear_children(self.image_area) self.image_area.add(self.current_img) self.image_area.show_all() @threaded def scale_image_from_parent_resize(self, widget, allocation): if not self.image_update_lock: GLib.idle_add(self._on_scale_image_from_parent_resize, ()) def _on_scale_image_from_parent_resize(self, eve): if self.current_img_uri: self.image_update_lock = True if not self.is_img_gif: self.current_img = Gtk.Image.new_from_pixbuf(self._get_pixbuf(self.current_img_uri)) self._load_image() else: try: self.gif_animation.advance() self.current_img.set_from_animation(self.gif_animation) except Exception: pass self.image_update_lock = False def get_clipboard_data(self): proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE) retcode = proc.wait() data = proc.stdout.read() return data.decode("utf-8").strip() def set_clipboard_data(self, data): proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE) proc.stdin.write(data) proc.stdin.close() retcode = proc.wait()