Introduce GTK signal types

Related #2273
This commit is contained in:
MattHag 2024-11-10 13:01:05 +01:00 committed by Peter F. Patel-Schneider
parent ab52c4a7c0
commit e9a58fb3e0
10 changed files with 167 additions and 94 deletions

View File

@ -17,6 +17,7 @@
import logging
from enum import Enum
from typing import Callable
import gi
@ -48,6 +49,12 @@ assert Gtk.get_major_version() > 2, "Solaar requires Gtk 3 python bindings"
APP_ID = "io.github.pwr_solaar.solaar"
class GtkSignal(Enum):
ACTIVATE = "activate"
COMMAND_LINE = "command-line"
SHUTDOWN = "shutdown"
def _startup(app, startup_hook, use_tray, show_window):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("startup registered=%s, remote=%s", app.get_is_registered(), app.get_is_remote())
@ -108,9 +115,9 @@ def run_loop(
lambda app, startup_hook: _startup(app, startup_hook, use_tray, show_window),
startup_hook,
)
application.connect("command-line", _command_line)
application.connect("activate", _activate)
application.connect("shutdown", _shutdown, shutdown_hook)
application.connect(GtkSignal.COMMAND_LINE.value, _command_line)
application.connect(GtkSignal.ACTIVATE.value, _activate)
application.connect(GtkSignal.SHUTDOWN.value, _shutdown, shutdown_hook)
application.register()
if application.get_is_remote():

View File

@ -13,8 +13,7 @@
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from enum import Enum
from typing import List
from typing import Tuple
from typing import Union
@ -24,6 +23,10 @@ from gi.repository import Gtk
from solaar import NAME
class GtkSignal(Enum):
RESPONSE = "response"
class AboutView:
def __init__(self) -> None:
self.view: Union[Gtk.AboutDialog, None] = None
@ -34,7 +37,7 @@ class AboutView:
self.view.set_icon_name(NAME.lower())
self.view.set_license_type(Gtk.License.GPL_2_0)
self.view.connect("response", lambda x, y: self.handle_close(x))
self.view.connect(GtkSignal.RESPONSE.value, lambda x, y: self.handle_close(x))
def update_version_info(self, version: str) -> None:
self.view.set_version(version)

View File

@ -14,6 +14,7 @@
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from enum import Enum
from gi.repository import Gdk
from gi.repository import Gtk
@ -24,6 +25,10 @@ from solaar.ui import common
from . import pair_window
class GtkSignal(Enum):
ACTIVATE = "activate"
def make_image_menu_item(label, icon_name, function, *args):
box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6)
label = Gtk.Label(label=label)
@ -33,7 +38,7 @@ def make_image_menu_item(label, icon_name, function, *args):
menu_item = Gtk.MenuItem()
menu_item.add(box)
menu_item.show_all()
menu_item.connect("activate", function, *args)
menu_item.connect(GtkSignal.ACTIVATE.value, function, *args)
menu_item.label = label
menu_item.icon = icon
return menu_item
@ -45,7 +50,7 @@ def make(name, label, function, stock_id=None, *args):
if stock_id is not None:
action.set_stock_id(stock_id)
if function:
action.connect("activate", function, *args)
action.connect(GtkSignal.ACTIVATE.value, function, *args)
return action
@ -54,7 +59,7 @@ def make_toggle(name, label, function, stock_id=None, *args):
action.set_icon_name(name)
if stock_id is not None:
action.set_stock_id(stock_id)
action.connect("activate", function, *args)
action.connect(GtkSignal.ACTIVATE.value, function, *args)
return action

View File

