2015-08-15 03:50:08 +00:00
|
|
|
|
#if defined(SUPPORT_X11)
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
#include "cfg/cfg.h"
|
2019-09-07 12:37:39 +00:00
|
|
|
|
#include "x11.h"
|
2019-02-06 18:57:13 +00:00
|
|
|
|
#include "rend/gui.h"
|
2019-02-12 10:30:24 +00:00
|
|
|
|
#include "input/gamepad.h"
|
2021-11-10 19:35:30 +00:00
|
|
|
|
#include "input/mouse.h"
|
2019-09-20 17:02:54 +00:00
|
|
|
|
#include "icon.h"
|
2019-10-18 19:57:08 +00:00
|
|
|
|
#include "wsi/context.h"
|
2021-11-10 19:35:30 +00:00
|
|
|
|
#include "wsi/gl_context.h"
|
2020-03-20 15:57:50 +00:00
|
|
|
|
#include "hw/maple/maple_devs.h"
|
2020-04-20 16:52:02 +00:00
|
|
|
|
#include "emulator.h"
|
2015-08-15 03:50:08 +00:00
|
|
|
|
|
2019-02-22 11:56:21 +00:00
|
|
|
|
#include "x11_keyboard.h"
|
2015-08-24 22:54:23 +00:00
|
|
|
|
|
2015-08-15 03:50:08 +00:00
|
|
|
|
#if defined(TARGET_PANDORA)
|
2019-02-22 11:56:21 +00:00
|
|
|
|
#define DEFAULT_FULLSCREEN true
|
2015-08-21 00:16:48 +00:00
|
|
|
|
#define DEFAULT_WINDOW_WIDTH 800
|
2015-08-15 03:50:08 +00:00
|
|
|
|
#else
|
2019-02-22 11:56:21 +00:00
|
|
|
|
#define DEFAULT_FULLSCREEN false
|
2015-08-21 00:16:48 +00:00
|
|
|
|
#define DEFAULT_WINDOW_WIDTH 640
|
2015-08-15 03:50:08 +00:00
|
|
|
|
#endif
|
2015-08-21 00:16:48 +00:00
|
|
|
|
#define DEFAULT_WINDOW_HEIGHT 480
|
2015-08-15 03:50:08 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
static Window x11_win;
|
|
|
|
|
Display *x11_disp;
|
2019-02-22 11:56:21 +00:00
|
|
|
|
|
2021-05-19 16:13:52 +00:00
|
|
|
|
class X11Mouse : public SystemMouse
|
2019-02-22 11:56:21 +00:00
|
|
|
|
{
|
|
|
|
|
public:
|
2021-05-19 16:13:52 +00:00
|
|
|
|
X11Mouse() : SystemMouse("X11")
|
2019-02-22 11:56:21 +00:00
|
|
|
|
{
|
2019-03-29 16:19:18 +00:00
|
|
|
|
_unique_id = "x11_mouse";
|
2021-05-19 16:13:52 +00:00
|
|
|
|
loadMapping();
|
2020-11-20 21:10:14 +00:00
|
|
|
|
}
|
2019-02-22 11:56:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-05-10 11:48:12 +00:00
|
|
|
|
static std::shared_ptr<X11Keyboard> x11Keyboard;
|
|
|
|
|
static std::shared_ptr<X11Mouse> x11Mouse;
|
2015-08-15 03:50:08 +00:00
|
|
|
|
|
2015-12-13 12:47:56 +00:00
|
|
|
|
int x11_width;
|
|
|
|
|
int x11_height;
|
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
static bool x11_fullscreen = false;
|
|
|
|
|
static Atom wmDeleteMessage;
|
2015-12-13 12:47:56 +00:00
|
|
|
|
|
2015-08-19 10:45:21 +00:00
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
_NET_WM_STATE_REMOVE =0,
|
|
|
|
|
_NET_WM_STATE_ADD = 1,
|
|
|
|
|
_NET_WM_STATE_TOGGLE =2
|
|
|
|
|
};
|
2015-08-15 03:50:08 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
static void x11_window_set_fullscreen(bool fullscreen)
|
2015-08-19 10:45:21 +00:00
|
|
|
|
{
|
|
|
|
|
XEvent xev;
|
|
|
|
|
xev.xclient.type = ClientMessage;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
xev.xclient.window = x11_win;
|
|
|
|
|
xev.xclient.message_type = XInternAtom(x11_disp, "_NET_WM_STATE", False);
|
2015-08-19 10:45:21 +00:00
|
|
|
|
xev.xclient.format = 32;
|
|
|
|
|
xev.xclient.data.l[0] = 2; // _NET_WM_STATE_TOGGLE
|
2019-10-18 19:57:08 +00:00
|
|
|
|
xev.xclient.data.l[1] = XInternAtom(x11_disp, "_NET_WM_STATE_FULLSCREEN", True);
|
2015-08-19 10:45:21 +00:00
|
|
|
|
xev.xclient.data.l[2] = 0; // no second property to toggle
|
|
|
|
|
xev.xclient.data.l[3] = 1;
|
|
|
|
|
xev.xclient.data.l[4] = 0;
|
|
|
|
|
|
2019-06-30 19:06:46 +00:00
|
|
|
|
INFO_LOG(RENDERER, "x11: setting fullscreen to %d", fullscreen);
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XSendEvent(x11_disp, DefaultRootWindow(x11_disp), False, SubstructureNotifyMask, &xev);
|
2015-08-19 10:45:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 14:54:15 +00:00
|
|
|
|
void event_x11_handle()
|
|
|
|
|
{
|
|
|
|
|
XEvent event;
|
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
while(XPending(x11_disp))
|
2018-07-23 17:47:24 +00:00
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XNextEvent(x11_disp, &event);
|
2018-04-27 14:54:15 +00:00
|
|
|
|
|
|
|
|
|
if (event.type == ClientMessage &&
|
2020-03-12 15:09:05 +00:00
|
|
|
|
(unsigned long)event.xclient.data.l[0] == wmDeleteMessage)
|
2019-02-25 16:52:53 +00:00
|
|
|
|
dc_exit();
|
2018-10-01 18:34:35 +00:00
|
|
|
|
else if (event.type == ConfigureNotify)
|
|
|
|
|
{
|
|
|
|
|
x11_width = event.xconfigure.width;
|
|
|
|
|
x11_height = event.xconfigure.height;
|
|
|
|
|
}
|
2018-04-27 14:54:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 07:27:16 +00:00
|
|
|
|
static bool capturing_mouse;
|
|
|
|
|
static Cursor empty_cursor = None;
|
|
|
|
|
|
|
|
|
|
static Cursor create_empty_cursor()
|
2015-08-17 21:46:28 +00:00
|
|
|
|
{
|
2018-09-18 07:27:16 +00:00
|
|
|
|
if (empty_cursor == None)
|
2015-08-17 21:46:28 +00:00
|
|
|
|
{
|
2018-09-18 07:27:16 +00:00
|
|
|
|
char data[] = { 0 };
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
2018-09-18 07:27:16 +00:00
|
|
|
|
XColor color;
|
|
|
|
|
color.red = color.green = color.blue = 0;
|
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
Pixmap pixmap = XCreateBitmapFromData(x11_disp, DefaultRootWindow(x11_disp),
|
2018-09-18 07:27:16 +00:00
|
|
|
|
data, 1, 1);
|
|
|
|
|
if (pixmap)
|
2015-08-17 21:46:28 +00:00
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
empty_cursor = XCreatePixmapCursor(x11_disp, pixmap, pixmap, &color, &color, 0, 0);
|
|
|
|
|
XFreePixmap(x11_disp, pixmap);
|
2018-09-18 07:27:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return empty_cursor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void destroy_empty_cursor()
|
|
|
|
|
{
|
|
|
|
|
if (empty_cursor != None)
|
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XFreeCursor(x11_disp, empty_cursor);
|
2018-09-18 07:27:16 +00:00
|
|
|
|
empty_cursor = None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void x11_capture_mouse()
|
|
|
|
|
{
|
2019-06-20 21:46:20 +00:00
|
|
|
|
x11_window_set_text("Flycast - mouse capture");
|
2018-09-18 07:27:16 +00:00
|
|
|
|
capturing_mouse = true;
|
|
|
|
|
Cursor cursor = create_empty_cursor();
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XDefineCursor(x11_disp, x11_win, cursor);
|
|
|
|
|
XGrabPointer(x11_disp, x11_win, False,
|
2018-09-18 07:27:16 +00:00
|
|
|
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask,
|
|
|
|
|
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void x11_uncapture_mouse()
|
|
|
|
|
{
|
2019-06-20 21:46:20 +00:00
|
|
|
|
x11_window_set_text("Flycast");
|
2018-09-18 07:27:16 +00:00
|
|
|
|
capturing_mouse = false;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XUndefineCursor(x11_disp, x11_win);
|
|
|
|
|
XUngrabPointer(x11_disp, CurrentTime);
|
2018-09-18 07:27:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void input_x11_handle()
|
|
|
|
|
{
|
|
|
|
|
//Handle X11
|
2018-09-26 00:00:50 +00:00
|
|
|
|
bool mouse_moved = false;
|
2018-09-18 07:27:16 +00:00
|
|
|
|
XEvent e;
|
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
while (XCheckWindowEvent(x11_disp, x11_win,
|
2018-09-18 07:27:16 +00:00
|
|
|
|
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask
|
|
|
|
|
| PointerMotionMask | FocusChangeMask,
|
|
|
|
|
&e))
|
|
|
|
|
{
|
|
|
|
|
switch(e.type)
|
|
|
|
|
{
|
|
|
|
|
case KeyPress:
|
2019-02-24 11:53:49 +00:00
|
|
|
|
{
|
|
|
|
|
char buf[2];
|
|
|
|
|
KeySym keysym_return;
|
|
|
|
|
int len = XLookupString(&e.xkey, buf, 1, &keysym_return, NULL);
|
|
|
|
|
if (len > 0)
|
2021-04-29 16:58:04 +00:00
|
|
|
|
{
|
|
|
|
|
// Cheap ISO Latin-1 to UTF-8 conversion
|
|
|
|
|
u16 b = (u8)buf[0];
|
|
|
|
|
if (b < 0x80)
|
|
|
|
|
gui_keyboard_input(b);
|
|
|
|
|
else
|
|
|
|
|
gui_keyboard_input((u16)((0xc2 + (b > 0xbf)) | ((b & 0x3f) + 0x80) << 8));
|
|
|
|
|
}
|
2019-02-24 11:53:49 +00:00
|
|
|
|
}
|
|
|
|
|
/* no break */
|
2018-09-18 07:27:16 +00:00
|
|
|
|
case KeyRelease:
|
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
if (e.type == KeyRelease && XEventsQueued(x11_disp, QueuedAfterReading))
|
2018-09-26 08:08:49 +00:00
|
|
|
|
{
|
|
|
|
|
XEvent nev;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XPeekEvent(x11_disp, &nev);
|
2018-09-26 08:08:49 +00:00
|
|
|
|
|
|
|
|
|
if (nev.type == KeyPress && nev.xkey.time == e.xkey.time &&
|
|
|
|
|
nev.xkey.keycode == e.xkey.keycode)
|
|
|
|
|
// Key wasn’t actually released: auto repeat
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-05-10 11:48:12 +00:00
|
|
|
|
x11Keyboard->keyboard_input(e.xkey.keycode, e.type == KeyPress);
|
2018-09-06 18:17:28 +00:00
|
|
|
|
|
2019-02-16 13:25:54 +00:00
|
|
|
|
// Start/stop mouse capture with Left Ctrl + Left Alt
|
|
|
|
|
if (e.type == KeyPress
|
|
|
|
|
&& ((e.xkey.keycode == KEY_LALT && (e.xkey.state & ControlMask))
|
|
|
|
|
|| (e.xkey.keycode == KEY_LCTRL && (e.xkey.state & Mod1Mask))))
|
2015-08-28 02:06:36 +00:00
|
|
|
|
{
|
2019-02-16 13:25:54 +00:00
|
|
|
|
capturing_mouse = !capturing_mouse;
|
|
|
|
|
if (capturing_mouse)
|
|
|
|
|
x11_capture_mouse();
|
|
|
|
|
else
|
|
|
|
|
x11_uncapture_mouse();
|
2015-08-28 02:06:36 +00:00
|
|
|
|
}
|
2021-05-10 11:48:12 +00:00
|
|
|
|
if (e.type == KeyPress && e.xkey.keycode == KEY_F11)
|
|
|
|
|
{
|
|
|
|
|
x11_fullscreen = !x11_fullscreen;
|
|
|
|
|
x11_window_set_fullscreen(x11_fullscreen);
|
2018-09-18 07:27:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FocusOut:
|
2021-05-19 16:13:52 +00:00
|
|
|
|
if (capturing_mouse)
|
|
|
|
|
x11_uncapture_mouse();
|
|
|
|
|
capturing_mouse = false;
|
2018-09-18 07:27:16 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ButtonPress:
|
|
|
|
|
case ButtonRelease:
|
2021-05-19 16:13:52 +00:00
|
|
|
|
switch (e.xbutton.button)
|
2018-09-18 07:27:16 +00:00
|
|
|
|
{
|
2021-05-19 16:13:52 +00:00
|
|
|
|
case Button1: // Left button
|
|
|
|
|
x11Mouse->setButton(Mouse::LEFT_BUTTON, e.type == ButtonPress);
|
|
|
|
|
break;
|
|
|
|
|
case Button2: // Middle button
|
|
|
|
|
x11Mouse->setButton(Mouse::MIDDLE_BUTTON, e.type == ButtonPress);
|
|
|
|
|
break;
|
|
|
|
|
case Button3: // Right button
|
|
|
|
|
x11Mouse->setButton(Mouse::RIGHT_BUTTON, e.type == ButtonPress);
|
|
|
|
|
break;
|
|
|
|
|
case Button4: // Mouse wheel up
|
|
|
|
|
x11Mouse->setWheel(-1);
|
|
|
|
|
break;
|
|
|
|
|
case Button5: // Mouse wheel down
|
|
|
|
|
x11Mouse->setWheel(1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2018-09-18 07:27:16 +00:00
|
|
|
|
}
|
2019-02-22 11:56:21 +00:00
|
|
|
|
/* no break */
|
2018-06-13 17:24:48 +00:00
|
|
|
|
|
2018-09-18 07:27:16 +00:00
|
|
|
|
case MotionNotify:
|
2021-05-19 16:13:52 +00:00
|
|
|
|
x11Mouse->setAbsPos(e.xmotion.x, e.xmotion.y, x11_width, x11_height);
|
2019-02-16 13:25:54 +00:00
|
|
|
|
mouse_moved = true;
|
2018-09-18 07:27:16 +00:00
|
|
|
|
break;
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-15 14:09:42 +00:00
|
|
|
|
if (gui_is_open() && capturing_mouse)
|
|
|
|
|
{
|
|
|
|
|
x11_uncapture_mouse();
|
|
|
|
|
capturing_mouse = false;
|
|
|
|
|
}
|
2018-09-26 00:00:50 +00:00
|
|
|
|
if (capturing_mouse && mouse_moved)
|
|
|
|
|
{
|
2021-01-21 20:00:46 +00:00
|
|
|
|
mo_x_prev[0] = x11_width / 2;
|
|
|
|
|
mo_y_prev[0] = x11_height / 2;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XWarpPointer(x11_disp, None, x11_win, 0, 0, 0, 0,
|
2021-01-21 20:00:46 +00:00
|
|
|
|
mo_x_prev[0], mo_y_prev[0]);
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XSync(x11_disp, true);
|
2018-09-26 00:00:50 +00:00
|
|
|
|
}
|
2015-08-15 03:50:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void input_x11_init()
|
|
|
|
|
{
|
2021-05-10 11:48:12 +00:00
|
|
|
|
x11Keyboard = std::make_shared<X11Keyboard>(0);
|
|
|
|
|
GamepadDevice::Register(x11Keyboard);
|
2021-05-19 16:13:52 +00:00
|
|
|
|
x11Mouse = std::make_shared<X11Mouse>();
|
2021-05-10 11:48:12 +00:00
|
|
|
|
GamepadDevice::Register(x11Mouse);
|
2015-08-15 03:50:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_window_create()
|
|
|
|
|
{
|
2015-08-17 21:46:28 +00:00
|
|
|
|
if (cfgLoadInt("pvr", "nox11", 0) == 0)
|
|
|
|
|
{
|
|
|
|
|
XInitThreads();
|
|
|
|
|
|
|
|
|
|
// Initializes the display and screen
|
2019-10-18 19:57:08 +00:00
|
|
|
|
x11_disp = XOpenDisplay(NULL);
|
|
|
|
|
if (x11_disp == nullptr && (x11_disp = XOpenDisplay(":0")) == nullptr)
|
2015-08-17 21:46:28 +00:00
|
|
|
|
{
|
2019-06-30 19:06:46 +00:00
|
|
|
|
ERROR_LOG(RENDERER, "Error: Unable to open X display");
|
2015-08-17 21:46:28 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2019-10-18 19:57:08 +00:00
|
|
|
|
int x11Screen = XDefaultScreen(x11_disp);
|
|
|
|
|
float xdpi = (float)DisplayWidth(x11_disp, x11Screen) / DisplayWidthMM(x11_disp, x11Screen) * 25.4;
|
|
|
|
|
float ydpi = (float)DisplayHeight(x11_disp, x11Screen) / DisplayHeightMM(x11_disp, x11Screen) * 25.4;
|
2022-04-13 16:06:19 +00:00
|
|
|
|
settings.display.dpi = std::max(xdpi, ydpi);
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
|
|
|
|
int depth = CopyFromParent;
|
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XVisualInfo* x11Visual = nullptr;
|
|
|
|
|
Colormap x11Colormap = 0;
|
2019-10-05 09:50:14 +00:00
|
|
|
|
#if !defined(GLES)
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
if (!theGLContext.ChooseVisual(x11_disp, &x11Visual, &depth))
|
2019-10-05 09:50:14 +00:00
|
|
|
|
exit(1);
|
2019-10-18 19:57:08 +00:00
|
|
|
|
x11Colormap = XCreateColormap(x11_disp, RootWindow(x11_disp, x11Screen), x11Visual->visual, AllocNone);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
#else
|
2019-10-18 19:57:08 +00:00
|
|
|
|
int i32Depth = DefaultDepth(x11_disp, x11Screen);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
x11Visual = new XVisualInfo;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
if (!XMatchVisualInfo(x11_disp, x11Screen, i32Depth, TrueColor, x11Visual))
|
2019-10-05 09:50:14 +00:00
|
|
|
|
{
|
|
|
|
|
ERROR_LOG(RENDERER, "Error: Unable to acquire visual");
|
2019-10-18 19:57:08 +00:00
|
|
|
|
delete x11Visual;
|
2019-10-05 09:50:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-12 15:09:05 +00:00
|
|
|
|
// Gets the window parameters
|
|
|
|
|
Window sRootWindow = RootWindow(x11_disp, x11Screen);
|
2019-10-18 19:57:08 +00:00
|
|
|
|
x11Colormap = XCreateColormap(x11_disp, sRootWindow, x11Visual->visual, AllocNone);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
#endif
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XSetWindowAttributes sWA;
|
2015-08-17 21:46:28 +00:00
|
|
|
|
sWA.colormap = x11Colormap;
|
|
|
|
|
|
|
|
|
|
// Add to these for handling other events
|
|
|
|
|
sWA.event_mask = StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask;
|
2019-02-06 18:57:13 +00:00
|
|
|
|
sWA.event_mask |= PointerMotionMask | FocusChangeMask;
|
2019-10-18 19:57:08 +00:00
|
|
|
|
unsigned long ui32Mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap;
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
2020-11-20 21:10:14 +00:00
|
|
|
|
x11_width = cfgLoadInt("window", "width", 0);
|
|
|
|
|
if (x11_width == 0)
|
|
|
|
|
x11_width = cfgLoadInt("x11", "width", DEFAULT_WINDOW_WIDTH);
|
|
|
|
|
x11_height = cfgLoadInt("window", "height", 0);
|
|
|
|
|
x11_fullscreen = cfgLoadBool("window", "fullscreen", DEFAULT_FULLSCREEN);
|
|
|
|
|
if (x11_height == 0)
|
|
|
|
|
{
|
|
|
|
|
x11_height = cfgLoadInt("x11", "height", DEFAULT_WINDOW_HEIGHT);
|
|
|
|
|
x11_fullscreen = cfgLoadBool("x11", "fullscreen", DEFAULT_FULLSCREEN);
|
|
|
|
|
}
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
2015-08-19 10:45:21 +00:00
|
|
|
|
if (x11_width < 0 || x11_height < 0)
|
2015-08-17 21:46:28 +00:00
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
x11_width = XDisplayWidth(x11_disp, x11Screen);
|
|
|
|
|
x11_height = XDisplayHeight(x11_disp, x11Screen);
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Creates the X11 window
|
2019-10-18 19:57:08 +00:00
|
|
|
|
x11_win = XCreateWindow(x11_disp, RootWindow(x11_disp, x11Screen), 0, 0, x11_width, x11_height,
|
2015-08-17 21:46:28 +00:00
|
|
|
|
0, depth, InputOutput, x11Visual->visual, ui32Mask, &sWA);
|
2020-03-12 15:09:05 +00:00
|
|
|
|
#if !defined(GLES)
|
|
|
|
|
XFree(x11Visual);
|
|
|
|
|
#else
|
|
|
|
|
delete x11Visual;
|
|
|
|
|
#endif
|
2015-08-17 21:46:28 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XSetWindowBackground(x11_disp, x11_win, 0);
|
2019-09-20 17:02:54 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
Atom net_wm_icon = XInternAtom(x11_disp, "_NET_WM_ICON", False);
|
|
|
|
|
Atom cardinal = XInternAtom(x11_disp, "CARDINAL", False);
|
|
|
|
|
XChangeProperty(x11_disp, x11_win, net_wm_icon, cardinal, 32, PropModeReplace,
|
2021-05-31 17:44:55 +00:00
|
|
|
|
(const unsigned char*)window_icon, sizeof(window_icon) / sizeof(*window_icon));
|
2019-09-20 17:02:54 +00:00
|
|
|
|
|
2018-07-23 17:47:24 +00:00
|
|
|
|
// Capture the close window event
|
2019-10-18 19:57:08 +00:00
|
|
|
|
wmDeleteMessage = XInternAtom(x11_disp, "WM_DELETE_WINDOW", False);
|
|
|
|
|
XSetWMProtocols(x11_disp, x11_win, &wmDeleteMessage, 1);
|
2018-04-27 14:54:15 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
if (x11_fullscreen)
|
2015-08-19 10:45:21 +00:00
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
Atom wmState = XInternAtom(x11_disp, "_NET_WM_STATE", False);
|
|
|
|
|
Atom wmFullscreen = XInternAtom(x11_disp, "_NET_WM_STATE_FULLSCREEN", False);
|
|
|
|
|
XChangeProperty(x11_disp, x11_win, wmState, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wmFullscreen, 1);
|
2015-08-19 10:45:21 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XMapRaised(x11_disp, x11_win);
|
2015-08-19 10:45:21 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XMapWindow(x11_disp, x11_win);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
}
|
2021-11-10 19:35:30 +00:00
|
|
|
|
initRenderApi((void *)x11_win, (void *)x11_disp);
|
2015-08-21 00:07:03 +00:00
|
|
|
|
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XFlush(x11_disp);
|
2018-07-06 20:38:48 +00:00
|
|
|
|
|
2019-06-20 21:46:20 +00:00
|
|
|
|
x11_window_set_text("Flycast");
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-06-30 19:06:46 +00:00
|
|
|
|
INFO_LOG(RENDERER, "Not creating X11 window ..");
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
2015-08-15 03:50:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_window_set_text(const char* text)
|
|
|
|
|
{
|
2015-08-17 21:46:28 +00:00
|
|
|
|
if (x11_win)
|
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XStoreName(x11_disp, x11_win, text);
|
|
|
|
|
XSetIconName(x11_disp, x11_win, text);
|
2019-09-20 17:02:54 +00:00
|
|
|
|
|
|
|
|
|
XClassHint hint = { (char *)"WM_CLASS", (char *)text };
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XSetClassHint(x11_disp, x11_win, &hint);
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
2015-08-15 03:50:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_window_destroy()
|
|
|
|
|
{
|
2019-02-22 11:56:21 +00:00
|
|
|
|
destroy_empty_cursor();
|
2021-11-10 19:35:30 +00:00
|
|
|
|
termRenderApi();
|
2019-10-05 09:50:14 +00:00
|
|
|
|
|
2015-08-17 21:46:28 +00:00
|
|
|
|
// close XWindow
|
|
|
|
|
if (x11_win)
|
|
|
|
|
{
|
2019-02-22 11:56:21 +00:00
|
|
|
|
if (!x11_fullscreen)
|
|
|
|
|
{
|
2020-11-20 21:10:14 +00:00
|
|
|
|
cfgSaveInt("window", "width", x11_width);
|
|
|
|
|
cfgSaveInt("window", "height", x11_height);
|
2019-02-22 11:56:21 +00:00
|
|
|
|
}
|
2020-11-20 21:10:14 +00:00
|
|
|
|
cfgSaveBool("window", "fullscreen", x11_fullscreen);
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XDestroyWindow(x11_disp, x11_win);
|
2019-10-21 14:39:16 +00:00
|
|
|
|
x11_win = (Window)0;
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (x11_disp)
|
|
|
|
|
{
|
2019-10-18 19:57:08 +00:00
|
|
|
|
XCloseDisplay(x11_disp);
|
|
|
|
|
x11_disp = nullptr;
|
2015-08-17 21:46:28 +00:00
|
|
|
|
}
|
2015-08-15 03:50:08 +00:00
|
|
|
|
}
|
2015-08-17 21:46:28 +00:00
|
|
|
|
#endif
|