#include #include #include #include #include #include // I cannot find a way to get dpi under VirtualBox //#include //#include #include #include #include #include #include #include #include "WindowData.h" #include "WindowData_X11.h" #if defined(USE_OPENGL_API) #include #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void init_keycodes(SWindowData_X11 *window_data_x11); extern void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct mfb_window * mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) { int depth, i, formatCount, convDepth = -1; XPixmapFormatValues* formats; XSetWindowAttributes windowAttributes; XSizeHints sizeHints; Visual* visual; SWindowData *window_data = (SWindowData *) malloc(sizeof(SWindowData)); if (!window_data) { return 0x0; } memset(window_data, 0, sizeof(SWindowData)); SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) malloc(sizeof(SWindowData_X11)); if (!window_data_x11) { free(window_data); return 0x0; } memset(window_data_x11, 0, sizeof(SWindowData_X11)); window_data->specific = window_data_x11; window_data_x11->display = XOpenDisplay(0); if (!window_data_x11->display) { free(window_data); free(window_data_x11); return 0x0; } init_keycodes(window_data_x11); window_data_x11->screen = DefaultScreen(window_data_x11->display); visual = DefaultVisual(window_data_x11->display, window_data_x11->screen); formats = XListPixmapFormats(window_data_x11->display, &formatCount); depth = DefaultDepth(window_data_x11->display, window_data_x11->screen); Window defaultRootWindow = DefaultRootWindow(window_data_x11->display); for (i = 0; i < formatCount; ++i) { if (depth == formats[i].depth) { convDepth = formats[i].bits_per_pixel; break; } } XFree(formats); // We only support 32-bit right now if (convDepth != 32) { XCloseDisplay(window_data_x11->display); return 0x0; } int screenWidth = DisplayWidth(window_data_x11->display, window_data_x11->screen); int screenHeight = DisplayHeight(window_data_x11->display, window_data_x11->screen); windowAttributes.border_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen); windowAttributes.background_pixel = BlackPixel(window_data_x11->display, window_data_x11->screen); windowAttributes.backing_store = NotUseful; int posX, posY; int windowWidth, windowHeight; window_data->window_width = width; window_data->window_height = height; window_data->buffer_width = width; window_data->buffer_height = height; window_data->buffer_stride = width * 4; calc_dst_factor(window_data, width, height); if (flags & WF_FULLSCREEN_DESKTOP) { posX = 0; posY = 0; windowWidth = screenWidth; windowHeight = screenHeight; } else { posX = (screenWidth - width) / 2; posY = (screenHeight - height) / 2; windowWidth = width; windowHeight = height; } window_data_x11->window = XCreateWindow( window_data_x11->display, defaultRootWindow, posX, posY, windowWidth, windowHeight, 0, depth, InputOutput, visual, CWBackPixel | CWBorderPixel | CWBackingStore, &windowAttributes); if (!window_data_x11->window) return 0x0; XSelectInput(window_data_x11->display, window_data_x11->window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask ); XStoreName(window_data_x11->display, window_data_x11->window, title); if (flags & WF_BORDERLESS) { struct StyleHints { unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status; } sh = { .flags = 2, .functions = 0, .decorations = 0, .inputMode = 0, .status = 0, }; Atom sh_p = XInternAtom(window_data_x11->display, "_MOTIF_WM_HINTS", True); XChangeProperty(window_data_x11->display, window_data_x11->window, sh_p, sh_p, 32, PropModeReplace, (unsigned char*)&sh, 5); } if (flags & WF_ALWAYS_ON_TOP) { Atom sa_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_ABOVE", False); XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", False), XA_ATOM, 32, PropModeReplace, (unsigned char *)&sa_p, 1); } if (flags & WF_FULLSCREEN) { Atom sf_p = XInternAtom(window_data_x11->display, "_NET_WM_STATE_FULLSCREEN", True); XChangeProperty(window_data_x11->display, window_data_x11->window, XInternAtom(window_data_x11->display, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char*)&sf_p, 1); } sizeHints.flags = PPosition | PMinSize | PMaxSize; sizeHints.x = 0; sizeHints.y = 0; sizeHints.min_width = width; sizeHints.min_height = height; if (flags & WF_RESIZABLE) { sizeHints.max_width = screenWidth; sizeHints.max_height = screenHeight; } else { sizeHints.max_width = width; sizeHints.max_height = height; } #if defined(USE_OPENGL_API) if(create_GL_context(window_data) == false) { return 0x0; } #else window_data_x11->image = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, width, height, 32, width * 4); #endif XSetWMNormalHints(window_data_x11->display, window_data_x11->window, &sizeHints); XClearWindow(window_data_x11->display, window_data_x11->window); XMapRaised(window_data_x11->display, window_data_x11->window); XFlush(window_data_x11->display); window_data_x11->gc = DefaultGC(window_data_x11->display, window_data_x11->screen); window_data_x11->timer = mfb_timer_create(); mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); #if defined(_DEBUG) || defined(DEBUG) printf("Window created using X11 API\n"); #endif window_data->is_initialized = true; return (struct mfb_window *) window_data; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int translate_key(int scancode); int translate_mod(int state); int translate_mod_ex(int key, int state, int is_pressed); static void processEvent(SWindowData *window_data, XEvent *event) { switch (event->type) { case KeyPress: case KeyRelease: { mfb_key key_code = (mfb_key) translate_key(event->xkey.keycode); int is_pressed = (event->type == KeyPress); window_data->mod_keys = translate_mod_ex(key_code, event->xkey.state, is_pressed); window_data->key_status[key_code] = is_pressed; kCall(keyboard_func, key_code, (mfb_key_mod) window_data->mod_keys, is_pressed); } break; case ButtonPress: case ButtonRelease: { mfb_mouse_button button = (mfb_mouse_button) event->xbutton.button; int is_pressed = (event->type == ButtonPress); window_data->mod_keys = translate_mod(event->xkey.state); switch (button) { case Button1: case Button2: case Button3: kCall(mouse_btn_func, button, (mfb_key_mod) window_data->mod_keys, is_pressed); break; case Button4: kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, 1.0f); break; case Button5: kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 0.0f, -1.0f); break; case 6: kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, 1.0f, 0.0f); break; case 7: kCall(mouse_wheel_func, (mfb_key_mod) window_data->mod_keys, -1.0f, 0.0f); break; default: kCall(mouse_btn_func, (mfb_mouse_button) (button - 4), (mfb_key_mod) window_data->mod_keys, is_pressed); break; } } break; case MotionNotify: window_data->mouse_pos_x = event->xmotion.x; window_data->mouse_pos_y = event->xmotion.y; kCall(mouse_move_func, event->xmotion.x, event->xmotion.y); break; case ConfigureNotify: { window_data->window_width = event->xconfigure.width; window_data->window_height = event->xconfigure.height; resize_dst(window_data, event->xconfigure.width, event->xconfigure.height); #if defined(USE_OPENGL_API) resize_GL(window_data); #else SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; if(window_data_x11->image_scaler != 0x0) { window_data_x11->image_scaler->data = 0x0; XDestroyImage(window_data_x11->image_scaler); window_data_x11->image_scaler = 0x0; window_data_x11->image_scaler_width = 0; window_data_x11->image_scaler_height = 0; } XClearWindow(window_data_x11->display, window_data_x11->window); #endif kCall(resize_func, window_data->window_width, window_data->window_height); } break; case EnterNotify: case LeaveNotify: break; case FocusIn: window_data->is_active = true; kCall(active_func, true); break; case FocusOut: window_data->is_active = false; kCall(active_func, false); break; case DestroyNotify: window_data->close = true; return; break; } } static void processEvents(SWindowData *window_data) { XEvent event; SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; while ((window_data->close == false) && XPending(window_data_x11->display)) { XNextEvent(window_data_x11->display, &event); processEvent(window_data, &event); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void destroy_window_data(SWindowData *window_data); mfb_update_state mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned height) { if (window == 0x0) { return STATE_INVALID_WINDOW; } SWindowData *window_data = (SWindowData *) window; if (window_data->close) { destroy_window_data(window_data); return STATE_EXIT; } if (buffer == 0x0) { return STATE_INVALID_BUFFER; } #if !defined(USE_OPENGL_API) SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; bool different_size = false; #endif if(window_data->buffer_width != width || window_data->buffer_height != height) { window_data->buffer_width = width; window_data->buffer_stride = width * 4; window_data->buffer_height = height; #if !defined(USE_OPENGL_API) different_size = true; #endif } #if !defined(USE_OPENGL_API) if (different_size || window_data->buffer_width != window_data->dst_width || window_data->buffer_height != window_data->dst_height) { if (window_data_x11->image_scaler_width != window_data->dst_width || window_data_x11->image_scaler_height != window_data->dst_height) { if (window_data_x11->image_scaler != 0x0) { window_data_x11->image_scaler->data = 0x0; XDestroyImage(window_data_x11->image_scaler); } if (window_data_x11->image_buffer != 0x0) { free(window_data_x11->image_buffer); window_data_x11->image_buffer = 0x0; } int depth = DefaultDepth(window_data_x11->display, window_data_x11->screen); window_data_x11->image_buffer = malloc(window_data->dst_width * window_data->dst_height * 4); if(window_data_x11->image_buffer == 0x0) { return STATE_INTERNAL_ERROR; } window_data_x11->image_scaler_width = window_data->dst_width; window_data_x11->image_scaler_height = window_data->dst_height; window_data_x11->image_scaler = XCreateImage(window_data_x11->display, CopyFromParent, depth, ZPixmap, 0, 0x0, window_data_x11->image_scaler_width, window_data_x11->image_scaler_height, 32, window_data_x11->image_scaler_width * 4); } } if (window_data_x11->image_scaler != 0x0) { stretch_image((uint32_t *) buffer, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->buffer_width, (uint32_t *) window_data_x11->image_buffer, 0, 0, window_data->dst_width, window_data->dst_height, window_data->dst_width); window_data_x11->image_scaler->data = (char *) window_data_x11->image_buffer; XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image_scaler, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } else { window_data_x11->image->data = (char *) buffer; XPutImage(window_data_x11->display, window_data_x11->window, window_data_x11->gc, window_data_x11->image, 0, 0, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height); } XFlush(window_data_x11->display); #else redraw_GL(window_data, buffer); #endif processEvents(window_data); return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// mfb_update_state mfb_update_events(struct mfb_window *window) { if (window == 0x0) { return STATE_INVALID_WINDOW; } SWindowData *window_data = (SWindowData *) window; if (window_data->close) { destroy_window_data(window_data); return STATE_EXIT; } SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; XFlush(window_data_x11->display); processEvents(window_data); return STATE_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// extern double g_time_for_frame; bool mfb_wait_sync(struct mfb_window *window) { if (window == 0x0) { return STATE_INVALID_WINDOW; } SWindowData *window_data = (SWindowData *) window; if (window_data->close) { destroy_window_data(window_data); return false; } SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; XFlush(window_data_x11->display); XEvent event; double current; uint32_t millis = 1; while(1) { if(XEventsQueued(window_data_x11->display, QueuedAlready) > 0) { XNextEvent(window_data_x11->display, &event); processEvent(window_data, &event); } if(window_data->close) { destroy_window_data(window_data); return false; } current = mfb_timer_now(window_data_x11->timer); if (current >= g_time_for_frame) { mfb_timer_reset(window_data_x11->timer); return true; } else if(current >= g_time_for_frame * 0.8) { millis = 0; } usleep(millis * 1000); //sched_yield(); } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void destroy_window_data(SWindowData *window_data) { if (window_data != 0x0) { if (window_data->specific != 0x0) { SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; #if defined(USE_OPENGL_API) destroy_GL_context(window_data); #else if (window_data_x11->image != 0x0) { window_data_x11->image->data = 0x0; XDestroyImage(window_data_x11->image); XDestroyWindow(window_data_x11->display, window_data_x11->window); XCloseDisplay(window_data_x11->display); } #endif mfb_timer_destroy(window_data_x11->timer); memset(window_data_x11, 0, sizeof(SWindowData_X11)); free(window_data_x11); } memset(window_data, 0, sizeof(SWindowData)); free(window_data); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// extern short int g_keycodes[512]; static int translateKeyCodeB(int keySym) { switch (keySym) { case XK_KP_0: return KB_KEY_KP_0; case XK_KP_1: return KB_KEY_KP_1; case XK_KP_2: return KB_KEY_KP_2; case XK_KP_3: return KB_KEY_KP_3; case XK_KP_4: return KB_KEY_KP_4; case XK_KP_5: return KB_KEY_KP_5; case XK_KP_6: return KB_KEY_KP_6; case XK_KP_7: return KB_KEY_KP_7; case XK_KP_8: return KB_KEY_KP_8; case XK_KP_9: return KB_KEY_KP_9; case XK_KP_Separator: case XK_KP_Decimal: return KB_KEY_KP_DECIMAL; case XK_KP_Equal: return KB_KEY_KP_EQUAL; case XK_KP_Enter: return KB_KEY_KP_ENTER; } return KB_KEY_UNKNOWN; } static int translateKeyCodeA(int keySym) { switch (keySym) { case XK_Escape: return KB_KEY_ESCAPE; case XK_Tab: return KB_KEY_TAB; case XK_Shift_L: return KB_KEY_LEFT_SHIFT; case XK_Shift_R: return KB_KEY_RIGHT_SHIFT; case XK_Control_L: return KB_KEY_LEFT_CONTROL; case XK_Control_R: return KB_KEY_RIGHT_CONTROL; case XK_Meta_L: case XK_Alt_L: return KB_KEY_LEFT_ALT; case XK_Mode_switch: // Mapped to Alt_R on many keyboards case XK_ISO_Level3_Shift: // AltGr on at least some machines case XK_Meta_R: case XK_Alt_R: return KB_KEY_RIGHT_ALT; case XK_Super_L: return KB_KEY_LEFT_SUPER; case XK_Super_R: return KB_KEY_RIGHT_SUPER; case XK_Menu: return KB_KEY_MENU; case XK_Num_Lock: return KB_KEY_NUM_LOCK; case XK_Caps_Lock: return KB_KEY_CAPS_LOCK; case XK_Print: return KB_KEY_PRINT_SCREEN; case XK_Scroll_Lock: return KB_KEY_SCROLL_LOCK; case XK_Pause: return KB_KEY_PAUSE; case XK_Delete: return KB_KEY_DELETE; case XK_BackSpace: return KB_KEY_BACKSPACE; case XK_Return: return KB_KEY_ENTER; case XK_Home: return KB_KEY_HOME; case XK_End: return KB_KEY_END; case XK_Page_Up: return KB_KEY_PAGE_UP; case XK_Page_Down: return KB_KEY_PAGE_DOWN; case XK_Insert: return KB_KEY_INSERT; case XK_Left: return KB_KEY_LEFT; case XK_Right: return KB_KEY_RIGHT; case XK_Down: return KB_KEY_DOWN; case XK_Up: return KB_KEY_UP; case XK_F1: return KB_KEY_F1; case XK_F2: return KB_KEY_F2; case XK_F3: return KB_KEY_F3; case XK_F4: return KB_KEY_F4; case XK_F5: return KB_KEY_F5; case XK_F6: return KB_KEY_F6; case XK_F7: return KB_KEY_F7; case XK_F8: return KB_KEY_F8; case XK_F9: return KB_KEY_F9; case XK_F10: return KB_KEY_F10; case XK_F11: return KB_KEY_F11; case XK_F12: return KB_KEY_F12; case XK_F13: return KB_KEY_F13; case XK_F14: return KB_KEY_F14; case XK_F15: return KB_KEY_F15; case XK_F16: return KB_KEY_F16; case XK_F17: return KB_KEY_F17; case XK_F18: return KB_KEY_F18; case XK_F19: return KB_KEY_F19; case XK_F20: return KB_KEY_F20; case XK_F21: return KB_KEY_F21; case XK_F22: return KB_KEY_F22; case XK_F23: return KB_KEY_F23; case XK_F24: return KB_KEY_F24; case XK_F25: return KB_KEY_F25; // Numeric keypad case XK_KP_Divide: return KB_KEY_KP_DIVIDE; case XK_KP_Multiply: return KB_KEY_KP_MULTIPLY; case XK_KP_Subtract: return KB_KEY_KP_SUBTRACT; case XK_KP_Add: return KB_KEY_KP_ADD; // These should have been detected in secondary keysym test above! case XK_KP_Insert: return KB_KEY_KP_0; case XK_KP_End: return KB_KEY_KP_1; case XK_KP_Down: return KB_KEY_KP_2; case XK_KP_Page_Down: return KB_KEY_KP_3; case XK_KP_Left: return KB_KEY_KP_4; case XK_KP_Right: return KB_KEY_KP_6; case XK_KP_Home: return KB_KEY_KP_7; case XK_KP_Up: return KB_KEY_KP_8; case XK_KP_Page_Up: return KB_KEY_KP_9; case XK_KP_Delete: return KB_KEY_KP_DECIMAL; case XK_KP_Equal: return KB_KEY_KP_EQUAL; case XK_KP_Enter: return KB_KEY_KP_ENTER; // Last resort: Check for printable keys (should not happen if the XKB // extension is available). This will give a layout dependent mapping // (which is wrong, and we may miss some keys, especially on non-US // keyboards), but it's better than nothing... case XK_a: return KB_KEY_A; case XK_b: return KB_KEY_B; case XK_c: return KB_KEY_C; case XK_d: return KB_KEY_D; case XK_e: return KB_KEY_E; case XK_f: return KB_KEY_F; case XK_g: return KB_KEY_G; case XK_h: return KB_KEY_H; case XK_i: return KB_KEY_I; case XK_j: return KB_KEY_J; case XK_k: return KB_KEY_K; case XK_l: return KB_KEY_L; case XK_m: return KB_KEY_M; case XK_n: return KB_KEY_N; case XK_o: return KB_KEY_O; case XK_p: return KB_KEY_P; case XK_q: return KB_KEY_Q; case XK_r: return KB_KEY_R; case XK_s: return KB_KEY_S; case XK_t: return KB_KEY_T; case XK_u: return KB_KEY_U; case XK_v: return KB_KEY_V; case XK_w: return KB_KEY_W; case XK_x: return KB_KEY_X; case XK_y: return KB_KEY_Y; case XK_z: return KB_KEY_Z; case XK_1: return KB_KEY_1; case XK_2: return KB_KEY_2; case XK_3: return KB_KEY_3; case XK_4: return KB_KEY_4; case XK_5: return KB_KEY_5; case XK_6: return KB_KEY_6; case XK_7: return KB_KEY_7; case XK_8: return KB_KEY_8; case XK_9: return KB_KEY_9; case XK_0: return KB_KEY_0; case XK_space: return KB_KEY_SPACE; case XK_minus: return KB_KEY_MINUS; case XK_equal: return KB_KEY_EQUAL; case XK_bracketleft: return KB_KEY_LEFT_BRACKET; case XK_bracketright: return KB_KEY_RIGHT_BRACKET; case XK_backslash: return KB_KEY_BACKSLASH; case XK_semicolon: return KB_KEY_SEMICOLON; case XK_apostrophe: return KB_KEY_APOSTROPHE; case XK_grave: return KB_KEY_GRAVE_ACCENT; case XK_comma: return KB_KEY_COMMA; case XK_period: return KB_KEY_PERIOD; case XK_slash: return KB_KEY_SLASH; case XK_less: return KB_KEY_WORLD_1; // At least in some layouts... default: break; } return KB_KEY_UNKNOWN; } void init_keycodes(SWindowData_X11 *window_data_x11) { size_t i; int keySym; // Clear keys for (i = 0; i < sizeof(g_keycodes) / sizeof(g_keycodes[0]); ++i) g_keycodes[i] = KB_KEY_UNKNOWN; // Valid key code range is [8,255], according to the Xlib manual for (i=8; i<=255; ++i) { // Try secondary keysym, for numeric keypad keys keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 1); g_keycodes[i] = translateKeyCodeB(keySym); if (g_keycodes[i] == KB_KEY_UNKNOWN) { keySym = XkbKeycodeToKeysym(window_data_x11->display, i, 0, 0); g_keycodes[i] = translateKeyCodeA(keySym); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int translate_key(int scancode) { if (scancode < 0 || scancode > 255) return KB_KEY_UNKNOWN; return g_keycodes[scancode]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int translate_mod(int state) { int mod_keys = 0; if (state & ShiftMask) mod_keys |= KB_MOD_SHIFT; if (state & ControlMask) mod_keys |= KB_MOD_CONTROL; if (state & Mod1Mask) mod_keys |= KB_MOD_ALT; if (state & Mod4Mask) mod_keys |= KB_MOD_SUPER; if (state & LockMask) mod_keys |= KB_MOD_CAPS_LOCK; if (state & Mod2Mask) mod_keys |= KB_MOD_NUM_LOCK; return mod_keys; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int translate_mod_ex(int key, int state, int is_pressed) { int mod_keys = 0; mod_keys = translate_mod(state); switch (key) { case KB_KEY_LEFT_SHIFT: case KB_KEY_RIGHT_SHIFT: if (is_pressed) mod_keys |= KB_MOD_SHIFT; else mod_keys &= ~KB_MOD_SHIFT; break; case KB_KEY_LEFT_CONTROL: case KB_KEY_RIGHT_CONTROL: if (is_pressed) mod_keys |= KB_MOD_CONTROL; else mod_keys &= ~KB_MOD_CONTROL; break; case KB_KEY_LEFT_ALT: case KB_KEY_RIGHT_ALT: if (is_pressed) mod_keys |= KB_MOD_ALT; else mod_keys &= ~KB_MOD_ALT; break; case KB_KEY_LEFT_SUPER: case KB_KEY_RIGHT_SUPER: if (is_pressed) mod_keys |= KB_MOD_SUPER; else mod_keys &= ~KB_MOD_SUPER; break; } return mod_keys; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; if (offset_x + width > window_data->window_width) { return false; } if (offset_y + height > window_data->window_height) { return false; } window_data->dst_offset_x = offset_x; window_data->dst_offset_y = offset_y; window_data->dst_width = width; window_data->dst_height = height; calc_dst_factor(window_data, window_data->window_width, window_data->window_height); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void mfb_get_monitor_scale(struct mfb_window *window, float *scale_x, float *scale_y) { float x = 96.0, y = 96.0; if(window != 0x0) { //SWindowData *window_data = (SWindowData *) window; //SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; // I cannot find a way to get dpi under VirtualBox // XrmGetResource "Xft.dpi", "Xft.Dpi" // XRRGetOutputInfo // DisplayWidthMM, DisplayHeightMM // All returning invalid values or 0 } if (scale_x) { *scale_x = x / 96.0f; if(*scale_x == 0) { *scale_x = 1.0f; } } if (scale_y) { *scale_y = y / 96.0f; if (*scale_y == 0) { *scale_y = 1.0f; } } }