Compare commits
13 Commits
Author | SHA1 | Date |
---|---|---|
itdominator | a362039e73 | |
itdominator | 02c31719d1 | |
itdominator | d65ea8dec8 | |
itdominator | fec0d26ab7 | |
itdominator | a47bd23e78 | |
itdominator | 44ef6ea2bb | |
itdominator | be7be00f78 | |
itdominator | 8e5ae4824c | |
itdominator | 37e3265be5 | |
itdominator | 4cafb7ff9f | |
itdominator | 9336df2afa | |
itdominator | d936b17429 | |
itdominator | e6739c3087 |
|
@ -184,11 +184,11 @@ class Plugin(PluginBase):
|
|||
response = requests.post(self.vqd_link, headers=self.vqd_headers, data=self.vqd_data, timeout=2)
|
||||
if response.status_code == 200:
|
||||
data = response.content
|
||||
vqd_start_index = data.index(b"vqd='") + 5
|
||||
vqd_end_index = data.index(b"'", vqd_start_index)
|
||||
vqd_start_index = data.index(b"vqd=\"") + 5
|
||||
vqd_end_index = data.index(b"\"", vqd_start_index)
|
||||
self._vqd_attrib = data[vqd_start_index:vqd_end_index].decode("utf-8")
|
||||
|
||||
print(f"Translation VQD: {self._vqd_attrib}")
|
||||
else:
|
||||
msg = f"Could not get VQS attribute... Response Code: {response.status_code}"
|
||||
self._translate_to_buffer.set_text(msg)
|
||||
self._translate_to_buffer.set_text(msg)
|
|
@ -16,13 +16,17 @@ from utils.settings_manager.manager import SettingsManager
|
|||
# NOTE: Threads WILL NOT die with parent's destruction.
|
||||
def threaded_wrapper(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
|
||||
thread = threading.Thread(target = fn, args = args, kwargs = kwargs, daemon = False)
|
||||
thread.start()
|
||||
return thread
|
||||
return wrapper
|
||||
|
||||
# NOTE: Threads WILL die with parent's destruction.
|
||||
def daemon_threaded_wrapper(fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
|
||||
thread = threading.Thread(target = fn, args = args, kwargs = kwargs, daemon = True)
|
||||
thread.start()
|
||||
return thread
|
||||
return wrapper
|
||||
|
||||
def sizeof_fmt_def(num, suffix="B"):
|
||||
|
@ -61,4 +65,4 @@ def custom_except_hook(exc_type, exc_value, exc_traceback):
|
|||
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
|
||||
sys.excepthook = custom_except_hook
|
||||
sys.excepthook = custom_except_hook
|
|
@ -3,14 +3,13 @@
|
|||
# Python imports
|
||||
import argparse
|
||||
import faulthandler
|
||||
import locale
|
||||
import 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 __builtins__ import *
|
||||
|
@ -18,39 +17,38 @@ from app import Application
|
|||
|
||||
|
||||
|
||||
def run():
|
||||
try:
|
||||
locale.setlocale(locale.LC_NUMERIC, 'C')
|
||||
def main(args, unknownargs):
|
||||
setproctitle(f'{app_name}')
|
||||
|
||||
setproctitle(f"{app_name}")
|
||||
faulthandler.enable() # For better debug info
|
||||
if args.debug == "true":
|
||||
settings_manager.set_debug(True)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Add long and short arguments
|
||||
parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.")
|
||||
parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.")
|
||||
parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.")
|
||||
if args.trace_debug == "true":
|
||||
settings_manager.set_trace_debug(True)
|
||||
|
||||
parser.add_argument("--new-tab", "-t", default="", help="Open a file into new tab.")
|
||||
parser.add_argument("--new-window", "-w", default="", help="Open a file into a new window.")
|
||||
settings_manager.do_dirty_start_check()
|
||||
Application(args, unknownargs)
|
||||
|
||||
# Read arguments (If any...)
|
||||
args, unknownargs = parser.parse_known_args()
|
||||
|
||||
if args.debug == "true":
|
||||
settings_manager.set_debug(True)
|
||||
|
||||
if args.trace_debug == "true":
|
||||
settings_manager.set_trace_debug(True)
|
||||
|
||||
settings_manager.do_dirty_start_check()
|
||||
Application(args, unknownargs)
|
||||
Gtk.main()
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
quit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
""" Set process title, get arguments, and create GTK main thread. """
|
||||
run()
|
||||
''' Set process title, get arguments, and create GTK main thread. '''
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Add long and short arguments
|
||||
parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.")
|
||||
parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.")
|
||||
parser.add_argument("--no-plugins", "-np", default="false", help="Do not load plugins.")
|
||||
|
||||
parser.add_argument("--new-tab", "-nt", default="false", help="Opens a 'New Tab' if a handler is set for it.")
|
||||
parser.add_argument("--file", "-f", default="default", help="JUST SOME FILE ARG.")
|
||||
|
||||
# Read arguments (If any...)
|
||||
args, unknownargs = parser.parse_known_args()
|
||||
|
||||
try:
|
||||
faulthandler.enable() # For better debug info
|
||||
main(args, unknownargs)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
quit()
|
|
@ -15,35 +15,40 @@ class AppLaunchException(Exception):
|
|||
...
|
||||
|
||||
|
||||
class Application(IPCServer):
|
||||
|
||||
class Application:
|
||||
""" docstring for Application. """
|
||||
|
||||
def __init__(self, args, unknownargs):
|
||||
super(Application, self).__init__()
|
||||
|
||||
if not settings_manager.is_trace_debug():
|
||||
self.socket_realization_check()
|
||||
|
||||
if not self.is_ipc_alive:
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isdir(arg):
|
||||
message = f"FILE|{arg}"
|
||||
self.send_ipc_message(message)
|
||||
|
||||
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
|
||||
self.load_ipc(args, unknownargs)
|
||||
|
||||
self.setup_debug_hook()
|
||||
Window(args, unknownargs)
|
||||
Window(args, unknownargs).main()
|
||||
|
||||
|
||||
def socket_realization_check(self):
|
||||
def load_ipc(self, args, unknownargs):
|
||||
ipc_server = IPCServer()
|
||||
self.ipc_realization_check(ipc_server)
|
||||
|
||||
if not ipc_server.is_ipc_alive:
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isfile(arg):
|
||||
message = f"FILE|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||
|
||||
def ipc_realization_check(self, ipc_server):
|
||||
try:
|
||||
self.create_ipc_listener()
|
||||
ipc_server.create_ipc_listener()
|
||||
except Exception:
|
||||
self.send_test_ipc_message()
|
||||
ipc_server.send_test_ipc_message()
|
||||
|
||||
try:
|
||||
self.create_ipc_listener()
|
||||
ipc_server.create_ipc_listener()
|
||||
except Exception as e:
|
||||
...
|
||||
|
||||
|
@ -51,9 +56,9 @@ class Application(IPCServer):
|
|||
try:
|
||||
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
|
||||
signal.signal(
|
||||
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
|
||||
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
|
||||
debug_signal_handler
|
||||
)
|
||||
except ValueError:
|
||||
# Typically: ValueError: signal only works in main thread
|
||||
...
|
||||
...
|
|
@ -78,6 +78,7 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
event_system.subscribe("do_action_from_menu_controls", self.do_action_from_menu_controls)
|
||||
event_system.subscribe("set_clipboard_data", self.set_clipboard_data)
|
||||
|
||||
|
||||
def _load_glade_file(self):
|
||||
self.builder.add_from_file( settings_manager.get_glade_file() )
|
||||
self.builder.expose_object("main_window", self.window)
|
||||
|
@ -113,6 +114,7 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
if not settings_manager.is_trace_debug():
|
||||
self.fm_controller.save_state()
|
||||
|
||||
|
||||
def reload_plugins(self, widget=None, eve=None):
|
||||
self.plugins.reload_plugins()
|
||||
|
||||
|
@ -133,6 +135,8 @@ class Controller(UIMixin, SignalsMixins, Controller_Data):
|
|||
event_system.emit("open_files")
|
||||
if action == "open_with":
|
||||
event_system.emit("show_appchooser_menu")
|
||||
if action == "open_2_new_tab":
|
||||
event_system.emit("open_2_new_tab")
|
||||
if action == "execute":
|
||||
event_system.emit("execute_files")
|
||||
if action == "execute_in_terminal":
|
||||
|
|
|
@ -70,23 +70,16 @@ class Controller_Data:
|
|||
Returns:
|
||||
state (obj): State
|
||||
'''
|
||||
# state = State()
|
||||
|
||||
state = self._state
|
||||
state.fm_controller = self.fm_controller
|
||||
state.notebooks = self.notebooks
|
||||
state.wid, state.tid = self.fm_controller.get_active_wid_and_tid()
|
||||
state.tab = self.get_fm_window(state.wid).get_tab_by_id(state.tid)
|
||||
state.icon_grid = self.builder.get_object(f"{state.wid}|{state.tid}|icon_grid", use_gtk = False)
|
||||
# state.icon_grid = event_system.emit_and_await("get_files_view_icon_grid", (state.wid, state.tid))
|
||||
state.store = state.icon_grid.get_model()
|
||||
|
||||
# NOTE: Need to watch this as I thought we had issues with just using single reference upon closing it.
|
||||
# But, I found that not doing it this way caused objects to generate upon every click... (Because we're getting state info, duh)
|
||||
# Yet interactive debug view shows them just pilling on and never clearing...
|
||||
state.message_dialog = self.message_dialog
|
||||
state.user_pass_dialog = self.user_pass_dialog
|
||||
# state.message_dialog = MessageWidget()
|
||||
# state.user_pass_dialog = UserPassWidget()
|
||||
|
||||
selected_files = state.icon_grid.get_selected_items()
|
||||
if selected_files:
|
||||
|
@ -186,4 +179,4 @@ class Controller_Data:
|
|||
proc = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
|
||||
proc.stdin.write(data.encode("utf-8"))
|
||||
proc.stdin.close()
|
||||
retcode = proc.wait()
|
||||
retcode = proc.wait()
|
|
@ -40,6 +40,7 @@ class FileSystemActions(HandlerMixin, CRUDMixin):
|
|||
|
||||
event_system.subscribe("open_files", self.open_files)
|
||||
event_system.subscribe("open_with_files", self.open_with_files)
|
||||
event_system.subscribe("open_2_new_tab", self.open_2_new_tab)
|
||||
event_system.subscribe("execute_files", self.execute_files)
|
||||
|
||||
event_system.subscribe("cut_files", self.cut_files)
|
||||
|
@ -104,6 +105,12 @@ class FileSystemActions(HandlerMixin, CRUDMixin):
|
|||
|
||||
state.tab.app_chooser_exec(app_info, uris)
|
||||
|
||||
def open_2_new_tab(self):
|
||||
state = event_system.emit_and_await("get_current_state")
|
||||
uri = state.uris[0]
|
||||
message = f"FILE|{uri}"
|
||||
logger.info(message)
|
||||
event_system.emit("post_file_to_ipc", message)
|
||||
|
||||
def execute_files(self, in_terminal=False):
|
||||
state = event_system.emit_and_await("get_current_state")
|
||||
|
@ -111,4 +118,4 @@ class FileSystemActions(HandlerMixin, CRUDMixin):
|
|||
command = None
|
||||
for path in state.uris:
|
||||
command = f"{shlex.quote(path)}" if not in_terminal else f"{state.tab.terminal_app} -e {shlex.quote(path)}"
|
||||
state.tab.execute(shlex.split(command), start_dir=state.tab.get_current_directory())
|
||||
state.tab.execute(shlex.split(command), start_dir=state.tab.get_current_directory())
|
|
@ -39,7 +39,6 @@ class FileActionSignalsMixin:
|
|||
if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.DELETED,
|
||||
Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN,
|
||||
Gio.FileMonitorEvent.MOVED_OUT]:
|
||||
logger.debug(eve_type)
|
||||
|
||||
if eve_type in [Gio.FileMonitorEvent.MOVED_IN, Gio.FileMonitorEvent.MOVED_OUT]:
|
||||
self.update_on_soft_lock_end(data[0])
|
||||
|
@ -48,7 +47,7 @@ class FileActionSignalsMixin:
|
|||
else:
|
||||
self.soft_lock_countdown(data[0])
|
||||
|
||||
@threaded
|
||||
@daemon_threaded
|
||||
def soft_lock_countdown(self, tab_widget):
|
||||
self.soft_update_lock[tab_widget] = { "last_update_time": time.time()}
|
||||
|
||||
|
@ -63,7 +62,6 @@ class FileActionSignalsMixin:
|
|||
self.soft_update_lock.pop(tab_widget, None)
|
||||
GLib.idle_add(self.update_on_soft_lock_end, *(tab_widget,))
|
||||
|
||||
|
||||
def update_on_soft_lock_end(self, tab_widget):
|
||||
wid, tid = tab_widget.split("|")
|
||||
notebook = self.builder.get_object(f"window_{wid}")
|
||||
|
@ -81,6 +79,8 @@ class FileActionSignalsMixin:
|
|||
if [wid, tid] in [state.wid, state.tid]:
|
||||
self.set_bottom_labels(tab)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def do_file_search(self, widget, eve = None):
|
||||
if not self.ctrl_down and not self.shift_down and not self.alt_down:
|
||||
|
@ -102,4 +102,4 @@ class FileActionSignalsMixin:
|
|||
|
||||
items = icon_grid.get_selected_items()
|
||||
if len(items) > 0:
|
||||
icon_grid.scroll_to_path(items[0], False, 0.5, 0.5)
|
||||
icon_grid.scroll_to_path(items[0], False, 0.5, 0.5)
|
|
@ -11,8 +11,8 @@ from gi.repository import Gdk
|
|||
# Application imports
|
||||
|
||||
|
||||
valid_keyvalue_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]")
|
||||
|
||||
valid_keyvalue_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]")
|
||||
|
||||
|
||||
|
||||
|
@ -20,13 +20,25 @@ class KeyboardSignalsMixin:
|
|||
""" KeyboardSignalsMixin keyboard hooks controller. """
|
||||
|
||||
# TODO: Need to set methods that use this to somehow check the keybindings state instead.
|
||||
def unset_keys_and_data(self, widget=None, eve=None):
|
||||
def unset_keys_and_data(self, widget = None, eve = None):
|
||||
self.ctrl_down = False
|
||||
self.shift_down = False
|
||||
self.alt_down = False
|
||||
|
||||
def unmap_special_keys(self, keyname):
|
||||
if "control" in keyname:
|
||||
self.ctrl_down = False
|
||||
if "shift" in keyname:
|
||||
self.shift_down = False
|
||||
if "alt" in keyname:
|
||||
self.alt_down = False
|
||||
|
||||
def on_global_key_press_controller(self, eve, user_data):
|
||||
keyname = Gdk.keyval_name(user_data.keyval).lower()
|
||||
modifiers = Gdk.ModifierType(user_data.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||
|
||||
self.was_midified_key = True if modifiers != 0 else False
|
||||
|
||||
if keyname.replace("_l", "").replace("_r", "") in ["control", "alt", "shift"]:
|
||||
if "control" in keyname:
|
||||
self.ctrl_down = True
|
||||
|
@ -36,52 +48,49 @@ class KeyboardSignalsMixin:
|
|||
self.alt_down = True
|
||||
|
||||
def on_global_key_release_controller(self, widget, event):
|
||||
"""Handler for keyboard events"""
|
||||
keyname = Gdk.keyval_name(event.keyval).lower()
|
||||
""" Handler for keyboard events """
|
||||
keyname = Gdk.keyval_name(event.keyval).lower()
|
||||
modifiers = Gdk.ModifierType(event.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||
|
||||
if keyname.replace("_l", "").replace("_r", "") in ["control", "alt", "shift"]:
|
||||
if "control" in keyname:
|
||||
self.ctrl_down = False
|
||||
if "shift" in keyname:
|
||||
self.shift_down = False
|
||||
if "alt" in keyname:
|
||||
self.alt_down = False
|
||||
should_return = self.was_midified_key and (self.ctrl_down or self.shift_down or self.alt_down)
|
||||
self.unmap_special_keys(keyname)
|
||||
|
||||
if should_return:
|
||||
self.was_midified_key = False
|
||||
return
|
||||
|
||||
mapping = keybindings.lookup(event)
|
||||
logger.debug(f"on_global_key_release_controller > key > {keyname}")
|
||||
logger.debug(f"on_global_key_release_controller > keyval > {event.keyval}")
|
||||
logger.debug(f"on_global_key_release_controller > mapping > {mapping}")
|
||||
|
||||
if mapping:
|
||||
# See if in filemanager scope
|
||||
try:
|
||||
getattr(self, mapping)()
|
||||
return True
|
||||
except Exception:
|
||||
# Must be plugins scope, event call, OR we forgot to add method to file manager scope
|
||||
if "||" in mapping:
|
||||
sender, eve_type = mapping.split("||")
|
||||
else:
|
||||
sender = ""
|
||||
eve_type = mapping
|
||||
|
||||
self.handle_plugin_key_event(sender, eve_type)
|
||||
self.handle_mapped_key_event(mapping)
|
||||
else:
|
||||
logger.debug(f"on_global_key_release_controller > key > {keyname}")
|
||||
self.handle_as_key_event_scope(keyname)
|
||||
|
||||
if self.ctrl_down:
|
||||
if keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]:
|
||||
self.builder.get_object(f"tggl_notebook_{keyname.strip('kp_')}").released()
|
||||
def handle_mapped_key_event(self, mapping):
|
||||
try:
|
||||
self.handle_as_controller_scope(mapping)
|
||||
except Exception:
|
||||
self.handle_as_plugin_scope(mapping)
|
||||
|
||||
def handle_plugin_key_event(self, sender, eve_type):
|
||||
event_system.emit(eve_type)
|
||||
def handle_as_controller_scope(self, mapping):
|
||||
getattr(self, mapping)()
|
||||
|
||||
def keyboard_close_tab(self):
|
||||
wid, tid = self.fm_controller.get_active_wid_and_tid()
|
||||
notebook = self.builder.get_object(f"window_{wid}")
|
||||
scroll = self.builder.get_object(f"{wid}|{tid}", use_gtk = False)
|
||||
page = notebook.page_num(scroll)
|
||||
tab = self.get_fm_window(wid).get_tab_by_id(tid)
|
||||
watcher = tab.get_dir_watcher()
|
||||
watcher.cancel()
|
||||
def handle_as_plugin_scope(self, mapping):
|
||||
if "||" in mapping:
|
||||
sender, eve_type = mapping.split("||")
|
||||
else:
|
||||
sender = ""
|
||||
eve_type = mapping
|
||||
|
||||
self.get_fm_window(wid).delete_tab_by_id(tid)
|
||||
notebook.remove_page(page)
|
||||
if not trace_debug:
|
||||
self.fm_controller.save_state()
|
||||
self.set_window_title()
|
||||
self.handle_key_event_system(sender, eve_type)
|
||||
|
||||
def handle_as_key_event_scope(self, keyname):
|
||||
if self.ctrl_down and not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]:
|
||||
self.handle_key_event_system(None, keyname)
|
||||
|
||||
def handle_key_event_system(self, sender, eve_type):
|
||||
event_system.emit(eve_type)
|
|
@ -7,6 +7,7 @@ import gi
|
|||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ...widgets.tab_header_widget import TabHeaderWidget
|
||||
|
@ -19,68 +20,73 @@ class GridMixin:
|
|||
"""docstring for GridMixin"""
|
||||
|
||||
def load_store(self, tab, store, save_state = False, use_generator = False):
|
||||
# dir = tab.get_current_directory()
|
||||
# file = Gio.File.new_for_path(dir)
|
||||
# dir_list = Gtk.DirectoryList.new("standard::*", file)
|
||||
# store.set(dir_list)
|
||||
|
||||
# file = Gio.File.new_for_path(dir)
|
||||
# for file in file.enumerate_children("standard::*", Gio.FILE_ATTRIBUTE_STANDARD_NAME, None):
|
||||
# store.append(file)
|
||||
|
||||
# return
|
||||
|
||||
|
||||
dir = tab.get_current_directory()
|
||||
files = tab.get_files()
|
||||
store.clear()
|
||||
|
||||
for file in files:
|
||||
store.append([None, file[0]])
|
||||
|
||||
Gtk.main_iteration()
|
||||
# for i, file in enumerate(files):
|
||||
# self.create_icon(i, tab, store, dir, file[0])
|
||||
|
||||
if use_generator:
|
||||
# NOTE: tab > icon > _get_system_thumbnail_gtk_thread must not be used
|
||||
# as the attempted promotion back to gtk threading stalls the generator. (We're already in main gtk thread)
|
||||
for i, icon in enumerate( self.create_icons_generator(tab, dir, files) ):
|
||||
self.load_icon(i, store, icon)
|
||||
else:
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop and loop.is_running():
|
||||
loop.create_task( self.create_icons(tab, store, dir, files) )
|
||||
else:
|
||||
asyncio.run( self.create_icons(tab, store, dir, files) )
|
||||
self.generate_icons(tab, store, dir, files)
|
||||
# GLib.Thread("", self.generate_icons, tab, store, dir, files)
|
||||
|
||||
# NOTE: Not likely called often from here but it could be useful
|
||||
if save_state and not trace_debug:
|
||||
self.fm_controller.save_state()
|
||||
|
||||
|
||||
@daemon_threaded
|
||||
def generate_icons(self, tab, store, dir, files):
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop and loop.is_running():
|
||||
loop.create_task( self.create_icons(tab, store, dir, files) )
|
||||
else:
|
||||
asyncio.run( self.create_icons(tab, store, dir, files) )
|
||||
|
||||
async def create_icons(self, tab, store, dir, files):
|
||||
tasks = [self.update_store(i, store, dir, tab, file[0]) for i, file in enumerate(files)]
|
||||
icons = [self.get_icon(tab, dir, file[0]) for file in files]
|
||||
data = await asyncio.gather(*icons)
|
||||
tasks = [self.update_store(i, store, icon) for i, icon in enumerate(data)]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
async def load_icon(self, i, store, icon):
|
||||
self.update_store(i, store, icon)
|
||||
GLib.idle_add(self.do_ui_update)
|
||||
|
||||
async def update_store(self, i, store, dir, tab, file):
|
||||
icon = tab.create_icon(dir, file)
|
||||
async def update_store(self, i, store, icon):
|
||||
itr = store.get_iter(i)
|
||||
GLib.idle_add(self.insert_store, store, itr, icon)
|
||||
|
||||
async def get_icon(self, tab, dir, file):
|
||||
return tab.create_icon(dir, file)
|
||||
|
||||
def insert_store(self, store, itr, icon):
|
||||
store.set_value(itr, 0, icon)
|
||||
|
||||
def create_icons_generator(self, tab, dir, files):
|
||||
for file in files:
|
||||
icon = tab.create_icon(dir, file[0])
|
||||
yield icon
|
||||
# Note: If the function returns GLib.SOURCE_REMOVE or False it is automatically removed from the list of event sources and will not be called again.
|
||||
return False
|
||||
|
||||
# @daemon_threaded
|
||||
# def create_icon(self, i, tab, store, dir, file):
|
||||
# icon = tab.create_icon(dir, file)
|
||||
# GLib.idle_add(self.update_store, *(i, store, icon,))
|
||||
#
|
||||
# @daemon_threaded
|
||||
# def load_icon(self, i, store, icon):
|
||||
# GLib.idle_add(self.update_store, *(i, store, icon,))
|
||||
def do_ui_update(self):
|
||||
Gtk.main_iteration()
|
||||
return False
|
||||
|
||||
# def update_store(self, i, store, icon):
|
||||
# itr = store.get_iter(i)
|
||||
# store.set_value(itr, 0, icon)
|
||||
|
||||
def create_tab_widget(self, tab):
|
||||
return TabHeaderWidget(tab, self.close_tab)
|
||||
def create_tab_widget(self):
|
||||
return TabHeaderWidget(self.close_tab)
|
||||
|
||||
def create_scroll_and_store(self, tab, wid, use_tree_view = False):
|
||||
scroll = Gtk.ScrolledWindow()
|
||||
|
@ -144,4 +150,4 @@ class GridMixin:
|
|||
icon_grid = obj.get_children()[0]
|
||||
name = icon_grid.get_name()
|
||||
if name == _name:
|
||||
return icon_grid
|
||||
return icon_grid
|
|
@ -34,10 +34,11 @@ class TabMixin(GridMixin):
|
|||
else:
|
||||
tab.set_path(path)
|
||||
|
||||
tab_widget = self.create_tab_widget(tab)
|
||||
tab_widget = self.get_tab_widget(tab)
|
||||
scroll, store = self.create_scroll_and_store(tab, wid)
|
||||
index = notebook.append_page(scroll, tab_widget)
|
||||
notebook.set_tab_detachable(scroll, True)
|
||||
notebook.set_tab_reorderable(scroll, True)
|
||||
|
||||
self.fm_controller.set_wid_and_tid(wid, tab.get_id())
|
||||
path_entry.set_text(tab.get_current_directory())
|
||||
|
@ -46,11 +47,18 @@ class TabMixin(GridMixin):
|
|||
|
||||
ctx = notebook.get_style_context()
|
||||
ctx.add_class("notebook-unselected-focus")
|
||||
notebook.set_tab_reorderable(scroll, True)
|
||||
self.load_store(tab, store)
|
||||
self.set_window_title()
|
||||
self.set_file_watcher(tab)
|
||||
|
||||
def get_tab_widget(self, tab):
|
||||
tab_widget = self.create_tab_widget()
|
||||
tab_widget.tab = tab
|
||||
|
||||
tab_widget.label.set_label(f"{tab.get_end_of_path()}")
|
||||
tab_widget.label.set_width_chars(len(tab.get_end_of_path()))
|
||||
|
||||
return tab_widget
|
||||
|
||||
def close_tab(self, button, eve = None):
|
||||
notebook = button.get_parent().get_parent()
|
||||
|
@ -71,11 +79,12 @@ class TabMixin(GridMixin):
|
|||
|
||||
self.builder.dereference_object(f"{wid}|{tid}|icon_grid")
|
||||
self.builder.dereference_object(f"{wid}|{tid}")
|
||||
icon_grid.set_model(None)
|
||||
|
||||
store.clear()
|
||||
icon_grid.destroy()
|
||||
scroll.destroy()
|
||||
tab_box.destroy()
|
||||
store.run_dispose()
|
||||
icon_grid.run_dispose()
|
||||
scroll.run_dispose()
|
||||
tab_box.run_dispose()
|
||||
|
||||
del store
|
||||
del icon_grid
|
||||
|
@ -84,12 +93,13 @@ class TabMixin(GridMixin):
|
|||
del watcher
|
||||
del tab
|
||||
|
||||
gc.collect()
|
||||
if not settings_manager.is_trace_debug():
|
||||
self.fm_controller.save_state()
|
||||
|
||||
self.set_window_title()
|
||||
|
||||
gc.collect()
|
||||
|
||||
# NOTE: Not actually getting called even tho set in the glade file...
|
||||
def on_tab_dnded(self, notebook, page, x, y):
|
||||
...
|
||||
|
@ -114,12 +124,13 @@ class TabMixin(GridMixin):
|
|||
def on_tab_switch_update(self, notebook, content = None, index = None):
|
||||
self.selected_files.clear()
|
||||
wid, tid = content.get_children()[0].get_name().split("|")
|
||||
|
||||
self.fm_controller.set_wid_and_tid(wid, tid)
|
||||
self.set_path_text(wid, tid)
|
||||
self.set_window_title()
|
||||
|
||||
def get_id_from_tab_box(self, tab_box):
|
||||
return tab_box.get_children()[2].get_text()
|
||||
return tab_box.tab.get_id()
|
||||
|
||||
def get_tab_label(self, notebook, icon_grid):
|
||||
return notebook.get_tab_label(icon_grid.get_parent()).get_children()[0]
|
||||
|
@ -218,6 +229,7 @@ class TabMixin(GridMixin):
|
|||
def do_focused_click(self, button):
|
||||
button.grab_focus()
|
||||
button.clicked()
|
||||
return False
|
||||
|
||||
def set_path_entry(self, button = None, eve = None):
|
||||
self.path_auto_filled = True
|
||||
|
@ -236,4 +248,4 @@ class TabMixin(GridMixin):
|
|||
tab = self.get_fm_window(wid).get_tab_by_id(tid)
|
||||
tab.set_hiding_hidden(not tab.is_hiding_hidden())
|
||||
tab.load_directory()
|
||||
self.builder.get_object("refresh_tab").released()
|
||||
self.builder.get_object("refresh_tab").released()
|
|
@ -177,6 +177,10 @@ class WindowMixin(TabMixin):
|
|||
if from_uri != dest:
|
||||
event_system.emit("move_files", (uris, dest))
|
||||
|
||||
Gtk.drag_finish(drag_context, True, False, time)
|
||||
return
|
||||
|
||||
Gtk.drag_finish(drag_context, False, False, time)
|
||||
|
||||
def create_new_tab_notebook(self, widget=None, wid=None, path=None):
|
||||
self.create_tab(wid, None, path)
|
||||
self.create_tab(wid, None, path)
|
|
@ -6,6 +6,7 @@ gi.require_version('Gtk', '3.0')
|
|||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from .mixins.ui.pane_mixin import PaneMixin
|
||||
|
@ -34,15 +35,15 @@ class UIMixin(PaneMixin, WindowMixin):
|
|||
nickname = session["window"]["Nickname"]
|
||||
tabs = session["window"]["tabs"]
|
||||
isHidden = True if session["window"]["isHidden"] == "True" else False
|
||||
event_system.emit("load_files_view_state", (nickname, tabs))
|
||||
event_system.emit("load_files_view_state", (nickname, tabs, isHidden))
|
||||
|
||||
|
||||
@daemon_threaded
|
||||
def _focus_last_visible_notebook(self, icon_grid):
|
||||
import time
|
||||
|
||||
window = settings_manager.get_main_window()
|
||||
while not window.is_visible() and not window.get_realized():
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.2)
|
||||
|
||||
icon_grid.event(Gdk.Event().new(type = Gdk.EventType.BUTTON_RELEASE))
|
||||
|
||||
|
@ -77,7 +78,7 @@ class UIMixin(PaneMixin, WindowMixin):
|
|||
|
||||
scroll_win = notebook.get_children()[-1]
|
||||
icon_grid = scroll_win.get_children()[0]
|
||||
self._focus_last_visible_notebook(icon_grid)
|
||||
GLib.Thread("", self._focus_last_visible_notebook, icon_grid)
|
||||
except UIMixinException as e:
|
||||
logger.info("\n: The saved session might be missing window data! :\nLocation: ~/.config/solarfm/session.json\nFix: Back it up and delete it to reset.\n")
|
||||
logger.debug(repr(e))
|
||||
|
|
|
@ -50,6 +50,9 @@ class RenameWidget:
|
|||
def show_rename_file_menu(self, widget=None, eve=None):
|
||||
if widget:
|
||||
widget.grab_focus()
|
||||
end_i = widget.get_text().rfind(".")
|
||||
if end_i > 0:
|
||||
widget.select_region(0, end_i)
|
||||
|
||||
response = self._rename_file_menu.run()
|
||||
if response == Gtk.ResponseType.CLOSE:
|
||||
|
@ -78,4 +81,4 @@ class RenameWidget:
|
|||
def hide_rename_file_menu_enter_key(self, widget=None, eve=None):
|
||||
keyname = Gdk.keyval_name(eve.keyval).lower()
|
||||
if keyname in ["return", "enter"]:
|
||||
self._rename_file_menu.hide()
|
||||
self._rename_file_menu.hide()
|
|
@ -1,11 +1,9 @@
|
|||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ...sfm_builder import SFMBuilder
|
||||
from ...mixins.signals.file_action_signals_mixin import FileActionSignalsMixin
|
||||
from .window_mixin import WindowMixin
|
||||
|
||||
|
@ -27,7 +25,8 @@ class FilesWidget(FileActionSignalsMixin, WindowMixin):
|
|||
|
||||
self.INDEX = self.ccount
|
||||
self.NAME = f"window_{self.INDEX}"
|
||||
self.builder = Gtk.Builder()
|
||||
self.builder = SFMBuilder()
|
||||
|
||||
self.files_view = None
|
||||
self.fm_controller = None
|
||||
|
||||
|
@ -41,20 +40,21 @@ class FilesWidget(FileActionSignalsMixin, WindowMixin):
|
|||
...
|
||||
|
||||
def _setup_signals(self):
|
||||
settings_manager.register_signals_to_builder([self,], self.builder)
|
||||
settings_manager.register_signals_to_builder([self], self.builder)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("load_files_view_state", self._load_files_view_state)
|
||||
event_system.subscribe("get_files_view_icon_grid", self._get_files_view_icon_grid)
|
||||
|
||||
def _load_widgets(self):
|
||||
_builder = settings_manager.get_builder()
|
||||
_builder = settings_manager.get_builder()
|
||||
self.files_view = _builder.get_object(f"{self.NAME}")
|
||||
|
||||
self.files_view.set_group_name("files_widget")
|
||||
|
||||
self.builder.expose_object(f"{self.NAME}", self.files_view)
|
||||
|
||||
def _load_files_view_state(self, win_name = None, tabs = None):
|
||||
def _load_files_view_state(self, win_name = None, tabs = None, isHidden = False):
|
||||
if win_name == self.NAME:
|
||||
if tabs:
|
||||
for tab in tabs:
|
||||
|
@ -62,10 +62,13 @@ class FilesWidget(FileActionSignalsMixin, WindowMixin):
|
|||
else:
|
||||
self.create_new_tab_notebook(None, self.INDEX, None)
|
||||
|
||||
if isHidden:
|
||||
self.files_view.hide()
|
||||
|
||||
def _get_files_view_icon_grid(self, win_index = None, tid = None):
|
||||
if win_index == str(self.INDEX):
|
||||
return self.builder.get_object(f"{self.INDEX}|{tid}|icon_grid", use_gtk = False)
|
||||
|
||||
|
||||
def set_fm_controller(self, _fm_controller):
|
||||
self.fm_controller = _fm_controller
|
||||
self.fm_controller = _fm_controller
|
|
@ -7,6 +7,7 @@ import gi
|
|||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ...widgets.tab_header_widget import TabHeaderWidget
|
||||
|
@ -19,6 +20,18 @@ class GridMixin:
|
|||
"""docstring for GridMixin"""
|
||||
|
||||
def load_store(self, tab, store, save_state = False, use_generator = False):
|
||||
# dir = tab.get_current_directory()
|
||||
# file = Gio.File.new_for_path(dir)
|
||||
# dir_list = Gtk.DirectoryList.new("standard::*", file)
|
||||
# store.set(dir_list)
|
||||
|
||||
# file = Gio.File.new_for_path(dir)
|
||||
# for file in file.enumerate_children("standard::*", Gio.FILE_ATTRIBUTE_STANDARD_NAME, None):
|
||||
# store.append(file)
|
||||
|
||||
# return
|
||||
|
||||
|
||||
dir = tab.get_current_directory()
|
||||
files = tab.get_files()
|
||||
|
||||
|
@ -26,60 +39,53 @@ class GridMixin:
|
|||
store.append([None, file[0]])
|
||||
|
||||
Gtk.main_iteration()
|
||||
if use_generator:
|
||||
# NOTE: tab > icon > _get_system_thumbnail_gtk_thread must not be used
|
||||
# as the attempted promotion back to gtk threading stalls the generator. (We're already in main gtk thread)
|
||||
for i, icon in enumerate( self.create_icons_generator(tab, dir, files) ):
|
||||
self.load_icon(i, store, icon)
|
||||
else:
|
||||
# for i, file in enumerate(files):
|
||||
# self.create_icon(i, tab, store, dir, file[0])
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop and loop.is_running():
|
||||
loop.create_task( self.create_icons(tab, store, dir, files) )
|
||||
else:
|
||||
asyncio.run( self.create_icons(tab, store, dir, files) )
|
||||
self.generate_icons(tab, store, dir, files)
|
||||
# GLib.Thread("", self.generate_icons, tab, store, dir, files)
|
||||
|
||||
# NOTE: Not likely called often from here but it could be useful
|
||||
if save_state and not trace_debug:
|
||||
self.fm_controller.save_state()
|
||||
|
||||
|
||||
@daemon_threaded
|
||||
def generate_icons(self, tab, store, dir, files):
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop and loop.is_running():
|
||||
loop.create_task( self.create_icons(tab, store, dir, files) )
|
||||
else:
|
||||
asyncio.run( self.create_icons(tab, store, dir, files) )
|
||||
|
||||
async def create_icons(self, tab, store, dir, files):
|
||||
tasks = [self.update_store(i, store, dir, tab, file[0]) for i, file in enumerate(files)]
|
||||
icons = [self.get_icon(tab, dir, file[0]) for file in files]
|
||||
data = await asyncio.gather(*icons)
|
||||
tasks = [self.update_store(i, store, icon) for i, icon in enumerate(data)]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
async def load_icon(self, i, store, icon):
|
||||
self.update_store(i, store, icon)
|
||||
GLib.idle_add(self.do_ui_update)
|
||||
|
||||
async def update_store(self, i, store, dir, tab, file):
|
||||
icon = tab.create_icon(dir, file)
|
||||
async def update_store(self, i, store, icon):
|
||||
itr = store.get_iter(i)
|
||||
GLib.idle_add(self.insert_store, store, itr, icon)
|
||||
|
||||
async def get_icon(self, tab, dir, file):
|
||||
return tab.create_icon(dir, file)
|
||||
|
||||
def insert_store(self, store, itr, icon):
|
||||
store.set_value(itr, 0, icon)
|
||||
|
||||
def create_icons_generator(self, tab, dir, files):
|
||||
for file in files:
|
||||
icon = tab.create_icon(dir, file[0])
|
||||
yield icon
|
||||
# Note: If the function returns GLib.SOURCE_REMOVE or False it is automatically removed from the list of event sources and will not be called again.
|
||||
return False
|
||||
|
||||
# @daemon_threaded
|
||||
# def create_icon(self, i, tab, store, dir, file):
|
||||
# icon = tab.create_icon(dir, file)
|
||||
# GLib.idle_add(self.update_store, *(i, store, icon,))
|
||||
#
|
||||
# @daemon_threaded
|
||||
# def load_icon(self, i, store, icon):
|
||||
# GLib.idle_add(self.update_store, *(i, store, icon,))
|
||||
#
|
||||
# def update_store(self, i, store, icon):
|
||||
# itr = store.get_iter(i)
|
||||
# store.set_value(itr, 0, icon)
|
||||
def do_ui_update(self):
|
||||
Gtk.main_iteration()
|
||||
return False
|
||||
|
||||
def create_tab_widget(self, tab):
|
||||
return TabHeaderWidget(tab, self.close_tab)
|
||||
def create_tab_widget(self):
|
||||
return TabHeaderWidget(self.close_tab)
|
||||
|
||||
def create_scroll_and_store(self, tab, wid, use_tree_view = False):
|
||||
scroll = Gtk.ScrolledWindow()
|
||||
|
@ -136,4 +142,4 @@ class GridMixin:
|
|||
store = icon_grid.get_model()
|
||||
tab_label = notebook.get_tab_label(obj).get_children()[0]
|
||||
|
||||
return store, tab_label
|
||||
return store, tab_label
|
|
@ -34,10 +34,11 @@ class TabMixin(GridMixin):
|
|||
else:
|
||||
tab.set_path(path)
|
||||
|
||||
tab_widget = self.create_tab_widget(tab)
|
||||
tab_widget = self.get_tab_widget(tab)
|
||||
scroll, store = self.create_scroll_and_store(tab, wid)
|
||||
index = notebook.append_page(scroll, tab_widget)
|
||||
notebook.set_tab_detachable(scroll, True)
|
||||
notebook.set_tab_reorderable(scroll, True)
|
||||
|
||||
self.fm_controller.set_wid_and_tid(wid, tab.get_id())
|
||||
event_system.emit("go_to_path", (tab.get_current_directory(),)) # NOTE: Not efficent if I understand how
|
||||
|
@ -47,12 +48,19 @@ class TabMixin(GridMixin):
|
|||
|
||||
ctx = notebook.get_style_context()
|
||||
ctx.add_class("notebook-unselected-focus")
|
||||
notebook.set_tab_reorderable(scroll, True)
|
||||
self.load_store(tab, store)
|
||||
# self.set_window_title()
|
||||
event_system.emit("set_window_title", (tab.get_current_directory(),))
|
||||
self.set_file_watcher(tab)
|
||||
|
||||
def get_tab_widget(self, tab):
|
||||
tab_widget = self.create_tab_widget()
|
||||
tab_widget.tab_id = tab.get_id()
|
||||
|
||||
tab_widget.label.set_label(f"{tab.get_end_of_path()}")
|
||||
tab_widget.label.set_width_chars(len(tab.get_end_of_path()))
|
||||
|
||||
return tab_widget
|
||||
|
||||
def close_tab(self, button, eve = None):
|
||||
notebook = button.get_parent().get_parent()
|
||||
|
@ -73,15 +81,12 @@ class TabMixin(GridMixin):
|
|||
|
||||
self.builder.dereference_object(f"{wid}|{tid}|icon_grid")
|
||||
self.builder.dereference_object(f"{wid}|{tid}")
|
||||
icon_grid.set_model(None)
|
||||
|
||||
store.clear()
|
||||
# store.run_dispose()
|
||||
icon_grid.destroy()
|
||||
# icon_grid.run_dispose()
|
||||
scroll.destroy()
|
||||
#scroll.run_dispose()
|
||||
tab_box.destroy()
|
||||
#tab_box.run_dispose()
|
||||
store.run_dispose()
|
||||
icon_grid.run_dispose()
|
||||
scroll.run_dispose()
|
||||
tab_box.run_dispose()
|
||||
|
||||
del store
|
||||
del icon_grid
|
||||
|
@ -90,12 +95,13 @@ class TabMixin(GridMixin):
|
|||
del watcher
|
||||
del tab
|
||||
|
||||
gc.collect()
|
||||
if not settings_manager.is_trace_debug():
|
||||
self.fm_controller.save_state()
|
||||
|
||||
self.set_window_title()
|
||||
|
||||
gc.collect()
|
||||
|
||||
# NOTE: Not actually getting called even tho set in the glade file...
|
||||
def on_tab_dnded(self, notebook, page, x, y):
|
||||
...
|
||||
|
@ -119,13 +125,13 @@ class TabMixin(GridMixin):
|
|||
|
||||
def on_tab_switch_update(self, notebook, content = None, index = None):
|
||||
self.selected_files.clear()
|
||||
wid, tid = content.get_children()[0].get_name().split("|")
|
||||
wid, tid = content.get_children()[0].tab.get_name().split("|")
|
||||
self.fm_controller.set_wid_and_tid(wid, tid)
|
||||
self.set_path_text(wid, tid)
|
||||
self.set_window_title()
|
||||
|
||||
def get_id_from_tab_box(self, tab_box):
|
||||
return tab_box.get_children()[2].get_text()
|
||||
return tab_box.tab.get_id()
|
||||
|
||||
def get_tab_label(self, notebook, icon_grid):
|
||||
return notebook.get_tab_label(icon_grid.get_parent()).get_children()[0]
|
||||
|
@ -225,6 +231,8 @@ class TabMixin(GridMixin):
|
|||
button.grab_focus()
|
||||
button.clicked()
|
||||
|
||||
return False
|
||||
|
||||
def set_path_entry(self, button = None, eve = None):
|
||||
self.path_auto_filled = True
|
||||
state = self.get_current_state()
|
||||
|
@ -241,4 +249,4 @@ class TabMixin(GridMixin):
|
|||
tab = self.get_fm_window(wid).get_tab_by_id(tid)
|
||||
tab.set_hiding_hidden(not tab.is_hiding_hidden())
|
||||
tab.load_directory()
|
||||
self.builder.get_object("refresh_tab").released()
|
||||
self.builder.get_object("refresh_tab").released()
|
|
@ -173,6 +173,10 @@ class WindowMixin(TabMixin):
|
|||
if from_uri != dest:
|
||||
event_system.emit("move_files", (uris, dest))
|
||||
|
||||
Gtk.drag_finish(drag_context, True, False, time)
|
||||
return
|
||||
|
||||
Gtk.drag_finish(drag_context, False, False, time)
|
||||
|
||||
def create_new_tab_notebook(self, widget=None, wid=None, path=None):
|
||||
self.create_tab(wid, None, path)
|
||||
self.create_tab(wid, None, path)
|
|
@ -75,6 +75,11 @@ class IconGridWidget(Gtk.IconView):
|
|||
return self.get_model()
|
||||
|
||||
def clear_and_set_new_store(self):
|
||||
store = self.get_model()
|
||||
if store:
|
||||
store.run_dispose()
|
||||
|
||||
self.set_model(None)
|
||||
store = Gtk.ListStore(GdkPixbuf.Pixbuf or GdkPixbuf.PixbufAnimation or None, str or None)
|
||||
# store = Gtk.ListStore(Gtk.DirectoryList)
|
||||
self.set_model(store)
|
||||
|
|
|
@ -59,7 +59,7 @@ class IconTreeWidget(Gtk.TreeView):
|
|||
name = Gtk.CellRendererText()
|
||||
selec = self.get_selection()
|
||||
|
||||
self.set_model(store)
|
||||
self.set_model(self._store)
|
||||
selec.set_mode(3)
|
||||
|
||||
column.pack_start(icon, False)
|
||||
|
|
|
@ -103,7 +103,7 @@ class MessagePopupWidget(Gtk.Popover):
|
|||
self.popup()
|
||||
self.hide_message_timeout(seconds)
|
||||
|
||||
@threaded
|
||||
@daemon_threaded
|
||||
def hide_message_timeout(self, seconds=3):
|
||||
time.sleep(seconds)
|
||||
GLib.idle_add(event_system.emit, ("hide_messages_popup"))
|
||||
|
@ -126,4 +126,4 @@ class MessagePopupWidget(Gtk.Popover):
|
|||
with open(target, "w") as f:
|
||||
f.write(text)
|
||||
|
||||
save_location_prompt.destroy()
|
||||
save_location_prompt.destroy()
|
|
@ -9,14 +9,12 @@ from gi.repository import Gtk
|
|||
|
||||
|
||||
|
||||
|
||||
class TabHeaderWidget(Gtk.Box):
|
||||
"""docstring for TabHeaderWidget"""
|
||||
|
||||
def __init__(self, tab, close_tab):
|
||||
def __init__(self, close_tab):
|
||||
super(TabHeaderWidget, self).__init__()
|
||||
|
||||
self._tab = tab
|
||||
self._close_tab = close_tab # NOTE: Close method in tab_mixin
|
||||
|
||||
self._setup_styling()
|
||||
|
@ -32,25 +30,19 @@ class TabHeaderWidget(Gtk.Box):
|
|||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
label = Gtk.Label()
|
||||
tid = Gtk.Label()
|
||||
self.label = Gtk.Label()
|
||||
close = Gtk.Button()
|
||||
icon = Gtk.Image(stock=Gtk.STOCK_CLOSE)
|
||||
|
||||
label.set_label(f"{self._tab.get_end_of_path()}")
|
||||
label.set_width_chars(len(self._tab.get_end_of_path()))
|
||||
label.set_xalign(0.0)
|
||||
label.set_margin_left(25)
|
||||
label.set_margin_right(25)
|
||||
label.set_hexpand(True)
|
||||
tid.set_label(f"{self._tab.get_id()}")
|
||||
self.label.set_xalign(0.0)
|
||||
self.label.set_margin_left(25)
|
||||
self.label.set_margin_right(25)
|
||||
self.label.set_hexpand(True)
|
||||
|
||||
close.connect("released", self._close_tab)
|
||||
|
||||
close.add(icon)
|
||||
self.add(label)
|
||||
self.add(self.label)
|
||||
self.add(close)
|
||||
self.add(tid)
|
||||
|
||||
self.show_all()
|
||||
tid.hide()
|
||||
self.show_all()
|
|
@ -25,17 +25,17 @@ class Window(Gtk.ApplicationWindow):
|
|||
|
||||
def __init__(self, args, unknownargs):
|
||||
super(Window, self).__init__()
|
||||
|
||||
self._controller = None
|
||||
settings_manager.set_main_window(self)
|
||||
|
||||
self._set_window_data()
|
||||
self._controller = None
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
|
||||
self._load_widgets(args, unknownargs)
|
||||
|
||||
self._set_window_data()
|
||||
self._set_size_constraints()
|
||||
self.show()
|
||||
|
||||
|
||||
|
@ -66,6 +66,18 @@ class Window(Gtk.ApplicationWindow):
|
|||
|
||||
self.add( self._controller.get_core_widget() )
|
||||
|
||||
def _set_size_constraints(self):
|
||||
_window_x = settings.config.main_window_x
|
||||
_window_y = settings.config.main_window_y
|
||||
_min_width = settings.config.main_window_min_width
|
||||
_min_height = settings.config.main_window_min_height
|
||||
_width = settings.config.main_window_width
|
||||
_height = settings.config.main_window_height
|
||||
|
||||
self.move(_window_x, _window_y - 28)
|
||||
self.set_size_request(_min_width, _min_height)
|
||||
self.set_default_size(_width, _height)
|
||||
|
||||
def _set_window_data(self) -> None:
|
||||
screen = self.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
|
@ -87,12 +99,25 @@ class Window(Gtk.ApplicationWindow):
|
|||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
cr.set_operator(cairo.OPERATOR_OVER)
|
||||
|
||||
|
||||
def _load_interactive_debug(self):
|
||||
self.set_interactive_debugging(True)
|
||||
|
||||
|
||||
def _tear_down(self, widget = None, eve = None):
|
||||
event_system.emit("shutting_down")
|
||||
|
||||
size = self.get_size()
|
||||
pos = self.get_position()
|
||||
|
||||
settings_manager.set_main_window_width(size.width)
|
||||
settings_manager.set_main_window_height(size.height)
|
||||
settings_manager.set_main_window_x(pos.root_x)
|
||||
settings_manager.set_main_window_y(pos.root_y)
|
||||
settings_manager.save_settings()
|
||||
|
||||
settings_manager.clear_pid()
|
||||
Gtk.main_quit()
|
||||
Gtk.main_quit()
|
||||
|
||||
def main(self):
|
||||
Gtk.main()
|
|
@ -119,6 +119,8 @@ class PluginsController:
|
|||
plugin.reference.run()
|
||||
self._plugin_collection.append(plugin)
|
||||
|
||||
return False
|
||||
|
||||
def reload_plugins(self, file: str = None) -> None:
|
||||
logger.info(f"Reloading plugins...")
|
||||
parent_path = os.getcwd()
|
||||
|
@ -127,4 +129,4 @@ class PluginsController:
|
|||
os.chdir(plugin.path)
|
||||
plugin.reference.reload_package(f"{plugin.path}/plugin.py")
|
||||
|
||||
os.chdir(parent_path)
|
||||
os.chdir(parent_path)
|
|
@ -138,6 +138,7 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin):
|
|||
def _call_gtk_thread(event, result):
|
||||
result.append( self.get_system_thumbnail(full_path, size) )
|
||||
event.set()
|
||||
return False
|
||||
|
||||
result = []
|
||||
event = threading.Event()
|
||||
|
@ -151,11 +152,11 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin):
|
|||
gio_file = Gio.File.new_for_path(full_path)
|
||||
info = gio_file.query_info('standard::icon' , 0, None)
|
||||
icon = info.get_icon().get_names()[0]
|
||||
data = settings_manager.get_icon_theme().lookup_icon(icon , size , 0)
|
||||
data = settings_manager.get_icon_theme().lookup_icon(icon , size, 0)
|
||||
|
||||
if data:
|
||||
icon_path = data.get_filename()
|
||||
return GdkPixbuf.Pixbuf.new_from_file(icon_path)
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, width = size, height = size)
|
||||
|
||||
raise IconException("No system icon found...")
|
||||
except IconException:
|
||||
|
@ -201,4 +202,4 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin):
|
|||
pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(data, GdkPixbuf.Colorspace.RGB,
|
||||
False, 8, w, h, w * 3)
|
||||
|
||||
return pixbuf.scale_simple(wxh[0], wxh[1], 2) # BILINEAR = 2
|
||||
return pixbuf.scale_simple(wxh[0], wxh[1], 2) # BILINEAR = 2
|
|
@ -113,4 +113,4 @@ class Launcher:
|
|||
if not os.path.islink(fp): # Skip if it is symbolic link
|
||||
total_size += os.path.getsize(fp)
|
||||
|
||||
return total_size
|
||||
return total_size
|
|
@ -18,7 +18,7 @@ def debug_signal_handler(signal, frame):
|
|||
rpdb2.start_embedded_debugger("foobar", True, True)
|
||||
rpdb2.setbreak(depth=1)
|
||||
return
|
||||
except StandardError:
|
||||
except Exception:
|
||||
...
|
||||
|
||||
try:
|
||||
|
@ -26,7 +26,7 @@ def debug_signal_handler(signal, frame):
|
|||
logger.debug("\n\nStarting embedded rconsole debugger...\n\n")
|
||||
rconsole.spawn_server()
|
||||
return
|
||||
except StandardError as ex:
|
||||
except Exception as ex:
|
||||
...
|
||||
|
||||
try:
|
||||
|
@ -34,7 +34,7 @@ def debug_signal_handler(signal, frame):
|
|||
logger.debug("\n\nStarting PuDB debugger...\n\n")
|
||||
set_trace(paused = True)
|
||||
return
|
||||
except StandardError as ex:
|
||||
except Exception as ex:
|
||||
...
|
||||
|
||||
try:
|
||||
|
@ -42,11 +42,11 @@ def debug_signal_handler(signal, frame):
|
|||
logger.debug("\n\nStarting embedded PDB debugger...\n\n")
|
||||
pdb.Pdb(skip=['gi.*']).set_trace()
|
||||
return
|
||||
except StandardError as ex:
|
||||
except Exception as ex:
|
||||
...
|
||||
|
||||
try:
|
||||
import code
|
||||
code.interact()
|
||||
except StandardError as ex:
|
||||
logger.debug(f"{ex}, returning to normal program flow...")
|
||||
except Exception as ex:
|
||||
logger.debug(f"{ex}, returning to normal program flow...")
|
|
@ -51,9 +51,10 @@ class IPCServer(Singleton):
|
|||
listener = Listener((self._ipc_address, self._ipc_port))
|
||||
|
||||
self.is_ipc_alive = True
|
||||
self._run_ipc_loop(listener)
|
||||
# self._run_ipc_loop(listener)
|
||||
GLib.Thread("", self._run_ipc_loop, listener)
|
||||
|
||||
@daemon_threaded
|
||||
# @daemon_threaded
|
||||
def _run_ipc_loop(self, listener) -> None:
|
||||
while True:
|
||||
try:
|
||||
|
@ -89,6 +90,8 @@ class IPCServer(Singleton):
|
|||
conn.close()
|
||||
break
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def send_ipc_message(self, message: str = "Empty Data...") -> None:
|
||||
try:
|
||||
|
@ -123,4 +126,4 @@ class IPCServer(Singleton):
|
|||
logger.error("IPC Socket no longer valid.... Removing.")
|
||||
os.unlink(self._ipc_address)
|
||||
except Exception as e:
|
||||
logger.error( repr(e) )
|
||||
logger.error( repr(e) )
|
|
@ -146,6 +146,13 @@ class SettingsManager(StartCheckMixin, Singleton):
|
|||
def is_trace_debug(self) -> bool: return self._trace_debug
|
||||
def is_debug(self) -> bool: return self._debug
|
||||
|
||||
def set_main_window_x(self, x = 0): self.settings.config.main_window_x = x
|
||||
def set_main_window_y(self, y = 0): self.settings.config.main_window_y = y
|
||||
def set_main_window_width(self, width = 800): self.settings.config.main_window_width = width
|
||||
def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height
|
||||
def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width
|
||||
def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height
|
||||
|
||||
def set_trace_debug(self, trace_debug: bool):
|
||||
self._trace_debug = trace_debug
|
||||
|
||||
|
|
|
@ -30,7 +30,14 @@ class Config:
|
|||
sys_icon_wh: list = field(default_factory=lambda: [56, 56])
|
||||
steam_cdn_url: str = "https://steamcdn-a.akamaihd.net/steam/apps/"
|
||||
remux_folder_max_disk_usage: str = "8589934592"
|
||||
make_transparent: int = 0
|
||||
main_window_x: int = 721
|
||||
main_window_y: int = 465
|
||||
main_window_min_width: int = 720
|
||||
main_window_min_height: int = 480
|
||||
main_window_width: int = 800
|
||||
main_window_height: int = 600
|
||||
application_dirs: list = field(default_factory=lambda: [
|
||||
"/usr/share/applications",
|
||||
f"{settings_manager.get_home_path()}/.local/share/applications"
|
||||
])
|
||||
])
|
|
@ -11,36 +11,48 @@ import inspect
|
|||
|
||||
|
||||
class StartCheckMixin:
|
||||
def is_dirty_start(self) -> bool: return self._dirty_start
|
||||
def clear_pid(self): self._clean_pid()
|
||||
def is_dirty_start(self) -> bool:
|
||||
return self._dirty_start
|
||||
|
||||
def clear_pid(self):
|
||||
if not self.is_trace_debug():
|
||||
self._clean_pid()
|
||||
|
||||
def do_dirty_start_check(self):
|
||||
if not os.path.exists(self._PID_FILE):
|
||||
self._write_new_pid()
|
||||
else:
|
||||
with open(self._PID_FILE, "r") as _pid:
|
||||
pid = _pid.readline().strip()
|
||||
if self.is_trace_debug():
|
||||
pid = os.getpid()
|
||||
self._print_pid(pid)
|
||||
return
|
||||
|
||||
if os.path.exists(self._PID_FILE):
|
||||
with open(self._PID_FILE, "r") as f:
|
||||
pid = f.readline().strip()
|
||||
if pid not in ("", None):
|
||||
self._check_alive_status(int(pid))
|
||||
else:
|
||||
self._write_new_pid()
|
||||
if self.is_pid_alive( int(pid) ):
|
||||
print("PID file exists and PID is alive... Letting downstream errors (sans debug args) handle app closure propigation.")
|
||||
return
|
||||
|
||||
self._write_new_pid()
|
||||
|
||||
""" Check For the existence of a unix pid. """
|
||||
def _check_alive_status(self, pid):
|
||||
def is_pid_alive(self, pid):
|
||||
print(f"PID Found: {pid}")
|
||||
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError:
|
||||
print(f"{app_name} is starting dirty...")
|
||||
print(f"{app_name} PID file exists but PID is irrelevant; starting dirty...")
|
||||
self._dirty_start = True
|
||||
self._write_new_pid()
|
||||
return
|
||||
return False
|
||||
|
||||
print("PID is alive... Let downstream errors (sans debug args) handle app closure propigation.")
|
||||
return True
|
||||
|
||||
def _write_new_pid(self):
|
||||
pid = os.getpid()
|
||||
self._write_pid(pid)
|
||||
self._print_pid(pid)
|
||||
|
||||
def _print_pid(self, pid):
|
||||
print(f"{app_name} PID: {pid}")
|
||||
|
||||
def _clean_pid(self):
|
||||
|
@ -48,4 +60,4 @@ class StartCheckMixin:
|
|||
|
||||
def _write_pid(self, pid):
|
||||
with open(self._PID_FILE, "w") as _pid:
|
||||
_pid.write(f"{pid}")
|
||||
_pid.write(f"{pid}")
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"Open Actions": {
|
||||
"Open": ["STOCK_OPEN", "open"],
|
||||
"Open With": ["STOCK_OPEN", "open_with"],
|
||||
"Execute": ["STOCK_EXECUTE", "execute"],
|
||||
"Open": ["STOCK_OPEN", "open"],
|
||||
"Open With": ["STOCK_OPEN", "open_with"],
|
||||
"Open 2 Tab": ["STOCK_OPEN", "open_2_new_tab"],
|
||||
"Execute": ["STOCK_EXECUTE", "execute"],
|
||||
"Execute in Terminal": ["STOCK_EXECUTE", "execute_in_terminal"]
|
||||
},
|
||||
"File Actions": {
|
||||
|
@ -16,4 +17,4 @@
|
|||
"Paste": ["STOCK_PASTE", "paste"]
|
||||
},
|
||||
"Plugins": {}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,14 @@
|
|||
"sys_icon_wh": [56, 56],
|
||||
"file_manager_app": "solarfm",
|
||||
"steam_cdn_url": "https://steamcdn-a.akamaihd.net/steam/apps/",
|
||||
"remux_folder_max_disk_usage": "8589934592"
|
||||
"remux_folder_max_disk_usage": "8589934592",
|
||||
"make_transparent":0,
|
||||
"main_window_x":721,
|
||||
"main_window_y":465,
|
||||
"main_window_min_width":720,
|
||||
"main_window_min_height":480,
|
||||
"main_window_width":800,
|
||||
"main_window_height":600,
|
||||
},
|
||||
"filters": {
|
||||
"meshs": [".dae", ".fbx", ".gltf", ".obj", ".stl"],
|
||||
|
|
Loading…
Reference in New Issue