|
18 | 18 | import qui.utils
|
19 | 19 |
|
20 | 20 | gi.require_version("Gtk", "3.0") # isort:skip
|
21 |
| -from gi.repository import Gio, Gtk, GLib, GdkPixbuf # isort:skip |
| 21 | +from gi.repository import Gdk, Gio, Gtk, GLib, GdkPixbuf, GObject # isort:skip |
22 | 22 |
|
23 | 23 | import gbulb
|
24 | 24 |
|
@@ -108,7 +108,11 @@ def __init__(self, label, img=None, icon_cache=None, icon_name=None):
|
108 | 108 | box.pack_start(placeholder, False, False, 0)
|
109 | 109 |
|
110 | 110 | # Add a label to the menu item
|
111 |
| - label_widget = Gtk.Label(label=label, xalign=0) |
| 111 | + label_widget = label |
| 112 | + if isinstance(label_widget, Gtk.Label): |
| 113 | + label_widget.set_xalign(0) |
| 114 | + else: |
| 115 | + label_widget = Gtk.Label(label=label, xalign=0) |
112 | 116 | box.pack_start(label_widget, True, True, 0)
|
113 | 117 |
|
114 | 118 | # Add the box to the menu item
|
@@ -289,17 +293,38 @@ async def perform_action(self):
|
289 | 293 | class RunTerminalItem(VMActionMenuItem):
|
290 | 294 | """Run Terminal menu Item. When activated runs a terminal emulator."""
|
291 | 295 |
|
292 |
| - def __init__(self, vm, icon_cache): |
| 296 | + __gsignals__ = { |
| 297 | + 'set-terminal-user-root': (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (bool,)), |
| 298 | + } |
| 299 | + |
| 300 | + def __init__(self, vm, icon_cache, as_root = False): |
| 301 | + label = Gtk.Label(RunTerminalItem.dynamic_label(as_root)) |
293 | 302 | super().__init__(
|
294 | 303 | vm,
|
295 |
| - label=_("Run Terminal"), |
| 304 | + label=label, |
296 | 305 | icon_cache=icon_cache,
|
297 | 306 | icon_name="terminal",
|
298 | 307 | )
|
| 308 | + self.as_root = as_root |
| 309 | + self.label = label |
| 310 | + self.connect('set-terminal-user-root', self.set_as_root) |
| 311 | + |
| 312 | + def dynamic_label(as_root): |
| 313 | + if as_root: |
| 314 | + return _("Run Root Terminal") |
| 315 | + else: |
| 316 | + return _("Run Terminal") |
| 317 | + |
| 318 | + def set_as_root(self, _item, as_root): |
| 319 | + self.as_root = as_root |
| 320 | + self.label.set_text(RunTerminalItem.dynamic_label(as_root)) |
299 | 321 |
|
300 | 322 | async def perform_action(self):
|
| 323 | + service_args = {} |
| 324 | + if self.as_root: |
| 325 | + service_args['user'] = 'root' |
301 | 326 | try:
|
302 |
| - self.vm.run_service("qubes.StartApp+qubes-run-terminal") |
| 327 | + self.vm.run_service("qubes.StartApp+qubes-run-terminal", **service_args) |
303 | 328 | except exc.QubesException as ex:
|
304 | 329 | show_error(
|
305 | 330 | _("Error starting terminal"),
|
@@ -361,7 +386,7 @@ def __init__(self, vm, app, icon_cache):
|
361 | 386 | self.app = app
|
362 | 387 |
|
363 | 388 | self.add(OpenFileManagerItem(self.vm, icon_cache))
|
364 |
| - self.add(RunTerminalItem(self.vm, icon_cache)) |
| 389 | + self.add(RunTerminalItem(self.vm, icon_cache, as_root = app.terminal_as_root)) |
365 | 390 | self.add(PreferencesItem(self.vm, icon_cache))
|
366 | 391 | self.add(PauseItem(self.vm, icon_cache))
|
367 | 392 | self.add(ShutdownItem(self.vm, icon_cache))
|
@@ -562,6 +587,8 @@ def _set_submenu(self, state):
|
562 | 587 | submenu = PausedMenu(self.vm, self.icon_cache)
|
563 | 588 | else:
|
564 | 589 | submenu = DebugMenu(self.vm, self.icon_cache)
|
| 590 | + submenu.connect('key-press-event', self.app.key_event) |
| 591 | + submenu.connect('key-release-event', self.app.key_event) |
565 | 592 | # This is a workaround for a bug in Gtk which occurs when a
|
566 | 593 | # submenu is replaced while it is open.
|
567 | 594 | # see https://gitlab.gnome.org/GNOME/gtk/issues/885
|
@@ -637,6 +664,8 @@ def __init__(self, app_name, qapp, dispatcher, stats_dispatcher):
|
637 | 664 |
|
638 | 665 | self.tray_menu = Gtk.Menu()
|
639 | 666 | self.tray_menu.set_reserve_toggle_size(False)
|
| 667 | + self.tray_menu.connect('key-press-event', self.key_event) |
| 668 | + self.tray_menu.connect('key-release-event', self.key_event) |
640 | 669 |
|
641 | 670 | self.icon_cache = IconCache()
|
642 | 671 |
|
@@ -704,6 +733,7 @@ def register_events(self):
|
704 | 733 | self.stats_dispatcher.add_handler("vm-stats", self.update_stats)
|
705 | 734 |
|
706 | 735 | def show_menu(self, _unused, event):
|
| 736 | + self.terminal_as_root = False |
707 | 737 | self.tray_menu.popup_at_pointer(event) # None means current event
|
708 | 738 |
|
709 | 739 | def emit_notification(self, vm, event, **kwargs):
|
@@ -1055,6 +1085,38 @@ def _disconnect_signals(self, _event):
|
1055 | 1085 |
|
1056 | 1086 | self.stats_dispatcher.remove_handler("vm-stats", self.update_stats)
|
1057 | 1087 |
|
| 1088 | + @property |
| 1089 | + def terminal_as_root(self): |
| 1090 | + try: |
| 1091 | + return self._terminal_as_root |
| 1092 | + except AttributeError: |
| 1093 | + self._terminal_as_root = False |
| 1094 | + return self.terminal_as_root |
| 1095 | + |
| 1096 | + @terminal_as_root.setter |
| 1097 | + def terminal_as_root(self, as_root): |
| 1098 | + if as_root == self.terminal_as_root: |
| 1099 | + return |
| 1100 | + |
| 1101 | + self._terminal_as_root = as_root |
| 1102 | + for item in self.menu_items.values(): |
| 1103 | + if item.vm: |
| 1104 | + submenu = item.get_submenu() |
| 1105 | + if submenu is None: |
| 1106 | + continue |
| 1107 | + def do_emit(child): |
| 1108 | + try: |
| 1109 | + child.emit('set-terminal-user-root', as_root) |
| 1110 | + except Exception: # pylint: disable=broad-except |
| 1111 | + pass |
| 1112 | + submenu.foreach(do_emit) |
| 1113 | + |
| 1114 | + def key_event(self, _unused, event): |
| 1115 | + if event.keyval in [Gdk.KEY_Shift_L, Gdk.KEY_Shift_R]: |
| 1116 | + if event.type == Gdk.EventType.KEY_PRESS: |
| 1117 | + self.terminal_as_root = True |
| 1118 | + elif event.type == Gdk.EventType.KEY_RELEASE: |
| 1119 | + self.terminal_as_root = False |
1058 | 1120 |
|
1059 | 1121 | def main():
|
1060 | 1122 | """main function"""
|
|
0 commit comments