From 2a93b0e4045a3eaed6cb36009d74ab574162b399 Mon Sep 17 00:00:00 2001 From: Maxim Stewart Date: Tue, 16 Jun 2020 21:19:40 -0500 Subject: [PATCH] Initial commit... --- README.md | 10 + cornea.desktop | 11 + images/pic1.png | Bin 0 -> 23726 bytes requirements.txt | 6 + src/__main__.py | 53 +++ src/resources/Main_Window.glade | 544 ++++++++++++++++++++++++++++ src/resources/cornea.png | Bin 0 -> 5612 bytes src/resources/stylesheet.css | 3 + src/screenshot | 14 + src/signal_classes/DrawingArea.py | 180 +++++++++ src/signal_classes/MainMenuPopup.py | 51 +++ src/signal_classes/MainWindow.py | 153 ++++++++ src/signal_classes/__init__.py | 3 + src/utils/CrossClassSignals.py | 96 +++++ src/utils/Settings.py | 71 ++++ src/utils/__init__.py | 2 + 16 files changed, 1197 insertions(+) create mode 100755 cornea.desktop create mode 100644 images/pic1.png create mode 100644 requirements.txt create mode 100755 src/__main__.py create mode 100644 src/resources/Main_Window.glade create mode 100644 src/resources/cornea.png create mode 100644 src/resources/stylesheet.css create mode 100755 src/screenshot create mode 100644 src/signal_classes/DrawingArea.py create mode 100644 src/signal_classes/MainMenuPopup.py create mode 100644 src/signal_classes/MainWindow.py create mode 100644 src/signal_classes/__init__.py create mode 100644 src/utils/CrossClassSignals.py create mode 100644 src/utils/Settings.py create mode 100644 src/utils/__init__.py diff --git a/README.md b/README.md index 526f8a8..c5ce5bc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # Cornea Cornea is a Python + Gtk application to take screenshots. + +# Notes +* Need python 2+ +* ```sudo apt-get install python3``` + +# Images +![1 Cornera interface. ](images/pic1.png) + +# TODO +* Create OCR feature... diff --git a/cornea.desktop b/cornea.desktop new file mode 100755 index 0000000..515f800 --- /dev/null +++ b/cornea.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=Cornea +GenericName=A python screenshot application. +Comment=Take screenshots of your desktop. +Exec=/screenshot +Icon=/resources/cornea.png +Type=Application +StartupNotify=true +Categories=Utility; +MimeType=text/plain; +Terminal=false diff --git a/images/pic1.png b/images/pic1.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8361de4e81b1ff9db841d44e2530c11db5a24a GIT binary patch literal 23726 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 mN}lto9n)H8ZDgIb=KlZ~a5PgV&h!5O0000 + + + + + False + True + True + False + False + center + + + + + + True + False + vertical + + + True + False + + + True + True + 0 + + + + + + + + + + + + + + True + False + gtk-copy + + + False + popup + mouse + menu + False + north-east + + + + + + True + False + + + True + False + vertical + True + + + Grab Region + True + True + True + grabRegionImage + True + + + + False + True + 0 + + + + + gtk-close + True + True + True + True + True + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + + + True + True + 1 + + + + + + + + + + + + + True + False + gtk-cancel + + + True + False + gtk-edit + + + True + False + gtk-undo + + + 60 + 1 + 10 + + + False + Cornea + center + 500 + 310 + pyCornea.png + center + + + + + + True + False + + + True + False + vertical + + + True + False + + + Entire screen + True + True + False + Take a screenshot of the entire screen. + 5 + True + True + + + + False + True + 0 + + + + + Active window + True + True + False + Take a screenshot of the active window. + 5 + 5 + True + True + entireScrnToggle + + + + False + True + 1 + + + + + Select a region + True + True + False + Select a region to be captured by clicking a point of the screen without releasing the mouse, dragging you mouse to the other corner of the region, and releasing the mouse button. + 5 + 5 + True + True + entireScrnToggle + + + + False + True + 2 + + + + + Select a monitor + True + True + False + Take a screenshot of the selected monitor. + 5 + 5 + True + True + entireScrnToggle + + + + False + True + 3 + + + + + False + True + 0 + + + + + True + False + 5 + 5 + + + True + False + Timeout + right + + + False + True + 0 + + + + + True + True + Delay in seconds before the screenshot is taken. + number + timeoutAdjustment + True + True + + + True + True + 1 + + + + + False + True + 1 + + + + + 312 + 312 + True + False + 0 + none + + + True + False + gtk-missing-image + + + + + False + True + 2 + + + + + True + True + 0 + + + + + True + False + vertical + + + Take Snapshot + True + True + True + picImage + True + + + + False + True + 0 + + + + + True + False + True + monitorStore + False + + + + + + Monitors + + + + 0 + + + + + + + False + True + 1 + + + + + 200 + True + True + 15 + in + + + True + True + fileStore + False + + + + + + + + + Images + True + descending + + + + 0 + + + + + + + + + True + True + 2 + + + + + gtk-close + True + True + True + True + True + + + + False + True + 3 + + + + + False + True + 2 + + + + + + + 320 + 150 + False + delayAmount + + + + True + False + vertical + + + True + False + + + True + True + True + + + True + True + 0 + + + + + Revert + True + True + True + revertImage + True + + + + False + True + 1 + + + + + False + True + 0 + + + + + Rename + True + True + True + renameImage + True + + + + False + True + 1 + + + + + gtk-open + True + True + True + True + True + + + + False + True + 2 + + + + + gtk-delete + True + True + True + True + True + + + + False + True + 3 + + + + + + diff --git a/src/resources/cornea.png b/src/resources/cornea.png new file mode 100644 index 0000000000000000000000000000000000000000..9227703692464d24f2072c0687c6d8305a8b5473 GIT binary patch literal 5612 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/dev/null 2>&1 ; pwd -P )" + cd "${SCRIPTPATH}" + source "../venv/bin/activate" + python . +} +main $@; diff --git a/src/signal_classes/DrawingArea.py b/src/signal_classes/DrawingArea.py new file mode 100644 index 0000000..3696ec4 --- /dev/null +++ b/src/signal_classes/DrawingArea.py @@ -0,0 +1,180 @@ +# Gtk imports +import gi, cairo +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') + +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk +from gi.repository import GLib as glib + + +# Python imports +import threading, html + +import pyscreenshot as capture + +# Application imports + + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + + return wrapper + +class MouseButtons: + LEFT_BUTTON = 1 + RIGHT_BUTTON = 3 + + +class DrawingArea: + def __init__(self, settings, utilsClass): + self.settings = settings + self.utilsClass = utilsClass + self.builder = self.settings.returnBuilder() + + self.mainWindow = self.builder.get_object('Main_Window') + self.regionWindow = self.builder.get_object('Region_Window') + self.regionMenu = self.builder.get_object('regionMenu') + self.messageLabel = self.builder.get_object('messageLabel') + MONITOR = self.settings.getMonitorData() + + self.settings.setWindowData(self.regionWindow) + self.regionWindow.set_default_size(MONITOR[0].width, MONITOR[0].height) + self.regionWindow.set_size_request(MONITOR[0].width, MONITOR[0].height) + self.regionWindow.set_keep_above(True) + + self.DRAW_AREA = self.builder.get_object("selectionArea") + self.DRAW_AREA.add_events(gdk.EventMask.BUTTON_PRESS_MASK) + self.DRAW_AREA.add_events(gdk.EventMask.BUTTON_RELEASE_MASK) + self.DRAW_AREA.add_events(gdk.EventMask.BUTTON1_MOTION_MASK) + self.DRAW_AREA.connect("button-press-event", self.on_button_press) + self.DRAW_AREA.connect("button-release-event", self.on_button_release) + self.DRAW_AREA.connect("motion-notify-event", self.on_mouse_move) + self.DRAW_AREA.connect("draw", self.on_draw) + + area = self.settings.getMonitorData()[0] + self.SCREENSHOTS_DIR = self.settings.returnScreenshotsDir() + self.WIN_REC = [area.x, area.y, area.width, area.height] + self.coords = [[0.0, 0.0], [0.0, 0.0]] # point1 and point2 + self.BORDER_COLOR = [255, 0, 0, 0.84] + self.TRANS_COLOR = [0, 0, 0, 0.0] + self.BG_COLOR = [0, 0, 0, 0.4] + self.success = "#88cc27" + self.warning = "#ffa800" + self.error = "#ff0000" + self.rec = None + self.cr = None + + self.regionWindow.set_default_size(area.width, area.height) + self.regionWindow.set_size_request(area.width, area.height) + self.regionWindow.move(area.x, area.y) + self.regionWindow.set_resizable(False) + self.regionWindow.set_keep_above(True) + + + + def on_button_press(self, w, e): + self.messageLabel.set_markup("") + if e.type == gdk.EventType.BUTTON_PRESS and e.button == MouseButtons.LEFT_BUTTON: + self.coords[0] = [e.x, e.y] + self.regionMenu.hide() + + # This will reset draw area initially. No further use + if self.cr: + self.draw(self.cr, self.WIN_REC, self.BG_COLOR) + self.DRAW_AREA.queue_draw() + if e.type == gdk.EventType.BUTTON_PRESS and e.button == MouseButtons.RIGHT_BUTTON: + self.regionMenu.show() + + # Update second set of coords. + def on_mouse_move(self, w, e): + self.coords[1] = [e.x, e.y] + self.DRAW_AREA.queue_draw() + + @threaded + def on_button_release(self, w, e): + if e.type == gdk.EventType.BUTTON_RELEASE and e.button == MouseButtons.LEFT_BUTTON: + glib.idle_add(self.regionMenu.show) + + + @threaded + def grabRegion(self, widget): + glib.idle_add(self.regionMenu.hide) + glib.idle_add(self.mainWindow.hide) + self.boundingBoxGrab(self.rec[0], self.rec[1], self.rec[2], self.rec[3]) + glib.idle_add(self.regionMenu.show) + glib.idle_add(self.mainWindow.show) + self.utilsClass.refereshDirectoryList() + + @threaded + def returnToMainWindow(self, widget): + glib.idle_add(self.regionWindow.hide) + glib.idle_add(self.regionMenu.hide) + glib.idle_add(self.mainWindow.show) + + + def on_draw(self, wid, cr): + if not self.cr: self.cr = cr + # Reset the screen with transparent view + self.draw(cr, self.WIN_REC, self.BG_COLOR) + + point1 = self.coords[0] + point2 = self.coords[1] + x1 = point1[0] + y1 = point1[1] + x2 = point2[0] + y2 = point2[1] + w = x2 - x1 + h = y2 - y1 + + # Rectangle information for region and screen grab + self.rec = [int(x1), int(y1), int(x2), int(y2)] + # Draw the new selection region + self.selectionDraw(cr, [x1, y1, w, h], self.BORDER_COLOR, self.TRANS_COLOR) + + + def draw(self, cr, x1y1wh, rgba): + cr.set_source_rgba(rgba[0], rgba[1], rgba[2], rgba[3]) + cr.rectangle(x1y1wh[0], x1y1wh[1], x1y1wh[2], x1y1wh[3]) + cr.set_operator(1); + cr.fill() + + def selectionDraw(self, cr, x1y1wh, brdrcol, transclr): + # Clear the region + cr.set_source_rgba(transclr[0], transclr[1], transclr[2], transclr[3]) + cr.rectangle(x1y1wh[0], x1y1wh[1], x1y1wh[2], x1y1wh[3]) + cr.set_operator(0); + cr.fill() + + # Draw a border + cr.set_source_rgba(brdrcol[0], brdrcol[1], brdrcol[2], brdrcol[3]) + cr.rectangle(x1y1wh[0] - 2, x1y1wh[1] - 2, x1y1wh[2] + 4, x1y1wh[3] + 4) + cr.set_operator(1); + cr.stroke() + + # Actual region grab + def boundingBoxGrab(self, x1, y1, x2, y2): + self.utilsClass.sleep(0.4) + try: + temp = 0; + if x2 < x1: + temp = x1 + x1 = x2 + x2 = temp + + if y2 < y1: + temp = y1 + y1 = y2 + y2 = temp + + + self.utilsClass.boundingBoxGrab(x1, y1, x2, y2) + markup = "Grabbed region successfully..." + glib.idle_add(self.messageLabel.set_markup, markup) + except Exception as e: + print(e) + markup = "Oops..." + \ + "\n" + html.escape( str(e) ) + "" + glib.idle_add(self.messageLabel.set_markup, markup) diff --git a/src/signal_classes/MainMenuPopup.py b/src/signal_classes/MainMenuPopup.py new file mode 100644 index 0000000..7b857a1 --- /dev/null +++ b/src/signal_classes/MainMenuPopup.py @@ -0,0 +1,51 @@ +# Gtk imports + +# Python imports +import os, subprocess + +# Application imports + + +class MainMenuPopup: + def __init__(self, settings, utilsClass): + self.settings = settings + self.utilsClass = utilsClass + + self.builder = self.settings.returnBuilder() + self.fileNameEntry = self.builder.get_object("fileNameEntry") + self.SCREENSHOTS_DIR = self.settings.returnScreenshotsDir() + self.backupName = None + + + def renameFile(self, widget, data=None): + newName = self.fileNameEntry.get_text().strip() + oldFilePath = self.SCREENSHOTS_DIR + '/' + self.backupName + newFilePath = self.SCREENSHOTS_DIR + '/' + newName + try: + if os.path.isfile(oldFilePath) and newName: + os.rename(oldFilePath, newFilePath) + self.backupName = newName + self.utilsClass.refereshDirectoryList() + except Exception as e: + print(str(e)) + + def openFile(self, widget, data=None): + filePath = self.SCREENSHOTS_DIR + '/' + self.backupName + subprocess.Popen(['xdg-open', filePath], stdout=subprocess.PIPE) + + def deleteFile(self, widget, data=None): + try: + filePath = self.SCREENSHOTS_DIR + '/' + self.backupName + if os.path.isfile(filePath): + os.remove(filePath) + self.builder.get_object("mainMenu").popdown() + self.utilsClass.refereshDirectoryList() + except Exception as e: + print(str(e)) + + + def resetName(self, widget, data=None): + self.fileNameEntry.set_text(self.backupName) + + def setBackupVar(self, widget): + self.backupName = self.fileNameEntry.get_text() diff --git a/src/signal_classes/MainWindow.py b/src/signal_classes/MainWindow.py new file mode 100644 index 0000000..010258e --- /dev/null +++ b/src/signal_classes/MainWindow.py @@ -0,0 +1,153 @@ +# Gtk imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') + +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk +from gi.repository import GLib as glib + +# Python imports +import threading, subprocess, os +import pyscreenshot as capture + +# Application imports + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + + return wrapper + +class MouseButtons: + LEFT_BUTTON = 1 + RIGHT_BUTTON = 3 + + +class MainWindow: + def __init__(self, settings, utilsClass): + self.settings = settings + self.utilsClass = utilsClass + self.builder = self.settings.returnBuilder() + + self.mainWindow = self.builder.get_object('Main_Window') + self.regionWindow = self.builder.get_object('Region_Window') + self.monitorStore = self.builder.get_object("monitorStore") + self.MONITORS = self.settings.getMonitorData() + + # Not adding the reference monitor + i = 0 + for monitor in self.MONITORS: + if i > 0: + mon = str(monitor.width) + "x" + str(monitor.height) + "+" + str(monitor.x) + "+" + str(monitor.y) + self.monitorStore.append([mon]) + i += 1 + + monitorsView = self.builder.get_object("monitorsView") + monitorsView.set_cursor(1) + + self.SCREENSHOTS_DIR = self.settings.returnScreenshotsDir() + self.utilsClass.refereshDirectoryList() + + + + def take_screenshot(self, widget): + active_radio = self.getActiveRadio() + active = active_radio.get_children()[0].get_text() + + if "Entire screen" in active: + self.getEntireScreen() + self.utilsClass.refereshDirectoryList() + if "Active window" in active: + self.getActiveWindow() + self.utilsClass.refereshDirectoryList() + if "Select a region" in active: + self.regionWindow.show_all() + if "Select a monitor" in active: + self.snapshotMonitor() + self.utilsClass.refereshDirectoryList() + + + def getEntireScreen(self): + self.utilsClass.sleep() + # childprocess=False needed to not crash program + im = capture.grab(childprocess=False) + im.save(self.utilsClass.generateScreenshotName()) + + def getActiveWindow(self): + self.utilsClass.sleep() + + 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(self.utilsClass.generateScreenshotName(), "png", (), ()) + + def snapshotMonitor(self): + monitorsView = self.builder.get_object("monitorsView") + iterator = monitorsView.get_selection().get_selected()[1] + path = self.monitorStore.get_path(iterator) + # Slot 0 is ref monitor. Need to add 1 to get proper slot + monitor = self.MONITORS[int(str(path)) + 1] + + self.utilsClass.sleep() + + x2 = monitor.x + monitor.width + y2 = monitor.y + monitor.height + self.utilsClass.boundingBoxGrab(monitor.x, monitor.y, x2, y2) + + def toggleRadioBttn(self, widget): + monitorsView = self.builder.get_object('monitorsView') + delayAmount = self.builder.get_object('delayAmount') + snapshotBttn = self.builder.get_object('snapshotBttn') + active = self.getActiveRadio().get_children()[0].get_text() + + self.regionWindow.hide() + monitorsView.set_sensitive(False) + delayAmount.set_sensitive(True) + snapshotBttn.set_sensitive(True) + delayAmount.set_value(0) + + if "Active window" in active: + delayAmount.set_value(4) + if "Select a region" in active: + delayAmount.set_sensitive(False) + if "Select a monitor" in active: + monitorsView.set_sensitive(True) + + def setImage(self, user_data): + # We need the refresh state for the files list b/c GtkTreeSelection + # is calling this method b/c caling this too quickly causes issues... + if self.utilsClass.returnRefreshingState() == False: + selected = user_data.get_selected()[1] + if selected: + fileNameEntry = self.builder.get_object("fileNameEntry") + imageView = self.builder.get_object("imageView") + file = self.builder.get_object("fileStore").get_value(selected, 0) + fullPath = self.SCREENSHOTS_DIR + "/" + file + + try: + if os.path.isfile(fullPath): + fileNameEntry.set_text(file) + pixbuf = gtk.Image.new_from_file(fullPath).get_pixbuf() + scaledPixBuf = pixbuf.scale_simple(480, 320, 2) # 2 = BILINEAR and is best by default + imageView.set_from_pixbuf(scaledPixBuf) + except Exception as e: + print(e) + + + + def getActiveRadio(self): + master_radio = self.builder.get_object('entireScrnToggle') + active_radio = next(( + radio for radio in master_radio.get_group() + if radio.get_active() + )) + return active_radio + + def showMainMenu(self, w, e): + if e.type == gdk.EventType.BUTTON_PRESS and e.button == MouseButtons.RIGHT_BUTTON: + self.builder.get_object("mainMenu").popup() + + def close(self, widget): + gtk.main_quit() diff --git a/src/signal_classes/__init__.py b/src/signal_classes/__init__.py new file mode 100644 index 0000000..4c9517c --- /dev/null +++ b/src/signal_classes/__init__.py @@ -0,0 +1,3 @@ +from .MainWindow import MainWindow +from .DrawingArea import DrawingArea +from .MainMenuPopup import MainMenuPopup diff --git a/src/utils/CrossClassSignals.py b/src/utils/CrossClassSignals.py new file mode 100644 index 0000000..7124714 --- /dev/null +++ b/src/utils/CrossClassSignals.py @@ -0,0 +1,96 @@ +# Gtk imports +from gi.repository import GLib as glib + +# Python imports +import os, threading, time, datetime + +import pyscreenshot as capture + +# Application imports + + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + + return wrapper + +class CrossClassSignals: + def __init__(self, settings): + self.settings = settings + self.builder = self.settings.returnBuilder() + self.SCREENSHOTS_DIR = self.settings.returnScreenshotsDir() + self.fileStore = self.builder.get_object("fileStore") + self.refreshingState = False + + + def returnRefreshingState(self): + return self.refreshingState + + def setRefreshingState(self, state): + self.refreshingState = state + + + @threaded + def refereshDirectoryList(self): + self.refreshingState = True + images = self.returnDirectoryList() + images.sort() + if len(images) != len(self.fileStore): + self.fileStore.clear() + for image in images: + glib.idle_add(self.addToStore, (image)) + + # self.fileStore.sort() + self.refreshingState = False + + + @threaded + def addToStore(self, image): + self.fileStore.append([image]) + + def returnDirectoryList(self): + files = [] + + for file in os.listdir(self.SCREENSHOTS_DIR): + if os.path.isfile(os.path.join(self.SCREENSHOTS_DIR, file)): + files.append(file) + + return files + + + def boundingBoxGrab(self, x1, y1, x2, y2): + # childprocess=False needed to not crash program + im = capture.grab(bbox=(x1, y1, x2, y2), childprocess=False) + im.save(self.generateScreenshotName()) + + def generateScreenshotName(self): + return self.SCREENSHOTS_DIR + '/scrshot_' + self.getTime() + '.png' + + def getTime(self): + now = datetime.datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S") + + def sleep(self, wait=None): + delayAmount = self.builder.get_object("delayAmount") + if not wait: + wait = delayAmount.get_value_as_int() + + time.sleep(wait) + + + def getClipboardData(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 setClipboardData(self, data): + proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE) + proc.stdin.write(data) + proc.stdin.close() + retcode = proc.wait() + + def close(self, widget): + gtk.main_quit() diff --git a/src/utils/Settings.py b/src/utils/Settings.py new file mode 100644 index 0000000..c20aefe --- /dev/null +++ b/src/utils/Settings.py @@ -0,0 +1,71 @@ +# Gtk imports +import gi, cairo +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') + +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk + +# Python imports +import os + +# Application imports + + +class Settings: + def __init__(self): + self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/" + self.builder = gtk.Builder() + self.builder.add_from_file(self.SCRIPT_PTH + "../resources/Main_Window.glade") + + # 'Filters' + self.images = ('.png', '.jpg', '.jpeg', '.gif') + HOME_PATH = os.path.expanduser('~') + self.SCREENSHOTS_DIR = HOME_PATH + "/" + ".screenshots" + + if not os.path.isdir(self.SCREENSHOTS_DIR): + os.mkdir(self.SCREENSHOTS_DIR) + + + def createWindow(self): + # Get window and connect signals + window = self.builder.get_object("Main_Window") + window.connect("delete-event", gtk.main_quit) + self.setWindowData(window) + return window + + def setWindowData(self, window): + screen = window.get_screen() + visual = screen.get_rgba_visual() + + if visual != None and screen.is_composited(): + window.set_visual(visual) + + # bind css file + cssProvider = gtk.CssProvider() + cssProvider.load_from_path(self.SCRIPT_PTH + '../resources/stylesheet.css') + screen = gdk.Screen.get_default() + styleContext = gtk.StyleContext() + styleContext.add_provider_for_screen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_USER) + + def getMonitorData(self): + screen = self.builder.get_object("Main_Window").get_screen() + wdth = screen.get_width() + hght = screen.get_height() + mon0 = gdk.Rectangle() + mon0.width = wdth + mon0.height = hght + monitors = [] + + monitors.append(mon0) + for m in range(screen.get_n_monitors()): + monitors.append(screen.get_monitor_geometry(m)) + + return monitors + + + def returnBuilder(self): return self.builder + def returnScreenshotsDir(self): return self.SCREENSHOTS_DIR + + # Filter returns + def returnImagesFilter(self): return self.images diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..6025f81 --- /dev/null +++ b/src/utils/__init__.py @@ -0,0 +1,2 @@ +from .Settings import Settings +from .CrossClassSignals import CrossClassSignals