Merge pull request #14622 from bruvzg/non-rectangular-windows

Experimental support for windows with per-pixel transparency.
This commit is contained in:
Hein-Pieter van Braam 2018-05-08 16:44:35 +02:00 committed by GitHub
commit e668757aa9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 417 additions and 21 deletions

View file

@ -336,6 +336,14 @@ void _OS::set_borderless_window(bool p_borderless) {
OS::get_singleton()->set_borderless_window(p_borderless);
}
bool _OS::get_window_per_pixel_transparency_enabled() const {
return OS::get_singleton()->get_window_per_pixel_transparency_enabled();
}
void _OS::set_window_per_pixel_transparency_enabled(bool p_enabled) {
OS::get_singleton()->set_window_per_pixel_transparency_enabled(p_enabled);
}
bool _OS::get_borderless_window() const {
return OS::get_singleton()->get_borderless_window();
}
@ -1068,6 +1076,9 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window);
ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window);
ClassDB::bind_method(D_METHOD("get_window_per_pixel_transparency_enabled"), &_OS::get_window_per_pixel_transparency_enabled);
ClassDB::bind_method(D_METHOD("set_window_per_pixel_transparency_enabled", "enabled"), &_OS::set_window_per_pixel_transparency_enabled);
ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &_OS::set_ime_position);
ClassDB::bind_method(D_METHOD("set_screen_orientation", "orientation"), &_OS::set_screen_orientation);
@ -1185,6 +1196,7 @@ void _OS::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"), "set_screen_orientation", "get_screen_orientation");
ADD_GROUP("Window", "window_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_borderless"), "set_borderless_window", "get_borderless_window");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_per_pixel_transparency_enabled"), "set_window_per_pixel_transparency_enabled", "get_window_per_pixel_transparency_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_fullscreen"), "set_window_fullscreen", "is_window_fullscreen");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_maximized"), "set_window_maximized", "is_window_maximized");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_minimized"), "set_window_minimized", "is_window_minimized");

View file

@ -180,6 +180,9 @@ public:
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window() const;
virtual bool get_window_per_pixel_transparency_enabled() const;
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
virtual void set_ime_position(const Point2 &p_pos);
Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);

View file

@ -672,6 +672,7 @@ OS::OS() {
_render_thread_mode = RENDER_THREAD_SAFE;
_allow_hidpi = false;
_allow_layered = false;
_stack_bottom = (void *)(&stack_bottom);
_logger = NULL;

View file

@ -65,6 +65,7 @@ class OS {
int _exit_code;
int _orientation;
bool _allow_hidpi;
bool _allow_layered;
bool _use_vsync;
char *last_error;
@ -102,6 +103,8 @@ public:
bool maximized;
bool always_on_top;
bool use_vsync;
bool layered_splash;
bool layered;
float get_aspect() const { return (float)width / (float)height; }
VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_always_on_top = false, bool p_use_vsync = false) {
width = p_width;
@ -112,6 +115,8 @@ public:
maximized = p_maximized;
always_on_top = p_always_on_top;
use_vsync = p_use_vsync;
layered = false;
layered_splash = false;
}
};
@ -220,6 +225,13 @@ public:
virtual void set_borderless_window(bool p_borderless) {}
virtual bool get_borderless_window() { return 0; }
virtual bool get_window_per_pixel_transparency_enabled() const { return false; }
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) {}
virtual uint8_t *get_layered_buffer_data() { return NULL; }
virtual Size2 get_layered_buffer_size() { return Size2(0, 0); }
virtual void swap_layered_buffer() {}
virtual void set_ime_position(const Point2 &p_pos) {}
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp) {}
@ -481,6 +493,7 @@ public:
virtual void force_process_input(){};
bool has_feature(const String &p_feature);
bool is_layered_allowed() const { return _allow_layered; }
bool is_hidpi_allowed() const { return _allow_hidpi; }
OS();
virtual ~OS();

