mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2025-02-05 06:56:34 +11:00
Handle scaling and window close
This commit is contained in:
parent
fa8101b885
commit
264a630c39
2 changed files with 152 additions and 26 deletions
|
@ -10,13 +10,13 @@
|
||||||
#define KEY_FUNCTION 0xFF
|
#define KEY_FUNCTION 0xFF
|
||||||
#define KEY_ESC 0x1B
|
#define KEY_ESC 0x1B
|
||||||
|
|
||||||
|
void mfb_close(void* window_info);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static int s_window_count = 0;
|
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_height;
|
|
||||||
static GC s_gc;
|
static GC s_gc;
|
||||||
static int s_depth;
|
static int s_depth;
|
||||||
static int s_setup_done = 0;
|
static int s_setup_done = 0;
|
||||||
|
@ -24,6 +24,7 @@ static Visual* s_visual;
|
||||||
static int s_screen_width;
|
static int s_screen_width;
|
||||||
static int s_screen_height;
|
static int s_screen_height;
|
||||||
static XContext s_context;
|
static XContext s_context;
|
||||||
|
static Atom s_wm_delete_window;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ typedef struct WindowInfo {
|
||||||
int scale;
|
int scale;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
int update;
|
||||||
} WindowInfo;
|
} WindowInfo;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -84,6 +86,9 @@ static int setup_display() {
|
||||||
s_screen_width = DisplayWidth(s_display, s_screen);
|
s_screen_width = DisplayWidth(s_display, s_screen);
|
||||||
s_screen_height = DisplayHeight(s_display, s_screen);
|
s_screen_height = DisplayHeight(s_display, s_screen);
|
||||||
|
|
||||||
|
const char* wmDeleteWindowName = "WM_DELETE_WINDOW";
|
||||||
|
XInternAtoms(s_display, (char**)&wmDeleteWindowName, 1, False, &s_wm_delete_window);
|
||||||
|
|
||||||
s_setup_done = 1;
|
s_setup_done = 1;
|
||||||
|
|
||||||
printf("setup done\n");
|
printf("setup done\n");
|
||||||
|
@ -105,6 +110,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
width *= scale;
|
||||||
|
height *= scale;
|
||||||
|
|
||||||
Window defaultRootWindow = DefaultRootWindow(s_display);
|
Window defaultRootWindow = DefaultRootWindow(s_display);
|
||||||
|
|
||||||
windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
|
windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
|
||||||
|
@ -154,6 +162,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
|
||||||
window_info->width = width;
|
window_info->width = width;
|
||||||
window_info->height = height;
|
window_info->height = height;
|
||||||
window_info->draw_buffer = malloc(width * height * 4);
|
window_info->draw_buffer = malloc(width * height * 4);
|
||||||
|
window_info->update = 1;
|
||||||
|
|
||||||
|
XSetWMProtocols(s_display, window, &s_wm_delete_window, 1);
|
||||||
|
|
||||||
XSaveContext(s_display, window, s_context, (XPointer) window_info);
|
XSaveContext(s_display, window, s_context, (XPointer) window_info);
|
||||||
|
|
||||||
|
@ -179,13 +190,22 @@ static WindowInfo* find_handle(Window handle)
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void process_event(XEvent* event) {
|
static int process_event(XEvent* event) {
|
||||||
KeySym sym;
|
KeySym sym;
|
||||||
|
|
||||||
WindowInfo* info = find_handle(event->xany.window);
|
WindowInfo* info = find_handle(event->xany.window);
|
||||||
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return 1;
|
||||||
|
|
||||||
|
if (event->type == ClientMessage) {
|
||||||
|
if ((Atom)event->xclient.data.l[0] == s_wm_delete_window) {
|
||||||
|
info->update = 0;
|
||||||
|
mfb_close(info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((event->type == KeyPress) || (event->type == KeyRelease) && info->key_callback) {
|
if ((event->type == KeyPress) || (event->type == KeyRelease) && info->key_callback) {
|
||||||
int sym = XLookupKeysym(&event->xkey, 0);
|
int sym = XLookupKeysym(&event->xkey, 0);
|
||||||
|
@ -196,6 +216,8 @@ static void process_event(XEvent* event) {
|
||||||
info->key_callback(info->rust_data, sym, 0);
|
info->key_callback(info->rust_data, sym, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -212,7 +234,10 @@ static int process_events()
|
||||||
{
|
{
|
||||||
XEvent event;
|
XEvent event;
|
||||||
XNextEvent(s_display, &event);
|
XNextEvent(s_display, &event);
|
||||||
process_event(&event);
|
|
||||||
|
// Don't process any more messages if event is 0
|
||||||
|
if (process_event(&event) == 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -220,16 +245,79 @@ static int process_events()
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void scale_2x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
||||||
|
int x, y;
|
||||||
|
for (y = 0; y < height; y += scale) {
|
||||||
|
for (x = 0; x < width; x += scale) {
|
||||||
|
const unsigned int t = *source++;
|
||||||
|
dest[0] = t;
|
||||||
|
dest[1] = t;
|
||||||
|
dest[width + 0] = t;
|
||||||
|
dest[width + 1] = t;
|
||||||
|
dest += scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest += width * (scale - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scale_4x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
||||||
|
int x, y;
|
||||||
|
for (y = 0; y < height; y += scale) {
|
||||||
|
for (x = 0; x < width; x += scale) {
|
||||||
|
const unsigned int t = *source++;
|
||||||
|
dest[(width * 0) + 0] = t;
|
||||||
|
dest[(width * 0) + 1] = t;
|
||||||
|
dest[(width * 0) + 2] = t;
|
||||||
|
dest[(width * 0) + 3] = t;
|
||||||
|
dest[(width * 1) + 0] = t;
|
||||||
|
dest[(width * 1) + 1] = t;
|
||||||
|
dest[(width * 1) + 2] = t;
|
||||||
|
dest[(width * 1) + 3] = t;
|
||||||
|
dest[(width * 2) + 0] = t;
|
||||||
|
dest[(width * 2) + 1] = t;
|
||||||
|
dest[(width * 2) + 2] = t;
|
||||||
|
dest[(width * 2) + 3] = t;
|
||||||
|
dest[(width * 3) + 0] = t;
|
||||||
|
dest[(width * 3) + 1] = t;
|
||||||
|
dest[(width * 3) + 2] = t;
|
||||||
|
dest[(width * 3) + 3] = t;
|
||||||
|
dest += scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest += width * (scale - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void mfb_update(void* window_info, void* buffer)
|
void mfb_update(void* window_info, void* buffer)
|
||||||
{
|
{
|
||||||
WindowInfo* info = (WindowInfo*)window_info;
|
WindowInfo* info = (WindowInfo*)window_info;
|
||||||
int width = info->width;
|
int width = info->width;
|
||||||
int height = info->height;
|
int height = info->height;
|
||||||
|
int scale = info->scale;
|
||||||
|
|
||||||
memcpy(info->draw_buffer, buffer, width * height * 4);
|
if (info->update) {
|
||||||
|
switch (scale) {
|
||||||
|
case 1: {
|
||||||
|
memcpy(info->draw_buffer, buffer, width * height * 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
scale_2x(info->draw_buffer, buffer, width, height, scale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
XPutImage(s_display, info->window, s_gc, info->ximage, 0, 0, 0, 0, width, height);
|
case 4: {
|
||||||
XFlush(s_display);
|
scale_4x(info->draw_buffer, buffer, width, height, scale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XPutImage(s_display, info->window, s_gc, info->ximage, 0, 0, 0, 0, width, height);
|
||||||
|
XFlush(s_display);
|
||||||
|
}
|
||||||
|
|
||||||
process_events();
|
process_events();
|
||||||
}
|
}
|
||||||
|
@ -240,18 +328,18 @@ void mfb_close(void* window_info)
|
||||||
{
|
{
|
||||||
WindowInfo* info = (WindowInfo*)window_info;
|
WindowInfo* info = (WindowInfo*)window_info;
|
||||||
|
|
||||||
|
if (!info->draw_buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XSaveContext(s_display, info->window, s_context, (XPointer)0);
|
||||||
|
|
||||||
|
free(info->draw_buffer);
|
||||||
|
|
||||||
info->ximage->data = NULL;
|
info->ximage->data = NULL;
|
||||||
|
info->draw_buffer = 0;
|
||||||
|
|
||||||
XDestroyImage(info->ximage);
|
XDestroyImage(info->ximage);
|
||||||
XDestroyWindow(s_display, info->window);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -263,3 +351,17 @@ void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(vo
|
||||||
win->rust_data = rust_data;
|
win->rust_data = rust_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int mfb_should_close(void* window) {
|
||||||
|
WindowInfo* win = (WindowInfo*)window;
|
||||||
|
return !!win->update;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
unsigned int mfb_get_screen_size() {
|
||||||
|
setup_display();
|
||||||
|
return (s_screen_width << 16) | s_screen_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ extern {
|
||||||
fn mfb_close(window: *mut c_void);
|
fn mfb_close(window: *mut c_void);
|
||||||
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
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_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_should_close(window: *mut c_void) -> i32;
|
||||||
//fn mfb_get_screen_size() -> u32;
|
fn mfb_get_screen_size() -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
@ -85,6 +85,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) {
|
||||||
XK_Left => (*win).key_handler.set_key_state(Key::Left, state),
|
XK_Left => (*win).key_handler.set_key_state(Key::Left, state),
|
||||||
XK_Right => (*win).key_handler.set_key_state(Key::Right, state),
|
XK_Right => (*win).key_handler.set_key_state(Key::Right, state),
|
||||||
XK_Up => (*win).key_handler.set_key_state(Key::Up, state),
|
XK_Up => (*win).key_handler.set_key_state(Key::Up, state),
|
||||||
|
XK_Escape => (*win).key_handler.set_key_state(Key::Escape, state),
|
||||||
XK_apostrophe => (*win).key_handler.set_key_state(Key::Apostrophe, state),
|
XK_apostrophe => (*win).key_handler.set_key_state(Key::Apostrophe, state),
|
||||||
XK_grave => (*win).key_handler.set_key_state(Key::Backquote, state),
|
XK_grave => (*win).key_handler.set_key_state(Key::Backquote, state),
|
||||||
XK_backslash => (*win).key_handler.set_key_state(Key::Backslash, state),
|
XK_backslash => (*win).key_handler.set_key_state(Key::Backslash, state),
|
||||||
|
@ -100,7 +101,6 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) {
|
||||||
XK_Delete => (*win).key_handler.set_key_state(Key::Delete, state),
|
XK_Delete => (*win).key_handler.set_key_state(Key::Delete, state),
|
||||||
XK_End => (*win).key_handler.set_key_state(Key::End, state),
|
XK_End => (*win).key_handler.set_key_state(Key::End, state),
|
||||||
XK_Return => (*win).key_handler.set_key_state(Key::Enter, state),
|
XK_Return => (*win).key_handler.set_key_state(Key::Enter, state),
|
||||||
XK_Escape => (*win).key_handler.set_key_state(Key::Escape, state),
|
|
||||||
XK_Home => (*win).key_handler.set_key_state(Key::Home, state),
|
XK_Home => (*win).key_handler.set_key_state(Key::Home, state),
|
||||||
XK_Insert => (*win).key_handler.set_key_state(Key::Insert, state),
|
XK_Insert => (*win).key_handler.set_key_state(Key::Insert, state),
|
||||||
XK_Menu => (*win).key_handler.set_key_state(Key::Menu, state),
|
XK_Menu => (*win).key_handler.set_key_state(Key::Menu, state),
|
||||||
|
@ -203,20 +203,44 @@ impl Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
true
|
unsafe { mfb_should_close(self.window_handle) == 1 }
|
||||||
//unsafe { mfb_should_close(self.window_handle) == 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_scale_factor(_: usize, _: usize, scale: Scale) -> i32 {
|
unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 {
|
||||||
let factor: i32 = match scale {
|
let factor: i32 = match scale {
|
||||||
Scale::X1 => 1,
|
Scale::X1 => 1,
|
||||||
Scale::X2 => 2,
|
Scale::X2 => 2,
|
||||||
Scale::X4 => 4,
|
Scale::X4 => 4,
|
||||||
Scale::X8 => 8,
|
|
||||||
Scale::X16 => 16,
|
|
||||||
Scale::X32 => 32,
|
|
||||||
Scale::FitScreen => {
|
Scale::FitScreen => {
|
||||||
1
|
let wh: u32 = mfb_get_screen_size();
|
||||||
|
let screen_x = (wh >> 16) as i32;
|
||||||
|
let screen_y = (wh & 0xffff) as i32;
|
||||||
|
|
||||||
|
println!("{} - {}", screen_x, screen_y);
|
||||||
|
|
||||||
|
let mut scale = 1i32;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let w = width as i32 * (scale + 1);
|
||||||
|
let h = height as i32 * (scale + 1);
|
||||||
|
|
||||||
|
if w > screen_x || h > screen_y {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if scale >= 4 {
|
||||||
|
4
|
||||||
|
} else {
|
||||||
|
scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
println!("Scale above 4 not support currently, defaults to 4");
|
||||||
|
4
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue