summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/foo.glade40
-rw-r--r--example/foo.py132
-rwxr-xr-xgmm-gtk180
-rwxr-xr-xgmm-tk2
4 files changed, 161 insertions, 193 deletions
diff --git a/example/foo.glade b/example/foo.glade
deleted file mode 100644
index b29f92f..0000000
--- a/example/foo.glade
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
- <menu id="app-menu">
- <section>
- <attribute name="label" translatable="yes">Change label</attribute>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 1</attribute>
- <attribute name="label" translatable="yes">String 1</attribute>
- </item>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 2</attribute>
- <attribute name="label" translatable="yes">String 2</attribute>
- </item>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 3</attribute>
- <attribute name="label" translatable="yes">String 3</attribute>
- </item>
- </section>
- <section>
- <item>
- <attribute name="action">win.maximize</attribute>
- <attribute name="label" translatable="yes">Maximize</attribute>
- </item>
- </section>
- <section>
- <item>
- <attribute name="action">app.about</attribute>
- <attribute name="label" translatable="yes">_About</attribute>
- </item>
- <item>
- <attribute name="action">app.quit</attribute>
- <attribute name="label" translatable="yes">_Quit</attribute>
- <attribute name="accel">&lt;Primary&gt;q</attribute>
- </item>
- </section>
- </menu>
-</interface>
diff --git a/example/foo.py b/example/foo.py
deleted file mode 100644
index bfcac79..0000000
--- a/example/foo.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import sys
-import gi
-gi.require_version("Gtk", "3.0")
-from gi.repository import GLib, Gio, Gtk
-# This would typically be its own file
-MENU_XML = """
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
- <menu id="app-menu">
- <section>
- <attribute name="label" translatable="yes">Change label</attribute>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 1</attribute>
- <attribute name="label" translatable="yes">String 1</attribute>
- </item>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 2</attribute>
- <attribute name="label" translatable="yes">String 2</attribute>
- </item>
- <item>
- <attribute name="action">win.change_label</attribute>
- <attribute name="target">String 3</attribute>
- <attribute name="label" translatable="yes">String 3</attribute>
- </item>
- </section>
- <section>
- <item>
- <attribute name="action">win.maximize</attribute>
- <attribute name="label" translatable="yes">Maximize</attribute>
- </item>
- </section>
- <section>
- <item>
- <attribute name="action">app.about</attribute>
- <attribute name="label" translatable="yes">_About</attribute>
- </item>
- <item>
- <attribute name="action">app.quit</attribute>
- <attribute name="label" translatable="yes">_Quit</attribute>
- <attribute name="accel">&lt;Primary&gt;q</attribute>
- </item>
- </section>
- </menu>
-</interface>
-"""
-class AppWindow(Gtk.ApplicationWindow):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- # This will be in the windows group and have the "win" prefix
- max_action = Gio.SimpleAction.new_stateful(
- "maximize", None, GLib.Variant.new_boolean(False)
- )
- max_action.connect("change-state", self.on_maximize_toggle)
- self.add_action(max_action)
- # Keep it in sync with the actual state
- self.connect(
- "notify::is-maximized",
- lambda obj, pspec: max_action.set_state(
- GLib.Variant.new_boolean(obj.props.is_maximized)
- ),
- )
- lbl_variant = GLib.Variant.new_string("String 1")
- lbl_action = Gio.SimpleAction.new_stateful(
- "change_label", lbl_variant.get_type(), lbl_variant
- )
- lbl_action.connect("change-state", self.on_change_label_state)
- self.add_action(lbl_action)
- self.label = Gtk.Label(label=lbl_variant.get_string(), margin=30)
- self.add(self.label)
- self.label.show()
- def on_change_label_state(self, action, value):
- action.set_state(value)
- self.label.set_text(value.get_string())
- def on_maximize_toggle(self, action, value):
- action.set_state(value)
- if value.get_boolean():
- self.maximize()
- else:
- self.unmaximize()
-class Application(Gtk.Application):
- def __init__(self, *args, **kwargs):
- super().__init__(
- *args,
- application_id="org.example.myapp",
- flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
- **kwargs
- )
- self.window = None
- self.add_main_option(
- "test",
- ord("t"),
- GLib.OptionFlags.NONE,
- GLib.OptionArg.NONE,
- "Command line test",
- None,
- )
- def do_startup(self):
- Gtk.Application.do_startup(self)
- action = Gio.SimpleAction.new("about", None)
- action.connect("activate", self.on_about)
- self.add_action(action)
- action = Gio.SimpleAction.new("quit", None)
- action.connect("activate", self.on_quit)
- self.add_action(action)
- builder = Gtk.Builder.new_from_string(MENU_XML, -1)
- self.set_app_menu(builder.get_object("app-menu"))
- def do_activate(self):
- # We only allow a single window and raise any existing ones
- if not self.window:
- # Windows are associated with the application
- # when the last one is closed the application shuts down
- self.window = AppWindow(application=self, title="Main Window")
- self.window.present()
- def do_command_line(self, command_line):
- options = command_line.get_options_dict()
- # convert GVariantDict -> GVariant -> dict
- options = options.end().unpack()
- if "test" in options:
- # This is printed on the main instance
- print("Test argument recieved: %s" % options["test"])
- self.activate()
- return 0
- def on_about(self, action, param):
- about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True)
- about_dialog.present()
- def on_quit(self, action, param):
- self.quit()
-if __name__ == "__main__":
- app = Application()
- app.run(sys.argv)
diff --git a/gmm-gtk b/gmm-gtk
index 0e10da8..6e9ceae 100755
--- a/gmm-gtk
+++ b/gmm-gtk
@@ -5,10 +5,17 @@
# Purpose: Easily mount iso files and easily manage these mounted files and mount points, basically like acetoneiso
# Reference:
# logout-manager-gtk
+# https://python-gtk-3-tutorial.readthedocs.io/en/latest/dialogs.html
+# https://python-gtk-3-tutorial.readthedocs.io/en/latest/menus.html also shows popup (right click) menu, and toolbars not used here
+# https://www.programcreek.com/python/example/1399/gtk.FileChooserDialog gtk2 example which took a little work to update to gtk3; minor things like FileChooserAction.CANCEL or similar.
+# https://gist.github.com/mi4code/d53b81ed6353275e9bbeedfb7b5fd990
+# disused references:
+# https://python-gtk-3-tutorial.readthedocs.io/en/latest/application.html#application
+# WORKHERE: need to define sudo rules
import gi, os, sys, subprocess
gi.require_version("Gtk", "3.0")
-from gi.repository import Gtk
+from gi.repository import Gtk, GLib, Gio, Gdk
from gi.repository.GdkPixbuf import Pixbuf
sys.path.append("/usr/share/gmm")
@@ -17,6 +24,21 @@ import gmm_lib as gmm
from gmm_lib import debuglev, ferror, appname
# GRAPHICAL APP
+MENU_INFO = """
+<ui>
+ <menubar name='MenuBar'>
+ <menu action='FileMenu'>
+ <menuitem action='FileMount' />
+ <menuitem action='FileSettings' />
+ <separator />
+ <menuitem action='FileQuit' />
+ </menu>
+ <menu action='HelpMenu'>
+ <menuitem action='HelpAbout' />
+ </menu>
+ </menubar>
+</ui>
+"""
# ripped directly from logout-manager-gtk
# graphical classes and functions
@@ -57,46 +79,164 @@ def get_scaled_icon(icon_name, size=24, fallback_icon_name = "", icon_theme = "d
filename=iconfilename,
width=size, height=size, preserve_aspect_ratio=True))
-class MainWindow(Gtk.Window):
- def __init__(self, gmmapp):
+class MainWindow(Gtk.ApplicationWindow):
+ def __init__(self, gmmapp, *args, **kwargs):
+ super().__init__(title="Graphical Mount Manager",*args, **kwargs)
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.liststore = Gtk.ListStore(str,str)
+ self.set_icon_name("dvd_unmount")
+ # menu
+ action_group = Gtk.ActionGroup(name="actions")
+ self.add_file_menu_actions(action_group)
+ self.add_help_menu_actions(action_group)
+ uimanager = self.create_ui_manager()
+ uimanager.insert_action_group(action_group)
+ self.menubar = uimanager.get_widget("/MenuBar")
+ # main layout
self.grid = Gtk.Grid()
self.add(self.grid)
- self.liststore = Gtk.ListStore(str,str)
+ self.grid.add(self.menubar)
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.append_column(Gtk.TreeViewColumn("Mount point",renderer,text=1))
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.grid.attach(self.ml, 0,1, 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
+ # xfe needs the Gdk.DragAction.MOVE flag
+ self.ml.drag_dest_set(
+ Gtk.DestDefaults.ALL,
+ [
+ Gtk.TargetEntry.new("text/uri-list", 0, 0),
+ ],
+ Gdk.DragAction.COPY | Gdk.DragAction.MOVE | Gdk.DragAction.ASK | Gdk.DragAction.LINK
+ )
+ self.ml.connect("drag-data-received", self.on_drop)
+ # WORKHERE: add settings dialog
# initial load
self.refresh_form()
+ def on_drop(self, context, x, y, data, info, time, o1 = None):
+ #print("Dropped file(s):", uris)
+ # mimetype, will probably just be uri-list
+ mimetype = None
+ try:
+ mimetype = info.get_data_type()
+ except:
+ pass
+ # raw string with \r\n, not useful because get_uris exists
+ #urilist = info.get_data()
+ uris = []
+ try:
+ uris = info.get_uris()
+ except:
+ pass
+ if debuglev(9):
+ ferror(f"DEBUG: on_drop got mimetype {mimetype}")
+ ferror(f"DEBUG: on_drop got uris {uris}")
+ for filename in [i.replace("file://","") for i in uris]:
+ self.mount_iso_to_default(filename)
+
+ def add_file_menu_actions(self, action_group):
+ action_filemenu = Gtk.Action(name="FileMenu", label="_File")
+ action_group.add_action(action_filemenu)
+ #action_fileopenmenu = Gtk.Action(name="FileOpen", stock_id=Gtk.STOCK_OPEN)
+ #action_group.add_action(action_fileopenmenu)
+
+ action_mount = Gtk.Action(
+ name="FileMount",
+ label="_Mount iso...",
+ tooltip="Mount existing disc image",
+ stock_id=Gtk.STOCK_OPEN
+ )
+ action_mount.connect("activate", self.on_menu_file_mount)
+ action_group.add_action_with_accel(action_mount, None)
+
+ action_settings = Gtk.Action(
+ name="FileSettings",
+ label="_Settings...",
+ tooltip="Open settings dialog",
+ )
+ action_settings.connect("activate", self.on_menu_file_settings)
+ action_group.add_action_with_accel(action_settings, None)
+
+ action_filequit = Gtk.Action(name="FileQuit", stock_id=Gtk.STOCK_QUIT)
+ action_filequit.connect("activate", self.on_menu_file_quit)
+ action_group.add_action(action_filequit)
+
+ def add_help_menu_actions(self, action_group):
+ action_helpmenu = Gtk.Action(name="HelpMenu", label="_Help")
+ action_group.add_action(action_helpmenu)
+ action_helpaboutmenu = Gtk.Action(name="HelpAbout", stock_id=Gtk.STOCK_ABOUT)
+ action_helpaboutmenu.connect("activate", self.on_menu_help_about)
+ action_group.add_action(action_helpaboutmenu)
+
+ def create_ui_manager(self):
+ uimanager = Gtk.UIManager()
+ uimanager.add_ui_from_string(MENU_INFO)
+ accelgroup = uimanager.get_accel_group()
+ self.add_accel_group(accelgroup)
+ return uimanager
+
+ def on_menu_file_mount(self, widget):
+ #print("STUB Do something with file mount....")
+ chooser = Gtk.FileChooserDialog(
+ title="Mount iso file",
+ action=Gtk.FileChooserAction.OPEN,
+ buttons=(
+ Gtk.STOCK_CANCEL,
+ Gtk.ResponseType.CANCEL,
+ Gtk.STOCK_OPEN,
+ Gtk.ResponseType.OK,
+ )
+ )
+ chooser.set_default_response(Gtk.ResponseType.OK)
+ filter = Gtk.FileFilter()
+ filter.set_name("Disc images")
+ filter.add_pattern("*.iso")
+ chooser.add_filter(filter)
+ filter = Gtk.FileFilter()
+ filter.set_name("All files")
+ filter.add_pattern("*")
+ chooser.add_filter(filter)
+ if chooser.run() == Gtk.ResponseType.OK:
+ filename = chooser.get_filename()
+ chooser.destroy()
+ #self.open_file(filename)
+ self.mount_iso_to_default(filename)
+ else:
+ chooser.destroy()
+ print(f"Got file {filename}")
+
+ def mount_iso_to_default(self, filename = None, o2 = None):
+ if debuglev(1):
+ #ferror(f"Mounting file {filename}")
+ ferror(f"Will try to mount {filename}")
+ if filename:
+ self.gmmapp.mount_iso_to_default(filename)
+ self.refresh_form()
+
+ def on_menu_file_settings(self, widget):
+ print("STUB Do something with file settings....")
+
+ def on_menu_file_quit(self, widget):
+ Gtk.main_quit()
+
+ def on_menu_help_about(self, widget):
+ about_dialog = Gtk.AboutDialog(transient_for=self, modal=True)
+ about_dialog.present()
+
def refresh_form(self):
self.gmmapp.mounts = self.gmmapp.list_mounts()
self.liststore.clear()
for i in self.gmmapp.mounts:
+ print(f"DEBUG: looping over {i}")
self.liststore.append([i["source"],i["mountpoint"]])
def func_double_click_entry(self, tree_view, path, column):
diff --git a/gmm-tk b/gmm-tk
index 2af5966..f1bcaa4 100755
--- a/gmm-tk
+++ b/gmm-tk
@@ -189,7 +189,7 @@ class TkApp(tk.Frame):
)
if filename:
ferror(f"Got {filename}")
- self.gmmapp.mount_iso_to_default(filename,self.gmmapp.config)
+ self.gmmapp.mount_iso_to_default(filename)
self.refresh_form()
if "__main__" == __name__:
bgstack15