View file

@ -316,7 +316,11 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
glViewport(0, 0, window_w, window_h);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glClearColor(p_color.r, p_color.g, p_color.b, p_color.a);
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
glClearColor(0.0, 0.0, 0.0, 0.0);
} else {
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
}
glClear(GL_COLOR_BUFFER_BIT);
canvas->canvas_begin();
@ -340,6 +344,27 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
storage->free(texture);
if (OS::get_singleton()->is_layered_allowed()) {
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
#ifdef WINDOWS_ENABLED
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
if (data) {
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
OS::get_singleton()->swap_layered_buffer();
return;
}
#endif
} else {
//clear alpha
glColorMask(false, false, false, true);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(true, true, true, true);
}
}
OS::get_singleton()->swap_buffers();
}
@ -373,6 +398,28 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
}
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
if (OS::get_singleton()->is_layered_allowed()) {
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
#ifdef WINDOWS_ENABLED
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
if (data) {
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
OS::get_singleton()->swap_layered_buffer();
return;
}
#endif
} else {
//clear alpha
glColorMask(false, false, false, true);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(true, true, true, true);
}
}
if (p_swap_buffers)
OS::get_singleton()->swap_buffers();
else

View file

@ -290,7 +290,11 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
glViewport(0, 0, window_w, window_h);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
glClearColor(0.0, 0.0, 0.0, 0.0);
} else {
glClearColor(p_color.r, p_color.g, p_color.b, 1.0);
}
glClear(GL_COLOR_BUFFER_BIT);
canvas->canvas_begin();
@ -329,6 +333,27 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
storage->free(texture); // free since it's only one frame that stays there
if (OS::get_singleton()->is_layered_allowed()) {
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
#ifdef WINDOWS_ENABLED
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
if (data) {
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
OS::get_singleton()->swap_layered_buffer();
return;
}
#endif
} else {
//clear alpha
glColorMask(false, false, false, true);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(true, true, true, true);
}
}
OS::get_singleton()->swap_buffers();
}
@ -365,6 +390,27 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re
void RasterizerGLES3::end_frame(bool p_swap_buffers) {
if (OS::get_singleton()->is_layered_allowed()) {
if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
#ifdef WINDOWS_ENABLED
Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
if (data) {
glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
OS::get_singleton()->swap_layered_buffer();
return;
}
#endif
} else {
//clear alpha
glColorMask(false, false, false, true);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(true, true, true, true);
}
}
if (p_swap_buffers)
OS::get_singleton()->swap_buffers();
else

View file

@ -875,7 +875,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
}
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/allow_per_pixel_transparency", false);
video_mode.use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true);
video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency", false);
video_mode.layered_splash = GLOBAL_DEF("display/window/per_pixel_transparency_splash", false);
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
@ -883,6 +887,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
OS::get_singleton()->_allow_layered = false;
}
Engine::get_singleton()->_pixel_snap = GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false);

View file

@ -99,6 +99,8 @@ public:
id pixelFormat;
id context;
bool layered_window;
CursorShape cursor_shape;
NSCursor *cursors[CURSOR_MAX];
MouseMode mouse_mode;
@ -226,6 +228,10 @@ public:
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window();
virtual bool get_window_per_pixel_transparency_enabled() const;
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
virtual void set_ime_position(const Point2 &p_pos);
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp);

View file

