def run_keybinder(callback): # for wayland DBusGMainLoop(set_as_default=True) dbus_menu = DbusMenu() if not is_wayland(): Keybinder.bind('<Alt>space', callback, dbus_menu) # GLib.timeout_add_seconds(1, callback) try: GLib.MainLoop().run() except KeyboardInterrupt: GLib.MainLoop().quit()
def create(cls, callback=None): if not is_wayland(): return cls(callback) else: return DummyKeybinder()
class CommandWindow(Gtk.ApplicationWindow): wayland = is_wayland() def __init__(self, *args, **kwargs): kwargs['type'] = Gtk.WindowType.POPUP super(Gtk.ApplicationWindow, self).__init__(*args, **kwargs) self.app = kwargs['application'] self.seat = Gdk.Display.get_default().get_default_seat() self.set_size_request(-1, -1) self.set_keep_above(True) self.set_resizable(False) self.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.set_position(Gtk.WindowPosition.CENTER) self.set_custom_position() self.set_skip_pager_hint(True) self.set_skip_taskbar_hint(True) self.set_destroy_with_parent(True) self.set_decorated(False) self.my_menu_bar = Gtk.MenuBar() self.accel_group = Gtk.AccelGroup() self.main_box = Gtk.VBox() self.main_box.add(self.my_menu_bar) self.add(self.main_box) # self.set_dark_variation() self.set_custom_styles() Gdk.event_handler_set(self.on_gdk_event) self.connect('show', self.on_window_show) self.connect('button-press-event', self.on_button_press_event) def open_menu_shortcut(self, menu): self.make_opaque() self.grab_keyboard(self.get_window()) self.my_menu_bar.select_item(menu) # activate_item(menu) def open_menu_by_name(self, name): name = name.replace('_', '') for menu in self.my_menu_bar.get_children(): if menu.get_label().replace('_', '') == name: self.open_menu_shortcut(menu) break def open_menu_by_character(self, char): for menu in self.my_menu_bar.get_children(): label = menu.get_label() idx = label.find('_') if idx != -1 and label[idx + 1] == char: self.open_menu_shortcut(menu) break def set_tree_menu(self, tree): self.destroy_menus() children = tree.children(tree[tree.root].identifier) for c in children: menu = Menu(tree, c, self.accel_group) button = Gtk.MenuItem() button.set_label(c.tag) button.set_use_underline(True) button.set_submenu(menu) # set_popup(menu) button.show_all() button.set_can_focus(True) self.my_menu_bar.append(button) def destroy_menus(self): self.main_box.remove(self.my_menu_bar) self.my_menu_bar = Gtk.MenuBar() self.main_box.add(self.my_menu_bar) def set_custom_position(self, x=-1, y=0): position = self.get_position() x = x if x != -1 else position.root_x self.move(x, y) def set_dark_variation(self): settings = Gtk.Settings.get_default() settings.set_property('gtk-application-prefer-dark-theme', True) def set_custom_styles(self): styles = """entry.search.flat { border: 0; outline: 0; border-image: none; box-shadow: none; } headerbar { box-shadow: none; background: @insensitive_bg_color; border-radius: 0; border-width: 0 0 1px 0; } scrolledwindow overshoot, scrolledwindow undershoot { background: none; box-shadow: none; } scrollbar { opacity: 0; } menubar { background-color: #1d1d1d; } menubar > menuitem { min-height: 1em; } window decoration { box-shadow: none; border-color: @borders; border-style: solid; border-width: 1px; border-radius: 0; } """ inject_custom_style(self, styles) def grab_keyboard(self, window, status=Gdk.GrabStatus.SUCCESS): if self.wayland: return while self.seat.grab(window, Gdk.SeatCapabilities.KEYBOARD, False, None, None, None) != status: time.sleep(0.1) def ungrab_keyboard(self): if self.wayland: return self.seat.ungrab() def emulate_focus_out_event(self): tstamp = Gdk.CURRENT_TIME self.seat.ungrab() fevent = Gdk.Event(Gdk.EventType.FOCUS_CHANGE) self.emit('focus-out-event', fevent) def clicked_inside(self, event): size = self.get_size() x_range = range(0, size.width) y_range = range(0, size.height) return int(event.x) in x_range and int(event.y) in y_range def on_gdk_event(self, event): Gtk.main_do_event(event) def on_window_show(self, window): window = self.get_window() status = Gdk.GrabStatus.SUCCESS tstamp = Gdk.CURRENT_TIME self.grab_keyboard(window, status) def on_button_press_event(self, widget, event): win_type = event.get_window().get_window_type() tmp_type = Gdk.WindowType.TEMP if win_type == tmp_type and not self.clicked_inside(event): self.emulate_focus_out_event() return True def make_opaque(self): self.set_opacity(1) def make_transparent(self): self.set_opacity(0)
import gi import os from gi.repository import Gio from fildem.utils.service import MyService from fildem.utils.wayland import is_wayland ''' Everything in this file is due to Wayland compatibility due to Bamf. This is the only file that should have import bamf. Its replacement is the gnome extension ''' # if there’s a problem, maybe try this # loginctl show-session $(loginctl | grep $(whoami) | awk '{print $1}') -p Type # 'Wayland' means nothing, what matters is if it is x11 or not wayland = is_wayland() if not wayland: gi.require_version('Bamf', '3') from gi.repository import Bamf class Window(object): def __init__(self, bamf_window=None): super(Window, self).__init__() self.bamf_window = bamf_window self.xid = 0 self.props = {} def get_xid(self): if self.bamf_window != None:
class CommandWindow(Gtk.ApplicationWindow): wayland = is_wayland() def __init__(self, *args, **kwargs): if not self.wayland: kwargs['type'] = Gtk.WindowType.POPUP super(Gtk.ApplicationWindow, self).__init__(*args, **kwargs) self.set_size_request(750, -1) self.set_keep_above(True) self.set_resizable(False) self.set_type_hint(Gdk.WindowTypeHint.UTILITY) self.set_position(Gtk.WindowPosition.CENTER) self.set_custom_position() self.set_skip_pager_hint(True) self.set_skip_taskbar_hint(True) self.set_destroy_with_parent(True) self.empty_label = Gtk.Label(margin=12) self.empty_label.set_label('No menu actions available!') self.empty_box = Gtk.Box(sensitive=False) self.empty_box.set_size_request(750, -1) self.empty_box.add(self.empty_label) self.command_list = CommandList() self.command_list.invalidate_selection() self.search_entry = Gtk.SearchEntry(hexpand=True, margin=2) self.search_entry.connect('search-changed', self.on_search_entry_changed) self.search_entry.set_has_frame(False) self.scrolled_window = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrolled_window.set_size_request(750, 210) self.scrolled_window.add(self.command_list) self.header_bar = Gtk.HeaderBar(spacing=0) self.header_bar.set_custom_title(self.search_entry) self.main_box = Gtk.Box() self.main_box.add(self.empty_box) self.main_box.add(self.scrolled_window) self.set_titlebar(self.header_bar) self.add(self.main_box) self.set_dark_variation() self.set_custom_styles() Gdk.event_handler_set(self.on_gdk_event) self.connect('show', self.on_window_show) self.connect('button-press-event', self.on_button_press_event) def set_menu_actions(self, actions): if actions: self.empty_box.hide() self.scrolled_window.show() self.command_list.set_property('menu-actions', actions) def set_window_actions(self, actions): self.empty_box.hide() self.scrolled_window.show() self.command_list.set_property('window-actions', actions) def set_custom_position(self): position = self.get_position() self.move(position.root_x, 32) def set_dark_variation(self, set_dark=True): settings = Gtk.Settings.get_default() settings.set_property('gtk-application-prefer-dark-theme', set_dark) def set_custom_styles(self): styles = """entry.search.flat { border: 0; outline: 0; border-image: none; box-shadow: none; } headerbar { box-shadow: none; background: @insensitive_bg_color; border-radius: 0; border-width: 0 0 1px 0; } scrolledwindow overshoot, scrolledwindow undershoot { background: none; box-shadow: none; } scrollbar { opacity: 0; } window decoration { box-shadow: none; border-color: @borders; border-style: solid; border-width: 1px; border-radius: 0; } """ inject_custom_style(self, styles) def grab_keyboard(self, window, status, tstamp): while Gdk.keyboard_grab(window, True, tstamp) != status: time.sleep(0.1) def grab_pointer(self, window, status, tstamp): mask = Gdk.EventMask.BUTTON_PRESS_MASK while Gdk.pointer_grab(window, True, mask, window, None, tstamp) != status: time.sleep(0.1) def emulate_focus_out_event(self): if not self.wayland: tstamp = Gdk.CURRENT_TIME Gdk.keyboard_ungrab(tstamp) Gdk.pointer_ungrab(tstamp) fevent = Gdk.Event(Gdk.EventType.FOCUS_CHANGE) self.emit('focus-out-event', fevent) def clicked_inside(self, event): size = self.get_size() x_range = range(0, size.width) y_range = range(0, size.height) return int(event.x) in x_range and int(event.y) in y_range def on_gdk_event(self, event): Gtk.main_do_event(event) def on_window_show(self, window): if not self.wayland: window = self.get_window() status = Gdk.GrabStatus.SUCCESS tstamp = Gdk.CURRENT_TIME self.grab_keyboard(window, status, tstamp) self.grab_pointer(window, status, tstamp) self.search_entry.grab_focus() def on_button_press_event(self, widget, event): win_type = event.get_window().get_window_type() tmp_type = Gdk.WindowType.TEMP if win_type == tmp_type and not self.clicked_inside(event): self.emulate_focus_out_event() return True def on_search_entry_changed(self, *args): search_value = self.search_entry.get_text() self.scrolled_window.unset_placement() self.command_list.set_filter_value(search_value)