mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2025-01-11 03:21:32 +11:00
WIP on X11 version
This commit is contained in:
parent
424e913521
commit
9c07aaae60
|
@ -167,6 +167,8 @@ mod key_handler;
|
|||
use self::os::macos as imp;
|
||||
#[cfg(target_os = "windows")]
|
||||
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:
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include <X11/Xresource.h>
|
||||
#include <X11/Xlib.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 int s_screen;
|
||||
static int s_width;
|
||||
static int s_height;
|
||||
static Window s_window;
|
||||
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;
|
||||
XPixmapFormatValues* formats;
|
||||
XSetWindowAttributes windowAttributes;
|
||||
XSizeHints sizeHints;
|
||||
Visual* visual;
|
||||
|
||||
if (s_setup_done) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
s_display = XOpenDisplay(0);
|
||||
|
||||
if (!s_display)
|
||||
return -1;
|
||||
|
||||
if (!s_display) {
|
||||
printf("Unable to open X11 display\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_context = XUniqueContext();
|
||||
s_screen = DefaultScreen(s_display);
|
||||
visual = DefaultVisual(s_display, s_screen);
|
||||
s_visual = DefaultVisual(s_display, s_screen);
|
||||
formats = XListPixmapFormats(s_display, &formatCount);
|
||||
depth = DefaultDepth(s_display, s_screen);
|
||||
Window defaultRootWindow = DefaultRootWindow(s_display);
|
||||
|
||||
for (i = 0; i < formatCount; ++i)
|
||||
{
|
||||
if (depth == formats[i].depth)
|
||||
{
|
||||
for (i = 0; i < formatCount; ++i) {
|
||||
if (depth == formats[i].depth) {
|
||||
convDepth = formats[i].bits_per_pixel;
|
||||
break;
|
||||
}
|
||||
|
@ -49,28 +69,57 @@ int mfb_open(const char* title, int width, int height)
|
|||
XFree(formats);
|
||||
|
||||
// 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);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int screenWidth = DisplayWidth(s_display, s_screen);
|
||||
int screenHeight = DisplayHeight(s_display, s_screen);
|
||||
s_depth = depth;
|
||||
|
||||
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.background_pixel = BlackPixel(s_display, s_screen);
|
||||
windowAttributes.backing_store = NotUseful;
|
||||
|
||||
s_window = XCreateWindow(s_display, defaultRootWindow, (screenWidth - width) / 2,
|
||||
(screenHeight - height) / 2, width, height, 0, depth, InputOutput,
|
||||
visual, CWBackPixel | CWBorderPixel | CWBackingStore,
|
||||
window = XCreateWindow(s_display, defaultRootWindow, (s_screen_width - width) / 2,
|
||||
(s_screen_height - height) / 2, width, height, 0, s_depth, InputOutput,
|
||||
s_visual, CWBackPixel | CWBorderPixel | CWBackingStore,
|
||||
&windowAttributes);
|
||||
if (!s_window)
|
||||
if (!window) {
|
||||
printf("Unable to create X11 Window\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
|
||||
XStoreName(s_display, s_window, title);
|
||||
//XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
|
||||
XStoreName(s_display, window, title);
|
||||
|
||||
sizeHints.flags = PPosition | PMinSize | PMaxSize;
|
||||
sizeHints.x = 0;
|
||||
|
@ -80,68 +129,104 @@ int mfb_open(const char* title, int width, int height)
|
|||
sizeHints.min_height = height;
|
||||
sizeHints.max_height = height;
|
||||
|
||||
XSetWMNormalHints(s_display, s_window, &sizeHints);
|
||||
XClearWindow(s_display, s_window);
|
||||
XMapRaised(s_display, s_window);
|
||||
XSetWMNormalHints(s_display, window, &sizeHints);
|
||||
XClearWindow(s_display, window);
|
||||
XMapRaised(s_display, window);
|
||||
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;
|
||||
s_height = height;
|
||||
window_info = (WindowInfo*)malloc(sizeof(WindowInfo));
|
||||
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;
|
||||
KeySym sym;
|
||||
|
||||
if (!XPending(s_display))
|
||||
return;
|
||||
|
||||
XNextEvent(s_display, &event);
|
||||
|
||||
if (event.type != KeyPress)
|
||||
return 0;
|
||||
|
||||
sym = XLookupKeysym(&event.xkey, 0);
|
||||
|
||||
if ((sym >> 8) != KEY_FUNCTION)
|
||||
return 0;
|
||||
|
||||
if ((sym & 0xFF) == KEY_ESC)
|
||||
return -1;
|
||||
count = XPending(s_display);
|
||||
while (count--)
|
||||
{
|
||||
XEvent event;
|
||||
XNextEvent(s_display, &event);
|
||||
process_event(&event);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (processEvents() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
process_events();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mfb_close (void)
|
||||
void mfb_close(void* window_info)
|
||||
{
|
||||
s_ximage->data = NULL;
|
||||
XDestroyImage(s_ximage);
|
||||
XDestroyWindow(s_display, s_window);
|
||||
XCloseDisplay(s_display);
|
||||
WindowInfo* info = (WindowInfo*)window_info;
|
||||
|
||||
info->ximage->data = NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,3 +2,5 @@
|
|||
pub mod macos;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
#[cfg(unix)]
|
||||
pub mod unix;
|
||||
|
|
119
src/os/unix/mod.rs
Normal file
119
src/os/unix/mod.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue