aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/x11/window.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/x11/window.rs')
-rw-r--r--src/api/x11/window.rs103
1 files changed, 74 insertions, 29 deletions
diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs
index 42134d0..15e27ce 100644
--- a/src/api/x11/window.rs
+++ b/src/api/x11/window.rs
@@ -9,6 +9,7 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use Api;
+use ContextError;
use CursorState;
use GlContext;
use GlRequest;
@@ -43,6 +44,7 @@ pub struct XWindow {
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
ic: ffi::XIC,
im: ffi::XIM,
+ colormap: ffi::Colormap,
}
pub enum Context {
@@ -64,6 +66,8 @@ impl Drop for XWindow {
// is still the current one
self.context = Context::None;
+ let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
+
if self.is_fullscreen {
(self.display.xf86vmode.XF86VidModeSwitchToMode)(self.display.display, self.screen_id, self.xf86_desk_mode);
(self.display.xf86vmode.XF86VidModeSetViewPort)(self.display.display, self.screen_id, 0, 0);
@@ -72,6 +76,7 @@ impl Drop for XWindow {
(self.display.xlib.XDestroyIC)(self.ic);
(self.display.xlib.XCloseIM)(self.im);
(self.display.xlib.XDestroyWindow)(self.display.display, self.window);
+ (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
}
}
}
@@ -215,6 +220,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
use events::Event::{MouseInput, MouseWheel};
use events::ElementState::{Pressed, Released};
use events::MouseButton::{Left, Right, Middle};
+ use events::MouseScrollDelta::{LineDelta};
let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
@@ -225,11 +231,13 @@ impl<'a> Iterator for PollEventsIterator<'a> {
ffi::Button2 => Some(Middle),
ffi::Button3 => Some(Right),
ffi::Button4 => {
- self.window.pending_events.lock().unwrap().push_back(MouseWheel(0.0, 1.0));
+ let delta = LineDelta(0.0, 1.0);
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta));
None
}
ffi::Button5 => {
- self.window.pending_events.lock().unwrap().push_back(MouseWheel(0.0, -1.0));
+ let delta = LineDelta(0.0, -1.0);
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta));
None
}
_ => None
@@ -256,9 +264,10 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
+ use std::sync::atomic::Ordering::Relaxed;
use std::mem;
- while !self.window.is_closed() {
+ while !self.window.is_closed.load(Relaxed) {
if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
return Some(ev);
}
@@ -335,34 +344,65 @@ impl Window {
if fb.is_null() {
return Err(OsError(format!("glx::ChooseFBConfig failed")));
}
- let preferred_fb = *fb; // TODO: choose more wisely
+
+ let preferred_fb = if builder.transparent {
+ let mut best_fbi_for_transparent = 0isize;
+
+ for i in 0isize..num_fb as isize {
+ let vi = display.glx.as_ref().unwrap().GetVisualFromFBConfig(display.display as *mut _, *fb.offset(i));
+ if (*vi).depth == 32 {
+ best_fbi_for_transparent = i;
+ break;
+ }
+ }
+
+ *fb.offset(best_fbi_for_transparent)
+ } else {
+ *fb // TODO: choose more wisely
+ };
+
(display.xlib.XFree)(fb as *mut _);
preferred_fb
};
- let mut best_mode = -1;
- let modes = unsafe {
+ // finding the mode to switch to if necessary
+ let (mode_to_switch_to, xf86_desk_mode) = unsafe {
let mut mode_num: libc::c_int = mem::uninitialized();
let mut modes: *mut *mut ffi::XF86VidModeModeInfo = mem::uninitialized();
if (display.xf86vmode.XF86VidModeGetAllModeLines)(display.display, screen_id, &mut mode_num, &mut modes) == 0 {
return Err(OsError(format!("Could not query the video modes")));
}
- for i in 0..mode_num {
- let mode: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _);
- if mode.hdisplay == dimensions.0 as u16 && mode.vdisplay == dimensions.1 as u16 {
- best_mode = i;
+ let xf86_desk_mode = *modes.offset(0);
+
+ // FIXME: `XF86VidModeModeInfo` is missing its `hskew` field. Therefore we point to
+ // `vsyncstart` instead of `vdisplay` as a temporary hack.
+
+ let mode_to_switch_to = if builder.monitor.is_some() {
+ let matching_mode = (0 .. mode_num).map(|i| {
+ let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
+ }).find(|m| m.hdisplay == dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16);
+
+ if let Some(matching_mode) = matching_mode {
+ Some(matching_mode)
+
+ } else {
+ let m = (0 .. mode_num).map(|i| {
+ let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
+ }).find(|m| m.hdisplay >= dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16);
+
+ match m {
+ Some(m) => Some(m),
+ None => return Err(OsError(format!("Could not find a suitable graphics mode")))
+ }
}
+ } else {
+ None
};
- if best_mode == -1 && builder.monitor.is_some() {
- return Err(OsError(format!("Could not find a suitable graphics mode")));
- }
- modes
- };
+ (display.xlib.XFree)(modes as *mut _);
- let xf86_desk_mode = unsafe {
- *modes.offset(0)
+ (mode_to_switch_to, xf86_desk_mode)
};
// getting the visual infos
@@ -421,15 +461,24 @@ impl Window {
ffi::KeyReleaseMask | ffi::ButtonPressMask |
ffi::ButtonReleaseMask | ffi::KeymapStateMask;
swa.border_pixel = 0;
+ if builder.transparent {
+ swa.background_pixel = 0;
+ }
swa.override_redirect = 0;
swa
};
- let mut window_attributes = ffi::CWBorderPixel | ffi::CWColormap | ffi:: CWEventMask;
- if builder.monitor.is_some() {
+ let mut window_attributes = ffi::CWBorderPixel | ffi::CWColormap | ffi::CWEventMask;
+
+ if builder.transparent {
+ window_attributes |= ffi::CWBackPixel;
+ }
+
+ // switching to fullscreen
+ if let Some(mut mode_to_switch_to) = mode_to_switch_to {
window_attributes |= ffi::CWOverrideRedirect;
unsafe {
- (display.xf86vmode.XF86VidModeSwitchToMode)(display.display, screen_id, *modes.offset(best_mode as isize));
+ (display.xf86vmode.XF86VidModeSwitchToMode)(display.display, screen_id, &mut mode_to_switch_to);
(display.xf86vmode.XF86VidModeSetViewPort)(display.display, screen_id, 0, 0);
set_win_attr.override_redirect = 1;
}
@@ -551,6 +600,7 @@ impl Window {
screen_id: screen_id,
is_fullscreen: is_fullscreen,
xf86_desk_mode: xf86_desk_mode,
+ colormap: cmap,
}),
is_closed: AtomicBool::new(false),
wm_delete_window: wm_delete_window,
@@ -564,11 +614,6 @@ impl Window {
Ok(window)
}
- pub fn is_closed(&self) -> bool {
- use std::sync::atomic::Ordering::Relaxed;
- self.is_closed.load(Relaxed)
- }
-
pub fn set_title(&self, title: &str) {
with_c_str(title, |title| unsafe {
(self.x.display.xlib.XStoreName)(self.x.display.display, self.x.window, title);
@@ -768,11 +813,11 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
match self.x.context {
Context::Glx(ref ctxt) => ctxt.make_current(),
Context::Egl(ref ctxt) => ctxt.make_current(),
- Context::None => {}
+ Context::None => Ok(())
}
}
@@ -792,11 +837,11 @@ impl GlContext for Window {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
match self.x.context {
Context::Glx(ref ctxt) => ctxt.swap_buffers(),
Context::Egl(ref ctxt) => ctxt.swap_buffers(),
- Context::None => {}
+ Context::None => Ok(())
}
}