How can I get the mouse X and Y in Glium + Glutin? - rust

I use Glium to write a game where I have to render an image in a specific position when a click is detected. To do so, I need to get the X and Y position. So how do I get them?
My current code looks like this:
/* ... */
event.run(move |event, _, control_flow| {
match event {
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested => {
println!("Received termination signal.");
*control_flow = glutin::event_loop::ControlFlow::Exit;
return;
},
_ => return,
},
glutin::event::Event::NewEvents(cause) => match cause {
glutin::event::StartCause::ResumeTimeReached { .. } => (),
glutin::event::StartCause::Init => (),
_ => return,
},
_ => return,
}
If possible, I wouldn't mind getting OpenGL Coordinates as X and Y (-1, 1), but I think it will be a hassle to pass it to a vertex buffer.

This is the answer I was looking for, it's a WindowEvent:
match event {
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested => {
println!("Received termination signal.");
*control_flow = glutin::event_loop::ControlFlow::Exit;
return;
},
/* The code to get the mouse position (And print it to the console) */
glutin::event::WindowEvent::CursorMoved { position, .. } => {
println!("Mouse position: {:?}x{:?}", position.x as u16, position.y as u16);
}
_ => return,
},
/* Handle the rest of events */

Related

How can I add a global keydown event listener in Dioxus)?

I'm currently trying out dioxus for rust, and I'm trying to figure out how to handle a global keyboard down event.
I want to use the arrow keys to move images back and forth:
Here's my code so far:
use dioxus::{events::*, prelude::*};
use log::{info, LevelFilter};
/**
* Specify <link data-trunk rel="copy-dir" href="src/assets" />
* in the index.html to copy the files!!
*
* You'll see them in the dist directory!
*/
fn main() {
dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
dioxus::web::launch(app);
}
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(img {
src: "{url}",
onkeydown: change_evt,
}))
}
In JavaScript would've been something like
document.addEventListener('keydown', (evt) => {
// Do magic
}
I've tried following the calculator example but can't get it to work.
Any ideas?
onkeydown does not seem to work as a callback passed to an image. Wrap it in a div.
I placed an extra button there because, for some reason, the keyboard event callbacks did not register until I interacted with the app somehow (tried it in the browser).
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| {
log::info!("{index}{}", evt.key);
match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(
img {
src: "{url}",
}
div {
class: "display",
onkeydown: change_evt,
button {
class: "but",
onclick: move |evt| {
println!("{evt:?}");
info!("{evt:?}");
},
"Press me!"
},
},
))
}

custom window manager: Some GTK+ 3 windows receive focus but will not accept mouse clicks

