1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use super::socket::WaylandSocket;
use super::wayland;
use super::wayland::{WlDisplay, WlObject, WlRawObject};
use crate::wayland::WlCallback;
use std::collections::HashMap;
use std::sync::Mutex;
use std::sync::{Arc, Condvar, RwLock};
use std::thread;

#[derive(Clone)]
pub struct Client {
    socket: Arc<WaylandSocket>,
    pub obj_map: Arc<Mutex<HashMap<u32, Arc<WlObject>>>>,
    pub max_id: Arc<Mutex<u32>>,
    pub event_listeners: Arc<RwLock<Vec<Box<Fn(&wayland::Event) + Send + Sync>>>>,
}

impl Client {
    pub fn connect(name: Option<&str>) -> Client {
        let socket = Arc::new(WaylandSocket::connect(name));

        let client = Client {
            socket,
            obj_map: Arc::new(Mutex::new(HashMap::new())),
            max_id: Arc::new(Mutex::new(0)),
            event_listeners: Arc::new(RwLock::new(Vec::new())),
        };
        client.bind_obj::<WlDisplay>(1);
        client.start_event_loop();

        return client;
    }

    pub fn start_event_loop(&self) {
        let this = self.clone();
        thread::spawn(move || loop {
            let evs = this.socket.read_event();
            for (raw_event_header, msg_body) in evs {
                let sender = this.get_obj(raw_event_header.sender_id).unwrap();
                let event = sender.parse_event(
                    raw_event_header.sender_id,
                    raw_event_header.op_code,
                    msg_body,
                );
                for event_handler in this.event_listeners.read().unwrap().iter() {
                    event_handler(&event);
                }
            }
        });
    }

    pub fn get_display(&self) -> WlDisplay {
        self.get_obj(1).unwrap().try_get_wl_display().unwrap()
    }

    pub fn sync(&self) {
        let callback_id = self.new_obj::<WlCallback>();

        let done_pair = Arc::new((Mutex::new(false), Condvar::new()));
        let c_done_pair = done_pair.clone();
        self.add_event_listener(Box::new(move |ev| match ev {
            wayland::Event::WlCallbackEvent(callback_ev) => match callback_ev {
                wayland::WlCallbackEvent::WlCallbackdoneEvent(done) => {
                    if done.sender_id == callback_id {
                        info!("Callback id {} Done", callback_id);
                        let &(ref done, ref cond_var) = &*c_done_pair;
                        *(done.lock().unwrap()) = true;
                        cond_var.notify_all();
                    }
                }
                _ => {}
            },
            _ => {}
        }));
        self.get_display().sync(callback_id);

        let &(ref done, ref cond_var) = &*done_pair;
        let mut done = done.lock().unwrap();
        while !*done {
            done = cond_var.wait(done).unwrap();
        }
    }

    pub fn get_obj(&self, obj_id: u32) -> Option<Arc<WlObject>> {
        Some(self.obj_map.lock().unwrap().get(&obj_id)?.clone())
    }

    pub fn new_obj<T: WlRawObject>(&self) -> u32 {
        let mut hash_map = self.obj_map.lock().unwrap();
        let mut now_max = self.max_id.lock().unwrap();

        let new_id = now_max.clone() + 1;
        let wl_obj = Arc::new(T::new(new_id, self.socket.clone()).to_enum());
        hash_map.insert(new_id, wl_obj.clone());
        *(now_max) += 1;

        return new_id;
    }

    pub fn delete_obj(&self, obj_id: u32) {
        self.obj_map.lock().unwrap().remove(&obj_id);
    }

    pub fn bind_obj<T: WlRawObject>(&self, obj_id: u32) {
        let wl_obj = Arc::new(T::new(obj_id, self.socket.clone()).to_enum());
        self.obj_map.lock().unwrap().insert(obj_id, wl_obj.clone());

        let now_max = self.max_id.lock().unwrap().clone();
        *(self.max_id.lock().unwrap()) = std::cmp::max(now_max, obj_id);
    }

    pub fn add_event_listener(&self, event_handler: Box<Fn(&wayland::Event) + Send + Sync>) {
        self.event_listeners.write().unwrap().push(event_handler);
    }

    pub fn disconnect(&self) {
        self.socket.disconnect();
    }
}