diff options
Diffstat (limited to 'src/x11/window/mod.rs')
-rw-r--r-- | src/x11/window/mod.rs | 109 |
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 { |