Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement precise mouse wheel handling and pinch-to-zoom on Mac. #19

Merged
merged 1 commit into from Jun 11, 2013
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

38 glut.rs
@@ -64,6 +64,11 @@ pub static MOUSE_UP: c_int = 1;
static WINDOW_WIDTH: GLenum = 102;
static WINDOW_HEIGHT: GLenum = 103;

#[cfg(target_os="linux")]
pub static HAVE_PRECISE_MOUSE_WHEEL: bool = false;
#[cfg(target_os="macos")]
pub static HAVE_PRECISE_MOUSE_WHEEL: bool = true;

pub enum State {
WindowWidth,
WindowHeight
@@ -252,6 +257,39 @@ pub fn reshape_func(_window: Window, callback: @fn(x: c_int, y: c_int)) {
}
}

// Mouse wheel handling.
//
// This is not part of the standard, but it's supported by freeglut and our Mac hack.
pub fn mouse_wheel_callback_tls_key(_callback: @@fn(wheel: c_int,
direction: c_int,
x: c_int,
y: c_int)) {
// Empty.
}

#[cfg(target_os="linux")]
pub extern fn mouse_wheel_callback(wheel: c_int, direction: c_int, x: c_int, y: c_int) {
unsafe {
let callback = local_data_get(wheel_callback_tls_key).get();
(*callback)(wheel, direction, x, y)
}
}

#[cfg(target_os="linux")]
pub fn mouse_wheel_func(callback: @fn(wheel: c_int, direction: c_int, x: c_int, y: c_int)) {
unsafe {
local_data_set(wheel_callback_tls_key, @callback);
glutMouseWheelFunc(mouse_wheel_callback);
}
}

#[cfg(target_os="macos")]
pub fn mouse_wheel_func(callback: @fn(wheel: c_int, direction: c_int, x: c_int, y: c_int)) {
unsafe {
local_data_set(mouse_wheel_callback_tls_key, @callback);
}
}

#[cfg(target_os="macos")]
pub fn check_loop() {
unsafe {
@@ -1,36 +1,99 @@
extern mod cocoa;

use glut::mouse_callback_tls_key;
use glut::{mouse_callback_tls_key, mouse_wheel_callback_tls_key};

use core::cast::transmute;
use core::libc::{c_int, c_void};
use core::local_data::local_data_get;
use machack::cocoa::base::{SEL, class_addMethod, id, msg_send_double, objc_getClass};
use core::ptr::null;
use machack::cocoa::base::{SEL, class_addMethod, id, msg_send_double, msg_send_id, objc_getClass};
use machack::cocoa::base::{sel_registerName};

#[link_args="-framework Carbon"]
extern {
// Carbon API.
#[fast_ffi]
fn GetEventKind(eventRef: *c_void) -> u32;
}

// From CarbonEvents.h.
static kEventMouseScroll: u32 = 11;

extern fn scrollWheelImpl(this: id, _cmd: SEL, event: id) {
unsafe {
let sel_deltaY = sel_registerName(transmute(&"deltaY"[0]));
let delta_y = msg_send_double(event, sel_deltaY);
// Get the underlying Carbon event to figure out if deviceDelta{Y,X} are available.
let sel__eventRef = sel_registerName(transmute(&"_eventRef"[0]));
let eventRef: *c_void = transmute(msg_send_id(event, sel__eventRef));
let is_scroll = eventRef != null() && GetEventKind(eventRef) == kEventMouseScroll;

// Use precise scrolling if available; otherwise, use coarse-grained scrolling.
let (delta_x, delta_y) = if is_scroll {
let sel_deviceDeltaY = sel_registerName(transmute(&"deviceDeltaY"[0]));
let delta_y = msg_send_double(event, sel_deviceDeltaY);
let sel_deviceDeltaX = sel_registerName(transmute(&"deviceDeltaX"[0]));
let delta_x = msg_send_double(event, sel_deviceDeltaX);
(delta_x, delta_y)
} else {
let sel_deltaY = sel_registerName(transmute(&"deltaY"[0]));
let delta_y = msg_send_double(event, sel_deltaY);
let sel_deltaX = sel_registerName(transmute(&"deltaX"[0]));
let delta_x = msg_send_double(event, sel_deltaX);
(delta_x * 30.0, delta_y * 30.0)
};

// First, try the wheel func.
match local_data_get(mouse_wheel_callback_tls_key) {
None => {} // Continue.
Some(callback) => {
(*callback)(0, (delta_y * 10000.0) as c_int, 0, 0);
(*callback)(1, (delta_x * 10000.0) as c_int, 0, 0);
return
}
}

// Fall through to the mouse func.
let button = if delta_y == 0.0 {
return
} else if delta_y > 0.0 {
3
} else {
4
};
let callback = local_data_get(mouse_callback_tls_key).get();
(*callback)(button, 1, 0, 0);

match local_data_get(mouse_callback_tls_key) {
None => {} // Ignore.
Some(callback) => (*callback)(button, 1, 0, 0),
}
}
}

extern fn magnifyWithEvent(this: id, _cmd: SEL, event: id) {
unsafe {
let sel_magnification = sel_registerName(transmute(&"magnification"[0]));
let magnification = msg_send_double(event, sel_magnification) + 1.0;

match local_data_get(mouse_wheel_callback_tls_key) {
None => {}
Some(callback) => (*callback)(2, (magnification * 10000.0) as c_int, 0, 0),
}
}
}

pub fn perform_scroll_wheel_hack() {
unsafe {
let sel_scrollWheel = sel_registerName(transmute(&"scrollWheel:"[0]));
let class_GLUTView = objc_getClass(transmute(&"GLUTView"[0]));

let sel_scrollWheel = sel_registerName(transmute(&"scrollWheel:"[0]));
class_addMethod(class_GLUTView,
sel_scrollWheel,
transmute(scrollWheelImpl),
transmute(&"v@:@"[0]));

let sel_magnifyWithEvent = sel_registerName(transmute(&"magnifyWithEvent:"[0]));
class_addMethod(class_GLUTView,
sel_magnifyWithEvent,
transmute(magnifyWithEvent),
transmute(&"v@:@"[0]));
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.