Skip to content

Commit

Permalink
#4432 remember the last start dialog selection
Browse files Browse the repository at this point in the history
  • Loading branch information
totaam committed Jan 7, 2025
1 parent c712de5 commit a34459a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 31 deletions.
55 changes: 39 additions & 16 deletions xpra/gtk/dialogs/start_new_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from xpra.gtk.pixbuf import get_icon_pixbuf
from xpra.gtk.signals import register_os_signals
from xpra.util.objects import typedict
from xpra.util.config import parse_user_config_file, update_config_attribute
from xpra.exit_codes import ExitValue
from xpra.os_util import gi_import
from xpra.log import Logger, enable_debug_for
Expand All @@ -20,6 +21,17 @@

log = Logger("exec")

START_NEW_COMMAND_CONFIG = "start_new_command.conf"


def update_config(prop: str, value: str) -> None:
update_config_attribute(prop, value, dirname="tools", filename=START_NEW_COMMAND_CONFIG)


def load_config() -> dict:
return parse_user_config_file("tools", START_NEW_COMMAND_CONFIG)


_instance = None


Expand All @@ -30,7 +42,7 @@ def getStartNewCommand(run_callback, can_share=False, xdg_menu=None):
return _instance


def btn(label, tooltip, callback, icon_name=None):
def btn(label, tooltip, callback, icon_name="") -> Gtk.Button:
b = Gtk.Button(label=label)
b.set_tooltip_text(tooltip)
b.connect("clicked", callback)
Expand All @@ -51,6 +63,8 @@ def __init__(self, run_callback=None, can_share=False, xdg_menu=None):
self.window.set_default_size(400, 150)
self.window.set_title("Start New Command")

self.prefs = load_config()

icon_pixbuf = get_icon_pixbuf("forward.png")
if icon_pixbuf:
self.window.set_icon(icon_pixbuf)
Expand All @@ -70,9 +84,12 @@ def __init__(self, run_callback=None, can_share=False, xdg_menu=None):
hbox.add(label("Category:"))
self.category_combo = Gtk.ComboBoxText()
hbox.add(self.category_combo)
for name in sorted(self.xdg_menu.keys()):
index = 0
for i, name in enumerate(sorted(self.xdg_menu.keys())):
self.category_combo.append_text(name)
self.category_combo.set_active(0)
if name == self.prefs.get("category", ""):
index = i
self.category_combo.set_active(index)
self.category_combo.connect("changed", self.category_changed)

hbox = Gtk.HBox(homogeneous=False, spacing=20)
Expand Down Expand Up @@ -105,30 +122,36 @@ def __init__(self, run_callback=None, can_share=False, xdg_menu=None):
hbox.pack_start(btn("Run", "Run this command", self.run_command, "forward.png"))
hbox.pack_start(btn("Cancel", "", self.close, "quit.png"))

def accel_close(*_args):
def accel_close(*_args) -> None:
self.close()

add_close_accel(self.window, accel_close)
vbox.show_all()
self.window.vbox = vbox
self.window.add(vbox)

def category_changed(self, *args):
def category_changed(self, *args) -> None:
category = self.category_combo.get_active_text()
update_config("category", category)
entries = typedict(typedict(self.xdg_menu.dictget(category, {})).dictget("Entries", {}))
log("category_changed(%s) category=%s, entries=%s", args, category, entries)
self.command_combo.get_model().clear()
for name in entries.keys():
index = -1
for i, name in enumerate(entries.keys()):
self.command_combo.append_text(name)
if entries:
self.command_combo.set_active(0)
if name == self.prefs.get("command", ""):
index = i
if index >= 0:
self.command_combo.set_active(index)

def command_changed(self, *args):
def command_changed(self, *args) -> None:
if not self.entry:
return
category = self.category_combo.get_active_text()
entries = typedict(typedict(self.xdg_menu.dictget(category, {})).dictget("Entries", {}))
command_name = self.command_combo.get_active_text()
if command_name:
update_config("command", command_name)
log("command_changed(%s) category=%s, entries=%s, command_name=%s", args, category, entries, command_name)
command = ""
if entries and command_name:
Expand All @@ -137,22 +160,22 @@ def command_changed(self, *args):
command = typedict(command_props).strget("command")
self.entry.set_text(command)

def show(self):
def show(self) -> None:
log("show()")
self.window.show()
self.window.present()

def hide(self):
def hide(self) -> None:
log("hide()")
if self.window:
self.window.hide()

def close(self, *args):
def close(self, *args) -> bool:
log("close%s", args)
self.hide()
return True

