diff options
| -rw-r--r-- | src/android/mod.rs | 14 | ||||
| -rw-r--r-- | src/events.rs | 3 | ||||
| -rw-r--r-- | src/lib.rs | 31 | ||||
| -rw-r--r-- | src/osx/mod.rs | 30 | ||||
| -rw-r--r-- | src/win32/mod.rs | 14 | ||||
| -rw-r--r-- | src/x11/ffi.rs | 2 | ||||
| -rw-r--r-- | src/x11/mod.rs | 2 | ||||
| -rw-r--r-- | src/x11/window/mod.rs | 143 | 
8 files changed, 187 insertions, 52 deletions
| diff --git a/src/android/mod.rs b/src/android/mod.rs index 8093d50..8bc82ce 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -207,6 +207,10 @@ impl Window {      pub fn set_inner_size(&self, _x: uint, _y: uint) {      } +    pub fn create_window_proxy(&self) -> WindowProxy { +        WindowProxy +    } +      pub fn poll_events(&self) -> Vec<Event> {          use std::time::Duration;          use std::io::timer; @@ -271,6 +275,16 @@ impl Window {      }  } +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy; + +impl WindowProxy { +    pub fn wakeup_event_loop(&self) { +        unimplemented!() +    } +} +  #[unsafe_destructor]  impl Drop for Window {      fn drop(&mut self) { diff --git a/src/events.rs b/src/events.rs index 76fda81..beafbec 100644 --- a/src/events.rs +++ b/src/events.rs @@ -31,6 +31,9 @@ pub enum Event {      /// An event from the mouse has been received.      MouseInput(ElementState, MouseButton), + +    /// The event loop was woken up by another thread. +    Awakened,  }  pub type ScanCode = u8; @@ -473,6 +473,15 @@ impl Window {      pub fn get_api(&self) -> Api {          self.window.get_api()      } + +    /// Create a window proxy for this window, that can be freely +    /// passed to different threads. +    #[inline] +    pub fn create_window_proxy(&self) -> WindowProxy { +        WindowProxy { +            proxy: self.window.create_window_proxy() +        } +    }  }  #[cfg(feature = "window")] @@ -482,6 +491,28 @@ impl gl_common::GlFunctionsSource for Window {      }  } +/// Represents a thread safe subset of operations that can be called +/// on a window. This structure can be safely cloned and sent between +/// threads. +/// +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy { +    proxy: winimpl::WindowProxy, +} + +#[cfg(feature = "window")] +impl WindowProxy { + +    /// Triggers a blocked event loop to wake up. This is +    /// typically called when another thread wants to wake +    /// up the blocked rendering thread to cause a refresh. +    #[inline] +    pub fn wakeup_event_loop(&self) { +        self.proxy.wakeup_event_loop(); +    } +} +  /// Represents a headless OpenGL context.  #[cfg(feature = "headless")]  pub struct HeadlessContext { diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 7ea6cb4..42a9ea2 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -74,6 +74,32 @@ impl Window {      }  } +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy; + +impl WindowProxy { +    pub fn wakeup_event_loop(&self) { +        unsafe { +            let pool = NSAutoreleasePool::new(nil); +            let event = +                NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( +                nil, +                NSApplicationDefined, +                NSPoint::new(0.0, 0.0), +                0, +                0.0, +                0, +                ptr::null_mut(), +                0, +                0, +                0); +            NSApp().postEvent_atStart_(event, true); +            pool.drain(); +        } +    } +} +  extern fn window_should_close(this: id, _: id) -> id {      unsafe {          let mut stored_value = ptr::null_mut(); @@ -278,6 +304,10 @@ impl Window {          unimplemented!()      } +    pub fn create_window_proxy(&self) -> WindowProxy { +        WindowProxy +    } +      pub fn poll_events(&self) -> Vec<Event> {          let mut events = Vec::new(); diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 5ba5a26..978e3b5 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -83,6 +83,16 @@ impl Window {      }  } +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy; + +impl WindowProxy { +    pub fn wakeup_event_loop(&self) { +        unimplemented!() +    } +} +  impl Window {      /// See the docs in the crate root file.      pub fn is_closed(&self) -> bool { @@ -180,6 +190,10 @@ impl Window {          }      } +    pub fn create_window_proxy(&self) -> WindowProxy { +        WindowProxy +    } +      /// See the docs in the crate root file.      // TODO: return iterator      pub fn poll_events(&self) -> Vec<Event> { diff --git a/src/x11/ffi.rs b/src/x11/ffi.rs index 3fe6499..1f8b10f 100644 --- a/src/x11/ffi.rs +++ b/src/x11/ffi.rs @@ -1420,6 +1420,8 @@ extern "C" {          x_return: *mut libc::c_int, y_return: *mut libc::c_int,          width_return: *mut libc::c_uint, height_return: *mut libc::c_uint,          border_width_return: *mut libc::c_uint, depth_return: *mut libc::c_uint) -> Status; +    pub fn XSendEvent(display: *mut Display, window: Window, propagate: Bool, +                      event_mask: libc::c_long, event_send: *mut XEvent) -> Status;      pub fn XInternAtom(display: *mut Display, atom_name: *const libc::c_char,          only_if_exists: Bool) -> Atom;      pub fn XKeycodeToKeysym(display: *mut Display, keycode: KeyCode, diff --git a/src/x11/mod.rs b/src/x11/mod.rs index 9d9d25c..9ce789f 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -2,7 +2,7 @@  pub use self::headless::HeadlessContext;  #[cfg(feature = "window")] -pub use self::window::{Window, MonitorID, get_available_monitors, get_primary_monitor}; +pub use self::window::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor};  mod ffi; diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index 01126e6..a0e7078 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -6,7 +6,7 @@ use std::{mem, ptr};  use std::cell::Cell;  use std::sync::atomic::AtomicBool;  use super::ffi; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Arc, Once, ONCE_INIT};  pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; @@ -23,17 +23,65 @@ fn ensure_thread_init() {      });  } -pub struct Window { +struct XWindow {      display: *mut ffi::Display,      window: ffi::Window, -    im: ffi::XIM, -    ic: ffi::XIC,      context: ffi::GLXContext, +    is_fullscreen: bool, +    screen_id: libc::c_int, +    xf86_desk_mode: *mut ffi::XF86VidModeModeInfo, +    ic: ffi::XIC, +    im: ffi::XIM, +} + +impl Drop for XWindow { +    fn drop(&mut self) { +        unsafe { +            ffi::glx::MakeCurrent(self.display, 0, ptr::null()); +            ffi::glx::DestroyContext(self.display, self.context); + +            if self.is_fullscreen { +                ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode); +                ffi::XF86VidModeSetViewPort(self.display, self.screen_id, 0, 0); +            } + +            ffi::XDestroyIC(self.ic); +            ffi::XCloseIM(self.im); +            ffi::XDestroyWindow(self.display, self.window); +            ffi::XCloseDisplay(self.display); +        } +    } +} + +#[deriving(Clone)] +pub struct WindowProxy { +    x: Arc<XWindow>, +} + +impl WindowProxy { +    pub fn wakeup_event_loop(&self) { +        let mut xev = ffi::XClientMessageEvent { +            type_: ffi::ClientMessage, +            window: self.x.window, +            format: 32, +            message_type: 0, +            serial: 0, +            send_event: 0, +            display: self.x.display, +            l: [0, 0, 0, 0, 0], +        }; + +        unsafe { +            ffi::XSendEvent(self.x.display, self.x.window, 0, 0, mem::transmute(&mut xev)); +            ffi::XFlush(self.x.display); +        } +    } +} + +pub struct Window { +    x: Arc<XWindow>,      is_closed: AtomicBool,      wm_delete_window: ffi::Atom, -    xf86_desk_mode: *mut ffi::XF86VidModeModeInfo, -    screen_id: libc::c_int, -    is_fullscreen: bool,      current_size: Cell<(libc::c_int, libc::c_int)>,  } @@ -257,7 +305,7 @@ impl Window {              });              let share = if let Some(win) = builder.sharing { -                win.window.context +                win.window.x.context              } else {                  ptr::null()              }; @@ -278,16 +326,18 @@ impl Window {          // creating the window object          let window = Window { -            display: display, -            window: window, -            im: im, -            ic: ic, -            context: context, +            x: Arc::new(XWindow { +                display: display, +                window: window, +                im: im, +                ic: ic, +                context: context, +                screen_id: screen_id, +                is_fullscreen: builder.monitor.is_some(), +                xf86_desk_mode: xf86_desk_mode, +            }),              is_closed: AtomicBool::new(false),              wm_delete_window: wm_delete_window, -            xf86_desk_mode: xf86_desk_mode, -            screen_id: screen_id, -            is_fullscreen: builder.monitor.is_some(),              current_size: Cell::new((0, 0)),          }; @@ -303,22 +353,22 @@ impl Window {      pub fn set_title(&self, title: &str) {          let c_title = title.to_c_str();          unsafe { -            ffi::XStoreName(self.display, self.window, c_title.as_ptr()); -            ffi::XFlush(self.display); +            ffi::XStoreName(self.x.display, self.x.window, c_title.as_ptr()); +            ffi::XFlush(self.x.display);          }      }      pub fn show(&self) {          unsafe { -            ffi::XMapRaised(self.display, self.window); -            ffi::XFlush(self.display); +            ffi::XMapRaised(self.x.display, self.x.window); +            ffi::XFlush(self.x.display);          }      }      pub fn hide(&self) {          unsafe { -            ffi::XUnmapWindow(self.display, self.window); -            ffi::XFlush(self.display); +            ffi::XUnmapWindow(self.x.display, self.x.window); +            ffi::XFlush(self.x.display);          }      } @@ -334,7 +384,7 @@ impl Window {              let mut border: libc::c_uint = mem::uninitialized();              let mut depth: libc::c_uint = mem::uninitialized(); -            if ffi::XGetGeometry(self.display, self.window, +            if ffi::XGetGeometry(self.x.display, self.x.window,                  &mut root, &mut x, &mut y, &mut width, &mut height,                  &mut border, &mut depth) == 0              { @@ -350,7 +400,7 @@ impl Window {      }      pub fn set_position(&self, x: int, y: int) { -        unsafe { ffi::XMoveWindow(self.display, self.window, x as libc::c_int, y as libc::c_int) } +        unsafe { ffi::XMoveWindow(self.x.display, self.x.window, x as libc::c_int, y as libc::c_int) }      }      pub fn get_inner_size(&self) -> Option<(uint, uint)> { @@ -365,6 +415,12 @@ impl Window {          unimplemented!()      } +    pub fn create_window_proxy(&self) -> WindowProxy { +        WindowProxy { +            x: self.x.clone() +        } +    } +      pub fn poll_events(&self) -> Vec<Event> {          use std::mem; @@ -374,10 +430,10 @@ impl Window {              use std::num::Int;              let mut xev = unsafe { mem::uninitialized() }; -            let res = unsafe { ffi::XCheckMaskEvent(self.display, Int::max_value(), &mut xev) }; +            let res = unsafe { ffi::XCheckMaskEvent(self.x.display, Int::max_value(), &mut xev) };              if res == 0 { -                let res = unsafe { ffi::XCheckTypedEvent(self.display, ffi::ClientMessage, &mut xev) }; +                let res = unsafe { ffi::XCheckTypedEvent(self.x.display, ffi::ClientMessage, &mut xev) };                  if res == 0 {                      break @@ -390,7 +446,7 @@ impl Window {                  },                  ffi::ClientMessage => { -                    use events::Event::Closed; +                    use events::Event::{Closed, Awakened};                      use std::sync::atomic::Relaxed;                      let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) }; @@ -398,6 +454,8 @@ impl Window {                      if client_msg.l[0] == self.wm_delete_window as libc::c_long {                          self.is_closed.store(true, Relaxed);                          events.push(Closed); +                    } else { +                        events.push(Awakened);                      }                  }, @@ -424,7 +482,7 @@ impl Window {                      if event.type_ == ffi::KeyPress {                          let raw_ev: *mut ffi::XKeyEvent = event; -                        unsafe { ffi::XFilterEvent(mem::transmute(raw_ev), self.window) }; +                        unsafe { ffi::XFilterEvent(mem::transmute(raw_ev), self.x.window) };                      }                      let state = if xev.type_ == ffi::KeyPress { Pressed } else { Released }; @@ -434,7 +492,7 @@ impl Window {                          let mut buffer: [u8, ..16] = [mem::uninitialized(), ..16];                          let raw_ev: *mut ffi::XKeyEvent = event; -                        let count = ffi::Xutf8LookupString(self.ic, mem::transmute(raw_ev), +                        let count = ffi::Xutf8LookupString(self.x.ic, mem::transmute(raw_ev),                              mem::transmute(buffer.as_mut_ptr()),                              buffer.len() as libc::c_int, ptr::null_mut(), ptr::null_mut()); @@ -447,7 +505,7 @@ impl Window {                      }                      let keysym = unsafe { -                        ffi::XKeycodeToKeysym(self.display, event.keycode as ffi::KeyCode, 0) +                        ffi::XKeycodeToKeysym(self.x.display, event.keycode as ffi::KeyCode, 0)                      };                      let vkey =  events::keycode_to_element(keysym as libc::c_uint); @@ -500,7 +558,7 @@ impl Window {              // this will block until an event arrives, but doesn't remove              //  it from the queue              let mut xev = unsafe { mem::uninitialized() }; -            unsafe { ffi::XPeekEvent(self.display, &mut xev) }; +            unsafe { ffi::XPeekEvent(self.x.display, &mut xev) };              // calling poll_events()              let ev = self.poll_events(); @@ -511,7 +569,7 @@ impl Window {      }      pub unsafe fn make_current(&self) { -        let res = ffi::glx::MakeCurrent(self.display, self.window, self.context); +        let res = ffi::glx::MakeCurrent(self.x.display, self.x.window, self.x.context);          if res == 0 {              panic!("glx::MakeCurrent failed");          } @@ -529,11 +587,11 @@ impl Window {      }      pub fn swap_buffers(&self) { -        unsafe { ffi::glx::SwapBuffers(self.display, self.window) } +        unsafe { ffi::glx::SwapBuffers(self.x.display, self.x.window) }      }      pub fn platform_display(&self) -> *mut libc::c_void { -        self.display as *mut libc::c_void +        self.x.display as *mut libc::c_void      }      /// See the docs in the crate root file. @@ -541,20 +599,3 @@ impl Window {          ::Api::OpenGl      }  } - -impl Drop for Window { -    fn drop(&mut self) { -        unsafe { ffi::glx::MakeCurrent(self.display, 0, ptr::null()); } -        unsafe { ffi::glx::DestroyContext(self.display, self.context); } - -        if self.is_fullscreen { -            unsafe { ffi::XF86VidModeSwitchToMode(self.display, self.screen_id, self.xf86_desk_mode); } -            unsafe { ffi::XF86VidModeSetViewPort(self.display, self.screen_id, 0, 0); } -        } - -        unsafe { ffi::XDestroyIC(self.ic); } -        unsafe { ffi::XCloseIM(self.im); } -        unsafe { ffi::XDestroyWindow(self.display, self.window); } -        unsafe { ffi::XCloseDisplay(self.display); } -    } -} | 