@ -18,6 +18,7 @@
import logging
import traceback
from enum import Enum
from threading import Timer
import gi
@ -38,6 +39,16 @@ from gi.repository import Gtk # NOQA: E402
logger = logging.getLogger(__name__)
class GtkSignal(Enum):
ACTIVATE = "activate"
CHANGED = "changed"
CLICKED = "clicked"
MATCH_SELECTED = "match_selected"
NOTIFY_ACTIVE = "notify::active"
TOGGLED = "toggled"
VALUE_CHANGED = "value-changed"
def _read_async(setting, force_read, sbox, device_is_online, sensitive):
def _do_read(s, force, sb, online, sensitive):
try:
@ -116,7 +127,7 @@ class ToggleControl(Gtk.Switch, Control):
def __init__(self, sbox, delegate=None):
super().__init__(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER)
self.init(sbox, delegate)
self.connect("notify::active", self.changed)
self.connect(GtkSignal.NOTIFY_ACTIVE.value, self.changed)
def set_value(self, value):
if value is not None:
@ -135,7 +146,7 @@ class SliderControl(Gtk.Scale, Control):
self.set_round_digits(0)
self.set_digits(0)
self.set_increments(1, 5)
self.connect("value-changed", self.changed)
self.connect(GtkSignal.VALUE_CHANGED.value, self.changed)
def get_value(self):
return int(super().get_value())
@ -167,7 +178,7 @@ class ChoiceControlLittle(Gtk.ComboBoxText, Control):
self.choices = choices if choices is not None else sbox.setting.choices
for entry in self.choices:
self.append(str(int(entry)), str(entry))
self.connect("changed", self.changed)
self.connect(GtkSignal.CHANGED.value, self.changed)
def get_value(self):
return int(self.get_active_id()) if self.get_active_id() is not None else None
@ -205,9 +216,9 @@ class ChoiceControlBig(Gtk.Entry, Control):
completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][1]))
completion.set_text_column(1)
self.set_completion(completion)
self.connect("changed", self.changed)
self.connect("activate", self.activate)
completion.connect("match_selected", self.select)
self.connect(GtkSignal.CHANGED.value, self.changed)
self.connect(GtkSignal.ACTIVATE.value, self.activate)
completion.connect(GtkSignal.MATCH_SELECTED.value, self.select)
def get_value(self):
choice = self.get_choice()
@ -253,7 +264,7 @@ class MapChoiceControl(Gtk.HBox, Control):
self.valueBox = _create_choice_control(sbox.setting, choices=self.value_choices, delegate=self)
self.pack_start(self.keyBox, False, False, 0)
self.pack_end(self.valueBox, False, False, 0)
self.keyBox.connect("changed", self.map_value_notify_key)
self.keyBox.connect(GtkSignal.CHANGED.value, self.map_value_notify_key)
def get_value(self):
key_choice = int(self.keyBox.get_active_id())
@ -301,7 +312,7 @@ class MultipleControl(Gtk.ListBox, Control):
self._showing = True
self.setup(sbox.setting) # set up the data and boxes for the sub-controls
btn = Gtk.Button(label=button_label)
btn.connect("clicked", self.toggle_display)
btn.connect(GtkSignal.CLICKED.value, self.toggle_display)
self._button = btn
hbox = Gtk.HBox(homogeneous=False, spacing=6)
hbox.pack_end(change, False, False, 0)
@ -349,7 +360,7 @@ class MultipleToggleControl(MultipleControl):
h.set_tooltip_text(lbl_tooltip or " ")
control = Gtk.Switch()
control._setting_key = int(k)
control.connect("notify::active", self.toggle_notify)
control.connect(GtkSignal.NOTIFY_ACTIVE.value, self.toggle_notify)
h.pack_start(lbl, False, False, 0)
h.pack_end(control, False, False, 0)
lbl.set_margin_start(30)
@ -426,7 +437,7 @@ class MultipleRangeControl(MultipleControl):
h.pack_end(control, False, False, 0)
else:
raise NotImplementedError
control.connect("value-changed", self.changed, item, sub_item)
control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, item, sub_item)
item_lb.add(h)
h._setting_sub_item = sub_item
h._label, h._control = sub_item_lbl, control
@ -487,7 +498,7 @@ class PackedRangeControl(MultipleRangeControl):
control = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, validator.min_value, validator.max_value, 1)
control.set_round_digits(0)
control.set_digits(0)
control.connect("value-changed", self.changed, validator.keys[item])
control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, validator.keys[item])
h.pack_start(lbl, False, False, 0)
h.pack_end(control, True, True, 0)
h._setting_item = validator.keys[item]
@ -548,7 +559,7 @@ class HeteroKeyControl(Gtk.HBox, Control):
for entry in item["choices"]:
item_box.append(str(int(entry)), str(entry))
item_box.set_active(0)
item_box.connect("changed", self.changed)
item_box.connect(GtkSignal.CHANGED.value, self.changed)
self.pack_start(item_box, False, False, 0)
elif item["kind"] == settings.Kind.RANGE:
item_box = Scale()
@ -556,7 +567,7 @@ class HeteroKeyControl(Gtk.HBox, Control):
item_box.set_round_digits(0)
item_box.set_digits(0)
item_box.set_increments(1, 5)
item_box.connect("value-changed", self.changed)
item_box.connect(GtkSignal.VALUE_CHANGED.value, self.changed)
self.pack_start(item_box, True, True, 0)
item_box.set_visible(False)
self._items[str(item["name"])] = (item_lblbox, item_box)
@ -664,7 +675,7 @@ def _create_sbox(s, _device):
change.set_relief(Gtk.ReliefStyle.NONE)
change.add(change_icon)
change.set_sensitive(True)
change.connect("clicked", _change_click, sbox)
change.connect(GtkSignal.CLICKED.value, _change_click, sbox)
if s.kind == settings.Kind.TOGGLE:
control = ToggleControl(sbox)

