diff --git a/src/clear_pycache_dirs.sh b/src/clear_pycache_dirs.sh new file mode 100755 index 0000000..7987a3d --- /dev/null +++ b/src/clear_pycache_dirs.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() { + find . -name "__pycache__" -exec rm -rf $1 {} \; + find . -name "*.pyc" -exec rm -rf $1 {} \; +} +main diff --git a/src/debs/build.sh b/src/debs/build.sh new file mode 100644 index 0000000..48e85d7 --- /dev/null +++ b/src/debs/build.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Fixes ownershp +function main() { + sudo find . -type f -exec chmod 644 {} + + sudo find . -type d -exec chmod 755 {} + + + # Set postrm permissions + for i in `find . -name postrm`; do + sudo chmod 755 "${i}" + done + + # Set pytop permissions + for i in `find . -name pytop`; do + sudo chmod 755 "${i}" + done + + sudo chown -R root:root ./*/ + + builder; + bash ./chownAll.sh +} + +#builds debs +function builder() { + for i in `ls`; do + if [[ -d "${i}" ]]; then + dpkg --build "${i}" + else + echo "Not a dir." + fi + done +} +main; diff --git a/src/debs/chownAll.sh b/src/debs/chownAll.sh new file mode 100644 index 0000000..44bef62 --- /dev/null +++ b/src/debs/chownAll.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function main() { + sudo chown -R abaddon:abaddon . +} +main; diff --git a/src/debs/pytop-0-0-1-x64/DEBIAN/control b/src/debs/pytop-0-0-1-x64/DEBIAN/control new file mode 100644 index 0000000..d7afe4f --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/DEBIAN/control @@ -0,0 +1,8 @@ +Package: pytop64 +Version: 0.0-1 +Section: python +Priority: optional +Architecture: amd64 +Depends: python3, wget, steamcmd, ffmpegthumbnailer (>= 2.0.10-0.1), gir1.2-wnck-1.0 +Maintainer: Maxim Stewart <1itdominator@gmail.com> +Description: Pytop is a custom desktop GUI. diff --git a/src/debs/pytop-0-0-1-x64/DEBIAN/postrm b/src/debs/pytop-0-0-1-x64/DEBIAN/postrm new file mode 100755 index 0000000..4962c4c --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/DEBIAN/postrm @@ -0,0 +1,11 @@ +#!/bin/bash +#postrm (script executed after uninstalling the package) +#set -e + +if [ -f /bin/pytop ]; then + rm /bin/pytop +fi + +if [ -d /opt/Pytop ]; then + rm -rf /opt/Pytop +fi diff --git a/src/debs/pytop-0-0-1-x64/bin/pytop b/src/debs/pytop-0-0-1-x64/bin/pytop new file mode 100755 index 0000000..d4cb9c9 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/bin/pytop differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/__init__.py new file mode 100644 index 0000000..054b613 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/__init__.py @@ -0,0 +1,73 @@ +#!/usr/bin/python3 + +# Python imports +import inspect + +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 Gdk as gdk +from gi.repository import GLib + +# Application imports +from utils import Settings +from signal_classes import Signals + + +class Main: + def __init__(self, args): + setproctitle('Pytop') + GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, gtk.main_quit) + faulthandler.enable() # For better debug info + + builder = gtk.Builder() + settings = Settings() + settings.attachBuilder(builder) + self.connectBuilder(settings, builder) + + window = settings.createWindow() + window.fullscreen() + window.show() + + monitors = settings.returnMonitorsInfo() + i = 1 + if len(monitors) > 1: + for mon in monitors[1:]: + subBuilder = gtk.Builder() + subSettings = Settings(i) + subSettings.attachBuilder(subBuilder) + self.connectBuilder(subSettings, subBuilder) + + win = subSettings.createWindow() + win.set_default_size(mon.width, mon.height) + win.set_size_request(mon.width, mon.height) + win.set_resizable(False) + win.move(mon.x, mon.y) + + win.show() + i += 1 + + + def connectBuilder(self, settings, builder): + # Gets the methods from the classes and sets to handler. + # Then, builder connects to any signals it needs. + classes = [Signals(settings)] + + handlers = {} + for c in classes: + methods = inspect.getmembers(c, predicate=inspect.ismethod) + handlers.update(methods) + + builder.connect_signals(handlers) + + +if __name__ == "__main__": + try: + main = Main() + gtk.main() + except Exception as e: + print( repr(e) ) diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/__main__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/__main__.py new file mode 100644 index 0000000..06514d9 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/__main__.py @@ -0,0 +1,35 @@ +#!/usr/bin/python3 + + +# Python imports +import argparse +import pdb # For trace debugging +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: + # pdb.set_trace() + setproctitle('Pytop') + 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="default", 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/debs/pytop-0-0-1-x64/opt/Pytop/resources/Main_Window.glade b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/Main_Window.glade new file mode 100644 index 0000000..f0222ae --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/Main_Window.glade @@ -0,0 +1,849 @@ + + + + + + + inode/directory + + + + 1 + 100 + 1 + 1 + 10 + + + + True + False + gtk-new + + + 64 + 64 + True + False + start_menu_icons/start_menu_icon2_32x32.png + + + False + 800 + 600 + desktop + False + center + + + + + + 256 + True + False + vertical + + + True + False + + + Menu + 64 + 64 + True + True + True + menuImage + True + + + + False + True + 0 + + + + + + + + True + False + start + + + + + + + + + + False + True + end + 3 + + + + + True + False + select-folder + Folders + Directory Chooser + + + + False + True + end + 2 + + + + + False + True + 0 + + + + + True + False + + + True + False + vertical + + + True + True + in + + + True + True + 6 + multiple + + + + + True + True + 0 + + + + + True + True + 0 + + + + + 180 + 64 + True + True + never + in + 225 + + + True + False + + + True + False + vertical + + + + + + + + + + False + True + 1 + + + + + True + True + 1 + + + + + True + False + + + 64 + True + True + never + in + + + True + False + + + True + False + + + + + + + + + + True + True + 0 + + + + + True + False + start + + + + + + False + True + 1 + + + + + True + False + True + + + + 126 + True + False + 10 + 10 + center + False + + + + + + + + False + True + 2 + + + + + False + True + 3 + + + + + + + 420 + 225 + False + timeLabelEveBox + False + + + True + True + 2020 + 3 + 22 + + + + + 500 + 0 + False + taskBarWorkspacesVer + bottom + + + True + False + + + True + True + True + True + rgb(138,226,52) + + + + False + True + 1 + + + + + 60 + True + False + + + + + True + True + 2 + + + + + True + True + brushSizeProp + + + False + True + 2 + + + + + + + 600 + 400 + False + 4 + mouse + True + True + True + False + False + center + True + + + + + + True + False + vertical + + + True + True + True + True + True + edit-find-symbolic + False + False + + + + False + True + 0 + + + + + True + False + + + True + False + vertical + start + + + Accessories + True + True + True + + + + True + True + 0 + + + + + Multimedia + True + True + True + + + + True + True + 1 + + + + + Graphics + True + True + True + + + + True + True + 2 + + + + + Game + True + True + True + + + + True + True + 3 + + + + + Office + True + True + True + + + + True + True + 4 + + + + + Development + True + True + True + + + + True + True + 5 + + + + + Internet + True + True + True + + + + True + True + 6 + + + + + Settings + True + True + True + + + + True + True + 7 + + + + + System + True + True + True + + + + True + True + 8 + + + + + Wine + True + True + True + + + + True + True + 9 + + + + + Other + True + True + True + + + + True + True + 10 + + + + + False + True + 0 + + + + + True + True + True + never + in + + + True + False + + + True + False + vertical + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + + + True + False + icons/trash.png + + + False + False + True + center + True + splashscreen + True + True + False + False + center + + + + + + + 500 + True + False + vertical + + + 500 + 26 + True + True + gtk-edit + + + + False + True + 0 + + + + + True + False + + + gtk-copy + True + True + True + Copy... + True + True + + + + False + True + 0 + + + + + gtk-cut + True + True + True + Cut... + True + True + + + + False + True + 1 + + + + + gtk-delete + True + True + True + Delete... + True + True + + + + False + True + 4 + + + + + Trash + True + True + True + Move to Trash... + trashImage + True + + + + False + True + end + 3 + + + + + False + True + 1 + + + + + True + False + vertical + + + True + False + + + True + False + 15 + Folder + + + + + + True + True + 0 + + + + + True + False + 15 + File + + + + + + True + True + 1 + + + + + False + True + 0 + + + + + True + True + File/Folder + True + + + False + True + 1 + + + + + Create + True + True + True + Create File/Folder... + createImage + True + + + + False + True + 2 + + + + + gtk-paste + True + True + True + Paste... + True + True + + + + False + True + 3 + + + + + False + True + 2 + + + + + + diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/archive.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/archive.png new file mode 100644 index 0000000..7943e4e Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/archive.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/audio.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/audio.png new file mode 100644 index 0000000..c010134 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/audio.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/bin.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/bin.png new file mode 100644 index 0000000..d6954e3 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/bin.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/dir.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/dir.png new file mode 100644 index 0000000..a9b5e9f Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/dir.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/doc.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/doc.png new file mode 100644 index 0000000..f838826 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/doc.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/pdf.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/pdf.png new file mode 100644 index 0000000..9f40122 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/pdf.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/presentation.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/presentation.png new file mode 100644 index 0000000..3a339af Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/presentation.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/spreadsheet.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/spreadsheet.png new file mode 100644 index 0000000..710efa6 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/spreadsheet.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/text.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/text.png new file mode 100644 index 0000000..2546fcd Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/text.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/trash.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/trash.png new file mode 100644 index 0000000..c6514b9 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/trash.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/video.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/video.png new file mode 100644 index 0000000..55afa98 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/video.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/web.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/web.png new file mode 100644 index 0000000..17017ce Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/icons/web.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_128x128.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_128x128.png new file mode 100644 index 0000000..d565a6a Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_128x128.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_256x256.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_256x256.png new file mode 100644 index 0000000..29810bb Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_256x256.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_32x32.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_32x32.png new file mode 100644 index 0000000..ba53a44 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_32x32.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_64x64.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_64x64.png new file mode 100644 index 0000000..07eae0a Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_64x64.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_72x72.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_72x72.png new file mode 100644 index 0000000..221cca5 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_72x72.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_96x96.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_96x96.png new file mode 100644 index 0000000..74020a7 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon2_96x96.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_128x128.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_128x128.png new file mode 100644 index 0000000..f11fb1b Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_128x128.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_256x256.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_256x256.png new file mode 100644 index 0000000..f7b5320 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_256x256.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_32x32.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_32x32.png new file mode 100644 index 0000000..f5abcf9 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_32x32.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_64x64.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_64x64.png new file mode 100644 index 0000000..7250d7c Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_64x64.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_72x72.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_72x72.png new file mode 100644 index 0000000..2d4e7c1 Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_72x72.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_96x96.png b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_96x96.png new file mode 100644 index 0000000..9ea489d Binary files /dev/null and b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/start_menu_icons/start_menu_icon_96x96.png differ diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/stylesheet.css b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/stylesheet.css new file mode 100644 index 0000000..d8263f5 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/resources/stylesheet.css @@ -0,0 +1,96 @@ +/* Menu css properties */ +.menu_scroller label { + font-size: 120%; +} + + +/* Grid css properties */ + +viewport, +treeview, +treeview > header, +notebook > stack, +notebook > header { + background-color: rgba(0, 0, 0, 0.24); +} + + +notebook > header { + background-color: rgba(0, 0, 0, 0.24); + border-color: rgba(0, 232, 255, 0.64); +} + +box, +iconview { + background-color: rgba(0, 0, 0, 0.2); + background: rgba(0, 0, 0, 0.2); +} + +treeview, +treeview.view { + background: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.2); +} + +cell { + margin: 0em; + padding: 0em; + /* float: left; */ +} + +cell:focus { + outline-style: solid; + outline-color: rgba(0, 232, 255, 0.64); +} + + +/* Ivonview and children default color */ +.view { + background-color: rgba(0, 0, 0, 0.22); + color: #ebebeb; +} + + +/* Hover over color when not selected */ +.view:hover { + box-shadow: inset 0 0 0 9999px alpha(rgba(0, 232, 255, 0.64), 0.54); +} + +/* Handles the icon selection hover and selected hover color. */ +.view:selected, +.view:selected:hover { + box-shadow: inset 0 0 0 9999px rgba(15, 134, 13, 0.49); +} + +/* Rubberband coloring */ +.rubberband, +rubberband, +flowbox rubberband, +treeview.view rubberband, +.content-view rubberband, +.content-view .rubberband, +XfdesktopIconView.view .rubberband { + border: 1px solid #6c6c6c; + background-color: rgba(21, 158, 167, 0.57); +} + +XfdesktopIconView.view:active { + background-color: rgba(172, 102, 21, 1); +} + + +XfdesktopIconView.view { + border-radius: 4px; + background-color: transparent; + color: white; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); +} + +XfdesktopIconView.view:active { + box-shadow: none; + text-shadow: none; +} + +XfdesktopIconView.view .rubberband { + border-radius: 0; +} diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/Signals.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/Signals.py new file mode 100644 index 0000000..97dd312 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/Signals.py @@ -0,0 +1,89 @@ +# Python imports +from datetime import datetime +import os + +# Gtk imports + + +# Application imports +from .mixins import CPUDrawMixin, MainMenuMixin, TaskbarMixin, GridMixin +from widgets import Grid +from widgets import Icon +from utils import FileHandler + + + +class Signals(CPUDrawMixin, MainMenuMixin, TaskbarMixin, GridMixin): + def __init__(self, settings): + self.settings = settings + self.builder = self.settings.returnBuilder() + + self.timeLabel = self.builder.get_object("timeLabel") + self.drawArea = self.builder.get_object("drawArea") + self.brushSizeProp = self.builder.get_object("brushSizeProp") + self.brushColorProp = self.builder.get_object("brushColorProp") + + # Menu bar setup - Note: Must be before setting clock + self.orientation = 1 # 0 = horizontal, 1 = vertical + self.setPagerWidget() + self.setTasklistWidget() + + # Must be after pager and task list inits + self.displayclock() + self.startClock() + + # CPUDrawMixin Parts + self.cpu_percents = [] + self.doDrawBackground = False + self.isDrawing = False + self.surface = None + self.aw = None # Draw area width + self.ah = None # Draw area height + self.xStep = None # For x-axis 60 sec steps + self.yStep = None # For y-axis %s + + rgba = self.brushColorProp.get_rgba() + self.brushColorVal = [rgba.red, rgba.green, rgba.blue, rgba.alpha] + self.brushSizeVal = self.brushSizeProp.get_value() + self.updateSpeed = 100 # 1 sec = 1000ms + + self.good = [0.53, 0.8, 0.15, 1.0] + self.warning = [1.0, 0.66, 0.0, 1.0] + self.danger = [1.0, 0.0, 0.0, 1.0] + + + # GridMixin Parts + self.filehandler = FileHandler(settings) + + self.builder = self.settings.returnBuilder() + self.gridObj = self.builder.get_object("Desktop") + selectDirDialog = self.builder.get_object("selectDirDialog") + filefilter = self.builder.get_object("Folders") + + self.currentPath = self.settings.returnSettings()[0] + self.copyCutArry = [] + self.selectedFiles = [] + self.gridClss = Grid(self.gridObj, self.settings) + self.pasteType = 1 # copy == 1 and cut == 2 + + + # Add filter to allow only folders to be selected + selectDirDialog.add_filter(filefilter) + selectDirDialog.set_filename(self.currentPath) + self.setNewDirectory(selectDirDialog) + + + # Program Menu Parts + self.menuWindow = self.builder.get_object("menuWindow") + self.menuWindow.set_keep_above(True); + self.showIcons = False + + self.iconFactory = Icon(self.settings) + self.grpDefault = "Accessories" + self.progGroup = self.grpDefault + HOME_APPS = os.path.expanduser('~') + "/.local/share/applications/" + paths = ["/opt/", "/usr/share/applications/", HOME_APPS] + self.menuData = self.getDesktopFilesInfo(paths) + self.desktopObjs = [] + self.getSubgroup() + self.generateListView() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/__init__.py new file mode 100644 index 0000000..f5b8431 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/__init__.py @@ -0,0 +1,4 @@ +from .mixins import CPUDrawMixin +from .mixins import TaskbarMixin +from .mixins import GridMixin +from signal_classes.Signals import Signals diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/CPUDrawMixin.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/CPUDrawMixin.py new file mode 100644 index 0000000..e921777 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/CPUDrawMixin.py @@ -0,0 +1,129 @@ +#!/usr/bin/python3 + + +# Python Imports +from __future__ import division +import cairo, psutil + + +# GTK Imports +from gi.repository import GObject +from gi.repository import GLib + + + + + +class CPUDrawMixin: + # Note: y-axis on draw area goes from top to bottom when increasing. + # Need to do the math such that you subtract from max height to start from bottom to go up + # self.linePoints.append([1 * xStep, ah - (23 * yStep)]) # 23% + # self.linePoints.append([2 * xStep, ah - (60 * yStep)]) # 60% + # self.drawPointLine() + # del self.linePoints[0:1] + # self.linePoints.append([3 * xStep, ah - (44 * yStep)]) # 44% + def updateCPUPoints(self): + # Clears screen when enough points exist and unshifts the + # first point to keep fixed range + self.drawBackground(self.brush, self.aw, self.ah) + del self.cpu_percents[0:1] + + precent = psutil.cpu_percent() + self.cpu_percents.append(precent) + self.drawPointLine() # Will re-draw every point + self.drawArea.queue_draw() + + return True + + + def drawPointLine(self): + self.brush.set_line_width(self.brushSizeVal) + self.brush.set_line_cap(1) # 0 = BUTT, 1 = ROUND, 2 = SQUARE + + oldX = 0.0 + oldP = 0.0 + i = 1 + for p in self.cpu_percents: + # set color depending on usage... + rgba = self.brushColorVal + if p > 50.0: + rgba = self.warning + if p > 85.0: + rgba = self.danger + + self.brush.set_source_rgba(rgba[0], rgba[1], rgba[2], rgba[3]) + + # Movbe to prev. point if any + if oldP is not 0.0 and oldX is not 0.0: + x = oldX + y = float(self.ah) - (oldP * self.yStep) + self.brush.move_to(x, y) + + # Draw line to the new point from old point + x2 = i * self.xStep + y2 = float(self.ah) - (p * self.yStep) + self.brush.line_to(x2, y2) + self.brush.stroke() + + # Collect info to use as prev. pint + oldX = x2 + oldP = p + i += 1 + + + def onConfigure(self, area, eve, data = None): + aw = area.get_allocated_width() + ah = area.get_allocated_height() + self.aw = aw + self.ah = ah + self.xStep = aw / 200 # For x-axis + self.yStep = ah / 100 # For y-axis %s + self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, aw, ah) + self.brush = cairo.Context(self.surface) + + self.drawBackground(self.brush, aw, ah) + if not self.isDrawing: + self.fillCPUPercents() + self.startCPUGraph() + self.isDrawing = True + + return False + + # Fill with y bank with 50%s + def fillCPUPercents(self): + self.cpu_percents = [50.0] * 198 + + + # Draw background white + def drawBackground(self, brush, aw, ah): + brush.rectangle(0, 0, aw, ah) # x, y, width, height + brush.set_source_rgba(1, 1, 1, 1.0) # 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... + + + # Starting graph generation + def startCPUGraph(self): + GObject.timeout_add(self.updateSpeed, self.updateCPUPoints) + + + 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 + + + def onColorSet(self, widget): + rgba = widget.get_rgba() + self.brushColorVal = [rgba.red, rgba.green, rgba.blue, rgba.alpha] + + def onBrushSizeChange(self, widget): + self.brushSizeVal = self.brushSizeProp.get_value() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/GridMixin.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/GridMixin.py new file mode 100644 index 0000000..a10cf42 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/GridMixin.py @@ -0,0 +1,77 @@ +# Gtk imports + +# Python imports + +# Application imports + + +class GridMixin: + # Calls the Grid widget class' method + def setNewDirectory(self, widget, data=None): + newPath = widget.get_filename() + self.gridClss.setNewDirectory(newPath) + self.settings.saveSettings(newPath) + + + # File control events + def create(self, wdget): + self.currentPath = self.gridClss.returnCurrentPath() + fileName = self.builder.get_object("filenameInput").get_text().strip() + type = self.builder.get_object("createSwitch").get_state() + + if fileName != "": + fileName = self.currentPath + "/" + fileName + status = self.filehandler.create(fileName, type) + if status == 0: + self.gridClss.setNewDirectory(self.currentPath) + + def copy(self, widget): + self.pasteType = 1 + self.copyCutArry = self.gridClss.returnSelectedFiles() + + def cut(self, widget): + self.pasteType = 2 + self.copyCutArry = self.gridClss.returnSelectedFiles() + + def paste(self, widget): + self.currentPath = self.gridClss.returnCurrentPath() + status = self.filehandler.paste(self.copyCutArry, self.currentPath, self.pasteType) + + if status == 0: + self.gridClss.setNewDirectory(self.currentPath) + if self.pasteType == 2: # cut == 2 + self.copyCutArry = [] + + def delete(self, widget): + self.getGridInfo() + status = self.filehandler.delete(self.selectedFiles) + + if status == 0: + self.selectedFiles = [] + self.gridClss.setNewDirectory(self.currentPath) + + def trash(self, widget): + self.getGridInfo() + status = self.filehandler.trash(self.selectedFiles) + + if status == 0: + self.selectedFiles = [] + self.gridClss.setNewDirectory(self.currentPath) + + def rename(self, widget, data): + if data.keyval == 65293: # Enter key press + self.getGridInfo() + file = widget.get_text(); + if len(self.selectedFiles) == 1: + newName = self.currentPath + "/" + file + print("Old Name: " + self.selectedFiles[0]) + print("New Name: " + newName.strip()) + + status = self.filehandler.rename(self.selectedFiles[0], newName.strip()) + if status == 0: + self.selectedFiles = [newName] + self.gridClss.setNewDirectory(self.currentPath) + + def getGridInfo(self): + self.selectedFiles = self.gridClss.returnSelectedFiles() + self.currentPath = self.gridClss.returnCurrentPath() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/MainMenuMixin.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/MainMenuMixin.py new file mode 100644 index 0000000..85c786f --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/MainMenuMixin.py @@ -0,0 +1,290 @@ +# Python imports +import subprocess +import threading +import os +import json + +from os.path import isdir, isfile, join +from os import listdir + + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') + +from gi.repository import Gtk as gtk +from gi.repository import GLib as glib +from xdg.DesktopEntry import DesktopEntry + + +# Application imports + + + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + return wrapper + + +class MainMenuMixin: + def toggleProgramMenu(self, widget): + pos = self.menuWindow.get_position() + posX = pos[0] + 32 + posY = pos[1] + 72 + if self.menuWindow.get_visible() == False: + self.menuWindow.move(posX, posY) + glib.idle_add(self.menuWindow.show_all) + else: + glib.idle_add(self.menuWindow.hide) + + + def setListGroup(self, widget): + self.progGroup = widget.get_label().strip() + self.getSubgroup(self.progGroup) + self.generateListView() + + + def searchForEntry(self, widget, data=None): + self.progGroup = "[ Search ]" + query = widget.get_text().strip() + if not query: + self.progGroup = self.grpDefault + self.getSubgroup() + self.generateListView() + return + + self.getSubgroup(query) + self.generateListView() + + + @threaded + def generateListView(self): + widget = self.builder.get_object("programListBttns") + + # Should have this as a useful method...But, I don't want to import Glib everywhere + children = widget.get_children() + for child in children: + glib.idle_add(widget.remove, (child)) + + for obj in self.desktopObjs: + title = obj[0] + dirPath = obj[1] + if self.showIcons: + image = self.iconFactory.parseDesktopFiles(dirPath) # .get_pixbuf() + self.addToProgramListView(widget, title, image) + else: + self.addToProgramListViewAsText(widget, title) + + + @threaded + def addToProgramListView(self, widget, title, icon): + button = gtk.Button(label=title) + button.set_image(icon) + button.connect("clicked", self.executeProgram) + + children = button.get_children() + alignment1 = children[0] + box = alignment1.get_children()[0] + label = box.get_children()[1] + + alignment1.set(0.0, 0.0, 0.0, 0.0) + label.set_halign(1) + label.set_line_wrap(True) + label.set_max_width_chars(38) + label.set_size_request(640, 64) + + button.show_all() + glib.idle_add(widget.add, (button)) + + @threaded + def addToProgramListViewAsText(self, widget, title): + button = gtk.Button(label=title) + button.connect("clicked", self.executeProgram) + + children = button.get_children() + label = children[0] + + label.set_halign(1) + label.set_line_wrap(True) + label.set_max_width_chars(38) + label.set_size_request(640, 64) + + button.show_all() + glib.idle_add(widget.add, (button)) + + + def executeProgram(self, widget): + """ + # TODO: + Need to refactor and pull out the sub loop that is used in both cases... + """ + entry = widget.get_label().strip() + group = self.progGroup + + parts = entry.split("||") + program = parts[0].strip() + comment = parts[1].strip() + + if "[ Search ]" in group: + gkeys = self.menuData.keys() + for gkey in gkeys: + for opt in self.menuData[gkey]: + if program in opt["title"]: + keys = opt.keys() + if comment in opt["comment"] or comment in opt["fileName"]: + DEVNULL = open(os.devnull, 'w') + execFailed = False + try: + command = opt["tryExec"].split("%")[0] + # self.logger.debug(command) + subprocess.Popen(command.split(), start_new_session=True, stdout=DEVNULL, stderr=DEVNULL) + break + except Exception as e: + execFailed = True + + if execFailed: + try: + if "exec" in keys and len(opt["exec"]): + command = opt["exec"].split("%")[0] + # self.logger.debug(command) + subprocess.Popen(command.split(), start_new_session=True, stdout=DEVNULL, stderr=DEVNULL) + break + except Exception as e: + print( repr(e) ) + # self.logger.debug(e) + else: + for opt in self.menuData[group]: + if program in opt["title"]: + keys = opt.keys() + if comment in opt["comment"] or comment in opt["fileName"]: + DEVNULL = open(os.devnull, 'w') + execFailed = False + try: + command = opt["tryExec"].split("%")[0] + # self.logger.debug(command) + subprocess.Popen(command.split(), start_new_session=True, stdout=DEVNULL, stderr=DEVNULL) + except Exception as e: + execFailed = True + + if execFailed: + try: + if "exec" in keys and len(opt["exec"]): + command = opt["exec"].split("%")[0] + # self.logger.debug(command) + subprocess.Popen(command.split(), start_new_session=True, stdout=DEVNULL, stderr=DEVNULL) + except Exception as e: + print( repr(e) ) + # self.logger.debug(e) + + + # Supoport methods + def getDesktopFilesInfo(self, paths): + menuObjs = { + "Accessories": [], + "Multimedia": [], + "Graphics": [], + "Game": [], + "Office": [], + "Development": [], + "Internet": [], + "Settings": [], + "System": [], + "Wine": [], + "Other": [] + } + + for path in paths: + if not "/opt/" in path: + self.listAndUpdateDesktopFiles(path, menuObjs); + else: + for folder in listdir(path): + try: + fPath = path + folder + "/" + self.listAndUpdateDesktopFiles(fPath, menuObjs); + except Exception as e: + print( repr(e) ) + + return menuObjs + + def listAndUpdateDesktopFiles(self, path, menuObjs): + for f in listdir(path): + fPath = path + f + if isfile(fPath) and f.endswith(".desktop"): + xdgObj = DesktopEntry(fPath) + + title = xdgObj.getName() + groups = xdgObj.getCategories() + comment = xdgObj.getComment() + icon = xdgObj.getIcon() + mainExec = xdgObj.getExec() + tryExec = xdgObj.getTryExec() + + group = "" + if "Accessories" in groups or "Utility" in groups: + group = "Accessories" + elif "Multimedia" in groups or "Video" in groups or "Audio" in groups: + group = "Multimedia" + elif "Development" in groups: + group = "Development" + elif "Game" in groups: + group = "Game" + elif "Internet" in groups or "Network" in groups: + group = "Internet" + elif "Graphics" in groups: + group = "Graphics" + elif "Office" in groups: + group = "Office" + elif "System" in groups: + group = "System" + elif "Settings" in groups: + group = "Settings" + elif "Wine" in groups: + group = "Wine" + else: + group = "Other" + + menuObjs[group].append( {"title": title, "groups": groups, + "comment": comment, "exec": mainExec, + "tryExec": tryExec, "fileName": f, + "filePath": fPath, "icon": icon}) + + + def getSubgroup(self, query = ""): + """ + Need to refactor and pull out the sub logic that is used in both cases... + """ + group = self.progGroup + self.desktopObjs.clear() + if "[ Search ]" in group: + gkeys = self.menuData.keys() + for gkey in gkeys: + for opt in self.menuData[gkey]: + keys = opt.keys() + + if "comment" in keys and len(opt["comment"]) > 0 : + if query.lower() in opt["comment"].lower(): + title = opt["title"] + " || " + opt["comment"] + fPath = opt["filePath"] + self.desktopObjs.append([title, fPath]) + continue + + if query.lower() in opt["title"].lower() or \ + query.lower() in opt["fileName"].lower(): + title = opt["title"] + " || " + opt["fileName"].replace(".desktop", "") + fPath = opt["filePath"] + self.desktopObjs.append([title, fPath]) + else: + for opt in self.menuData[group]: + keys = opt.keys() + if "comment" in keys and len(opt["comment"]) > 0 : + title = opt["title"] + " || " + opt["comment"] + fPath = opt["filePath"] + self.desktopObjs.append([title, fPath]) + else: + title = opt["title"] + " || " + opt["fileName"].replace(".desktop", "") + fPath = opt["filePath"] + self.desktopObjs.append([title, fPath]) + + return self.desktopObjs diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/TaskbarMixin.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/TaskbarMixin.py new file mode 100644 index 0000000..f8fee3b --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/TaskbarMixin.py @@ -0,0 +1,90 @@ +# Python imports +import threading +from datetime import datetime + +# Gtk imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Wnck', '3.0') + +from gi.repository import Wnck as wnck +from gi.repository import Gtk as gtk +from gi.repository import Gdk as gdk +from gi.repository import GLib +from gi.repository import GObject + +# Application imports + + + +class MouseButton: + LEFT_BUTTON = 1 + MIDDLE_BUTTON = 2 + RIGHT_BUTTON = 3 + + +class TaskbarMixin: + def toggleCalPopover(self, widget, eve): + calendarPopup = self.builder.get_object('calendarPopup') + if (calendarPopup.get_visible() == False): + calendarWid = self.builder.get_object('calendarWid') + now = datetime.now() + timeStr = now.strftime("%m/%d/%Y") + parts = timeStr.split("/") + month = int(parts[0]) - 1 + day = int(parts[1]) + year = int(parts[2]) + calendarWid.select_day(day) + calendarWid.select_month(month, year) + calendarPopup.popup() + else: + calendarPopup.popdown() + + + def showSystemStats(self, widget, eve): + if eve.type == gdk.EventType.BUTTON_RELEASE and eve.button == MouseButton.RIGHT_BUTTON: + self.builder.get_object('systemStats').popup() + + def setPagerWidget(self): + pager = wnck.Pager() + + if self.orientation == 0: + self.builder.get_object('taskBarWorkspacesHor').add(pager) + else: + self.builder.get_object('taskBarWorkspacesVer').add(pager) + + pager.show() + + + def setTasklistWidget(self): + tasklist = wnck.Tasklist() + tasklist.set_scroll_enabled(False) + tasklist.set_button_relief(2) # 0 = normal relief, 2 = no relief + tasklist.set_grouping(1) # 0 = mever group, 1 auto group, 2 = always group + + tasklist.set_orientation(self.orientation) + if self.orientation == 0: + self.builder.get_object('taskBarButtonsHor').add(tasklist) + else: + self.builder.get_object('taskBarButtonsVer').add(tasklist) + + tasklist.show() + + + # Displays Timer + def displayclock(self): + now = datetime.now() + hms = now.strftime("%I:%M %p") + mdy = now.strftime("%m/%d/%Y") + timeStr = hms + "\n" + mdy + self.timeLabel.set_label(timeStr) + return True + + # Starting or clock + def startClock(self): + GObject.timeout_add(59000, self.displayclock) + + + def closePopup(self, widget, data=None): + widget.hide() diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/__init__.py new file mode 100644 index 0000000..7df5562 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/signal_classes/mixins/__init__.py @@ -0,0 +1,4 @@ +from .MainMenuMixin import MainMenuMixin +from .TaskbarMixin import TaskbarMixin +from .CPUDrawMixin import CPUDrawMixin +from .GridMixin import GridMixin diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Dragging.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Dragging.py new file mode 100644 index 0000000..abf0a03 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Dragging.py @@ -0,0 +1,85 @@ +# Gtk imports +import gi + +gi.require_version('Gdk', '3.0') + +from gi.repository import Gdk +from gi.repository import GObject + +# Python imports +import os + +# Application imports + + +class Dragging: + def __init__(self): + # higher values make movement more performant + # lower values make movement smoother + self.SENSITIVITY = 1 + self.desktop = None + self.EvMask = Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON1_MOTION_MASK + self.offsetx = 0 + self.offsety = 0 + self.px = 0 + self.py = 0 + self.maxx = 0 + self.maxy = 0 + + def connectEvents(self, desktop, widget): + self.desktop = desktop + widget.set_events(self.EvMask) + widget.connect("button_press_event", self.press_event) + widget.connect("motion_notify_event", self.draggingEvent) + widget.show() + + def press_event(self, w, event): + if event.button == 1: + p = w.get_parent() + # offset == distance of parent widget from edge of screen ... + self.offsetx, self.offsety = p.get_window().get_position() + # plus distance from pointer to edge of widget + self.offsetx += event.x + self.offsety += event.y + # self.maxx, self.maxy both relative to the parent + # note that we're rounding down now so that these max values don't get + # rounded upward later and push the widget off the edge of its parent. + self.maxx = self.RoundDownToMultiple(p.get_allocation().width - w.get_allocation().width, self.SENSITIVITY) + self.maxy = self.RoundDownToMultiple(p.get_allocation().height - w.get_allocation().height, self.SENSITIVITY) + + + def draggingEvent(self, widget, event): + # x_root,x_root relative to screen + # x,y relative to parent (fixed widget) + # self.px,self.py stores previous values of x,y + + # get starting values for x,y + x = event.x_root - self.offsetx + y = event.y_root - self.offsety + # make sure the potential coordinates x,y: + # 1) will not push any part of the widget outside of its parent container + # 2) is a multiple of self.SENSITIVITY + x = self.RoundToNearestMultiple(self.Max(self.Min(x, self.maxx), 0), self.SENSITIVITY) + y = self.RoundToNearestMultiple(self.Max(self.Min(y, self.maxy), 0), self.SENSITIVITY) + if x != self.px or y != self.py: + self.px = x + self.py = y + self.desktop.move(widget, x, y) + + def Min(self, a, b): + if b < a: + return b + return a + + def Max(self, a, b): + if b > a: + return b + return a + + def RoundDownToMultiple(self, i, m): + return i/m*m + + def RoundToNearestMultiple(self, i, m): + if i % m > m / 2: + return (i/m+1)*m + return i/m*m diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/FileHandler.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/FileHandler.py new file mode 100644 index 0000000..3c8045d --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/FileHandler.py @@ -0,0 +1,162 @@ +# Gtk imports + +# Python imports +import os, shutil, subprocess, threading + +# Application imports + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + return wrapper + +class FileHandler: + def __init__(self, settings): + # 'Filters' + self.office = settings.returnOfficeFilter() + self.vids = settings.returnVidsFilter() + self.txt = settings.returnTextFilter() + self.music = settings.returnMusicFilter() + self.images = settings.returnImagesFilter() + self.pdf = settings.returnPdfFilter() + + # Args + self.MEDIAPLAYER = settings.returnMediaProg() + self.IMGVIEWER = settings.returnImgVwrProg() + self.MUSICPLAYER = settings.returnMusicProg() + self.OFFICEPROG = settings.returnOfficeProg() + self.TEXTVIEWER = settings.returnTextProg() + self.PDFVIEWER = settings.returnPdfProg() + self.FILEMANAGER = settings.returnFileMngrProg() + self.MPLAYER_WH = settings.returnMplyrWH() + self.MPV_WH = settings.returnMpvWHProg() + self.TRASHFILESFOLDER = settings.returnTrshFilesPth() + self.TRASHINFOFOLDER = settings.returnTrshInfoPth() + + + def openFile(self, file): + print("Opening: " + file) + DEVNULL = open(os.devnull, 'w') + + if file.lower().endswith(self.vids): + subprocess.Popen([self.MEDIAPLAYER, self.MPV_WH, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + elif file.lower().endswith(self.music): + subprocess.Popen([self.MUSICPLAYER, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + elif file.lower().endswith(self.images): + subprocess.Popen([self.IMGVIEWER, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + elif file.lower().endswith(self.txt): + subprocess.Popen([self.TEXTVIEWER, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + elif file.lower().endswith(self.pdf): + subprocess.Popen([self.PDFVIEWER, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + elif file.lower().endswith(self.office): + subprocess.Popen([self.OFFICEPROG, file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + else: + subprocess.Popen(['xdg-open', file], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) + + + def create(self, name, type): + try: + if type == True: # Create File + open(name, 'w') + else: # Create Folder + os.mkdir(name) + except Exception as e: + print( repr(e) ) + return 1 + + return 0 + + def paste(self, files, toPath, pasteType): + try: + for file in files: + parts = file.split("/") + toBePath = toPath + "/" + parts[len(parts) - 1] # Used to check for duplicates + finalForm = file + self.dedupPathIter(toBePath) + isDuplicate = finalForm != file + + if isDuplicate: + os.rename(file, finalForm) + + if pasteType == 1: # copy paste = 1 + shutil.copy2(finalForm, toPath) + if isDuplicate: + os.rename(finalForm, file) # Rename back after copy completes + if pasteType == 2: # cut paste = 2 + shutil.move(finalForm, toPath) + + except Exception as e: + print( repr(e) ) + return 1 + + return 0 + + def delete(self, toDeleteFiles): + try: + print("Deleting...") + for file in toDeleteFiles: + print(file) + if os.path.exists(file): + if os.path.isfile(file): + os.remove(file) + elif os.path.isdir(file): + shutil.rmtree(file) + else: + print("The folder/file does not exist") + return 1 + except Exception as e: + print("An error occured deleting the file:") + print( repr(e) ) + return 1 + + return 0 + + def trash(self, toTrashFiles): + try: + print("Moving to Trash...") + for file in toTrashFiles: + print(file) + if os.path.exists(file): + parts = file.split("/") + toBeTrashPath = self.TRASHFILESFOLDER + parts[len(parts) - 1] + finalForm = file + self.dedupPathIter(toBeTrashPath) + + if finalForm != file: + os.rename(file, finalForm) + + shutil.move(finalForm, self.TRASHFILESFOLDER) + else: + print("The folder/file does not exist") + return 1 + except Exception as e: + print( repr(e) ) + return 1 + + return 0 + + def rename(self, oldFileName, newFileName): + try: + if os.path.exists(oldFileName): + print("Renaming...") + print(oldFileName + " --> " + newFileName) + os.rename(oldFileName, newFileName) + else: + print("The folder/file does not exist") + return 1 + except Exception as e: + print( repr(e) ) + return 1 + + return 0 + + + def dedupPathIter(self, toBeTrashPath): + duplicateFix = "" + i = 0 + + if os.path.exists(toBeTrashPath): + while os.path.exists(toBeTrashPath + duplicateFix) == True: + i+=1 + duplicateFix = "-" + str(i) + + return duplicateFix diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Logger.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Logger.py new file mode 100644 index 0000000..c8dc0db --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Logger.py @@ -0,0 +1,55 @@ +# Python imports +import os, logging + +# Application imports + + +class Logger: + def __init__(self): + self.USER_HOME = os.path.expanduser("~") + + def get_logger(self, loggerName = "NO_LOGGER_NAME_PASSED", createFile = True): + """ + Create a new logging object and return it. + :note: + NOSET # Don't know the actual log level of this... (defaulting or literally none?) + Log Levels (From least to most) + Type Value + CRITICAL 50 + ERROR 40 + WARNING 30 + INFO 20 + DEBUG 10 + :param loggerName: Sets the name of the logger object. (Used in log lines) + :param createFile: Whether we create a log file or just pump to terminal + + :return: the logging object we created + """ + + globalLogLvl = logging.DEBUG # Keep this at highest so that handlers can filter to their desired levels + chLogLevel = logging.CRITICAL # Prety musch the only one we change ever + fhLogLevel = logging.DEBUG + log = logging.getLogger(loggerName) + + # Set our log output styles + fFormatter = logging.Formatter('[%(asctime)s] %(pathname)s:%(lineno)d %(levelname)s - %(message)s', '%m-%d %H:%M:%S') + cFormatter = logging.Formatter('%(pathname)s:%(lineno)d] %(levelname)s - %(message)s') + + ch = logging.StreamHandler() + ch.setLevel(level=chLogLevel) + ch.setFormatter(cFormatter) + log.addHandler(ch) + + if createFile: + folder = self.USER_HOME + ".config/pytop/logs" + file = folder + "/application.log" + + if not os.path.exists(folder): + os.mkdir(folder) + + fh = logging.FileHandler(file) + fh.setLevel(level=fhLogLevel) + fh.setFormatter(fFormatter) + log.addHandler(fh) + + return log diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.py new file mode 100644 index 0000000..c9c4174 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/Settings.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 + +# Python imports +import os, json + +# Application imports + + +class Settings: + def __init__(self, monIndex = 0): + self.builder = None + self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/" + + # 'Filters' + self.office = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm', + '.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf') + self.vids = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', + '.mpeg', '.mp4', '.webm') + self.txt = ('.txt', '.text', '.sh', '.cfg', '.conf') + self.music = ('.psf', '.mp3', '.ogg' , '.flac') + self.images = ('.png', '.jpg', '.jpeg', '.gif') + self.pdf = ('.pdf') + + self.hideHiddenFiles = True + self.ColumnSize = 8 + self.usrHome = os.path.expanduser('~') + self.desktopPath = self.usrHome + "/Desktop" + self.iconContainerWxH = [128, 128] + self.systemIconImageWxH = [56, 56] + self.viIconWxH = [256, 128] + self.monitors = None + + 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.TRASHFOLDER = os.path.expanduser('~') + "/.local/share/Trash/" + self.TRASHFILESFOLDER = self.TRASHFOLDER + "files/" + self.TRASHINFOFOLDER = self.TRASHFOLDER + "info/" + self.THUMB_GENERATOR = "ffmpegthumbnailer" + self.MEDIAPLAYER = "mpv"; + self.IMGVIEWER = "mirage"; + self.MUSICPLAYER = "/opt/deadbeef/bin/deadbeef"; + self.OFFICEPROG = "libreoffice"; + self.TEXTVIEWER = "leafpad"; + self.PDFVIEWER = "evince"; + self.FILEMANAGER = "spacefm"; + self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% "; + self.MPV_WH = " -geometry 50%:50% "; + self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1) + + configFolder = os.path.expanduser('~') + "/.config/pytop/" + self.configFile = configFolder + "mon_" + str(monIndex) + "_settings.ini" + + if os.path.isdir(configFolder) == False: + os.mkdir(configFolder) + + if os.path.isdir(self.TRASHFOLDER) == False: + os.mkdir(TRASHFILESFOLDER) + os.mkdir(TRASHINFOFOLDER) + + if os.path.isdir(self.TRASHFILESFOLDER) == False: + os.mkdir(TRASHFILESFOLDER) + + if os.path.isdir(self.TRASHINFOFOLDER) == False: + os.mkdir(TRASHINFOFOLDER) + + if os.path.isfile(self.configFile) == False: + open(self.configFile, 'a').close() + self.saveSettings(self.desktopPath) + + + def attachBuilder(self, builder): + self.builder = builder + self.builder.add_from_file(self.SCRIPT_PTH + "../resources/Main_Window.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(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) + + window.set_app_paintable(True) + self.monitors = self.getMonitorData(screen) + window.resize(self.monitors[0].width, self.monitors[0].height) + + 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) + "+" + str(monitor.height) + "+" + str(monitor.x) + "+" + str(monitor.y)) + + return monitors + + + def returnMonitorsInfo(self): + return self.monitors + + + def saveSettings(self, startPath): + data = {} + data['pytop_settings'] = [] + + data['pytop_settings'].append({ + 'startPath' : startPath + }) + + with open(self.configFile, 'w') as outfile: + json.dump(data, outfile) + + + def returnSettings(self): + returnData = [] + + with open(self.configFile) as infile: + try: + data = json.load(infile) + for obj in data['pytop_settings']: + returnData = [obj['startPath']] + except Exception as e: + returnData = ['~/Desktop/'] + + + if returnData[0] == '': + returnData[0] = '~/Desktop/' + + return returnData + + + def returnBuilder(self): return self.builder + def returnUserHome(self): return self.usrHome + def returnDesktopPath(self): return self.usrHome + "/Desktop" + def returnColumnSize(self): return self.ColumnSize + def returnContainerWH(self): return self.iconContainerWxH + def returnSystemIconImageWH(self): return self.systemIconImageWxH + def returnVIIconWH(self): return self.viIconWxH + def isHideHiddenFiles(self): return self.hideHiddenFiles + + # Filter returns + def returnOfficeFilter(self): return self.office + def returnVidsFilter(self): return self.vids + def returnTextFilter(self): return self.txt + def returnMusicFilter(self): return self.music + def returnImagesFilter(self): return self.images + def returnPdfFilter(self): return self.pdf + + def returnIconImagePos(self): return self.GTK_ORIENTATION + def getThumbnailGenerator(self): return self.THUMB_GENERATOR + def returnMediaProg(self): return self.MEDIAPLAYER + def returnImgVwrProg(self): return self.IMGVIEWER + def returnMusicProg(self): return self.MUSICPLAYER + def returnOfficeProg(self): return self.OFFICEPROG + def returnTextProg(self): return self.TEXTVIEWER + def returnPdfProg(self): return self.PDFVIEWER + def returnFileMngrProg(self): return self.FILEMANAGER + def returnMplyrWH(self): return self.MPLAYER_WH + def returnMpvWHProg(self): return self.MPV_WH + def returnTrshFilesPth(self): return self.TRASHFILESFOLDER + def returnTrshInfoPth(self): return self.TRASHINFOFOLDER diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py new file mode 100644 index 0000000..548f6d4 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/utils/__init__.py @@ -0,0 +1,4 @@ +from utils.Dragging import Dragging +from .Logger import Logger +from utils.FileHandler import FileHandler +from utils.Settings import Settings diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Grid.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Grid.py new file mode 100644 index 0000000..ae67fb7 --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Grid.py @@ -0,0 +1,209 @@ +# Python imports +import os, threading, time +from os.path import isdir, isfile, join +from os import listdir + + +# 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 +from gi.repository import GdkPixbuf + + +# Application imports +from .Icon import Icon +from utils.FileHandler import FileHandler + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + return wrapper + + +class Grid: + def __init__(self, grid, settings): + self.grid = grid + self.settings = settings + self.fileHandler = FileHandler(self.settings) + + self.store = gtk.ListStore(GdkPixbuf.Pixbuf, str) + self.usrHome = settings.returnUserHome() + self.hideHiddenFiles = settings.isHideHiddenFiles() + self.builder = settings.returnBuilder() + self.ColumnSize = settings.returnColumnSize() + self.vidsFilter = settings.returnVidsFilter() + self.imagesFilter = settings.returnImagesFilter() + self.iconFactory = Icon(settings) + self.selectedFiles = [] + self.currentPath = "" + + self.grid.set_model(self.store) + self.grid.set_pixbuf_column(0) + self.grid.set_text_column(1) + self.grid.connect("item-activated", self.iconDblLeftClick) + self.grid.connect("button_release_event", self.iconSingleClick, (self.grid,)) + + def setNewDirectory(self, path): + self.store.clear() + self.currentPath = path + dirPaths = ['.', '..'] + vids = [] + images = [] + desktop = [] + files = [] + + for f in listdir(path): + file = join(path, f) + if self.hideHiddenFiles: + if f.startswith('.'): + continue + + if isfile(file): + lowerName = file.lower() + + if lowerName.endswith(self.vidsFilter): + vids.append(f) + elif lowerName.endswith(self.imagesFilter): + images.append(f) + elif lowerName.endswith((".desktop",)): + desktop.append(f) + else: + files.append(f) + else: + dirPaths.append(f) + + dirPaths.sort() + vids.sort() + images.sort() + desktop.sort() + files.sort() + + files = dirPaths + vids + images + desktop + files + self.generateGridIcons(path, files) + self.fillVideoIcons(path, vids, len(dirPaths)) + + + @threaded + def generateGridIcons(self, dirPath, files): + for file in files: + image = self.iconFactory.createIcon(dirPath, file).get_pixbuf() + glib.idle_add(self.addToGrid, (image, file,)) + + + @threaded + def fillVideoIcons(self, dirPath, files, start): + model = self.grid.get_model() + + # Wait till we have a proper index... + while len(self.store) < (start + 1): + time.sleep(.650) + + i = start + for file in files: + self.updateGrid(model, dirPath, file, i) + i += 1 + + @threaded + def updateGrid(self, model, dirPath, file, i): + try: + image = self.iconFactory.createThumbnail(dirPath, file).get_pixbuf() + iter = model.get_iter_from_string(str(i)) + glib.idle_add(self.replaceInGrid, (iter, image,)) + except Exception as e: + # Errors seem to happen when fillVideoIcons index wait check is to low + print("widgets/Grid.py sinking errors on updateGrid method...") + + def addToGrid(self, dataSet): + self.store.append([dataSet[0], dataSet[1]]) + + def replaceInGrid(self, dataSet): + # Iter, row column, new pixbuf... + self.store.set_value(dataSet[0], 0 , dataSet[1]) + + + def iconDblLeftClick(self, widget, item): + try: + model = widget.get_model() + fileName = model[item][1] + dir = self.currentPath + file = dir + "/" + fileName + + if fileName == ".": + self.setNewDirectory(dir) + elif fileName == "..": + parentDir = os.path.abspath(os.path.join(dir, os.pardir)) + self.currentPath = parentDir + self.setNewDirectory(parentDir) + self.settings.saveSettings(parentDir) + elif isdir(file): + self.currentPath = file + self.setNewDirectory(self.currentPath) + self.settings.saveSettings(self.currentPath) + elif isfile(file): + self.fileHandler.openFile(file) + except Exception as e: + print(e) + + def iconSingleClick(self, widget, eve, rclicked_icon): + try: + if eve.type == gdk.EventType.BUTTON_RELEASE and eve.button == 1: + self.selectedFiles.clear() + items = widget.get_selected_items() + model = widget.get_model() + dir = self.currentPath + + for item in items: + fileName = model[item][1] + + if fileName != "." and fileName != "..": + file = dir + "/" + fileName + self.selectedFiles.append(file) # Used for return to caller + + elif eve.type == gdk.EventType.BUTTON_RELEASE and eve.button == 3: + input = self.builder.get_object("filenameInput") + controls = self.builder.get_object("iconControlsWindow") + iconsButtonBox = self.builder.get_object("iconsButtonBox") + menuButtonBox = self.builder.get_object("menuButtonBox") + + + if len(self.selectedFiles) == 1: + parts = self.selectedFiles[0].split("/") + input.set_text(parts[len(parts) - 1]) + input.show() + iconsButtonBox.show() + menuButtonBox.hide() + controls.show() + elif len(self.selectedFiles) > 1: + input.set_text("") + input.hide() + menuButtonBox.hide() + iconsButtonBox.show() + controls.show() + else: + input.set_text("") + input.show() + menuButtonBox.show() + iconsButtonBox.hide() + controls.show() + + except Exception as e: + print(e) + + def returnSelectedFiles(self): + # NOTE: Just returning selectedFiles looks like it returns a "pointer" + # to the children. This means we lose the list if any left click occures + # in this class. + files = [] + for file in self.selectedFiles: + files.append(file) + return files + + def returnCurrentPath(self): + currentPath = self.currentPath + return currentPath diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Icon.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Icon.py new file mode 100644 index 0000000..2562a9b --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/Icon.py @@ -0,0 +1,228 @@ +# Python Imports +import os, subprocess, hashlib, threading +from os.path import isdir, isfile, join + + +# 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 Gio as gio +from xdg.DesktopEntry import DesktopEntry + + +# Application imports + + + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + return wrapper + +class Icon: + def __init__(self, settings): + self.settings = settings + self.thubnailGen = settings.getThumbnailGenerator() + self.vidsList = settings.returnVidsFilter() + self.imagesList = settings.returnImagesFilter() + self.GTK_ORIENTATION = settings.returnIconImagePos() + self.usrHome = settings.returnUserHome() + self.iconContainerWH = settings.returnContainerWH() + self.systemIconImageWH = settings.returnSystemIconImageWH() + self.viIconWH = settings.returnVIIconWH() + self.SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + "/" + self.INTERNAL_ICON_PTH = self.SCRIPT_PTH + "../resources/icons/text.png" + + + def createIcon(self, dir, file): + fullPath = dir + "/" + file + return self.getIconImage(file, fullPath) + + def createThumbnail(self, dir, file): + fullPath = dir + "/" + file + try: + # Video thumbnail + if file.lower().endswith(self.vidsList): + fileHash = hashlib.sha256(str.encode(fullPath)).hexdigest() + hashImgPth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" + + if isfile(hashImgPth) == False: + self.generateVideoThumbnail(fullPath, hashImgPth) + + thumbnl = self.createScaledImage(hashImgPth, self.viIconWH) + if thumbnl == None: # If no icon whatsoever, return internal default + thumbnl = gtk.Image.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png") + + return thumbnl + except Exception as e: + print("Thumbnail generation issue:") + print( repr(e) ) + return gtk.Image.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png") + + + def getIconImage(self, file, fullPath): + try: + thumbnl = None + + # Video icon + if file.lower().endswith(self.vidsList): + thumbnl = gtk.Image.new_from_file(self.SCRIPT_PTH + "../resources/icons/video.png") + # Image Icon + elif file.lower().endswith(self.imagesList): + thumbnl = self.createScaledImage(fullPath, self.viIconWH) + # .desktop file parsing + elif fullPath.lower().endswith( ('.desktop',) ): + thumbnl = self.parseDesktopFiles(fullPath) + # System icons + else: + thumbnl = self.getSystemThumbnail(fullPath, self.systemIconImageWH[0]) + + if thumbnl == None: # If no icon whatsoever, return internal default + thumbnl = gtk.Image.new_from_file(self.INTERNAL_ICON_PTH) + + return thumbnl + except Exception as e: + print("Icon generation issue:") + print( repr(e) ) + return gtk.Image.new_from_file(self.INTERNAL_ICON_PTH) + + def parseDesktopFiles(self, fullPath): + try: + xdgObj = DesktopEntry(fullPath) + icon = xdgObj.getIcon() + altIconPath = "" + + if "steam" in icon: + steamIconsDir = self.usrHome + "/.thumbnails/steam_icons/" + name = xdgObj.getName() + fileHash = hashlib.sha256(str.encode(name)).hexdigest() + + if isdir(steamIconsDir) == False: + os.mkdir(steamIconsDir) + + hashImgPth = steamIconsDir + fileHash + ".jpg" + if isfile(hashImgPth) == True: + # Use video sizes since headers are bigger + return self.createScaledImage(hashImgPth, self.viIconWH) + + execStr = xdgObj.getExec() + parts = execStr.split("steam://rungameid/") + id = parts[len(parts) - 1] + imageLink = "https://steamcdn-a.akamaihd.net/steam/apps/" + id + "/header.jpg" + proc = subprocess.Popen(["wget", "-O", hashImgPth, imageLink]) + proc.wait() + + # Use video thumbnail sizes since headers are bigger + return self.createScaledImage(hashImgPth, self.viIconWH) + elif os.path.exists(icon): + return self.createScaledImage(icon, self.systemIconImageWH) + else: + iconsDirs = ["/usr/share/pixmaps", "/usr/share/icons", self.usrHome + "/.icons" ,] + altIconPath = "" + + for iconsDir in iconsDirs: + altIconPath = self.traverseIconsFolder(iconsDir, icon) + if altIconPath is not "": + break + + return self.createScaledImage(altIconPath, self.systemIconImageWH) + except Exception as e: + print(".desktop icon generation issue:") + print( repr(e) ) + return None + + + def traverseIconsFolder(self, path, icon): + altIconPath = "" + + for (dirpath, dirnames, filenames) in os.walk(path): + for file in filenames: + appNM = "application-x-" + icon + if icon in file or appNM in file: + altIconPath = dirpath + "/" + file + break + + return altIconPath + + + def getSystemThumbnail(self, filename, size): + try: + if os.path.exists(filename): + gioFile = gio.File.new_for_path(filename) + info = gioFile.query_info('standard::icon' , 0, gio.Cancellable()) + icon = info.get_icon().get_names()[0] + iconTheme = gtk.IconTheme.get_default() + iconData = iconTheme.lookup_icon(icon , size , 0) + if iconData: + iconPath = iconData.get_filename() + return gtk.Image.new_from_file(iconPath) # This seems to cause a lot of core dump issues... + else: + return None + else: + return None + except Exception as e: + print("system icon generation issue:") + print( repr(e) ) + return None + + + def createScaledImage(self, path, wxh): + try: + pixbuf = gtk.Image.new_from_file(path).get_pixbuf() + scaledPixBuf = pixbuf.scale_simple(wxh[0], wxh[1], 2) # 2 = BILINEAR and is best by default + return gtk.Image.new_from_pixbuf(scaledPixBuf) + except Exception as e: + print("Image Scaling Issue:") + print( repr(e) ) + return None + + def createFromFile(self, path): + try: + return gtk.Image.new_from_file(path) + except Exception as e: + print("Image from file Issue:") + print( repr(e) ) + return None + + def returnGenericIcon(self): + return gtk.Image.new_from_file(self.INTERNAL_ICON_PTH) + + + def generateVideoThumbnail(self, fullPath, hashImgPth): + proc = None + try: + # Stream duration + command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath] + data = subprocess.run(command, stdout=subprocess.PIPE) + duration = data.stdout.decode('utf-8') + + # Format (container) duration + if "N/A" in duration: + command = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath] + data = subprocess.run(command , stdout=subprocess.PIPE) + duration = data.stdout.decode('utf-8') + + # Stream duration type: image2 + if "N/A" in duration: + command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-f", "image2", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath] + data = subprocess.run(command, stdout=subprocess.PIPE) + duration = data.stdout.decode('utf-8') + + # Format (container) duration type: image2 + if "N/A" in duration: + command = ["ffprobe", "-v", "error", "-f", "image2", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPath] + data = subprocess.run(command , stdout=subprocess.PIPE) + duration = data.stdout.decode('utf-8') + + # Get frame roughly 35% through video + grabTime = str( int( float( duration.split(".")[0] ) * 0.35) ) + command = ["ffmpeg", "-ss", grabTime, "-an", "-i", fullPath, "-s", "320x180", "-vframes", "1", hashImgPth] + proc = subprocess.Popen(command, stdout=subprocess.PIPE) + proc.wait() + except Exception as e: + print("Video thumbnail generation issue in thread:") + print( repr(e) ) diff --git a/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/__init__.py b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/__init__.py new file mode 100644 index 0000000..148c91c --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/opt/Pytop/widgets/__init__.py @@ -0,0 +1,2 @@ +from widgets.Grid import Grid +from widgets.Icon import Icon diff --git a/src/debs/pytop-0-0-1-x64/usr/share/doc/pytop/copyright b/src/debs/pytop-0-0-1-x64/usr/share/doc/pytop/copyright new file mode 100644 index 0000000..04b188e --- /dev/null +++ b/src/debs/pytop-0-0-1-x64/usr/share/doc/pytop/copyright @@ -0,0 +1,22 @@ +Pytop is copyright 2019 Maxim Stewart. +Pytop is currently developed by ITDominator <1itdominator@gmail.com>. + +License: GPLv2+ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +See /usr/share/common-licenses/GPL-2, or + for the terms of the latest version +of the GNU General Public License.