diff --git a/Cargo.lock b/Cargo.lock index bb1d07ef..cb1be684 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -324,6 +324,9 @@ name = "rs" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cairo-sys-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gdk 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "gio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index b7fbd203..c8a2d632 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,15 @@ serde = { version = "1.0.*", features = ["derive"] } serde_yaml = "0.8.*" xkbcommon = { version = "0.4.*", features = ["wayland"] } +[dependencies.cairo-rs] +version = "0.5.*" + +[dependencies.cairo-sys-rs] +version = "" + +[dependencies.gdk] +version = "" + [dependencies.gio] version = "" features = ["v2_44"] @@ -22,7 +31,6 @@ features = ["v2_44"] version = "" features = ["v2_44"] - [dependencies.gtk] version = "0.5.*" features = ["v3_22"] diff --git a/eek/eek-gtk-keyboard.c b/eek/eek-gtk-keyboard.c index c9590db5..9f092fd1 100644 --- a/eek/eek-gtk-keyboard.c +++ b/eek/eek-gtk-keyboard.c @@ -85,7 +85,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, cairo_t *cr) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); GtkAllocation allocation; gtk_widget_get_allocation (self, &allocation); @@ -101,10 +101,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self, gtk_widget_get_scale_factor (self)); } - // render the keyboard without any key activity (TODO: from a cached buffer) eek_renderer_render_keyboard (priv->renderer, cr); - // render only a few remaining changes - squeek_layout_draw_all_changed(priv->keyboard->layout, EEK_GTK_KEYBOARD(self)); return FALSE; } @@ -113,7 +110,7 @@ eek_gtk_keyboard_real_size_allocate (GtkWidget *self, GtkAllocation *allocation) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); if (priv->renderer) eek_renderer_set_allocation_size (priv->renderer, @@ -231,7 +228,7 @@ static void eek_gtk_keyboard_real_unmap (GtkWidget *self) { EekGtkKeyboardPrivate *priv = - eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); + eek_gtk_keyboard_get_instance_private (EEK_GTK_KEYBOARD (self)); if (priv->keyboard) { squeek_layout_release_all_only( @@ -322,25 +319,9 @@ eek_gtk_keyboard_new (LevelKeyboard *keyboard) return GTK_WIDGET(ret); } -static void -render_pressed_button (GtkWidget *widget, - struct button_place *place) -{ - EekGtkKeyboard *self = EEK_GTK_KEYBOARD (widget); +EekRenderer *eek_gtk_keyboard_get_renderer(EekGtkKeyboard *self) { EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - GdkWindow *window = gtk_widget_get_window (widget); - cairo_region_t *region = gdk_window_get_clip_region (window); - GdkDrawingContext *context = gdk_window_begin_draw_frame (window, region); - cairo_t *cr = gdk_drawing_context_get_cairo_context (context); - - eek_renderer_render_button (priv->renderer, cr, place, 1.0, TRUE, FALSE); -/* - eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE); -*/ - gdk_window_end_draw_frame (window, context); - - cairo_region_destroy (region); + return priv->renderer; } void @@ -381,31 +362,6 @@ render_released_button (GtkWidget *widget, cairo_region_destroy (region); } -void -eek_gtk_on_button_pressed (struct button_place place, - EekGtkKeyboard *self) -{ - EekGtkKeyboardPrivate *priv = eek_gtk_keyboard_get_instance_private (self); - - /* renderer may have not been set yet if the widget is a popup */ - if (!priv->renderer) - return; - - if (!place.row) { - return; - } - render_pressed_button (GTK_WIDGET(self), &place); - gtk_widget_queue_draw (GTK_WIDGET(self)); - -#if HAVE_LIBCANBERRA - ca_gtk_play_for_widget (widget, 0, - CA_PROP_EVENT_ID, "button-pressed", - CA_PROP_EVENT_DESCRIPTION, "virtual key pressed", - CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard", - NULL); -#endif -} - void eek_gtk_on_button_released (const struct squeek_button *button, struct squeek_view *view, diff --git a/eek/eek-renderer.c b/eek/eek-renderer.c index ce9499ee..2d687b38 100644 --- a/eek/eek-renderer.c +++ b/eek/eek-renderer.c @@ -63,7 +63,7 @@ static void eek_renderer_render_button_label (EekRenderer *self, cairo_t *cr, Gt const struct squeek_button *button); static void invalidate (EekRenderer *renderer); -static void render_button (EekRenderer *self, +void eek_render_button (EekRenderer *self, cairo_t *cr, const struct squeek_button *button, gboolean pressed, gboolean locked); @@ -92,7 +92,7 @@ create_keyboard_surface_button_callback (struct squeek_button *button, bounds.height); cairo_clip (data->cr); - render_button (data->renderer, data->cr, button, FALSE, FALSE); + eek_render_button (data->renderer, data->cr, button, FALSE, FALSE); cairo_restore (data->cr); } @@ -147,8 +147,6 @@ render_keyboard_surface (EekRenderer *renderer, struct squeek_view *view) cairo_save (data.cr); - cairo_scale (data.cr, priv->scale, priv->scale); - EekBounds bounds = squeek_view_get_bounds (view); cairo_translate (data.cr, bounds.x, bounds.y); @@ -186,12 +184,10 @@ render_outline (cairo_t *cr, } static void render_button_in_context(EekRenderer *self, - gdouble scale, gint scale_factor, cairo_t *cr, GtkStyleContext *ctx, - const struct squeek_button *button, - gboolean active) { + const struct squeek_button *button) { /* blank background */ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); cairo_paint (cr); @@ -234,8 +230,8 @@ static void render_button_in_context(EekRenderer *self, eek_renderer_render_button_label (self, cr, ctx, button); } -static void -render_button (EekRenderer *self, +void +eek_render_button (EekRenderer *self, cairo_t *cr, const struct squeek_button *button, gboolean pressed, @@ -263,7 +259,7 @@ render_button (EekRenderer *self, } gtk_style_context_add_class(ctx, outline_name); - render_button_in_context(self, priv->scale, priv->scale_factor, cr, ctx, button, pressed); + render_button_in_context(self, priv->scale_factor, cr, ctx, button); // Save and restore functions don't work if gtk_render_* was used in between gtk_style_context_set_state(ctx, GTK_STATE_FLAG_NORMAL); @@ -417,7 +413,7 @@ eek_renderer_render_button (EekRenderer *self, cairo_translate (cr, bounds.x, bounds.y); eek_renderer_apply_transformation_for_button (cr, place, scale); - render_button ( + eek_render_button ( self, cr, place->button, is_pressed, is_locked @@ -425,21 +421,19 @@ eek_renderer_render_button (EekRenderer *self, cairo_restore (cr); } -static void -eek_renderer_real_render_keyboard (EekRenderer *self, +void +eek_renderer_render_keyboard (EekRenderer *self, cairo_t *cr) { EekRendererPrivate *priv = eek_renderer_get_instance_private (self); - cairo_pattern_t *source; g_return_if_fail (priv->keyboard); g_return_if_fail (priv->allocation_width > 0.0); g_return_if_fail (priv->allocation_height > 0.0); - cairo_save (cr); - + cairo_save(cr); cairo_translate (cr, priv->origin_x, priv->origin_y); - + cairo_scale (cr, priv->scale, priv->scale); if (priv->keyboard_surface) cairo_surface_destroy (priv->keyboard_surface); @@ -450,10 +444,11 @@ eek_renderer_real_render_keyboard (EekRenderer *self, render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout)); cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0); - source = cairo_get_source (cr); + cairo_pattern_t *source = cairo_get_source (cr); cairo_pattern_set_extend (source, CAIRO_EXTEND_PAD); cairo_paint (cr); + squeek_layout_draw_all_changed(priv->keyboard->layout, self, cr); cairo_restore (cr); } @@ -529,8 +524,6 @@ eek_renderer_class_init (EekRendererClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; - klass->render_keyboard = eek_renderer_real_render_keyboard; - gobject_class->set_property = eek_renderer_set_property; gobject_class->get_property = eek_renderer_get_property; gobject_class->dispose = eek_renderer_dispose; @@ -783,14 +776,6 @@ eek_renderer_get_icon_surface (const gchar *icon_name, return surface; } -void -eek_renderer_render_keyboard (EekRenderer *renderer, - cairo_t *cr) -{ - g_return_if_fail (EEK_IS_RENDERER(renderer)); - EEK_RENDERER_GET_CLASS(renderer)->render_keyboard (renderer, cr); -} - static gboolean sign (EekPoint *p1, EekPoint *p2, EekPoint *p3) { diff --git a/eek/eek-renderer.h b/eek/eek-renderer.h index ec52e809..c5b3d4d8 100644 --- a/eek/eek-renderer.h +++ b/eek/eek-renderer.h @@ -25,7 +25,6 @@ #include #include "eek-types.h" -#include "src/layout.h" G_BEGIN_DECLS @@ -36,9 +35,6 @@ struct _EekRendererClass { GObjectClass parent_class; - void (* render_keyboard) (EekRenderer *self, - cairo_t *cr); - cairo_surface_t *(* get_icon_surface) (EekRenderer *self, const gchar *icon_name, gint size, diff --git a/eek/eek-types.h b/eek/eek-types.h index db187250..6324094b 100644 --- a/eek/eek-types.h +++ b/eek/eek-types.h @@ -88,5 +88,14 @@ struct transformation { gdouble origin_y; gdouble scale; }; + +struct squeek_button; +struct squeek_row; + +/// Represents the path to the button within a view +struct button_place { + const struct squeek_row *row; + const struct squeek_button *button; +}; G_END_DECLS #endif /* EEK_TYPES_H */ diff --git a/src/drawing.rs b/src/drawing.rs new file mode 100644 index 00000000..71ef59fe --- /dev/null +++ b/src/drawing.rs @@ -0,0 +1,154 @@ +/*! Drawing the UI */ + +use cairo; +use std::cell::RefCell; + +use ::keyboard; +use ::layout; +use ::layout::{ Button, Layout }; +use ::layout::c::{ EekGtkKeyboard, Point }; + +use gdk::{ WindowExt, DrawingContextExt }; +use glib::translate::FromGlibPtrNone; +use gtk::WidgetExt; + +mod c { + use super::*; + + use cairo_sys; + use std::os::raw::c_void; + + // This is constructed only in C, no need for warnings + #[allow(dead_code)] + #[repr(transparent)] + #[derive(Clone, Copy)] + pub struct EekRenderer(*const c_void); + + #[no_mangle] + extern "C" { + // Button and View inside CButtonPlace are safe to pass to C + // as long as they don't outlive the call + // and nothing dereferences them + #[allow(improper_ctypes)] + pub fn eek_render_button( + renderer: EekRenderer, + cr: *mut cairo_sys::cairo_t, + button: *const Button, + pressed: u64, + locked: u64, + ); + + pub fn eek_gtk_keyboard_get_renderer( + keyboard: EekGtkKeyboard, + ) -> EekRenderer; + + pub fn eek_renderer_get_transformation( + renderer: EekRenderer, + ) -> layout::c::Transformation; + } + + #[no_mangle] + pub extern "C" + fn squeek_layout_draw_all_changed( + layout: *mut Layout, + renderer: EekRenderer, + cr: *mut cairo_sys::cairo_t, + ) { + let layout = unsafe { &mut *layout }; + let cr = unsafe { cairo::Context::from_raw_none(cr) }; + + let view = layout.get_current_view(); + let view_position = view.bounds.get_position(); + for row in &view.rows { + for button in &row.buttons { + let state = RefCell::borrow(&button.state).clone(); + if state.pressed == keyboard::PressType::Pressed || state.locked { + let position = &view_position + + row.bounds.clone().unwrap().get_position() + + button.bounds.get_position(); + render_button_at_position( + renderer, &cr, + position, button.as_ref(), + state.pressed, state.locked, + ); + } + } + } + } +} + +/// Renders a button at a position (button's own bounds ignored) +pub fn render_button_at_position( + renderer: c::EekRenderer, + cr: &cairo::Context, + position: Point, + button: &Button, + pressed: keyboard::PressType, + locked: bool, +) { + cr.save(); + cr.translate(position.x, position.y); + cr.rectangle( + 0.0, 0.0, + button.bounds.width, button.bounds.height + ); + cr.clip(); + unsafe { + c::eek_render_button( + renderer, + cairo::Context::to_raw_none(&cr), + button as *const Button, + pressed as u64, + locked as u64, + ) + }; + cr.restore(); +} + +pub fn queue_redraw(keyboard: EekGtkKeyboard) { + let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) }; + widget.queue_draw(); +} + +/// Renders a single frame +/// Opens a frame on `keyboard`'s `GdkWindow`, attempt to get a drawing context, +/// calls `f`, closes the frame. +/// If the drawing context was successfully retrieved, returns `f` call result. +pub fn render_as_frame(keyboard: EekGtkKeyboard, mut f: F) -> Option + where F: FnMut(c::EekRenderer, &cairo::Context) -> T +{ + let renderer = unsafe { c::eek_gtk_keyboard_get_renderer(keyboard) }; + + let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) }; + widget.get_window() + .and_then(|window| { + // Need to split the `.and_then` chain here + // because `window` needs to be in scope + // for the references deeper inside. + window.get_clip_region() + // contrary to the docs, `Region` gets destroyed automatically + .and_then(|region| window.begin_draw_frame(®ion)) + .and_then(|drawctx| { + let ret: Option = drawctx.get_cairo_context() + .map(|cr| { + let transformation = unsafe { + c::eek_renderer_get_transformation(renderer) + }; + cr.translate( + transformation.origin_x, + transformation.origin_y, + ); + cr.scale( + transformation.scale, + transformation.scale, + ); + queue_redraw(keyboard); + f(renderer, &cr) // finally! + }); + // This must always happen after `begin_draw_frame`, + // enven if `get_cairo_context` fails. + window.end_draw_frame(&drawctx); + ret + }) + }) +} diff --git a/src/keyboard.rs b/src/keyboard.rs index 0aa4dcfb..c81c7450 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -11,7 +11,7 @@ use ::action::Action; use std::io::Write; use std::iter::{ FromIterator, IntoIterator }; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum PressType { Released = 0, Pressed = 1, diff --git a/src/layout.h b/src/layout.h index eefae7fe..6c6455f3 100644 --- a/src/layout.h +++ b/src/layout.h @@ -5,6 +5,7 @@ #include #include "eek/eek-element.h" #include "eek/eek-gtk-keyboard.h" +#include "eek/eek-renderer.h" #include "eek/eek-types.h" #include "virtual-keyboard-unstable-v1-client-protocol.h" @@ -13,17 +14,9 @@ enum squeek_arrangement_kind { ARRANGEMENT_KIND_WIDE = 1, }; -struct squeek_button; -struct squeek_row; struct squeek_view; struct squeek_layout; -/// Represents the path to the button within a view -struct button_place { - const struct squeek_row *row; - const struct squeek_button *button; -}; - int32_t squeek_row_get_angle(const struct squeek_row*); EekBounds squeek_row_get_bounds(const struct squeek_row*); @@ -71,5 +64,5 @@ void squeek_layout_drag(struct squeek_layout *layout, struct zwp_virtual_keyboar double x_widget, double y_widget, struct transformation widget_to_layout, uint32_t timestamp, EekGtkKeyboard *ui_keyboard); -void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekGtkKeyboard *ui_keyboard); +void squeek_layout_draw_all_changed(struct squeek_layout *layout, EekRenderer* renderer, cairo_t *cr); #endif diff --git a/src/layout.rs b/src/layout.rs index 9a2264f3..03a04c5f 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -24,6 +24,7 @@ use std::rc::Rc; use std::vec::Vec; use ::action::Action; +use ::drawing; use ::float_ord::FloatOrd; use ::keyboard::{ KeyState, PressType }; use ::submission::{ Timestamp, VirtualKeyboard }; @@ -34,10 +35,12 @@ use std::borrow::Borrow; pub mod c { use super::*; + use gtk_sys; use std::ffi::CStr; use std::os::raw::{ c_char, c_void }; use std::ptr; - use gtk_sys; + + use std::ops::Add; // The following defined in C @@ -55,6 +58,23 @@ pub mod c { pub x: f64, pub y: f64, } + + impl Add for Point { + type Output = Self; + fn add(self, other: Self) -> Self { + &self + other + } + } + + impl Add for &Point { + type Output = Point; + fn add(self, other: Point) -> Point { + Point { + x: self.x + other.x, + y: self.y + other.y, + } + } + } /// Defined in eek-types.h #[repr(C)] @@ -66,6 +86,51 @@ pub mod c { pub height: f64 } + impl Bounds { + pub fn get_position(&self) -> Point { + Point { + x: self.x, + y: self.y, + } + } + } + + /// Scale + translate + #[repr(C)] + pub struct Transformation { + pub origin_x: f64, + pub origin_y: f64, + pub scale: f64, + } + + impl Transformation { + fn forward(&self, p: Point) -> Point { + Point { + x: (p.x - self.origin_x) / self.scale, + y: (p.y - self.origin_y) / self.scale, + } + } + fn reverse(&self, p: Point) -> Point { + Point { + x: p.x * self.scale + self.origin_x, + y: p.y * self.scale + self.origin_y, + } + } + pub fn reverse_bounds(&self, b: Bounds) -> Bounds { + let start = self.reverse(Point { x: b.x, y: b.y }); + let end = self.reverse(Point { + x: b.x + b.width, + y: b.y + b.height, + }); + Bounds { + x: start.x, + y: start.y, + width: end.x - start.x, + height: end.y - start.y, + } + } + } + type ButtonCallback = unsafe extern "C" fn(button: *mut ::layout::Button, data: *mut UserData); type RowCallback = unsafe extern "C" fn(row: *mut ::layout::Row, data: *mut UserData); @@ -212,7 +277,7 @@ pub mod c { use super::*; use ::submission::c::ZwpVirtualKeyboardV1; - + #[repr(C)] #[derive(PartialEq, Debug)] pub struct CButtonPlace { @@ -228,42 +293,6 @@ pub mod c { } } } - - /// Scale + translate - #[repr(C)] - pub struct Transformation { - origin_x: f64, - origin_y: f64, - scale: f64, - } - - impl Transformation { - fn forward(&self, p: Point) -> Point { - Point { - x: (p.x - self.origin_x) / self.scale, - y: (p.y - self.origin_y) / self.scale, - } - } - fn reverse(&self, p: Point) -> Point { - Point { - x: p.x * self.scale + self.origin_x, - y: p.y * self.scale + self.origin_y, - } - } - pub fn reverse_bounds(&self, b: Bounds) -> Bounds { - let start = self.reverse(Point { x: b.x, y: b.y }); - let end = self.reverse(Point { - x: b.x + b.width, - y: b.y + b.height, - }); - Bounds { - x: start.x, - y: start.y, - width: end.x - start.x, - height: end.y - start.y, - } - } - } // This is constructed only in C, no need for warnings #[allow(dead_code)] @@ -289,24 +318,6 @@ pub mod c { view: *const View, keyboard: EekGtkKeyboard, ); - - // Button and View inside CButtonPlace are safe to pass to C - // as long as they don't outlive the call - // and nothing dereferences them - #[allow(improper_ctypes)] - pub fn eek_gtk_on_button_pressed( - place: CButtonPlace, - keyboard: EekGtkKeyboard, - ); - - // Button and View inside CButtonPlace are safe to pass to C - // as long as they don't outlive the call - // and nothing dereferences them - #[allow(improper_ctypes)] - pub fn eek_gtk_render_locked_button( - keyboard: EekGtkKeyboard, - place: CButtonPlace, - ); } /// Places each button in order, starting from 0 on the left, @@ -346,15 +357,16 @@ pub mod c { // because it will be mutated in the loop for key in layout.pressed_keys.clone() { let key: &Rc> = key.borrow(); - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, time, ui_keyboard, - key + key, ); } + drawing::queue_redraw(ui_keyboard); } /// Release all buittons but don't redraw @@ -393,27 +405,16 @@ pub mod c { let point = widget_to_layout.forward( Point { x: x_widget, y: y_widget } ); - - // the immutable reference to `layout` through `view` - // must be dropped - // before `layout.press_key` borrows it mutably again - let state_place = { - let view = layout.get_current_view(); - let place = view.find_button_by_position(point); - place.map(|place| {( - place.button.state.clone(), - place.into(), - )}) - }; - - if let Some((mut state, c_place)) = state_place { + + if let Some(position) = layout.get_button_at_point(point) { + let mut state = position.button.state.clone(); layout.press_key( &VirtualKeyboard(virtual_keyboard), &mut state, Timestamp(time), ); - - unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) }; + // maybe TODO: draw on the display buffer here + drawing::queue_redraw(ui_keyboard); } } @@ -439,23 +440,26 @@ pub mod c { ); let pressed = layout.pressed_keys.clone(); - let state_place = { + let button_info = { let view = layout.get_current_view(); let place = view.find_button_by_position(point); place.map(|place| {( place.button.state.clone(), - place.into(), + place.button.clone(), + view.bounds.get_position() + + place.row.bounds.clone().unwrap().get_position() + + place.button.bounds.get_position(), )}) }; - if let Some((mut state, c_place)) = state_place { + if let Some((mut state, _button, _view_position)) = button_info { let mut found = false; for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); if Rc::ptr_eq(&state, &wrapped_key.0) { found = true; } else { - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, @@ -467,12 +471,12 @@ pub mod c { } if !found { layout.press_key(&virtual_keyboard, &mut state, time); - unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) }; + // maybe TODO: draw on the display buffer here } } else { for wrapped_key in pressed { let key: &Rc> = wrapped_key.borrow(); - ui::release_key( + seat::handle_release_key( layout, &virtual_keyboard, &widget_to_layout, @@ -482,33 +486,7 @@ pub mod c { ); } } - } - - #[no_mangle] - pub extern "C" - fn squeek_layout_draw_all_changed( - layout: *mut Layout, - ui_keyboard: EekGtkKeyboard, - ) { - let layout = unsafe { &mut *layout }; - - for row in &layout.get_current_view().rows { - for button in &row.buttons { - let c_place = CButtonPlace::from( - ButtonPlace { row, button } - ); - let state = RefCell::borrow(&button.state); - match (state.pressed, state.locked) { - (PressType::Released, false) => {} - (PressType::Pressed, _) => unsafe { - eek_gtk_on_button_pressed(c_place, ui_keyboard) - }, - (_, true) => unsafe { - eek_gtk_render_locked_button(ui_keyboard, c_place) - }, - } - } - } + drawing::queue_redraw(ui_keyboard); } #[cfg(test)] @@ -535,6 +513,12 @@ pub mod c { } } +/// Relative to `View` +struct ButtonPosition { + view_position: c::Point, + button: Button, +} + pub struct ButtonPlace<'a> { button: &'a Button, row: &'a Row, @@ -779,7 +763,8 @@ impl Layout { locked_keys: HashSet::new(), } } - fn get_current_view(&self) -> &Box { + + pub fn get_current_view(&self) -> &Box { self.views.get(&self.current_view).expect("Selected nonexistent view") } @@ -871,6 +856,18 @@ impl Layout { }; }; } + + fn get_button_at_point(&self, point: c::Point) -> Option { + let view = self.get_current_view(); + let place = view.find_button_by_position(point); + place.map(|place| ButtonPosition { + button: place.button.clone(), + // Rows have no business being inside a view + // if they have no valid bounds. + view_position: place.row.bounds.clone().unwrap().get_position() + + place.button.bounds.get_position(), + }) + } } mod procedures { @@ -1002,15 +999,15 @@ mod procedures { } } -/// Top level UI procedures -mod ui { +/// Top level procedures, dispatching to everything +mod seat { use super::*; // TODO: turn into release_button - pub fn release_key( + pub fn handle_release_key( layout: &mut Layout, virtual_keyboard: &VirtualKeyboard, - widget_to_layout: &c::procedures::Transformation, + widget_to_layout: &c::Transformation, time: Timestamp, ui_keyboard: c::EekGtkKeyboard, key: &Rc>, @@ -1040,6 +1037,7 @@ mod ui { } } + // TODO: move one level up; multiple buttons might have been released procedures::release_ui_buttons(view, key, ui_keyboard); } } diff --git a/src/lib.rs b/src/lib.rs index 3795b257..d7bf622d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,8 @@ #[macro_use] extern crate bitflags; +extern crate cairo; +extern crate cairo_sys; +extern crate gdk; extern crate gio; extern crate glib; extern crate glib_sys; @@ -14,6 +17,7 @@ extern crate xkbcommon; mod action; pub mod data; +mod drawing; pub mod float_ord; pub mod imservice; mod keyboard;