Skip to content

Commit

Permalink
improv: Watch shortcut changes safely
Browse files Browse the repository at this point in the history
  • Loading branch information
mmstick committed Sep 14, 2020
1 parent 8d37d42 commit 2f01614
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 102 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ derive_more = "0.99.5"
enclose = "1.1.8"
gdk = "0.13.0"
gio = "0.9.0"
glib = "0.10.0"
glib = "0.10.2"
glib-sys = "0.10.0"
gtk = { version = "0.9.0", features = ["v3_22"] }
pango = "0.9.0"
Expand Down
101 changes: 61 additions & 40 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use gio::prelude::*;
use gtk::prelude::*;
use std::collections::HashMap;
use std::rc::Rc;

const LAPTOP_DARK: &[u8] = include_bytes!("../assets/laptop-dark.svg");
const DISPLAY_DARK: &[u8] = include_bytes!("../assets/display-dark.svg");
Expand Down Expand Up @@ -199,6 +199,45 @@ pub enum Event {
CloseWindow,
}

pub struct State {
// Holds the schema settings that are to be connected later
pub registration: HashMap<String, (gio::Settings, HashMap<String, gtk::Box>)>,
}

impl Default for State {
fn default() -> Self {
Self {
registration: HashMap::default(),
}
}
}

impl State {
/// Register an intention to watch a key on a schema for changes
pub fn register(&mut self, schema: String, settings: gio::Settings, key: String, shortcuts: gtk::Box) {
self.registration.entry(schema)
.or_insert_with(|| (settings, HashMap::new()))
.1
.insert(key, shortcuts);
}

/// Watch for changes to keys on schemas, with one signal per `gio::Settings`
pub fn connect_schemas(&mut self) {
for (_, (settings, keys)) in self.registration.drain() {
settings.connect_changed(move |settings, changed| {
if let Some(widget) = keys.get(changed) {
widget.foreach(|w| widget.remove(w));
for shortcut in settings.get_strv(changed) {
widget.add(&gtk::ShortcutLabel::new(&shortcut));
}
widget.show_all();
}
});
}
}
}


pub struct Section {
pub header: &'static str,
pub shortcuts: &'static [Shortcut],
Expand Down Expand Up @@ -242,15 +281,14 @@ pub fn main(app: &gtk::Application) {
);
}

// let laptop = &svg_draw_area(LAPTOP_DARK, 300, 230);
// let display = &svg_draw_area(DISPLAY_DARK, 300, 300);
let mut state = State::default();
let shortcuts_section = shortcuts_section(&mut state);
state.connect_schemas();

let shortcuts = cascade! {
gtk::Box::new(gtk::Orientation::Vertical, 24);
..set_border_width(8);
//..add(&legend());
..add(&shortcuts_section());
//..add(&settings_reference());
..add(&shortcuts_section);
};