View File

@ -56,6 +56,18 @@ _diversion_dialog = None
_rule_component_clipboard = None
class GtkSignal(Enum):
ACTIVATE = "activate"
BUTTON_RELEASE_EVENT = "button-release-event"
CHANGED = "changed"
CLICKED = "clicked"
DELETE_EVENT = "delete-event"
KEY_PRESS_EVENT = "key-press-event"
NOTIFY_ACTIVE = "notify::active"
TOGGLED = "toggled"
VALUE_CHANGED = "value_changed"
def create_all_settings(all_settings: list[Setting]) -> dict[str, list[Setting]]:
settings = {}
for s in sorted(all_settings, key=lambda setting: setting.label):
@ -333,7 +345,7 @@ class ActionMenu:
def _menu_flatten(self, m, it):
menu_flatten = Gtk.MenuItem(_("Flatten"))
menu_flatten.connect("activate", self.menu_do_flatten, m, it)
menu_flatten.connect(GtkSignal.ACTIVATE.value, self.menu_do_flatten, m, it)
menu_flatten.show()
return menu_flatten
@ -416,7 +428,7 @@ class ActionMenu:
label, feature, *args = spec
item = Gtk.MenuItem(label)
args = [a.copy() if isinstance(a, list) else a for a in args]
item.connect("activate", self._menu_do_insert_new, m, it, feature, *args, below)
item.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, feature, *args, below)
return item
else:
return None
@ -427,7 +439,7 @@ class ActionMenu:
def _menu_create_rule(self, m, it, below=False) -> Gtk.MenuItem:
menu_create_rule = Gtk.MenuItem(_("Insert new rule"))
menu_create_rule.connect("activate", self._menu_do_insert_new, m, it, diversion.Rule, [], below)
menu_create_rule.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, diversion.Rule, [], below)
menu_create_rule.show()
return menu_create_rule
@ -447,7 +459,7 @@ class ActionMenu:
def _menu_delete(self, m, it) -> Gtk.MenuItem:
menu_delete = Gtk.MenuItem(_("Delete"))
menu_delete.connect("activate", self.menu_do_delete, m, it)
menu_delete.connect(GtkSignal.ACTIVATE.value, self.menu_do_delete, m, it)
menu_delete.show()
return menu_delete
@ -469,7 +481,7 @@ class ActionMenu:
def _menu_negate(self, m, it) -> Gtk.MenuItem:
menu_negate = Gtk.MenuItem(_("Negate"))
menu_negate.connect("activate", self.menu_do_negate, m, it)
menu_negate.connect(GtkSignal.ACTIVATE.value, self.menu_do_negate, m, it)
menu_negate.show()
return menu_negate
@ -497,9 +509,9 @@ class ActionMenu:
menu_sub_rule = Gtk.MenuItem(_("Sub-rule"))
menu_and = Gtk.MenuItem(_("And"))
menu_or = Gtk.MenuItem(_("Or"))
menu_sub_rule.connect("activate", self.menu_do_wrap, m, it, diversion.Rule)
menu_and.connect("activate", self.menu_do_wrap, m, it, diversion.And)
menu_or.connect("activate", self.menu_do_wrap, m, it, diversion.Or)
menu_sub_rule.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Rule)
menu_and.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.And)
menu_or.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Or)
submenu_wrap.append(menu_sub_rule)
submenu_wrap.append(menu_and)
submenu_wrap.append(menu_or)
@ -523,7 +535,7 @@ class ActionMenu:
def _menu_cut(self, m, it):
menu_cut = Gtk.MenuItem(_("Cut"))
menu_cut.connect("activate", self.menu_do_cut, m, it)
menu_cut.connect(GtkSignal.ACTIVATE.value, self.menu_do_cut, m, it)
menu_cut.show()
return menu_cut
@ -539,13 +551,13 @@ class ActionMenu:
def _menu_paste(self, m, it, below=False):
menu_paste = Gtk.MenuItem(_("Paste"))
menu_paste.connect("activate", self.menu_do_paste, m, it, below)
menu_paste.connect(GtkSignal.ACTIVATE.value, self.menu_do_paste, m, it, below)
menu_paste.show()
return menu_paste
def _menu_copy(self, m, it):
menu_copy = Gtk.MenuItem(_("Copy"))
menu_copy.connect("activate", self.menu_do_copy, m, it)
menu_copy.connect(GtkSignal.ACTIVATE.value, self.menu_do_copy, m, it)
menu_copy.show()
return menu_copy
@ -554,7 +566,7 @@ class DiversionDialog:
def __init__(self, action_menu):
window = Gtk.Window()
window.set_title(_("Solaar Rule Editor"))
window.connect("delete-event", self._closing)
window.connect(GtkSignal.DELETE_EVENT.value, self._closing)
vbox = Gtk.VBox()
self.top_panel, self.view = self._create_top_panel()
@ -597,7 +609,7 @@ class DiversionDialog:
window.show_all()
window.connect("delete-event", lambda w, e: w.hide_on_delete() or True)
window.connect(GtkSignal.DELETE_EVENT.value, lambda w, e: w.hide_on_delete() or True)
style = window.get_style_context()
style.add_class("solaar")
@ -645,9 +657,9 @@ class DiversionDialog:
view.set_enable_tree_lines(True)
view.set_reorderable(False)
view.connect("key-press-event", self._event_key_pressed)
view.connect("button-release-event", self._event_button_released)
view.get_selection().connect("changed", self._selection_changed)
view.connect(GtkSignal.KEY_PRESS_EVENT.value, self._event_key_pressed)
view.connect(GtkSignal.BUTTON_RELEASE_EVENT.value, self._event_button_released)
view.get_selection().connect(GtkSignal.CHANGED.value, self._selection_changed)
sw.add(view)
sw.set_size_request(0, 300) # don't ask for so much height
@ -662,8 +674,8 @@ class DiversionDialog:
self.discard_btn.set_always_show_image(True)
self.discard_btn.set_sensitive(False)
self.discard_btn.set_valign(Gtk.Align.CENTER)
self.save_btn.connect("clicked", lambda *_args: self._save_yaml_file())
self.discard_btn.connect("clicked", lambda *_args: self._reload_yaml_file())
self.save_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._save_yaml_file())
self.discard_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._reload_yaml_file())
button_box.pack_start(self.save_btn, False, False, 0)
button_box.pack_start(self.discard_btn, False, False, 0)
button_box.set_halign(Gtk.Align.CENTER)
@ -869,7 +881,7 @@ class SmartComboBox(Gtk.ComboBox):
if name != self.get_child().get_text():
self.get_child().set_text(name)
self.connect("changed", lambda *a: replace_with(self.get_value(invalid_as_str=False)))
self.connect(GtkSignal.CHANGED.value, lambda *a: replace_with(self.get_value(invalid_as_str=False)))
self.set_id_column(0)
if self.get_has_entry():
@ -1158,7 +1170,7 @@ class LaterUI(RuleComponentUI):
self.field.set_halign(Gtk.Align.CENTER)
self.field.set_valign(Gtk.Align.CENTER)
self.field.set_hexpand(True)
self.field.connect("value-changed", self._on_update)
self.field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update)
self.widgets[self.field] = (0, 1, 1, 1)
def show(self, component, editable):
@ -1226,15 +1238,15 @@ class SetValueControl(Gtk.HBox):
],
case_insensitive=True,
)
self.toggle_widget.connect("changed", self._changed)
self.toggle_widget.connect(GtkSignal.CHANGED.value, self._changed)
self.range_widget = Gtk.SpinButton.new_with_range(0, 0xFFFF, 1)
self.range_widget.connect("value-changed", self._changed)
self.range_widget.connect(GtkSignal.VALUE_CHANGED.value, self._changed)
self.choice_widget = SmartComboBox(
[], completion=True, has_entry=True, case_insensitive=True, replace_with_default_name=True
)
self.choice_widget.connect("changed", self._changed)
self.choice_widget.connect(GtkSignal.CHANGED.value, self._changed)
self.sub_key_widget = SmartComboBox([])
self.sub_key_widget.connect("changed", self._changed)
self.sub_key_widget.connect(GtkSignal.CHANGED.value, self._changed)
self.unsupported_label = Gtk.Label(label=_("Unsupported setting"))
self.pack_start(self.sub_key_widget, False, False, 0)
self.sub_key_widget.set_hexpand(False)
@ -1385,7 +1397,7 @@ class _DeviceUI:
self.device_field.set_value("")
self.device_field.set_valign(Gtk.Align.CENTER)
self.device_field.set_size_request(400, 0)
self.device_field.connect("changed", self._on_update)
self.device_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.device_field] = (1, 1, 1, 1)
def update_devices(self):
@ -1436,7 +1448,7 @@ class HostUI(ConditionUI):
self.widgets[self.label] = (0, 0, 1, 1)
self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)
self.field.set_size_request(600, 0)
self.field.connect("changed", self._on_update)
self.field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.field] = (0, 1, 1, 1)
def show(self, component, editable):
@ -1483,8 +1495,8 @@ class _SettingWithValueUI:
self.device_field.set_valign(Gtk.Align.CENTER)
self.device_field.set_size_request(400, 0)
self.device_field.set_margin_top(m)
self.device_field.connect("changed", self._changed_device)
self.device_field.connect("changed", self._on_update)
self.device_field.connect(GtkSignal.CHANGED.value, self._changed_device)
self.device_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.device_field] = (1, 1, 1, 1)
lbl = Gtk.Label(
@ -1497,8 +1509,8 @@ class _SettingWithValueUI:
self.widgets[lbl] = (0, 2, 1, 1)
self.setting_field = SmartComboBox([(s[0].name, s[0].label) for s in ALL_SETTINGS.values()])
self.setting_field.set_valign(Gtk.Align.CENTER)
self.setting_field.connect("changed", self._changed_setting)
self.setting_field.connect("changed", self._on_update)
self.setting_field.connect(GtkSignal.CHANGED.value, self._changed_setting)
self.setting_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.setting_field] = (1, 2, 1, 1)
self.value_lbl = Gtk.Label(
@ -1521,8 +1533,8 @@ class _SettingWithValueUI:
self.key_field.set_margin_top(m)
self.key_field.hide()
self.key_field.set_valign(Gtk.Align.CENTER)
self.key_field.connect("changed", self._changed_key)
self.key_field.connect("changed", self._on_update)
self.key_field.connect(GtkSignal.CHANGED.value, self._changed_key)
self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.key_field] = (3, 1, 1, 1)
@classmethod

View File

@ -17,6 +17,8 @@
import logging
from enum import Enum
from gi.repository import GLib
from gi.repository import Gtk
from logitech_receiver import hidpp10_constants
@ -32,6 +34,11 @@ _PAIRING_TIMEOUT = 30 # seconds
_STATUS_CHECK = 500 # milliseconds
class GtkSignal(Enum):
CANCEL = "cancel"
CLOSE = "close"
def create(receiver):
receiver.reset_pairing() # clear out any information on previous pairing
title = _("%(receiver_name)s: pair new device") % {"receiver_name": receiver.name}
@ -207,8 +214,8 @@ def _create_assistant(receiver, ok, finish, title, text):
assistant.set_page_complete(page_intro, True)
else:
page_intro = _create_failure_page(assistant, receiver.pairing.error)
assistant.connect("cancel", finish, receiver)
assistant.connect("close", finish, receiver)
assistant.connect(GtkSignal.CANCEL.value, finish, receiver)
assistant.connect(GtkSignal.CLOSE.value, finish, receiver)
return assistant

View File

@ -13,7 +13,7 @@
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from enum import Enum
from shlex import quote as shlex_quote
from gi.repository import Gtk
@ -29,6 +29,12 @@ from solaar.ui.rule_base import CompletionEntry
from solaar.ui.rule_base import RuleComponentUI
class GtkSignal(Enum):
CHANGED = "changed"
CLICKED = "clicked"
TOGGLED = "toggled"
class ActionUI(RuleComponentUI):
CLASS = diversion.Action
@ -51,21 +57,21 @@ class KeyPressUI(ActionUI):
self.widgets[self.label] = (0, 0, 5, 1)
self.del_btns = []
self.add_btn = Gtk.Button(label=_("Add key"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
self.add_btn.connect("clicked", self._clicked_add)
self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)
self.widgets[self.add_btn] = (1, 1, 1, 1)
self.action_clicked_radio = Gtk.RadioButton.new_with_label_from_widget(None, _("Click"))
self.action_clicked_radio.connect("toggled", self._on_update, CLICK)
self.action_clicked_radio.connect(GtkSignal.TOGGLED.value, self._on_update, CLICK)
self.widgets[self.action_clicked_radio] = (0, 3, 1, 1)
self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_clicked_radio, _("Depress"))
self.action_pressed_radio.connect("toggled", self._on_update, DEPRESS)
self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, DEPRESS)
self.widgets[self.action_pressed_radio] = (1, 3, 1, 1)
self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _("Release"))
self.action_released_radio.connect("toggled", self._on_update, RELEASE)
self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, RELEASE)
self.widgets[self.action_released_radio] = (2, 3, 1, 1)
def _create_field(self):
field_entry = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
field_entry.connect("changed", self._on_update)
field_entry.connect(GtkSignal.CHANGED.value, self._on_update)
self.fields.append(field_entry)
self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1)
return field_entry
@ -74,7 +80,7 @@ class KeyPressUI(ActionUI):
btn = Gtk.Button(label=_("Delete"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)
self.del_btns.append(btn)
self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)
btn.connect("clicked", self._clicked_del, len(self.del_btns) - 1)
btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)
return btn
def _clicked_add(self, _btn):
@ -153,8 +159,8 @@ class MouseScrollUI(ActionUI):
for f in [self.field_x, self.field_y]:
f.set_halign(Gtk.Align.CENTER)
f.set_valign(Gtk.Align.START)
self.field_x.connect("changed", self._on_update)
self.field_y.connect("changed", self._on_update)
self.field_x.connect(GtkSignal.CHANGED.value, self._on_update)
self.field_y.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.label_x] = (0, 1, 1, 1)
self.widgets[self.field_x] = (1, 1, 1, 1)
self.widgets[self.label_y] = (2, 1, 1, 1)
@ -210,9 +216,9 @@ class MouseClickUI(ActionUI):
for f in [self.field_b, self.field_c]:
f.set_halign(Gtk.Align.CENTER)
f.set_valign(Gtk.Align.START)
self.field_b.connect("changed", self._on_update)
self.field_c.connect("changed", self._on_update)
self.field_d.connect("changed", self._on_update)
self.field_b.connect(GtkSignal.CHANGED.value, self._on_update)
self.field_c.connect(GtkSignal.CHANGED.value, self._on_update)
self.field_d.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.label_b] = (0, 1, 1, 1)
self.widgets[self.field_b] = (1, 1, 1, 1)
self.widgets[self.label_c] = (2, 1, 1, 1)
@ -257,13 +263,13 @@ class ExecuteUI(ActionUI):
self.fields = []
self.add_btn = Gtk.Button(label=_("Add argument"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
self.del_btns = []
self.add_btn.connect("clicked", self._clicked_add)
self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)
self.widgets[self.add_btn] = (1, 1, 1, 1)
def _create_field(self):
field_entry = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
field_entry.set_size_request(150, 0)
field_entry.connect("changed", self._on_update)
field_entry.connect(GtkSignal.CHANGED.value, self._on_update)
self.fields.append(field_entry)
self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1)
return field_entry
@ -273,7 +279,7 @@ class ExecuteUI(ActionUI):
btn.set_size_request(150, 0)
self.del_btns.append(btn)
self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)
btn.connect("clicked", self._clicked_del, len(self.del_btns) - 1)
btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)
return btn
def _clicked_add(self, *_args):

