diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/AndroidManifest.xml.template | 2 | ||||
-rw-r--r-- | platform/android/build.gradle.template | 1 | ||||
-rw-r--r-- | platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java | 10 | ||||
-rw-r--r-- | platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java | 8 | ||||
-rw-r--r-- | platform/iphone/app_delegate.mm | 21 | ||||
-rw-r--r-- | platform/javascript/engine.js | 21 | ||||
-rw-r--r-- | platform/javascript/export/export.cpp | 2 | ||||
-rw-r--r-- | platform/javascript/os_javascript.cpp | 12 | ||||
-rw-r--r-- | platform/osx/os_osx.h | 6 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 160 | ||||
-rw-r--r-- | platform/server/os_server.cpp | 6 | ||||
-rw-r--r-- | platform/server/os_server.h | 3 | ||||
-rw-r--r-- | platform/uwp/export/export.cpp | 4 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 170 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 13 | ||||
-rw-r--r-- | platform/x11/context_gl_x11.cpp | 83 | ||||
-rw-r--r-- | platform/x11/context_gl_x11.h | 1 | ||||
-rw-r--r-- | platform/x11/detect.py | 6 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 81 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 6 |
20 files changed, 516 insertions, 100 deletions
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template index 3e42b7a3cd..13d10b5026 100644 --- a/platform/android/AndroidManifest.xml.template +++ b/platform/android/AndroidManifest.xml.template @@ -201,6 +201,6 @@ $$ADD_PERMISSION_CHUNKS$$ <uses-permission android:name="godot.custom.18"/> <uses-permission android:name="godot.custom.19"/> -<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="23"/> +<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="27"/> </manifest> diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 7269e658b4..cc45fee95f 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -21,7 +21,6 @@ allprojects { } dependencies { - compile 'com.android.support:support-v4:27.+' // can be removed if minSdkVersion 16 and modify DownloadNotification.java & V14CustomNotification.java $$GRADLE_DEPENDENCIES$$ } diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java index 73e6f83bec..a9f674803c 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java @@ -27,7 +27,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.os.Messenger; -import android.support.v4.app.NotificationCompat; /** * This class handles displaying the notification associated with the download @@ -49,9 +48,8 @@ public class DownloadNotification implements IDownloaderClient { private IDownloaderClient mClientProxy; final ICustomNotification mCustomNotification; - // NotificationCompat.Builder is used to support API < 16. This can be changed to Notification.Builder if minimum API >= 16. - private NotificationCompat.Builder mNotificationBuilder; - private NotificationCompat.Builder mCurrentNotificationBuilder; + private Notification.Builder mNotificationBuilder; + private Notification.Builder mCurrentNotificationBuilder; private CharSequence mLabel; private String mCurrentText; private PendingIntent mContentIntent; @@ -187,7 +185,7 @@ public class DownloadNotification implements IDownloaderClient { void setTimeRemaining(long timeRemaining); - NotificationCompat.Builder updateNotification(Context c); + Notification.Builder updateNotification(Context c); } /** @@ -220,7 +218,7 @@ public class DownloadNotification implements IDownloaderClient { mContext.getSystemService(Context.NOTIFICATION_SERVICE); mCustomNotification = CustomNotificationFactory .createCustomNotification(); - mNotificationBuilder = new NotificationCompat.Builder(ctx); + mNotificationBuilder = new Notification.Builder(ctx); mCurrentNotificationBuilder = mNotificationBuilder; } diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java index 390bde96e9..56b2331e31 100644 --- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java +++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java @@ -22,7 +22,6 @@ import com.google.android.vending.expansion.downloader.Helpers; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; -import android.support.v4.app.NotificationCompat; public class V14CustomNotification implements DownloadNotification.ICustomNotification { @@ -54,14 +53,13 @@ public class V14CustomNotification implements DownloadNotification.ICustomNotifi mCurrentKB = currentBytes; } - void setProgress(NotificationCompat.Builder builder) { + void setProgress(Notification.Builder builder) { } @Override - public NotificationCompat.Builder updateNotification(Context c) { - // NotificationCompat.Builder is used to support API < 16. This can be changed to Notification.Builder if minimum API >= 16. - NotificationCompat.Builder builder = new NotificationCompat.Builder(c); + public Notification.Builder updateNotification(Context c) { + Notification.Builder builder = new Notification.Builder(c); builder.setContentTitle(mTitle); if (mTotalKB > 0 && -1 != mCurrentKB) { builder.setProgress((int) (mTotalKB >> 8), (int) (mCurrentKB >> 8), false); diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 7ed1328b20..dd5ce4ab10 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -709,21 +709,18 @@ static int frame_count = 0; iphone_finish(); }; -- (void)applicationDidEnterBackground:(UIApplication *)application { - ///@TODO maybe add pause motionManager? and where would we unpause it? +// When application goes to background (e.g. user switches to another app or presses Home), +// then applicationWillResignActive -> applicationDidEnterBackground are called. +// When user opens the inactive app again, +// applicationWillEnterForeground -> applicationDidBecomeActive are called. - on_focus_out(view_controller, &is_focus_out); -} - -- (void)applicationWillEnterForeground:(UIApplication *)application { - // OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN); - [view_controller.view startAnimation]; -} +// There are cases when applicationWillResignActive -> applicationDidBecomeActive +// sequence is called without the app going to background. For example, that happens +// if you open the app list without switching to another app or open/close the +// notification panel by swiping from the upper part of the screen. - (void)applicationWillResignActive:(UIApplication *)application { - // OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT); - [view_controller.view - stopAnimation]; // FIXME: pause seems to be recommended elsewhere + on_focus_out(view_controller, &is_focus_out); } - (void)applicationDidBecomeActive:(UIApplication *)application { diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js index e4839af433..c3ef5bbbb5 100644 --- a/platform/javascript/engine.js +++ b/platform/javascript/engine.js @@ -10,6 +10,7 @@ var DOWNLOAD_ATTEMPTS_MAX = 4; var basePath = null; + var wasmFilenameExtensionOverride = null; var engineLoadPromise = null; var loadingFiles = {}; @@ -129,13 +130,17 @@ this.startGame = function(mainPack) { executableName = getBaseName(mainPack); + var mainArgs = []; + if (!getPathLeaf(mainPack).endsWith('.pck')) { + mainArgs = ['--main-pack', getPathLeaf(mainPack)]; + } return Promise.all([ // Load from directory, this.init(getBasePath(mainPack)), // ...but write to root where the engine expects it. this.preloadFile(mainPack, getPathLeaf(mainPack)) ]).then( - Function.prototype.apply.bind(synchronousStart, this, []) + Function.prototype.apply.bind(synchronousStart, this, mainArgs) ); }; @@ -161,6 +166,10 @@ actualCanvas.style.padding = 0; actualCanvas.style.borderWidth = 0; actualCanvas.style.borderStyle = 'none'; + // disable right-click context menu + actualCanvas.addEventListener('contextmenu', function(ev) { + ev.preventDefault(); + }, false); // until context restoration is implemented actualCanvas.addEventListener('webglcontextlost', function(ev) { alert("WebGL context lost, please reload the page"); @@ -299,6 +308,14 @@ return !!testContext; }; + Engine.setWebAssemblyFilenameExtension = function(override) { + + if (String(override).length === 0) { + throw new Error('Invalid WebAssembly filename extension override'); + } + wasmFilenameExtensionOverride = String(override); + } + Engine.load = function(newBasePath) { if (newBasePath !== undefined) basePath = getBasePath(newBasePath); @@ -306,7 +323,7 @@ if (typeof WebAssembly !== 'object') return Promise.reject(new Error("Browser doesn't support WebAssembly")); // TODO cache/retrieve module to/from idb - engineLoadPromise = loadPromise(basePath + '.wasm').then(function(xhr) { + engineLoadPromise = loadPromise(basePath + '.' + (wasmFilenameExtensionOverride || 'wasm')).then(function(xhr) { return xhr.response; }); engineLoadPromise = engineLoadPromise.catch(function(err) { diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index d81aa25c32..9591850662 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -117,7 +117,7 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_GLOBAL_FILE, "html"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "html"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 1b5463e40d..6c6e4d2d1c 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -167,10 +167,9 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent int mask = _input->get_mouse_button_mask(); int button_flag = 1 << (ev->get_button_index() - 1); if (ev->is_pressed()) { - // since the event is consumed, focus manually - if (!is_canvas_focused()) { - focus_canvas(); - } + // Since the event is consumed, focus manually. The containing iframe, + // if used, may not have focus yet, so focus even if already focused. + focus_canvas(); mask |= button_flag; } else if (mask & button_flag) { mask &= ~button_flag; @@ -181,7 +180,8 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent ev->set_button_mask(mask); _input->parse_input_event(ev); - // prevent selection dragging + // Prevent multi-click text selection and wheel-click scrolling anchor. + // Context menu is prevented through contextmenu event. return true; } @@ -204,7 +204,7 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m ev->set_position(pos); ev->set_global_position(ev->get_position()); - ev->set_relative(ev->get_position() - _input->get_mouse_position()); + ev->set_relative(Vector2(mouse_event->movementX, mouse_event->movementY)); _input->set_mouse_position(ev->get_position()); ev->set_speed(_input->get_last_mouse_speed()); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index fee25e98cb..c1022a1aca 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -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); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index fbefd41bb7..bde0b4e898 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -541,7 +541,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; } - (void)cursorUpdate:(NSEvent *)event { - //setModeCursor(window, window->cursorMode); + OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape; + OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; + OS_OSX::singleton->set_cursor_shape(p_shape); } static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { @@ -656,11 +658,12 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { return; if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED) OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER); - if (OS_OSX::singleton->input) { + if (OS_OSX::singleton->input) OS_OSX::singleton->input->set_mouse_in_window(true); - OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; - OS_OSX::singleton->set_cursor_shape(OS::CURSOR_ARROW); - } + + OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape; + OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX; + OS_OSX::singleton->set_cursor_shape(p_shape); } - (void)magnifyWithEvent:(NSEvent *)event { @@ -847,16 +850,16 @@ struct _KeyCodeMap { static const _KeyCodeMap _keycodes[55] = { { '`', KEY_QUOTELEFT }, { '~', KEY_ASCIITILDE }, - { '0', KEY_KP_0 }, - { '1', KEY_KP_1 }, - { '2', KEY_KP_2 }, - { '3', KEY_KP_3 }, - { '4', KEY_KP_4 }, - { '5', KEY_KP_5 }, - { '6', KEY_KP_6 }, - { '7', KEY_KP_7 }, - { '8', KEY_KP_8 }, - { '9', KEY_KP_9 }, + { '0', KEY_0 }, + { '1', KEY_1 }, + { '2', KEY_2 }, + { '3', KEY_3 }, + { '4', KEY_4 }, + { '5', KEY_5 }, + { '6', KEY_6 }, + { '7', KEY_7 }, + { '8', KEY_8 }, + { '9', KEY_9 }, { '-', KEY_MINUS }, { '_', KEY_UNDERSCORE }, { '=', KEY_EQUAL }, @@ -1330,6 +1333,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; } @@ -1510,39 +1516,78 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) { void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; - Ref<Image> image = texture->get_data(); + Ref<AtlasTexture> atlas_texture = p_cursor; + Ref<Image> image; + Size2 texture_size; + Rect2 atlas_rect; - ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256); + if (texture.is_valid()) { + image = texture->get_data(); + } + + if (!image.is_valid() && atlas_texture.is_valid()) { + texture = atlas_texture->get_atlas(); + + atlas_rect.size.width = texture->get_width(); + atlas_rect.size.height = texture->get_height(); + atlas_rect.position.x = atlas_texture->get_region().position.x; + atlas_rect.position.y = atlas_texture->get_region().position.y; + + texture_size.width = atlas_texture->get_region().size.x; + texture_size.height = atlas_texture->get_region().size.y; + } else if (image.is_valid()) { + texture_size.width = texture->get_width(); + texture_size.height = texture->get_height(); + } + + ERR_FAIL_COND(!texture.is_valid()); + ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); + + image = texture->get_data(); NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:image->get_width() - pixelsHigh:image->get_height() + pixelsWide:int(texture_size.width) + pixelsHigh:int(texture_size.height) bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:image->get_width() * 4 + bytesPerRow:int(texture_size.width) * 4 bitsPerPixel:32] autorelease]; ERR_FAIL_COND(imgrep == nil); uint8_t *pixels = [imgrep bitmapData]; - int len = image->get_width() * image->get_height(); + int len = int(texture_size.width * texture_size.height); PoolVector<uint8_t> data = image->get_data(); PoolVector<uint8_t>::Read r = data.read(); + image->lock(); + /* Premultiply the alpha channel */ for (int i = 0; i < len; i++) { - uint8_t alpha = r[i * 4 + 3]; - pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255); - pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255); - pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255); + int row_index = floor(i / texture_size.width) + atlas_rect.position.y; + int column_index = (i % int(texture_size.width)) + atlas_rect.position.x; + + if (atlas_texture.is_valid()) { + column_index = MIN(column_index, atlas_rect.size.width - 1); + row_index = MIN(row_index, atlas_rect.size.height - 1); + } + + uint32_t color = image->get_pixel(column_index, row_index).to_argb32(); + + uint8_t alpha = (color >> 24) & 0xFF; + pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255; + pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255; + pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255; pixels[i * 4 + 3] = alpha; } - NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease]; + image->unlock(); + + NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)] autorelease]; [nsimage addRepresentation:imgrep]; NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)]; @@ -1552,6 +1597,11 @@ void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c if (p_shape == CURSOR_ARROW) { [cursor set]; } + } else { + // Reset to default system cursor + cursors[p_shape] = NULL; + cursor_shape = CURSOR_MAX; + set_cursor_shape(p_shape); } } @@ -2042,6 +2092,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 +2175,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 +2216,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 @@ -2339,12 +2427,21 @@ void OS_OSX::run() { //int frames=0; //uint64_t frame=0; - while (!force_quit) { + bool quit = false; - process_events(); // get rid of pending events - joypad_osx->process_joypads(); - if (Main::iteration() == true) - break; + while (!force_quit && !quit) { + + @try { + + process_events(); // get rid of pending events + joypad_osx->process_joypads(); + + if (Main::iteration() == true) { + quit = true; + } + } @catch (NSException *exception) { + ERR_PRINTS("NSException: " + String([exception reason].UTF8String)); + } }; main_loop->finish(); @@ -2435,6 +2532,7 @@ OS_OSX::OS_OSX() { im_position = Point2(); im_callback = NULL; im_target = NULL; + layered_window = false; autoreleasePool = [[NSAutoreleasePool alloc] init]; eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp index a8be4fbc35..3b1be780d4 100644 --- a/platform/server/os_server.cpp +++ b/platform/server/os_server.cpp @@ -30,6 +30,7 @@ #include "os_server.h" #include "drivers/dummy/audio_driver_dummy.h" #include "drivers/dummy/rasterizer_dummy.h" +#include "drivers/dummy/texture_loader_dummy.h" #include "print_string.h" #include "servers/visual/visual_server_raster.h" #include <stdio.h> @@ -83,6 +84,9 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int _ensure_user_data_dir(); + resource_loader_dummy = memnew(ResourceFormatDummyTexture); + ResourceLoader::add_resource_format_loader(resource_loader_dummy); + return OK; } @@ -99,6 +103,8 @@ void OS_Server::finalize() { memdelete(power_manager); + memdelete(resource_loader_dummy); + args.clear(); } diff --git a/platform/server/os_server.h b/platform/server/os_server.h index 2cc6f0c47e..f1a880ecc2 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -32,6 +32,7 @@ #include "../x11/crash_handler_x11.h" #include "../x11/power_x11.h" +#include "drivers/dummy/texture_loader_dummy.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/unix/os_unix.h" #include "main/input_default.h" @@ -65,6 +66,8 @@ class OS_Server : public OS_Unix { CrashHandler crash_handler; + ResourceFormatDummyTexture *resource_loader_dummy; + protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 3c537b3b58..35c0b30ce4 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -777,7 +777,7 @@ class EditorExportUWP : public EditorExportPlatform { result = result.replace("$version_string$", version); Platform arch = (Platform)(int)p_preset->get("architecture/target"); - String architecture = arch == ARM ? "ARM" : arch == X86 ? "x86" : "x64"; + String architecture = arch == ARM ? "arm" : arch == X86 ? "x86" : "x64"; result = result.replace("$architecture$", architecture); result = result.replace("$display_name$", String(p_preset->get("package/display_name")).empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name"))); @@ -1046,7 +1046,7 @@ public: } virtual void get_export_options(List<ExportOption> *r_options) { - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "ARM,x86,x64"), 1)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "arm,x86,x64"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 7b46608c55..d6cdea7b88 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -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(); @@ -1918,27 +2033,57 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) { void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; - Ref<Image> image = texture->get_data(); + Ref<AtlasTexture> atlas_texture = p_cursor; + Ref<Image> image; + Size2 texture_size; + Rect2 atlas_rect; - UINT image_size = texture->get_width() * texture->get_height(); - UINT size = sizeof(UINT) * image_size; + if (texture.is_valid()) { + image = texture->get_data(); + } + + if (!image.is_valid() && atlas_texture.is_valid()) { + texture = atlas_texture->get_atlas(); - ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256); + atlas_rect.size.width = texture->get_width(); + atlas_rect.size.height = texture->get_height(); + atlas_rect.position.x = atlas_texture->get_region().position.x; + atlas_rect.position.y = atlas_texture->get_region().position.y; + + texture_size.width = atlas_texture->get_region().size.x; + texture_size.height = atlas_texture->get_region().size.y; + } else if (image.is_valid()) { + texture_size.width = texture->get_width(); + texture_size.height = texture->get_height(); + } + + ERR_FAIL_COND(!texture.is_valid()); + ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); + + image = texture->get_data(); + + UINT image_size = texture_size.width * texture_size.height; + UINT size = sizeof(UINT) * image_size; // Create the BITMAP with alpha channel COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size); image->lock(); for (UINT index = 0; index < image_size; index++) { - int row_index = floor(index / texture->get_width()); - int column_index = index % texture->get_width(); + int row_index = floor(index / texture_size.width) + atlas_rect.position.y; + int column_index = (index % int(texture_size.width)) + atlas_rect.position.x; + + if (atlas_texture.is_valid()) { + column_index = MIN(column_index, atlas_rect.size.width - 1); + row_index = MIN(row_index, atlas_rect.size.height - 1); + } *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32(); } image->unlock(); // Using 4 channels, so 4 * 8 bits - HBITMAP bitmap = CreateBitmap(texture->get_width(), texture->get_height(), 1, 4 * 8, buffer); + HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer); COLORREF clrTransparent = -1; // Create the AND and XOR masks for the bitmap @@ -1972,6 +2117,11 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap if (hXorMask != NULL) { DeleteObject(hXorMask); } + } else { + // Reset to default system cursor + cursors[p_shape] = NULL; + cursor_shape = CURSOR_MAX; + set_cursor_shape(p_shape); } } @@ -2582,6 +2732,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 +2767,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 diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 584f6fb334..221109318e 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -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); diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp index 1a7cbc0d6d..cd76667c64 100644 --- a/platform/x11/context_gl_x11.cpp +++ b/platform/x11/context_gl_x11.cpp @@ -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; + + 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); + + for (int i = 0; i < fbcount; i++) { + vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]); + if (!vi) + continue; + + XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual); + if (!pict_format) { + XFree(vi); + vi = NULL; + continue; + } + + 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); - XVisualInfo *vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); + } else { + GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); + ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); - XSetWindowAttributes swa; + vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); - swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); - swa.border_pixel = 0; - swa.event_mask = StructureNotifyMask; + fbconfig = fbc[0]; - /* - char* windowid = getenv("GODOT_WINDOWID"); - if (windowid) { + 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); + } - //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); 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; } diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h index b54cc84fac..b8f3eb95d4 100644 --- a/platform/x11/context_gl_x11.h +++ b/platform/x11/context_gl_x11.h @@ -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; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 5820a926e9..ad2620c9f5 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -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 ") diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 336068cb1e..eec371865e 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -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; @@ -2390,13 +2420,38 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) { void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture> texture = p_cursor; - Ref<Image> image = texture->get_data(); + Ref<AtlasTexture> atlas_texture = p_cursor; + Ref<Image> image; + Size2 texture_size; + Rect2 atlas_rect; + + if (texture.is_valid()) { + image = texture->get_data(); + } + + if (!image.is_valid() && atlas_texture.is_valid()) { + texture = atlas_texture->get_atlas(); + + atlas_rect.size.width = texture->get_width(); + atlas_rect.size.height = texture->get_height(); + atlas_rect.position.x = atlas_texture->get_region().position.x; + atlas_rect.position.y = atlas_texture->get_region().position.y; + + texture_size.width = atlas_texture->get_region().size.x; + texture_size.height = atlas_texture->get_region().size.y; + } else if (image.is_valid()) { + texture_size.width = texture->get_width(); + texture_size.height = texture->get_height(); + } - ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256); + ERR_FAIL_COND(!texture.is_valid()); + ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); + + image = texture->get_data(); // Create the cursor structure - XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height()); - XcursorUInt image_size = texture->get_width() * texture->get_height(); + XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height); + XcursorUInt image_size = texture_size.width * texture_size.height; XcursorDim size = sizeof(XcursorPixel) * image_size; cursor_image->version = 1; @@ -2410,8 +2465,13 @@ void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c image->lock(); for (XcursorPixel index = 0; index < image_size; index++) { - int row_index = floor(index / texture->get_width()); - int column_index = index % texture->get_width(); + int row_index = floor(index / texture_size.width) + atlas_rect.position.y; + int column_index = (index % int(texture_size.width)) + atlas_rect.position.x; + + if (atlas_texture.is_valid()) { + column_index = MIN(column_index, atlas_rect.size.width - 1); + row_index = MIN(row_index, atlas_rect.size.height - 1); + } *(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32(); } @@ -2426,6 +2486,14 @@ void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c if (p_shape == CURSOR_ARROW) { XDefineCursor(x11_display, x11_window, cursors[p_shape]); } + } else { + // Reset to default system cursor + if (img[p_shape]) { + cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]); + } + + current_cursor = CURSOR_MAX; + set_cursor_shape(p_shape); } } @@ -2715,6 +2783,7 @@ OS_X11::OS_X11() { AudioDriverManager::add_driver(&driver_alsa); #endif + layered_window = false; minimized = false; xim_style = 0L; mouse_mode = MOUSE_MODE_VISIBLE; diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 0a39da77de..09ed9588c4 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -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; |