let scroller = cascade! {
Expand All @@ -264,7 +302,6 @@ pub fn main(app: &gtk::Application) {
let content = cascade! {
gtk::Box::new(gtk::Orientation::Vertical, 24);
..set_border_width(8);
//..add(&demo_section(&laptop, display));
..add(&scroller);
};

Expand Down Expand Up @@ -365,7 +402,7 @@ fn settings_reference() -> gtk::Box {
container
}

fn shortcuts_section() -> gtk::FlowBox {
fn shortcuts_section(state: &mut State) -> gtk::FlowBox {
let key_sg = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal);

let container = cascade! {
Expand All @@ -376,17 +413,9 @@ fn shortcuts_section() -> gtk::FlowBox {
..set_column_spacing(12);
};

let event_handler: Rc<dyn Fn(&gtk::EventBox, Event)> = Rc::new(|widget, event| {
println!("clicked {:?}", event);
});

let mut settings_map = HashMap::new();
let iter = COLUMNS.iter().flat_map(|i| i.iter()).map(|section| {
let section = cascade! {
crate::widgets::Section::new(&key_sg, section, &event_handler, &mut settings_map);
};

section
crate::widgets::Section::new(&key_sg, section, state, &mut settings_map)
});

for widget in iter {
Expand All @@ -396,27 +425,19 @@ fn shortcuts_section() -> gtk::FlowBox {
container
}

/*
fn svg_draw_area(svg: &[u8], width: i32, height: i32) -> gtk::DrawingArea {
let drawing_area = gtk::DrawingArea::new();
let opt = resvg::Options::default();
let tree = resvg::usvg::Tree::from_data(svg, &opt.usvg).unwrap();
drawing_area.connect_draw(move |w, cr| {
let screen = resvg::ScreenSize::new(
w.get_allocated_width() as u32,
w.get_allocated_height() as u32,
pub fn open_schema(schema: &str) -> gio::Settings {
if schema == "org.gnome.shell.extensions.pop-shell" {
let settings_schema = gio::SettingsSchemaSource::from_directory(
"/usr/share/gnome-shell/extensions/[email protected]/schemas",
None,
false
).unwrap().lookup(schema, false).unwrap();
gio::Settings::new_full::<gio::SettingsBackend>(
&settings_schema,
None,
None,
)
.unwrap();
resvg::backend_cairo::render_to_canvas(&tree, &opt, screen, cr);
gtk::Inhibit(false)
});
drawing_area.set_size_request(width, height);
drawing_area
}
*/
} else {
gio::Settings::new(schema)
}
}
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[macro_use]
extern crate cascade;
#[macro_use]
extern crate enclose;
// #[macro_use]
// extern crate enclose;
#[macro_use]
extern crate derive_more;

Expand Down
82 changes: 25 additions & 57 deletions src/widgets.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use crate::{
app::{Event, Schema, Section as SectionInfo},
app::{Schema, Section as SectionInfo},
misc::keycap,
};

use gio::prelude::*;
use glib::clone;
use glib::translate::{FromGlibPtrContainer, ToGlibPtr};
use gtk::prelude::*;
use std::collections::HashMap;
use std::rc::Rc;

use crate::app::State;

#[derive(AsRef, Deref)]
#[as_ref]
Expand All @@ -19,7 +18,7 @@ impl Section {
pub fn new(
key_sg: &gtk::SizeGroup,
section: &SectionInfo,
func: &Rc<dyn Fn(&gtk::EventBox, Event)>,
state: &mut State,
settings_map: &mut HashMap<&'static str, gio::Settings>,
) -> Self {
let label = gtk::LabelBuilder::new()
Expand All @@ -40,55 +39,6 @@ impl Section {

key_sg.add_widget(&keys);

match shortcut.schema {
Schema::GSettings { schema, key } => {
let settings =
settings_map.entry(schema).or_insert_with(|| {
if schema == "org.gnome.shell.extensions.pop-shell" {
let settings_schema = gio::SettingsSchemaSource::from_directory(
"/usr/share/gnome-shell/extensions/[email protected]/schemas",
None,
false
).unwrap().lookup(schema, false).unwrap();
gio::Settings::new_full::<gio::SettingsBackend>(
&settings_schema,
None,
None,
)
} else {
gio::Settings::new(schema)
}
});

for i in settings.get_strv(key) {
keys.add(&gtk::ShortcutLabel::new(&i));
//let (keysym, mask) = gtk::accelerator_parse(&i);
//keys.add(&keycap(&gtk::accelerator_get_label(keysym, mask).unwrap()));
}
let action = settings.create_action(key).unwrap();
action.connect_property_state_notify(clone!(@weak keys => @default-panic, move |action| {
let state = action.get_state().unwrap();
let strv: Vec<glib::GString> = unsafe { FromGlibPtrContainer::from_glib_container(glib_sys::g_variant_get_strv(state.to_glib_none().0, std::ptr::null_mut())) };
keys.foreach(|w| keys.remove(w));
for i in strv {
keys.add(&gtk::ShortcutLabel::new(&i));
//let (keysym, mask) = gtk::accelerator_parse(&i);
//keys.add(&keycap(&gtk::accelerator_get_label(keysym, mask).unwrap()));
}
keys.show_all();

}));

// Trick so that `action` is freed when the `keys` GObject is freed
unsafe { keys.set_data("action", action) };
}
Schema::Hardcoded(binding) => {
binding.iter().for_each(|binding| {
keys.add(&keycap(binding));
});
}
}

let event_box = gtk::EventBoxBuilder::new()
.can_focus(false)
.hexpand(true)
Expand All @@ -101,10 +51,28 @@ impl Section {
..add(&gtk::Label::new(shortcut.description.into()));
});

event_box.connect_button_press_event(enclose!((func) move |event_box, _| {
func(event_box, shortcut.event);
event_box.connect_button_press_event(move |_, _| {
// TODO: Someday handle click event
gtk::Inhibit(true)
}));
});

match shortcut.schema {
Schema::GSettings { schema, key } => {
let settings = settings_map.entry(schema)
.or_insert_with(|| crate::app::open_schema(schema));

for i in settings.get_strv(key) {
keys.add(&gtk::ShortcutLabel::new(&i));
}

state.register(schema.into(), settings.clone(), key.into(), keys);
}
Schema::Hardcoded(binding) => {
binding.iter().for_each(|binding| {
keys.add(&keycap(binding));
});
}
}

bindings.add(&event_box);
}
Expand Down

0 comments on commit 2f01614

Please sign in to comment.