mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2025-01-11 11:31: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;
|
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:
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
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