Browse Source

Update dependencies, use futures

environments/review-jsparber-h-cxnwl8/deployments/1
Jonas Platte 9 years ago
parent
commit
008b63406f
  1. 1044
      Cargo.lock
  2. 8
      Cargo.toml
  3. 59
      src/app.rs
  4. 55
      src/bg_thread.rs
  5. 7
      src/main.rs
  6. 18
      src/util.rs

1044
Cargo.lock generated

File diff suppressed because it is too large Load Diff

8
Cargo.toml

@ -4,12 +4,14 @@ name = "ruma-gtk"
version = "0.1.0"
[dependencies]
gio = "0.1.1"
reqwest = "0.2.0"
futures = "0.1.14"
gio = "0.1.3"
tokio-core = "0.1.8"
url = "1.5.1"
[dependencies.gtk]
features = ["v3_12"]
version = "0.1.1"
version = "0.1.3"
[dependencies.ruma-client]
git = "https://github.com/ruma/ruma-client.git"

59
src/app.rs

@ -1,8 +1,12 @@
use std::{self, env, thread};
use std::time::Duration;
use futures;
use gio;
use gtk;
use gtk::prelude::*;
use std::{env, sync, time, thread};
use bg_thread;
use url::Url;
// TODO: Is this the correct format for GApplication IDs?
const APP_ID: &'static str = "jplatte.ruma_gtk";
@ -18,12 +22,21 @@ pub struct App {
/// Used to access the UI elements.
gtk_builder: gtk::Builder,
/// Sender to the homeserver channel.
///
/// With this channel, we tell the background thread to connect to a new
/// matrix homeserver. Currently, there can only be one connection to a
/// homeserver at one time, so sending a homeserver url over this channel
/// will result in the background thread first disconnecting, if it is
/// connected to another homeserver already.
homeserver_chan_tx: futures::sync::mpsc::Sender<Url>,
/// Channel receiver which allows to run actions from the matrix connection thread.
///
/// Long polling is required to receive messages from the rooms and so they have to
/// run in separate threads. In order to allow those threads to modify the gtk content,
/// they will send closures to the main thread using this channel.
dispatch_rx: sync::mpsc::Receiver<Box<Fn(&gtk::Builder) + Send>>,
dispatch_chan_rx: std::sync::mpsc::Receiver<Box<Fn(&gtk::Builder) + Send>>,
/// Matrix communication thread join handler used to clean up the tread when
/// closing the application.
@ -38,23 +51,21 @@ impl App {
let gtk_builder = gtk::Builder::new_from_file("res/main_window.glade");
let builder = gtk_builder.clone();
gtk_app.connect_activate(move |app| {
gtk_app.connect_activate(clone!(gtk_builder => move |app| {
// Set up shutdown callback
let window: gtk::Window = builder.get_object("main_window")
let window: gtk::Window = gtk_builder.get_object("main_window")
.expect("Couldn't find main_window in ui file.");
let app2 = app.clone();
window.connect_delete_event(move |_, _| {
app2.quit();
window.connect_delete_event(clone!(app => move |_, _| {
app.quit();
Inhibit(false)
});
}));
// Set up user popover
let user_button: gtk::Button = builder.get_object("user_button")
let user_button: gtk::Button = gtk_builder.get_object("user_button")
.expect("Couldn't find user_button in ui file.");
let user_menu: gtk::Popover = builder.get_object("user_menu")
let user_menu: gtk::Popover = gtk_builder.get_object("user_menu")
.expect("Couldn't find user_menu in ui file.");
user_button.connect_clicked(move |_| user_menu.show());
@ -62,35 +73,37 @@ impl App {
// Associate window with the Application and show it
window.set_application(Some(app));
window.show_all();
});
}));
let (homeserver_chan_tx, homeserver_chan_rx) = futures::sync::mpsc::channel(1);
// Create channel to allow the matrix connection thread to send closures to the main loop.
let (dispatch_tx, dispatch_rx) = sync::mpsc::channel::<Box<Fn(&gtk::Builder) + Send>>();
let (dispatch_chan_tx, dispatch_chan_rx) = std::sync::mpsc::channel();
let bg_thread_join_handle =
thread::spawn(move || bg_thread::run(dispatch_tx));
thread::spawn(move || bg_thread::run(homeserver_chan_rx, dispatch_chan_tx));
App {
gtk_app: gtk_app,
gtk_builder: gtk_builder,
dispatch_rx: dispatch_rx,
bg_thread_join_handle: bg_thread_join_handle,
gtk_app,
gtk_builder,
homeserver_chan_tx,
dispatch_chan_rx,
bg_thread_join_handle,
}
}
pub fn run(self) {
// Convert the args to a Vec<&str>. Application::run requires argv as &[&str]
// Convert the args to a Vec<&str>. Application::run requires argv as &[&str]
// and envd::args() returns an iterator of Strings.
let args = env::args().collect::<Vec<_>>();
let args_refs = args.iter().map(|x| &x[..]).collect::<Vec<_>>();
// Poll the matrix communication thread channel and run the closures to allow
// the threads to run actions in the main loop.
let dispatch_rx = self.dispatch_rx;
let dispatch_chan_rx = self.dispatch_chan_rx;
let gtk_builder = self.gtk_builder;
gtk::idle_add(move || {
if let Ok(dispatch_fn) = dispatch_rx.recv_timeout(time::Duration::from_millis(5)) {
if let Ok(dispatch_fn) = dispatch_chan_rx.recv_timeout(Duration::from_millis(5)) {
dispatch_fn(&gtk_builder);
}
@ -103,4 +116,4 @@ impl App {
// Clean up
self.bg_thread_join_handle.join().unwrap();
}
}
}

55
src/bg_thread.rs

@ -1,18 +1,57 @@
use std;
use std::error::Error;
use futures::{self, Future, Stream};
use gtk;
use ruma_client::Client as RumaClient;
use std::sync::mpsc::Sender;
use tokio_core::reactor::{Core, Handle};
use url::Url;
fn bg_main(
homeserver: Url,
core_handle: Handle,
homeserver_chan_rx: futures::sync::mpsc::Receiver<Url>,
dispatch_chan_tx: std::sync::mpsc::Sender<Box<Fn(&gtk::Builder) + Send>>,
) -> impl Future<Item = (), Error = Box<Error>> {
let client = RumaClient::https(&core_handle, homeserver, None).unwrap();
futures::future::ok(())
pub fn run(dispatch_tx: Sender<Box<Fn(&gtk::Builder) + Send>>) {
let client = RumaClient::new().unwrap();
// TODO: background main loop
// TODO: use loop_fn instead of manually recursing?
// TODO: Register as guest, only when successful do this stuff
dispatch_tx.send(box move |builder| {
builder.get_object::<gtk::Stack>("user_button_stack")
/*dispatch_chan_tx.send(box move |builder| {
builder
.get_object::<gtk::Stack>("user_button_stack")
.expect("Can't find user_button_stack in ui file.")
.set_visible_child_name("user_connected_page");
builder.get_object::<gtk::Label>("display_name_label")
builder
.get_object::<gtk::Label>("display_name_label")
.expect("Can't find display_name_label in ui file.")
.set_text("Guest");
});
});*/
}
pub fn run(
homeserver_chan_rx: futures::sync::mpsc::Receiver<Url>,
dispatch_chan_tx: std::sync::mpsc::Sender<Box<Fn(&gtk::Builder) + Send>>,
) {
let mut core = Core::new().unwrap();
let handle = core.handle();
core.run(
homeserver_chan_rx
.into_future()
.map_err(|_| std::sync::mpsc::RecvError.into())
.and_then(
move |(opt_url, homeserver_chan_rx)| -> Box<Future<Item = (), Error = Box<Error>>> {
if let Some(url) = opt_url {
box bg_main(url, handle, homeserver_chan_rx, dispatch_chan_tx)
} else {
box futures::future::ok(())
}
},
),
).unwrap();
}

7
src/main.rs

@ -1,14 +1,21 @@
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
// not using this yet because rustfmt doesn't support it:
// https://github.com/rust-lang-nursery/rustfmt/issues/1215
//#![feature(field_init_shorthand)]
extern crate futures;
extern crate gio;
extern crate gtk;
extern crate ruma_client;
extern crate tokio_core;
extern crate url;
// extern crate xdg;
#[macro_use]
mod util;
mod app;
mod bg_thread;

18
src/util.rs

@ -0,0 +1,18 @@
// from https://stackoverflow.com/a/43992218/1592377
#[macro_export]
macro_rules! clone {
(@param _) => ( _ );
(@param $x:ident) => ( $x );
($($n:ident),+ => move || $body:expr) => (
{
$( let $n = $n.clone(); )+
move || $body
}
);
($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
{
$( let $n = $n.clone(); )+
move |$(clone!(@param $p),)+| $body
}
);
}
Loading…
Cancel
Save