@ -1330,6 +1330,9 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
restore_rect = Rect2(get_window_position(), get_window_size());
if (p_desired.layered_splash) {
set_window_per_pixel_transparency_enabled(true);
}
return OK;
}
@ -2042,6 +2045,8 @@ void OS_OSX::set_window_size(const Size2 p_size) {
void OS_OSX::set_window_fullscreen(bool p_enabled) {
if (zoomed != p_enabled) {
if (layered_window)
set_window_per_pixel_transparency_enabled(false);
[window_object toggleFullScreen:nil];
}
zoomed = p_enabled;
@ -2123,6 +2128,39 @@ void OS_OSX::request_attention() {
[NSApp requestUserAttention:NSCriticalRequest];
}
bool OS_OSX::get_window_per_pixel_transparency_enabled() const {
if (!is_layered_allowed()) return false;
return layered_window;
}
void OS_OSX::set_window_per_pixel_transparency_enabled(bool p_enabled) {
if (!is_layered_allowed()) return;
if (layered_window != p_enabled) {
if (p_enabled) {
set_borderless_window(true);
GLint opacity = 0;
[window_object setBackgroundColor:[NSColor clearColor]];
[window_object setOpaque:NO];
[window_object setHasShadow:NO];
[context setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity];
layered_window = true;
} else {
GLint opacity = 1;
[window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
[window_object setOpaque:YES];
[window_object setHasShadow:YES];
[context setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity];
layered_window = false;
}
[context update];
NSRect frame = [window_object frame];
[window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, 1, 1) display:YES];
[window_object setFrame:frame display:YES];
}
}
void OS_OSX::set_borderless_window(bool p_borderless) {
// OrderOut prevents a lose focus bug with the window
@ -2131,6 +2169,9 @@ void OS_OSX::set_borderless_window(bool p_borderless) {
if (p_borderless) {
[window_object setStyleMask:NSWindowStyleMaskBorderless];
} else {
if (layered_window)
set_window_per_pixel_transparency_enabled(false);
[window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable];
// Force update of the window styles
@ -2435,6 +2476,7 @@ OS_OSX::OS_OSX() {
im_position = Point2();
im_callback = NULL;
im_target = NULL;
layered_window = false;
autoreleasePool = [[NSAutoreleasePool alloc] init];
eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);

View file

@ -637,6 +637,28 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
maximized = false;
minimized = false;
}
if (is_layered_allowed() && layered_window) {
DeleteObject(hBitmap);
RECT r;
GetWindowRect(hWnd, &r);
dib_size = Size2(r.right - r.left, r.bottom - r.top);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = dib_size.x;
bmi.bmiHeader.biHeight = dib_size.y;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = dib_size.x, dib_size.y * 4;
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
SelectObject(hDC_dib, hBitmap);
ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
}
//return 0; // Jump Back
} break;
case WM_ENTERSIZEMOVE: {
@ -1151,6 +1173,9 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
SetFocus(hWnd); // Sets Keyboard Focus To
}
if (p_desired.layered_splash) {
set_window_per_pixel_transparency_enabled(true);
}
return OK;
}
@ -1542,6 +1567,9 @@ void OS_Windows::set_window_fullscreen(bool p_enabled) {
if (video_mode.fullscreen == p_enabled)
return;
if (layered_window)
set_window_per_pixel_transparency_enabled(false);
if (p_enabled) {
if (pre_fs_valid) {
@ -1646,10 +1674,97 @@ bool OS_Windows::is_window_always_on_top() const {
return video_mode.always_on_top;
}
bool OS_Windows::get_window_per_pixel_transparency_enabled() const {
if (!is_layered_allowed()) return false;
return layered_window;
}
void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) {
if (!is_layered_allowed()) return;
if (layered_window != p_enabled) {
if (p_enabled) {
set_borderless_window(true);
//enable per-pixel alpha
hDC_dib = CreateCompatibleDC(GetDC(hWnd));
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
RECT r;
GetWindowRect(hWnd, &r);
dib_size = Size2(r.right - r.left, r.bottom - r.top);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = dib_size.x;
bmi.bmiHeader.biHeight = dib_size.y;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
SelectObject(hDC_dib, hBitmap);
ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
layered_window = true;
} else {
//disable per-pixel alpha
layered_window = false;
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
//cleanup
DeleteObject(hBitmap);
DeleteDC(hDC_dib);
}
}
}
uint8_t *OS_Windows::get_layered_buffer_data() {
return (is_layered_allowed() && layered_window) ? dib_data : NULL;
}
Size2 OS_Windows::get_layered_buffer_size() {
return (is_layered_allowed() && layered_window) ? dib_size : Size2();
}
void OS_Windows::swap_layered_buffer() {
if (is_layered_allowed() && layered_window) {
//premultiply alpha
for (int y = 0; y < dib_size.y; y++) {
for (int x = 0; x < dib_size.x; x++) {
float alpha = (float)dib_data[y * (int)dib_size.x * 4 + x * 4 + 3] / (float)0xFF;
dib_data[y * (int)dib_size.x * 4 + x * 4 + 0] *= alpha;
dib_data[y * (int)dib_size.x * 4 + x * 4 + 1] *= alpha;
dib_data[y * (int)dib_size.x * 4 + x * 4 + 2] *= alpha;
}
}
//swap layered window buffer
POINT ptSrc = { 0, 0 };
SIZE sizeWnd = { (long)dib_size.x, (long)dib_size.y };
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = AC_SRC_ALPHA;
bf.SourceConstantAlpha = 0xFF;
UpdateLayeredWindow(hWnd, NULL, NULL, &sizeWnd, hDC_dib, &ptSrc, 0, &bf, ULW_ALPHA);
}
}
void OS_Windows::set_borderless_window(bool p_borderless) {
if (video_mode.borderless_window == p_borderless)
return;
if (!p_borderless && layered_window)
set_window_per_pixel_transparency_enabled(false);
video_mode.borderless_window = p_borderless;
_update_window_style();
@ -2582,6 +2697,8 @@ Error OS_Windows::move_to_trash(const String &p_path) {
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
key_event_pos = 0;
layered_window = false;
hBitmap = NULL;
force_quit = false;
alt_mem = false;
gr_mem = false;
@ -2615,6 +2732,10 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
}
OS_Windows::~OS_Windows() {
if (is_layered_allowed() && layered_window) {
DeleteObject(hBitmap);
DeleteDC(hDC_dib);
}
#ifdef STDOUT_FILE
fclose(stdo);
#endif

View file

@ -93,6 +93,12 @@ class OS_Windows : public OS {
HINSTANCE hInstance; // Holds The Instance Of The Application
HWND hWnd;
HBITMAP hBitmap; //DIB section for layered window
uint8_t *dib_data;
Size2 dib_size;
HDC hDC_dib;
bool layered_window;
uint32_t move_timer_id;
HCURSOR hCursor;
@ -212,6 +218,13 @@ public:
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window();
virtual bool get_window_per_pixel_transparency_enabled() const;
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
virtual uint8_t *get_layered_buffer_data();
virtual Size2 get_layered_buffer_size();
virtual void swap_layered_buffer();
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
virtual Error close_dynamic_library(void *p_library_handle);
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);

View file

@ -116,32 +116,76 @@ Error ContextGL_X11::initialize() {
None
};
static int visual_attribs_layered[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, true,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
None
};
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
GLXFBConfig fbconfig;
XVisualInfo *vi = NULL;
XVisualInfo *vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
XSetWindowAttributes swa;
for (int i = 0; i < fbcount; i++) {
vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
if (!vi)
continue;
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
if (!pict_format) {
XFree(vi);
vi = NULL;
continue;
}
/*
char* windowid = getenv("GODOT_WINDOWID");
if (windowid) {
fbconfig = fbc[i];
if (pict_format->direct.alphaMask > 0) {
break;
}
}
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
swa.border_pixel = 0;
swa.background_pixmap = None;
swa.background_pixel = 0;
swa.border_pixmap = None;
swa.event_mask = StructureNotifyMask;
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | CWBackPixel, &swa);
//freopen("/home/punto/stdout", "w", stdout);
//reopen("/home/punto/stderr", "w", stderr);
x11_window = atol(windowid);
} else {
*/
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
fbconfig = fbc[0];
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
}
ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
set_class_hint(x11_display, x11_window);
XMapWindow(x11_display, x11_window);
//};
int (*oldHandler)(Display *, XErrorEvent *) =
XSetErrorHandler(&ctxErrorHandler);
@ -160,7 +204,7 @@ Error ContextGL_X11::initialize() {
None
};
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
ERR_EXPLAIN("Could not obtain an OpenGL 3.0 context!");
ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
} break;
@ -175,7 +219,7 @@ Error ContextGL_X11::initialize() {
None
};
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
p->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
ERR_EXPLAIN("Could not obtain an OpenGL 3.3 context!");
ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED);
} break;
@ -195,7 +239,6 @@ Error ContextGL_X11::initialize() {
//glXMakeCurrent(x11_display, None, NULL);
XFree(vi);
XFree(fbc);
return OK;
}

View file

@ -41,6 +41,7 @@
#include "drivers/gl_context/context_gl.h"
#include "os/os.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
struct ContextGL_X11_Private;

View file

@ -42,6 +42,11 @@ def can_build():
print("xrandr not found.. x11 disabled.")
return False
x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
if (x11_error):
print("xrender not found.. x11 disabled.")
return False
return True
def get_opts():
@ -141,6 +146,7 @@ def configure(env):
env.ParseConfig('pkg-config xcursor --cflags --libs')
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
env.ParseConfig('pkg-config xrender --cflags --libs')
if (env['touch']):
x11_error = os.system("pkg-config xi --modversion > /dev/null ")

View file

@ -517,6 +517,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
power_manager = memnew(PowerX11);
if (p_desired.layered_splash) {
set_window_per_pixel_transparency_enabled(true);
}
XEvent xevent;
while (XPending(x11_display) > 0) {
XNextEvent(x11_display, &xevent);
@ -707,6 +711,25 @@ Point2 OS_X11::get_mouse_position() const {
return last_mouse_pos;
}
bool OS_X11::get_window_per_pixel_transparency_enabled() const {
if (!is_layered_allowed()) return false;
return layered_window;
}
void OS_X11::set_window_per_pixel_transparency_enabled(bool p_enabled) {
if (!is_layered_allowed()) return;
if (layered_window != p_enabled) {
if (p_enabled) {
set_borderless_window(true);
layered_window = true;
} else {
layered_window = false;
}
}
}
void OS_X11::set_window_title(const String &p_title) {
XStoreName(x11_display, x11_window, p_title.utf8().get_data());
@ -1006,9 +1029,13 @@ void OS_X11::set_window_size(const Size2 p_size) {
}
void OS_X11::set_window_fullscreen(bool p_enabled) {
if (current_videomode.fullscreen == p_enabled)
return;
if (layered_window)
set_window_per_pixel_transparency_enabled(false);
if (p_enabled && current_videomode.always_on_top) {
// Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
set_window_maximized(true);
@ -1254,6 +1281,9 @@ void OS_X11::set_borderless_window(bool p_borderless) {
if (current_videomode.borderless_window == p_borderless)
return;
if (!p_borderless && layered_window)
set_window_per_pixel_transparency_enabled(false);
current_videomode.borderless_window = p_borderless;
Hints hints;
@ -2715,6 +2745,7 @@ OS_X11::OS_X11() {
AudioDriverManager::add_driver(&driver_alsa);
#endif
layered_window = false;
minimized = false;
xim_style = 0L;
mouse_mode = MOUSE_MODE_VISIBLE;

View file

@ -172,6 +172,8 @@ class OS_X11 : public OS_Unix {
PowerX11 *power_manager;
bool layered_window;
CrashHandler crash_handler;
int audio_driver_index;
@ -263,6 +265,10 @@ public:
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window();
virtual bool get_window_per_pixel_transparency_enabled() const;
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
virtual void set_ime_position(const Point2 &p_pos);
virtual String get_unique_id() const;