Browse Source

context-menu-bin: Do not subclass AdwBin to fix keyboard focus

AdwBin overrides the GtkWidget::focus virtual method by only checking
if the children can be focused.
Not allowing the bin itself to be focused with tab navigation.
fractal-7
Kévin Commaille 2 years ago
parent
commit
5799c32120
No known key found for this signature in database
GPG Key ID: 29A48C1F03620416
  1. 56
      src/components/context_menu_bin.rs
  2. 2
      src/components/context_menu_bin.ui
  3. 4
      src/session/view/content/room_history/item_row.rs
  4. 8
      src/session/view/sidebar/row.rs

56
src/components/context_menu_bin.rs

@ -4,7 +4,7 @@ use gtk::{gdk, glib, glib::clone, prelude::*, CompositeTemplate};
use crate::utils::BoundObject;
mod imp {
use std::cell::Cell;
use std::cell::{Cell, RefCell};
use glib::subclass::InitializingObject;
@ -41,6 +41,9 @@ mod imp {
/// The popover displaying the context menu.
#[property(get, set = Self::set_popover, explicit_notify, nullable)]
pub popover: BoundObject<gtk::PopoverMenu>,
/// The child widget.
#[property(get, set = Self::set_child, explicit_notify, nullable)]
pub child: RefCell<Option<gtk::Widget>>,
}
#[glib::object_subclass]
@ -48,12 +51,14 @@ mod imp {
const NAME: &'static str = "ContextMenuBin";
const ABSTRACT: bool = true;
type Type = super::ContextMenuBin;
type ParentType = adw::Bin;
type ParentType = gtk::Widget;
type Class = ContextMenuBinClass;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
klass.set_layout_manager_type::<gtk::BinLayout>();
klass.install_action("context-menu.activate", None, |obj, _, _| {
obj.open_menu_at(0, 0)
});
@ -113,11 +118,14 @@ mod imp {
if let Some(popover) = self.popover.obj() {
popover.unparent();
}
if let Some(child) = self.child.take() {
child.unparent();
}
}
}
impl WidgetImpl for ContextMenuBin {}
impl BinImpl for ContextMenuBin {}
impl ContextMenuBin {
/// Set whether this widget has a context menu.
@ -171,13 +179,35 @@ mod imp {
obj.notify_popover();
}
/// The child widget.
fn child(&self) -> Option<gtk::Widget> {
self.child.borrow().clone()
}
/// Set the child widget.
fn set_child(&self, child: Option<gtk::Widget>) {
if self.child() == child {
return;
}
if let Some(child) = &child {
child.set_parent(&*self.obj());
}
if let Some(old_child) = self.child.replace(child) {
old_child.unparent();
}
self.obj().notify_child();
}
}
}
glib::wrapper! {
/// A Bin widget that can have a context menu.
pub struct ContextMenuBin(ObjectSubclass<imp::ContextMenuBin>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
@extends gtk::Widget, @implements gtk::Accessible;
}
impl ContextMenuBin {
@ -210,6 +240,13 @@ pub trait ContextMenuBinExt: 'static {
/// Set the `PopoverMenu` used in the context menu.
fn set_popover(&self, popover: Option<gtk::PopoverMenu>);
/// Get the child widget.
#[allow(dead_code)]
fn child(&self) -> Option<gtk::Widget>;
/// Set the child widget.
fn set_child(&self, child: Option<&impl IsA<gtk::Widget>>);
/// Called when the menu was requested to open but before the menu is shown.
fn menu_opened(&self);
}
@ -231,6 +268,15 @@ impl<O: IsA<ContextMenuBin>> ContextMenuBinExt for O {
self.upcast_ref().set_popover(popover);
}
fn child(&self) -> Option<gtk::Widget> {
self.upcast_ref().child()
}
fn set_child(&self, child: Option<&impl IsA<gtk::Widget>>) {
self.upcast_ref()
.set_child(child.map(|w| w.clone().upcast()));
}
fn menu_opened(&self) {
imp::context_menu_bin_menu_opened(self.upcast_ref())
}
@ -241,7 +287,7 @@ impl<O: IsA<ContextMenuBin>> ContextMenuBinExt for O {
///
/// Overriding a method from this Trait overrides also its behavior in
/// `ContextMenuBinExt`.
pub trait ContextMenuBinImpl: BinImpl {
pub trait ContextMenuBinImpl: WidgetImpl {
/// Called when the menu was requested to open but before the menu is shown.
///
/// This method should be used to set the popover dynamically.

2
src/components/context_menu_bin.ui

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ContextMenuBin" parent="AdwBin">
<template class="ContextMenuBin" parent="GtkWidget">
<property name="focusable">True</property>
<child>
<object class="GtkGestureClick" id="click_gesture">

4
src/session/view/content/room_history/item_row.rs

@ -90,7 +90,6 @@ mod imp {
}
impl WidgetImpl for ItemRow {}
impl BinImpl for ItemRow {}
impl ContextMenuBinImpl for ItemRow {
fn menu_opened(&self) {
@ -351,14 +350,13 @@ mod imp {
glib::wrapper! {
/// A row presenting an item in the room history.
pub struct ItemRow(ObjectSubclass<imp::ItemRow>)
@extends gtk::Widget, adw::Bin, ContextMenuBin, @implements gtk::Accessible;
@extends gtk::Widget, ContextMenuBin, @implements gtk::Accessible;
}
impl ItemRow {
pub fn new(room_history: &RoomHistory) -> Self {
glib::Object::builder()
.property("room-history", room_history)
.property("focusable", true)
.build()
}

8
src/session/view/sidebar/row.rs

@ -81,7 +81,6 @@ mod imp {
}
impl WidgetImpl for Row {}
impl BinImpl for Row {}
impl ContextMenuBinImpl for Row {
fn menu_opened(&self) {
@ -363,15 +362,12 @@ mod imp {
glib::wrapper! {
/// A row of the sidebar.
pub struct Row(ObjectSubclass<imp::Row>)
@extends gtk::Widget, adw::Bin, ContextMenuBin, @implements gtk::Accessible;
@extends gtk::Widget, ContextMenuBin, @implements gtk::Accessible;
}
impl Row {
pub fn new(sidebar: &Sidebar) -> Self {
glib::Object::builder()
.property("sidebar", sidebar)
.property("focusable", true)
.build()
glib::Object::builder().property("sidebar", sidebar).build()
}
/// Get the `Room` of this item, if this is a room row.

Loading…
Cancel
Save