As the title says. I'm writing a custom X11 window manager in Rust, using the xcb library. A specific window -- the "configuration" window for cairo-dock -- will not take button 1 clicks when focused, despite ungrabbing button 1 on that window.
Previously, I thought that said window was not holding focus, but that turns out to not be correct. Instead, the window in question is receiving focus, but not allowing any button 1 clicks through.
Relevant code for setting focus:
#[allow(clippy::single_match)]
fn set_focus(&mut self, window: xproto::Window) {
if window != self.root && window != self.focus {
let prev = self.focus;
// ungrab focus from the previous window
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
self.focus,
0
);
// make sure we don't accidentally have button 1 grabbed
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
window,
0
);
// See https://github.com/i3/i3/blob/b61a28f156aad545d5c54b9a6f40ef7cae1a1c9b/src/x.c#L1286-L1337
if self.needs_take_focus(window)
&& self.doesnt_take_focus(window)
&& window != base::NONE
&& window != self.root {
let client_message =
xproto::ClientMessageEvent::new(
32,
window,
self.atom("WM_PROTOCOLS"),
xproto::ClientMessageData::from_data32(
[
self.atom("WM_TAKE_FOCUS"),
self.last_timestamp,
0,
0,
0
]
)
);
xproto::send_event(self.conn, false, window, base::NONE as u32, &client_message);
} else {
debug!("{} can be focused normally", window);
xproto::set_input_focus(
self.conn,
xproto::INPUT_FOCUS_PARENT as u8,
window,
self.last_timestamp,
);
}
self.replace_prop(
self.root,
self.atom("_NET_ACTIVE_WINDOW"),
32,
&[window]
);
debug!("updating _NET_WM_STATE with _NET_WM_STATE_FOCUSED!");
self.remove_prop(prev, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.append_prop(window, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.focus = window;
debug!("focused window: {}", self.focus);
} else if window == self.root {
self.remove_prop(self.focus, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
debug!("focusing root -> NONE");
self.replace_prop(self.root, self.atom("_NET_ACTIVE_WINDOW"), 32, &[base::NONE]);
xproto::set_input_focus(self.conn, 0, base::NONE, base::CURRENT_TIME);
self.focus = xcb::NONE;
}
}
fn append_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
// TODO: Check result
xproto::change_property(
self.conn,
xproto::PROP_MODE_APPEND as u8,
window,
prop,
xproto::ATOM_ATOM,
32,
&[atom]
);
}
fn remove_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
let cookie = xproto::get_property(self.conn, false, window, prop, xproto::GET_PROPERTY_TYPE_ANY, 0, 4096);
match cookie.get_reply() {
Ok(res) => {
match res.value::<u32>() {
[] => {},
values => {
let mut new_values: Vec<u32> = Vec::from(values);
new_values.retain(|value| value != &atom);
self.replace_prop(window, prop, 32, &new_values);
},
}
},
Err(err) => error!("couldn't get props to remove from: {:#?}", err),
}
}
fn needs_take_focus(&self, window: xproto::Window) -> bool {
let properties_cookie =
xproto::get_property(
self.conn,
false,
window,
self.atom("WM_PROTOCOLS"),
xproto::ATOM_ANY,
0,
2048
);
match properties_cookie.get_reply() {
Ok(protocols) => {
let mut needs_help = false;
for proto in protocols.value::<u32>().iter() {
match self.atom_by_id_checked(proto) {
Some("WM_TAKE_FOCUS") => {
needs_help = true
},
_ => (),
}
}
needs_help
},
// FIXME
Err(_) => false,
}
}
fn doesnt_take_focus(&self, window: xproto::Window) -> bool {
match xcb_util::icccm::get_wm_hints(self.conn, window).get_reply() {
Ok(hints) => {
if let Some(input) = hints.input() {
input
} else {
false
}
},
// FIXME
Err(_) => false,
}
}
It turns out my problem was that I wasn't ungrabbing button 1 correctly; focus was actually being passed correctly (see question edit history), I was just forgetting to ungrab correctly because I forgot that the initial grab had a button mask on it. Thank you so much to Uli Schlachter in the comments helping me get it figured out.

Unrolling tree-recursion into an iterative program

I wrote a library that can generate arbitrary strings given a spec-object (https://github.com/rgrannell1/revexp) and I want to convert the function that reads the spec from a recursive algorithm to an iterative algorithm. I'm running into stackoverflow errors due to the depth of the specs I'm traversing.
I believe I need to move from using the call-stack to an explicit stack, but I've never done this before. I've read through previous posts on StackOverflow but I didn't fully understand how to apply the solutions to this problem.
Here is an example spec object.
const data = {
every: [
{
digit: { zero: false }
},
{
repeat: {
value: { digit: {} }
}
}
]
}
and a minimal example of how the algorithm currently traverses the spec and generates a string matching the spec.
const fromSpec = (data) => {
if (data.every) {
return fromSpec.every(data)
} else if (data.digit) {
return fromSpec.digit()
} else if (data.repeat) {
return fromSpec.repeat(data.repeat)
}
}
fromSpec.digit = () => {
return Math.floor(Math.random() * 10)
}
fromSpec.every = part => {
let message = ''
for (const elem of part.every) {
message += fromSpec(elem)
}
return message
}
fromSpec.repeat = part => {
let message = ''
// -- just using fixed repeat for the example
for (let ith = 0; ith < 10; ++ith) {
message += fromSpec(part.value)
}
return message
}
const result = fromSpec(data)
result // 1034856872
I'd appreciate any advice on how to traverse this data-structure and generate an output string in an iterative rather than recursive fashion.
The following example modifies the code to use a stack data structure. Data on the stack is processed incrementally, with new data possibly added on each iteration.
const fromSpec = (data) => {
const stack = [data];
let message = '';
while (stack.length > 0) {
const item = stack.pop();
// Assumption based on the code in the question:
// 'every', 'digit', and 'repeat' keys are mutually exclusive.
if (item.every) {
// Add items in reverse order, so that items are popped off the stack
// in the original order.
for (let i = item.every.length - 1; i >= 0; --i) {
stack.push(item.every[i]);
}
} else if (item.digit) {
message += String(Math.floor(Math.random() * 10));
} else if (item.repeat) {
for (let i = 0; i < 10; ++i) {
stack.push(item.repeat.value);
}
}
}
return message;
}
An alternative approach would be required for a more complicated scenario (e.g., when a node in the tree requires processing both 1) when it's initially encountered in the traversal and 2) after all its children have been traversed).
The following links may be relevant.
https://web.archive.org/web/20120227170843/http://cs.saddleback.edu/rwatkins/CS2B/Lab%20Exercises/Stacks%20and%20Recursion%20Lab.pdf
https://web.archive.org/web/20161206082402/https://secweb.cs.odu.edu/~zeil/cs361/web/website/Lectures/recursionConversion/page/recursionConversion.html
It's natural to write RevExp.toString as a recursive program because it is expected to process a recursively structured input. However because recursive programs can lead to deep stacks, it's not uncommon to flatten a recursive process to an iterative one.
Good programmers know that maintaining complexity goes a long way in sustaining our sanity. I want to keep my recursive program and I want the computer to handle flattening the process for me. Can I have my cake and eat it too?
Here's another way to look a the problem -
// example1.js
import { concat, upper, digit, str, toString } from './RevExp.js'
const licensePlate =
concat(upper(), upper(), upper(), str("-"), digit(), digit(), digit())
console.log(toString(licensePlate))
console.log(toString(licensePlate))
console.log(toString(licensePlate))
// RFX-559
// VKT-794
// KSF-823
Let's begin writing the RevExp module. We'll start by creating constructors for each of our expression types -
// RevExp.js
const str = (value = "") =>
({ type: str, value })
const lower = () =>
({ type: lower })
const upper = () =>
({ type: upper })
const digit = ({ zero = true } = {}) =>
({ type: digit, zero })
const concat = (...exprs) =>
({ type: concat, exprs })
Now let's work on RevExp.toString -
// RevExp.js (continued)
import { inRange } from './Rand.js'
const toString = (e) =>
{ switch (e.type)
{ case str:
return String(e.value)
case lower:
return String.fromCharCode(inRange(97, 122))
case upper:
return String.fromCharCode(inRange(65, 90))
case digit:
return e.zero
? String(inRange(0, 9))
: String(inRange(1, 9))
case concat:
return e.exprs.reduce((r, v) => r + toString(v), "")
default: throw Error(`unsupported expression type: ${e.type}`)
}
}
export { lower, upper, digit, alpha, repeat, concat, str, toString }
It should be possible to make complex expressions by combining several simple expressions. And we imagine some new types like alpha, and repeat -
// example2.js
import { alpha, digit, repeat, concat, str, toString } from './RevExp.js'
const segment =
concat(alpha(), digit(), alpha(), digit(), alpha())
const serial =
concat
( repeat
( concat(segment, str("-"))
, { count: 4 }
)
, segment
)
console.log(toString(serial))
console.log(toString(serial))
console.log(toString(serial))
// F3Q7U-b6k8Q-R8e3A-a2q3M-j0a9k
// g6G3w-h2O3O-b8O3k-L4p1y-m5I0y
// m6E0M-A4C2y-K3g0M-d7X7j-w8v5G
And add corresponding support in the RevExp module -
// RevExp.js (enhanced)
import { inRange, sample } from './Rand.js'
const str = // ...
const lower = // ...
const upper = // ...
const digit = // ...
const concat = // ...
const alpha = () =>
oneOf(upper(), lower())
const oneOf = (...exprs) =>
({ type: oneOf, exprs })
const repeat = (expr = {}, { count = 10 } = {}) =>
({ type: repeat, expr, count })
const toString = (e) =>
{ switch (e.type)
{ case str: // ...
case lower: // ...
case upper: // ...
case digit: // ...
case concat: // ...
case oneOf:
return toString(sample(e.exprs))
case repeat:
return toString(concat(...Array(e.count).fill(e.expr)))
default: // ...
}
}
export { /* ..., */ alpha, oneOf, repeat }
Now let's transform the recursive program to an iterative one. And without having to think about the stack or mutate state as the program runs, too!
// RevExp.js (stack-safe)
// ...
import * as Str from './Str.js'
import { loop, recur, call } from './TailRec.js'
// ...
const toString = (e = {}) =>
loop(toStringTailRec, e)
const toStringTailRec = e =>
{ switch (e.type)
{ case str: // ...
case lower: // ...
case upper: // ...
case digit: // ...
case concat:
return e.exprs.length
? call
( Str.concat
, recur(e.exprs[0])
, recur(concat(...e.exprs.slice(1)))
)
: Str.empty
case oneOf:
return recur(sample(e.exprs))
case repeat:
return recur(concat(...Array(e.count).fill(e.expr)))
default: throw Error(`unsupported expression type: ${e.type}`)
}
}
export { /*...*/, toString } // <-- don't export toStringTailRec helper
And here are the remaining modules, Str, Rand, and TailRec -
// Str.js
const empty =
""
const concat = (a = "", b = "") =>
a + b
export { empty, concat }
// Rand.js
const rand = (n = 2) =>
Math.floor(Math.random() * n)
const inRange = (min = 0, max = 1) =>
rand(max - min + 1) + min
const sample = (t = []) =>
t[rand(t.length)]
export { rand, inRange, sample }
Writing modules is an important factor in creating reusable code. This TailRec module was written in another post and can be reused, without modification1, to meet our program's needs.
Now we can rely on recursively structured programs without having to introduce complexity or requiring a change in how we think every time we encounter a recursive problem. Write the module once, reuse as needed -
// TailRec.js
const identity = x =>
x
const call = (f, ...values) =>
({ type: call, f, values })
const recur = (...values) =>
({ type: recur, values })
const loop = (f, ...init) =>
{ const aux1 = (e, k) =>
e.type === recur
? call(aux, e.values, r => call(aux1, f(...r), k))
: e.type === call
? call(aux, e.values, r => call(aux1, e.f(...r), k))
: call(k, e)
const aux = (exprs, k) =>
call
( exprs.reduce
( (mr, e) =>
k => call(mr, r => call(aux1, e, x => call(k, [ ...r, x ])))
, k => call(k, [])
)
, k
)
return run(aux1(f(...init), identity))
}
const run = r =>
{ while (r && r.type === call)
r = r.f(...r.values)
return r
}
export { loop, call, recur }
In the end, the approach here is virtually the same as yours. However instead of representing expressions writing JS objects by hand, we use functions, which can be parameterized and composed, and can handle the tedious and precarious assembly for us. Programmer sanity maintained -
// example2.js
// ...
console.log(serial)
{ type: concat
, exprs:
[ { type: repeat
, expr:
{ type: concat
, exprs:
[ { type: concat
, exprs:
[ { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
, { type: digit, zero: true }
, { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
, { type: digit, zero: true }
, { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
]
}
, { type: str, value: "-" }
]
}
, count: 4
}
, { type: concat
, exprs:
[ { type: concat
, exprs:
[ { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
, { type: digit, zero: true }
, { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
, { type: digit, zero: true }
, { type: oneOf, exprs: [ { type: lower }, { type: upper } ] }
]
}
]
}
]
}
I hope this was seen as an exciting way to see the same problem from a different perspective. If you end up using the TailRec module, see the original post for additional explanation. I'm happy to answer any follow-up questions.
1. Minor formatting changes and variable renaming for consistency with this answer

Gtk Widgets returning None even when they hold data

I have a filechoosernative and a comboboxtext in my UI. Now I am trying to extract data from those two inside callbacks but they are returning me None even though they clearly have data set by the user. Why is this happening?
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L41
fn get_selected_file(&self) -> Option<std::path::PathBuf> {
let selected_file = self.fcn.get_filename();
dbg!(&selected_file);
selected_file
}
Excerpt from https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L35
fn get_selected_device(&self) -> Option<udisks::DiskDevice> {
// Combo box text only stores a Gstring (Device ID)
// Search through the list of devices from udisks2 again
// and find the device with matching device ID
let selected_device = match self.lsblk_cbt.get_active_text() {
Some(txt) => {
dbg!(&txt);
for disk in crate::aux::backend::get_disks() {
if disk.drive.id == txt {
return Some(disk);
}
}
dbg!("No matching device found. Must reload.");
None
}
None => {
dbg!("lsblk_cbt is returning nothing");
None
}
};
dbg!(&selected_device);
selected_device
}
Both return None in https://gitlab.com/9898287/nixwriter/-/blob/rir/src/frontend/mod.rs#L110
fn set_lsblk_cbt(&mut self) {
let cbt = self.lsblk_cbt.clone();
for ddev in crate::aux::backend::get_disks() {
cbt.append_text(&ddev.drive.id);
}
let (device_chosen, file_chosen) = (
self.get_selected_device().is_some(),
self.get_selected_file().is_some(),
);
let start = self.start.clone();
cbt.connect_changed(move |_| {
start.set_sensitive(device_chosen && file_chosen);
dbg!("From set_lsblk_cbt", device_chosen, file_chosen);
});
}
even after the user has set a file and selected an item from ComboboxText.

Reducing match indentation for deeply nested properties

I need to refer to a value deep within a structure which includes an Option nested in a struct property, nested in a Result.
My current (working) solution is:
let raw = &packet[16..];
match PacketHeaders::from_ip_slice(raw) {
Err(_value) => {
/* ignore */
},
Ok(value) => {
match value.ip {
Some(Version4(header)) => {
let key = format!("{}.{}.{}.{},{}.{}.{}.{}",
header.source[0], header.source[1], header.source[2], header.source[3],
header.destination[0], header.destination[1], header.destination[2], header.destination[3],
);
let Count {packets, bytes} = counts.entry(key).or_insert(Count {packets: 0, bytes: 0});
*packets += 1;
*bytes += packet.len();
if p > 1000 { /* exit after 1000 packets */
for (key, value) in counts {
println!("{},{},{}", key, value.packets, value.bytes);
}
return ();
}
p += 1;
}
_ => {
/* ignore */
}
}
}
}
(The problem with my current code is the excessive nesting and the two matches.)
All I want is PacketHeaders::from_ip_slice(ip) >> Ok >> ip >> Some >> Version4.
How can I get this, or ignore a failure nicely (NOT crash/exit) for each captured packet?
Pattern matching nests, and the pattern for struct looks like struct literals with the addition that .. means "and match all the rest, which I don't care about", similar to how the _ pattern means "match anything". Meaning you can do
match PacketHeaders::from_ip_slice(raw) {
Ok(PacketHeaders { ip: Version4(header), .. }) => {
/* handle */
}
_ => {
/* ignore `Err(_)` and other `Ok(_)` */
},
}
and if you're going to ignore all but one case, you can use if let:
if let Ok(PacketHeaders { ip: Version4(header), .. }) = PacketHeaders::from_ip_slice(raw) {
/* handle */
}
Code ended up being:
let raw = &packet[16..];
if let Ok(PacketHeaders { ip: Some(Version4(header)), link: _, vlan: _, transport: _, payload: _}) = PacketHeaders::from_ip_slice(raw) {
let key = format!("{}.{}.{}.{},{}.{}.{}.{}",
header.source[0], header.source[1], header.source[2], header.source[3],
header.destination[0], header.destination[1], header.destination[2], header.destination[3],
);
let Count {packets, bytes} = counts.entry(key).or_insert(Count {packets: 0, bytes: 0});
*packets += 1;
*bytes += packet.len();
}

Resources