def destroy(self, *args):
def destroy(self, *args) -> None:
log("close%s", args)
if self.window:
self.window.destroy()
Expand All @@ -164,20 +187,20 @@ def run(self) -> ExitValue:
log("run() Gtk.main done")
return 0

def quit(self, *args):
def quit(self, *args) -> None:
log("quit%s", args)
self.close()
Gtk.main_quit()

def run_command(self, *_args):
def run_command(self, *_args) -> None:
self.hide()
command = self.entry.get_text()
log("command=%s", command)
if self.run_callback and command:
self.run_callback(command, self.share is None or self.share.get_active())


def main(): # pragma: no cover
def main() -> int: # pragma: no cover
from xpra.platform.gui import init as gui_init, ready as gui_ready
from xpra.platform import program_context
gui_init()
Expand Down
37 changes: 22 additions & 15 deletions xpra/util/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,38 @@
from datetime import datetime
from typing import Callable

from xpra.gtk.configure.common import log
from xpra.os_util import gi_import
from xpra.scripts.config import make_defaults_struct
from xpra.util.env import osexpand
from xpra.util.parsing import parse_simple_dict
from xpra.util.thread import start_thread
from xpra.log import Logger

log = Logger("util")


CONFIGURE_TOOL_CONFIG = "99_configure_tool.conf"


def get_user_config_file(filename=CONFIGURE_TOOL_CONFIG) -> str:
def get_user_config_file(dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> str:
from xpra.platform.paths import get_user_conf_dirs
return osexpand(os.path.join(get_user_conf_dirs()[0], "conf.d", filename))
return osexpand(os.path.join(get_user_conf_dirs()[0], dirname, filename))


def parse_user_config_file(filename=CONFIGURE_TOOL_CONFIG) -> dict[str, str | list[str] | dict[str, str]]:
filename = get_user_config_file(filename)
def parse_user_config_file(dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> dict[str, str | list[str] | dict[str, str]]:
filename = get_user_config_file(dirname, filename)
if not os.path.exists(filename):
return {}
with open(filename, "r", encoding="utf8") as f:
data = f.read().replace("\r", "\n")
return parse_simple_dict(data, sep="\n")


def save_user_config_file(options: dict, filename=CONFIGURE_TOOL_CONFIG) -> None:
filename = get_user_config_file(filename)
def save_user_config_file(options: dict,
dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> None:
filename = get_user_config_file(dirname, filename)
conf_dir = os.path.dirname(filename)
log(f"save_user_config_file({options}, {dirname!r}, {filename!r}) {conf_dir=!r}")
if not os.path.exists(conf_dir):
os.mkdir(conf_dir, mode=0o755)
with open(filename, "w", encoding="utf8") as f:
Expand All @@ -51,30 +55,33 @@ def save_user_config_file(options: dict, filename=CONFIGURE_TOOL_CONFIG) -> None
f.write(f"{k} = {item}\n")


def update_config_attribute(attribute: str, value: str | int | float, filename=CONFIGURE_TOOL_CONFIG) -> None:
config = parse_user_config_file(filename)
def update_config_attribute(attribute: str, value: str | int | float,
dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> None:
config = parse_user_config_file(dirname, filename)
value_str = str(value)
if isinstance(value, bool):
value_str = "yes" if bool(value) else "no"
config[attribute] = value_str
log(f"update config: {attribute}={value_str}")
save_user_config_file(config, filename)
save_user_config_file(config, dirname, filename)


def update_config_env(attribute: str, value, filename=CONFIGURE_TOOL_CONFIG) -> None:
def update_config_env(attribute: str, value,
dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> None:
# there can be many env attributes
log(f"update config env: {attribute}={value}")
config = parse_user_config_file(filename)
config = parse_user_config_file(dirname, filename)
env = config.get("env")
if not isinstance(env, dict):
log.warn(f"Warning: env option was using invalid type {type(env)}")
config["env"] = env = {}
env[attribute] = str(value)
save_user_config_file(config, filename)
save_user_config_file(config, dirname, filename)


def get_config_env(var_name: str, filename=CONFIGURE_TOOL_CONFIG) -> str:
config = parse_user_config_file(filename)
def get_config_env(var_name: str,
dirname="conf.d", filename=CONFIGURE_TOOL_CONFIG) -> str:
config = parse_user_config_file(dirname, filename)
env = config.get("env", {})
if not isinstance(env, dict):
log.warn(f"Warning: env option was using invalid type {type(env)}")
Expand Down

0 comments on commit a34459a

Please sign in to comment.