summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/AndroidManifest.xml.template2
-rw-r--r--platform/android/build.gradle.template1
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java10
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java8
-rw-r--r--platform/iphone/app_delegate.mm21
-rw-r--r--platform/javascript/engine.js21
-rw-r--r--platform/javascript/export/export.cpp2
-rw-r--r--platform/javascript/os_javascript.cpp12
-rw-r--r--platform/osx/os_osx.h6
-rw-r--r--platform/osx/os_osx.mm160
-rw-r--r--platform/server/os_server.cpp6
-rw-r--r--platform/server/os_server.h3
-rw-r--r--platform/uwp/export/export.cpp4
-rw-r--r--platform/windows/os_windows.cpp170
-rw-r--r--platform/windows/os_windows.h13
-rw-r--r--platform/x11/context_gl_x11.cpp83
-rw-r--r--platform/x11/context_gl_x11.h1
-rw-r--r--platform/x11/detect.py6
-rw-r--r--platform/x11/os_x11.cpp81
-rw-r--r--platform/x11/os_x11.h6
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;