WIP on X11 version

This commit is contained in:
Daniel Collin 2016-01-03 11:25:05 +01:00
parent 424e913521
commit 9c07aaae60
4 changed files with 271 additions and 63 deletions

View file

@ -167,6 +167,8 @@ mod key_handler;
use self::os::macos as imp; use self::os::macos as imp;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::os::windows as imp; use self::os::windows as imp;
#[cfg(unix)]
use self::os::unix as imp;
/// ///
/// Window used for displaying a 32-bit RGB buffer. Here is a small example on how to use it: /// Window used for displaying a 32-bit RGB buffer. Here is a small example on how to use it:

View file

@ -1,5 +1,9 @@
#include <X11/Xresource.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -8,39 +12,55 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int s_window_count = 0;
static Display* s_display; static Display* s_display;
static int s_screen; static int s_screen;
static int s_width; static int s_width;
static int s_height; static int s_height;
static Window s_window;
static GC s_gc; static GC s_gc;
static XImage *s_ximage; static int s_depth;
static int s_setup_done = 0;
static Visual* s_visual;
static int s_screen_width;
static int s_screen_height;
static XContext s_context;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mfb_open(const char* title, int width, int height) typedef struct WindowInfo {
{ Window window;
XImage* ximage;
void* draw_buffer;
int scale;
int width;
int height;
} WindowInfo;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int setup_display() {
int depth, i, formatCount, convDepth = -1; int depth, i, formatCount, convDepth = -1;
XPixmapFormatValues* formats; XPixmapFormatValues* formats;
XSetWindowAttributes windowAttributes;
XSizeHints sizeHints; if (s_setup_done) {
Visual* visual; return 1;
}
s_display = XOpenDisplay(0); s_display = XOpenDisplay(0);
if (!s_display) if (!s_display) {
return -1; printf("Unable to open X11 display\n");
return 0;
}
s_context = XUniqueContext();
s_screen = DefaultScreen(s_display); s_screen = DefaultScreen(s_display);
visual = DefaultVisual(s_display, s_screen); s_visual = DefaultVisual(s_display, s_screen);
formats = XListPixmapFormats(s_display, &formatCount); formats = XListPixmapFormats(s_display, &formatCount);
depth = DefaultDepth(s_display, s_screen); depth = DefaultDepth(s_display, s_screen);
Window defaultRootWindow = DefaultRootWindow(s_display);
for (i = 0; i < formatCount; ++i) for (i = 0; i < formatCount; ++i) {
{ if (depth == formats[i].depth) {
if (depth == formats[i].depth)
{
convDepth = formats[i].bits_per_pixel; convDepth = formats[i].bits_per_pixel;
break; break;
} }
@ -49,28 +69,57 @@ int mfb_open(const char* title, int width, int height)
XFree(formats); XFree(formats);
// We only support 32-bit right now // We only support 32-bit right now
if (convDepth != 32) if (convDepth != 32) {
{ printf("Unable to find 32-bit format for X11 display\n");
XCloseDisplay(s_display); XCloseDisplay(s_display);
return -1; return 0;
} }
int screenWidth = DisplayWidth(s_display, s_screen); s_depth = depth;
int screenHeight = DisplayHeight(s_display, s_screen);
s_gc = DefaultGC(s_display, s_screen);
s_screen_width = DisplayWidth(s_display, s_screen);
s_screen_height = DisplayHeight(s_display, s_screen);
s_setup_done = 1;
printf("setup done\n");
return 1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void* mfb_open(const char* title, int width, int height, int scale)
{
XSetWindowAttributes windowAttributes;
XSizeHints sizeHints;
XImage* image;
Window window;
WindowInfo* window_info;
if (!setup_display()) {
return 0;
}
Window defaultRootWindow = DefaultRootWindow(s_display);
windowAttributes.border_pixel = BlackPixel(s_display, s_screen); windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
windowAttributes.background_pixel = BlackPixel(s_display, s_screen); windowAttributes.background_pixel = BlackPixel(s_display, s_screen);
windowAttributes.backing_store = NotUseful; windowAttributes.backing_store = NotUseful;
s_window = XCreateWindow(s_display, defaultRootWindow, (screenWidth - width) / 2, window = XCreateWindow(s_display, defaultRootWindow, (s_screen_width - width) / 2,
(screenHeight - height) / 2, width, height, 0, depth, InputOutput, (s_screen_height - height) / 2, width, height, 0, s_depth, InputOutput,
visual, CWBackPixel | CWBorderPixel | CWBackingStore, s_visual, CWBackPixel | CWBorderPixel | CWBackingStore,
&windowAttributes); &windowAttributes);
if (!s_window) if (!window) {
printf("Unable to create X11 Window\n");
return 0; return 0;
}
XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask); //XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
XStoreName(s_display, s_window, title); XStoreName(s_display, window, title);
sizeHints.flags = PPosition | PMinSize | PMaxSize; sizeHints.flags = PPosition | PMinSize | PMaxSize;
sizeHints.x = 0; sizeHints.x = 0;
@ -80,68 +129,104 @@ int mfb_open(const char* title, int width, int height)
sizeHints.min_height = height; sizeHints.min_height = height;
sizeHints.max_height = height; sizeHints.max_height = height;
XSetWMNormalHints(s_display, s_window, &sizeHints); XSetWMNormalHints(s_display, window, &sizeHints);
XClearWindow(s_display, s_window); XClearWindow(s_display, window);
XMapRaised(s_display, s_window); XMapRaised(s_display, window);
XFlush(s_display); XFlush(s_display);
s_gc = DefaultGC(s_display, s_screen); image = XCreateImage(s_display, CopyFromParent, s_depth, ZPixmap, 0, NULL, width, height, 32, width * 4);
s_ximage = XCreateImage(s_display, CopyFromParent, depth, ZPixmap, 0, NULL, width, height, 32, width * 4); if (!image) {
XDestroyWindow(s_display, window);
printf("Unable to create XImage\n");
return 0;
}
s_width = width; window_info = (WindowInfo*)malloc(sizeof(WindowInfo));
s_height = height; window_info->window = window;
window_info->ximage = image;
window_info->scale = scale;
window_info->width = width;
window_info->height = height;
window_info->draw_buffer = malloc(width * height * 4);
return 1; XSaveContext(s_display, window, s_context, (XPointer) window_info);
image->data = (char*)window_info->draw_buffer;
s_window_count += 1;
return (void*)window_info;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int processEvents() static void process_event(XEvent* event) {
KeySym sym;
if (event->type != KeyPress)
return;
sym = XLookupKeysym(&event->xkey, 0);
if ((sym >> 8) != KEY_FUNCTION)
return;
if ((sym & 0xFF) == KEY_ESC)
return;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int process_events()
{ {
int count;
XEvent event; XEvent event;
KeySym sym; KeySym sym;
if (!XPending(s_display)) count = XPending(s_display);
return; while (count--)
{
XNextEvent(s_display, &event); XEvent event;
XNextEvent(s_display, &event);
if (event.type != KeyPress) process_event(&event);
return 0; }
sym = XLookupKeysym(&event.xkey, 0);
if ((sym >> 8) != KEY_FUNCTION)
return 0;
if ((sym & 0xFF) == KEY_ESC)
return -1;
return 0; return 0;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mfb_update(void* buffer) void mfb_update(void* window_info, void* buffer)
{ {
s_ximage->data = (char*)buffer; WindowInfo* info = (WindowInfo*)window_info;
int width = info->width;
int height = info->height;
XPutImage(s_display, s_window, s_gc, s_ximage, 0, 0, 0, 0, s_width, s_height); memcpy(info->draw_buffer, buffer, width * height * 4);
XPutImage(s_display, info->window, s_gc, info->ximage, 0, 0, 0, 0, width, height);
XFlush(s_display); XFlush(s_display);
if (processEvents() < 0) process_events();
return -1;
return 0;
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void mfb_close (void) void mfb_close(void* window_info)
{ {
s_ximage->data = NULL; WindowInfo* info = (WindowInfo*)window_info;
XDestroyImage(s_ximage);
XDestroyWindow(s_display, s_window); info->ximage->data = NULL;
XCloseDisplay(s_display);
XDestroyImage(info->ximage);
XDestroyWindow(s_display, info->window);
s_window_count--;
// Only close display when there are no windows left
if (s_window_count == 0) {
XCloseDisplay(s_display);
}
} }

View file

@ -2,3 +2,5 @@
pub mod macos; pub mod macos;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub mod windows; pub mod windows;
#[cfg(unix)]
pub mod unix;

119
src/os/unix/mod.rs Normal file
View file

@ -0,0 +1,119 @@
#![cfg(unix)]
use {Scale, Key, KeyRepeat};
use key_handler::KeyHandler;
use libc::{c_void, c_char, c_uchar};
use std::ffi::{CString};
use std::ptr;
//use std::mem;
#[link(name = "X11")]
extern {
fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void;
fn mfb_close(window: *mut c_void);
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
//fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
//fn mfb_should_close(window: *mut c_void) -> i32;
//fn mfb_get_screen_size() -> u32;
}
pub struct Window {
window_handle: *mut c_void,
key_handler: KeyHandler,
}
impl Window {
pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result<Window, &str> {
let n = match CString::new(name) {
Err(_) => {
println!("Unable to convert {} to c_string", name);
return Err("Unable to set correct name");
}
Ok(n) => n,
};
unsafe {
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, Self::get_scale_factor(width, height, scale));
if handle == ptr::null_mut() {
return Err("Unable to open Window");
}
Ok(Window {
window_handle: handle,
key_handler: KeyHandler::new(),
})
}
}
pub fn update(&mut self, buffer: &[u32]) {
self.key_handler.update();
unsafe {
mfb_update(self.window_handle, buffer.as_ptr() as *const u8);
//mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
}
}
#[inline]
pub fn get_keys(&self) -> Option<Vec<Key>> {
self.key_handler.get_keys()
}
#[inline]
pub fn get_keys_pressed(&self, repeat: KeyRepeat) -> Option<Vec<Key>> {
self.key_handler.get_keys_pressed(repeat)
}
#[inline]
pub fn is_key_down(&self, key: Key) -> bool {
self.key_handler.is_key_down(key)
}
#[inline]
pub fn set_key_repeat_delay(&mut self, delay: f32) {
self.key_handler.set_key_repeat_delay(delay)
}
#[inline]
pub fn set_key_repeat_rate(&mut self, rate: f32) {
self.key_handler.set_key_repeat_rate(rate)
}
#[inline]
pub fn is_key_pressed(&self, key: Key, repeat: KeyRepeat) -> bool {
self.key_handler.is_key_pressed(key, repeat)
}
#[inline]
pub fn is_open(&self) -> bool {
true
//unsafe { mfb_should_close(self.window_handle) == 0 }
}
unsafe fn get_scale_factor(_: usize, _: usize, scale: Scale) -> i32 {
let factor: i32 = match scale {
Scale::X1 => 1,
Scale::X2 => 2,
Scale::X4 => 4,
Scale::X8 => 8,
Scale::X16 => 16,
Scale::X32 => 32,
Scale::FitScreen => {
1
}
};
return factor;
}
}
impl Drop for Window {
fn drop(&mut self) {
unsafe {
mfb_close(self.window_handle);
}
}
}