diff --git a/src/Javascript/amazon-calculate-spending.js b/src/Javascript/amazon-calculate-spending.js
new file mode 100644
index 0000000..1790409
--- /dev/null
+++ b/src/Javascript/amazon-calculate-spending.js
@@ -0,0 +1,15 @@
+// Open the Orders page in Amazon.
+// Run the script for each page you wish to calculate total of.
+
+elms = document.querySelectorAll("#ordersContainer")[0].querySelectorAll(".a-row .a-size-base");
+total = 0;
+
+for (let i = 0; i < elms.length ; i++) {
+ value = elms[i].innerText;
+ if (value.includes("$")) {
+ total += parseInt(value.replace("$", ""), 10);
+ console.log(value);
+ }
+}
+
+console.log(total);
diff --git a/src/Javascript/bulk-delete-youtube-videos.js b/src/Javascript/bulk-delete-youtube-videos.js
new file mode 100644
index 0000000..a18ed05
--- /dev/null
+++ b/src/Javascript/bulk-delete-youtube-videos.js
@@ -0,0 +1,39 @@
+pos = 7 // Position to delete from. Note: 0 is the 1st video of the list; 1 is the 2nd, etc.
+end = 5 // How many videos to delete?
+
+// :: UI Timeouts :: (1000 equals 1 second.)
+// Note: Your computer is a toaster or potato? Can't render UI changes quickly?
+// Bump these up till the proper prompts show, then up the Interval Timer.
+t1 = 800
+t2 = 800
+t3 = 800
+
+// :: Interval Timer :: (1000 equals 1 second.)
+// Note: Slow internet or bumped up the UI Timeouts?
+// If slow internet, incrimint this by 1 second till things delete.
+// If you bumped uo or down the UI Timeouts, add them up and add ~2000.
+wait = 4000
+
+
+i = 1 // Index to keep track of deletions. Don't change!
+interval = setInterval(function () {
+ if (i == end)
+ clearInterval(interval)
+
+ elm = document.getElementsByClassName('style-scope ytcp-video-list-cell-video open-menu-button')[pos];
+
+ elm.click();
+ setTimeout(function () {
+ document.getElementById('text-item-4').click();
+ }, t1);
+
+ setTimeout(function () {
+ document.getElementById('delete-confirm-checkbox').click();
+ }, t2);
+
+ setTimeout(function () {
+ document.getElementById('delete-confirm-button').click();
+ }, t3);
+
+ i += 1
+}, wait);
diff --git a/src/Javascript/google-scripts-api-examples.js b/src/Javascript/google-scripts-api-examples.js
new file mode 100644
index 0000000..241bc2e
--- /dev/null
+++ b/src/Javascript/google-scripts-api-examples.js
@@ -0,0 +1,39 @@
+Reference Material:
+ https://developers.google.com/apps-script
+
+
+
+
+# ---- Functions ---- #
+
+function createSheetsFromRow() {
+ // getActiveSpreadsheet actually returns the whole SpreadSheet object whereas getActiveSheet returns a single "Sheet" or null object.
+ let spreadSheet = SpreadsheetApp.getActiveSpreadsheet(); // The "container" that holds all your Sheet objects
+ let activeSheet = SpreadsheetApp.getActiveSheet(); // The Sheet that is active in your SpreadSheet object
+ let sheetData = activeSheet.getDataRange().getValues(); // Get the active Sheet's data... aka Rows and Columns
+
+ for (var i in sheetData) {
+ if (i == 0) { continue; } // Keep from adding first row as sheet
+ let row = sheetData[i]; // Get row's data
+ let newSheetName = row[2]; // New sheet name is derived from 3rd column (2nd index) which is Agency column
+ let newSheet = spreadSheet.getSheetByName(newSheetName);
+ if (newSheet === null) { // If sheet doesn't exists, we create it
+ newSheet = spreadSheet.insertSheet(newSheetName);
+ }
+ newSheet.appendRow(row);
+ }
+}
+
+function deleteAllSheetsButForFirst() {
+ let spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
+ let sheets = spreadSheet.getSheets();
+
+ for (var i in sheets) {
+ if (i == 0) { continue; } // Keep from deleting first sheet
+ let sheet = sheets[i];
+ spreadSheet.deleteSheet(sheet);
+ }
+}
+
+
+
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.py
new file mode 100755
index 0000000..f6b3baf
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python3
+
+# Gtk imports
+import gi, faulthandler, signal
+gi.require_version('Gtk', '3.0')
+gi.require_version('WebKit2', '4.0')
+
+from gi.repository import Gtk as gtk
+from gi.repository import Gdk as gdk
+from gi.repository import WebKit2 as webkit
+from gi.repository import GLib
+
+# Python imports
+import inspect, faulthandler
+
+# Application imports
+from utils import Settings
+from signal_classes import CrossClassSignals, WebviewSignals
+
+
+class Main:
+ def __init__(self):
+ GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit)
+ faulthandler.enable() # For better debug info
+ webkit.WebView() # Need one initialized for webview to work from glade file
+
+ builder = gtk.Builder()
+ settings = Settings()
+ settings.attachBuilder(builder)
+
+ # Gets the methods from the classes and sets to handler.
+ # Then, builder connects to any signals it needs.
+ classes = [CrossClassSignals(settings),
+ WebviewSignals(settings)]
+
+ handlers = {}
+ for c in classes:
+ methods = inspect.getmembers(c, predicate=inspect.ismethod)
+ handlers.update(methods)
+
+ builder.connect_signals(handlers)
+ window = settings.createWindow()
+ window.show_all()
+
+
+if __name__ == "__main__":
+ try:
+ main = Main()
+ gtk.main()
+ except Exception as e:
+ print(e)
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.sh b/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.sh
new file mode 100755
index 0000000..f102198
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/ChronosBrowser.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# set -o xtrace ## To debug scripts
+# set -o errexit ## To exit on error
+# set -o errunset ## To exit if a variable is referenced but not set
+
+
+function main() {
+ # GTK_DEBUG=interactive python3 ./ChronosBrowser.py
+ python3 ./ChronosBrowser.py
+}
+main $@;
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/WebviewFactory.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/WebviewFactory.py
new file mode 100644
index 0000000..2ee1dcb
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/WebviewFactory.py
@@ -0,0 +1,39 @@
+# Gtk imports
+import gi
+gi.require_version('WebKit2', '4.0')
+
+from gi.repository import WebKit2 as webkit
+
+
+# Python imports
+
+# Application imports
+
+
+class WebviewFactory:
+ def __init__(self):
+ self.index = -1
+ self.view_collection = []
+
+ def createWebview(self):
+ view = webkit.WebView()
+ self.view_collection.append(view)
+ self.index += 1
+ return view
+
+ def deleteWebview(self, index):
+ if (len(self.view_collection) - 1) > 0:
+ self.view_collection.pop(index)
+ self.index -= 1
+ return 0
+ else:
+ return 1
+
+ def get_index(self, index):
+ val = index
+ if val >= 0 and val < len(self.view_collection):
+ self.index = index
+ return self.view_collection[self.index]
+
+ def returnNotebookSize(self,):
+ return len(self.view_collection)
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/__init__.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/__init__.py
new file mode 100644
index 0000000..6b58560
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/factory/__init__.py
@@ -0,0 +1 @@
+from factory.WebviewFactory import WebviewFactory
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/requirements.txt b/src/Python/Scripts/GTK/chronos-webkit2-browser/requirements.txt
new file mode 100644
index 0000000..66c1b01
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/requirements.txt
@@ -0,0 +1 @@
+sudo apt-get -y install python3 pygobject3-devel webkitgtk3-devel ubuntu-restricted-extras gstreamer1.0-gtk3
\ No newline at end of file
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/ChronosBrowser.glade b/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/ChronosBrowser.glade
new file mode 100644
index 0000000..4b7e184
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/ChronosBrowser.glade
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/stylesheet.css b/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/stylesheet.css
new file mode 100644
index 0000000..fb2a684
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/resources/stylesheet.css
@@ -0,0 +1,3 @@
+window {
+
+}
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/CrossClassSignals.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/CrossClassSignals.py
new file mode 100644
index 0000000..08614af
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/CrossClassSignals.py
@@ -0,0 +1,15 @@
+# Gtk imports
+
+# Python imports
+
+# Application imports
+
+
+class CrossClassSignals:
+ def __init__(self, settings):
+ self.settings = settings
+ self.builder = self.settings.returnBuilder()
+
+
+ def closePopup(self, widget, data=None):
+ widget.hide()
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/WebviewSignals.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/WebviewSignals.py
new file mode 100644
index 0000000..9cbce1b
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/WebviewSignals.py
@@ -0,0 +1,98 @@
+# Gtk imports
+import gi
+gi.require_version('Gtk', '3.0')
+
+from gi.repository import Gtk as gtk
+
+# Python imports
+
+# Application imports
+from factory import WebviewFactory
+
+
+class WebviewSignals:
+ def __init__(self, settings):
+ self.webviewFactory = WebviewFactory()
+ self.settings = settings
+ builder = settings.returnBuilder()
+
+ self.home_page = settings.returnWebHome()
+ self.webview_search = builder.get_object("webview_search")
+ self.notebook = builder.get_object("notebook")
+ self.page = None
+ self.index = 0
+ self.labelLen = settings.returnLabelLen()
+
+ self.addTab()
+ self.page = self.notebook.get_nth_page(0)
+
+
+ def addTab(self, widget=None, uri=None):
+ self.current_webview = self.createWebview()
+ self.addToNotebook(self.current_webview, uri)
+
+ def delTab(self, widget):
+ state = self.webviewFactory.deleteWebview(self.index)
+ if state == 0:
+ self.notebook.remove_page(self.index)
+
+ def selecte_view(self, widget, page, index):
+ self.current_webview = self.webviewFactory.get_index(index)
+ self.webview_search.set_text(self.current_webview.get_uri())
+ self.page = page
+ self.index = index
+
+ def createWebview(self):
+ webview = self.webviewFactory.createWebview()
+ webview.connect("create", self.webviewCreateSignal)
+ self.set_webview_settings(webview)
+ webview.load_uri(self.home_page)
+ webview.connect("load-changed", self.setUrlBar)
+ return webview
+
+ def runSearchWebview(self, widget, data=None):
+ query = widget.get_text().strip()
+ if data.keyval == 65293: # If enter key pressed
+ if "http://" in query or "https://" in query or "file://" in query:
+ self.current_webview.load_uri(query)
+ else:
+ query = '+'.join(query.split())
+ query = "http://www.google.com/search?q=" + query
+ self.current_webview.load_uri(query)
+
+ self.notebook.get_tab_label(self.page).set_text(query)
+
+ def refreshPage(self, widget, data=None):
+ self.current_webview.load_uri(self.current_webview.get_uri())
+
+ def loadHome(self, widget):
+ self.current_webview.load_uri(self.home_page)
+
+ def setUrlBar(self, widget, data=None):
+ uri = widget.get_uri()
+ self.webview_search.set_text(uri)
+ label = uri[0: self.labelLen] + "..."
+ self.notebook.get_tab_label(self.page).set_text(label)
+
+ def webviewCreateSignal(self, widget, eve):
+ uri = eve.get_request()
+ type = eve.get_navigation_type()
+ isRedirect = eve.is_redirect()
+
+ if isRedirect == False and type == 5: # Open in new tab
+ self.addTab(None, uri.get_uri())
+
+
+ def addToNotebook(self, view, uri=None):
+ webview_box = gtk.Box()
+ webview_box.pack_start(view, expand = True, fill = True, padding = 0)
+ webview_box.show_all()
+
+ if uri:
+ self.notebook.append_page(webview_box, gtk.Label(uri))
+ view.load_uri(uri)
+ else:
+ self.notebook.append_page(webview_box, gtk.Label(view.get_uri()))
+
+ def set_webview_settings(self, view):
+ self.settings.setDefaultWebviewSettings(view, view.get_settings())
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/__init__.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/__init__.py
new file mode 100644
index 0000000..e82d0ea
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/signal_classes/__init__.py
@@ -0,0 +1,2 @@
+from signal_classes.CrossClassSignals import CrossClassSignals
+from signal_classes.WebviewSignals import WebviewSignals
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/Settings.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/Settings.py
new file mode 100644
index 0000000..3fc8229
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/Settings.py
@@ -0,0 +1,125 @@
+# 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.builder = None
+
+ self.THUMB_GENERATOR = "ffmpegthumbnailer"
+ self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
+ self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
+ self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
+
+ self.webHome = 'http://webfm.com/'
+ self.labelLength = 25 - 3
+ self.vidsExtensionList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
+ self.imagesExtensionList = ('.png', '.jpg', '.jpeg', '.gif', '.ico', '.tga')
+
+
+ def attachBuilder(self, builder):
+ self.builder = builder
+ self.builder.add_from_file("resources/ChronosBrowser.glade")
+
+ def createWindow(self):
+ # Get window and connect signals
+ window = self.builder.get_object("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('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):
+ monitors = []
+ for m in range(screen.get_n_monitors()):
+ monitors.append(screen.get_monitor_geometry(m))
+
+ for monitor in monitors:
+ print(str(monitor.width) + "x" + str(monitor.height) + "+" + str(monitor.x) + "+" + str(monitor.y))
+
+ return monitors
+
+
+ def returnBuilder(self): return self.builder
+ def returnWebHome(self): return self.webHome
+ def returnVidsExtensionList(self): return self.vidsExtensionList
+ def returnImagesExtensionList(self): return self.imagesExtensionList
+ def returnLabelLen(self): return self.labelLength
+
+ def setDefaultWebviewSettings(self, widget, settings=None):
+ # Usability
+ settings.set_property('enable-fullscreen', True)
+ settings.set_property('print-backgrounds', True)
+ settings.set_property('enable-frame-flattening', False)
+ settings.set_property('enable-plugins', True)
+ settings.set_property('enable-java', False)
+ settings.set_property('enable-resizable-text-areas', True)
+ settings.set_property('zoom-text-only', False)
+ settings.set_property('enable-smooth-scrolling', True)
+ settings.set_property('enable-back-forward-navigation-gestures', False)
+ settings.set_property('media-playback-requires-user-gesture', False)
+ settings.set_property('enable-tabs-to-links', True)
+ settings.set_property('enable-caret-browsing', False)
+
+ # Security
+ settings.set_property('user-agent','Mozilla/5.0 (X11; Generic; Linux x86-64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Safari/605.1.15')
+ settings.set_property('enable-private-browsing', False)
+ settings.set_property('enable-xss-auditor', True)
+ settings.set_property('enable-hyperlink-auditing', False)
+ settings.set_property('enable-site-specific-quirks', True)
+ settings.set_property('enable-offline-web-application-cache', True)
+ settings.set_property('enable-page-cache', True)
+ settings.set_property('allow-modal-dialogs', True)
+ settings.set_property('enable-html5-local-storage', True)
+ settings.set_property('enable-html5-database', True)
+ settings.set_property('allow-file-access-from-file-urls', True)
+ settings.set_property('allow-universal-access-from-file-urls', False)
+ settings.set_property('enable-dns-prefetching', False)
+
+ # Media stuff
+ settings.set_hardware_acceleration_policy(0)
+ # settings.set_property('hardware-acceleration-policy', 'on-demand')
+ settings.set_property('enable-webgl', True)
+ settings.set_property('enable-webaudio', True)
+ settings.set_property('enable-accelerated-2d-canvas', True)
+ settings.set_property('auto-load-images', True)
+ settings.set_property('enable-media-capabilities', True)
+ settings.set_property('enable-media-stream', True)
+ settings.set_property('enable-mediasource', True)
+ settings.set_property('enable-encrypted-media', True)
+ settings.set_property('media-playback-allows-inline', True)
+
+ # JS
+ settings.set_property('enable-javascript', True)
+ settings.set_property('enable-javascript-markup', True)
+ settings.set_property('javascript-can-access-clipboard', False)
+ settings.set_property('javascript-can-open-windows-automatically', False)
+
+ # Debugging
+ settings.set_property('enable-developer-extras', False)
+ settings.set_property('enable-write-console-messages-to-stdout', False)
+ settings.set_property('draw-compositing-indicators', False)
+ settings.set_property('enable-mock-capture-devices', False)
+ settings.set_property('enable-spatial-navigation', False)
diff --git a/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/__init__.py b/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/__init__.py
new file mode 100644
index 0000000..27b4e23
--- /dev/null
+++ b/src/Python/Scripts/GTK/chronos-webkit2-browser/utils/__init__.py
@@ -0,0 +1 @@
+from utils.Settings import Settings
diff --git a/src/Python/Scripts/GTK/dark-overlay/pyDarkness.desktop b/src/Python/Scripts/GTK/dark-overlay/pyDarkness.desktop
new file mode 100755
index 0000000..3853b35
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/pyDarkness.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=pyDarkness
+GenericName=Darken a region or add highlighting over an area.
+Comment=Darken a region or add highlighting over an area.
+Exec=/home/abaddon/Portable_Apps/local_bin/DarkOverlay/src/darkness
+Icon=/home/abaddon/Portable_Apps/local_bin/DarkOverlay/src/resources/darkness.png
+Type=Application
+StartupNotify=true
+Categories=Utility;
+MimeType=text/plain;
+Terminal=false
diff --git a/src/Python/Scripts/GTK/dark-overlay/requirements.txt b/src/Python/Scripts/GTK/dark-overlay/requirements.txt
new file mode 100644
index 0000000..e89fc2a
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/requirements.txt
@@ -0,0 +1,6 @@
+EasyProcess==0.2.7
+Pillow==6.1.0
+pycairo==1.18.1
+PyGObject==3.34.0
+pyscreenshot==0.5.1
+setproctitle==1.1.10
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/__init__.py b/src/Python/Scripts/GTK/dark-overlay/src/__init__.py
new file mode 100644
index 0000000..45e0c34
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/__init__.py
@@ -0,0 +1,29 @@
+# Python imports
+import inspect
+
+
+# Gtk imports
+
+
+# Application imports
+from utils import Settings
+from signal_classes import CrossClassSignals
+
+
+class Main:
+ def __init__(self, args):
+ settings = Settings()
+ builder = settings.returnBuilder()
+
+ # Gets the methods from the classes and sets to handler.
+ # Then, builder connects to any signals it needs.
+ classes = [CrossClassSignals(settings)]
+
+ handlers = {}
+ for c in classes:
+ methods = inspect.getmembers(c, predicate=inspect.ismethod)
+ handlers.update(methods)
+
+ builder.connect_signals(handlers)
+ window = settings.createWindow()
+ window.show()
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/__main__.py b/src/Python/Scripts/GTK/dark-overlay/src/__main__.py
new file mode 100644
index 0000000..de20660
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/__main__.py
@@ -0,0 +1,32 @@
+#!/usr/bin/python3
+
+
+# Python imports
+import argparse
+from setproctitle import setproctitle
+
+# Gtk imports
+import gi, faulthandler, signal
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk as gtk
+from gi.repository import GLib
+
+# Application imports
+from __init__ import Main
+
+
+if __name__ == "__main__":
+ try:
+ setproctitle('DarkOverlay')
+ GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit)
+ faulthandler.enable() # For better debug info
+ parser = argparse.ArgumentParser()
+ # Add long and short arguments
+ parser.add_argument("--file", "-f", default="firefox", help="JUST SOME FILE ARG.")
+
+ # Read arguments (If any...)
+ args = parser.parse_args()
+ main = Main(args)
+ gtk.main()
+ except Exception as e:
+ print( repr(e) )
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/darkness b/src/Python/Scripts/GTK/dark-overlay/src/darkness
new file mode 100755
index 0000000..b8f0580
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/darkness
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# set -o xtrace ## To debug scripts
+# set -o errexit ## To exit on error
+# set -o errunset ## To exit if a variable is referenced but not set
+
+
+function main() {
+ SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+ source "/home/abaddon/Portable_Apps/py-venvs/pycornia-venv/bin/activate"
+ python "${SCRIPTPATH}"
+}
+main $@;
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/resources/Main_Window.glade b/src/Python/Scripts/GTK/dark-overlay/src/resources/Main_Window.glade
new file mode 100644
index 0000000..ae68179
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/resources/Main_Window.glade
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.01
+ 1
+ 0.75
+ 0.01
+ 10
+
+
+
+
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/resources/darkness.png b/src/Python/Scripts/GTK/dark-overlay/src/resources/darkness.png
new file mode 100644
index 0000000..9f8f2cc
Binary files /dev/null and b/src/Python/Scripts/GTK/dark-overlay/src/resources/darkness.png differ
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/resources/stylesheet.css b/src/Python/Scripts/GTK/dark-overlay/src/resources/stylesheet.css
new file mode 100644
index 0000000..5ad1098
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/resources/stylesheet.css
@@ -0,0 +1,3 @@
+.regionWindow {
+ background-color: rgba(0, 0, 0, 0.0);
+}
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/CrossClassSignals.py b/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/CrossClassSignals.py
new file mode 100644
index 0000000..2802ae5
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/CrossClassSignals.py
@@ -0,0 +1,187 @@
+# Python imports
+import threading, subprocess, os, cairo
+
+
+# Gtk imports
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk as gtk
+from gi.repository import Gdk as gdk
+
+
+# Application imports
+
+
+def threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs).start()
+ return wrapper
+
+
+class MouseButton:
+ LEFT_BUTTON = 1
+ MIDDLE_BUTTON = 2
+ RIGHT_BUTTON = 3
+
+class StateController:
+ isDragging = False
+ isCtrlDown = False
+
+
+class CrossClassSignals:
+ def __init__(self, settings):
+ self.settings = settings
+ self.builder = self.settings.returnBuilder()
+
+ self.window = self.builder.get_object("Main_Window")
+ self.drawArea = self.builder.get_object("drawArea")
+ self.brushColorProp = self.builder.get_object("brushColorProp")
+ self.wh = self.builder.get_object("wh")
+ self.xy = self.builder.get_object("xy")
+
+ self.opacityVal = 0.75
+ self.states = StateController()
+ self.area = None
+ self.states.isCtrlDown = False
+ self.states.isMouseHeld = False
+ self.doDrawBackground = True
+ self.surface = None
+ self.brush = None
+ self.aw = None # Draw area width
+ self.ah = None # Draw area height
+ rgba = self.brushColorProp.get_rgba()
+ self.brushColorVal = [rgba.red, rgba.green, rgba.blue, self.opacityVal]
+ self.startCoords = [0.0, 0.0]
+ self.w1 = 0.0
+ self.h1 = 0.0
+
+ self.window.set_keep_above(True)
+
+
+
+
+ def onConfigure(self, area, eve, data = None):
+ self.area = area
+ aw = area.get_allocated_width()
+ ah = area.get_allocated_height()
+ self.aw = aw
+ self.ah = ah
+ self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, aw, ah)
+ self.brush = cairo.Context(self.surface)
+
+ self.drawBackground(self.brush, aw, ah)
+ return False
+
+
+ def onDraw(self, area, brush):
+ if self.surface is not None:
+ brush.set_source_surface(self.surface, 0.0, 0.0)
+ brush.paint()
+ else:
+ print("No surface info...")
+
+ return False
+
+
+ # Draw background white
+ def drawBackground(self, brush, aw, ah):
+ rgba = self.brushColorVal
+ brush.rectangle(0, 0, aw, ah) # x, y, width, height
+ brush.set_source_rgba(rgba[0], rgba[1], rgba[2], rgba[3]) # x, y, width, height
+
+ if not self.doDrawBackground: # If transparent or white
+ self.brush.set_operator(0);
+
+ brush.fill()
+ self.brush.set_operator(1); # reset the brush after filling bg...
+
+
+ def onColorSet(self, widget):
+ rgba = widget.get_rgba()
+ self.brushColorVal = [rgba.red, rgba.green, rgba.blue, self.opacityVal]
+ self.drawArea.queue_draw()
+ self.drawArea.emit("configure_event", gdk.Event())
+
+
+ def onOpacityChange(self, widget):
+ self.opacityVal = widget.get_value()
+ self.brushColorVal[3] = self.opacityVal
+ self.drawArea.queue_draw()
+ self.drawArea.emit("configure_event", gdk.Event())
+
+
+ def popupMenu(self, widget, eve):
+ self.states.isMouseHeld = False
+ if eve.type == gdk.EventType.BUTTON_RELEASE and eve.button == MouseButton.RIGHT_BUTTON:
+ self.builder.get_object("rClickMenu").popup()
+
+
+ def getStartCoords(self, widget, eve):
+ if eve.type == gdk.EventType.BUTTON_PRESS and eve.button == MouseButton.LEFT_BUTTON:
+ self.startCoords = [eve.x, eve.y] # Used for delta calculations
+ self.w1 = self.window.get_size()[0] # Ref window width
+ self.h1 = self.window.get_size()[1] # Ref window height
+ self.states.isMouseHeld = True # State check for when updating width 'n height
+
+
+ def keyActionToggle(self, widget, eve):
+ key_id = gdk.keyval_name(eve.keyval).upper()
+ if key_id in ["CONTROL_R", "CONTROL_L"]:
+ self.states.isCtrlDown = True
+
+ def endKeyActionToggle(self, widget, eve):
+ key_id = gdk.keyval_name(eve.keyval).upper()
+ if key_id in ["CONTROL_R", "CONTROL_L"]:
+ self.states.isCtrlDown = False
+
+
+ def onMotion(self, widget, eve):
+ if self.states.isMouseHeld:
+ if self.states.isCtrlDown is False:
+ px1 = self.window.get_position()[0] # Ref window x
+ py1 = self.window.get_position()[1] # Ref window y
+
+ # Getting deltas of movement inner to draw event box
+ x1 = self.startCoords[0]
+ y1 = self.startCoords[1]
+ x2 = eve.x
+ y2 = eve.y
+ px = 0
+ py = 0
+
+ # Calculate that to actual posion change
+ if x2 > x1: # Is growing
+ px = px1 + (x2 - x1)
+ else: # Is shrinking
+ px = px1 - (x1 - x2)
+
+ if y2 > y1: # Is growing
+ py = py1 + (y2 - y1)
+ else: # Is shrinking
+ py = py1 - (y1 - y2)
+
+ self.window.move(px, py)
+
+ if self.states.isCtrlDown:
+ x1 = self.startCoords[0]
+ y1 = self.startCoords[1]
+ x2 = eve.x
+ y2 = eve.y
+ w = 0
+ h = 0
+
+ if x2 > x1: # Is growing
+ w = self.w1 + (x2 - x1)
+ else: # Is shrinking
+ w = self.w1 - (x1 - x2)
+
+ if y2 > y1: # Is growing
+ h = self.h1 + (y2 - y1)
+ else: # Is shrinking
+ h = self.h1 - (y1 - y2)
+
+ self.window.resize(w, h)
+
+
+ def close_app(self, widget):
+ gtk.main_quit()
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/__init__.py b/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/__init__.py
new file mode 100644
index 0000000..2c626b0
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/signal_classes/__init__.py
@@ -0,0 +1 @@
+from .CrossClassSignals import CrossClassSignals
diff --git a/src/Python/Scripts/GTK/dark-overlay/src/utils/Settings.py b/src/Python/Scripts/GTK/dark-overlay/src/utils/Settings.py
new file mode 100644
index 0000000..c20aefe
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/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/Python/Scripts/GTK/dark-overlay/src/utils/__init__.py b/src/Python/Scripts/GTK/dark-overlay/src/utils/__init__.py
new file mode 100644
index 0000000..e2cf696
--- /dev/null
+++ b/src/Python/Scripts/GTK/dark-overlay/src/utils/__init__.py
@@ -0,0 +1 @@
+from .Settings import Settings
diff --git a/src/Python/Scripts/GTK/edit-path/__main__.py b/src/Python/Scripts/GTK/edit-path/__main__.py
new file mode 100755
index 0000000..7085258
--- /dev/null
+++ b/src/Python/Scripts/GTK/edit-path/__main__.py
@@ -0,0 +1,151 @@
+#!/usr/bin/python3
+
+# GTK Imports
+import gi, faulthandler, signal
+gi.require_version('Gtk', '3.0')
+
+from gi.repository import Gtk as gtk
+from gi.repository import GLib
+
+
+# Python Imports
+import os, threading, time
+
+from setproctitle import setproctitle
+
+
+def threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs).start()
+
+ return wrapper
+
+
+
+class Main:
+ def __init__(self):
+ setproctitle('PATH Edit Tool')
+ GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit)
+ faulthandler.enable() # For better debug info
+
+ self.HOME = os.path.expanduser('~')
+ PREFERED_BASH_PATH = self.HOME + "/" + ".bash_paths"
+ SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/"
+ GLADE_FILE = "main.glade"
+
+ self.builder = gtk.Builder()
+ self.builder.add_from_file(SCRIPT_PTH + GLADE_FILE)
+ self.builder.connect_signals(self)
+
+ self.pathTreeView = self.builder.get_object("pathTreeView")
+ self.messageWidget = self.builder.get_object("messageWidget")
+ self.messageLabel = self.builder.get_object("messageLabel")
+
+ self.pathListStore = gtk.ListStore(str)
+ self.success = "#88cc27"
+ self.warning = "#ffa800"
+ self.error = "#ff0000"
+ self.selected = None
+ self.bashrcPath = ""
+
+ if os.path.isfile(PREFERED_BASH_PATH):
+ self.bashrcPath = PREFERED_BASH_PATH
+ else:
+ self.bashrcPath = self.HOME + "/" + ".bashrc"
+
+ self.setupTreeview()
+ self.loadPaths()
+
+ window = self.builder.get_object("Main_Window")
+ window.connect("delete-event", gtk.main_quit)
+ window.show()
+
+
+
+ def addEntry(self, widget):
+ toAddPathTxt = self.builder.get_object("toAddPathEntry").get_text().strip()
+
+ if os.path.isdir(toAddPathTxt):
+ self.pathListStore.append([toAddPathTxt])
+ else:
+ self.displayMessage(self.warning, "Not a directory!")
+
+ def deleteEntry(self, widget):
+ self.pathListStore.remove(self.selected)
+
+ def saveToBashrc(self, widget):
+ try:
+ paths = list()
+ iter = self.pathListStore.get_iter_first()
+ while iter != None:
+ pth = self.pathListStore.get_value(iter, 0)
+ pth = pth.replace(self.HOME, "$HOME")
+ paths.append(pth)
+ # paths.append(self.pathListStore.get_value(iter, 0))
+ iter = self.pathListStore.iter_next(iter)
+
+
+ toExport = "export PATH=\"" + ':'.join(paths) + "\"\n\n"
+ file = open(self.bashrcPath, mode='r')
+ for line in file:
+ if "export PATH=" in line:
+ continue
+ else:
+ toExport += line
+
+ file.close()
+ file = open(self.bashrcPath, mode='w')
+ file.write(toExport)
+ file.close()
+ self.displayMessage(self.success, "Successfully saved file!")
+ except Exception as e:
+ self.displayMessage(self.error, "Opening/Writing to file failed!")
+ print("Opening/Writing to file failed with the following:\n\n")
+ print(e)
+
+
+ def setSelected(self, user_data):
+ selected = user_data.get_selected()[1]
+ if selected:
+ self.selected = selected
+
+ def loadPaths(self):
+ pathsStr = os.getenv("PATH")
+
+ # If path exists in bashrc replace default selection...
+ file = open(self.bashrcPath, mode='r')
+ for line in file:
+ if "export PATH=" in line:
+ part = line.replace("export PATH=", "")
+ cleaned = part.replace("\"", "")
+ pathsStr = cleaned.strip()
+
+ # Split string into list/tuple and add parts to store
+ paths = pathsStr.split(":")
+ for path in paths:
+ self.pathListStore.append([path])
+
+
+ def setupTreeview(self):
+ renderer = gtk.CellRendererText()
+ pathColumn = gtk.TreeViewColumn(title="Paths", cell_renderer=renderer, text=0)
+ self.pathTreeView.append_column(pathColumn)
+ self.pathTreeView.set_model(self.pathListStore)
+
+
+ def displayMessage(self, type, text):
+ markup = "" + text + ""
+ self.messageLabel.set_markup(markup)
+ self.messageWidget.popup()
+ self.hideMessageTimed()
+
+ @threaded
+ def hideMessageTimed(self):
+ time.sleep(3)
+ GLib.idle_add(self.messageWidget.popdown)
+
+
+
+if __name__ == '__main__':
+ main = Main()
+ gtk.main()
diff --git a/src/Python/Scripts/GTK/edit-path/main.glade b/src/Python/Scripts/GTK/edit-path/main.glade
new file mode 100644
index 0000000..9853404
--- /dev/null
+++ b/src/Python/Scripts/GTK/edit-path/main.glade
@@ -0,0 +1,162 @@
+
+
+
+
+
+ True
+ False
+ gtk-delete
+
+
+ True
+ False
+ gtk-add
+
+
+ False
+ Edit PATH App
+ center
+ 480
+ 560
+ applications-accessories
+ center
+
+
+
+
+
+ True
+ False
+ vertical
+
+
+ True
+ False
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ True
+ in
+
+
+ True
+ False
+
+
+ True
+ True
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ 1
+
+
+
+
+ True
+ False
+
+
+ True
+ True
+ Path...
+
+
+ True
+ True
+ 0
+
+
+
+
+ True
+ True
+ True
+ Add path...
+ plusImage
+ True
+
+
+
+ False
+ True
+ 1
+
+
+
+
+ True
+ True
+ True
+ Delete...
+ delImage
+ True
+
+
+
+ False
+ True
+ 2
+
+
+
+
+ False
+ True
+ 2
+
+
+
+
+ gtk-save
+ True
+ True
+ True
+ Save...
+ True
+ True
+
+
+
+ False
+ True
+ 3
+
+
+
+
+
+
+ 320
+ False
+ separator1
+ bottom
+
+
+ True
+ False
+ center
+
+
+
+
+
+
+
diff --git a/src/Python/Scripts/bulk-rename/__init__.py b/src/Python/Scripts/bulk-rename/__init__.py
new file mode 100644
index 0000000..c7dcd65
--- /dev/null
+++ b/src/Python/Scripts/bulk-rename/__init__.py
@@ -0,0 +1,53 @@
+# Python Imports
+import os
+import sys
+
+# Lib Imports
+import typer
+
+
+# Application Imports
+
+
+app = typer.Typer()
+
+
+@app.command()
+def makeTitleCase(file: str):
+ if os.path.isdir(file) :
+ for f in os.listdir(file):
+ os.rename(f, f.title())
+ else:
+ os.rename(file, file.title())
+
+
+@app.command()
+def removeFromName(fsub: str, file: str):
+ if os.path.isdir(file) :
+ for f in os.listdir(file):
+ os.rename(f, f.replace(fsub, ''))
+ else:
+ os.rename(file, file.replace(fsub, ''))
+
+@app.command()
+def removeFromToName(fsub: str, tsub: str, file: str):
+ if os.path.isdir(file) :
+ for f in os.listdir(file):
+ startIndex = f.index(fsub) + 1
+ endIndex = f.index(tsub)
+ toRemove = f[startIndex:endIndex]
+ os.rename(f, f.replace(toRemove, ''))
+ else:
+ startIndex = file.index(fsub) + 1
+ endIndex = file.index(tsub)
+ toRemove = file[startIndex:endIndex]
+ os.rename(file, file.replace(toRemove, ''))
+
+
+@app.command()
+def replaceInName(fsub: str, tsub: str, file: str):
+ if os.path.isdir(file) :
+ for f in os.listdir(file):
+ os.rename(f, f.replace(fsub, tsub))
+ else:
+ os.rename(file, file.replace(fsub, tsub))
diff --git a/src/Python/Scripts/bulk-rename/__main__.py b/src/Python/Scripts/bulk-rename/__main__.py
new file mode 100644
index 0000000..9919b99
--- /dev/null
+++ b/src/Python/Scripts/bulk-rename/__main__.py
@@ -0,0 +1,7 @@
+#!/usr/sbin/python
+
+from __init__ import app
+
+
+if __name__ == "__main__":
+ app()
diff --git a/src/Python/Scripts/smart-device-manager.py b/src/Python/Scripts/smart-device-manager.py
new file mode 100644
index 0000000..30b52ca
--- /dev/null
+++ b/src/Python/Scripts/smart-device-manager.py
@@ -0,0 +1,73 @@
+# Python imports
+import json
+import asyncio
+import time
+
+# Lib imports
+from kasa import Discover
+
+# Application imports
+
+
+class SmartDeviceManager:
+ def __init__(self):
+ self.BASE_IP = "192.168.0."
+ self.IPs = ["12", "13", "14", "15", "16", "17"]
+ self.devices = self.retrieve_devices()
+
+
+ def retrieve_devices(self):
+ devices = []
+ for ip in self.IPs:
+ device = self.get_device(self.BASE_IP + ip)
+ if device:
+ print("Device: {} is available...".format(device.alias))
+ print("{}".format(device.hw_info))
+ devices.append(device)
+
+ return devices
+
+ def set_device_on(self, device):
+ asyncio.run(device.turn_on())
+
+ def set_device_off(self, device):
+ asyncio.run(device.turn_off())
+
+ def set_led_on(self, device):
+ asyncio.run(device.set_led(True))
+
+ def set_led_off(self, device):
+ asyncio.run(device.set_led(False))
+
+ def set_device_alias(self, device, alias):
+ asyncio.run(device.set_alias(alias))
+
+ def update_info(self, device):
+ try:
+ asyncio.run(device.update())
+ except Exception as e:
+ pass
+
+ def get_device(self, addr):
+ try:
+ device = asyncio.run( Discover.discover_single(addr) )
+ self.update_info(device)
+ return device
+ except Exception as e:
+ print(repr(e))
+ return None
+
+ def pulsate(self, device, rate = 1):
+ state = "on"
+ while True:
+ if state == "on":
+ state = "off"
+ self.set_device_on(device)
+ else:
+ state = "on"
+ self.set_device_off(device)
+
+ time.sleep(rate)
+
+if __name__ == '__main__':
+ SmartDeviceManager()
diff --git a/src/Python/Scripts/smart-window-position.py b/src/Python/Scripts/smart-window-position.py
new file mode 100644
index 0000000..a400c57
--- /dev/null
+++ b/src/Python/Scripts/smart-window-position.py
@@ -0,0 +1,288 @@
+#!/usr/bin/env python3
+
+# Python Imports
+import sys
+import enum
+import argparse
+
+# Lib Imports
+from Xlib import display
+from Xlib.ext import randr, xinerama
+
+
+try:
+ from . import __version__
+except ImportError:
+ __version__ = "N/A"
+
+
+class Position(enum.Enum):
+ TOP = enum.auto()
+ BOTTOM = enum.auto()
+ LEFT = enum.auto()
+ RIGHT = enum.auto()
+
+ def __str__(self):
+ return self.name.lower()
+
+ @staticmethod
+ def from_str(pos):
+ try:
+ return Position[pos.upper()]
+ except KeyError:
+ raise ValueError(f"value '{pos}' not part of the Pos enum")
+
+
+class Shape:
+ def __init__(self, major, minor):
+ if max(major, minor) > 1.0 or min(major, minor) < 0.0:
+ raise ValueError(f"Shape out of range [0,1]: major={major}, minor={minor}")
+ self.major = major
+ self.minor = minor
+
+
+class Monitor:
+ def __init__(self, name, x, y, width, height):
+ self.name = name
+ self.x = x
+ self.y = y
+ self.width = width
+ self.height = height
+
+
+DEFAULTS = {
+ "name": "Smart Position",
+ "shape": (1.0, 0.4),
+ "position": str(Position.LEFT),
+}
+
+
+class SmartPositioner:
+ def __init__(self, name: str, shape: Shape, pos: Position, positioner_argv: list = None):
+ self.positioner_argv = positioner_argv
+ self.display = display.Display()
+ self.screen = self.display.screen()
+ self.root = self.screen.root
+
+ # self.fakeWindow = self.screen.root.create_window(0, 0, 1, 1, 1, self.screen.root_depth)
+
+ self.name = name
+ self.shape = shape
+ self.pos = pos
+ self.id = None
+ self.monitors = []
+
+ self.printXineramaVersion()
+ self.generateMonitorList()
+ self.getActiveMonitor()
+
+
+ def on_keybind(self, _, be):
+ pass
+ # if be.binding.command == f"nop {self.name}":
+ # self.toggle()
+
+
+ def _get_instance(self):
+ pass
+ # tree = self.i3.get_tree()
+ # if self.id is None:
+ # matches = tree.find_instanced(self.name)
+ # instance = {m.window_instance: m for m in matches}.get(self.name, None)
+ # if instance is not None:
+ # self.id = instance.id
+ # else:
+ # instance = tree.find_by_id(self.id)
+ # return instance
+
+ def toggle(self):
+ scrSize = self.getScreenSize()
+ mPos = self.getMousePosition()
+ self.display.flush() # Needed in some instances to prompt XWindows
+
+ # kitty = self._get_instance()
+ # if kitty is None:
+ # self.spawn()
+ # else:
+ # focused_ws = self._get_focused_workspace()
+ # if focused_ws is None:
+ # print("no focused workspaces; ignoring toggle request")
+ # return
+ # if kitty.workspace().name == focused_ws.name: # kitty present on current WS; hide
+ # self.i3.command(f"[con_id={self.id}] floating enable, move scratchpad")
+ # else:
+ # self.fetch(focused_ws)
+
+
+ def getMousePosition(self):
+ data = self.screen.root.query_pointer()._data
+ return data["root_x"], data["root_y"]
+
+ def getActiveMonitor(self):
+ pos = self.getMousePosition()
+ for mon in self.monitors:
+ pass
+
+ def getScreenSize(self):
+ w = self.display.screen().width_in_pixels
+ h = self.display.screen().height_in_pixels
+ return w, h
+
+
+ def printXineramaVersion(self):
+ xinerama_version = self.display.xinerama_query_version()
+ print('Found XINERAMA version %s.%s' % (
+ xinerama_version.major_version,
+ xinerama_version.minor_version,
+ ), file=sys.stderr)
+
+ def generateMonitorList(self):
+ print('Available screens:')
+ screens = xinerama.query_screens(self.root).screens
+ i = 1
+ for (idx, screen) in enumerate(screens):
+ x, y, w, h = screen.x, screen.y, screen.width, screen.height
+ print('screen %d: %s' % (idx, screen))
+ self.monitors.append( Monitor( "Monitor " + str(i), x, y, w, x ) )
+ i += 1
+
+ # resources = randr.get_screen_resources(self.root)
+ # for output in resources.outputs:
+ # params = self.display.xrandr_get_output_info(output, resources.config_timestamp)
+ # if not params.crtc:
+ # continue
+
+ # crtc = self.display.xrandr_get_crtc_info(params.crtc, resources.config_timestamp)
+ # self.monitors.append( Monitor(params.name, crtc.width, crtc.height) )
+
+
+ def spawn(self):
+ pass
+ # cmd_base = f"exec --no-startup-id kitty --name {self.name}"
+ # if self.positioner_argv is None:
+ # cmd = cmd_base
+ # else:
+ # argv = " ".join(self.positioner_argv)
+ # cmd = f"{cmd_base} {argv}"
+ # self.i3.command(cmd)
+
+ def on_spawned(self, _, we):
+ pass
+ # if we.container.window_instance == self.name:
+ # self.id = we.container.id
+ # self.i3.command(f"[con_id={we.container.id}] "
+ # "floating enable, "
+ # "border none, "
+ # "move scratchpad")
+ # self.fetch(self._get_focused_workspace())
+
+ def on_moved(self, _, we):
+ pass
+ # # Con is floating wrapper; the Kitty window/container is a child
+ # is_kitty = we.container.find_by_id(self.id)
+ # if not is_kitty:
+ # return
+ # focused_ws = self._get_focused_workspace()
+ # if focused_ws is None:
+ # return
+ # kitty = self._get_instance() # need "fresh" instance to capture destination WS
+ # kitty_ws = kitty.workspace()
+ # if (kitty_ws is None or kitty_ws.name == focused_ws.name or
+ # kitty_ws.name == "__i3_scratch"): # FIXME: fragile way to check if hidden?
+ # return
+ # self.fetch(kitty_ws, retrieve=False)
+
+ def _get_focused_workspace(self):
+ pass
+ # focused_workspaces = [w for w in self.i3.get_workspaces() if w.focused]
+ # if not len(focused_workspaces):
+ # return None
+ # return focused_workspaces[0]
+
+ def fetch(self, ws, retrieve=True):
+ pass
+ # if self.id is None:
+ # raise RuntimeError("Kitty instance ID not yet assigned")
+ #
+ # if self.pos in (Position.TOP, Position.BOTTOM):
+ # width = round(ws.rect.width * self.shape.major)
+ # height = round(ws.rect.height * self.shape.minor)
+ # x = ws.rect.x
+ # y = ws.rect.y if self.pos is Position.TOP else ws.rect.y + ws.rect.height - height
+ # else: # LEFT || RIGHT
+ # width = round(ws.rect.width * self.shape.minor)
+ # height = round(ws.rect.height * self.shape.major)
+ # x = ws.rect.x if self.pos is Position.LEFT else ws.rect.x + ws.rect.width - width
+ # y = ws.rect.y
+ #
+ # self.i3.command(f"[con_id={self.id}] "
+ # f"resize set {width}px {height}px, "
+ # f"{', move scratchpad, scratchpad show' if retrieve else ''}"
+ # f"move absolute position {x}px {y}px")
+
+ @staticmethod
+ def on_shutdown(_, se):
+ exit(0)
+
+
+def _split_args(args):
+ try:
+ split = args.index("--")
+ return args[:split], args[split + 1:]
+ except ValueError:
+ return args, None
+
+
+def _simple_fraction(arg):
+ arg = float(arg)
+ if not 0 <= arg <= 1:
+ raise argparse.ArgumentError("Argument needs to be a simple fraction, within"
+ "[0, 1]")
+ return arg
+
+
+def _parse_args(argv, defaults):
+ ap = argparse.ArgumentParser(
+ description="SmartPositioner: Window position wrapper for programs. "
+ "Arguments following '--' are forwarded to the program instance")
+ ap.set_defaults(**defaults)
+ ap.add_argument("-v", "--version",
+ action="version",
+ version=f"%(prog)s {__version__}",
+ help="show %(prog)s's version number and exit")
+ ap.add_argument("-n", "--name",
+ help="name/tag connecting a Kitti3 bindsym with a Kitty instance. "
+ "Forwarded to Kitty on spawn and scanned for on i3 binding "
+ "events")
+ ap.add_argument("-p", "--position",
+ type=Position.from_str,
+ choices=list(Position),
+ help="Along which edge of the screen to align the Kitty window")
+ ap.add_argument("-s", "--shape",
+ type=_simple_fraction,
+ nargs=2,
+ help="shape of the terminal window major and minor dimensions as a "
+ "fraction [0, 1] of the screen size (note: i3bar is accounted "
+ "for such that a 1.0 1.0 shaped terminal would not overlap it)")
+
+ args = ap.parse_args(argv)
+ return args
+
+
+
+
+def cli():
+ argv_positioner3, argv_positioner = _split_args(sys.argv[1:])
+ args = _parse_args(argv_positioner3, DEFAULTS)
+
+ positioner = SmartPositioner(
+ name=args.name,
+ shape=Shape(*args.shape),
+ pos=args.position,
+ positioner_argv=argv_positioner,
+ )
+ # positioner.loop()
+
+
+if __name__ == "__main__":
+ cli()
diff --git a/src/Scripts/Generate Java Project/insert_base_Java_data.sh b/src/Shell/Generate Java Project/insert_base_Java_data.sh
similarity index 100%
rename from src/Scripts/Generate Java Project/insert_base_Java_data.sh
rename to src/Shell/Generate Java Project/insert_base_Java_data.sh
diff --git a/src/Scripts/Generate Java Project/insert_script_data.sh b/src/Shell/Generate Java Project/insert_script_data.sh
similarity index 100%
rename from src/Scripts/Generate Java Project/insert_script_data.sh
rename to src/Shell/Generate Java Project/insert_script_data.sh
diff --git a/src/Scripts/Generate Java Project/make_java_project.sh b/src/Shell/Generate Java Project/make_java_project.sh
similarity index 100%
rename from src/Scripts/Generate Java Project/make_java_project.sh
rename to src/Shell/Generate Java Project/make_java_project.sh
diff --git a/src/Scripts/Retriev GBA Roms/gba_rom_dlr.sh b/src/Shell/Retriev GBA Roms/gba_rom_dlr.sh
similarity index 100%
rename from src/Scripts/Retriev GBA Roms/gba_rom_dlr.sh
rename to src/Shell/Retriev GBA Roms/gba_rom_dlr.sh
diff --git a/src/Scripts/Retriev GBA Roms/get_rom_list.sh b/src/Shell/Retriev GBA Roms/get_rom_list.sh
similarity index 100%
rename from src/Scripts/Retriev GBA Roms/get_rom_list.sh
rename to src/Shell/Retriev GBA Roms/get_rom_list.sh
diff --git a/src/Scripts/Utils/a-z_folder_maker.sh b/src/Shell/Utils/a-z_folder_maker.sh
similarity index 100%
rename from src/Scripts/Utils/a-z_folder_maker.sh
rename to src/Shell/Utils/a-z_folder_maker.sh
diff --git a/src/Scripts/Utils/clean_start_menu.sh b/src/Shell/Utils/clean_start_menu.sh
similarity index 100%
rename from src/Scripts/Utils/clean_start_menu.sh
rename to src/Shell/Utils/clean_start_menu.sh
diff --git a/src/Scripts/Utils/clear_pycache_dirs.sh b/src/Shell/Utils/clear_pycache_dirs.sh
similarity index 100%
rename from src/Scripts/Utils/clear_pycache_dirs.sh
rename to src/Shell/Utils/clear_pycache_dirs.sh
diff --git a/src/Scripts/Utils/compress.sh b/src/Shell/Utils/compress.sh
similarity index 100%
rename from src/Scripts/Utils/compress.sh
rename to src/Shell/Utils/compress.sh
diff --git a/src/Scripts/Utils/get_missing_gpg_keys.sh b/src/Shell/Utils/get_missing_gpg_keys.sh
similarity index 100%
rename from src/Scripts/Utils/get_missing_gpg_keys.sh
rename to src/Shell/Utils/get_missing_gpg_keys.sh
diff --git a/src/Scripts/Utils/get_mynoise_src.sh b/src/Shell/Utils/get_mynoise_src.sh
similarity index 100%
rename from src/Scripts/Utils/get_mynoise_src.sh
rename to src/Shell/Utils/get_mynoise_src.sh
diff --git a/src/Scripts/Utils/marathon_game_launcher.sh b/src/Shell/Utils/marathon_game_launcher.sh
similarity index 100%
rename from src/Scripts/Utils/marathon_game_launcher.sh
rename to src/Shell/Utils/marathon_game_launcher.sh
diff --git a/src/Scripts/Utils/quick_hash_extractor.sh b/src/Shell/Utils/quick_hash_extractor.sh
similarity index 100%
rename from src/Scripts/Utils/quick_hash_extractor.sh
rename to src/Shell/Utils/quick_hash_extractor.sh
diff --git a/src/Scripts/Utils/sound_fix_ubuntu.sh b/src/Shell/Utils/sound_fix_ubuntu.sh
similarity index 100%
rename from src/Scripts/Utils/sound_fix_ubuntu.sh
rename to src/Shell/Utils/sound_fix_ubuntu.sh
diff --git a/src/Scripts/automated_dreamscene_switcher.sh b/src/Shell/automated_dreamscene_switcher.sh
similarity index 100%
rename from src/Scripts/automated_dreamscene_switcher.sh
rename to src/Shell/automated_dreamscene_switcher.sh
diff --git a/src/Scripts/cisco_anytime_vpn_setup.sh b/src/Shell/cisco_anytime_vpn_setup.sh
similarity index 100%
rename from src/Scripts/cisco_anytime_vpn_setup.sh
rename to src/Shell/cisco_anytime_vpn_setup.sh
diff --git a/src/Scripts/create_virtualbox_HDD_vmdk.sh b/src/Shell/create_virtualbox_HDD_vmdk.sh
similarity index 100%
rename from src/Scripts/create_virtualbox_HDD_vmdk.sh
rename to src/Shell/create_virtualbox_HDD_vmdk.sh
diff --git a/src/Scripts/install_development_packages.sh b/src/Shell/install_development_packages.sh
similarity index 100%
rename from src/Scripts/install_development_packages.sh
rename to src/Shell/install_development_packages.sh
diff --git a/src/Scripts/media_list_backup_maker.sh b/src/Shell/media_list_backup_maker.sh
similarity index 100%
rename from src/Scripts/media_list_backup_maker.sh
rename to src/Shell/media_list_backup_maker.sh
diff --git a/src/Scripts/profile_backup.sh b/src/Shell/profile_backup.sh
similarity index 100%
rename from src/Scripts/profile_backup.sh
rename to src/Shell/profile_backup.sh
diff --git a/src/Scripts/qemu_setup.sh b/src/Shell/qemu_setup.sh
similarity index 100%
rename from src/Scripts/qemu_setup.sh
rename to src/Shell/qemu_setup.sh
diff --git a/src/Scripts/system_admin.sh b/src/Shell/system_admin.sh
similarity index 100%
rename from src/Scripts/system_admin.sh
rename to src/Shell/system_admin.sh
diff --git a/src/Scripts/system_info.sh b/src/Shell/system_info.sh
similarity index 100%
rename from src/Scripts/system_info.sh
rename to src/Shell/system_info.sh
diff --git a/src/Scripts/vnc_servers.sh b/src/Shell/vnc_servers.sh
similarity index 100%
rename from src/Scripts/vnc_servers.sh
rename to src/Shell/vnc_servers.sh
diff --git a/src/Scripts/xbox_controller.sh b/src/Shell/xbox_controller.sh
similarity index 100%
rename from src/Scripts/xbox_controller.sh
rename to src/Shell/xbox_controller.sh