diff --git a/README.md b/README.md index cce5bf5..f75c6bf 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ It includes the XWinWrap binary and source code for Shantanu Goel's version of X # Notes * Need python 2+ +* Need PyGObject * When you first run the application and save settings for a screen, you need to chmod 744 the new file(s) in your $HOME directory. * A settings file per screen is generated. diff --git a/bin/gwinwrap-0-0-2-x64.deb b/bin/gwinwrap-0-0-2-x64.deb new file mode 100644 index 0000000..0bb7b17 Binary files /dev/null and b/bin/gwinwrap-0-0-2-x64.deb differ diff --git a/src/GWinWrap/GWinWrap.desktop b/src/versions/0.0.1/GWinWrap/GWinWrap.desktop similarity index 100% rename from src/GWinWrap/GWinWrap.desktop rename to src/versions/0.0.1/GWinWrap/GWinWrap.desktop diff --git a/src/GWinWrap/__init__.py b/src/versions/0.0.1/GWinWrap/__init__.py similarity index 100% rename from src/GWinWrap/__init__.py rename to src/versions/0.0.1/GWinWrap/__init__.py diff --git a/src/GWinWrap/__main__.py b/src/versions/0.0.1/GWinWrap/__main__.py similarity index 100% rename from src/GWinWrap/__main__.py rename to src/versions/0.0.1/GWinWrap/__main__.py diff --git a/src/GWinWrap/resources/Main_Window.glade b/src/versions/0.0.1/GWinWrap/resources/Main_Window.glade similarity index 99% rename from src/GWinWrap/resources/Main_Window.glade rename to src/versions/0.0.1/GWinWrap/resources/Main_Window.glade index e0d1930..495ebfe 100644 --- a/src/GWinWrap/resources/Main_Window.glade +++ b/src/versions/0.0.1/GWinWrap/resources/Main_Window.glade @@ -435,6 +435,7 @@ .animatedBGstarter.sh .animatedBGstarter2.sh + .animatedBGstarter3.sh diff --git a/src/GWinWrap/resources/icons/GWinWrap.png b/src/versions/0.0.1/GWinWrap/resources/icons/GWinWrap.png similarity index 100% rename from src/GWinWrap/resources/icons/GWinWrap.png rename to src/versions/0.0.1/GWinWrap/resources/icons/GWinWrap.png diff --git a/src/GWinWrap/resources/icons/folder.png b/src/versions/0.0.1/GWinWrap/resources/icons/folder.png similarity index 100% rename from src/GWinWrap/resources/icons/folder.png rename to src/versions/0.0.1/GWinWrap/resources/icons/folder.png diff --git a/src/GWinWrap/resources/icons/picture.png b/src/versions/0.0.1/GWinWrap/resources/icons/picture.png similarity index 100% rename from src/GWinWrap/resources/icons/picture.png rename to src/versions/0.0.1/GWinWrap/resources/icons/picture.png diff --git a/src/GWinWrap/resources/icons/player.png b/src/versions/0.0.1/GWinWrap/resources/icons/player.png similarity index 100% rename from src/GWinWrap/resources/icons/player.png rename to src/versions/0.0.1/GWinWrap/resources/icons/player.png diff --git a/src/GWinWrap/resources/stylesheet.css b/src/versions/0.0.1/GWinWrap/resources/stylesheet.css similarity index 100% rename from src/GWinWrap/resources/stylesheet.css rename to src/versions/0.0.1/GWinWrap/resources/stylesheet.css diff --git a/src/GWinWrap/signal_classes/CrossClassSignals.py b/src/versions/0.0.1/GWinWrap/signal_classes/CrossClassSignals.py similarity index 87% rename from src/GWinWrap/signal_classes/CrossClassSignals.py rename to src/versions/0.0.1/GWinWrap/signal_classes/CrossClassSignals.py index 2654eb9..6cbbb7e 100644 --- a/src/GWinWrap/signal_classes/CrossClassSignals.py +++ b/src/versions/0.0.1/GWinWrap/signal_classes/CrossClassSignals.py @@ -84,7 +84,6 @@ class CrossClassSignals: dir = widget.get_filename() threading.Thread(target=self.newDir, args=(dir,)).start() - @threaded def newDir(self, dir): imageGrid = self.builder.get_object("imageGrid") dirPath = dir @@ -97,41 +96,15 @@ class CrossClassSignals: if file.lower().endswith(('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm', '.png', '.jpg', '.jpeg', '.gif')): files.append(file) - fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) - tickCount = 0.0 + # fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) + # tickCount = 0.0 self.clear() imageGrid.remove_column(0) self.loadProgress.set_text("Loading...") self.loadProgress.set_fraction(0.0) self.helpLabel.set_markup("" + dirPath.strip(self.usrHome) + "") for file in files: - fullPathFile = dirPath + "/" + file - eveBox = gtk.EventBox() - thumbnl = gtk.Image() - - if file.lower().endswith(('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')): - fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() - hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" - if isfile(hashImgpth) == False: - self.generateThumbnail(fullPathFile, hashImgpth) - - thumbnl = self.createGtkImage(hashImgpth, [310, 310]) - eveBox.connect("button_press_event", self.runMplayerProcess, (fullPathFile, file, eveBox,)) - eveBox.connect("enter_notify_event", self.mouseOver, ()) - eveBox.connect("leave_notify_event", self.mouseOut, ()) - elif file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')): - thumbnl = self.createGtkImage(fullPathFile, [310, 310]) - eveBox.connect("button_press_event", self.runImageViewerProcess, (fullPathFile, file, eveBox,)) - eveBox.connect("enter_notify_event", self.mouseOver, ()) - eveBox.connect("leave_notify_event", self.mouseOut, ()) - else: - print("Not a video or image file.") - continue - - glib.idle_add(self.preGridSetup, (eveBox, thumbnl, )) - glib.idle_add(self.addToGrid, (imageGrid, eveBox, col, row,)) - tickCount = tickCount + fractionTick - self.loadProgress.set_fraction(tickCount) + self.porocess_file(imageGrid, dirPath, file, col, row) col += 1 if col == 2: @@ -140,6 +113,39 @@ class CrossClassSignals: self.loadProgress.set_text("Finished...") + @threaded + def porocess_file(self, imageGrid, dirPath, file, col, row): + fullPathFile = dirPath + "/" + file + eveBox = gtk.EventBox() + thumbnl = gtk.Image() + + if file.lower().endswith(('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')): + fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() + hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" + if isfile(hashImgpth) == False: + self.generateThumbnail(fullPathFile, hashImgpth) + + thumbnl = self.createGtkImage(hashImgpth, [310, 310]) + eveBox.connect("button_press_event", self.runMplayerProcess, (fullPathFile, file, eveBox,)) + eveBox.connect("enter_notify_event", self.mouseOver, ()) + eveBox.connect("leave_notify_event", self.mouseOut, ()) + elif file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')): + thumbnl = self.createGtkImage(fullPathFile, [310, 310]) + eveBox.connect("button_press_event", self.runImageViewerProcess, (fullPathFile, file, eveBox,)) + eveBox.connect("enter_notify_event", self.mouseOver, ()) + eveBox.connect("leave_notify_event", self.mouseOut, ()) + else: + print("Not a video or image file.") + return + + glib.idle_add(self.preGridSetup, (eveBox, thumbnl, )) + glib.idle_add(self.addToGrid, (imageGrid, eveBox, col, row,)) + # tickCount = tickCount + fractionTick + # self.loadProgress.set_fraction(tickCount) + + + + def preGridSetup(self, args): args[0].show() args[1].show() @@ -267,7 +273,7 @@ class CrossClassSignals: offset4Res = self.builder.get_object("posOffset") resolution = plyBckRes.get_active_text() + offset4Res.get_active_text() self.applyType = self.stateSaver.saveToFile(self.toSavePath, resolution, - saveLoc, useXscreenSaver, self.xScreenVal) + saveLoc, useXscreenSaver, self.xScreenVal, self.player) if self.applyType == -1: self.helpLabel.set_markup("Nothing saved...") return @@ -277,8 +283,11 @@ class CrossClassSignals: def applySttngs(self, widget, data=None): os.system("killall xwinwrap &") if self.applyType == 1: - os.system("bash -c '~/.animatedBGstarter.sh' &") - os.system("bash -c '~/.animatedBGstarter2.sh' &") + files = os.listdir(self.usrHome) + for file in files: + fPath = self.usrHome + "/" + file + if os.path.isfile(fPath) and "animatedBGstarter" in file: + os.system("bash -c '~/" + file + "' &") elif self.applyType == 2: os.system("nitrogen --restore &") else: diff --git a/src/GWinWrap/signal_classes/__init__.py b/src/versions/0.0.1/GWinWrap/signal_classes/__init__.py similarity index 100% rename from src/GWinWrap/signal_classes/__init__.py rename to src/versions/0.0.1/GWinWrap/signal_classes/__init__.py diff --git a/src/GWinWrap/utils/SaveGWinWrapSettings.py b/src/versions/0.0.1/GWinWrap/utils/SaveGWinWrapSettings.py similarity index 100% rename from src/GWinWrap/utils/SaveGWinWrapSettings.py rename to src/versions/0.0.1/GWinWrap/utils/SaveGWinWrapSettings.py diff --git a/src/GWinWrap/utils/SaveStateToXWinWarp.py b/src/versions/0.0.1/GWinWrap/utils/SaveStateToXWinWarp.py similarity index 73% rename from src/GWinWrap/utils/SaveStateToXWinWarp.py rename to src/versions/0.0.1/GWinWrap/utils/SaveStateToXWinWarp.py index ee0045d..1e086be 100644 --- a/src/GWinWrap/utils/SaveStateToXWinWarp.py +++ b/src/versions/0.0.1/GWinWrap/utils/SaveStateToXWinWarp.py @@ -5,24 +5,27 @@ import os class SaveStateToXWinWarp: def __init__(self): self.fileWriter = None - self.toSavePath = None + self.toSavePath = None self.useXSvrn = None self.xScreenVal = None self.sveFileLoc = None self.resolution = None + self.player = None + def saveToFile(self, toSavePath, resolution, - saveLoc, useXSvrn, xScreenVal): + saveLoc, useXSvrn, xScreenVal, player): self.toSavePath = toSavePath self.useXSvrn = useXSvrn self.xScreenVal = xScreenVal self.resolution = resolution + self.player = player userPth = os.path.expanduser('~') # Saves to file with selected and needed settings if toSavePath: - if toSavePath.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')): + if toSavePath.lower().endswith(('.png', '.jpg', '.jpeg')): self.sveFileLoc = userPth + "/" + ".config/nitrogen/bg-saved.cfg" else: self.sveFileLoc = userPth + "/" + saveLoc @@ -40,9 +43,6 @@ class SaveStateToXWinWarp: applyType = 1 output = None - print("XScreen: " + str(self.useXSvrn)) - print(self.fileWriter) - # XSCREENSAVER if self.useXSvrn: output = "xwinwrap -ov -g " + self.resolution + " -st -sp -b -nf -s -ni -- /usr/lib/xscreensaver/" + self.xScreenVal + " -window-id WID -root"; @@ -51,15 +51,19 @@ class SaveStateToXWinWarp: output = "xwinwrap -ov -g " + self.resolution + " -st -sp -b -nf -s -ni -- gifview -a -w WID " + self.toSavePath; # Standard images using nitrogen elif self.toSavePath.lower().endswith(('.png', 'jpg', '.jpeg')): - output = "[xin_0] \n file=" + self.toSavePath + "\nmode=0 \nbgcolor=#000000\n[xin_1] \nfile=" + self.toSavePath + "\nmode=0 \nbgcolor=#000000"; + output = "[xin_0] \nfile=" + self.toSavePath + "\nmode=0 \nbgcolor=#000000\n\n[xin_1] \nfile=" + self.toSavePath + "\nmode=0 \nbgcolor=#000000"; applyType = 2; # VIDEO else: - output = "xwinwrap -ov -g " + self.resolution + " -st -sp -b -nf -s -ni -- mplayer -wid WID -really-quiet -ao null -loop 0 '" + self.toSavePath + "'"; + output = "xwinwrap -ov -g " + self.resolution + " -st -sp -b -nf -s -ni -- " + self.player + " -wid WID -really-quiet -ao null -loop 0 '" + self.toSavePath + "'"; pass - if self.fileWriter: - self.fileWriter.write(output) - self.fileWriter.close() + try: + if self.fileWriter: + self.fileWriter.write(output) + self.fileWriter.close() + except Exception as e: + print(":: Write failed! ::") + print(e) return applyType; diff --git a/src/GWinWrap/utils/Settings.py b/src/versions/0.0.1/GWinWrap/utils/Settings.py similarity index 95% rename from src/GWinWrap/utils/Settings.py rename to src/versions/0.0.1/GWinWrap/utils/Settings.py index 1f5479f..8ffc52a 100644 --- a/src/GWinWrap/utils/Settings.py +++ b/src/versions/0.0.1/GWinWrap/utils/Settings.py @@ -58,7 +58,7 @@ class Settings: 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)) + print("{}x{}+{}+{}".format(monitor.width, monitor.height, monitor.x, monitor.y)) return monitors diff --git a/src/GWinWrap/utils/__init__.py b/src/versions/0.0.1/GWinWrap/utils/__init__.py similarity index 100% rename from src/GWinWrap/utils/__init__.py rename to src/versions/0.0.1/GWinWrap/utils/__init__.py diff --git a/src/XWinWrap/Makefile b/src/versions/0.0.1/XWinWrap/Makefile similarity index 100% rename from src/XWinWrap/Makefile rename to src/versions/0.0.1/XWinWrap/Makefile diff --git a/src/XWinWrap/xwinwrap.c b/src/versions/0.0.1/XWinWrap/xwinwrap.c similarity index 100% rename from src/XWinWrap/xwinwrap.c rename to src/versions/0.0.1/XWinWrap/xwinwrap.c diff --git a/src/compileBin.sh b/src/versions/0.0.1/compileBin.sh similarity index 100% rename from src/compileBin.sh rename to src/versions/0.0.1/compileBin.sh diff --git a/src/gwinwrap_exec_bin.cpp b/src/versions/0.0.1/gwinwrap_exec_bin.cpp similarity index 100% rename from src/gwinwrap_exec_bin.cpp rename to src/versions/0.0.1/gwinwrap_exec_bin.cpp diff --git a/src/versions/0.0.2/GWinWrap/__builtins__.py b/src/versions/0.0.2/GWinWrap/__builtins__.py new file mode 100644 index 0000000..287a5fb --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/__builtins__.py @@ -0,0 +1,73 @@ +import builtins + +# Python imports +import builtins + +# Lib imports + +# Application imports +from signal_classes import IPCServerMixin + + + +class Builtins(IPCServerMixin): + """Docstring for __builtins__ extender""" + + def __init__(self): + # NOTE: The format used is list of [type, target, data] + # Where data may be any kind of data + self._gui_events = [] + self._fm_events = [] + self.is_ipc_alive = False + self.ipc_authkey = b'GWinWrap-ipc' + self.ipc_address = '127.0.0.1' + self.ipc_port = 8888 + self.ipc_timeout = 15.0 + + # Makeshift fake "events" type system FIFO + def _pop_gui_event(self): + if len(self._gui_events) > 0: + return self._gui_events.pop(0) + return None + + def _pop_fm_event(self): + if len(self._fm_events) > 0: + return self._fm_events.pop(0) + return None + + + def push_gui_event(self, event): + if len(event) == 3: + self._gui_events.append(event) + return None + + raise Exception("Invald event format! Please do: [type, target, data]") + + def push_fm_event(self, event): + if len(event) == 3: + self._fm_events.append(event) + return None + + raise Exception("Invald event format! Please do: [type, target, data]") + + def read_gui_event(self): + return self._gui_events[0] + + def read_fm_event(self): + return self._fm_events[0] + + def consume_gui_event(self): + return self._pop_gui_event() + + def consume_fm_event(self): + return self._pop_fm_event() + + + +# NOTE: Just reminding myself we can add to builtins two different ways... +# __builtins__.update({"event_system": Builtins()}) +builtins.app_name = "GWinWrap" +builtins.event_system = Builtins() +builtins.event_sleep_time = 0.2 +builtins.debug = False +builtins.trace_debug = False diff --git a/src/versions/0.0.2/GWinWrap/__init__.py b/src/versions/0.0.2/GWinWrap/__init__.py new file mode 100644 index 0000000..56356ba --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/__init__.py @@ -0,0 +1,50 @@ +# Python imports +import os, inspect, time + +# Lib imports + +# Application imports +from utils import Settings +from signal_classes import Controller +from __builtins__ import Builtins + + + + +class Main(Builtins): + def __init__(self, args, unknownargs): + if not debug: + event_system.create_ipc_server() + + time.sleep(0.2) + if not trace_debug: + if not event_system.is_ipc_alive: + if unknownargs: + for arg in unknownargs: + if os.path.isdir(arg): + message = f"FILE|{arg}" + event_system.send_ipc_message(message) + + raise Exception("IPC Server Exists: Will send data to it and close...") + + + settings = Settings() + settings.create_window() + + controller = Controller(settings, args, unknownargs) + if not controller: + raise Exception("Controller exited and doesn't exist...") + + # Gets the methods from the classes and sets to handler. + # Then, builder from settings will connect to any signals it needs. + classes = [controller] + handlers = {} + for c in classes: + methods = None + try: + methods = inspect.getmembers(c, predicate=inspect.ismethod) + handlers.update(methods) + except Exception as e: + print(repr(e)) + + settings.get_builder().connect_signals(handlers) diff --git a/src/versions/0.0.2/GWinWrap/__main__.py b/src/versions/0.0.2/GWinWrap/__main__.py new file mode 100644 index 0000000..dc06b1a --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/__main__.py @@ -0,0 +1,39 @@ +#!/usr/bin/python3 + + +# Python imports +import argparse, faulthandler, traceback +from setproctitle import setproctitle + +import tracemalloc +tracemalloc.start() + + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports +from __init__ import Main + + +if __name__ == "__main__": + try: + # import web_pdb + # web_pdb.set_trace() + + setproctitle('GWinWrap') + 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, unknownargs = parser.parse_known_args() + + Main(args, unknownargs) + Gtk.main() + except Exception as e: + traceback.print_exc() + quit() diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/Controller.py b/src/versions/0.0.2/GWinWrap/signal_classes/Controller.py new file mode 100644 index 0000000..adcb743 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/Controller.py @@ -0,0 +1,151 @@ +# Python imports +import threading, signal, subprocess, inspect, os, time + +# Gtk imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk, GLib, Gdk + +# Application imports +from .mixins import * +from . import Controller_Data + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + + return wrapper + + +class Controller(ThumbnailMixin, ImageViewerMixin, DrawAreaMixin, GridMixin, Controller_Data): + def __init__(self, _settings, args, unknownargs): + self.setup_controller_data(_settings) + self.window.show() + self.retrieve_settings() + + + def tear_down(self, widget=None, eve=None): + event_system.send_ipc_message("close server") + if self.demo_area_pid: + self.close_demo_popup() + + self.close_image_popup() + time.sleep(event_sleep_time) + Gtk.main_quit() + + def close_program(self, widget, data=None): + self.tear_down() + + + @threaded + def gui_event_observer(self): + while True: + time.sleep(event_sleep_time) + event = event_system.consume_gui_event() + if event: + try: + type, target, data = event + method = getattr(self.__class__, type) + GLib.idle_add(method, (self, data,)) + except Exception as e: + print(repr(e)) + + + + def apply_settings(self, widget, data=None): + os.system("killall xwinwrap &") + user_home = self.settings.get_home_path() + + if self.apply_type == 1: + files = os.listdir(user_home) + for file in files: + fPath = f"{user_home}/{file}" + if os.path.isfile(fPath) and "animatedBGstarter" in file: + os.system(f"bash -c '~/{file}' &") + elif self.apply_type == 2: + os.system("nitrogen --restore &") + else: + os.system("nitrogen --restore &") + + self.help_label.set_markup(self.appliedLabel) + + def save_to_settings_file(self, widget): + self.start_path = self.builder.get_object("customStartPath").get_text().strip() + self.default_player = self.builder.get_object("customVideoPlayer").get_text().strip() + self.default_img_viewer = self.builder.get_object("customImgViewer").get_text().strip() + + self.settings_saver.save_settings(self.start_path, self.default_player, self.default_img_viewer) + + def save_to_file(self, widget, data=None): + save_location = self.builder.get_object("saveLoc").get_active_text() + use_xscreensvr = self.builder.get_object("useXScrnList").get_active() + playBackRes = self.builder.get_object("playbackResolution") + monitorOffset = self.builder.get_object("monitorOffsetData") + resolution = playBackRes.get_active_text() + monitorOffset.get_active_text() + self.apply_type = self.state_saver.save_to_file(self.to_be_background, resolution, save_location, use_xscreensvr, self.xscreen_value, self.default_player) + + if self.apply_type == -1: + self.help_label.set_markup("Nothing saved...") + return + + self.help_label.set_markup(self.savedLabel) + + + def toggle_xscreen_list(self, widget, data=None): + use_xscreensvr = self.builder.get_object("useXScrnList") + if use_xscreensvr.get_active(): + self.builder.get_object("xScreenSvrList").set_sensitive(True) + else: + self.builder.get_object("xScreenSvrList").set_sensitive(False) + + def show_settings_popup(self, widget): + self.builder.get_object("settingsWindow").popup() + + + def preview_xscreensaver(self, widget, eve): + if eve.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: + demoXscrnSaver = self.xscreensavers + self.xscreen_value + xid = self.getXID() + command = [demoXscrnSaver, "-window-id", str(xid)] + self.run_demo_in_draw_area(command) + + def pass_xscreen_value(self, widget): + row = widget.get_cursor() + path = Gtk.TreePath(row.path) + treeiter = self.xscreen_store.get_iter(path[0]) + self.xscreen_value = self.xscreen_store.get_value(treeiter, 0) + + def kill_xwinwrap(self, widget, data=None): + os.system("killall xwinwrap &") + self.help_label.set_markup(self.stoppedLabel) + + def set_selected_eve_box(self, eveBox): + if self.selected_eve_box: + color = Gdk.RGBA(0.0, 0.0, 0.0, 0.0) + self.selected_eve_box.override_background_color(Gtk.StateType.NORMAL, color) + + color = Gdk.RGBA(0.9, 0.7, 0.4, 0.74) + eveBox.override_background_color(Gtk.StateType.NORMAL, color) + self.selected_eve_box = eveBox + + def mouse_over(self, widget, eve, args): + hand_cursor = Gdk.Cursor(Gdk.CursorType.HAND2) + self.window.get_window().set_cursor(hand_cursor) + + def mouse_out(self, widget, eve, args): + watch_cursor = Gdk.Cursor(Gdk.CursorType.LEFT_PTR) + self.window.get_window().set_cursor(watch_cursor) + + def get_clipboard_data(self): + proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE) + retcode = proc.wait() + data = proc.stdout.read() + return data.decode("utf-8").strip() + + def set_clipboard_data(self, data): + proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE) + proc.stdin.write(data) + proc.stdin.close() + retcode = proc.wait() diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/Controller_Data.py b/src/versions/0.0.2/GWinWrap/signal_classes/Controller_Data.py new file mode 100644 index 0000000..e651a46 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/Controller_Data.py @@ -0,0 +1,102 @@ +# Python imports +import signal +from os import listdir +from os.path import isfile, join + +# Lib imports +from gi.repository import GLib + +# Application imports +from . import SaveStateToXWinWarp, SaveGWinWrapSettings + + + +class Controller_Data: + def has_method(self, obj, name): + return callable(getattr(obj, name, None)) + + def setup_controller_data(self, _settings): + self.settings = _settings + self.state_saver = SaveStateToXWinWarp(_settings) + self.settings_saver = SaveGWinWrapSettings(_settings) + + + self.builder = self.settings.get_builder() + self.window = self.settings.get_main_window() + self.logger = self.settings.get_logger() + + self.home_path = self.settings.get_home_path() + self.success_color = self.settings.get_success_color() + self.warning_color = self.settings.get_warning_color() + self.error_color = self.settings.get_error_color() + + + self.image_grid = self.builder.get_object("imageGrid") + self.grid_label = self.builder.get_object("gridLabel") + self.help_label = self.builder.get_object("helpLabel") + self.xscreen_store = self.builder.get_object("XScreensaverStore") + + self.defaultLabel = "Note: Double click an image to view the video or image." + self.savedLabel = f"Saved settings..." + self.appliedLabel = f"Running xwinwrap..." + self.stoppedLabel = f"Stopped xwinwrap..." + + # Add filter to allow only folders to be selected + dialog = self.builder.get_object("selectedDirDialog") + file_filter = self.builder.get_object("Folders") + dialog.add_filter(file_filter) + + self.xscreensavers = self.settings.get_xscreensavers() + list = [f for f in listdir(self.xscreensavers) if isfile(join(self.xscreensavers , f))] + list.sort() + for file in list: + self.xscreen_store.append((file,)) + + + self.selected_eve_box = None + self.start_path = None + self.default_player = None + self.default_img_viewer = None + self.demo_area_pid = None + + self.apply_type = 1 # 1 is XWinWrap and 2 is Nitrogen + self.xscreen_value = None + self.to_be_background = None # Global file path and type for saving to file + + + self.window.connect("delete-event", self.tear_down) + GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down) + + self.set_monitor_offset_data() + self.retrieve_settings() + + + def set_monitor_offset_data(self): + monitors = self.settings.get_monitor_data() + monitorOffsetData = self.builder.get_object("monitorOffsetData") + + for monitor in monitors: + if monitor.x >= 0 and monitor.y >= 0: + monitorOffsetData.append_text("+" + str(monitor.x) + "+" + str(monitor.y)) + elif monitor.x <= 0 and monitor.y <= 0: + monitorOffsetData.append_text(str(monitor.x) + str(monitor.y)) + elif monitor.x >= 0 and monitor.y <= 0: + monitorOffsetData.append_text("+" + str(monitor.x) + str(monitor.y)) + elif monitor.x <= 0 and monitor.y >= 0: + monitorOffsetData.append_text(str(monitor.x) + "+" + str(monitor.y)) + + monitorOffsetData.set_active(0) + + def retrieve_settings(self): + data = self.settings_saver.retrieve_settings() + self.start_path = data[0] + self.default_player = data[1] + self.default_img_viewer = data[2] + + self.builder.get_object("customStartPath").set_text(self.start_path) + self.builder.get_object("customVideoPlayer").set_text(self.default_player) + self.builder.get_object("customImgViewer").set_text(self.default_img_viewer) + self.builder.get_object("selectedDirDialog").set_filename(self.start_path) + + if self.start_path: + self.load_path(None, self.start_path) diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/IPCServerMixin.py b/src/versions/0.0.2/GWinWrap/signal_classes/IPCServerMixin.py new file mode 100644 index 0000000..be92ace --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/IPCServerMixin.py @@ -0,0 +1,64 @@ +# Python imports +import threading, socket, time +from multiprocessing.connection import Listener, Client + +# Lib imports + +# Application imports + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start() + return wrapper + + + + +class IPCServerMixin: + + @threaded + def create_ipc_server(self): + listener = Listener((self.ipc_address, self.ipc_port), authkey=self.ipc_authkey) + self.is_ipc_alive = True + while True: + conn = listener.accept() + start_time = time.time() + + print(f"New Connection: {listener.last_accepted}") + while True: + msg = conn.recv() + if debug: + print(msg) + + if "FILE|" in msg: + file = msg.split("FILE|")[1].strip() + if file: + event_system.push_gui_event(["create_tab_from_ipc", None, file]) + + conn.close() + break + + + if msg == 'close connection': + conn.close() + break + if msg == 'close server': + conn.close() + break + + # NOTE: Not perfect but insures we don't lockup the connection for too long. + end_time = time.time() + if (end - start) > self.ipc_timeout: + conn.close() + + listener.close() + + + def send_ipc_message(self, message="Empty Data..."): + try: + conn = Client((self.ipc_address, self.ipc_port), authkey=self.ipc_authkey) + conn.send(message) + conn.send('close connection') + except Exception as e: + print(repr(e)) diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/SaveGWinWrapSettings.py b/src/versions/0.0.2/GWinWrap/signal_classes/SaveGWinWrapSettings.py new file mode 100644 index 0000000..38025a1 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/SaveGWinWrapSettings.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +import os, json + +class SaveGWinWrapSettings: + def __init__(self, settings): + self.config_file = settings.get_config_file() + + if os.path.isfile(self.config_file) == False: + open(self.config_file, 'a').close() + + + def save_settings(self, start_path, default_player, default_img_viewer): + data = {} + data['settings'] = [] + + data['settings'].append({ + 'start_path': start_path, + 'default_player': default_player, + 'default_img_viewer': default_img_viewer + }) + + with open(self.config_file, 'w') as outfile: + json.dump(data, outfile, separators=(',', ':'), indent=4) + + + def retrieve_settings(self): + data = [] + + with open(self.config_file) as infile: + try: + _data = json.load(infile) + for obj in _data['settings']: + data = [obj['start_path'], obj['default_player'], obj['default_img_viewer']] + except Exception as e: + print(repr(e)) + data = ['', 'mplayer', 'xdg-open'] + + + if data[0] == '': + data[0] = '' + + if data[1] == '': + data[1] = 'mplayer' + + if data[2] == '': + data[2] = 'xdg-open' + + return data diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/SaveStateToXWinWarp.py b/src/versions/0.0.2/GWinWrap/signal_classes/SaveStateToXWinWarp.py new file mode 100644 index 0000000..14ff763 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/SaveStateToXWinWarp.py @@ -0,0 +1,68 @@ + +class SaveStateToXWinWarp: + def __init__(self, _settings): + self.settings = _settings + self.user_home = self.settings.get_home_path() + + self._file_writer = None + self._to_be_background = None + self._use_xscreensvr = None + self._xscreen_value = None + self._save_file_target = None + self._resolution = None + self._player = None + + + def save_to_file(self, to_be_background, resolution, save_location, + use_xscreensvr, xscreen_value, player): + + self._to_be_background = to_be_background + self._use_xscreensvr = use_xscreensvr + self._xscreen_value = xscreen_value + self._resolution = resolution + self._player = player + + # Saves to file with selected and needed settings + if to_be_background: + if to_be_background.lower().endswith(self.settings.get_images_filter()): + self._save_file_target = f"{self.user_home}/.config/nitrogen/bg-saved.cfg" + else: + self._save_file_target = f"{self.user_home}/{save_location}" + elif use_xscreensvr and xscreen_value: + self._save_file_target = f"{self.user_home}/{save_location}" + else: + return -1 + + if self._save_file_target: + self._file_writer = open(self._save_file_target, "w") + + return self.save() + + def save(self): + applyType = 1 + output = None + + # XSCREENSAVER + if self._use_xscreensvr: + output = f"xwinwrap -ov -g {self._resolution} -st -sp -b -nf -s -ni -- /usr/lib/xscreensaver/{self._xscreen_value} -window-id WID -root"; + # GIF + elif self._to_be_background.lower().endswith(('.gif')): + output = f"xwinwrap -ov -g {self._resolution} -st -sp -b -nf -s -ni -- gifview -a -w WID {self._to_be_background}"; + # Standard images using nitrogen + elif self._to_be_background.lower().endswith(('.png', 'jpg', '.jpeg')): + output = f"[xin_0] \nfile={self._to_be_background}\nmode=0 \nbgcolor=#000000\n\n[xin_1] \nfile={self._to_be_background}\nmode=0 \nbgcolor=#000000"; + applyType = 2; + # VIDEO + else: + output = f"xwinwrap -ov -g {self._resolution} -st -sp -b -nf -s -ni -- {self._player} -wid WID -really-quiet -ao null -loop 0 '{self._to_be_background}'"; + pass + + try: + if self._file_writer: + self._file_writer.write(output) + self._file_writer.close() + except Exception as e: + print(":: Write failed! ::") + print(e) + + return applyType; diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/__init__.py b/src/versions/0.0.2/GWinWrap/signal_classes/__init__.py new file mode 100644 index 0000000..97a8b3b --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/__init__.py @@ -0,0 +1,9 @@ +""" + Gtk Bound Signal Module +""" +from .mixins import * +from .SaveStateToXWinWarp import SaveStateToXWinWarp +from .SaveGWinWrapSettings import SaveGWinWrapSettings +from .IPCServerMixin import IPCServerMixin +from .Controller_Data import Controller_Data +from .Controller import Controller diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/mixins/DrawAreaMixin.py b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/DrawAreaMixin.py new file mode 100644 index 0000000..833d3ae --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/DrawAreaMixin.py @@ -0,0 +1,59 @@ +# Python imports +import os, subprocess, signal, time + +# Gtk imports +import gi +gi.require_version('Gdk', '3.0') +from gi.repository import Gdk + +# Application imports + + +class DrawAreaMixin: + """docstring for DrawAreaMixin""" + + def close_demo_popup(self, widget=None, data=None): + os.kill(self.demo_area_pid, signal.SIGTERM) #or signal.SIGKILL + self.demo_area_pid = None + time.sleep(.200) + self.builder.get_object("demoPreviewPopWindow").popdown() + + def run_mplayer_process(self, widget, eve, params): + video, file, eveBox = params + self.set_selected_eve_box(eveBox) + + if eve.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: + if self.default_player == "mplayer": + xid = self.getXID() + command = [self.default_player, video, "-slave", "-wid", str(xid), "-really-quiet", "-ao", "null", "-loop", "0"] + self.run_demo_in_draw_area(command) + else: + subprocess.call([self.default_player, video, "-really-quiet", "-ao", "null", "-loop", "0"]) + + + self.to_be_background = video + self.applyType = 1 + self.help_label.set_markup(f"{file}") + + def run_demo_in_draw_area(self, command): + self.help_label.set_markup("") + + if self.demo_area_pid: + os.kill(self.demo_area_pid, signal.SIGTERM) #or signal.SIGKILL + self.demo_area_pid = None + time.sleep(.800) # 800 mili-seconds to ensure first process dead + + process = subprocess.Popen(command) + self.demo_area_pid = process.pid + + def getXID(self): + # Must be actualized before getting window + popup = self.builder.get_object("demoPreviewPopWindow") + + if popup.get_visible() == False: + popup.show_all() + popup.popup() + + preview = self.builder.get_object("demoPreview") + window = preview.get_window() + return window.get_xid() diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/mixins/GridMixin.py b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/GridMixin.py new file mode 100644 index 0000000..513d7b1 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/GridMixin.py @@ -0,0 +1,116 @@ +# Python imports +import threading, hashlib +from os import listdir +from os.path import isfile, join + +# Gtk imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, GLib + +# Application imports + + + + + +def threaded(fn): + def wrapper(*args, **kwargs): + threading.Thread(target=fn, args=args, kwargs=kwargs).start() + + return wrapper + + +class GridMixin: + """docstring for GridMixin.""" + + def set_new_path(self, widget, data=None): + dir = widget.get_filename() + self.load_path(None, dir) + + def load_path(self, widget=None, dir=''): + path = dir + list = [f for f in listdir(path) if isfile(join(path, f))] + files = [] + row = 0 + col = 0 + + for file in list: + if file.lower().endswith(self.settings.get_vids_filter() + \ + self.settings.get_images_filter()): + files.append(file) + + # fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) + # tickCount = 0.0 + self.clear() + self.image_grid.remove_column(0) + # self.loadProgress.set_text("Loading...") + # self.loadProgress.set_fraction(0.0) + self.help_label.set_markup(f"{path.strip(self.settings.get_home_path())}") + for file in files: + self.porocess_file(path, file, col, row) + + col += 1 + if col == 2: + col = 0 + row += 1 + + # self.loadProgress.set_text("Finished...") + + @threaded + def porocess_file(self, path, file, col, row): + fPath = f"{path}/{file}" + eveBox = Gtk.EventBox() + thumbnl = Gtk.Image() + + if file.lower().endswith(self.settings.get_vids_filter()): + fileHash = hashlib.sha256(str.encode(fPath)).hexdigest() + hashImgPath = f"{self.settings.get_home_path()}/.thumbnails/normal/{fileHash}.png" + if isfile(hashImgPath) == False: + self.generate_thumbnail(fPath, hashImgPath) + + thumbnl = self.create_gtk_image(hashImgPath, [310, 310]) + eveBox.connect("button_press_event", self.run_mplayer_process, (fPath, file, eveBox,)) + eveBox.connect("enter_notify_event", self.mouse_over, ()) + eveBox.connect("leave_notify_event", self.mouse_out, ()) + elif file.lower().endswith(self.settings.get_images_filter()): + thumbnl = self.create_gtk_image(fPath, [310, 310]) + eveBox.connect("button_press_event", self.run_image_viewer_process, (fPath, file, eveBox,)) + eveBox.connect("enter_notify_event", self.mouse_over, ()) + eveBox.connect("leave_notify_event", self.mouse_out, ()) + else: + print("Not a video or image file.") + return + + GLib.idle_add(self.pre_grid_setup, (eveBox, thumbnl, )) + GLib.idle_add(self.add_to_grid, (self.image_grid, eveBox, col, row,)) + # tickCount = tickCount + fractionTick + # self.loadProgress.set_fraction(tickCount) + + def pre_grid_setup(self, args): + args[0].show() + args[1].show() + args[0].add(args[1]) + + def add_to_grid(self, args): + args[0].attach(args[1], args[2], args[3], 1, 1) + + def clear_selection(self, widget, data=None): + self.clear() + + def clear(self): + while True: + if self.image_grid.get_child_at(0,0)!= None: + self.image_grid.remove_row(0) + else: + break + + self.image_grid.attach(self.grid_label, 0, 0, 1, 1) + self.builder.get_object("xScreenSvrList").set_sensitive(False) + self.builder.get_object("useXScrnList").set_active(False) + self.help_label.set_markup(self.defaultLabel) + # self.loadProgress.set_text("") + # self.loadProgress.set_fraction(0.0) + self.xscreen_value = None + self.to_be_background = None + self.apply_type = 1 diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ImageViewerMixin.py b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ImageViewerMixin.py new file mode 100644 index 0000000..e4dd1b6 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ImageViewerMixin.py @@ -0,0 +1,34 @@ +# Python imports +import subprocess + +# Gtk imports +import gi +gi.require_version('Gdk', '3.0') +from gi.repository import Gdk + +# Application imports + + +class ImageViewerMixin: + """docstring for ImageViewerMixin""" + + def close_image_popup(self, widget=None): + self.builder.get_object("previewWindow").popdown() + + def open_main_image_viewer(self, widget): + subprocess.call([self.default_img_viewer, self.to_be_background]) + + def run_image_viewer_process(self, widget, eve, params): + image, file, eveBox = params + self.set_selected(eveBox) + + if eve.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: + previewWindow = self.builder.get_object("previewWindow") + previewImg = self.builder.get_object("previewImg") + previewImg.set_from_file(image) + previewWindow.show_all() + previewWindow.popup() + + self.to_be_background = image + self.apply_type = 2 + self.help_label.set_markup(f"{file}") diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ThumbnailMixin.py b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ThumbnailMixin.py new file mode 100644 index 0000000..e067732 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/ThumbnailMixin.py @@ -0,0 +1,56 @@ +# Python imports +import subprocess + +# Gtk imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import GdkPixbuf + +# Application imports + + +class ThumbnailMixin: + """docstring for ThumbnailMixin""" + + def create_gtk_image(self, path, wxh): + try: + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( + filename = path, + width = wxh[0], + height = wxh[1], + preserve_aspect_ratio = True) + return Gtk.Image.new_from_pixbuf(pixbuf) + except Exception as e: + print(repr(e)) + + return Gtk.Image() + + def generate_thumbnail(self, fullPathFile, hashImgpth): + # Stream duration + command = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration", "-of", "default=noprint_wrappers=1:nokey=1", fullPathFile] + 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", fullPathFile] + 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", fullPathFile] + 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", fullPathFile] + 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, "-i", fullPathFile, "-an", "-vframes", "1", "-s", "320x180", "-q:v", "2", hashImgpth] + subprocess.call(command) diff --git a/src/versions/0.0.2/GWinWrap/signal_classes/mixins/__init__.py b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/__init__.py new file mode 100644 index 0000000..f482286 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/signal_classes/mixins/__init__.py @@ -0,0 +1,4 @@ +from .ThumbnailMixin import ThumbnailMixin +from .DrawAreaMixin import DrawAreaMixin +from .ImageViewerMixin import ImageViewerMixin +from .GridMixin import GridMixin diff --git a/src/versions/0.0.2/GWinWrap/utils/Logger.py b/src/versions/0.0.2/GWinWrap/utils/Logger.py new file mode 100644 index 0000000..c7f294e --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/utils/Logger.py @@ -0,0 +1,56 @@ +# Python imports +import os, logging + +# Application imports + + +class Logger: + def __init__(self): + pass + + 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) + log.setLevel(globalLogLvl) + + # 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 = "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/versions/0.0.2/GWinWrap/utils/Settings.py b/src/versions/0.0.2/GWinWrap/utils/Settings.py new file mode 100644 index 0000000..e729ee4 --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/utils/Settings.py @@ -0,0 +1,112 @@ +# Python imports +import os + +# Gtk imports +import gi, cairo +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') + +from gi.repository import Gtk +from gi.repository import Gdk + + +# Application imports +from . import Logger + + + +class Settings: + def __init__(self): + self._SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__)) + self._USER_HOME = os.path.expanduser('~') + self._CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}" + self._GLADE_FILE = f"{self._CONFIG_PATH}/Main_Window.glade" + self._CSS_FILE = f"{self._CONFIG_PATH}/stylesheet.css" + self._DEFAULT_ICONS = f"{self._CONFIG_PATH}/icons" + self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png" + self._USR_PATH = f"/usr/share/{app_name.lower()}" + self._CONFIG_FILE = f"{self._CONFIG_PATH}/settings.json" + self._XSCREEN_SAVERS = "/usr/lib/xscreensaver/" + + + self._logger = Logger().get_logger() + self._builder = Gtk.Builder() + self._main_window = None + + # '_filters' + self._vids_filter = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm') + self._images_filter = ('.png', '.jpg', '.jpeg', '.gif') + + self._success_color = "#88cc27" + self._warning_color = "#ffa800" + self._error_color = "#ff0000" + + if not os.path.exists(self._GLADE_FILE): + self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade" + if not os.path.exists(self._CSS_FILE): + self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css" + if not os.path.exists(self._WINDOW_ICON): + self._WINDOW_ICON = f"{self._USR_PATH}/icons/{app_name.lower()}.png" + if not os.path.exists(self._DEFAULT_ICONS): + self.DEFAULT_ICONS = f"{self._USR_PATH}/icons" + + self._builder.add_from_file(self._GLADE_FILE) + + + + def create_window(self): + # Get window and connect signals + self._main_window = self._builder.get_object("Main_Window") + self.set_window_data() + + def set_window_data(self): + self._main_window.set_icon_from_file(self._WINDOW_ICON) + screen = self._main_window.get_screen() + visual = screen.get_rgba_visual() + + if visual != None and screen.is_composited(): + self._main_window.set_visual(visual) + self._main_window.set_app_paintable(True) + self._main_window.connect("draw", self.draw_area) + + # bind css file + cssProvider = Gtk.CssProvider() + cssProvider.load_from_path(self._CSS_FILE) + screen = Gdk.Screen.get_default() + styleContext = Gtk.StyleContext() + styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER) + + def get_monitor_data(self): + screen = self._builder.get_object("Main_Window").get_screen() + monitors = [] + for m in range(screen.get_n_monitors()): + monitors.append(screen.get_monitor_geometry(m)) + + for monitor in monitors: + print("{}x{}|{}+{}".format(monitor.width, monitor.height, monitor.x, monitor.y)) + + return monitors + + def draw_area(self, widget, cr): + cr.set_source_rgba(0, 0, 0, 0.54) + cr.set_operator(cairo.OPERATOR_SOURCE) + cr.paint() + cr.set_operator(cairo.OPERATOR_OVER) + + + + + def get_builder(self): return self._builder + def get_logger(self): return self._logger + def get_main_window(self): return self._main_window + def get_home_path(self): return self._USER_HOME + def get_config_file(self): return self._CONFIG_FILE + def get_xscreensavers(self): return self._XSCREEN_SAVERS + + # Filter returns + def get_vids_filter(self): return self._vids_filter + def get_images_filter(self): return self._images_filter + + def get_success_color(self): return self._success_color + def get_warning_color(self): return self._warning_color + def get_error_color(self): return self._error_color diff --git a/src/versions/0.0.2/GWinWrap/utils/__init__.py b/src/versions/0.0.2/GWinWrap/utils/__init__.py new file mode 100644 index 0000000..415301e --- /dev/null +++ b/src/versions/0.0.2/GWinWrap/utils/__init__.py @@ -0,0 +1,6 @@ +""" + Utils module +""" + +from .Logger import Logger +from .Settings import Settings diff --git a/src/versions/0.0.2/XWinWrap/Makefile b/src/versions/0.0.2/XWinWrap/Makefile new file mode 100644 index 0000000..4a67078 --- /dev/null +++ b/src/versions/0.0.2/XWinWrap/Makefile @@ -0,0 +1,20 @@ +all: all64 all32 + +all64: + gcc -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -lX11 -lXext -lXrender xwinwrap.c -o xwinwrap + -mkdir x86_64 + mv ./xwinwrap ./x86_64 + +all32: + gcc -m32 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -lX11 -lXext -lXrender xwinwrap.c -o xwinwrap + -mkdir i386 + mv ./xwinwrap ./i386 + +install64: + cp x86_64/xwinwrap /usr/bin + +install32: + cp i386/xwinwrap /usr/bin + +clean: + -rm -rf x86_64/ i386/ diff --git a/src/versions/0.0.2/XWinWrap/xwinwrap.c b/src/versions/0.0.2/XWinWrap/xwinwrap.c new file mode 100644 index 0000000..a2daa04 --- /dev/null +++ b/src/versions/0.0.2/XWinWrap/xwinwrap.c @@ -0,0 +1,459 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman + */ + +/* + * Modified by: Shantanu Goel + * Tech Blog: http://tech.shantanugoel.com + * Blog: http://blog.shantanugoel.com + * Home Page: http://tech.shantanugoel.com/projects/linux/shantz-xwinwrap + * + * Changelog: + * 15-Jan-09: 1. Fixed the bug where XFetchName returning a NULL for "name" + * resulted in a crash. + * 2. Provided an option to specify the desktop window name. + * 3. Added debug messages + * + * 24-Aug-08: 1. Fixed the geometry option (-g) so that it works + * 2. Added override option (-ov), for seamless integration with + * desktop like a background in non-fullscreen modes + * 3. Added shape option (-sh), to create non-rectangular windows. + * Currently supporting circlular and triangular windows + */ + + /* + * Modified by: Maxim Stewart + * Tech Blog: https://www.itdominator.com/ + * + * Changelog: + * 3-March-19: 1. Cleaned up code formatting. + * 2. Removed unused DEBUG_MSG reference. + * 3. Moved functions to a more reasonable order. + * 4. Compile dev library list 32 & 64 bit: + * # 32 + * sudo apt install libxext-dev:i386 libxrender-dev:i386 libc6-dev-i386 + * + * # 64 + * sudo apt install libxext-dev libxrender-dev libc6-dev + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define WIDTH 512 +#define HEIGHT 384 +#define OPAQUE 0xffffffff +#define NAME "xwinwrap" +#define VERSION "0.3" +#define DESKTOP_WINDOW_NAME_MAX_SIZE 25 +#define DEFAULT_DESKTOP_WINDOW_NAME "Desktop" +#define DEBUG_MSG(x) if(debug) { fprintf(stderr, x); } + +typedef enum { + SHAPE_RECT = 0, + SHAPE_CIRCLE, + SHAPE_TRIG, +} win_shape; + +static pid_t pid = 0; +static char **childArgv = 0; +static int nChildArgv = 0; +int debug = 0; +char desktop_window_name[DESKTOP_WINDOW_NAME_MAX_SIZE]; + +static int addArguments(char **argv, int n) { + char **newArgv; + int i; + + newArgv = realloc (childArgv, sizeof (char *) * (nChildArgv + n)); + if (!newArgv) + return 0; + + for (i = 0; i < n; i++) + newArgv[nChildArgv + i] = argv[i]; + + childArgv = newArgv; + nChildArgv += n; + + return n; +} + +static void setWindowOpacity(Display *dpy, Window win, unsigned int opacity) { + CARD32 o; + o = opacity; + XChangeProperty (dpy, win, XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0), + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) &o, 1); +} + +static Visual * findArgbVisual(Display *dpy, int scr) { + XVisualInfo *xvi; + XVisualInfo template; + int nvi; + int i; + XRenderPictFormat *format; + Visual *visual; + + template.screen = scr; + template.depth = 32; + template.class = TrueColor; + + xvi = XGetVisualInfo (dpy, + VisualScreenMask | + VisualDepthMask | + VisualClassMask, + &template, + &nvi); + + if (!xvi) + return 0; + + visual = 0; + for (i = 0; i < nvi; i++) { + format = XRenderFindVisualFormat (dpy, xvi[i].visual); + if (format->type == PictTypeDirect && format->direct.alphaMask) { + visual = xvi[i].visual; + break; + } + } + + XFree (xvi); + return visual; +} + +static Window find_desktop_window(Display *display, int screen, + Window *root, Window *p_desktop) { + int i; + unsigned int n; + Window win = *root; + Window troot, parent, *children; + char *name; + int status; + int width = DisplayWidth(display, screen); + int height = DisplayHeight(display, screen); + XWindowAttributes attrs; + + XQueryTree(display, *root, &troot, &parent, &children, &n); + for (i = 0; i < (int) n; i++) { + status = XFetchName(display, children[i], &name); + status |= XGetWindowAttributes(display, children[i], &attrs); + + if ((status != 0) && (NULL != name)) { + if( (attrs.map_state != 0) && (attrs.width == width) && + (attrs.height == height) && (!strcmp(name, desktop_window_name)) ) { + win = children[i]; + XFree(children); + XFree(name); + *p_desktop = win; + return win; + } + + if(name) + XFree(name); + } + } + + DEBUG_MSG("Desktop Window Not found\n"); + return 0; +} + +static void usage (void) { + fprintf(stderr, "%s v%s- Modified by Shantanu Goel. Visit http://tech.shantanugoel.com for updates, queries and feature requests\n", NAME, VERSION); + fprintf (stderr, "\nUsage: %s [-g {w}x{h}+{x}+{y}] [-ni] [-argb] [-fs] [-s] [-st] [-sp] [-a] " + "[-b] [-nf] [-o OPACITY] [-sh SHAPE] [-ov]-- COMMAND ARG1...\n", NAME); + fprintf (stderr, "Options:\n \ + -g - Specify Geometry (w=width, h=height, x=x-coord, y=y-coord. ex: -g 640x480+100+100)\n \ + -ni - Ignore Input\n \ + -d - Desktop Window Hack. Provide name of the \"Desktop\" window as parameter \ + -argb - RGB\n \ + -fs - Full Screen\n \ + -s - Sticky\n \ + -st - Skip Taskbar\n \ + -sp - Skip Pager\n \ + -a - Above\n \ + -b - Below\n \ + -nf - No Focus\n \ + -o - Opacity value between 0 to 1 (ex: -o 0.20)\n \ + -sh - Shape of window (choose between rectangle, circle or triangle. Default is rectangle)\n \ + -ov - Set override_redirect flag (For seamless desktop background integration in non-fullscreenmode)\n \ + -debug - Enable debug messages\n"); +} + +static void sigHandler (int sig) { kill(pid, sig); } + +int main (int argc, char **argv) { + Display *dpy; + Window win; + Window root; + Window p_desktop = 0; + int screen; + XSizeHints xsh; + XWMHints xwmh; + char widArg[256]; + char *widArgv[] = { widArg }; + char *endArg = NULL; + int i; + int status = 0; + unsigned int opacity = OPAQUE; + int x = 0; + int y = 0; + unsigned int width = WIDTH; + unsigned int height = HEIGHT; + int argb = 0; + int fullscreen = 0; + int noInput = 0; + int noFocus = 0; + Atom state[256]; + int nState = 0; + int override = 0; + win_shape shape = SHAPE_RECT; + Pixmap mask; + GC mask_gc; + XGCValues xgcv; + + + dpy = XOpenDisplay (NULL); + if (!dpy) { + fprintf (stderr, "%s: Error: couldn't open display\n", argv[0]); + return 1; + } + + screen = DefaultScreen (dpy); + root = RootWindow (dpy, screen); + strcpy(desktop_window_name, DEFAULT_DESKTOP_WINDOW_NAME); + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-g") == 0) { + if (++i < argc) + XParseGeometry (argv[i], &x, &y, &width, &height); + } else if (strcmp(argv[i], "-ni") == 0) { + noInput = 1; + } else if (strcmp(argv[i], "-d") == 0) { + ++i; + strcpy(desktop_window_name, argv[i]); + } else if (strcmp(argv[i], "-argb") == 0) { + argb = 1; + } else if (strcmp(argv[i], "-fs") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0); + fullscreen = 1; + } else if (strcmp(argv[i], "-s") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0); + } else if (strcmp(argv[i], "-st") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0); + } else if (strcmp(argv[i], "-sp") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0); + } else if (strcmp(argv[i], "-a") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0); + } else if (strcmp(argv[i], "-b") == 0) { + state[nState++] = XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0); + } else if (strcmp(argv[i], "-nf") == 0) { + noFocus = 1; + } else if (strcmp(argv[i], "-o") == 0) { + if (++i < argc) + opacity = (unsigned int) (atof (argv[i]) * OPAQUE); + } else if (strcmp(argv[i], "-sh") == 0) { + if (++i < argc) { + if(strcasecmp(argv[i], "circle") == 0) { + shape = SHAPE_CIRCLE; + } else if(strcasecmp(argv[i], "triangle") == 0) { + shape = SHAPE_TRIG; + } + } + } else if (strcmp(argv[i], "-ov") == 0) { + override = 1; + } else if (strcmp(argv[i], "-debug") == 0) { + debug = 1; + } else if (strcmp(argv[i], "--") == 0) { + break; + } else { + usage (); + return 1; + } + } + + for (i = i + 1; i < argc; i++) { + if (strcmp(argv[i], "WID") == 0) + addArguments (widArgv, 1); + else + addArguments (&argv[i], 1); + } + + if (!nChildArgv) { + fprintf (stderr, "%s: Error: couldn't create command line\n", argv[0]); + usage (); + return 1; + } + + addArguments (&endArg, 1); + + if (fullscreen) { + xsh.flags = PSize | PPosition; + xsh.width = DisplayWidth (dpy, screen); + xsh.height = DisplayHeight (dpy, screen); + } else { + xsh.flags = PSize; + xsh.width = width; + xsh.height = height; + } + + xwmh.flags = InputHint; + xwmh.input = !noFocus; + + if (argb) { + XSetWindowAttributes attr; + Visual *visual; + + visual = findArgbVisual (dpy, screen); + if (!visual) { + fprintf (stderr, "%s: Error: couldn't find argb visual\n", argv[0]); + return 1; + } + + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap (dpy, root, visual, AllocNone); + + win = XCreateWindow (dpy, root, 0, 0, xsh.width, xsh.height, 0, 32, + InputOutput, visual, + CWBackPixel | CWBorderPixel | CWColormap, &attr); + } else { + XSetWindowAttributes attr; + attr.override_redirect = override; + + if( override && find_desktop_window(dpy, screen, &root, &p_desktop) ) { + win = XCreateWindow (dpy, p_desktop, x, y, xsh.width, xsh.height, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWOverrideRedirect, &attr); + } else { + win = XCreateWindow (dpy, root, x, y, xsh.width, xsh.height, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWOverrideRedirect, &attr); + } + } + + XSetWMProperties (dpy, win, NULL, NULL, argv, argc, &xsh, &xwmh, NULL); + + if (opacity != OPAQUE) + setWindowOpacity (dpy, win, opacity); + + if (noInput) { + Region region; + + region = XCreateRegion (); + if (region) { + XShapeCombineRegion (dpy, win, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion (region); + } + } + + if (nState) + XChangeProperty (dpy, win, XInternAtom (dpy, "_NET_WM_STATE", 0), + XA_ATOM, 32, PropModeReplace, (unsigned char *) state, nState); + + if (shape) { + mask = XCreatePixmap(dpy, win, width, height, 1); + mask_gc = XCreateGC(dpy, mask, 0, &xgcv); + + switch(shape) { + //Nothing special to be done if it's a rectangle + case SHAPE_CIRCLE: + /* fill mask */ + XSetForeground(dpy, mask_gc, 0); + XFillRectangle(dpy, mask, mask_gc, 0, 0, width, height); + + XSetForeground(dpy, mask_gc, 1); + XFillArc(dpy, mask, mask_gc, 0, 0, width, height, 0, 23040); + break; + + case SHAPE_TRIG: + { + XPoint points[3] = { {0, height}, + {width/2, 0}, + {width, height} }; + + XSetForeground(dpy, mask_gc, 0); + XFillRectangle(dpy, mask, mask_gc, 0, 0, width, height); + + XSetForeground(dpy, mask_gc, 1); + XFillPolygon(dpy, mask, mask_gc, points, 3, Complex, CoordModeOrigin); + } + break; + default: + break; + } + /* combine */ + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, mask, ShapeSet); + } + + XMapWindow (dpy, win); + + if(p_desktop == 0) + XLowerWindow(dpy, win); + + XSync (dpy, win); + sprintf (widArg, "0x%x", (int) win); + pid = fork (); + + switch (pid) { + case -1: + perror ("fork"); + return 1; + case 0: + execvp (childArgv[0], childArgv); + perror (childArgv[0]); + exit (2); + break; + default: + break; + } + + signal (SIGTERM, sigHandler); + signal (SIGINT, sigHandler); + + for (;;) { + if (waitpid (pid, &status, 0) != -1) { + if (WIFEXITED (status)) + fprintf (stderr, "%s died, exit status %d\n", childArgv[0], + WEXITSTATUS (status)); + break; + } + } + + XDestroyWindow (dpy, win); + XCloseDisplay (dpy); + return 0; +} diff --git a/src/versions/0.0.2/compileBin.sh b/src/versions/0.0.2/compileBin.sh new file mode 100755 index 0000000..fdd8222 --- /dev/null +++ b/src/versions/0.0.2/compileBin.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +function main() { + gcc -no-pie -s gwinwrap_exec_bin.cpp -o gwinwrap +} +main; diff --git a/src/versions/0.0.2/gwinwrap_exec_bin.cpp b/src/versions/0.0.2/gwinwrap_exec_bin.cpp new file mode 100644 index 0000000..81978ec --- /dev/null +++ b/src/versions/0.0.2/gwinwrap_exec_bin.cpp @@ -0,0 +1,10 @@ +#include +#include +#include +using namespace std; + +int main() { + chdir("/opt/GWinWrap/"); + system("python3 ."); +return 0; +} diff --git a/user_config/usr/share/gwinwrap/Main_Window.glade b/user_config/usr/share/gwinwrap/Main_Window.glade new file mode 100644 index 0000000..41e0e23 --- /dev/null +++ b/user_config/usr/share/gwinwrap/Main_Window.glade @@ -0,0 +1,882 @@ + + + + + + + inode/directory + + + + + + + + + + True + False + gtk-clear + 3 + + + True + False + gtk-quit + 3 + + + True + False + gtk-cancel + 3 + + + True + False + gtk-jump-to + 3 + + + True + False + gtk-save + 3 + + + True + False + gtk-save + 3 + + + True + False + Settings.... + gtk-properties + 3 + + + True + False + gtk-media-play + 3 + + + True + False + gtk-media-stop + 3 + + + 950 + 600 + False + GWinWrap + center + 950 + 600 + icons/GWinWrap.png + center + + + True + False + + + True + False + 15 + 15 + 15 + vertical + + + True + False + 5 + + + True + False + 15 + Note: Double click an image to view the video or image. + + + True + True + 0 + + + + + True + False + Chose Dream Scene / Image Directory + select-folder + False + Folders + Dream Scene / Image Dir + + + + False + True + 1 + + + + + True + True + True + settingsImage + True + + + + False + True + 2 + + + + + False + True + 0 + + + + + True + False + True + + + False + True + 1 + + + + + True + True + in + + + True + False + + + + True + False + vertical + 10 + 10 + True + True + + + 640 + 525 + True + False + Choose Image/Video Directory... + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + 2 + + + + + Clear + True + True + True + clearImage + True + + + + False + True + 3 + + + + + True + True + 0 + + + + + 300 + True + False + 10 + 15 + 15 + 15 + False + vertical + + + True + False + vertical + + + Use XScreenSaver + True + True + False + center + 5 + True + + + + False + True + 0 + + + + + True + True + in + + + True + False + True + XScreensaverStore + False + + + + + + + + XScreensaves + + + + 0 + + + + + + + + + True + True + 1 + + + + + True + True + 0 + + + + + True + False + False + vertical + + + True + False + vertical + + + True + False + + + True + False + 10 + 10 + Playback Resolutions + + + True + True + 0 + + + + + True + False + 10 + 10 + Position Offset + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + + + True + False + 3 + + 7680x4320 + 3840x2160 + 2048x1080 + 1920x1080 + 1440x720 + 1600x900 + 1280x720 + 800x600 + + + + True + True + 0 + + + + + True + False + + + True + True + 1 + + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + vertical + + + True + False + 10 + 5 + Save Path + + + True + True + 0 + + + + + True + False + 0 + + .animatedBGstarter.sh + .animatedBGstarter2.sh + .animatedBGstarter3.sh + + + + True + True + 1 + + + + + False + True + 1 + + + + + + True + False + + + Save + True + True + True + True + True + saveImage + True + + + + 1 + 0 + + + + + (Re)Start + True + True + True + True + True + startImage + True + + + + 0 + 0 + + + + + Stop + True + True + True + True + True + stopImage + True + + + + 0 + 1 + + + + + Close + True + True + True + True + True + closeImage + True + + + + 1 + 1 + + + + + + + + + + + + + + + + + + + + False + True + 2 + + + + + False + False + end + 1 + + + + + False + True + 1 + 1 + + + + + + + 640 + 525 + False + 350 + True + True + helpLabel + bottom + False + + + True + False + vertical + + + True + False + + + True + True + True + Close Demo Window + closePopupImage + True + + + + False + True + end + 0 + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + + + + + True + True + 1 + + + + + + + 640 + 525 + False + True + True + helpLabel + bottom + + + True + False + vertical + + + True + False + bottom + + + Main Image Viewer + True + True + True + openProgImage + True + + + + False + True + 0 + + + + + True + True + True + True + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + True + in + False + + + True + False + + + True + False + gtk-missing-image + 6 + + + + + + + True + True + 1 + + + + + + + 250 + False + button1 + + + True + False + vertical + + + True + False + + + True + False + folder + + + False + True + 0 + + + + + 330 + 26 + True + True + Set Custom Default Path + Set Custom Start Path + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + + + True + False + video-x-generic + + + False + True + 0 + + + + + 330 + 26 + True + True + Set Custom Video Player + Set Custom Video Player + + + True + True + 1 + + + + + False + True + 1 + + + + + True + False + + + True + False + image-x-generic + + + False + True + 0 + + + + + 330 + 26 + True + True + Set Custom Image Viewer + Set Custom Image Viewer + + + False + True + 1 + + + + + False + True + 2 + + + + + Save + True + True + True + saveImag + True + + + + False + True + 3 + + + + + + diff --git a/user_config/usr/share/gwinwrap/icons/dir.png b/user_config/usr/share/gwinwrap/icons/dir.png new file mode 100644 index 0000000..a9b5e9f Binary files /dev/null and b/user_config/usr/share/gwinwrap/icons/dir.png differ diff --git a/user_config/usr/share/gwinwrap/icons/gwinwrap.png b/user_config/usr/share/gwinwrap/icons/gwinwrap.png new file mode 100644 index 0000000..cdd708d Binary files /dev/null and b/user_config/usr/share/gwinwrap/icons/gwinwrap.png differ diff --git a/user_config/usr/share/gwinwrap/icons/picture.png b/user_config/usr/share/gwinwrap/icons/picture.png new file mode 100644 index 0000000..46f1ae6 Binary files /dev/null and b/user_config/usr/share/gwinwrap/icons/picture.png differ diff --git a/user_config/usr/share/gwinwrap/icons/video.png b/user_config/usr/share/gwinwrap/icons/video.png new file mode 100644 index 0000000..55afa98 Binary files /dev/null and b/user_config/usr/share/gwinwrap/icons/video.png differ diff --git a/user_config/usr/share/gwinwrap/settings.json b/user_config/usr/share/gwinwrap/settings.json new file mode 100644 index 0000000..596ddd2 --- /dev/null +++ b/user_config/usr/share/gwinwrap/settings.json @@ -0,0 +1,9 @@ +{ + "settings":[ + { + "start_path":"/home/abaddon/LazyShare/Movies-TV-Music/Dream Scenes/Games/Halo", + "default_player":"mpv", + "default_img_viewer":"mirage" + } + ] +} \ No newline at end of file diff --git a/user_config/usr/share/gwinwrap/stylesheet.css b/user_config/usr/share/gwinwrap/stylesheet.css new file mode 100644 index 0000000..c0383f6 --- /dev/null +++ b/user_config/usr/share/gwinwrap/stylesheet.css @@ -0,0 +1,86 @@ +/* Set fm to have transparent window */ +box, +iconview, +notebook, +paned, +stack, +scrolledwindow, +treeview.view, +.content-view, +.view { + background: rgba(19, 21, 25, 0.14); + color: rgba(255, 255, 255, 1); +} + +notebook > header > tabs > tab:checked { + /* Neon Blue 00e8ff */ + background-color: rgba(0, 232, 255, 0.2); + /* Dark Bergundy */ + /* background-color: rgba(116, 0, 0, 0.25); */ + + color: rgba(255, 255, 255, 0.8); +} + +#message_view { + font: 16px "Monospace"; +} + +.view:selected, +.view:selected:hover { + box-shadow: inset 0 0 0 9999px rgba(21, 158, 167, 0.34); + color: rgba(255, 255, 255, 0.5); +} + +.alert-border { + border: 2px solid rgba(116, 0, 0, 0.64); +} + +.search-border { + border: 2px solid rgba(136, 204, 39, 1); +} + +.notebook-selected-focus { + /* Neon Blue 00e8ff border */ + border: 2px solid rgba(0, 232, 255, 0.34); + /* Dark Bergundy */ + /* border: 2px solid rgba(116, 0, 0, 0.64); */ +} + +.notebook-unselected-focus { + /* Neon Blue 00e8ff border */ + /* border: 2px solid rgba(0, 232, 255, 0.25); */ + /* Dark Bergundy */ + /* border: 2px solid rgba(116, 0, 0, 0.64); */ + /* Snow White */ + border: 2px solid rgba(255, 255, 255, 0.24); +} + + + + + +/* * { + background: rgba(0, 0, 0, 0.14); + color: rgba(255, 255, 255, 1); +} */ + +/* * selection { + background-color: rgba(116, 0, 0, 0.65); + color: rgba(255, 255, 255, 0.5); +} */ + +/* 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); +} */