mirror of https://github.com/libsdl-org/SDL
Add support for modal windows to more platforms
- Adds support for modal windows to Win32, Mac, and Haiku, and enhances functionality on Wayland and X11, which previous set only the parent window, but not the modal state. - Windows can be declared modal at creation time, and the modal state can be toggled at any time via SDL_SetWindowModalFor() (tested with UE5 through sdl2-compat). - Allows dynamic unparenting/reparenting of windows. - Includes a modal window test.
This commit is contained in:
parent
97f7b4620a
commit
c6a70d6898
|
@ -144,6 +144,7 @@ typedef Uint32 SDL_WindowFlags;
|
||||||
#define SDL_WINDOW_INPUT_FOCUS 0x00000200U /**< window has input focus */
|
#define SDL_WINDOW_INPUT_FOCUS 0x00000200U /**< window has input focus */
|
||||||
#define SDL_WINDOW_MOUSE_FOCUS 0x00000400U /**< window has mouse focus */
|
#define SDL_WINDOW_MOUSE_FOCUS 0x00000400U /**< window has mouse focus */
|
||||||
#define SDL_WINDOW_EXTERNAL 0x00000800U /**< window not created by SDL */
|
#define SDL_WINDOW_EXTERNAL 0x00000800U /**< window not created by SDL */
|
||||||
|
#define SDL_WINDOW_MODAL 0x00001000U /**< window is modal */
|
||||||
#define SDL_WINDOW_HIGH_PIXEL_DENSITY 0x00002000U /**< window uses high pixel density back buffer if possible */
|
#define SDL_WINDOW_HIGH_PIXEL_DENSITY 0x00002000U /**< window uses high pixel density back buffer if possible */
|
||||||
#define SDL_WINDOW_MOUSE_CAPTURE 0x00004000U /**< window has mouse captured (unrelated to MOUSE_GRABBED) */
|
#define SDL_WINDOW_MOUSE_CAPTURE 0x00004000U /**< window has mouse captured (unrelated to MOUSE_GRABBED) */
|
||||||
#define SDL_WINDOW_ALWAYS_ON_TOP 0x00008000U /**< window should always be above others */
|
#define SDL_WINDOW_ALWAYS_ON_TOP 0x00008000U /**< window should always be above others */
|
||||||
|
@ -907,13 +908,15 @@ extern DECLSPEC SDL_Window *SDLCALL SDL_CreatePopupWindow(SDL_Window *parent, in
|
||||||
* with Metal rendering
|
* with Metal rendering
|
||||||
* - `SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN`: true if the window should
|
* - `SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN`: true if the window should
|
||||||
* start minimized
|
* start minimized
|
||||||
|
* - `SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN`: true if the window is modal to its
|
||||||
|
* parent
|
||||||
* - `SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN`: true if the window starts
|
* - `SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN`: true if the window starts
|
||||||
* with grabbed mouse focus
|
* with grabbed mouse focus
|
||||||
* - `SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN`: true if the window will be used
|
* - `SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN`: true if the window will be used
|
||||||
* with OpenGL rendering
|
* with OpenGL rendering
|
||||||
* - `SDL_PROP_WINDOW_CREATE_PARENT_POINTER`: an SDL_Window that will be the
|
* - `SDL_PROP_WINDOW_CREATE_PARENT_POINTER`: an SDL_Window that will be the
|
||||||
* parent of this window, required for windows with the "toolip" and "menu"
|
* parent of this window, required for windows with the "toolip", "menu", and
|
||||||
* properties
|
* "modal" properties
|
||||||
* - `SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN`: true if the window should be
|
* - `SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN`: true if the window should be
|
||||||
* resizable
|
* resizable
|
||||||
* - `SDL_PROP_WINDOW_CREATE_TITLE_STRING`: the title of the window, in UTF-8
|
* - `SDL_PROP_WINDOW_CREATE_TITLE_STRING`: the title of the window, in UTF-8
|
||||||
|
@ -1008,6 +1011,7 @@ extern DECLSPEC SDL_Window *SDLCALL SDL_CreateWindowWithProperties(SDL_Propertie
|
||||||
#define SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN "menu"
|
#define SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN "menu"
|
||||||
#define SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN "metal"
|
#define SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN "metal"
|
||||||
#define SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN "minimized"
|
#define SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN "minimized"
|
||||||
|
#define SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN "modal"
|
||||||
#define SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN "mouse_grabbed"
|
#define SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN "mouse_grabbed"
|
||||||
#define SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN "opengl"
|
#define SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN "opengl"
|
||||||
#define SDL_PROP_WINDOW_CREATE_PARENT_POINTER "parent"
|
#define SDL_PROP_WINDOW_CREATE_PARENT_POINTER "parent"
|
||||||
|
@ -2000,7 +2004,12 @@ extern DECLSPEC int SDLCALL SDL_SetWindowOpacity(SDL_Window *window, float opaci
|
||||||
extern DECLSPEC int SDLCALL SDL_GetWindowOpacity(SDL_Window *window, float *out_opacity);
|
extern DECLSPEC int SDLCALL SDL_GetWindowOpacity(SDL_Window *window, float *out_opacity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the window as a modal for another window.
|
* Set the window as a modal to a parent window.
|
||||||
|
*
|
||||||
|
* If the window is already modal to an existing window, it will be reparented to the new owner.
|
||||||
|
* Setting the parent window to null unparents the modal window and removes modal status.
|
||||||
|
*
|
||||||
|
* Setting a window as modal to a parent that is a descendent of the modal window results in undefined behavior.
|
||||||
*
|
*
|
||||||
* \param modal_window the window that should be set modal
|
* \param modal_window the window that should be set modal
|
||||||
* \param parent_window the parent window for the modal window
|
* \param parent_window the parent window for the modal window
|
||||||
|
@ -2181,6 +2190,8 @@ extern DECLSPEC int SDLCALL SDL_FlashWindow(SDL_Window *window, SDL_FlashOperati
|
||||||
/**
|
/**
|
||||||
* Destroy a window.
|
* Destroy a window.
|
||||||
*
|
*
|
||||||
|
* Any popups or modal windows owned by the window will be recursively destroyed as well.
|
||||||
|
*
|
||||||
* If `window` is NULL, this function will return immediately after setting
|
* If `window` is NULL, this function will return immediately after setting
|
||||||
* the SDL error message to "Invalid window". See SDL_GetError().
|
* the SDL error message to "Invalid window". See SDL_GetError().
|
||||||
*
|
*
|
||||||
|
|
|
@ -200,6 +200,33 @@ static void SDL_SyncIfRequired(SDL_Window *window)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent)
|
||||||
|
{
|
||||||
|
/* Unlink the window from the existing parent. */
|
||||||
|
if (window->parent) {
|
||||||
|
if (window->next_sibling) {
|
||||||
|
window->next_sibling->prev_sibling = window->prev_sibling;
|
||||||
|
}
|
||||||
|
if (window->prev_sibling) {
|
||||||
|
window->prev_sibling->next_sibling = window->next_sibling;
|
||||||
|
} else {
|
||||||
|
window->parent->first_child = window->next_sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
window->parent = parent;
|
||||||
|
|
||||||
|
window->next_sibling = parent->first_child;
|
||||||
|
if (parent->first_child) {
|
||||||
|
parent->first_child->prev_sibling = window;
|
||||||
|
}
|
||||||
|
parent->first_child = window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Support for framebuffer emulation using an accelerated renderer */
|
/* Support for framebuffer emulation using an accelerated renderer */
|
||||||
|
|
||||||
#define SDL_PROP_WINDOW_TEXTUREDATA_POINTER "SDL.internal.window.texturedata"
|
#define SDL_PROP_WINDOW_TEXTUREDATA_POINTER "SDL.internal.window.texturedata"
|
||||||
|
@ -2002,6 +2029,7 @@ static struct {
|
||||||
{ SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, SDL_WINDOW_POPUP_MENU, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, SDL_WINDOW_POPUP_MENU, SDL_FALSE },
|
||||||
{ SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN, SDL_WINDOW_METAL, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN, SDL_WINDOW_METAL, SDL_FALSE },
|
||||||
{ SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN, SDL_WINDOW_MINIMIZED, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN, SDL_WINDOW_MINIMIZED, SDL_FALSE },
|
||||||
|
{ SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN, SDL_WINDOW_MODAL, SDL_FALSE },
|
||||||
{ SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN, SDL_WINDOW_MOUSE_GRABBED, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN, SDL_WINDOW_MOUSE_GRABBED, SDL_FALSE },
|
||||||
{ SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, SDL_WINDOW_OPENGL, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, SDL_WINDOW_OPENGL, SDL_FALSE },
|
||||||
{ SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, SDL_WINDOW_RESIZABLE, SDL_FALSE },
|
{ SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, SDL_WINDOW_RESIZABLE, SDL_FALSE },
|
||||||
|
@ -2057,6 +2085,11 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & SDL_WINDOW_MODAL) && (!parent || parent->magic != &_this->window_magic)) {
|
||||||
|
SDL_SetError("Modal windows must specify a parent window");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) != 0) {
|
if ((flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) != 0) {
|
||||||
if (!(_this->device_caps & VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT)) {
|
if (!(_this->device_caps & VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT)) {
|
||||||
SDL_Unsupported();
|
SDL_Unsupported();
|
||||||
|
@ -2074,7 +2107,7 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure no more than one of these flags is set */
|
/* Ensure no more than one of these flags is set */
|
||||||
type_flags = flags & (SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU);
|
type_flags = flags & (SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_MODAL);
|
||||||
if (type_flags & (type_flags - 1)) {
|
if (type_flags & (type_flags - 1)) {
|
||||||
SDL_SetError("Conflicting window type flags specified: 0x%.8x", (unsigned int)type_flags);
|
SDL_SetError("Conflicting window type flags specified: 0x%.8x", (unsigned int)type_flags);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2200,14 +2233,9 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||||
}
|
}
|
||||||
_this->windows = window;
|
_this->windows = window;
|
||||||
|
|
||||||
if (parent) {
|
/* Set the parent before creation if this is non-modal, otherwise it will be set later. */
|
||||||
window->parent = parent;
|
if (!(flags & SDL_WINDOW_MODAL)) {
|
||||||
|
SDL_SetWindowParent(window, parent);
|
||||||
window->next_sibling = parent->first_child;
|
|
||||||
if (parent->first_child) {
|
|
||||||
parent->first_child->prev_sibling = window;
|
|
||||||
}
|
|
||||||
parent->first_child = window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->CreateSDLWindow && _this->CreateSDLWindow(_this, window, props) < 0) {
|
if (_this->CreateSDLWindow && _this->CreateSDLWindow(_this, window, props) < 0) {
|
||||||
|
@ -2236,6 +2264,9 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||||
flags = window->flags;
|
flags = window->flags;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (flags & SDL_WINDOW_MODAL) {
|
||||||
|
SDL_SetWindowModalFor(window, parent);
|
||||||
|
}
|
||||||
if (title) {
|
if (title) {
|
||||||
SDL_SetWindowTitle(window, title);
|
SDL_SetWindowTitle(window, title);
|
||||||
}
|
}
|
||||||
|
@ -2293,6 +2324,7 @@ int SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||||
SDL_bool need_vulkan_unload = SDL_FALSE;
|
SDL_bool need_vulkan_unload = SDL_FALSE;
|
||||||
SDL_bool need_vulkan_load = SDL_FALSE;
|
SDL_bool need_vulkan_load = SDL_FALSE;
|
||||||
SDL_WindowFlags graphics_flags;
|
SDL_WindowFlags graphics_flags;
|
||||||
|
SDL_Window *parent = window->parent;
|
||||||
|
|
||||||
/* ensure no more than one of these flags is set */
|
/* ensure no more than one of these flags is set */
|
||||||
graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
|
graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
|
||||||
|
@ -2317,6 +2349,11 @@ int SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||||
flags &= ~SDL_WINDOW_EXTERNAL;
|
flags &= ~SDL_WINDOW_EXTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this is a modal dialog, clear the modal status. */
|
||||||
|
if (window->flags & SDL_WINDOW_MODAL) {
|
||||||
|
SDL_SetWindowModalFor(window, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore video mode, etc. */
|
/* Restore video mode, etc. */
|
||||||
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
|
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
|
||||||
const SDL_bool restore_on_show = window->restore_on_show;
|
const SDL_bool restore_on_show = window->restore_on_show;
|
||||||
|
@ -2410,6 +2447,10 @@ int SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||||
window->flags |= SDL_WINDOW_EXTERNAL;
|
window->flags |= SDL_WINDOW_EXTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & SDL_WINDOW_MODAL) {
|
||||||
|
SDL_SetWindowModalFor(window, parent);
|
||||||
|
}
|
||||||
|
|
||||||
if (_this->SetWindowTitle && window->title) {
|
if (_this->SetWindowTitle && window->title) {
|
||||||
_this->SetWindowTitle(_this, window);
|
_this->SetWindowTitle(_this, window);
|
||||||
}
|
}
|
||||||
|
@ -3259,15 +3300,35 @@ int SDL_GetWindowOpacity(SDL_Window *window, float *out_opacity)
|
||||||
int SDL_SetWindowModalFor(SDL_Window *modal_window, SDL_Window *parent_window)
|
int SDL_SetWindowModalFor(SDL_Window *modal_window, SDL_Window *parent_window)
|
||||||
{
|
{
|
||||||
CHECK_WINDOW_MAGIC(modal_window, -1);
|
CHECK_WINDOW_MAGIC(modal_window, -1);
|
||||||
CHECK_WINDOW_MAGIC(parent_window, -1);
|
|
||||||
CHECK_WINDOW_NOT_POPUP(modal_window, -1);
|
CHECK_WINDOW_NOT_POPUP(modal_window, -1);
|
||||||
CHECK_WINDOW_NOT_POPUP(parent_window, -1);
|
|
||||||
|
if (parent_window) {
|
||||||
|
CHECK_WINDOW_MAGIC(parent_window, -1);
|
||||||
|
CHECK_WINDOW_NOT_POPUP(parent_window, -1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_this->SetWindowModalFor) {
|
if (!_this->SetWindowModalFor) {
|
||||||
return SDL_Unsupported();
|
return SDL_Unsupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _this->SetWindowModalFor(_this, modal_window, parent_window);
|
if (parent_window) {
|
||||||
|
modal_window->flags |= SDL_WINDOW_MODAL;
|
||||||
|
} else if (modal_window->flags & SDL_WINDOW_MODAL) {
|
||||||
|
modal_window->flags &= ~SDL_WINDOW_MODAL;
|
||||||
|
} else {
|
||||||
|
return 0; /* Not modal; nothing to do. */
|
||||||
|
}
|
||||||
|
|
||||||
|
const int ret = _this->SetWindowModalFor(_this, modal_window, parent_window);
|
||||||
|
|
||||||
|
/* The existing parent might be needed when changing the modal status,
|
||||||
|
* so don't change the heirarchy until after setting the new modal state.
|
||||||
|
*/
|
||||||
|
if (!ret) {
|
||||||
|
SDL_SetWindowParent(modal_window, !ret ? parent_window : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDL_SetWindowInputFocus(SDL_Window *window)
|
int SDL_SetWindowInputFocus(SDL_Window *window)
|
||||||
|
@ -3686,16 +3747,12 @@ void SDL_DestroyWindow(SDL_Window *window)
|
||||||
|
|
||||||
SDL_DestroyProperties(window->props);
|
SDL_DestroyProperties(window->props);
|
||||||
|
|
||||||
/* If this is a child window, unlink it from its siblings */
|
/* Clear the modal status, but don't unset the parent, as it may be
|
||||||
if (window->parent) {
|
* needed later in the destruction process if a backend needs to
|
||||||
if (window->next_sibling) {
|
* update the input focus.
|
||||||
window->next_sibling->prev_sibling = window->prev_sibling;
|
*/
|
||||||
}
|
if (_this->SetWindowModalFor && (window->flags & SDL_WINDOW_MODAL)) {
|
||||||
if (window->prev_sibling) {
|
_this->SetWindowModalFor(_this, window, NULL);
|
||||||
window->prev_sibling->next_sibling = window->next_sibling;
|
|
||||||
} else {
|
|
||||||
window->parent->first_child = window->next_sibling;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore video mode, etc. */
|
/* Restore video mode, etc. */
|
||||||
|
@ -3765,6 +3822,9 @@ void SDL_DestroyWindow(SDL_Window *window)
|
||||||
SDL_free(window->title);
|
SDL_free(window->title);
|
||||||
SDL_DestroySurface(window->icon);
|
SDL_DestroySurface(window->icon);
|
||||||
|
|
||||||
|
/* Unlink the window from its siblings. */
|
||||||
|
SDL_SetWindowParent(window, NULL);
|
||||||
|
|
||||||
/* Unlink the window from the list */
|
/* Unlink the window from the list */
|
||||||
if (window->next) {
|
if (window->next) {
|
||||||
window->next->prev = window->prev;
|
window->next->prev = window->prev;
|
||||||
|
|
|
@ -563,6 +563,14 @@ Uint64 Cocoa_GetEventTimestamp(NSTimeInterval nsTimestamp)
|
||||||
|
|
||||||
int Cocoa_PumpEventsUntilDate(SDL_VideoDevice *_this, NSDate *expiration, bool accumulate)
|
int Cocoa_PumpEventsUntilDate(SDL_VideoDevice *_this, NSDate *expiration, bool accumulate)
|
||||||
{
|
{
|
||||||
|
/* Run any existing modal sessions. */
|
||||||
|
for (SDL_Window *w = _this->windows; w; w = w->next) {
|
||||||
|
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)w->driverdata;
|
||||||
|
if (data.modal_session) {
|
||||||
|
[NSApp runModalSession:data.modal_session];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES];
|
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||||
if (event == nil) {
|
if (event == nil) {
|
||||||
|
|
|
@ -122,6 +122,7 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
|
||||||
device->UpdateWindowShape = Cocoa_UpdateWindowShape;
|
device->UpdateWindowShape = Cocoa_UpdateWindowShape;
|
||||||
device->FlashWindow = Cocoa_FlashWindow;
|
device->FlashWindow = Cocoa_FlashWindow;
|
||||||
device->SetWindowFocusable = Cocoa_SetWindowFocusable;
|
device->SetWindowFocusable = Cocoa_SetWindowFocusable;
|
||||||
|
device->SetWindowModalFor = Cocoa_SetWindowModalFor;
|
||||||
device->SyncWindow = Cocoa_SyncWindow;
|
device->SyncWindow = Cocoa_SyncWindow;
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_OPENGL_CGL
|
#ifdef SDL_VIDEO_OPENGL_CGL
|
||||||
|
|
|
@ -138,6 +138,7 @@ typedef enum
|
||||||
@property(nonatomic) NSInteger flash_request;
|
@property(nonatomic) NSInteger flash_request;
|
||||||
@property(nonatomic) SDL_Window *keyboard_focus;
|
@property(nonatomic) SDL_Window *keyboard_focus;
|
||||||
@property(nonatomic) Cocoa_WindowListener *listener;
|
@property(nonatomic) Cocoa_WindowListener *listener;
|
||||||
|
@property(nonatomic) NSModalSession modal_session;
|
||||||
@property(nonatomic) SDL_CocoaVideoData *videodata;
|
@property(nonatomic) SDL_CocoaVideoData *videodata;
|
||||||
@property(nonatomic) SDL_bool send_floating_size;
|
@property(nonatomic) SDL_bool send_floating_size;
|
||||||
@property(nonatomic) SDL_bool send_floating_position;
|
@property(nonatomic) SDL_bool send_floating_position;
|
||||||
|
@ -178,6 +179,7 @@ extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||||
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
|
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
|
||||||
extern int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
extern int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||||
extern int Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
extern int Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||||
|
extern int Cocoa_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||||
extern int Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
extern int Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
|
|
||||||
#endif /* SDL_cocoawindow_h_ */
|
#endif /* SDL_cocoawindow_h_ */
|
||||||
|
|
|
@ -2369,6 +2369,10 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->driverdata).nswindow;
|
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->driverdata).nswindow;
|
||||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||||
} else {
|
} else {
|
||||||
|
if ((window->flags & SDL_WINDOW_MODAL) && window->parent) {
|
||||||
|
Cocoa_SetWindowModalFor(_this, window, window->parent);
|
||||||
|
}
|
||||||
|
|
||||||
if (bActivate) {
|
if (bActivate) {
|
||||||
[nswindow makeKeyAndOrderFront:nil];
|
[nswindow makeKeyAndOrderFront:nil];
|
||||||
} else {
|
} else {
|
||||||
|
@ -2402,6 +2406,11 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
[nswindow close];
|
[nswindow close];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this window is the source of a modal session, end it when
|
||||||
|
* hidden, or other windows will be prevented from closing.
|
||||||
|
*/
|
||||||
|
Cocoa_SetWindowModalFor(_this, window, NULL);
|
||||||
|
|
||||||
/* Transfer keyboard focus back to the parent */
|
/* Transfer keyboard focus back to the parent */
|
||||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||||
if (window == SDL_GetKeyboardFocus()) {
|
if (window == SDL_GetKeyboardFocus()) {
|
||||||
|
@ -2928,6 +2937,24 @@ void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Cocoa_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
SDL_CocoaWindowData *modal_data = (__bridge SDL_CocoaWindowData *)modal_window->driverdata;
|
||||||
|
|
||||||
|
if (modal_data.modal_session) {
|
||||||
|
[NSApp endModalSession:modal_data.modal_session];
|
||||||
|
modal_data.modal_session = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent_window) {
|
||||||
|
modal_data.modal_session = [NSApp beginModalSessionForWindow:modal_data.nswindow];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation)
|
int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
|
@ -39,7 +39,7 @@ static SDL_INLINE SDL_BLooper *_GetBeLooper() {
|
||||||
return SDL_Looper;
|
return SDL_Looper;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _InitWindow(SDL_VideoDevice *_this, SDL_Window *window) {
|
static int _InitWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) {
|
||||||
uint32 flags = 0;
|
uint32 flags = 0;
|
||||||
window_look look = B_TITLED_WINDOW_LOOK;
|
window_look look = B_TITLED_WINDOW_LOOK;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ static int _InitWindow(SDL_VideoDevice *_this, SDL_Window *window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int HAIKU_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) {
|
int HAIKU_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) {
|
||||||
if (_InitWindow(_this, window) < 0) {
|
if (_InitWindow(_this, window, create_props) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +171,25 @@ int HAIKU_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window * window, SDL_bo
|
||||||
return SDL_Unsupported();
|
return SDL_Unsupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int HAIKU_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window) {
|
||||||
|
if (modal_window->parent && modal_window->parent != parent_window) {
|
||||||
|
/* Remove from the subset of a previous parent. */
|
||||||
|
_ToBeWin(modal_window)->RemoveFromSubset(_ToBeWin(modal_window->parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent_window) {
|
||||||
|
_ToBeWin(modal_window)->SetLook(B_MODAL_WINDOW_LOOK);
|
||||||
|
_ToBeWin(modal_window)->SetFeel(B_MODAL_SUBSET_WINDOW_FEEL);
|
||||||
|
_ToBeWin(modal_window)->AddToSubset(_ToBeWin(parent_window));
|
||||||
|
} else {
|
||||||
|
window_look look = (modal_window->flags & SDL_WINDOW_BORDERLESS) ? B_NO_BORDER_WINDOW_LOOK : B_TITLED_WINDOW_LOOK;
|
||||||
|
_ToBeWin(modal_window)->SetLook(look);
|
||||||
|
_ToBeWin(modal_window)->SetFeel(B_NORMAL_WINDOW_FEEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void HAIKU_DestroyWindow(SDL_VideoDevice *_this, SDL_Window * window) {
|
void HAIKU_DestroyWindow(SDL_VideoDevice *_this, SDL_Window * window) {
|
||||||
_ToBeWin(window)->LockLooper(); /* This MUST be locked */
|
_ToBeWin(window)->LockLooper(); /* This MUST be locked */
|
||||||
_GetBeLooper()->ClearID(_ToBeWin(window));
|
_GetBeLooper()->ClearID(_ToBeWin(window));
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "viewporter-client-protocol.h"
|
#include "viewporter-client-protocol.h"
|
||||||
#include "xdg-activation-v1-client-protocol.h"
|
#include "xdg-activation-v1-client-protocol.h"
|
||||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||||
|
#include "xdg-dialog-v1-client-protocol.h"
|
||||||
#include "xdg-foreign-unstable-v2-client-protocol.h"
|
#include "xdg-foreign-unstable-v2-client-protocol.h"
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
|
@ -1088,6 +1089,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
|
||||||
}
|
}
|
||||||
} else if (SDL_strcmp(interface, "zxdg_exporter_v2") == 0) {
|
} else if (SDL_strcmp(interface, "zxdg_exporter_v2") == 0) {
|
||||||
d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1);
|
d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1);
|
||||||
|
} else if (SDL_strcmp(interface, "xdg_wm_dialog_v1") == 0) {
|
||||||
|
d->xdg_wm_dialog_v1 = wl_registry_bind(d->registry, id, &xdg_wm_dialog_v1_interface, 1);
|
||||||
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
|
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
|
||||||
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
|
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
|
||||||
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
|
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
|
||||||
|
@ -1346,6 +1349,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
|
||||||
data->zxdg_exporter_v2 = NULL;
|
data->zxdg_exporter_v2 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->xdg_wm_dialog_v1) {
|
||||||
|
xdg_wm_dialog_v1_destroy(data->xdg_wm_dialog_v1);
|
||||||
|
data->xdg_wm_dialog_v1 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (data->kde_output_order) {
|
if (data->kde_output_order) {
|
||||||
Wayland_FlushOutputOrder(data);
|
Wayland_FlushOutputOrder(data);
|
||||||
kde_output_order_v1_destroy(data->kde_output_order);
|
kde_output_order_v1_destroy(data->kde_output_order);
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct SDL_VideoData
|
||||||
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
|
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
|
||||||
struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
|
struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
|
||||||
struct zxdg_exporter_v2 *zxdg_exporter_v2;
|
struct zxdg_exporter_v2 *zxdg_exporter_v2;
|
||||||
|
struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1;
|
||||||
struct kde_output_order_v1 *kde_output_order;
|
struct kde_output_order_v1 *kde_output_order;
|
||||||
|
|
||||||
struct xkb_context *xkb_context;
|
struct xkb_context *xkb_context;
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "viewporter-client-protocol.h"
|
#include "viewporter-client-protocol.h"
|
||||||
#include "fractional-scale-v1-client-protocol.h"
|
#include "fractional-scale-v1-client-protocol.h"
|
||||||
#include "xdg-foreign-unstable-v2-client-protocol.h"
|
#include "xdg-foreign-unstable-v2-client-protocol.h"
|
||||||
|
#include "xdg-dialog-v1-client-protocol.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBDECOR_H
|
#ifdef HAVE_LIBDECOR_H
|
||||||
#include <libdecor.h>
|
#include <libdecor.h>
|
||||||
|
@ -654,6 +655,8 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time
|
||||||
for (SDL_Window *w = wind->sdlwindow->first_child; w; w = w->next_sibling) {
|
for (SDL_Window *w = wind->sdlwindow->first_child; w; w = w->next_sibling) {
|
||||||
if (w->driverdata->surface_status == WAYLAND_SURFACE_STATUS_SHOW_PENDING) {
|
if (w->driverdata->surface_status == WAYLAND_SURFACE_STATUS_SHOW_PENDING) {
|
||||||
Wayland_ShowWindow(SDL_GetVideoDevice(), w);
|
Wayland_ShowWindow(SDL_GetVideoDevice(), w);
|
||||||
|
} else if ((w->flags & SDL_WINDOW_MODAL) && w->driverdata->modal_reparenting_required) {
|
||||||
|
Wayland_SetWindowModalFor(SDL_GetVideoDevice(), w, w->parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1434,35 +1437,56 @@ int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window,
|
||||||
{
|
{
|
||||||
SDL_VideoData *viddata = _this->driverdata;
|
SDL_VideoData *viddata = _this->driverdata;
|
||||||
SDL_WindowData *modal_data = modal_window->driverdata;
|
SDL_WindowData *modal_data = modal_window->driverdata;
|
||||||
SDL_WindowData *parent_data = parent_window->driverdata;
|
SDL_WindowData *parent_data = parent_window ? parent_window->driverdata : NULL;
|
||||||
|
struct xdg_toplevel *modal_toplevel = NULL;
|
||||||
|
struct xdg_toplevel *parent_toplevel = NULL;
|
||||||
|
|
||||||
if (modal_data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP || parent_data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) {
|
modal_data->modal_reparenting_required = SDL_FALSE;
|
||||||
return SDL_SetError("Modal/Parent was a popup, not a toplevel");
|
|
||||||
|
if (parent_data && parent_data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN) {
|
||||||
|
/* Need to wait for the parent to become mapped, or it's the same as setting a null parent. */
|
||||||
|
modal_data->modal_reparenting_required = SDL_TRUE;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Libdecor crashes on attempts to unset the parent by passing null, which is allowed by the
|
||||||
|
* toplevel spec, so just use the raw xdg-toplevel instead (that's what libdecor does
|
||||||
|
* internally anyways).
|
||||||
|
*/
|
||||||
#ifdef HAVE_LIBDECOR_H
|
#ifdef HAVE_LIBDECOR_H
|
||||||
if (viddata->shell.libdecor) {
|
if (modal_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && modal_data->shell_surface.libdecor.frame) {
|
||||||
if (!modal_data->shell_surface.libdecor.frame) {
|
modal_toplevel = libdecor_frame_get_xdg_toplevel(modal_data->shell_surface.libdecor.frame);
|
||||||
return SDL_SetError("Modal window was hidden");
|
|
||||||
}
|
|
||||||
if (!parent_data->shell_surface.libdecor.frame) {
|
|
||||||
return SDL_SetError("Parent window was hidden");
|
|
||||||
}
|
|
||||||
libdecor_frame_set_parent(modal_data->shell_surface.libdecor.frame,
|
|
||||||
parent_data->shell_surface.libdecor.frame);
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if (viddata->shell.xdg) {
|
if (modal_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && modal_data->shell_surface.xdg.roleobj.toplevel) {
|
||||||
if (modal_data->shell_surface.xdg.roleobj.toplevel == NULL) {
|
modal_toplevel = modal_data->shell_surface.xdg.roleobj.toplevel;
|
||||||
return SDL_SetError("Modal window was hidden");
|
}
|
||||||
|
|
||||||
|
if (parent_data) {
|
||||||
|
#ifdef HAVE_LIBDECOR_H
|
||||||
|
if (parent_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && parent_data->shell_surface.libdecor.frame) {
|
||||||
|
parent_toplevel = libdecor_frame_get_xdg_toplevel(parent_data->shell_surface.libdecor.frame);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (parent_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && parent_data->shell_surface.xdg.roleobj.toplevel) {
|
||||||
|
parent_toplevel = parent_data->shell_surface.xdg.roleobj.toplevel;
|
||||||
}
|
}
|
||||||
if (parent_data->shell_surface.xdg.roleobj.toplevel == NULL) {
|
}
|
||||||
return SDL_SetError("Parent window was hidden");
|
|
||||||
|
if (modal_toplevel) {
|
||||||
|
xdg_toplevel_set_parent(modal_toplevel, parent_toplevel);
|
||||||
|
|
||||||
|
if (viddata->xdg_wm_dialog_v1) {
|
||||||
|
if (parent_toplevel) {
|
||||||
|
if (!modal_data->xdg_dialog_v1) {
|
||||||
|
modal_data->xdg_dialog_v1 = xdg_wm_dialog_v1_get_xdg_dialog(viddata->xdg_wm_dialog_v1, modal_toplevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
xdg_dialog_v1_set_modal(modal_data->xdg_dialog_v1);
|
||||||
|
} else if (modal_data->xdg_dialog_v1) {
|
||||||
|
xdg_dialog_v1_unset_modal(modal_data->xdg_dialog_v1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xdg_toplevel_set_parent(modal_data->shell_surface.xdg.roleobj.toplevel,
|
|
||||||
parent_data->shell_surface.xdg.roleobj.toplevel);
|
|
||||||
} else {
|
|
||||||
return SDL_Unsupported();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1653,6 +1677,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore state that was set prior to this call */
|
/* Restore state that was set prior to this call */
|
||||||
|
if (window->flags & SDL_WINDOW_MODAL) {
|
||||||
|
Wayland_SetWindowModalFor(_this, window, window->parent);
|
||||||
|
}
|
||||||
|
|
||||||
Wayland_SetWindowTitle(_this, window);
|
Wayland_SetWindowTitle(_this, window);
|
||||||
|
|
||||||
/* We have to wait until the surface gets a "configure" event, or use of
|
/* We have to wait until the surface gets a "configure" event, or use of
|
||||||
|
@ -2590,6 +2618,10 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
wp_fractional_scale_v1_destroy(wind->fractional_scale);
|
wp_fractional_scale_v1_destroy(wind->fractional_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wind->xdg_dialog_v1) {
|
||||||
|
xdg_dialog_v1_destroy(wind->xdg_dialog_v1);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_free(wind->outputs);
|
SDL_free(wind->outputs);
|
||||||
SDL_free(wind->app_id);
|
SDL_free(wind->app_id);
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ struct SDL_WindowData
|
||||||
struct wp_viewport *viewport;
|
struct wp_viewport *viewport;
|
||||||
struct wp_fractional_scale_v1 *fractional_scale;
|
struct wp_fractional_scale_v1 *fractional_scale;
|
||||||
struct zxdg_exported_v2 *exported;
|
struct zxdg_exported_v2 *exported;
|
||||||
|
struct xdg_dialog_v1 *xdg_dialog_v1;
|
||||||
|
|
||||||
SDL_AtomicInt swap_interval_ready;
|
SDL_AtomicInt swap_interval_ready;
|
||||||
|
|
||||||
|
@ -172,6 +173,7 @@ struct SDL_WindowData
|
||||||
SDL_bool fullscreen_was_positioned;
|
SDL_bool fullscreen_was_positioned;
|
||||||
SDL_bool show_hide_sync_required;
|
SDL_bool show_hide_sync_required;
|
||||||
SDL_bool scale_to_display;
|
SDL_bool scale_to_display;
|
||||||
|
SDL_bool modal_reparenting_required;
|
||||||
|
|
||||||
SDL_HitTestResult hit_test_result;
|
SDL_HitTestResult hit_test_result;
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
|
||||||
device->SetWindowResizable = WIN_SetWindowResizable;
|
device->SetWindowResizable = WIN_SetWindowResizable;
|
||||||
device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
|
device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
|
||||||
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
|
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
|
||||||
|
device->SetWindowModalFor = WIN_SetWindowModalFor;
|
||||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||||
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
|
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
|
||||||
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
|
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
|
||||||
|
|
|
@ -984,6 +984,10 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
WIN_SetWindowPosition(_this, window);
|
WIN_SetWindowPosition(_this, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window->flags & SDL_WINDOW_MODAL) {
|
||||||
|
EnableWindow(window->parent->driverdata->hwnd, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
hwnd = window->driverdata->hwnd;
|
hwnd = window->driverdata->hwnd;
|
||||||
style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||||
if (style & WS_EX_NOACTIVATE) {
|
if (style & WS_EX_NOACTIVATE) {
|
||||||
|
@ -1006,6 +1010,11 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
{
|
{
|
||||||
HWND hwnd = window->driverdata->hwnd;
|
HWND hwnd = window->driverdata->hwnd;
|
||||||
|
|
||||||
|
if (window->flags & SDL_WINDOW_MODAL) {
|
||||||
|
EnableWindow(window->parent->driverdata->hwnd, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
ShowWindow(hwnd, SW_HIDE);
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
|
|
||||||
/* Transfer keyboard focus back to the parent */
|
/* Transfer keyboard focus back to the parent */
|
||||||
|
@ -1720,4 +1729,39 @@ void WIN_UpdateDarkModeForHWND(HWND hwnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WIN_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||||
|
{
|
||||||
|
SDL_WindowData *modal_data = modal_window->driverdata;
|
||||||
|
const LONG_PTR parent_hwnd = (LONG_PTR)(parent_window ? parent_window->driverdata->hwnd : NULL);
|
||||||
|
const LONG_PTR old_ptr = GetWindowLongPtr(modal_data->hwnd, GWLP_HWNDPARENT);
|
||||||
|
const DWORD style = GetWindowLong(modal_data->hwnd, GWL_STYLE);
|
||||||
|
|
||||||
|
if (old_ptr == parent_hwnd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reenable the old parent window. */
|
||||||
|
if (old_ptr) {
|
||||||
|
EnableWindow((HWND)old_ptr, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(style & WS_CHILD)) {
|
||||||
|
/* Despite the name, this changes the *owner* of a toplevel window, not
|
||||||
|
* the parent of a child window.
|
||||||
|
*
|
||||||
|
* https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613
|
||||||
|
*/
|
||||||
|
SetWindowLongPtr(modal_data->hwnd, GWLP_HWNDPARENT, parent_hwnd);
|
||||||
|
} else {
|
||||||
|
SetParent(modal_data->hwnd, (HWND)parent_hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable the new parent window if the modal window is visible. */
|
||||||
|
if (!(modal_window->flags & SDL_WINDOW_HIDDEN) && parent_hwnd) {
|
||||||
|
EnableWindow((HWND)parent_hwnd, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||||
|
|
|
@ -118,6 +118,7 @@ extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||||
extern int WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
extern int WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||||
extern int WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_WindowRect rect_type);
|
extern int WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_WindowRect rect_type);
|
||||||
extern int WIN_AdjustWindowRectForHWND(HWND hwnd, LPRECT lpRect, UINT frame_dpi);
|
extern int WIN_AdjustWindowRectForHWND(HWND hwnd, LPRECT lpRect, UINT frame_dpi);
|
||||||
|
extern int WIN_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -389,6 +389,7 @@ int X11_VideoInit(SDL_VideoDevice *_this)
|
||||||
GET_ATOM(WM_DELETE_WINDOW);
|
GET_ATOM(WM_DELETE_WINDOW);
|
||||||
GET_ATOM(WM_TAKE_FOCUS);
|
GET_ATOM(WM_TAKE_FOCUS);
|
||||||
GET_ATOM(WM_NAME);
|
GET_ATOM(WM_NAME);
|
||||||
|
GET_ATOM(WM_TRANSIENT_FOR);
|
||||||
GET_ATOM(_NET_WM_STATE);
|
GET_ATOM(_NET_WM_STATE);
|
||||||
GET_ATOM(_NET_WM_STATE_HIDDEN);
|
GET_ATOM(_NET_WM_STATE_HIDDEN);
|
||||||
GET_ATOM(_NET_WM_STATE_FOCUSED);
|
GET_ATOM(_NET_WM_STATE_FOCUSED);
|
||||||
|
@ -398,6 +399,7 @@ int X11_VideoInit(SDL_VideoDevice *_this)
|
||||||
GET_ATOM(_NET_WM_STATE_ABOVE);
|
GET_ATOM(_NET_WM_STATE_ABOVE);
|
||||||
GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
|
GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
|
||||||
GET_ATOM(_NET_WM_STATE_SKIP_PAGER);
|
GET_ATOM(_NET_WM_STATE_SKIP_PAGER);
|
||||||
|
GET_ATOM(_NET_WM_STATE_MODAL);
|
||||||
GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
|
GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
|
||||||
GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
|
GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
|
||||||
GET_ATOM(_NET_WM_NAME);
|
GET_ATOM(_NET_WM_NAME);
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct SDL_VideoData
|
||||||
Atom WM_DELETE_WINDOW;
|
Atom WM_DELETE_WINDOW;
|
||||||
Atom WM_TAKE_FOCUS;
|
Atom WM_TAKE_FOCUS;
|
||||||
Atom WM_NAME;
|
Atom WM_NAME;
|
||||||
|
Atom WM_TRANSIENT_FOR;
|
||||||
Atom _NET_WM_STATE;
|
Atom _NET_WM_STATE;
|
||||||
Atom _NET_WM_STATE_HIDDEN;
|
Atom _NET_WM_STATE_HIDDEN;
|
||||||
Atom _NET_WM_STATE_FOCUSED;
|
Atom _NET_WM_STATE_FOCUSED;
|
||||||
|
@ -76,6 +77,7 @@ struct SDL_VideoData
|
||||||
Atom _NET_WM_STATE_ABOVE;
|
Atom _NET_WM_STATE_ABOVE;
|
||||||
Atom _NET_WM_STATE_SKIP_TASKBAR;
|
Atom _NET_WM_STATE_SKIP_TASKBAR;
|
||||||
Atom _NET_WM_STATE_SKIP_PAGER;
|
Atom _NET_WM_STATE_SKIP_PAGER;
|
||||||
|
Atom _NET_WM_STATE_MODAL;
|
||||||
Atom _NET_WM_ALLOWED_ACTIONS;
|
Atom _NET_WM_ALLOWED_ACTIONS;
|
||||||
Atom _NET_WM_ACTION_FULLSCREEN;
|
Atom _NET_WM_ACTION_FULLSCREEN;
|
||||||
Atom _NET_WM_NAME;
|
Atom _NET_WM_NAME;
|
||||||
|
|
|
@ -138,6 +138,7 @@ void X11_SetNetWMState(SDL_VideoDevice *_this, Window xwindow, SDL_WindowFlags f
|
||||||
Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE;
|
Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE;
|
||||||
Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR;
|
Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR;
|
||||||
Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER;
|
Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER;
|
||||||
|
Atom _NET_WM_STATE_MODAL = videodata->_NET_WM_STATE_MODAL;
|
||||||
Atom atoms[16];
|
Atom atoms[16];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
@ -167,6 +168,9 @@ void X11_SetNetWMState(SDL_VideoDevice *_this, Window xwindow, SDL_WindowFlags f
|
||||||
if (flags & SDL_WINDOW_FULLSCREEN) {
|
if (flags & SDL_WINDOW_FULLSCREEN) {
|
||||||
atoms[count++] = _NET_WM_STATE_FULLSCREEN;
|
atoms[count++] = _NET_WM_STATE_FULLSCREEN;
|
||||||
}
|
}
|
||||||
|
if (flags & SDL_WINDOW_MODAL) {
|
||||||
|
atoms[count++] = _NET_WM_STATE_MODAL;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_assert(count <= SDL_arraysize(atoms));
|
SDL_assert(count <= SDL_arraysize(atoms));
|
||||||
|
|
||||||
|
@ -1204,10 +1208,43 @@ int X11_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opaci
|
||||||
int X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
int X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *data = modal_window->driverdata;
|
SDL_WindowData *data = modal_window->driverdata;
|
||||||
SDL_WindowData *parent_data = parent_window->driverdata;
|
SDL_WindowData *parent_data = parent_window ? parent_window->driverdata : NULL;
|
||||||
Display *display = data->videodata->display;
|
SDL_VideoData *video_data = _this->driverdata;
|
||||||
|
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(modal_window);
|
||||||
|
Display *display = video_data->display;
|
||||||
|
Uint32 flags = modal_window->flags;
|
||||||
|
Atom _NET_WM_STATE = data->videodata->_NET_WM_STATE;
|
||||||
|
Atom _NET_WM_STATE_MODAL = data->videodata->_NET_WM_STATE_MODAL;
|
||||||
|
|
||||||
|
if (parent_data) {
|
||||||
|
flags |= SDL_WINDOW_MODAL;
|
||||||
|
X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
|
||||||
|
} else {
|
||||||
|
flags &= ~SDL_WINDOW_MODAL;
|
||||||
|
X11_XDeleteProperty(display, data->xwindow, video_data->WM_TRANSIENT_FOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (X11_IsWindowMapped(_this, modal_window)) {
|
||||||
|
XEvent e;
|
||||||
|
|
||||||
|
SDL_zero(e);
|
||||||
|
e.xany.type = ClientMessage;
|
||||||
|
e.xclient.message_type = _NET_WM_STATE;
|
||||||
|
e.xclient.format = 32;
|
||||||
|
e.xclient.window = data->xwindow;
|
||||||
|
e.xclient.data.l[0] =
|
||||||
|
parent_data ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||||
|
e.xclient.data.l[1] = _NET_WM_STATE_MODAL;
|
||||||
|
e.xclient.data.l[3] = 0l;
|
||||||
|
|
||||||
|
X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
|
||||||
|
SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||||
|
} else {
|
||||||
|
X11_SetNetWMState(_this, data->xwindow, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
X11_XFlush(display);
|
||||||
|
|
||||||
X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,6 +414,7 @@ add_sdl_test_executable(testpopup SOURCES testpopup.c)
|
||||||
add_sdl_test_executable(testdialog SOURCES testdialog.c)
|
add_sdl_test_executable(testdialog SOURCES testdialog.c)
|
||||||
add_sdl_test_executable(testtime SOURCES testtime.c)
|
add_sdl_test_executable(testtime SOURCES testtime.c)
|
||||||
add_sdl_test_executable(testmanymouse SOURCES testmanymouse.c)
|
add_sdl_test_executable(testmanymouse SOURCES testmanymouse.c)
|
||||||
|
add_sdl_test_executable(testmodal SOURCES testmodal.c)
|
||||||
|
|
||||||
if (HAVE_WAYLAND)
|
if (HAVE_WAYLAND)
|
||||||
# Set the GENERATED property on the protocol file, since it is first created at build time
|
# Set the GENERATED property on the protocol file, since it is first created at build time
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely.
|
||||||
|
*/
|
||||||
|
/* Sample program: Create a parent window and a modal child window. */
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
#include <SDL3/SDL_test.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
SDL_Window *w1 = NULL, *w2 = NULL;
|
||||||
|
SDL_Renderer *r1 = NULL, *r2 = NULL;
|
||||||
|
SDLTest_CommonState *state = NULL;
|
||||||
|
Uint64 show_deadline = 0;
|
||||||
|
int i;
|
||||||
|
int exit_code = 0;
|
||||||
|
|
||||||
|
/* Initialize test framework */
|
||||||
|
state = SDLTest_CommonCreateState(argv, 0);
|
||||||
|
if (state == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable standard application logging */
|
||||||
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
||||||
|
|
||||||
|
/* Parse commandline */
|
||||||
|
for (i = 1; i < argc;) {
|
||||||
|
int consumed;
|
||||||
|
|
||||||
|
consumed = SDLTest_CommonArg(state, i);
|
||||||
|
|
||||||
|
if (consumed <= 0) {
|
||||||
|
static const char *options[] = { NULL };
|
||||||
|
SDLTest_CommonLogUsage(state, argv[0], options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
|
SDL_Log("SDL_Init failed (%s)", SDL_GetError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_CreateWindowAndRenderer("Parent Window", 640, 480, 0, &w1, &r1)) {
|
||||||
|
SDL_Log("Failed to create parent window and/or renderer: %s\n", SDL_GetError());
|
||||||
|
exit_code = 1;
|
||||||
|
goto sdl_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_CreateWindowAndRenderer("Non-Modal Window", 320, 200, 0, &w2, &r2);
|
||||||
|
if (!w2) {
|
||||||
|
SDL_Log("Failed to create parent window and/or renderer: %s\n", SDL_GetError());
|
||||||
|
exit_code = 1;
|
||||||
|
goto sdl_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||||
|
SDL_SetWindowTitle(w2, "Modal Window");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int quit = 0;
|
||||||
|
SDL_Event e;
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
if (e.type == SDL_EVENT_QUIT) {
|
||||||
|
quit = 1;
|
||||||
|
break;
|
||||||
|
} else if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
|
||||||
|
if (e.window.windowID == SDL_GetWindowID(w2)) {
|
||||||
|
SDL_DestroyRenderer(r2);
|
||||||
|
SDL_DestroyWindow(w2);
|
||||||
|
r2 = NULL;
|
||||||
|
w2 = NULL;
|
||||||
|
} else if (e.window.windowID == SDL_GetWindowID(w1)) {
|
||||||
|
SDL_DestroyRenderer(r1);
|
||||||
|
SDL_DestroyWindow(w1);
|
||||||
|
r1 = NULL;
|
||||||
|
w1 = NULL;
|
||||||
|
}
|
||||||
|
} else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
if ((e.key.keysym.sym == SDLK_m || e.key.keysym.sym == SDLK_n) && !w2) {
|
||||||
|
if (SDL_CreateWindowAndRenderer("Non-Modal Window", 320, 200, SDL_WINDOW_HIDDEN, &w2, &r2) < 0) {
|
||||||
|
SDL_Log("Failed to create modal window and/or renderer: %s\n", SDL_GetError());
|
||||||
|
exit_code = 1;
|
||||||
|
goto sdl_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key.keysym.sym == SDLK_m) {
|
||||||
|
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||||
|
SDL_SetWindowTitle(w2, "Modal Window");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_ShowWindow(w2);
|
||||||
|
} else if (e.key.keysym.sym == SDLK_ESCAPE && w2) {
|
||||||
|
SDL_DestroyWindow(w2);
|
||||||
|
r2 = NULL;
|
||||||
|
w2 = NULL;
|
||||||
|
} else if (e.key.keysym.sym == SDLK_h) {
|
||||||
|
if (e.key.keysym.mod & SDL_KMOD_CTRL) {
|
||||||
|
/* Hide the parent, which should hide the modal too. */
|
||||||
|
show_deadline = SDL_GetTicksNS() + SDL_SECONDS_TO_NS(3);
|
||||||
|
SDL_HideWindow(w1);
|
||||||
|
} else if (w2) {
|
||||||
|
/* Show/hide the modal window */
|
||||||
|
if (SDL_GetWindowFlags(w2) & SDL_WINDOW_HIDDEN) {
|
||||||
|
SDL_ShowWindow(w2);
|
||||||
|
} else {
|
||||||
|
SDL_HideWindow(w2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (e.key.keysym.sym == SDLK_p && w2) {
|
||||||
|
if (SDL_GetWindowFlags(w2) & SDL_WINDOW_MODAL) {
|
||||||
|
/* Unparent the window */
|
||||||
|
if (!SDL_SetWindowModalFor(w2, NULL)) {
|
||||||
|
SDL_SetWindowTitle(w2, "Non-Modal Window");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Reparent the window */
|
||||||
|
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||||
|
SDL_SetWindowTitle(w2, "Modal Window");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (quit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SDL_Delay(100);
|
||||||
|
|
||||||
|
if (show_deadline && show_deadline <= SDL_GetTicksNS()) {
|
||||||
|
SDL_ShowWindow(w1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parent window is red */
|
||||||
|
if (r1) {
|
||||||
|
SDL_SetRenderDrawColor(r1, 224, 48, 12, SDL_ALPHA_OPAQUE);
|
||||||
|
SDL_RenderClear(r1);
|
||||||
|
SDL_RenderPresent(r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Child window is blue */
|
||||||
|
if (r2) {
|
||||||
|
SDL_SetRenderDrawColor(r2, 6, 76, 255, SDL_ALPHA_OPAQUE);
|
||||||
|
SDL_RenderClear(r2);
|
||||||
|
SDL_RenderPresent(r2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdl_quit:
|
||||||
|
if (w1) {
|
||||||
|
/* The child window and renderer will be cleaned up automatically. */
|
||||||
|
SDL_DestroyWindow(w1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
SDLTest_CommonDestroyState(state);
|
||||||
|
return exit_code;
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="xdg_dialog_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2023 Carlos Garnacho
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="xdg_wm_dialog_v1" version="1">
|
||||||
|
<description summary="create dialogs related to other toplevels">
|
||||||
|
The xdg_wm_dialog_v1 interface is exposed as a global object allowing
|
||||||
|
to register surfaces with a xdg_toplevel role as "dialogs" relative to
|
||||||
|
another toplevel.
|
||||||
|
|
||||||
|
The compositor may let this relation influence how the surface is
|
||||||
|
placed, displayed or interacted with.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is currently in the testing
|
||||||
|
phase. Backward compatible changes may be added together with the
|
||||||
|
corresponding interface version bump. Backward incompatible changes can
|
||||||
|
only be done by creating a new major version of the extension.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_used" value="0"
|
||||||
|
summary="the xdg_toplevel object has already been used to create a xdg_dialog_v1"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the dialog manager object">
|
||||||
|
Destroys the xdg_wm_dialog_v1 object. This does not affect
|
||||||
|
the xdg_dialog_v1 objects generated through it.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="get_xdg_dialog">
|
||||||
|
<description summary="create a dialog object">
|
||||||
|
Creates a xdg_dialog_v1 object for the given toplevel. See the interface
|
||||||
|
description for more details.
|
||||||
|
|
||||||
|
Compositors must raise an already_used error if clients attempt to
|
||||||
|
create multiple xdg_dialog_v1 objects for the same xdg_toplevel.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="xdg_dialog_v1"/>
|
||||||
|
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="xdg_dialog_v1" version="1">
|
||||||
|
<description summary="dialog object">
|
||||||
|
A xdg_dialog_v1 object is an ancillary object tied to a xdg_toplevel. Its
|
||||||
|
purpose is hinting the compositor that the toplevel is a "dialog" (e.g. a
|
||||||
|
temporary window) relative to another toplevel (see
|
||||||
|
xdg_toplevel.set_parent). If the xdg_toplevel is destroyed, the xdg_dialog_v1
|
||||||
|
becomes inert.
|
||||||
|
|
||||||
|
Through this object, the client may provide additional hints about
|
||||||
|
the purpose of the secondary toplevel. This interface has no effect
|
||||||
|
on toplevels that are not attached to a parent toplevel.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the dialog object">
|
||||||
|
Destroys the xdg_dialog_v1 object. If this object is destroyed
|
||||||
|
before the related xdg_toplevel, the compositor should unapply its
|
||||||
|
effects.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_modal">
|
||||||
|
<description summary="mark dialog as modal">
|
||||||
|
Hints that the dialog has "modal" behavior. Modal dialogs typically
|
||||||
|
require to be fully addressed by the user (i.e. closed) before resuming
|
||||||
|
interaction with the parent toplevel, and may require a distinct
|
||||||
|
presentation.
|
||||||
|
|
||||||
|
Clients must implement the logic to filter events in the parent
|
||||||
|
toplevel on their own.
|
||||||
|
|
||||||
|
Compositors may choose any policy in event delivery to the parent
|
||||||
|
toplevel, from delivering all events unfiltered to using them for
|
||||||
|
internal consumption.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="unset_modal">
|
||||||
|
<description summary="mark dialog as not modal">
|
||||||
|
Drops the hint that this dialog has "modal" behavior. See
|
||||||
|
xdg_dialog_v1.set_modal for more details.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
Loading…
Reference in New Issue