From a2e99ce302bf12cca301ed78810d8575bd8f10c3 Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 16 Apr 2023 23:57:12 -0500 Subject: [PATCH] Added 3 of 4 screen grab functionality --- src/new-src/app.py | 4 +- src/new-src/core/controller.py | 8 +- src/new-src/core/controller_data.py | 1 - src/new-src/core/screenshot_controller.py | 84 +++++++++++++++++++++ src/new-src/core/widgets/delay_amount.py | 14 +++- src/new-src/core/widgets/images_list.py | 28 ++++++- src/new-src/core/widgets/monitor_list.py | 21 ++++-- src/new-src/core/widgets/snapshot_button.py | 15 ++-- src/new-src/core/window.py | 3 +- src/new-src/mixins/tree_nixin.py | 2 +- src/new-src/utils/settings/settings.py | 8 ++ 11 files changed, 164 insertions(+), 24 deletions(-) create mode 100644 src/new-src/core/screenshot_controller.py diff --git a/src/new-src/app.py b/src/new-src/app.py index 1ea9b36..3f8a989 100644 --- a/src/new-src/app.py +++ b/src/new-src/app.py @@ -8,11 +8,11 @@ from utils.ipc_server import IPCServer from core.window import Window + class AppLaunchException(Exception): ... - class Application(IPCServer): ''' Create Settings and Controller classes. Bind signal to Builder. Inherit from Builtins to bind global methods and classes.''' @@ -26,7 +26,7 @@ class Application(IPCServer): if not self.is_ipc_alive: for arg in unknownargs + [args.new_tab,]: - if os.path.isdir(arg): + if os.path.isfile(arg): message = f"FILE|{arg}" self.send_ipc_message(message) diff --git a/src/new-src/core/controller.py b/src/new-src/core/controller.py index 95aef43..5e0748c 100644 --- a/src/new-src/core/controller.py +++ b/src/new-src/core/controller.py @@ -12,11 +12,11 @@ from gi.repository import GLib # Application imports from .mixins.signals_mixins import SignalsMixins from .controller_data import ControllerData +from .screenshot_controller import ScreenshotController from .containers.core_widget import CoreWidget - class Controller(SignalsMixins, ControllerData): def __init__(self, args, unknownargs): self.setup_controller_data() @@ -24,6 +24,7 @@ class Controller(SignalsMixins, ControllerData): self._setup_styling() self._setup_signals() self._subscribe_to_events() + self._load_widgets() if args.no_plugins == "false": self.plugins.launch_plugins() @@ -51,9 +52,12 @@ class Controller(SignalsMixins, ControllerData): event_system.subscribe("handle_dir_from_ipc", self.handle_dir_from_ipc) event_system.subscribe("tggl_top_main_menubar", self._tggl_top_main_menubar) + def _load_widgets(self): + ScreenshotController() + def load_glade_file(self): self.builder = Gtk.Builder() - self.builder.add_from_file(settings.get_glade_file()) + # self.builder.add_from_file(settings.get_glade_file()) self.builder.expose_object("main_window", self.window) settings.set_builder(self.builder) diff --git a/src/new-src/core/controller_data.py b/src/new-src/core/controller_data.py index 8ac1b71..a444284 100644 --- a/src/new-src/core/controller_data.py +++ b/src/new-src/core/controller_data.py @@ -9,7 +9,6 @@ from plugins.plugins_controller import PluginsController - class ControllerData: ''' ControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' diff --git a/src/new-src/core/screenshot_controller.py b/src/new-src/core/screenshot_controller.py new file mode 100644 index 0000000..baf7a25 --- /dev/null +++ b/src/new-src/core/screenshot_controller.py @@ -0,0 +1,84 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gdk', '3.0') +from gi.repository import Gdk as Gdk +from gi.repository import GLib + +import pyscreenshot as capture + +# Application imports + + + +class ScreenshotController: + def __init__(self): + super(ScreenshotController, self).__init__() + + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() + self._load_widgets() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _subscribe_to_events(self): + event_system.subscribe("grab_entire_screen", self.grab_entire_screen) + event_system.subscribe("grab_active_window", self.grab_active_window) + event_system.subscribe("pass_to_region_handler", self.pass_to_region_handler) + event_system.subscribe("grab_selected_monitor", self.grab_selected_monitor) + + def _load_widgets(self): + ... + + def grab_entire_screen(self): + logger.info("Grabbing Entire Screen...") + window = settings.get_main_window() + + @daemon_threaded + def do_grab(): + im = capture.grab(childprocess = False) + im.save( settings.generate_screenshot_name() ) + GLib.idle_add(window.show) + + window.hide() + do_grab() + + + def grab_active_window(self): + logger.info("Grabbing Active Window...") + + event_system.emit("grab_delay") + screen = Gdk.get_default_root_window().get_screen() + w = screen.get_active_window() + pb = Gdk.pixbuf_get_from_window(w, *w.get_geometry()) + pb.savev(settings.generate_screenshot_name(), "png", (), ()) + + def pass_to_region_handler(self): + logger.info("Grabbing Selected Region Stub...") + # window = settings.get_main_window() + # window.hide() + + def grab_selected_monitor(self): + logger.info("Grabbing Monitor...") + + window = settings.get_main_window() + monitor = event_system.emit_and_await("get_selected_monitor") + x2 = monitor.x + monitor.width + y2 = monitor.y + monitor.height + + @daemon_threaded + def do_bounding_box_grab(x1, y1, x2, y2): + im = capture.grab(bbox = (x1, y1, x2, y2), childprocess = False) + im.save( settings.generate_screenshot_name() ) + GLib.idle_add(window.show) + + event_system.emit("grab_delay") + window.hide() + do_bounding_box_grab(monitor.x, monitor.y, x2, y2) diff --git a/src/new-src/core/widgets/delay_amount.py b/src/new-src/core/widgets/delay_amount.py index 613059a..4ee0ef3 100644 --- a/src/new-src/core/widgets/delay_amount.py +++ b/src/new-src/core/widgets/delay_amount.py @@ -1,4 +1,5 @@ # Python imports +import time # Lib imports import gi @@ -15,6 +16,7 @@ class DelayAmount(Gtk.Box): self._setup_styling() self._setup_signals() + self._subscribe_to_events() self._load_widgets() self.show_all() @@ -28,6 +30,9 @@ class DelayAmount(Gtk.Box): def _setup_signals(self): ... + def _subscribe_to_events(self): + event_system.subscribe("grab_delay", self.grab_delay) + def _load_widgets(self): label = Gtk.Label("Timeout: ") spinner = Gtk.SpinButton() @@ -36,8 +41,15 @@ class DelayAmount(Gtk.Box): spinner.set_numeric(True) spinner.set_snap_to_ticks(True) spinner.set_digits(0) - spinner.set_range(1, 120) + spinner.set_range(0, 120) spinner.set_increments(1, 5) self.add(label) self.add(spinner) + + def grab_delay(self, wait = None): + delay_amount = self.get_children()[1] + if not wait: + wait = delay_amount.get_value_as_int() + + time.sleep(wait) diff --git a/src/new-src/core/widgets/images_list.py b/src/new-src/core/widgets/images_list.py index 7f7471f..5153c52 100644 --- a/src/new-src/core/widgets/images_list.py +++ b/src/new-src/core/widgets/images_list.py @@ -4,6 +4,8 @@ import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk +from gi.repository import Gio +from gi.repository import GLib # Application imports from mixins.tree_nixin import TreeMixin @@ -16,6 +18,7 @@ class ImagesList(TreeMixin, Gtk.ScrolledWindow): self._store = None + self._set_file_watcher() self._setup_styling() self._setup_signals() self._subscribe_to_events() @@ -41,14 +44,31 @@ class ImagesList(TreeMixin, Gtk.ScrolledWindow): self.referesh_directory_list() self.add(grid) + def _set_file_watcher(self): + if settings.is_debug(): + logger.debug(f"Watcher Will Not Be Set...") + return + + images_dir = settings.get_screenshots_dir() + dir_watcher = Gio.File.new_for_path(f"{images_dir}") \ + .monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, Gio.Cancellable()) + + dir_watcher.connect("changed", self._dir_watch_updates) + + def _dir_watch_updates(self, file_monitor, file, other_file = None, eve_type = None, data = None): + if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.DELETED, + Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN, + Gio.FileMonitorEvent.MOVED_OUT]: + + self._store.clear() + self.referesh_directory_list() + @threaded def referesh_directory_list(self): images = settings.get_directory_list() images.sort() - if len(images) != len(self._store): - self._store.clear() - for image in images: - GLib.idle_add(self.add_to_store, (image,)) + for image in images: + GLib.idle_add(self.add_to_store, (image,)) def add_to_store(self, image): self._store.append(image) diff --git a/src/new-src/core/widgets/monitor_list.py b/src/new-src/core/widgets/monitor_list.py index b2e6f31..d8bd29f 100644 --- a/src/new-src/core/widgets/monitor_list.py +++ b/src/new-src/core/widgets/monitor_list.py @@ -14,7 +14,9 @@ class MonitorList(TreeMixin, Gtk.Box): def __init__(self): super(MonitorList, self).__init__() - self._store = None + self.MONITORS: [] = None + self._monitors_view = None + self._store = None self._setup_styling() self._setup_signals() @@ -31,20 +33,29 @@ class MonitorList(TreeMixin, Gtk.Box): ... def _subscribe_to_events(self): - ... + event_system.subscribe("get_selected_monitor", self.get_selected_monitor) def _load_widgets(self): - grid, self._store = self._create_treeview_widget("Monitors") + grid, self._store = self._create_treeview_widget("Monitors") + self._monitors_view = grid.get_children()[0] + self._load_monitor_store() grid.set_hexpand(True) self.add(grid) def _load_monitor_store(self): - MONITORS = settings.get_monitor_data() + self.MONITORS = settings.get_monitor_data() i = 0 - for monitor in MONITORS: + for monitor in self.MONITORS: if i > 0: mon = str(monitor.width) + "x" + str(monitor.height) + "+" + str(monitor.x) + "+" + str(monitor.y) self._store.append([mon]) i += 1 + + def get_selected_monitor(self): + iter = self._monitors_view.get_selection().get_selected()[1] + path = self._store.get_path(iter) + + # Slot 0 is ref monitor. Need to add 1 to get proper slot + return self.MONITORS[int(str(path)) + 1] diff --git a/src/new-src/core/widgets/snapshot_button.py b/src/new-src/core/widgets/snapshot_button.py index 30c68b3..581938e 100644 --- a/src/new-src/core/widgets/snapshot_button.py +++ b/src/new-src/core/widgets/snapshot_button.py @@ -37,9 +37,12 @@ class SnapshotButton(Gtk.Button): self.set_image(image) def _take_snapshot(self, widget = None, eve = None): - type = event_system.emit_and_await("get_screenshot_type").get_label() - print(type) - # NOTE: - # 1. Get type of screenshot - # 2. Grab screenshot - # 3. Emit images list file update + active = event_system.emit_and_await("get_screenshot_type").get_label() + if "Entire Screen" in active: + event_system.emit("grab_entire_screen") + if "Active Window" in active: + event_system.emit("grab_active_window") + if "Select Region" in active: + event_system.emit("pass_to_region_handler") + if "Select Monitor" in active: + event_system.emit("grab_selected_monitor") diff --git a/src/new-src/core/window.py b/src/new-src/core/window.py index d91edbf..0545ed0 100644 --- a/src/new-src/core/window.py +++ b/src/new-src/core/window.py @@ -15,12 +15,11 @@ from gi.repository import GLib from core.controller import Controller + class ControllerStartExceptiom(Exception): ... - - class Window(Gtk.ApplicationWindow): """docstring for Window.""" diff --git a/src/new-src/mixins/tree_nixin.py b/src/new-src/mixins/tree_nixin.py index 9182fa7..b547fa6 100644 --- a/src/new-src/mixins/tree_nixin.py +++ b/src/new-src/mixins/tree_nixin.py @@ -20,7 +20,7 @@ class TreeMixin: grid.set_model(store) selec.set_mode(2) - scroll.set_size_request(145, 96) + scroll.set_size_request(145, 72) column.pack_start(name, True) column.add_attribute(name, "text", 0) diff --git a/src/new-src/utils/settings/settings.py b/src/new-src/utils/settings/settings.py index 2aeba1c..64b16c8 100644 --- a/src/new-src/utils/settings/settings.py +++ b/src/new-src/utils/settings/settings.py @@ -2,6 +2,7 @@ import os import json import inspect +import datetime # Lib imports import gi @@ -208,3 +209,10 @@ class Settings(StartCheckMixin, Singleton): files.append(file) return files + + def generate_screenshot_name(self): + return f"{self._SCREENSHOTS_DIR}/scrshot_{self.get_time()}.png" + + def get_time(self): + now = datetime.datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S")