Initial code for sending clicked event
This commit is contained in:
parent
308253d9a9
commit
aca1ea3a15
1 changed files with 89 additions and 54 deletions
|
|
@ -1,6 +1,11 @@
|
||||||
use byte_string::ByteStr;
|
use byte_string::ByteStr;
|
||||||
use cascade::cascade;
|
use cascade::cascade;
|
||||||
use gtk4::{gdk_pixbuf, gio, glib, prelude::*, subclass::prelude::*};
|
use gtk4::{
|
||||||
|
gdk_pixbuf, gio,
|
||||||
|
glib::{self, clone},
|
||||||
|
prelude::*,
|
||||||
|
subclass::prelude::*,
|
||||||
|
};
|
||||||
use std::{borrow::Cow, collections::HashMap, fmt, io};
|
use std::{borrow::Cow, collections::HashMap, fmt, io};
|
||||||
|
|
||||||
use crate::deref_cell::DerefCell;
|
use crate::deref_cell::DerefCell;
|
||||||
|
|
@ -9,6 +14,9 @@ use crate::deref_cell::DerefCell;
|
||||||
pub struct StatusMenuInner {
|
pub struct StatusMenuInner {
|
||||||
menu_button: DerefCell<gtk4::MenuButton>,
|
menu_button: DerefCell<gtk4::MenuButton>,
|
||||||
vbox: DerefCell<gtk4::Box>,
|
vbox: DerefCell<gtk4::Box>,
|
||||||
|
item: DerefCell<StatusNotifierItem>,
|
||||||
|
layout: DerefCell<Layout>,
|
||||||
|
dbus_menu: DerefCell<DBusMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -61,11 +69,15 @@ impl StatusMenu {
|
||||||
obj.inner().menu_button.set_icon_name(&icon_name);
|
obj.inner().menu_button.set_icon_name(&icon_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(menu) = item.menu() {
|
let menu = item.menu().unwrap(); // XXX unwrap?
|
||||||
let layout = menu.get_layout(0, -1, &[]).await?.1;
|
let layout = menu.get_layout(0, -1, &[]).await?.1;
|
||||||
println!("{:#?}", layout);
|
|
||||||
populate_menu(&obj.inner().vbox, &layout);
|
obj.inner().item.set(item);
|
||||||
}
|
obj.inner().layout.set(layout);
|
||||||
|
obj.inner().dbus_menu.set(menu);
|
||||||
|
|
||||||
|
println!("{:#?}", &*obj.inner().layout);
|
||||||
|
obj.populate_menu(&obj.inner().vbox, &obj.inner().layout);
|
||||||
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|
@ -73,61 +85,66 @@ impl StatusMenu {
|
||||||
fn inner(&self) -> &StatusMenuInner {
|
fn inner(&self) -> &StatusMenuInner {
|
||||||
StatusMenuInner::from_instance(self)
|
StatusMenuInner::from_instance(self)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn populate_menu(box_: >k4::Box, layout: &Layout) {
|
fn populate_menu(&self, box_: >k4::Box, layout: &Layout) {
|
||||||
for i in layout.children() {
|
for i in layout.children() {
|
||||||
if i.type_().as_deref() == Some("separator") {
|
if i.type_().as_deref() == Some("separator") {
|
||||||
let separator = gtk4::Separator::new(gtk4::Orientation::Horizontal);
|
let separator = gtk4::Separator::new(gtk4::Orientation::Horizontal);
|
||||||
box_.append(&separator);
|
box_.append(&separator);
|
||||||
} else if let Some(label) = i.label() {
|
} else if let Some(label) = i.label() {
|
||||||
let label_widget = cascade! {
|
let label_widget = cascade! {
|
||||||
gtk4::Label::new(Some(&label));
|
gtk4::Label::new(Some(&label));
|
||||||
..set_halign(gtk4::Align::Start);
|
..set_halign(gtk4::Align::Start);
|
||||||
..set_hexpand(true);
|
..set_hexpand(true);
|
||||||
..set_use_underline(true);
|
..set_use_underline(true);
|
||||||
};
|
|
||||||
|
|
||||||
let hbox = cascade! {
|
|
||||||
gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
|
|
||||||
..append(&label_widget);
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(icon_data) = i.icon_data() {
|
|
||||||
let icon_data = io::Cursor::new(icon_data);
|
|
||||||
let pixbuf = gdk_pixbuf::Pixbuf::from_read(icon_data).unwrap(); // XXX unwrap
|
|
||||||
let image = cascade! {
|
|
||||||
gtk4::Image::from_pixbuf(Some(&pixbuf));
|
|
||||||
..set_halign(gtk4::Align::End);
|
|
||||||
};
|
|
||||||
hbox.append(&image);
|
|
||||||
}
|
|
||||||
|
|
||||||
let button = cascade! {
|
|
||||||
gtk4::Button::new();
|
|
||||||
..set_child(Some(&hbox));
|
|
||||||
..style_context().add_class("flat");
|
|
||||||
..set_sensitive(i.enabled().unwrap_or(true)); // default to true?
|
|
||||||
};
|
|
||||||
box_.append(&button);
|
|
||||||
|
|
||||||
if i.children_display().as_deref() == Some("submenu") {
|
|
||||||
let vbox = cascade! {
|
|
||||||
gtk4::Box::new(gtk4::Orientation::Vertical, 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let revealer = cascade! {
|
let hbox = cascade! {
|
||||||
gtk4::Revealer::new();
|
gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
|
||||||
..set_child(Some(&vbox));
|
..append(&label_widget);
|
||||||
};
|
};
|
||||||
|
|
||||||
populate_menu(&vbox, &i);
|
if let Some(icon_data) = i.icon_data() {
|
||||||
|
let icon_data = io::Cursor::new(icon_data);
|
||||||
|
let pixbuf = gdk_pixbuf::Pixbuf::from_read(icon_data).unwrap(); // XXX unwrap
|
||||||
|
let image = cascade! {
|
||||||
|
gtk4::Image::from_pixbuf(Some(&pixbuf));
|
||||||
|
..set_halign(gtk4::Align::End);
|
||||||
|
};
|
||||||
|
hbox.append(&image);
|
||||||
|
}
|
||||||
|
|
||||||
box_.append(&revealer);
|
let id = i.id();
|
||||||
|
let button = cascade! {
|
||||||
|
gtk4::Button::new();
|
||||||
|
..set_child(Some(&hbox));
|
||||||
|
..style_context().add_class("flat");
|
||||||
|
..set_sensitive(i.enabled().unwrap_or(true)); // default to true?
|
||||||
|
..connect_clicked(clone!(@weak self as self_ => move |_| {
|
||||||
|
// XXX data, timestamp
|
||||||
|
self_.inner().dbus_menu.event(id, "clicked", &0.to_variant(), 0);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
box_.append(&button);
|
||||||
|
|
||||||
button.connect_clicked(move |_| {
|
if i.children_display().as_deref() == Some("submenu") {
|
||||||
revealer.set_reveal_child(!revealer.reveals_child());
|
let vbox = cascade! {
|
||||||
});
|
gtk4::Box::new(gtk4::Orientation::Vertical, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
let revealer = cascade! {
|
||||||
|
gtk4::Revealer::new();
|
||||||
|
..set_child(Some(&vbox));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.populate_menu(&vbox, &i);
|
||||||
|
|
||||||
|
box_.append(&revealer);
|
||||||
|
|
||||||
|
button.connect_clicked(move |_| {
|
||||||
|
revealer.set_reveal_child(!revealer.reveals_child());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +180,10 @@ impl Layout {
|
||||||
self.1.get(name)?.get()
|
self.1.get(name)?.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
fn accessible_desc(&self) -> Option<String> {
|
fn accessible_desc(&self) -> Option<String> {
|
||||||
self.prop("accessible-desc")
|
self.prop("accessible-desc")
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +275,20 @@ impl DBusMenu {
|
||||||
.get()
|
.get()
|
||||||
.unwrap())
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn event(&self, id: i32, eventid: &str, data: &glib::Variant, timestamp: u32) {
|
||||||
|
let res = self.0.call_future(
|
||||||
|
"Event",
|
||||||
|
Some(&(id, eventid, data, timestamp).to_variant()),
|
||||||
|
gio::DBusCallFlags::NONE,
|
||||||
|
1000,
|
||||||
|
);
|
||||||
|
glib::MainContext::default().spawn_local(async move {
|
||||||
|
if let Err(err) = res.await {
|
||||||
|
eprintln!("Failed to call `Event`: {}", err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StatusNotifierItem(gio::DBusProxy, Option<DBusMenu>);
|
struct StatusNotifierItem(gio::DBusProxy, Option<DBusMenu>);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue