Handle scaling and window close

This commit is contained in:
Daniel Collin 2016-01-03 15:11:18 +01:00
parent fa8101b885
commit 264a630c39
2 changed files with 152 additions and 26 deletions

View file

@ -10,13 +10,13 @@
#define KEY_FUNCTION 0xFF
#define KEY_ESC 0x1B
void mfb_close(void* window_info);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int s_window_count = 0;
static Display* s_display;
static int s_screen;
static int s_width;
static int s_height;
static GC s_gc;
static int s_depth;
static int s_setup_done = 0;
@ -24,6 +24,7 @@ static Visual* s_visual;
static int s_screen_width;
static int s_screen_height;
static XContext s_context;
static Atom s_wm_delete_window;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -36,6 +37,7 @@ typedef struct WindowInfo {
int scale;
int width;
int height;
int update;
} WindowInfo;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -84,6 +86,9 @@ static int setup_display() {
s_screen_width = DisplayWidth(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;
printf("setup done\n");
@ -105,6 +110,9 @@ void* mfb_open(const char* title, int width, int height, int scale)
return 0;
}
width *= scale;
height *= scale;
Window defaultRootWindow = DefaultRootWindow(s_display);
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->height = height;
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);
@ -179,13 +190,22 @@ static WindowInfo* find_handle(Window handle)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void process_event(XEvent* event) {
static int process_event(XEvent* event) {
KeySym sym;
WindowInfo* info = find_handle(event->xany.window);
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) {
int sym = XLookupKeysym(&event->xkey, 0);
@ -196,6 +216,8 @@ static void process_event(XEvent* event) {
info->key_callback(info->rust_data, sym, 0);
}
}
return 1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -212,7 +234,10 @@ static int process_events()
{
XEvent 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;
@ -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)
{
WindowInfo* info = (WindowInfo*)window_info;
int width = info->width;
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);
XFlush(s_display);
case 4: {
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();
}
@ -240,18 +328,18 @@ void mfb_close(void* 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->draw_buffer = 0;
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);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -263,3 +351,17 @@ void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(vo
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;
}

View file

@ -17,8 +17,8 @@ extern {
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;
fn mfb_should_close(window: *mut c_void) -> i32;
fn mfb_get_screen_size() -> u32;
}
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_Right => (*win).key_handler.set_key_state(Key::Right, 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_grave => (*win).key_handler.set_key_state(Key::Backquote, 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_End => (*win).key_handler.set_key_state(Key::End, 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_Insert => (*win).key_handler.set_key_state(Key::Insert, state),
XK_Menu => (*win).key_handler.set_key_state(Key::Menu, state),
@ -203,20 +203,44 @@ impl Window {
#[inline]
pub fn is_open(&self) -> bool {
true
//unsafe { mfb_should_close(self.window_handle) == 0 }
unsafe { mfb_should_close(self.window_handle) == 1 }
}
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 {
Scale::X1 => 1,
Scale::X2 => 2,
Scale::X4 => 4,
Scale::X8 => 8,
Scale::X16 => 16,
Scale::X32 => 32,
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
}
};