View File

@ -14,6 +14,7 @@
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from dataclasses import dataclass
from enum import Enum
from gi.repository import Gtk
from logitech_receiver import diversion
@ -26,6 +27,14 @@ from solaar.ui.rule_base import CompletionEntry
from solaar.ui.rule_base import RuleComponentUI
class GtkSignal(Enum):
CHANGED = "changed"
CLICKED = "clicked"
NOTIFY_ACTIVE = "notify::active"
TOGGLED = "toggled"
VALUE_CHANGED = "value-changed"
class ConditionUI(RuleComponentUI):
CLASS = diversion.Condition
@ -44,7 +53,7 @@ class ProcessUI(ConditionUI):
self.widgets[self.label] = (0, 0, 1, 1)
self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)
self.field.set_size_request(600, 0)
self.field.connect("changed", self._on_update)
self.field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.field] = (0, 1, 1, 1)
def show(self, component, editable=True):
@ -74,7 +83,7 @@ class MouseProcessUI(ConditionUI):
self.widgets[self.label] = (0, 0, 1, 1)
self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)
self.field.set_size_request(600, 0)
self.field.connect("changed", self._on_update)
self.field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.field] = (0, 1, 1, 1)
def show(self, component, editable=True):
@ -119,7 +128,7 @@ class FeatureUI(ConditionUI):
self.field.append(feature, feature)
self.field.set_valign(Gtk.Align.CENTER)
self.field.set_size_request(600, 0)
self.field.connect("changed", self._on_update)
self.field.connect(GtkSignal.CHANGED.value, self._on_update)
all_features = [str(f) for f in SupportedFeature]
CompletionEntry.add_completion_to_entry(self.field.get_child(), all_features)
self.widgets[self.field] = (0, 1, 1, 1)
@ -163,7 +172,7 @@ class ReportUI(ConditionUI):
self.field.set_halign(Gtk.Align.CENTER)
self.field.set_valign(Gtk.Align.CENTER)
self.field.set_hexpand(True)
self.field.connect("changed", self._on_update)
self.field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.field] = (0, 1, 1, 1)
def show(self, component, editable=True):
@ -200,7 +209,7 @@ class ModifiersUI(ConditionUI):
self.widgets[switch] = (i, 2, 1, 1)
self.labels[m] = label
self.switches[m] = switch
switch.connect("notify::active", self._on_update)
switch.connect(GtkSignal.NOTIFY_ACTIVE.value, self._on_update)
def show(self, component, editable=True):
super().show(component, editable)
@ -236,13 +245,13 @@ class KeyUI(ConditionUI):
self.widgets[self.label] = (0, 0, 5, 1)
self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)
self.key_field.set_size_request(600, 0)
self.key_field.connect("changed", self._on_update)
self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.key_field] = (0, 1, 2, 1)
self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(None, _("Key down"))
self.action_pressed_radio.connect("toggled", self._on_update, Key.DOWN)
self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.DOWN)
self.widgets[self.action_pressed_radio] = (2, 1, 1, 1)
self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _("Key up"))
self.action_released_radio.connect("toggled", self._on_update, Key.UP)
self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.UP)
self.widgets[self.action_released_radio] = (3, 1, 1, 1)
def show(self, component, editable=True):
@ -288,7 +297,7 @@ class KeyIsDownUI(ConditionUI):
self.widgets[self.label] = (0, 0, 5, 1)
self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)
self.key_field.set_size_request(600, 0)
self.key_field.connect("changed", self._on_update)
self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.key_field] = (0, 1, 1, 1)
def show(self, component, editable=True):
@ -335,12 +344,12 @@ class TestUI(ConditionUI):
self.test.set_hexpand(False)
self.test.set_size_request(300, 0)
CompletionEntry.add_completion_to_entry(self.test.get_child(), diversion.TESTS)
self.test.connect("changed", self._on_update)
self.test.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.test] = (1, 1, 1, 1)
self.parameter = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
self.parameter.set_size_request(150, 0)
self.parameter.connect("changed", self._on_update)
self.parameter.connect(GtkSignal.CHANGED.value, self._on_update)
self.widgets[self.parameter] = (3, 1, 1, 1)
def show(self, component, editable=True):
@ -444,14 +453,14 @@ class TestBytesUI(ConditionUI):
field = Gtk.SpinButton.new_with_range(element.min, element.max, 1)
field.set_value(0)
field.set_size_request(150, 0)
field.connect("value-changed", self._on_update)
field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update)
label = Gtk.Label(label=element.label, margin_top=20)
self.fields[element.id] = field
self.field_labels[element.id] = label
self.widgets[label] = (col, 1, 1, 1)
self.widgets[field] = (col, 2, 1, 1)
col += 1 if col != mode_col - 1 else 2
self.mode_field.connect("changed", lambda cb: (self._on_update(), self._only_mode(cb.get_active_id())))
self.mode_field.connect(GtkSignal.CHANGED.value, lambda cb: (self._on_update(), self._only_mode(cb.get_active_id())))
self.mode_field.set_active_id("range")
def show(self, component, editable=True):
@ -529,7 +538,7 @@ class MouseGestureUI(ConditionUI):
self.widgets[self.label] = (0, 0, 5, 1)
self.del_btns = []
self.add_btn = Gtk.Button(label=_("Add movement"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)
self.add_btn.connect("clicked", self._clicked_add)
self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)
self.widgets[self.add_btn] = (1, 1, 1, 1)
def _create_field(self):
@ -537,7 +546,7 @@ class MouseGestureUI(ConditionUI):
for g in self.MOUSE_GESTURE_NAMES:
field.append(g, g)
CompletionEntry.add_completion_to_entry(field.get_child(), self.MOVE_NAMES)
field.connect("changed", self._on_update)
field.connect(GtkSignal.CHANGED.value, self._on_update)
self.fields.append(field)
self.widgets[field] = (len(self.fields) - 1, 1, 1, 1)
return field
@ -546,7 +555,7 @@ class MouseGestureUI(ConditionUI):
btn = Gtk.Button(label=_("Delete"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)
self.del_btns.append(btn)
self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)
btn.connect("clicked", self._clicked_del, len(self.del_btns) - 1)
btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)
return btn
def _clicked_add(self, _btn):

