aboutsummaryrefslogtreecommitdiffstats
path: root/src/x11/window/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/x11/window/mod.rs')
-rw-r--r--src/x11/window/mod.rs109
1 files changed, 86 insertions, 23 deletions
diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs
index ad10e16..26d5497 100644
--- a/src/x11/window/mod.rs
+++ b/src/x11/window/mod.rs
@@ -1,14 +1,26 @@
-use {Event, WindowBuilder};
+use {Event, WindowBuilder, KeyModifiers};
use libc;
use std::{mem, ptr};
-use std::sync::atomics::AtomicBool;
+use std::cell::Cell;
+use std::sync::atomic::AtomicBool;
use super::ffi;
+use sync::one::{Once, ONCE_INIT};
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
mod events;
mod monitor;
+static THREAD_INIT: Once = ONCE_INIT;
+
+fn ensure_thread_init() {
+ THREAD_INIT.doit(|| {
+ unsafe {
+ ffi::XInitThreads();
+ }
+ });
+}
+
pub struct Window {
display: *mut ffi::Display,
window: ffi::Window,
@@ -20,10 +32,13 @@ pub struct Window {
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
screen_id: libc::c_int,
is_fullscreen: bool,
+ current_modifiers: Cell<KeyModifiers>,
+ current_size: Cell<(libc::c_int, libc::c_int)>,
}
impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, String> {
+ ensure_thread_init();
let dimensions = builder.dimensions.unwrap_or((800, 600));
// calling XOpenDisplay
@@ -83,7 +98,7 @@ impl Window {
best_mode = i;
}
};
- if best_mode == -1 {
+ if best_mode == -1 && builder.monitor.is_some() {
return Err(format!("Could not find a suitable graphics mode"));
}
@@ -120,7 +135,7 @@ impl Window {
let mut set_win_attr = {
let mut swa: ffi::XSetWindowAttributes = unsafe { mem::zeroed() };
swa.colormap = cmap;
- swa.event_mask = ffi::ExposureMask | ffi::ResizeRedirectMask |
+ swa.event_mask = ffi::ExposureMask | ffi::StructureNotifyMask |
ffi::VisibilityChangeMask | ffi::KeyPressMask | ffi::PointerMotionMask |
ffi::KeyReleaseMask | ffi::ButtonPressMask |
ffi::ButtonReleaseMask | ffi::KeymapStateMask;
@@ -152,11 +167,12 @@ impl Window {
let wm_delete_window = unsafe {
use std::c_str::ToCStr;
+ let delete_window = "WM_DELETE_WINDOW".to_c_str();
ffi::XMapWindow(display, window);
- let mut wm_delete_window = ffi::XInternAtom(display,
- "WM_DELETE_WINDOW".to_c_str().as_ptr() as *const libc::c_char, 0);
+ let mut wm_delete_window = ffi::XInternAtom(display, delete_window.as_ptr(), 0);
ffi::XSetWMProtocols(display, window, &mut wm_delete_window, 1);
- ffi::XStoreName(display, window, mem::transmute(builder.title.as_slice().as_ptr()));
+ let c_title = builder.title.to_c_str();
+ ffi::XStoreName(display, window, c_title.as_ptr());
ffi::XFlush(display);
wm_delete_window
@@ -175,8 +191,10 @@ impl Window {
let ic = unsafe {
use std::c_str::ToCStr;
- let ic = ffi::XCreateIC(im, "inputStyle".to_c_str().as_ptr(),
- ffi::XIMPreeditNothing | ffi::XIMStatusNothing, "clientWindow".to_c_str().as_ptr(),
+ let input_style = "inputStyle".to_c_str();
+ let client_window = "clientWindow".to_c_str();
+ let ic = ffi::XCreateIC(im, input_style.as_ptr(),
+ ffi::XIMPreeditNothing | ffi::XIMStatusNothing, client_window.as_ptr(),
window, ptr::null());
if ic.is_null() {
return Err(format!("XCreateIC failed"));
@@ -231,6 +249,9 @@ impl Window {
context
};
+ // Make context current before call to glViewport below.
+ unsafe { ffi::glx::MakeCurrent(display, window, context) };
+
// creating the window object
let window = Window {
display: display,
@@ -243,6 +264,8 @@ impl Window {
xf86_desk_mode: xf86_desk_mode,
screen_id: screen_id,
is_fullscreen: builder.monitor.is_some(),
+ current_modifiers: Cell::new(KeyModifiers::empty()),
+ current_size: Cell::new((0, 0)),
};
// calling glViewport
@@ -260,14 +283,15 @@ impl Window {
}
pub fn is_closed(&self) -> bool {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.load(Relaxed)
}
pub fn set_title(&self, title: &str) {
+ let c_title = title.to_c_str();
unsafe {
- ffi::XStoreName(self.display, self.window,
- mem::transmute(title.as_slice().as_ptr()));
+ ffi::XStoreName(self.display, self.window, c_title.as_ptr());
+ ffi::XFlush(self.display);
}
}
@@ -340,7 +364,7 @@ impl Window {
ffi::ClientMessage => {
use Closed;
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) };
@@ -350,10 +374,14 @@ impl Window {
}
},
- ffi::ResizeRequest => {
+ ffi::ConfigureNotify => {
use Resized;
- let rs_event: &ffi::XResizeRequestEvent = unsafe { mem::transmute(&xev) };
- events.push(Resized(rs_event.width as uint, rs_event.height as uint));
+ let cfg_event: &ffi::XConfigureEvent = unsafe { mem::transmute(&xev) };
+ let (current_width, current_height) = self.current_size.get();
+ if current_width != cfg_event.width || current_height != cfg_event.height {
+ self.current_size.set((cfg_event.width, cfg_event.height));
+ events.push(Resized(cfg_event.width as uint, cfg_event.height as uint));
+ }
},
ffi::MotionNotify => {
@@ -363,7 +391,10 @@ impl Window {
},
ffi::KeyPress | ffi::KeyRelease => {
- use {KeyboardInput, Pressed, Released, ReceivedCharacter, KeyModifiers};
+ use {KeyboardInput, Pressed, Released, ReceivedCharacter};
+ use {LEFT_CONTROL_MODIFIER, RIGHT_CONTROL_MODIFIER};
+ use {LEFT_SHIFT_MODIFIER, RIGHT_SHIFT_MODIFIER};
+ use {LEFT_ALT_MODIFIER, RIGHT_ALT_MODIFIER, CAPS_LOCK_MODIFIER};
let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&xev) };
if event.type_ == ffi::KeyPress {
@@ -394,16 +425,38 @@ impl Window {
ffi::XKeycodeToKeysym(self.display, event.keycode as ffi::KeyCode, 0)
};
+ let modifier_flag = match keysym as u32 {
+ ffi::XK_Shift_L => Some(LEFT_SHIFT_MODIFIER),
+ ffi::XK_Shift_R => Some(RIGHT_SHIFT_MODIFIER),
+ ffi::XK_Control_L => Some(LEFT_CONTROL_MODIFIER),
+ ffi::XK_Control_R => Some(RIGHT_CONTROL_MODIFIER),
+ ffi::XK_Caps_Lock => Some(CAPS_LOCK_MODIFIER),
+ ffi::XK_Meta_L => Some(LEFT_ALT_MODIFIER),
+ ffi::XK_Meta_R => Some(RIGHT_ALT_MODIFIER),
+ _ => None,
+ };
+ match modifier_flag {
+ Some(flag) => {
+ let mut current_modifiers = self.current_modifiers.get();
+ match state {
+ Pressed => current_modifiers.insert(flag),
+ Released => current_modifiers.remove(flag),
+ }
+ self.current_modifiers.set(current_modifiers);
+ }
+ None => {}
+ }
+
let vkey = events::keycode_to_element(keysym as libc::c_uint);
events.push(KeyboardInput(state, event.keycode as u8,
- vkey, KeyModifiers::empty()));
+ vkey, self.current_modifiers.get()));
//
},
ffi::ButtonPress | ffi::ButtonRelease => {
- use {MouseInput, Pressed, Released};
- use {LeftMouseButton, RightMouseButton, MiddleMouseButton, OtherMouseButton};
+ use {MouseInput, MouseWheel, Pressed, Released};
+ use {LeftMouseButton, RightMouseButton, MiddleMouseButton};
let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
let state = if xev.type_ == ffi::ButtonPress { Pressed } else { Released };
@@ -412,8 +465,14 @@ impl Window {
ffi::Button1 => Some(LeftMouseButton),
ffi::Button2 => Some(MiddleMouseButton),
ffi::Button3 => Some(RightMouseButton),
- ffi::Button4 => Some(OtherMouseButton(4)),
- ffi::Button5 => Some(OtherMouseButton(5)),
+ ffi::Button4 => {
+ events.push(MouseWheel(1));
+ None
+ }
+ ffi::Button5 => {
+ events.push(MouseWheel(-1));
+ None
+ }
_ => None
};
@@ -451,7 +510,7 @@ impl Window {
pub unsafe fn make_current(&self) {
let res = ffi::glx::MakeCurrent(self.display, self.window, self.context);
if res == 0 {
- fail!("glx::MakeCurrent failed");
+ panic!("glx::MakeCurrent failed");
}
}
@@ -469,6 +528,10 @@ impl Window {
pub fn swap_buffers(&self) {
unsafe { ffi::glx::SwapBuffers(self.display, self.window) }
}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ self.display as *mut libc::c_void
+ }
}
impl Drop for Window {