#!/usr/bin/env python3 # vim: set et ts=4 sts=4 sw=4: # Startdate: 2024-11-20-4 16:31 # Title: Graphical Mount Manager in Gtk3 # Purpose: Easily mount iso files and easily manage these mounted files and mount points, basically like acetoneiso # Reference: # logout-manager-gtk import gi, os, sys, subprocess gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository.GdkPixbuf import Pixbuf sys.path.append("/usr/share/gmm") sys.path.append(".") import gmm_lib as gmm from gmm_lib import debuglev, ferror, appname # GRAPHICAL APP # ripped directly from logout-manager-gtk # graphical classes and functions def get_scaled_icon(icon_name, size=24, fallback_icon_name = "", icon_theme = "default"): # return a Gtk.Image.new_from_pixbuf # ripped from https://stackoverflow.com/questions/42800482/how-to-set-size-of-a-gtk-image-in-python and combined with https://stackoverflow.com/questions/6090241/how-can-i-get-the-full-file-path-of-an-icon-name # further ref for lookup_icon function: https://lazka.github.io/pgi-docs/Gtk-3.0/flags.html#Gtk.IconLookupFlags # if a file exists by the specific name, use it. if Path(icon_name).is_file(): iconfilename = icon_name else: if icon_theme != "default": this_theme = Gtk.IconTheme.new() this_theme.set_custom_theme(icon_theme) else: this_theme = Gtk.IconTheme.get_default() try: icon_info = this_theme.lookup_icon(icon_name, size, 0) iconfilename = icon_info.get_filename() except: try: icon_info = this_theme.lookup_icon(fallback_icon_name, size, 0) iconfilename = icon_info.get_filename() except: # no icon in the current theme. Try a hard-coded fallback: try: # if debuglev 3 print("Error: could not find default icon for", icon_name+", so using fallback.") this_theme = Gtk.IconTheme.new() this_theme.set_custom_theme("Numix-Circle") icon_info = this_theme.lookup_icon(icon_name, size, 0) iconfilename = icon_info.get_filename() except: print("Error: Could not find any icon for", icon_name) return None #print(iconfilename) return Gtk.Image.new_from_pixbuf(Pixbuf.new_from_file_at_scale( filename=iconfilename, width=size, height=size, preserve_aspect_ratio=True)) class MainWindow(Gtk.Window): def __init__(self, gmmapp): self.gmmapp = gmmapp Gtk.Window.__init__(self, title="Graphical Mount Manager") # for window icon liststore = Gtk.ListStore(Pixbuf, str) iconview = Gtk.IconView.new() iconview.set_model(liststore) iconview.set_pixbuf_column(0) iconview.set_text_column(1) pixbuf24 = Gtk.IconTheme.get_default().load_icon("dvd_unmount", 24, 0) pixbuf32 = Gtk.IconTheme.get_default().load_icon("dvd_unmount", 32, 0) pixbuf48 = Gtk.IconTheme.get_default().load_icon("dvd_unmount", 48, 0) pixbuf64 = Gtk.IconTheme.get_default().load_icon("dvd_unmount", 64, 0) pixbuf96 = Gtk.IconTheme.get_default().load_icon("dvd_unmount", 96, 0) self.set_icon_list([pixbuf24, pixbuf32, pixbuf48, pixbuf64, pixbuf96]); self.grid = Gtk.Grid() self.add(self.grid) self.liststore = Gtk.ListStore(str,str) renderer = Gtk.CellRendererText() #column = Gtk.TreeViewColumn("Source",renderer,text=0,weight=1) self.ml = Gtk.TreeView(model=self.liststore) self.ml.append_column(Gtk.TreeViewColumn("Source",renderer,text=0)) self.ml.append_column(Gtk.TreeViewColumn("Mount point",renderer,text=0)) self.ml.connect("row-activated", self.func_double_click_entry) self.current_selection = None selection = self.ml.get_selection() selection.connect("changed", self.func_tree_selection_changed) self.grid.attach(self.ml, 0,0, 4, 1) self.unmount_btn = Gtk.Button.new_with_mnemonic(label="_Unmount") self.unmount_btn.connect("clicked", self.func_unmount_current_selection) self.grid.attach_next_to(self.unmount_btn,self.ml,Gtk.PositionType.BOTTOM,1,1) # WORKHERE: add menu, dnd # initial load self.refresh_form() def refresh_form(self): self.gmmapp.mounts = self.gmmapp.list_mounts() self.liststore.clear() for i in self.gmmapp.mounts: self.liststore.append([i["source"],i["mountpoint"]]) def func_double_click_entry(self, tree_view, path, column): if debuglev(9): ferror(f"DEBUG: double-click {tree_view},{path},{column}") path = self.current_selection if path: if debuglev(1): ferror(f"Running xdg-open {path}") subprocess.Popen(["xdg-open",path]) else: if debuglev(4): ferror(f"INFO: No item selected to open, continuing...") pass def func_tree_selection_changed(self, selection): model, treeiter = selection.get_selected() if treeiter is not None: # you have to know which column has the mountpoint. It is column 1 in gmm. try: self.current_selection = str(model[treeiter][1]) except Exception as e: print(f"WARNING: cannot seem to save string from {model[treeiter]}") def func_unmount_current_selection(self, o1 = None): if debuglev(9): ferror(f"DEBUG: unmount button {o1}") #ferror(f"please unmount, {self.current_selection}!") path = self.current_selection if path: self.gmmapp.unmount_iso_to_path(path,"") self.refresh_form() elif debuglev(4): ferror(f"INFO: Nothing selected to unmount, continuing...") if "__main__" == __name__: # MAIN GRAPICAL APP app = gmm.Gmm(gmm.args) app.cli_main() if app.show_gui: win = MainWindow(app) win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main()