View File

@ -18,6 +18,7 @@
import logging
import os
from enum import Enum
from time import time
import gi
@ -42,6 +43,11 @@ _TRAY_ICON_SIZE = 48
_MENU_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
class GtkSignal(Enum):
ACTIVATE = "activate"
SCROLL_EVENT = "scroll-event"
def _create_menu(quit_handler):
# per-device menu entries will be generated as-needed
menu = Gtk.Menu()
@ -172,7 +178,7 @@ try:
# ind.set_label(NAME.lower(), NAME.lower())
ind.set_menu(menu)
ind.connect("scroll-event", _scroll)
ind.connect(GtkSignal.SCROLL_EVENT.value, _scroll)
return ind
@ -214,8 +220,8 @@ except ImportError:
icon.set_name(NAME.lower())
icon.set_title(NAME)
icon.set_tooltip_text(NAME)
icon.connect("activate", window.toggle)
icon.connect("scroll-event", _scroll)
icon.connect(GtkSignal.ACTIVATE.value, window.toggle)
icon.connect(GtkSignal.SCROLL_EVENT.value, _scroll)
icon.connect(
"popup-menu",
lambda icon, button, time: menu.popup(None, None, icon.position_menu, icon, button, time),

View File

@ -17,6 +17,7 @@
import logging
from enum import Enum
from enum import IntEnum
import gi
@ -75,6 +76,12 @@ assert len(_TREE_SEPATATOR) == len(_COLUMN_TYPES)
assert len(_COLUMN_TYPES) == len(Column)
class GtkSignal(Enum):
CHANGED = "changed"
CLICKED = "clicked"
DELETE_EVENT = "delete-event"
def _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZE, tooltip=None, toggle=False, clicked=None):
b = Gtk.ToggleButton() if toggle else Gtk.Button()
c = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
@ -84,7 +91,7 @@ def _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZE, toolt
c.pack_start(Gtk.Label(label=label), True, True, 0)
b.add(c)
if clicked is not None:
b.connect("clicked", clicked)
b.connect(GtkSignal.CLICKED.value, clicked)
if tooltip:
b.set_tooltip_text(tooltip)
if not label and icon_size < _NORMAL_BUTTON_ICON_SIZE:
@ -296,7 +303,7 @@ def _create_window_layout():
assert _empty is not None
assert _tree.get_selection().get_mode() == Gtk.SelectionMode.SINGLE
_tree.get_selection().connect("changed", _device_selected)
_tree.get_selection().connect(GtkSignal.CHANGED.value, _device_selected)
tree_scroll = Gtk.ScrolledWindow()
tree_scroll.add(_tree)
@ -341,7 +348,7 @@ def _create(delete_action):
window = Gtk.Window()
window.set_title(NAME)
window.set_role("status-window")
window.connect("delete-event", delete_action)
window.connect(GtkSignal.DELETE_EVENT.value, delete_action)
vbox = _create_window_layout()
window.add(vbox)