aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Watson <gw@intuitionlibrary.com>2014-12-17 14:49:11 +1000
committerGlenn Watson <gw@intuitionlibrary.com>2014-12-17 14:50:05 +1000
commit9dc5689eef87cace5e6ac6b5438928a1c99688c4 (patch)
tree224ec970788ed9d1f6830381946421a05d9c8741
parent19d120b8b19d85e9cea5c3e8851b8809d072b8bd (diff)
downloadglutin-9dc5689eef87cace5e6ac6b5438928a1c99688c4.tar.gz
glutin-9dc5689eef87cace5e6ac6b5438928a1c99688c4.zip
Introduce a WindowProxy for accessing a subset of functionality
from other threads. This currently provides a way for other threads to wakeup a blocked event loop on X11. Other platforms have stub functions that need to be implemented. This is similar to the functionality of glfwPostEmptyEvent.
-rw-r--r--src/android/mod.rs14
-rw-r--r--src/events.rs3
-rw-r--r--src/lib.rs31
-rw-r--r--src/osx/mod.rs14
-rw-r--r--src/win32/mod.rs14
-rw-r--r--src/x11/ffi.rs2
-rw-r--r--src/x11/mod.rs2
-rw-r--r--src/x11/window/mod.rs143
8 files changed, 171 insertions, 52 deletions
diff --git a/src/android/mod.rs b/src/android/mod.rs
index 8093d50..fd0a857 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) {
+ // TODO
+ }
+}
+
#[unsafe_destructor]
impl Drop for Window {
fn drop(&mut self) {
diff --git a/src/events.rs b/src/events.rs
index 76fda81..3cb81ff 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 window should be redrawn.
+ Refresh,
}
pub type ScanCode = u8;
diff --git a/src/lib.rs b/src/lib.rs
index 9ba3e13..029b576 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 c69486a..3f9da82 100644
--- a/src/osx/mod.rs
+++ b/src/osx/mod.rs
@@ -74,6 +74,16 @@ impl Window {
}
}
+#[cfg(feature = "window")]
+#[deriving(Clone)]
+pub struct WindowProxy;
+
+impl WindowProxy {
+ pub fn wakeup_event_loop(&self) {
+ // TODO
+ }
+}
+
extern fn window_should_close(this: id, _: id) -> id {
unsafe {
let mut stored_value = ptr::null_mut();
@@ -278,6 +288,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..099c126 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) {
+ // TODO
+ }
+}
+
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 f22d1f8..6ea14c5 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, Refresh};
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(Refresh);
}
},
@@ -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); }
- }
-}