#!/usr/bin/python3 import os import signal import subprocess import sys import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GLib from nwg_panel.tools import get_config_dir, local_dir, load_json, save_json, load_string, list_outputs, check_key, \ list_configs, create_pixbuf, update_image, is_command, check_commands, cmd2string from nwg_panel.__about__ import __version__ dir_name = os.path.dirname(__file__) sway = os.getenv('SWAYSOCK') is not None config_dir = get_config_dir() configs = {} editor = None selector_window = None outputs = {} SKELETON_PANEL: dict = { "name": "", "output": "", "layer": "bottom", "position": "top", "controls": "off", "menu-start": "off", "width": "auto", "height": 0, "margin-top": 0, "margin-bottom": 0, "padding-horizontal": 0, "padding-vertical": 0, "spacing": 0, "icons": "", "css-name": "", "modules-left": [], "modules-center": [], "modules-right": [], "controls-settings": { "components": ["net", "brightness", "volume", "battery"], "commands": {"net": "", "bluetooth": "", "battery": ""}, "show-values": False, "interval": 1, "icon-size": 16, "hover-opens": True, "leave-closes": True, "root-css-name": "controls-overview", "css-name": "controls-window", "net-interface": "", "custom-items": [{"name": "Panel settings", "icon": "nwg-panel", "cmd": "nwg-panel-config"}], "menu": {"name": "unnamed", "icon": "", "items": []} }, "menu-start-settings": { "cmd-lock": "swaylock -f -c 000000", "cmd-logout": "swaymsg exit", "cmd-restart": "systemctl reboot", "cmd-shutdown": "systemctl -i poweroff", "autohide": True, "file-manager": "thunar", "height": 0, "icon-size-large": 32, "icon-size-small": 16, "icon-size-button": 16, "margin-bottom": 0, "margin-left": 0, "margin-right": 0, "margin-top": 0, "padding": 2, "terminal": "foot", "width": 0 }, "sway-taskbar": { "workspace-menu": ["1", "2", "3", "4", "5", "6", "7", "8"], "name-max-len": 20, "image-size": 16, "workspaces-spacing": 0, "task-padding": 0, "show-app-icon": True, "show-app-name": True, "show-layout": True, "workspace-buttons": True, "all-workspaces": True, "mark-autotiling": True, "mark-xwayland": True, "all-outputs": False }, "sway-workspaces": { "numbers": ["1", "2", "3", "4", "5", "6", "7", "8"], "show-icon": True, "image-size": 16, "show-name": True, "name-length": 40, "mark-autotiling": True, "mark-content": True, "show-layout": True }, "clock": { "format": "%a, %d. %b %H:%M:%S", "tooltip-text": "", "tooltip-date-format": False, "on-left-click": "", "on-middle-click": "", "on-right-click": "", "on-scroll-up": "", "on-scroll-down": "", "root-css-name": "root-clock", "css-name": "clock", "interval": 1 }, "playerctl": { "buttons-position": "left", "icon-size": 16, "chars": 30, "button-css-name": "", "label-css-name": "", "interval": 1 }, "scratchpad": { "css-name": "", "icon-size": 16 }, "dwl-tags": { "tag-names": "1 2 3 4 5 6 7 8 9", "title-limit": 55 } } def signal_handler(sig, frame): desc = {2: "SIGINT", 15: "SIGTERM"} if sig == 2 or sig == 15: print("Terminated with {}".format(desc[sig])) Gtk.main_quit() else: print("{} signal received".format(sig)) def handle_keyboard(window, event): if event.type == Gdk.EventType.KEY_RELEASE and event.keyval == Gdk.KEY_Escape: window.close() class PanelSelector(Gtk.Window): def __init__(self): super(PanelSelector, self).__init__() self.to_delete = [] self.connect("key-release-event", handle_keyboard) self.connect('destroy', Gtk.main_quit) self.plugin_menu_start = is_command("nwg-menu") self.outer_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) self.add(self.outer_box) self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_propagate_natural_width(True) self.scrolled_window.set_propagate_natural_height(True) self.scrolled_window.set_property("margin-top", 12) max_height = 0 for key in outputs: h = outputs[key]["height"] if max_height == 0: max_height = h if not h > max_height: max_height = h self.scrolled_window.set_max_content_height(int(max_height * 0.9)) self.outer_box.add(self.scrolled_window) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) self.scrolled_window.add(vbox) self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) vbox.pack_start(self.hbox, True, False, 12) listboxes = self.build_listboxes() self.hbox.pack_start(listboxes, True, True, 12) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) logo = Gtk.Image.new_from_icon_name("nwg-panel", Gtk.IconSize.LARGE_TOOLBAR) logo.set_property("margin-left", 12) hbox.pack_start(logo, False, False, 0) label = Gtk.Label() try: ver = __version__ except: ver = "" label.set_markup('nwg-panel v{} GitHub'.format(ver)) hbox.pack_start(label, False, False, 0) self.outer_box.pack_end(hbox, False, False, 18) inner_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) hbox.pack_start(inner_hbox, True, True, 12) label = Gtk.Label() label.set_text("New file:") label.set_halign(Gtk.Align.START) inner_hbox.pack_start(label, False, False, 6) self.new_file_entry = Gtk.Entry() self.new_file_entry.set_width_chars(20) self.new_file_entry.set_placeholder_text("filename") self.new_file_entry.connect("changed", validate_name) inner_hbox.pack_start(self.new_file_entry, False, False, 0) btn = Gtk.Button.new_with_label("Add/delete files") btn.connect("clicked", self.add_delete_files) inner_hbox.pack_end(btn, False, False, 0) btn = Gtk.Button.new_with_label("Close") btn.connect("clicked", Gtk.main_quit) inner_hbox.pack_end(btn, False, False, 0) self.show_all() self.connect("show", self.refresh) def refresh(self, *args, reload=True): if reload: global configs configs = list_configs(config_dir) for item in self.hbox.get_children(): item.destroy() listboxes = self.build_listboxes() self.hbox.pack_start(listboxes, True, True, 20) self.new_file_entry.set_text("") self.show_all() def build_listboxes(self): vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) for path in configs: hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) label = Gtk.Label() label.set_text(path) label.set_halign(Gtk.Align.START) hbox.pack_start(label, True, True, 6) checkbox = Gtk.CheckButton.new_with_label("delete file") checkbox.connect("toggled", self.mark_to_delete, path) hbox.pack_end(checkbox, False, False, 0) vbox.pack_start(hbox, False, False, 10) panels = configs[path] panel_idx = 0 for panel in panels: for item in ["name", "output", "position"]: check_key(panel, item, "") listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) vbox.add(listbox) row = Gtk.ListBoxRow() ivbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) lbl_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) lbl_box.set_homogeneous(True) hbox.pack_start(lbl_box, True, True, 0) ivbox.pack_start(hbox, False, False, 3) label = Gtk.Label() label.set_text("{} ".format(panel["name"])[:20]) label.set_halign(Gtk.Align.START) lbl_box.pack_start(label, True, True, 6) label = Gtk.Label() label.set_text(panel["output"]) label.set_halign(Gtk.Align.START) lbl_box.pack_start(label, True, True, 6) label = Gtk.Label() label.set_text(panel["position"]) label.set_halign(Gtk.Align.START) lbl_box.pack_start(label, True, True, 6) btn_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) btn = Gtk.Button.new_from_icon_name("gtk-go-up", Gtk.IconSize.MENU) btn.set_always_show_image(True) if panel_idx > 0: btn.set_tooltip_text("Move up") btn.set_sensitive(panel_idx > 0) btn.connect("clicked", self.move_up, panels, panels[panel_idx]) btn_box.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-down", Gtk.IconSize.MENU) btn.set_always_show_image(True) if panel_idx < len(panels) - 1: btn.set_tooltip_text("Move down") btn.set_sensitive(panel_idx < len(panels) - 1) btn.connect("clicked", self.move_down, panels, panels[panel_idx]) btn_box.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-remove", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_tooltip_text("Remove panel") btn.connect("clicked", self.delete, panels, panels[panel_idx]) btn_box.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-edit", Gtk.IconSize.BUTTON) btn.connect("clicked", self.on_edit_button, path, panel_idx) btn.set_tooltip_text("Edit panel") btn_box.pack_start(btn, False, False, 0) hbox.pack_end(btn_box, False, False, 6) row.add(ivbox) listbox.add(row) panel_idx += 1 listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) vbox.add(listbox) row = Gtk.ListBoxRow() ivbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) ivbox.pack_start(hbox, False, False, 3) btn_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) btn = Gtk.Button.new_from_icon_name("gtk-add", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_label("New") btn.connect("clicked", self.append, path) btn_box.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-apply", Gtk.IconSize.BUTTON) btn.set_label("Apply") btn_box.pack_start(btn, False, False, 0) btn.connect("clicked", self.apply, panels, path) hbox.pack_end(btn_box, False, False, 6) row.add(ivbox) listbox.add(row) return vbox def mark_to_delete(self, cb, file): if cb.get_active(): if file not in self.to_delete: self.to_delete.append(file) else: if file in self.to_delete: self.to_delete.remove(file) def add_delete_files(self, btn): for file in self.to_delete: os.remove(file) self.to_delete = [] if self.new_file_entry.get_text(): config = [] save_json(config, os.path.join(config_dir, self.new_file_entry.get_text())) self.refresh() def on_edit_button(self, button, file, panel_idx): global editor editor = EditorWrapper(self, file, panel_idx, self.plugin_menu_start) editor.edit_panel() def move_up(self, btn, panels, panel): old_index = panels.index(panel) panels.insert(old_index - 1, panels.pop(old_index)) self.refresh(reload=False) def move_down(self, btn, panels, panel): old_index = panels.index(panel) panels.insert(old_index + 1, panels.pop(old_index)) self.refresh(reload=False) def delete(self, btn, panels, panel): panels.remove(panel) self.refresh(reload=False) def append(self, btn, file): config = load_json(file) panel = SKELETON_PANEL config.append(panel) idx = config.index(panel) save_json(config, file) global editor editor = EditorWrapper(self, file, idx, self.plugin_menu_start) editor.set_panel() editor.edit_panel() def apply(self, btn, panels, path): save_json(panels, path) self.refresh() def validate_workspaces(gtk_entry): valid_text = "" for char in gtk_entry.get_text(): if char.isdigit() or char == " ": valid_text += char while ' ' in valid_text: valid_text = valid_text.replace(' ', ' ') gtk_entry.set_text(valid_text) def validate_name(gtk_entry): valid_text = "" for char in gtk_entry.get_text(): if char == " ": char = "-" if char.isalnum() or char in ["-", "_"]: valid_text += char.lower() while '--' in valid_text: valid_text = valid_text.replace('--', '-') gtk_entry.set_text(valid_text) def update_icon(gtk_entry, icons): icons_path = "" if icons == "light": icons_path = os.path.join(get_config_dir(), "icons_light") elif icons == "dark": icons_path = os.path.join(get_config_dir(), "icons_dark") name = gtk_entry.get_text() gtk_entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, create_pixbuf(name, 16, icons_path=icons_path)) class EditorWrapper(object): def __init__(self, parent, file, panel_idx, plugin_menu_start): self.file = file self.panel_idx = panel_idx self.config = {} self.panel = {} self.executors_base = {} self.executors_file = os.path.join(local_dir(), "executors.json") self.executors_base = load_json(self.executors_file) if os.path.isfile(self.executors_file) else {} builder = Gtk.Builder() builder.add_from_file(os.path.join(dir_name, "glade/config_main.glade")) self.window = builder.get_object("main-window") #self.window.set_transient_for(parent) self.window.set_keep_above(True) self.window.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.window.connect('destroy', self.show_parent, parent) self.window.connect("key-release-event", handle_keyboard) self.window.connect("show", self.hide_parent, parent) Gtk.Widget.set_size_request(self.window, 820, 1) self.known_modules = ["clock", "playerctl", "sway-taskbar", "sway-workspaces", "scratchpad", "dwl-tags", "tray"] self.scrolled_window = builder.get_object("scrolled-window") eb = builder.get_object("eb-panel") eb.connect("button-press-event", self.edit_panel) eb = builder.get_object("eb-modules-left") eb.connect("button-press-event", self.edit_modules, "left") eb = builder.get_object("eb-modules-center") eb.connect("button-press-event", self.edit_modules, "center") eb = builder.get_object("eb-modules-right") eb.connect("button-press-event", self.edit_modules, "right") eb = builder.get_object("eb-controls") eb.connect("button-press-event", self.controls_menu) eb = builder.get_object("eb-swaync") if is_command("swaync"): eb.connect("button-press-event", self.edit_swaync) else: eb.set_sensitive(False) eb.set_tooltip_text("'swaync' package required") eb = builder.get_object("eb-tray") try: import dasbus eb.connect("button-press-event", self.edit_tray) except ModuleNotFoundError: eb.set_sensitive(False) eb.set_tooltip_text("'python-dasbus' package required") eb = builder.get_object("eb-clock") eb.connect("button-press-event", self.edit_clock) eb = builder.get_object("eb-playerctl") eb.connect("button-press-event", self.edit_playerctl) eb = builder.get_object("eb-sway-taskbar") eb.connect("button-press-event", self.edit_sway_taskbar) eb = builder.get_object("eb-sway-workspaces") eb.connect("button-press-event", self.edit_sway_workspaces) eb = builder.get_object("eb-scratchpad") eb.connect("button-press-event", self.edit_scratchpad) eb = builder.get_object("eb-dwl-tags") eb.connect("button-press-event", self.edit_dwl_tags) eb = builder.get_object("eb-executors") eb.connect("button-press-event", self.select_executor) eb = builder.get_object("eb-buttons") eb.connect("button-press-event", self.select_button) eb = builder.get_object("eb-menu-start") if plugin_menu_start: eb.connect("button-press-event", self.edit_menu_start) else: eb.set_sensitive(False) eb.set_tooltip_text("'nwg-menu' package required") btn = builder.get_object("btn-close") btn.connect("clicked", self.quit) btn = builder.get_object("btn-apply") btn.connect("clicked", self.apply_changes) btn = builder.get_object("btn-apply-restart") btn.connect("clicked", self.restart_panel) self.eb_name = None self.cb_output = None self.cb_position = None self.cb_controls = None self.cb_layer = None self.sb_width = None self.ckb_width_auto = None self.sb_height = None self.sb_margin_top = None self.sb_margin_bottom = None self.sb_padding_horizontal = None self.sb_padding_vertical = None self.sb_spacing = None self.cb_icons = None self.eb_css_name = None self.edited = None self.set_panel() self.edit_panel() self.window.show_all() def quit(self, btn): selector_window.show_all() self.window.close() def load_panel(self): if self.panel_idx is not None: self.config = load_json(self.file) self.panel = self.config[self.panel_idx] else: self.config = [] self.panel = SKELETON_PANEL self.config.append(self.panel) self.panel_idx = self.config.index(self.panel) save_json(self.config, self.file) self.check_defaults() def set_panel(self): if self.file: self.load_panel() else: self.panel = SKELETON_PANEL self.check_defaults() def check_defaults(self): defaults = { "name": "", "output": "", "layer": "bottom", "position": "top", "controls": "off", "menu-start": "off", "width": "auto", "height": 0, "margin-top": 0, "margin-bottom": 0, "padding-horizontal": 0, "padding-vertical": 0, "spacing": 0, "icons": "", "css-name": "" } for key in defaults: check_key(self.panel, key, defaults[key]) for key in self.known_modules: check_key(self.panel, key, {}) def edit_panel(self, *args): self.check_defaults() self.edited = "panel" builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_panel.glade")) frame = builder.get_object("frame") self.eb_name = builder.get_object("name") self.eb_name.set_text(self.panel["name"]) self.eb_name.connect("changed", validate_name) self.cb_output = builder.get_object("output") for key in outputs: self.cb_output.append(key, key) self.cb_output.append("All", "All") if self.panel["output"] and (self.panel["output"] in outputs or self.panel["output"] == "All"): self.cb_output.set_active_id(self.panel["output"]) screen_width, screen_height = None, None if self.cb_output.get_active_id() and self.cb_output.get_active_id() in outputs: screen_width = outputs[self.cb_output.get_active_id()]["width"] screen_height = outputs[self.cb_output.get_active_id()]["height"] self.cb_position = builder.get_object("position") self.cb_position.set_active_id(self.panel["position"]) self.cb_controls = builder.get_object("controls") if not self.panel["controls"]: self.cb_controls.set_active_id("off") else: if self.panel["controls"] == "right": self.cb_controls.set_active_id("right") elif self.panel["controls"] == "left": self.cb_controls.set_active_id("left") else: self.cb_controls.set_active_id("off") self.cb_menu = builder.get_object("menu") if not self.panel["menu-start"]: self.cb_menu.set_active_id("off") else: if self.panel["menu-start"] == "right": self.cb_menu.set_active_id("right") elif self.panel["menu-start"] == "left": self.cb_menu.set_active_id("left") else: self.cb_menu.set_active_id("off") self.cb_layer = builder.get_object("layer") self.cb_layer.set_active_id(self.panel["layer"]) self.sb_width = builder.get_object("width") self.sb_width.set_numeric(True) upper = float(screen_width + 1) if screen_width is not None else 8193 adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_width.configure(adj, 1, 0) self.ckb_width_auto = builder.get_object("width-auto") if isinstance(self.panel["width"], int): self.sb_width.set_value(float(self.panel["width"])) else: self.ckb_width_auto.set_active(True) self.sb_width.set_sensitive(False) self.ckb_width_auto.connect("toggled", self.on_auto_toggle, self.sb_width, self.cb_output) self.sb_height = builder.get_object("height") self.sb_height.set_numeric(True) upper = float(screen_height + 1) if screen_height is not None else 4602 adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_height.configure(adj, 1, 0) self.sb_height.set_value(float(self.panel["height"])) self.sb_margin_top = builder.get_object("margin-top") self.sb_margin_top.set_numeric(True) upper = float(screen_height + 1) if screen_height is not None else 4602 if self.sb_height.get_value(): upper = upper - self.sb_height.get_value() adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_margin_top.configure(adj, 1, 0) self.sb_margin_top.set_value(float(self.panel["margin-top"])) self.sb_margin_bottom = builder.get_object("margin-bottom") self.sb_margin_bottom.set_numeric(True) upper = float(screen_height + 1) if screen_height is not None else 4602 if self.sb_height.get_value(): upper = upper - self.sb_height.get_value() adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_margin_bottom.configure(adj, 1, 0) self.sb_margin_bottom.set_value(float(self.panel["margin-bottom"])) self.sb_padding_horizontal = builder.get_object("padding-horizontal") self.sb_padding_horizontal.set_numeric(True) upper = float(screen_width / 3 + 1) if screen_width is not None else 640 adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_padding_horizontal.configure(adj, 1, 0) self.sb_padding_horizontal.set_value(float(self.panel["padding-horizontal"])) self.sb_padding_vertical = builder.get_object("padding-vertical") self.sb_padding_vertical.set_numeric(True) upper = float(screen_height / 3 + 1) if screen_height is not None else 360 adj = Gtk.Adjustment(value=0, lower=0, upper=upper, step_increment=1, page_increment=10, page_size=1) self.sb_padding_vertical.configure(adj, 1, 0) self.sb_padding_vertical.set_value(float(self.panel["padding-vertical"])) self.sb_spacing = builder.get_object("spacing") self.sb_spacing.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=201, step_increment=1, page_increment=10, page_size=1) self.sb_spacing.configure(adj, 1, 0) self.sb_spacing.set_value(float(self.panel["spacing"])) self.cb_icons = builder.get_object("icons") if self.panel["icons"]: self.cb_icons.set_active_id(self.panel["icons"]) else: self.cb_icons.set_active_id("gtk") self.eb_css_name = builder.get_object("css-name") self.eb_css_name.set_text(self.panel["css-name"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def on_auto_toggle(self, checkbutton, sb_width, cb_output): if not checkbutton.get_active(): o_name = cb_output.get_active_id() sb_width.set_sensitive(True) if o_name in outputs: sb_width.set_value(float(outputs[o_name]["width"])) else: sb_width.set_sensitive(False) def update_panel(self): val = self.eb_name.get_text() if val: self.panel["name"] = val val = self.cb_output.get_active_id() if val: self.panel["output"] = val val = self.cb_position.get_active_id() if val: self.panel["position"] = val val = self.cb_controls.get_active_id() if val: if val in ["left", "right"]: self.panel["controls"] = val else: self.panel["controls"] = "off" val = self.cb_menu.get_active_id() if val: if val in ["left", "right"]: self.panel["menu-start"] = val else: self.panel["menu-start"] = "off" val = self.cb_layer.get_active_id() if val: self.panel["layer"] = val val = self.ckb_width_auto.get_active() if val: self.panel["width"] = "auto" else: val = self.sb_width.get_value() if val is not None: self.panel["width"] = int(val) val = self.sb_height.get_value() if val is not None: self.panel["height"] = int(val) val = self.sb_margin_top.get_value() if val is not None: self.panel["margin-top"] = int(val) val = self.sb_margin_bottom.get_value() if val is not None: self.panel["margin-bottom"] = int(val) val = self.sb_padding_horizontal.get_value() if val is not None: self.panel["padding-horizontal"] = int(val) val = self.sb_padding_vertical.get_value() if val is not None: self.panel["padding-vertical"] = int(val) val = self.sb_spacing.get_value() if val is not None: self.panel["spacing"] = int(val) val = self.cb_icons.get_active_id() if val != "gtk": self.panel["icons"] = val else: self.panel["icons"] = "" val = self.eb_css_name.get_text() self.panel["css-name"] = val save_json(self.config, self.file) def hide_parent(self, w, parent): parent.set_sensitive(False) def show_parent(self, w, parent): parent.set_sensitive(True) def apply_changes(self, *args): if self.edited == "panel": self.update_panel() elif self.edited == "sway-taskbar": self.update_sway_taskbar() elif self.edited == "clock": self.update_clock() elif self.edited == "playerctl": self.update_playerctl() elif self.edited == "sway-workspaces": self.update_sway_workspaces() elif self.edited == "scratchpad": self.update_scratchpad() elif self.edited == "executor": self.update_executor() elif self.edited == "swaync": self.update_swaync() elif self.edited == "tray": self.update_tray() elif self.edited == "button": self.update_button() elif self.edited == "modules": save_json(self.config, self.file) elif self.edited == "controls": self.update_controls() elif self.edited == "menu-start": self.update_menu_start() elif self.edited == "dwl-tags": self.update_dwl_tags() elif self.edited == "custom-items": save_json(self.config, self.file) elif self.edited == "user-menu": save_json(self.config, self.file) selector_window.refresh(reload=True) def restart_panel(self, *args): self.apply_changes() cmd = "nwg-panel" try: args_string = load_string(os.path.join(local_dir(), "args")) cmd = "nwg-panel {}".format(args_string) except: pass print("Restarting panels".format(cmd)) subprocess.Popen('exec {}'.format(cmd), shell=True) def edit_sway_taskbar(self, *args): self.load_panel() self.edited = "sway-taskbar" check_key(self.panel, "sway-taskbar", {}) settings = self.panel["sway-taskbar"] defaults = { "workspace-menu": [1, 2, 3, 4, 5, 6, 7, 8], "name-max-len": 20, "image-size": 16, "workspaces-spacing": 0, "task-padding": 0, "show-app-icon": True, "show-app-name": True, "show-layout": True, "workspace-buttons": True, "all-workspaces": True, "mark-autotiling": True, "mark-xwayland": True, "all-outputs": False } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_sway_taskbar.glade")) frame = builder.get_object("frame") self.eb_workspace_menu = builder.get_object("workspace-menu") workspaces = settings["workspace-menu"] text = "" for item in workspaces: text += str(item) + " " self.eb_workspace_menu.set_text(text.strip()) self.eb_workspace_menu.connect("changed", validate_workspaces) self.sb_name_max_len = builder.get_object("name-max-len") self.sb_name_max_len.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=257, step_increment=1, page_increment=10, page_size=1) self.sb_name_max_len.configure(adj, 1, 0) self.sb_name_max_len.set_value(settings["name-max-len"]) self.sb_image_size = builder.get_object("image-size") self.sb_image_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=129, step_increment=1, page_increment=10, page_size=1) self.sb_image_size.configure(adj, 1, 0) self.sb_image_size.set_value(settings["image-size"]) self.sb_workspace_spacing = builder.get_object("workspaces-spacing") self.sb_workspace_spacing.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=1000, step_increment=1, page_increment=10, page_size=1) self.sb_workspace_spacing.configure(adj, 1, 0) self.sb_workspace_spacing.set_value(settings["workspaces-spacing"]) self.sb_task_padding = builder.get_object("task-padding") self.sb_task_padding.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=257, step_increment=1, page_increment=10, page_size=1) self.sb_task_padding.configure(adj, 1, 0) self.sb_task_padding.set_value(settings["task-padding"]) self.ckb_show_app_icon = builder.get_object("show-app-icon") self.ckb_show_app_icon.set_active(settings["show-app-icon"]) self.ckb_show_app_name = builder.get_object("show-app-name") self.ckb_show_app_name.set_active(settings["show-app-name"]) self.ckb_show_layout = builder.get_object("show-layout") self.ckb_show_layout.set_active(settings["show-layout"]) self.workspace_buttons = builder.get_object("workspace-buttons") self.workspace_buttons.set_active(settings["workspace-buttons"]) self.ckb_all_workspaces = builder.get_object("all-workspaces") self.ckb_all_workspaces.set_active(settings["all-workspaces"]) self.ckb_mark_autotiling = builder.get_object("mark-autotiling") self.ckb_mark_autotiling.set_active(settings["mark-autotiling"]) self.ckb_mark_xwayland = builder.get_object("mark-xwayland") self.ckb_mark_xwayland.set_active(settings["mark-xwayland"]) self.ckb_all_outputs = builder.get_object("all-outputs") self.ckb_all_outputs.set_active(settings["all-outputs"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_sway_taskbar(self): settings = self.panel["sway-taskbar"] val = self.eb_workspace_menu.get_text() if val: settings["workspace-menu"] = val.split() val = self.sb_name_max_len.get_value() if val is not None: settings["name-max-len"] = int(val) val = self.sb_image_size.get_value() if val is not None: settings["image-size"] = int(val) val = self.sb_workspace_spacing.get_value() if val is not None: settings["workspaces-spacing"] = int(val) val = self.sb_task_padding.get_value() if val is not None: settings["task-padding"] = int(val) settings["show-app-icon"] = self.ckb_show_app_icon.get_active() settings["show-app-name"] = self.ckb_show_app_name.get_active() settings["show-layout"] = self.ckb_show_layout.get_active() settings["workspace-buttons"] = self.workspace_buttons.get_active() settings["all-workspaces"] = self.ckb_all_workspaces.get_active() settings["mark-autotiling"] = self.ckb_mark_autotiling.get_active() settings["mark-xwayland"] = self.ckb_mark_xwayland.get_active() settings["all-outputs"] = self.ckb_all_outputs.get_active() save_json(self.config, self.file) def edit_clock(self, *args): self.load_panel() self.edited = "clock" check_key(self.panel, "clock", {}) settings = self.panel["clock"] defaults = { "format": "%a, %d. %b %H:%M:%S", "tooltip-text": "", "tooltip-date-format": False, "on-left-click": "", "on-middle-click": "", "on-right-click": "", "on-scroll-up": "", "on-scroll-down": "", "root-css-name": "root-clock", "css-name": "clock", "interval": 1 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_clock.glade")) frame = builder.get_object("frame") self.eb_format = builder.get_object("format") self.eb_format.set_text(settings["format"]) self.eb_tooltip_text = builder.get_object("tooltip-text") self.eb_tooltip_text.set_text(settings["tooltip-text"]) self.eb_tooltip_date = builder.get_object("tooltip-date") self.eb_tooltip_date.set_active(settings["tooltip-date-format"]) self.eb_on_left_click = builder.get_object("on-left-click") self.eb_on_left_click.set_text(settings["on-left-click"]) self.eb_on_middle_click = builder.get_object("on-middle-click") self.eb_on_middle_click.set_text(settings["on-middle-click"]) self.eb_on_right_click = builder.get_object("on-right-click") self.eb_on_right_click.set_text(settings["on-right-click"]) self.eb_on_scroll_up = builder.get_object("on-scroll-up") self.eb_on_scroll_up.set_text(settings["on-scroll-up"]) self.eb_on_scroll_down = builder.get_object("on-scroll-down") self.eb_on_scroll_down.set_text(settings["on-scroll-down"]) self.eb_root_css_name_clock = builder.get_object("root-css-name") self.eb_root_css_name_clock.set_text(settings["root-css-name"]) self.eb_css_name_clock = builder.get_object("css-name") self.eb_css_name_clock.set_text(settings["css-name"]) self.sb_interval = builder.get_object("interval") self.sb_interval.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=3600, step_increment=1, page_increment=10, page_size=1) self.sb_interval.configure(adj, 1, 0) self.sb_interval.set_value(settings["interval"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_clock(self): settings = self.panel["clock"] settings["format"] = self.eb_format.get_text() settings["tooltip-text"] = self.eb_tooltip_text.get_text() settings["tooltip-date-format"] = self.eb_tooltip_date.get_active() settings["on-left-click"] = self.eb_on_left_click.get_text() settings["on-middle-click"] = self.eb_on_middle_click.get_text() settings["on-right-click"] = self.eb_on_right_click.get_text() settings["on-scroll-up"] = self.eb_on_scroll_up.get_text() settings["on-scroll-down"] = self.eb_on_scroll_down.get_text() settings["root-css-name"] = self.eb_root_css_name_clock.get_text() settings["css-name"] = self.eb_css_name_clock.get_text() val = self.sb_interval.get_value() if val is not None: settings["interval"] = int(val) save_json(self.config, self.file) def edit_swaync(self, *args): self.load_panel() self.edited = "swaync" check_key(self.panel, "swaync", {}) settings = self.panel["swaync"] defaults = { "tooltip-text": "Notifications", "on-left-click": "swaync-client -t", "on-middle-click": "", "on-right-click": "", "on-scroll-up": "", "on-scroll-down": "", "root-css-name": "root-executor", "css-name": "executor", "icon-placement": "left", "icon-size": 18, "interval": 1, "always-show-icon": True } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_swaync.glade")) frame = builder.get_object("frame") self.nc_tooltip_text = builder.get_object("tooltip-text") self.nc_tooltip_text.set_text(settings["tooltip-text"]) self.nc_on_middle_click = builder.get_object("on-middle-click") self.nc_on_middle_click.set_text(settings["on-middle-click"]) self.nc_on_right_click = builder.get_object("on-right-click") self.nc_on_right_click.set_text(settings["on-right-click"]) self.nc_on_scroll_up = builder.get_object("on-scroll-up") self.nc_on_scroll_up.set_text(settings["on-scroll-up"]) self.nc_on_scroll_down = builder.get_object("on-scroll-down") self.nc_on_scroll_down.set_text(settings["on-scroll-down"]) self.nc_root_css_name = builder.get_object("root-css-name") self.nc_root_css_name.set_text(settings["root-css-name"]) self.nc_css_name = builder.get_object("css-name") self.nc_css_name.set_text(settings["css-name"]) self.nc_icon_placement = builder.get_object("icon-placement") self.nc_icon_placement.set_active_id(settings["icon-placement"]) self.nc_icon_size = builder.get_object("icon-size") self.nc_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.nc_icon_size.configure(adj, 1, 0) self.nc_icon_size.set_value(settings["icon-size"]) self.nc_interval = builder.get_object("interval") self.nc_interval.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=3600, step_increment=1, page_increment=10, page_size=1) self.nc_interval.configure(adj, 1, 0) self.nc_interval.set_value(settings["interval"]) self.nc_always_show_icon = builder.get_object("always-show-icon") self.nc_always_show_icon.set_active(settings["always-show-icon"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_swaync(self): settings = self.panel["swaync"] settings["tooltip-text"] = self.nc_tooltip_text.get_text() settings["on-middle-click"] = self.nc_on_middle_click.get_text() settings["on-right-click"] = self.nc_on_right_click.get_text() settings["on-scroll-up"] = self.nc_on_scroll_up.get_text() settings["on-scroll-down"] = self.nc_on_scroll_down.get_text() settings["root-css-name"] = self.nc_root_css_name.get_text() settings["css-name"] = self.nc_css_name.get_text() val = self.nc_interval.get_value() if val is not None: settings["interval"] = int(val) if self.nc_icon_placement.get_active_id(): settings["icon-placement"] = self.nc_icon_placement.get_active_id() settings["icon-size"] = int(self.nc_icon_size.get_value()) settings["interval"] = int(self.nc_interval.get_value()) settings["always-show-icon"] = self.nc_always_show_icon.get_active() save_json(self.config, self.file) def edit_tray(self, *args): self.load_panel() self.edited = "tray" check_key(self.panel, "tray", {}) settings = self.panel["tray"] defaults = { "icon-size": 16, "root-css-name": "tray", "inner-css-name": "inner-tray", "smooth-scrolling-threshold": 0 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_tray.glade")) frame = builder.get_object("frame") self.nc_icon_size = builder.get_object("icon-size") self.nc_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.nc_icon_size.configure(adj, 1, 0) self.nc_icon_size.set_value(settings["icon-size"]) self.nc_root_css_name = builder.get_object("root-css-name") self.nc_root_css_name.set_text(settings["root-css-name"]) self.nc_inner_css_name = builder.get_object("inner-css-name") self.nc_inner_css_name.set_text(settings["inner-css-name"]) self.nc_smooth_scrolling_threshold = builder.get_object("smooth-scrolling-threshold") self.nc_smooth_scrolling_threshold.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=3600, step_increment=1, page_increment=10, page_size=1) self.nc_smooth_scrolling_threshold.configure(adj, 1, 0) self.nc_smooth_scrolling_threshold.set_value(settings["smooth-scrolling-threshold"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_tray(self): settings = self.panel["tray"] settings["icon-size"] = int(self.nc_icon_size.get_value()) settings["root-css-name"] = self.nc_root_css_name.get_text() settings["inner-css-name"] = self.nc_inner_css_name.get_text() settings["smooth-scrolling-threshold"] = int(self.nc_smooth_scrolling_threshold.get_value()) save_json(self.config, self.file) def edit_playerctl(self, *args): self.load_panel() self.edited = "playerctl" check_key(self.panel, "playerctl", {}) settings = self.panel["playerctl"] defaults = { "buttons-position": "left", "icon-size": 16, "chars": 30, "button-css-name": "", "label-css-name": "", "interval": 1 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_playerctl.glade")) frame = builder.get_object("frame") self.cb_buttons_position = builder.get_object("buttons-position") self.cb_buttons_position.set_active_id(settings["buttons-position"]) self.sc_icon_size_playerctl = builder.get_object("icon-size") self.sc_icon_size_playerctl.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.sc_icon_size_playerctl.configure(adj, 1, 0) self.sc_icon_size_playerctl.set_value(settings["icon-size"]) self.sc_chars = builder.get_object("chars") self.sc_chars.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=256, step_increment=1, page_increment=10, page_size=1) self.sc_chars.configure(adj, 1, 0) self.sc_chars.set_value(settings["chars"]) self.sc_interval_playerctl = builder.get_object("interval") self.sc_interval_playerctl.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=60, step_increment=1, page_increment=10, page_size=1) self.sc_interval_playerctl.configure(adj, 1, 0) self.sc_interval_playerctl.set_value(settings["interval"]) self.eb_button_css_name = builder.get_object("button-css-name") self.eb_button_css_name.set_text(settings["button-css-name"]) self.eb_label_css_name = builder.get_object("label-css-name") self.eb_label_css_name.set_text(settings["label-css-name"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_playerctl(self): settings = self.panel["playerctl"] val = self.cb_buttons_position.get_active_id() if val: settings["buttons-position"] = val settings["icon-size"] = int(self.sc_icon_size_playerctl.get_value()) settings["chars"] = int(self.sc_chars.get_value()) settings["button-css-name"] = self.eb_button_css_name.get_text() settings["label-css-name"] = self.eb_label_css_name.get_text() settings["interval"] = int(self.sc_interval_playerctl.get_value()) save_json(self.config, self.file) def edit_sway_workspaces(self, *args): self.load_panel() self.edited = "sway-workspaces" check_key(self.panel, "sway-workspaces", {}) settings = self.panel["sway-workspaces"] defaults = { "numbers": [1, 2, 3, 4, 5, 6, 7, 8], "show-icon": True, "image-size": 16, "show-name": True, "name-length": 40, "mark-autotiling": True, "mark-content": True, "show-layout": True } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_sway_workspaces.glade")) frame = builder.get_object("frame") self.eb_workspaces_menu = builder.get_object("numbers") workspaces = settings["numbers"] text = "" for item in workspaces: text += str(item) + " " self.eb_workspaces_menu.set_text(text.strip()) self.eb_workspaces_menu.connect("changed", validate_workspaces) self.ws_show_icon = builder.get_object("show-icon") self.ws_show_icon.set_active(settings["show-icon"]) self.ws_show_name = builder.get_object("show-name") self.ws_show_name.set_active(settings["show-name"]) self.ws_image_size = builder.get_object("image-size") self.ws_image_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=129, step_increment=1, page_increment=10, page_size=1) self.ws_image_size.configure(adj, 1, 0) self.ws_image_size.set_value(settings["image-size"]) self.ws_name_length = builder.get_object("name-length") self.ws_name_length.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=256, step_increment=1, page_increment=10, page_size=1) self.ws_name_length.configure(adj, 1, 0) self.ws_name_length.set_value(settings["name-length"]) self.ws_mark_autotiling = builder.get_object("mark-autotiling") self.ws_mark_autotiling.set_active(settings["mark-autotiling"]) self.ws_mark_content = builder.get_object("mark-content") self.ws_mark_content.set_active(settings["mark-content"]) self.ws_show_layout = builder.get_object("show-layout") self.ws_show_layout.set_active(settings["show-layout"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_sway_workspaces(self): settings = self.panel["sway-workspaces"] val = self.eb_workspaces_menu.get_text() if val: settings["numbers"] = val.split() val = self.ws_show_icon.get_active() if val is not None: settings["show-icon"] = val val = self.ws_show_name.get_active() if val is not None: settings["show-name"] = val settings["image-size"] = int(self.ws_image_size.get_value()) settings["name-length"] = int(self.ws_name_length.get_value()) val = self.ws_mark_autotiling.get_active() if val is not None: settings["mark-autotiling"] = val val = self.ws_mark_content.get_active() if val is not None: settings["mark-content"] = val val = self.ws_show_layout.get_active() if val is not None: settings["show-layout"] = val save_json(self.config, self.file) def edit_menu_start(self, *args): self.load_panel() self.edited = "menu-start" check_key(self.panel, "menu-start-settings", {}) settings = self.panel["menu-start-settings"] defaults = { "cmd-lock": "swaylock -f -c 000000", "cmd-logout": "swaymsg exit", "cmd-restart": "systemctl reboot", "cmd-shutdown": "systemctl -i poweroff", "autohide": True, "file-manager": "thunar", "height": 0, "icon-size-large": 32, "icon-size-small": 16, "icon-size-button": 16, "margin-bottom": 0, "margin-left": 0, "margin-right": 0, "margin-top": 0, "padding": 2, "terminal": "foot", "width": 0 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_menu_start.glade")) frame = builder.get_object("frame") self.ms_window_width = builder.get_object("width") self.ms_window_width.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=1921, step_increment=1, page_increment=10, page_size=1) self.ms_window_width.configure(adj, 1, 0) self.ms_window_width.set_value(settings["width"]) self.ms_window_height = builder.get_object("height") self.ms_window_height.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=2161, step_increment=1, page_increment=10, page_size=1) self.ms_window_height.configure(adj, 1, 0) self.ms_window_height.set_value(settings["height"]) self.ms_icon_size_large = builder.get_object("icon-size-large") self.ms_icon_size_large.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=16, upper=129, step_increment=1, page_increment=10, page_size=1) self.ms_icon_size_large.configure(adj, 1, 0) self.ms_icon_size_large.set_value(settings["icon-size-large"]) self.ms_icon_size_small = builder.get_object("icon-size-small") self.ms_icon_size_small.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=16, upper=129, step_increment=1, page_increment=10, page_size=1) self.ms_icon_size_small.configure(adj, 1, 0) self.ms_icon_size_small.set_value(settings["icon-size-small"]) self.ms_icon_size_button = builder.get_object("icon-size-button") self.ms_icon_size_button.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=129, step_increment=1, page_increment=10, page_size=1) self.ms_icon_size_button.configure(adj, 1, 0) self.ms_icon_size_button.set_value(settings["icon-size-button"]) self.ms_padding = builder.get_object("padding") self.ms_padding.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=100, step_increment=1, page_increment=10, page_size=1) self.ms_padding.configure(adj, 1, 0) self.ms_padding.set_value(settings["padding"]) self.ms_margin_bottom = builder.get_object("margin-bottom") self.ms_margin_bottom.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=400, step_increment=1, page_increment=10, page_size=1) self.ms_margin_bottom.configure(adj, 1, 0) self.ms_margin_bottom.set_value(settings["margin-bottom"]) self.ms_margin_left = builder.get_object("margin-left") self.ms_margin_left.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=400, step_increment=1, page_increment=10, page_size=1) self.ms_margin_left.configure(adj, 1, 0) self.ms_margin_left.set_value(settings["margin-left"]) self.ms_margin_top = builder.get_object("margin-top") self.ms_margin_top.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=400, step_increment=1, page_increment=10, page_size=1) self.ms_margin_top.configure(adj, 1, 0) self.ms_margin_top.set_value(settings["margin-top"]) self.ms_margin_right = builder.get_object("margin-right") self.ms_margin_right.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=400, step_increment=1, page_increment=10, page_size=1) self.ms_margin_right.configure(adj, 1, 0) self.ms_margin_right.set_value(settings["margin-right"]) self.ms_cmd_lock = builder.get_object("cmd-lock") self.ms_cmd_lock.set_text(settings["cmd-lock"]) self.ms_cmd_logout = builder.get_object("cmd-logout") self.ms_cmd_logout.set_text(settings["cmd-logout"]) self.ms_cmd_restart = builder.get_object("cmd-restart") self.ms_cmd_restart.set_text(settings["cmd-restart"]) self.ms_cmd_shutdown = builder.get_object("cmd-shutdown") self.ms_cmd_shutdown.set_text(settings["cmd-shutdown"]) self.ms_file_manager = builder.get_object("file-manager") self.ms_file_manager.set_text(settings["file-manager"]) self.ms_terminal = builder.get_object("terminal") self.ms_terminal.set_text(settings["terminal"]) self.ms_autohide = builder.get_object("autohide") self.ms_autohide.set_active(settings["autohide"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_menu_start(self): settings = self.panel["menu-start-settings"] settings["width"] = int(self.ms_window_width.get_value()) settings["height"] = int(self.ms_window_height.get_value()) settings["icon-size-large"] = int(self.ms_icon_size_large.get_value()) settings["icon-size-small"] = int(self.ms_icon_size_small.get_value()) settings["icon-size-button"] = int(self.ms_icon_size_button.get_value()) settings["padding"] = int(self.ms_padding.get_value()) settings["margin-bottom"] = int(self.ms_margin_bottom.get_value()) settings["margin-left"] = int(self.ms_margin_left.get_value()) settings["margin-top"] = int(self.ms_margin_top.get_value()) settings["margin-right"] = int(self.ms_margin_right.get_value()) val = self.ms_cmd_lock.get_text() if val: settings["cmd-lock"] = val val = self.ms_cmd_logout.get_text() if val: settings["cmd-logout"] = val val = self.ms_cmd_restart.get_text() if val: settings["cmd-restart"] = val val = self.ms_cmd_shutdown.get_text() if val: settings["cmd-shutdown"] = val val = self.ms_file_manager.get_text() if val: settings["file-manager"] = val val = self.ms_terminal.get_text() if val: settings["terminal"] = val val = self.ms_autohide.get_active() if val is not None: settings["autohide"] = val save_json(self.config, self.file) def edit_scratchpad(self, *args): self.load_panel() self.edited = "scratchpad" check_key(self.panel, "scratchpad", {}) settings = self.panel["scratchpad"] defaults = { "css-name": "", "icon-size": 16 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_scratchpad.glade")) frame = builder.get_object("frame") self.scratchpad_css_name = builder.get_object("css-name") self.scratchpad_css_name.set_text(settings["css-name"]) self.scratchpad_icon_size = builder.get_object("icon-size") self.scratchpad_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.scratchpad_icon_size.configure(adj, 1, 0) self.scratchpad_icon_size.set_value(settings["icon-size"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_scratchpad(self, *args): settings = self.panel["scratchpad"] settings["css-name"] = self.scratchpad_css_name.get_text() settings["icon-size"] = int(self.scratchpad_icon_size.get_value()) save_json(self.config, self.file) def edit_dwl_tags(self, *args): self.load_panel() self.edited = "dwl-tags" check_key(self.panel, "dwl-tags", {}) settings = self.panel["dwl-tags"] defaults = { "tag-names": "1 2 3 4 5 6 7 8 9", "title-limit": 55 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_dwl_tags.glade")) frame = builder.get_object("frame") self.dwl_tag_names = builder.get_object("tag-names") self.dwl_tag_names.set_text(settings["tag-names"]) self.dwl_tags_title_limit = builder.get_object("title-limit") self.dwl_tags_title_limit.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=256, step_increment=1, page_increment=10, page_size=1) self.dwl_tags_title_limit.configure(adj, 1, 0) self.dwl_tags_title_limit.set_value(settings["title-limit"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_dwl_tags(self, *args): settings = self.panel["dwl-tags"] settings["tag-names"] = self.dwl_tag_names.get_text() settings["title-limit"] = int(self.dwl_tags_title_limit.get_value()) save_json(self.config, self.file) def select_executor(self, ebox, event): self.edited = "executors" menu = Gtk.Menu() executors = [] # Why the list? We need the number of executors. for key in self.panel: if key.startswith("executor-"): executors.append(key) for name in executors: item = Gtk.MenuItem.new_with_label(name[9:]) item.connect("activate", self.edit_executor, name) menu.append(item) item = Gtk.SeparatorMenuItem() menu.append(item) item = Gtk.MenuItem.new_with_label("Add new") menu.append(item) item.connect("activate", self.edit_executor, "executor-unnamed_{}".format(len(executors) + 1), True) if self.executors_base: item = Gtk.MenuItem.new_with_label("Database") item.connect("activate", self.import_executor) menu.append(item) menu.show_all() menu.popup_at_widget(ebox.get_parent(), Gdk.Gravity.EAST, Gdk.Gravity.WEST, None) def edit_executor(self, item, name, new=False): self.load_panel() self.edited = "executor" settings = self.panel[name] if not new else {} defaults = { "script": "", "tooltip-text": "", "on-left-click": "", "on-middle-click": "", "on-right-click": "", "on-scroll-up": "", "on-scroll-down": "", "root-css-name": "", "css-name": "", "icon-placement": "left", "icon-size": 16, "interval": 1 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_executor.glade")) frame = builder.get_object("frame") self.executor_name = builder.get_object("name") self.executor_name.set_text(name[9:]) self.executor_name.connect("changed", validate_name) self.executor_script = builder.get_object("script") self.executor_script.set_text(settings["script"]) self.executor_tooltip_text = builder.get_object("tooltip-text") self.executor_tooltip_text.set_text(settings["tooltip-text"]) self.executor_on_left_click = builder.get_object("on-left-click") self.executor_on_left_click.set_text(settings["on-left-click"]) self.executor_on_middle_click = builder.get_object("on-middle-click") self.executor_on_middle_click.set_text(settings["on-middle-click"]) self.executor_on_right_click = builder.get_object("on-right-click") self.executor_on_right_click.set_text(settings["on-right-click"]) self.executor_on_scroll_up = builder.get_object("on-scroll-up") self.executor_on_scroll_up.set_text(settings["on-scroll-up"]) self.executor_on_scroll_down = builder.get_object("on-scroll-down") self.executor_on_scroll_down.set_text(settings["on-scroll-down"]) self.executor_root_css_name = builder.get_object("root-css-name") self.executor_root_css_name.set_text(settings["root-css-name"]) self.executor_css_name = builder.get_object("css-name") self.executor_css_name.set_text(settings["css-name"]) self.executor_icon_placement = builder.get_object("icon-placement") self.executor_icon_placement.set_active_id(settings["icon-placement"]) self.executor_icon_size = builder.get_object("icon-size") self.executor_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.executor_icon_size.configure(adj, 1, 0) self.executor_icon_size.set_value(settings["icon-size"]) self.executor_interval = builder.get_object("interval") self.executor_interval.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=1, upper=3600, step_increment=1, page_increment=10, page_size=1) self.executor_interval.configure(adj, 1, 0) self.executor_interval.set_value(settings["interval"]) self.executor_remove = builder.get_object("remove") self.executor_save_to_db_btn = builder.get_object("save-to-database") self.executor_save_to_db_btn.connect("clicked", self.check_and_save_to_db, name, settings) if new: self.executor_remove.set_visible(False) self.executor_save_to_db_btn.set_visible(False) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def check_and_save_to_db(self, btn, name, settings): if name not in self.executors_base: self.save_executor_to_db(btn, name, settings) else: menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Replace '{}' in database".format(name)) item.connect("activate", self.save_executor_to_db, name, settings) menu.append(item) menu.set_reserve_toggle_size(False) menu.show_all() menu.popup_at_widget(btn, Gdk.Gravity.NORTH, Gdk.Gravity.SOUTH, None) def save_executor_to_db(self, widget, name, settings): self.executors_base[name] = settings save_json(self.executors_base, self.executors_file) def update_executor(self): config_key = "executor-{}".format(self.executor_name.get_text()) settings = self.panel[config_key] if config_key in self.panel else {} if not self.executor_remove.get_active(): settings["script"] = self.executor_script.get_text() settings["tooltip-text"] = self.executor_tooltip_text.get_text() settings["on-left-click"] = self.executor_on_left_click.get_text() settings["on-middle-click"] = self.executor_on_middle_click.get_text() settings["on-right-click"] = self.executor_on_right_click.get_text() settings["on-scroll-up"] = self.executor_on_scroll_up.get_text() settings["on-scroll-down"] = self.executor_on_scroll_down.get_text() settings["root-css-name"] = self.executor_root_css_name.get_text() settings["css-name"] = self.executor_css_name.get_text() val = self.executor_icon_placement.get_active_id() if val: settings["icon-placement"] = val settings["icon-size"] = int(self.executor_icon_size.get_value()) settings["interval"] = int(self.executor_interval.get_value()) self.panel[config_key] = settings else: # delete from panel try: self.panel.pop(config_key) print("Removed '{}' from panel".format(config_key)) except: pass # delete from modules left/center/right if exists try: for item in self.panel["modules-left"]: if item == config_key: self.panel["modules-left"].remove(item) print("Removed '{}' from modules-left".format(config_key)) except: pass try: for item in self.panel["modules-center"]: if item == config_key: self.panel["modules-center"].remove(item) print("Removed '{}' from modules-center".format(config_key)) except: pass try: for item in self.panel["modules-right"]: if item == config_key: self.panel["modules-right"].remove(item) print("Removed '{}' from modules-right".format(config_key)) except: pass save_json(self.config, self.file) def import_executor(self, item): builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/executor_import.glade")) frame = builder.get_object("frame") for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) self.ie_combo = builder.get_object("select") for key in self.executors_base: self.ie_combo.append(key, key) self.ie_combo.connect("changed", self.ie_on_combo_changed, self.executors_base) self.ie_script = builder.get_object("script") self.ie_interval = builder.get_object("interval") self.ie_icon_size = builder.get_object("icon-size") self.ie_on_left_click = builder.get_object("on-left-click") self.ie_on_middle_click = builder.get_object("on-middle-click") self.ie_on_right_click = builder.get_object("on-right-click") self.ie_on_scroll_up = builder.get_object("on-scroll-up") self.ie_on_scroll_down = builder.get_object("on-scroll-down") self.ie_tooltip_text = builder.get_object("tooltip-text") self.ie_icon_placement = builder.get_object("icon-placement") self.ie_css_name = builder.get_object("css-name") self.ie_btn_delete = builder.get_object("btn-delete") self.ie_btn_delete.connect("clicked", self.ie_show_btn_delete_menu) self.ie_btn_import = builder.get_object("btn-import") self.ie_btn_import.set_label("Add to '{}'".format(self.panel["name"])) self.ie_btn_import.connect("clicked", self.ie_on_import_btn) def ie_on_import_btn(self, btn): executor = self.ie_combo.get_active_text() if executor not in self.panel: self.ie_add_executor(btn, executor) else: self.ie_show_btn_import_menu(btn) def ie_show_btn_import_menu(self, btn): executor = self.ie_combo.get_active_text() menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Replace '{}' in '{}'".format(executor, self.panel["name"])) item.connect("activate", self.ie_add_executor, executor) menu.append(item) menu.set_reserve_toggle_size(False) menu.show_all() menu.popup_at_widget(btn, Gdk.Gravity.NORTH, Gdk.Gravity.SOUTH, None) def ie_show_btn_delete_menu(self, btn): executor = self.ie_combo.get_active_text() menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Delete '{}' from database".format(executor)) item.connect("activate", self.ie_remove_executor, executor) menu.append(item) menu.set_reserve_toggle_size(False) menu.show_all() menu.popup_at_widget(btn, Gdk.Gravity.NORTH, Gdk.Gravity.SOUTH, None) def ie_add_executor(self, widget, executor): self.panel[executor] = self.executors_base[executor].copy() save_json(self.config, self.file) def ie_remove_executor(self, item, executor): del self.executors_base[executor] self.ie_combo.remove_all() for key in self.executors_base: self.ie_combo.append(key, key) for label in [self.ie_script, self.ie_interval, self.ie_icon_size, self.ie_on_left_click, self.ie_on_middle_click, self.ie_on_right_click, self.ie_on_scroll_up, self.ie_on_scroll_down, self.ie_tooltip_text, self.ie_icon_placement, self.ie_css_name]: label.set_text("") save_json(self.executors_base, self.executors_file) def ie_on_combo_changed(self, combo, executors): executor = combo.get_active_text() if executor: self.ie_script.set_text(executors[executor]["script"]) self.ie_interval.set_text(str(executors[executor]["interval"])) self.ie_icon_size.set_text(str(executors[executor]["icon-size"])) self.ie_on_left_click.set_text(executors[executor]["on-left-click"]) self.ie_on_middle_click.set_text(executors[executor]["on-middle-click"]) self.ie_on_right_click.set_text(executors[executor]["on-right-click"]) self.ie_on_scroll_up.set_text(executors[executor]["on-scroll-up"]) self.ie_on_scroll_down.set_text(executors[executor]["on-scroll-down"]) self.ie_tooltip_text.set_text(executors[executor]["tooltip-text"]) self.ie_icon_placement.set_text(executors[executor]["icon-placement"]) self.ie_css_name.set_text(executors[executor]["css-name"]) self.ie_btn_delete.set_sensitive(True) self.ie_btn_import.set_sensitive(True) def select_button(self, ebox, event): self.edited = "buttons" menu = Gtk.Menu() buttons = [] for key in self.panel: if key.startswith("button-"): buttons.append(key) for name in buttons: item = Gtk.MenuItem.new_with_label(name[7:]) item.connect("activate", self.edit_button, name) menu.append(item) item = Gtk.SeparatorMenuItem() menu.append(item) item = Gtk.MenuItem.new_with_label("Add new") menu.append(item) item.connect("activate", self.edit_button, "button-unnamed_{}".format(len(buttons) + 1), True) menu.show_all() menu.popup_at_widget(ebox.get_parent(), Gdk.Gravity.EAST, Gdk.Gravity.WEST, None) def edit_button(self, item, name, new=False): self.load_panel() self.edited = "button" settings = self.panel[name] if not new else {} defaults = { "command": "", "icon": "", "label": "", "label-position": "right", "css-name": "", "icon-size": 16 } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_button.glade")) frame = builder.get_object("frame") self.button_name = builder.get_object("name") self.button_name.set_text(name[7:]) self.button_name.connect("changed", validate_name) self.button_command = builder.get_object("command") self.button_command.set_text(settings["command"]) self.button_icon = builder.get_object("icon") self.button_icon.set_text(settings["icon"]) update_icon(self.button_icon, self.panel["icons"]) self.button_icon.connect("changed", update_icon, self.panel["icons"]) self.button_picker = builder.get_object("btn-picker") img = Gtk.Image.new_from_icon_name("nwg-icon-picker", Gtk.IconSize.BUTTON) self.button_picker.set_image(img) if is_command("nwg-icon-picker"): self.button_picker.set_tooltip_text("Pick an icon") self.button_picker.connect("clicked", on_pick_btn, self.button_icon) else: self.button_picker.hide() self.button_label = builder.get_object("label") self.button_label.set_text(settings["label"]) self.button_label_position = builder.get_object("label-position") self.button_label_position.set_active_id(settings["label-position"]) self.button_css_name = builder.get_object("css-name") self.button_css_name.set_text(settings["css-name"]) self.button_icon_size = builder.get_object("icon-size") self.button_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.button_icon_size.configure(adj, 1, 0) self.button_icon_size.set_value(settings["icon-size"]) self.button_remove = builder.get_object("remove") self.button_remove.set_sensitive(name in self.panel) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_button(self): config_key = "button-{}".format(self.button_name.get_text()) settings = self.panel[config_key] if config_key in self.panel else {} if not self.button_remove.get_active(): settings["command"] = self.button_command.get_text() settings["icon"] = self.button_icon.get_text() settings["label"] = self.button_label.get_text() settings["label-position"] = self.button_label_position.get_active_id() settings["css-name"] = self.button_css_name.get_text() settings["icon-size"] = int(self.button_icon_size.get_value()) self.panel[config_key] = settings else: # delete from panel try: self.panel.pop(config_key) print("Removed '{}' from panel".format(config_key)) except: pass # delete from modules left/center/right if exists try: for item in self.panel["modules-left"]: if item == config_key: self.panel["modules-left"].remove(item) print("Removed '{}' from modules-left".format(config_key)) except: pass try: for item in self.panel["modules-center"]: if item == config_key: self.panel["modules-center"].remove(item) print("Removed '{}' from modules-center".format(config_key)) except: pass try: for item in self.panel["modules-right"]: if item == config_key: self.panel["modules-right"].remove(item) print("Removed '{}' from modules-right".format(config_key)) except: pass save_json(self.config, self.file) def edit_modules(self, ebox, event, which): self.load_panel() self.edited = "modules" self.modules = None if which == "left": check_key(self.panel, "modules-left", []) self.modules = self.panel["modules-left"] elif which == "center": check_key(self.panel, "modules-center", []) self.modules = self.panel["modules-center"] elif which == "right": check_key(self.panel, "modules-right", []) self.modules = self.panel["modules-right"] builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_modules.glade")) modules_label = builder.get_object("label") modules_label.set_text("{} {}".format(modules_label.get_text(), which.capitalize())) frame = builder.get_object("frame") self.modules_grid = builder.get_object("grid") self.modules_combo = builder.get_object("menu") btn = builder.get_object("btn-append") btn.connect("clicked", self.append) # Built-in stuff first for key in self.panel: if key in self.known_modules: self.modules_combo.append(key, key.capitalize()) for key in self.panel: if key.startswith("executor-") or key.startswith("button-"): self.modules_combo.append(key, key) self.modules_combo.set_active(0) self.modules_combo.show_all() self.refresh_listbox() for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def refresh_listbox(self): if self.modules_grid.get_child_at(1, 2) is not None: self.modules_grid.get_child_at(1, 2).destroy() self.modules_listbox = self.build_listbox() self.modules_grid.attach(self.modules_listbox, 1, 2, 2, 1) def build_listbox(self): listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) for i in range(len(self.modules)): module = self.modules[i] if module in self.panel: row = Gtk.ListBoxRow() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) row.add(vbox) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) label = Gtk.Label() label.set_text(module) label.set_xalign(0) Gtk.Widget.set_size_request(label, 180, 1) hbox.pack_start(label, False, False, 6) btn = Gtk.Button.new_from_icon_name("gtk-go-up", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i > 0) btn.connect("clicked", self.move_up, module) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-down", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i < len(self.modules) - 1) btn.connect("clicked", self.move_down, module) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-remove", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.connect("clicked", self.delete, module) hbox.pack_start(btn, False, False, 0) listbox.add(row) listbox.show_all() return listbox def move_up(self, btn, module): old_index = self.modules.index(module) self.modules.insert(old_index - 1, self.modules.pop(old_index)) self.refresh_listbox() def move_down(self, btn, module): old_index = self.modules.index(module) self.modules.insert(old_index + 1, self.modules.pop(old_index)) self.refresh_listbox() def delete(self, btn, module): self.modules.remove(module) self.refresh_listbox() def append(self, btn): if self.modules_combo.get_active_id(): self.modules.append(self.modules_combo.get_active_id()) self.refresh_listbox() def controls_menu(self, ebox, event): menu = Gtk.Menu() item = Gtk.MenuItem.new_with_label("Settings") item.connect("activate", self.edit_controls) menu.append(item) item = Gtk.MenuItem.new_with_label("Custom items") item.connect("activate", self.edit_custom_items) menu.append(item) item = Gtk.MenuItem.new_with_label("User menu") item.connect("activate", self.edit_user_menu) menu.append(item) menu.show_all() menu.popup_at_widget(ebox.get_parent(), Gdk.Gravity.EAST, Gdk.Gravity.WEST, None) def edit_controls(self, *args): self.load_panel() self.edited = "controls" check_key(self.panel, "controls-settings", {}) settings = self.panel["controls-settings"] defaults = { "components": [ "net", "brightness", "volume", "battery" ], "commands": { }, "show-values": False, "output-switcher": False, "backlight-device": "", "interval": 1, "window-width": 0, "window-margin": 0, "icon-size": 16, "hover-opens": True, "leave-closes": True, "root-css-name": "controls-overview", "css-name": "controls-window", "net-interface": "", "custom-items": [ { "name": "Panel settings", "icon": "nwg-panel", "cmd": "nwg-panel-config" } ], "menu": { "name": "Exit", "icon": "system-shutdown-symbolic", "items": [ { "name": "Lock", "cmd": "swaylock -f -c 000000" }, { "name": "Logout", "cmd": "swaymsg exit" }, { "name": "Reboot", "cmd": "systemctl reboot" }, { "name": "Shutdown", "cmd": "systemctl -i poweroff" } ] } } for key in defaults: check_key(settings, key, defaults[key]) builder = Gtk.Builder.new_from_file(os.path.join(dir_name, "glade/config_controls.glade")) frame = builder.get_object("frame") self.ctrl_comp_brightness = builder.get_object("ctrl-comp-brightness") self.ctrl_comp_brightness.set_active("brightness" in settings["components"]) self.ctrl_backlight_device = builder.get_object("backlight-device") self.ctrl_backlight_device.set_text(settings["backlight-device"]) self.ctrl_comp_volume = builder.get_object("ctrl-comp-volume") self.ctrl_comp_volume.set_active("volume" in settings["components"]) self.ctrl_comp_switcher = builder.get_object("output-switcher") self.ctrl_comp_switcher.set_sensitive(is_command("pamixer")) self.ctrl_comp_switcher.set_active(settings["output-switcher"]) self.ctrl_comp_net = builder.get_object("ctrl-comp-net") self.ctrl_comp_net.set_active("net" in settings["components"]) self.ctrl_comp_bluetooth = builder.get_object("ctrl-comp-bluetooth") if is_command("btmgmt"): self.ctrl_comp_bluetooth.set_active("bluetooth" in settings["components"]) else: self.ctrl_comp_bluetooth.set_active(False) self.ctrl_comp_bluetooth.set_sensitive(False) self.ctrl_comp_battery = builder.get_object("ctrl-comp-battery") self.ctrl_comp_battery.set_active("battery" in settings["components"]) self.ctrl_cdm_net = builder.get_object("ctrl-cmd-net") check_key(settings["commands"], "net", "") self.ctrl_cdm_net.set_text(settings["commands"]["net"]) self.ctrl_net_name = builder.get_object("ctrl-net-name") self.ctrl_net_name.set_text(settings["net-interface"]) self.ctrl_cdm_bluetooth = builder.get_object("ctrl-cmd-bluetooth") check_key(settings["commands"], "bluetooth", "") self.ctrl_cdm_bluetooth.set_text(settings["commands"]["bluetooth"]) self.ctrl_cdm_battery = builder.get_object("ctrl-cmd-battery") check_key(settings["commands"], "battery", "") self.ctrl_cdm_battery.set_text(settings["commands"]["battery"]) self.ctrl_root_css_name = builder.get_object("root-css-name") self.ctrl_root_css_name.set_text(settings["root-css-name"]) self.ctrl_css_name = builder.get_object("css-name") self.ctrl_css_name.set_text(settings["css-name"]) self.ctrl_window_width = builder.get_object("window-width") self.ctrl_window_width.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=1920, step_increment=1, page_increment=10, page_size=1) self.ctrl_window_width.configure(adj, 1, 0) self.ctrl_window_width.set_value(settings["window-width"]) self.ctrl_window_margin = builder.get_object("window-margin") self.ctrl_window_margin.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=0, upper=1920, step_increment=1, page_increment=10, page_size=1) self.ctrl_window_margin.configure(adj, 1, 0) self.ctrl_window_margin.set_value(settings["window-margin"]) self.ctrl_icon_size = builder.get_object("icon-size") self.ctrl_icon_size.set_numeric(True) adj = Gtk.Adjustment(value=0, lower=8, upper=128, step_increment=1, page_increment=10, page_size=1) self.ctrl_icon_size.configure(adj, 1, 0) self.ctrl_icon_size.set_value(settings["icon-size"]) self.ctrl_interval = builder.get_object("interval") self.ctrl_interval.set_numeric(True) adj = Gtk.Adjustment(value=1, lower=1, upper=60, step_increment=1, page_increment=10, page_size=1) self.ctrl_interval.configure(adj, 1, 0) self.ctrl_interval.set_value(settings["interval"]) self.ctrl_show_values = builder.get_object("show-values") self.ctrl_show_values.set_active(settings["show-values"]) self.ctrl_hover_opens = builder.get_object("hover-opens") self.ctrl_hover_opens.set_active(settings["hover-opens"]) self.ctrl_leave_closes = builder.get_object("leave-closes") self.ctrl_leave_closes.set_active(settings["leave-closes"]) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(frame) def update_controls(self): settings = self.panel["controls-settings"] if self.ctrl_comp_brightness.get_active(): if "brightness" not in settings["components"]: settings["components"].append("brightness") else: if "brightness" in settings["components"]: settings["components"].remove("brightness") settings["backlight-device"] = self.ctrl_backlight_device.get_text() if self.ctrl_comp_volume.get_active(): if "volume" not in settings["components"]: settings["components"].append("volume") else: if "volume" in settings["components"]: settings["components"].remove("volume") settings["output-switcher"] = self.ctrl_comp_switcher.get_active() if self.ctrl_comp_net.get_active(): if "net" not in settings["components"]: settings["components"].append("net") else: if "net" in settings["components"]: settings["components"].remove("net") if self.ctrl_comp_bluetooth.get_active(): if "bluetooth" not in settings["components"]: settings["components"].append("bluetooth") else: if "bluetooth" in settings["components"]: settings["components"].remove("bluetooth") if self.ctrl_comp_battery.get_active(): if "battery" not in settings["components"]: settings["components"].append("battery") else: if "battery" in settings["components"]: settings["components"].remove("battery") settings["commands"]["net"] = self.ctrl_cdm_net.get_text() settings["net-interface"] = self.ctrl_net_name.get_text() settings["commands"]["bluetooth"] = self.ctrl_cdm_bluetooth.get_text() settings["commands"]["battery"] = self.ctrl_cdm_battery.get_text() settings["root-css-name"] = self.ctrl_root_css_name.get_text() settings["css-name"] = self.ctrl_css_name.get_text() settings["window-width"] = int(self.ctrl_window_width.get_value()) settings["window-margin"] = int(self.ctrl_window_margin.get_value()) settings["icon-size"] = int(self.ctrl_icon_size.get_value()) settings["interval"] = int(self.ctrl_interval.get_value()) settings["show-values"] = self.ctrl_show_values.get_active() settings["hover-opens"] = self.ctrl_hover_opens.get_active() settings["leave-closes"] = self.ctrl_leave_closes.get_active() save_json(self.config, self.file) def edit_custom_items(self, item): self.load_panel() self.edited = "custom-items" custom_items_grid = ControlsCustomItems(self.panel, self.config, self.file) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(custom_items_grid) def edit_user_menu(self, item): self.load_panel() self.edited = "user-menu" custom_items_grid = ControlsUserMenu(self.panel, self.config, self.file) for item in self.scrolled_window.get_children(): item.destroy() self.scrolled_window.add(custom_items_grid) def on_pick_btn(btn, entry): s = cmd2string("nwg-icon-picker") if s: entry.set_text(s) class ControlsCustomItems(Gtk.Frame): def __init__(self, panel, config, file): check_key(panel, "controls-settings", {}) self.settings = panel["controls-settings"] Gtk.Frame.__init__(self) self.set_label("Controls: Custom items") self.grid = Gtk.Grid() self.grid.set_column_spacing(10) self.grid.set_row_spacing(10) self.set_label_align(0.5, 0.5) self.grid.set_property("margin", 6) self.add(self.grid) check_key(self.settings, "custom-items", []) self.items = self.settings["custom-items"] self.icons = panel["icons"] self.config = config self.file = file self.refresh() def refresh(self): listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) for i in range(len(self.items)): item = self.items[i] row = Gtk.ListBoxRow() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) row.add(vbox) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) entry = Gtk.Entry() entry.set_width_chars(15) entry.set_text(item["name"]) entry.connect("changed", self.update_value_from_entry, i, "name") hbox.pack_start(entry, False, False, 0) entry = Gtk.Entry() entry.set_width_chars(15) entry.set_text(item["icon"]) update_icon(entry, self.icons) entry.connect("changed", self.update_icon, self.icons, i, "icon") hbox.pack_start(entry, False, False, 0) if is_command("nwg-icon-picker"): btn = Gtk.Button.new_from_icon_name("nwg-icon-picker", Gtk.IconSize.MENU) btn.set_tooltip_text("Pick an icon") btn.connect("clicked", on_pick_btn, entry) hbox.pack_start(btn, False, False, 0) entry = Gtk.Entry() entry.set_width_chars(15) entry.set_text(item["cmd"]) entry.connect("changed", self.update_value_from_entry, i, "cmd") hbox.pack_start(entry, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-up", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i > 0) btn.connect("clicked", self.move_up, item) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-down", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i < len(self.items) - 1) btn.connect("clicked", self.move_down, item) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-remove", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.connect("clicked", self.delete, item) hbox.pack_start(btn, False, False, 0) listbox.add(row) # Empty row row = Gtk.ListBoxRow() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) row.add(vbox) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) self.new_name = Gtk.Entry() self.new_name.set_width_chars(15) self.new_name.set_placeholder_text("label") hbox.pack_start(self.new_name, False, False, 0) self.new_icon = Gtk.Entry() self.new_icon.set_width_chars(15) self.new_icon.set_placeholder_text("icon") update_icon(self.new_icon, self.icons) self.new_icon.connect("changed", update_icon, self.icons) hbox.pack_start(self.new_icon, False, False, 0) if is_command("nwg-icon-picker"): btn = Gtk.Button.new_from_icon_name("nwg-icon-picker", Gtk.IconSize.MENU) btn.set_tooltip_text("Pick an icon") btn.connect("clicked", on_pick_btn, self.new_icon) hbox.pack_start(btn, False, False, 0) self.new_command = Gtk.Entry() self.new_command.set_width_chars(15) self.new_command.set_placeholder_text("command") hbox.pack_start(self.new_command, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-add", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_label("Append") btn.connect("clicked", self.append) hbox.pack_start(btn, True, True, 0) listbox.add(row) if self.grid.get_child_at(0, 1): self.grid.get_child_at(0, 1).destroy() self.grid.attach(listbox, 0, 1, 3, 1) self.show_all() def update_value_from_entry(self, gtk_entry, i, key): self.items[i][key] = gtk_entry.get_text() def update_icon(self, gtk_entry, icons, i, key): icons_path = "" if icons == "light": icons_path = os.path.join(get_config_dir(), "icons_light") elif icons == "dark": icons_path = os.path.join(get_config_dir(), "icons_dark") name = gtk_entry.get_text() gtk_entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, create_pixbuf(name, 16, icons_path=icons_path)) self.items[i][key] = gtk_entry.get_text() def move_up(self, btn, item): old_index = self.items.index(item) self.items.insert(old_index - 1, self.items.pop(old_index)) self.refresh() def move_down(self, btn, item): old_index = self.items.index(item) self.items.insert(old_index + 1, self.items.pop(old_index)) self.refresh() def delete(self, btn, item): self.items.remove(item) self.refresh() def append(self, btn): name = self.new_name.get_text() icon = self.new_icon.get_text() cmd = self.new_command.get_text() if name: item = {"name": name, "icon": icon, "cmd": cmd} self.items.append(item) self.refresh() class ControlsUserMenu(Gtk.Frame): def __init__(self, panel, config, file): check_key(panel, "controls-settings", {}) self.settings = panel["controls-settings"] Gtk.Frame.__init__(self) self.set_label("Controls: User menu") self.grid = Gtk.Grid() self.grid.set_column_spacing(10) self.grid.set_row_spacing(10) self.set_label_align(0.5, 0.5) self.grid.set_property("margin", 6) self.add(self.grid) check_key(self.settings, "menu", {}) check_key(self.settings["menu"], "name", "unnamed") check_key(self.settings["menu"], "icon", "") check_key(self.settings["menu"], "items", []) self.name = self.settings["menu"]["name"] self.icon = self.settings["menu"]["icon"] self.items = self.settings["menu"]["items"] self.icons = panel["icons"] self.config = config self.file = file self.refresh() def refresh(self): vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) label = Gtk.Label() label.set_text("Menu name") hbox.pack_start(label, False, False, 6) entry = Gtk.Entry() entry.set_width_chars(15) entry.set_text(self.name) entry.connect("changed", self.update_prop_from_entry, "name") hbox.pack_start(entry, False, False, 0) label = Gtk.Label() label.set_text("Icon") hbox.pack_start(label, False, False, 6) entry = Gtk.Entry() entry.set_width_chars(25) entry.set_text(self.icon) update_icon(entry, self.icons) entry.connect("changed", self.update_icon, self.icons, "icon") hbox.pack_start(entry, False, False, 0) self.grid.attach(vbox, 0, 1, 3, 1) listbox = Gtk.ListBox() listbox.set_selection_mode(Gtk.SelectionMode.NONE) for i in range(len(self.items)): item = self.items[i] row = Gtk.ListBoxRow() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) row.add(vbox) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) entry = Gtk.Entry() entry.set_width_chars(15) entry.set_text(item["name"]) entry.connect("changed", self.update_value_from_entry, i, "name") hbox.pack_start(entry, False, False, 0) entry = Gtk.Entry() entry.set_width_chars(25) entry.set_text(item["cmd"]) entry.connect("changed", self.update_value_from_entry, i, "cmd") hbox.pack_start(entry, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-up", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i > 0) btn.connect("clicked", self.move_up, item) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-go-down", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_sensitive(i < len(self.items) - 1) btn.connect("clicked", self.move_down, item) hbox.pack_start(btn, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-remove", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.connect("clicked", self.delete, item) hbox.pack_start(btn, False, False, 0) listbox.add(row) # Empty row row = Gtk.ListBoxRow() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) row.add(vbox) hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) vbox.pack_start(hbox, False, False, 6) self.new_name = Gtk.Entry() self.new_name.set_width_chars(15) self.new_name.set_placeholder_text("label") hbox.pack_start(self.new_name, False, False, 0) self.new_command = Gtk.Entry() self.new_command.set_width_chars(25) self.new_command.set_placeholder_text("command") hbox.pack_start(self.new_command, False, False, 0) btn = Gtk.Button.new_from_icon_name("gtk-add", Gtk.IconSize.MENU) btn.set_always_show_image(True) btn.set_label("Append") btn.connect("clicked", self.append) hbox.pack_start(btn, True, True, 0) listbox.add(row) if self.grid.get_child_at(0, 2): self.grid.get_child_at(0, 2).destroy() self.grid.attach(listbox, 0, 2, 3, 1) self.show_all() def update_prop_from_entry(self, gtk_entry, key): self.settings["menu"][key] = gtk_entry.get_text() def update_value_from_entry(self, gtk_entry, i, key): self.items[i][key] = gtk_entry.get_text() def update_icon(self, gtk_entry, icons, key): icons_path = "" if icons == "light": icons_path = os.path.join(get_config_dir(), "icons_light") elif icons == "dark": icons_path = os.path.join(get_config_dir(), "icons_dark") name = gtk_entry.get_text() gtk_entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.PRIMARY, create_pixbuf(name, 16, icons_path=icons_path)) self.update_prop_from_entry(gtk_entry, key) def move_up(self, btn, item): old_index = self.items.index(item) self.items.insert(old_index - 1, self.items.pop(old_index)) self.refresh() def move_down(self, btn, item): old_index = self.items.index(item) self.items.insert(old_index + 1, self.items.pop(old_index)) self.refresh() def delete(self, btn, item): self.items.remove(item) self.refresh() def append(self, btn): name = self.new_name.get_text() cmd = self.new_command.get_text() if name and cmd: item = {"name": name, "cmd": cmd} self.items.append(item) self.refresh() def main(): global configs configs = list_configs(config_dir) GLib.set_prgname('nwg-panel-config') check_commands() tree = None if sway: try: from i3ipc import Connection except ModuleNotFoundError: print("'python-i3ipc' package required on sway, terminating") sys.exit(1) i3 = Connection() tree = i3.get_tree() global outputs outputs = list_outputs(sway=sway, tree=tree) global selector_window selector_window = PanelSelector() catchable_sigs = set(signal.Signals) - {signal.SIGKILL, signal.SIGSTOP} for sig in catchable_sigs: signal.signal(sig, signal_handler) Gtk.main() if __name__ == "__main__": sys.exit(main())