mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-27 05:43:29 +08:00
video: Allow setting the parents of toplevel windows
Allow setting a parent/child relationship on toplevel windows, which allows raising sets of windows together, and allows child windows to always float above their parents. Modal windows are now set by setting the parent, then toggling modal status, as the previous interface duplicated functionality now handled by SDL_SetWindowParent().
This commit is contained in:
parent
af4c6682ce
commit
a46e7027ce
@ -2223,24 +2223,47 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetWindowOpacity(SDL_Window *window, fl
|
||||
*/
|
||||
extern SDL_DECLSPEC float SDLCALL SDL_GetWindowOpacity(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Set the window as a modal to a parent window.
|
||||
/**
|
||||
* Set the window as a child of 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.
|
||||
* If the window is already the child of an existing window, it will be reparented
|
||||
* to the new owner. Setting the parent window to null unparents the window and
|
||||
* removes child window status.
|
||||
*
|
||||
* Setting a window as modal to a parent that is a descendent of the modal
|
||||
* Attempting to set the parent of a window that is currently in the modal state will fail.
|
||||
* Use SDL_SetWindowModalFor() to cancel the modal status before attempting to change
|
||||
* the parent.
|
||||
*
|
||||
* Setting a parent window that is currently the sibling or descendent of the child
|
||||
* window results in undefined behavior.
|
||||
*
|
||||
* \param modal_window the window that should be set modal.
|
||||
* \param parent_window the parent window for the modal window.
|
||||
* \param window the window that should become the child of a parent.
|
||||
* \param parent the new parent window for the child window.
|
||||
* \returns SDL_TRUE on success or SDL_FALSE on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_SetWindowModal
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent);
|
||||
|
||||
/**
|
||||
* Toggle the state of the window as modal.
|
||||
*
|
||||
* To enable modal status on a window, the window must currently be the child window of a parent,
|
||||
* or toggling modal status on will fail.
|
||||
*
|
||||
* \param window the window on which to set the modal state.
|
||||
* \param modal SDL_TRUE to toggle modal status on, SDL_FALSE to toggle it off.
|
||||
* \returns SDL_TRUE on success or SDL_FALSE on failure; call SDL_GetError()
|
||||
* for more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_SetWindowParent
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetWindowModalFor(SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetWindowModal(SDL_Window *window, SDL_bool modal);
|
||||
|
||||
/**
|
||||
* Set whether the window may have input focus.
|
||||
|
@ -854,10 +854,11 @@ SDL3_0.0.0 {
|
||||
SDL_SetWindowKeyboardGrab;
|
||||
SDL_SetWindowMaximumSize;
|
||||
SDL_SetWindowMinimumSize;
|
||||
SDL_SetWindowModalFor;
|
||||
SDL_SetWindowModal;
|
||||
SDL_SetWindowMouseGrab;
|
||||
SDL_SetWindowMouseRect;
|
||||
SDL_SetWindowOpacity;
|
||||
SDL_SetWindowParent;
|
||||
SDL_SetWindowPosition;
|
||||
SDL_SetWindowRelativeMouseMode;
|
||||
SDL_SetWindowResizable;
|
||||
|
@ -879,10 +879,11 @@
|
||||
#define SDL_SetWindowKeyboardGrab SDL_SetWindowKeyboardGrab_REAL
|
||||
#define SDL_SetWindowMaximumSize SDL_SetWindowMaximumSize_REAL
|
||||
#define SDL_SetWindowMinimumSize SDL_SetWindowMinimumSize_REAL
|
||||
#define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL
|
||||
#define SDL_SetWindowModal SDL_SetWindowModal_REAL
|
||||
#define SDL_SetWindowMouseGrab SDL_SetWindowMouseGrab_REAL
|
||||
#define SDL_SetWindowMouseRect SDL_SetWindowMouseRect_REAL
|
||||
#define SDL_SetWindowOpacity SDL_SetWindowOpacity_REAL
|
||||
#define SDL_SetWindowParent SDL_SetWindowParent_REAL
|
||||
#define SDL_SetWindowPosition SDL_SetWindowPosition_REAL
|
||||
#define SDL_SetWindowRelativeMouseMode SDL_SetWindowRelativeMouseMode_REAL
|
||||
#define SDL_SetWindowResizable SDL_SetWindowResizable_REAL
|
||||
|
@ -889,10 +889,11 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowIcon,(SDL_Window *a, SDL_Surface *b),(a,b)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowKeyboardGrab,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowMaximumSize,(SDL_Window *a, int b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowMinimumSize,(SDL_Window *a, int b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowModal,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowMouseGrab,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowMouseRect,(SDL_Window *a, const SDL_Rect *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowOpacity,(SDL_Window *a, float b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowParent,(SDL_Window *a, SDL_Window *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowPosition,(SDL_Window *a, int b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowRelativeMouseMode,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
|
@ -264,7 +264,8 @@ struct SDL_VideoDevice
|
||||
bool (*GetWindowBordersSize)(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
|
||||
void (*GetWindowSizeInPixels)(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
bool (*SetWindowOpacity)(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
bool (*SetWindowModalFor)(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
bool (*SetWindowParent)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
bool (*SetWindowModal)(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
void (*ShowWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
void (*HideWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
void (*RaiseWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
@ -219,7 +219,7 @@ static void SDL_SyncIfRequired(SDL_Window *window)
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent)
|
||||
static void SDL_UpdateWindowHierarchy(SDL_Window *window, SDL_Window *parent)
|
||||
{
|
||||
// Unlink the window from the existing parent.
|
||||
if (window->parent) {
|
||||
@ -2169,6 +2169,10 @@ static void ApplyWindowFlags(SDL_Window *window, SDL_WindowFlags flags)
|
||||
SDL_MinimizeWindow(window);
|
||||
}
|
||||
|
||||
if (flags & SDL_WINDOW_MODAL) {
|
||||
SDL_SetWindowModal(window, true);
|
||||
}
|
||||
|
||||
if (flags & SDL_WINDOW_MOUSE_GRABBED) {
|
||||
SDL_SetWindowMouseGrab(window, true);
|
||||
}
|
||||
@ -2432,10 +2436,8 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||
}
|
||||
_this->windows = window;
|
||||
|
||||
// Set the parent before creation if this is non-modal, otherwise it will be set later.
|
||||
if (!(flags & SDL_WINDOW_MODAL)) {
|
||||
SDL_SetWindowParent(window, parent);
|
||||
}
|
||||
// Set the parent before creation.
|
||||
SDL_UpdateWindowHierarchy(window, parent);
|
||||
|
||||
if (_this->CreateSDLWindow && !_this->CreateSDLWindow(_this, window, props)) {
|
||||
SDL_DestroyWindow(window);
|
||||
@ -2462,10 +2464,6 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||
*/
|
||||
flags = window->flags;
|
||||
#endif
|
||||
|
||||
if (flags & SDL_WINDOW_MODAL) {
|
||||
SDL_SetWindowModalFor(window, parent);
|
||||
}
|
||||
if (title) {
|
||||
SDL_SetWindowTitle(window, title);
|
||||
}
|
||||
@ -2525,7 +2523,6 @@ bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||
bool need_vulkan_unload = false;
|
||||
bool need_vulkan_load = false;
|
||||
SDL_WindowFlags graphics_flags;
|
||||
SDL_Window *parent = window->parent;
|
||||
|
||||
// ensure no more than one of these flags is set
|
||||
graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
|
||||
@ -2552,7 +2549,7 @@ bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||
|
||||
// If this is a modal dialog, clear the modal status.
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
SDL_SetWindowModalFor(window, NULL);
|
||||
SDL_SetWindowModal(window, false);
|
||||
}
|
||||
|
||||
// Restore video mode, etc.
|
||||
@ -2642,10 +2639,6 @@ bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags)
|
||||
window->flags |= SDL_WINDOW_EXTERNAL;
|
||||
}
|
||||
|
||||
if (flags & SDL_WINDOW_MODAL) {
|
||||
SDL_SetWindowModalFor(window, parent);
|
||||
}
|
||||
|
||||
if (_this->SetWindowTitle && window->title) {
|
||||
_this->SetWindowTitle(_this, window);
|
||||
}
|
||||
@ -3579,40 +3572,59 @@ float SDL_GetWindowOpacity(SDL_Window *window)
|
||||
return window->opacity;
|
||||
}
|
||||
|
||||
SDL_bool SDL_SetWindowModalFor(SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
SDL_bool SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent)
|
||||
{
|
||||
bool result;
|
||||
CHECK_WINDOW_MAGIC(window, false);
|
||||
CHECK_WINDOW_NOT_POPUP(window, false);
|
||||
|
||||
CHECK_WINDOW_MAGIC(modal_window, false);
|
||||
CHECK_WINDOW_NOT_POPUP(modal_window, false);
|
||||
|
||||
if (parent_window) {
|
||||
CHECK_WINDOW_MAGIC(parent_window, false);
|
||||
CHECK_WINDOW_NOT_POPUP(parent_window, false);
|
||||
if (parent) {
|
||||
CHECK_WINDOW_MAGIC(parent, false);
|
||||
CHECK_WINDOW_NOT_POPUP(parent, false);
|
||||
}
|
||||
|
||||
if (!_this->SetWindowModalFor) {
|
||||
if (!_this->SetWindowParent) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
if (parent_window) {
|
||||
modal_window->flags |= SDL_WINDOW_MODAL;
|
||||
} else if (modal_window->flags & SDL_WINDOW_MODAL) {
|
||||
modal_window->flags &= ~SDL_WINDOW_MODAL;
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
return SDL_SetError("Modal windows cannot change parents; call SDL_SetWindowModal() to clear modal status first.");
|
||||
}
|
||||
|
||||
if (window->parent == parent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const SDL_bool ret = _this->SetWindowParent(_this, window, parent);
|
||||
SDL_UpdateWindowHierarchy(window, ret ? parent : NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SDL_bool SDL_SetWindowModal(SDL_Window *window, SDL_bool modal)
|
||||
{
|
||||
CHECK_WINDOW_MAGIC(window, false);
|
||||
CHECK_WINDOW_NOT_POPUP(window, false);
|
||||
|
||||
if (!_this->SetWindowModal) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
if (modal) {
|
||||
if (!window->parent) {
|
||||
return SDL_SetError("Window must have a parent to enable the modal state; use SDL_SetWindowParent() to set the parent first.");
|
||||
}
|
||||
window->flags |= SDL_WINDOW_MODAL;
|
||||
} else if (window->flags & SDL_WINDOW_MODAL) {
|
||||
window->flags &= ~SDL_WINDOW_MODAL;
|
||||
} else {
|
||||
return true; // Not modal; nothing to do.
|
||||
return true; // Already not modal, so nothing to do.
|
||||
}
|
||||
|
||||
result = _this->SetWindowModalFor(_this, modal_window, parent_window);
|
||||
|
||||
/* The existing parent might be needed when changing the modal status,
|
||||
* so don't change the hierarchy until after setting the new modal state.
|
||||
*/
|
||||
if (result) {
|
||||
SDL_SetWindowParent(modal_window, parent_window);
|
||||
if (window->flags & SDL_WINDOW_HIDDEN) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
return _this->SetWindowModal(_this, window, modal);
|
||||
}
|
||||
|
||||
SDL_bool SDL_SetWindowFocusable(SDL_Window *window, SDL_bool focusable)
|
||||
@ -4101,12 +4113,12 @@ void SDL_DestroyWindow(SDL_Window *window)
|
||||
SDL_DestroyProperties(window->text_input_props);
|
||||
SDL_DestroyProperties(window->props);
|
||||
|
||||
/* Clear the modal status, but don't unset the parent, as it may be
|
||||
* needed later in the destruction process if a backend needs to
|
||||
* update the input focus.
|
||||
/* Clear the modal status, but don't unset the parent just yet, as it
|
||||
* may be needed later in the destruction process if a backend needs
|
||||
* to update the input focus.
|
||||
*/
|
||||
if (_this->SetWindowModalFor && (window->flags & SDL_WINDOW_MODAL)) {
|
||||
_this->SetWindowModalFor(_this, window, NULL);
|
||||
if (_this->SetWindowModal && (window->flags & SDL_WINDOW_MODAL)) {
|
||||
_this->SetWindowModal(_this, window, false);
|
||||
}
|
||||
|
||||
// Make sure the destroyed window isn't referenced by any display as a fullscreen window.
|
||||
@ -4168,9 +4180,9 @@ void SDL_DestroyWindow(SDL_Window *window)
|
||||
SDL_DestroySurface(window->icon);
|
||||
|
||||
// Unlink the window from its siblings.
|
||||
SDL_SetWindowParent(window, NULL);
|
||||
SDL_UpdateWindowHierarchy(window, NULL);
|
||||
|
||||
// Unlink the window from the list
|
||||
// Unlink the window from the global window list
|
||||
if (window->next) {
|
||||
window->next->prev = window->prev;
|
||||
}
|
||||
|
@ -122,7 +122,8 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
|
||||
device->UpdateWindowShape = Cocoa_UpdateWindowShape;
|
||||
device->FlashWindow = Cocoa_FlashWindow;
|
||||
device->SetWindowFocusable = Cocoa_SetWindowFocusable;
|
||||
device->SetWindowModalFor = Cocoa_SetWindowModalFor;
|
||||
device->SetWindowParent = Cocoa_SetWindowParent;
|
||||
device->SetWindowModal = Cocoa_SetWindowModal;
|
||||
device->SyncWindow = Cocoa_SyncWindow;
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_CGL
|
||||
|
@ -183,7 +183,8 @@ extern bool Cocoa_SetWindowHitTest(SDL_Window *window, bool enabled);
|
||||
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, bool accept);
|
||||
extern bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
extern bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
extern bool Cocoa_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern bool Cocoa_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern bool Cocoa_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#endif // SDL_cocoawindow_h_
|
||||
|
@ -2075,23 +2075,10 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
|
||||
window->flags &= ~SDL_WINDOW_MINIMIZED;
|
||||
}
|
||||
|
||||
if (!SDL_WINDOW_IS_POPUP(window)) {
|
||||
if ([nswindow isKeyWindow]) {
|
||||
window->flags |= SDL_WINDOW_INPUT_FOCUS;
|
||||
Cocoa_SetKeyboardFocus(data.window);
|
||||
}
|
||||
} else {
|
||||
if (window->parent) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow;
|
||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||
|
||||
if (window->flags & SDL_WINDOW_TOOLTIP) {
|
||||
[nswindow setIgnoresMouseEvents:YES];
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
if (window->parent == SDL_GetKeyboardFocus()) {
|
||||
Cocoa_SetKeyboardFocus(window);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: Should not need to call addChildWindow then orderOut.
|
||||
Attaching a hidden child window to a hidden parent window will cause the child window
|
||||
to show when the parent does. We therefore shouldn't attach the child window here as we're
|
||||
@ -2103,6 +2090,21 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
|
||||
}
|
||||
}
|
||||
|
||||
if (!SDL_WINDOW_IS_POPUP(window)) {
|
||||
if ([nswindow isKeyWindow]) {
|
||||
window->flags |= SDL_WINDOW_INPUT_FOCUS;
|
||||
Cocoa_SetKeyboardFocus(data.window);
|
||||
}
|
||||
} else {
|
||||
if (window->flags & SDL_WINDOW_TOOLTIP) {
|
||||
[nswindow setIgnoresMouseEvents:YES];
|
||||
} else if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
if (window->parent == SDL_GetKeyboardFocus()) {
|
||||
Cocoa_SetKeyboardFocus(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nswindow.isOpaque) {
|
||||
window->flags &= ~SDL_WINDOW_TRANSPARENT;
|
||||
} else {
|
||||
@ -2465,14 +2467,15 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
|
||||
if (![nswindow isMiniaturized]) {
|
||||
[windowData.listener pauseVisibleObservation];
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (window->parent) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow;
|
||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||
} else {
|
||||
if ((window->flags & SDL_WINDOW_MODAL) && window->parent) {
|
||||
Cocoa_SetWindowModalFor(_this, window, window->parent);
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
Cocoa_SetWindowModal(_this, window, true);
|
||||
}
|
||||
}
|
||||
if (!SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (bActivate) {
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
@ -2482,9 +2485,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
}
|
||||
}
|
||||
}
|
||||
[nswindow setIsVisible:YES];
|
||||
[windowData.listener resumeVisibleObservation];
|
||||
}
|
||||
[nswindow setIsVisible:YES];
|
||||
[windowData.listener resumeVisibleObservation];
|
||||
}
|
||||
}
|
||||
|
||||
@ -2492,6 +2495,7 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow;
|
||||
const BOOL waskey = [nswindow isKeyWindow];
|
||||
|
||||
/* orderOut has no effect on miniaturized windows, so close must be used to remove
|
||||
* the window from the desktop and window list in this case.
|
||||
@ -2509,9 +2513,9 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
/* 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);
|
||||
Cocoa_SetWindowModal(_this, window, false);
|
||||
|
||||
// Transfer keyboard focus back to the parent
|
||||
// Transfer keyboard focus back to the parent when closing a popup menu
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
if (window == SDL_GetKeyboardFocus()) {
|
||||
SDL_Window *new_focus = window->parent;
|
||||
@ -2523,6 +2527,20 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
|
||||
Cocoa_SetKeyboardFocus(new_focus);
|
||||
}
|
||||
} else if (window->parent && waskey) {
|
||||
/* Key status is not automatically set on the parent when a child is hidden. Check if the
|
||||
* child window was key, and set the first visible parent to be key if so.
|
||||
*/
|
||||
SDL_Window *new_focus = window->parent;
|
||||
|
||||
while (new_focus->parent != NULL && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
new_focus = new_focus->parent;
|
||||
}
|
||||
|
||||
if (new_focus) {
|
||||
NSWindow *newkey = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow;
|
||||
[newkey makeKeyAndOrderFront:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2539,19 +2557,21 @@ void Cocoa_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
*/
|
||||
[windowData.listener pauseVisibleObservation];
|
||||
if (![nswindow isMiniaturized] && [nswindow isVisible]) {
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (window->parent) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow;
|
||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||
if (bActivate) {
|
||||
[nswindow makeKeyWindow];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (!SDL_WINDOW_IS_POPUP(window)) {
|
||||
if (bActivate) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
[nswindow orderFront:nil];
|
||||
}
|
||||
} else {
|
||||
if (bActivate) {
|
||||
[nswindow makeKeyWindow];
|
||||
}
|
||||
}
|
||||
}
|
||||
[windowData.listener resumeVisibleObservation];
|
||||
@ -2943,7 +2963,7 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
*/
|
||||
if (topmost_data.keyboard_focus == window) {
|
||||
SDL_Window *new_focus = window;
|
||||
while(new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
while (new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) {
|
||||
new_focus = new_focus->parent;
|
||||
}
|
||||
|
||||
@ -3054,18 +3074,38 @@ void Cocoa_AcceptDragAndDrop(SDL_Window *window, bool accept)
|
||||
}
|
||||
}
|
||||
|
||||
bool Cocoa_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
bool Cocoa_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaWindowData *modal_data = (__bridge SDL_CocoaWindowData *)modal_window->internal;
|
||||
SDL_CocoaWindowData *child_data = (__bridge SDL_CocoaWindowData *)window->internal;
|
||||
|
||||
if (modal_data.modal_session) {
|
||||
[NSApp endModalSession:modal_data.modal_session];
|
||||
modal_data.modal_session = nil;
|
||||
// Remove an existing parent.
|
||||
if (child_data.nswindow.parentWindow) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow;
|
||||
[nsparent removeChildWindow:child_data.nswindow];
|
||||
}
|
||||
|
||||
if (parent_window) {
|
||||
modal_data.modal_session = [NSApp beginModalSessionForWindow:modal_data.nswindow];
|
||||
if (parent) {
|
||||
SDL_CocoaWindowData *parent_data = (__bridge SDL_CocoaWindowData *)parent->internal;
|
||||
[parent_data.nswindow addChildWindow:child_data.nswindow ordered:NSWindowAbove];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cocoa_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
|
||||
|
||||
if (data.modal_session) {
|
||||
[NSApp endModalSession:data.modal_session];
|
||||
data.modal_session = nil;
|
||||
}
|
||||
|
||||
if (modal) {
|
||||
data.modal_session = [NSApp beginModalSessionForWindow:data.nswindow];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,8 @@ static SDL_VideoDevice * HAIKU_CreateDevice(void)
|
||||
device->SetWindowFullscreen = HAIKU_SetWindowFullscreen;
|
||||
device->SetWindowMouseGrab = HAIKU_SetWindowMouseGrab;
|
||||
device->SetWindowMinimumSize = HAIKU_SetWindowMinimumSize;
|
||||
device->SetWindowParent = HAIKU_SetWindowParent;
|
||||
device->SetWindowModal = HAIKU_SetWindowModal;
|
||||
device->DestroyWindow = HAIKU_DestroyWindow;
|
||||
device->CreateWindowFramebuffer = HAIKU_CreateWindowFramebuffer;
|
||||
device->UpdateWindowFramebuffer = HAIKU_UpdateWindowFramebuffer;
|
||||
|
@ -188,21 +188,22 @@ bool HAIKU_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window * window, bool
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
bool HAIKU_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
bool HAIKU_SetWindowParent(SDL_VideoDevice *_this, SDL_Window * window, SDL_Window *parent)
|
||||
{
|
||||
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));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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));
|
||||
bool HAIKU_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal)
|
||||
{
|
||||
if (modal) {
|
||||
_ToBeWin(window)->SetLook(B_MODAL_WINDOW_LOOK);
|
||||
_ToBeWin(window)->SetFeel(B_MODAL_SUBSET_WINDOW_FEEL);
|
||||
_ToBeWin(window)->AddToSubset(_ToBeWin(window->parent));
|
||||
} 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);
|
||||
window_look look = (window->flags & SDL_WINDOW_BORDERLESS) ? B_NO_BORDER_WINDOW_LOOK : B_TITLED_WINDOW_LOOK;
|
||||
_ToBeWin(window)->RemoveFromSubset(_ToBeWin(window->parent));
|
||||
_ToBeWin(window)->SetLook(look);
|
||||
_ToBeWin(window)->SetFeel(B_NORMAL_WINDOW_FEEL);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -39,6 +39,8 @@ extern void HAIKU_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
extern void HAIKU_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
extern SDL_FullscreenResult HAIKU_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
|
||||
extern bool HAIKU_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern bool HAIKU_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool HAIKU_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern void HAIKU_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
#endif
|
||||
|
@ -547,7 +547,8 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
|
||||
device->SetWindowSize = Wayland_SetWindowSize;
|
||||
device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize;
|
||||
device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize;
|
||||
device->SetWindowModalFor = Wayland_SetWindowModalFor;
|
||||
device->SetWindowParent = Wayland_SetWindowParent;
|
||||
device->SetWindowModal = Wayland_SetWindowModal;
|
||||
device->SetWindowOpacity = Wayland_SetWindowOpacity;
|
||||
device->SetWindowTitle = Wayland_SetWindowTitle;
|
||||
device->SetWindowIcon = Wayland_SetWindowIcon;
|
||||
|
@ -672,8 +672,11 @@ 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) {
|
||||
if (w->internal->surface_status == WAYLAND_SURFACE_STATUS_SHOW_PENDING) {
|
||||
Wayland_ShowWindow(SDL_GetVideoDevice(), w);
|
||||
} else if ((w->flags & SDL_WINDOW_MODAL) && w->internal->modal_reparenting_required) {
|
||||
Wayland_SetWindowModalFor(SDL_GetVideoDevice(), w, w->parent);
|
||||
} else if (w->internal->reparenting_required) {
|
||||
Wayland_SetWindowParent(SDL_GetVideoDevice(), w, w->parent);
|
||||
if (w->flags & SDL_WINDOW_MODAL) {
|
||||
Wayland_SetWindowModal(SDL_GetVideoDevice(), w, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1564,58 +1567,75 @@ bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled)
|
||||
return true; // just succeed, the real work is done elsewhere.
|
||||
}
|
||||
|
||||
bool Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
static struct xdg_toplevel *GetToplevelForWindow(SDL_WindowData *wind)
|
||||
{
|
||||
SDL_VideoData *viddata = _this->internal;
|
||||
SDL_WindowData *modal_data = modal_window->internal;
|
||||
SDL_WindowData *parent_data = parent_window ? parent_window->internal : NULL;
|
||||
struct xdg_toplevel *modal_toplevel = NULL;
|
||||
struct xdg_toplevel *parent_toplevel = NULL;
|
||||
if (wind) {
|
||||
/* 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
|
||||
if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) {
|
||||
return libdecor_frame_get_xdg_toplevel(wind->shell_surface.libdecor.frame);
|
||||
} else
|
||||
#endif
|
||||
if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && wind->shell_surface.xdg.roleobj.toplevel) {
|
||||
return wind->shell_surface.xdg.roleobj.toplevel;
|
||||
}
|
||||
}
|
||||
|
||||
modal_data->modal_reparenting_required = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Wayland_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent_window)
|
||||
{
|
||||
SDL_WindowData *child_data = window->internal;
|
||||
SDL_WindowData *parent_data = parent_window ? parent_window->internal : NULL;
|
||||
|
||||
child_data->reparenting_required = SDL_FALSE;
|
||||
|
||||
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 = true;
|
||||
child_data->reparenting_required = SDL_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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
|
||||
if (modal_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && modal_data->shell_surface.libdecor.frame) {
|
||||
modal_toplevel = libdecor_frame_get_xdg_toplevel(modal_data->shell_surface.libdecor.frame);
|
||||
} else
|
||||
#endif
|
||||
if (modal_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && modal_data->shell_surface.xdg.roleobj.toplevel) {
|
||||
modal_toplevel = modal_data->shell_surface.xdg.roleobj.toplevel;
|
||||
struct xdg_toplevel *child_toplevel = GetToplevelForWindow(child_data);
|
||||
struct xdg_toplevel *parent_toplevel = GetToplevelForWindow(parent_data);
|
||||
|
||||
if (child_toplevel) {
|
||||
xdg_toplevel_set_parent(child_toplevel, parent_toplevel);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal)
|
||||
{
|
||||
SDL_VideoData *viddata = _this->internal;
|
||||
SDL_WindowData *data = window->internal;
|
||||
SDL_WindowData *parent_data = window->parent->internal;
|
||||
|
||||
if (parent_data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN) {
|
||||
// Need to wait for the parent to become mapped before changing modal status.
|
||||
data->reparenting_required = true;
|
||||
return true;
|
||||
} else {
|
||||
data->reparenting_required = false;
|
||||
}
|
||||
|
||||
if (modal_toplevel) {
|
||||
xdg_toplevel_set_parent(modal_toplevel, parent_toplevel);
|
||||
struct xdg_toplevel *toplevel = GetToplevelForWindow(data);
|
||||
|
||||
if (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);
|
||||
if (modal) {
|
||||
if (!data->xdg_dialog_v1) {
|
||||
data->xdg_dialog_v1 = xdg_wm_dialog_v1_get_xdg_dialog(viddata->xdg_wm_dialog_v1, 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_dialog_v1_set_modal(data->xdg_dialog_v1);
|
||||
} else if (data->xdg_dialog_v1) {
|
||||
xdg_dialog_v1_unset_modal(data->xdg_dialog_v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1820,8 +1840,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
}
|
||||
|
||||
// Restore state that was set prior to this call
|
||||
Wayland_SetWindowParent(_this, window, window->parent);
|
||||
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
Wayland_SetWindowModalFor(_this, window, window->parent);
|
||||
Wayland_SetWindowModal(_this, window, true);
|
||||
}
|
||||
|
||||
Wayland_SetWindowTitle(_this, window);
|
||||
|
@ -172,7 +172,7 @@ struct SDL_WindowData
|
||||
bool fullscreen_was_positioned;
|
||||
bool show_hide_sync_required;
|
||||
bool scale_to_display;
|
||||
bool modal_reparenting_required;
|
||||
bool reparenting_required;
|
||||
bool pending_restored_size;
|
||||
bool double_buffer;
|
||||
|
||||
@ -200,7 +200,8 @@ extern void Wayland_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *win
|
||||
extern void Wayland_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
extern SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern bool Wayland_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent_window);
|
||||
extern bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern bool Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
|
@ -229,7 +229,8 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
|
||||
device->SetWindowResizable = WIN_SetWindowResizable;
|
||||
device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
|
||||
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
|
||||
device->SetWindowModalFor = WIN_SetWindowModalFor;
|
||||
device->SetWindowParent = WIN_SetWindowParent;
|
||||
device->SetWindowModal = WIN_SetWindowModal;
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
|
||||
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
|
||||
|
@ -693,10 +693,10 @@ bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
|
||||
int x, y;
|
||||
int w, h;
|
||||
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
parent = window->parent->internal->hwnd;
|
||||
} else if (window->flags & SDL_WINDOW_UTILITY) {
|
||||
if (window->flags & SDL_WINDOW_UTILITY) {
|
||||
parent = CreateWindow(SDL_Appname, TEXT(""), STYLE_BASIC, 0, 0, 32, 32, NULL, NULL, SDL_Instance, NULL);
|
||||
} else if (window->parent) {
|
||||
parent = window->parent->internal->hwnd;
|
||||
}
|
||||
|
||||
style |= GetWindowStyle(window);
|
||||
@ -1017,12 +1017,6 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
WIN_SetWindowPosition(_this, window);
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
EnableWindow(window->parent->internal->hwnd, FALSE);
|
||||
}
|
||||
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
hwnd = window->internal->hwnd;
|
||||
style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if (style & WS_EX_NOACTIVATE) {
|
||||
@ -1040,17 +1034,18 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
WIN_SetKeyboardFocus(window);
|
||||
}
|
||||
}
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
WIN_SetWindowModal(_this, window, true);
|
||||
}
|
||||
}
|
||||
|
||||
void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
HWND hwnd = window->internal->hwnd;
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
if (window->flags & SDL_WINDOW_MODAL) {
|
||||
EnableWindow(window->parent->internal->hwnd, TRUE);
|
||||
WIN_SetWindowModal(_this, window, false);
|
||||
}
|
||||
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
|
||||
@ -2240,22 +2235,12 @@ void WIN_UpdateDarkModeForHWND(HWND hwnd)
|
||||
}
|
||||
}
|
||||
|
||||
bool WIN_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
bool WIN_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
SDL_WindowData *modal_data = modal_window->internal;
|
||||
const LONG_PTR parent_hwnd = (LONG_PTR)(parent_window ? parent_window->internal->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 true;
|
||||
}
|
||||
|
||||
// Reenable the old parent window.
|
||||
if (old_ptr) {
|
||||
EnableWindow((HWND)old_ptr, TRUE);
|
||||
}
|
||||
SDL_WindowData *child_data = window->internal;
|
||||
const LONG_PTR parent_hwnd = (LONG_PTR)(parent ? parent->internal->hwnd : NULL);
|
||||
const DWORD style = GetWindowLong(child_data->hwnd, GWL_STYLE);
|
||||
|
||||
if (!(style & WS_CHILD)) {
|
||||
/* Despite the name, this changes the *owner* of a toplevel window, not
|
||||
@ -2263,14 +2248,26 @@ bool WIN_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL
|
||||
*
|
||||
* https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613
|
||||
*/
|
||||
SetWindowLongPtr(modal_data->hwnd, GWLP_HWNDPARENT, parent_hwnd);
|
||||
SetWindowLongPtr(child_data->hwnd, GWLP_HWNDPARENT, parent_hwnd);
|
||||
} else {
|
||||
SetParent(modal_data->hwnd, (HWND)parent_hwnd);
|
||||
SetParent(child_data->hwnd, (HWND)parent_hwnd);
|
||||
}
|
||||
#endif /*!defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/
|
||||
|
||||
// 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 true;
|
||||
}
|
||||
|
||||
bool WIN_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
const HWND parent_hwnd = window->parent->internal->hwnd;
|
||||
|
||||
if (modal) {
|
||||
// Disable the parent window.
|
||||
EnableWindow(parent_hwnd, FALSE);
|
||||
} else if (!(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
// Re-enable the parent window
|
||||
EnableWindow(parent_hwnd, TRUE);
|
||||
}
|
||||
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
|
@ -137,7 +137,8 @@ extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern bool WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
extern bool WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_WindowRect rect_type);
|
||||
extern bool WIN_AdjustWindowRectForHWND(HWND hwnd, LPRECT lpRect, UINT frame_dpi);
|
||||
extern bool WIN_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern bool WIN_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool WIN_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
|
||||
// Ends C function definitions when using C++
|
||||
#ifdef __cplusplus
|
||||
|
@ -197,7 +197,8 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
||||
device->SetWindowAspectRatio = X11_SetWindowAspectRatio;
|
||||
device->GetWindowBordersSize = X11_GetWindowBordersSize;
|
||||
device->SetWindowOpacity = X11_SetWindowOpacity;
|
||||
device->SetWindowModalFor = X11_SetWindowModalFor;
|
||||
device->SetWindowParent = X11_SetWindowParent;
|
||||
device->SetWindowModal = X11_SetWindowModal;
|
||||
device->ShowWindow = X11_ShowWindow;
|
||||
device->HideWindow = X11_HideWindow;
|
||||
device->RaiseWindow = X11_RaiseWindow;
|
||||
|
@ -792,6 +792,11 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
|
||||
}
|
||||
windowdata = window->internal;
|
||||
|
||||
// Set the parent if this is a non-popup window.
|
||||
if (!SDL_WINDOW_IS_POPUP(window) && window->parent) {
|
||||
X11_XSetTransientForHint(display, w, window->parent->internal->xwindow);
|
||||
}
|
||||
|
||||
// Set the flag if the borders were forced on when creating a fullscreen window for later removal.
|
||||
windowdata->fullscreen_borders_forced_on = !!(window->pending_flags & SDL_WINDOW_FULLSCREEN) &&
|
||||
!!(window->flags & SDL_WINDOW_BORDERLESS);
|
||||
@ -1235,26 +1240,40 @@ bool X11_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opac
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window)
|
||||
bool X11_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent)
|
||||
{
|
||||
SDL_WindowData *data = modal_window->internal;
|
||||
SDL_WindowData *parent_data = parent_window ? parent_window->internal : NULL;
|
||||
SDL_WindowData *data = window->internal;
|
||||
SDL_WindowData *parent_data = parent ? parent->internal : NULL;
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(modal_window);
|
||||
Display *display = video_data->display;
|
||||
Uint32 flags = modal_window->flags;
|
||||
|
||||
if (parent_data) {
|
||||
X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow);
|
||||
} else {
|
||||
X11_XDeleteProperty(display, data->xwindow, video_data->WM_TRANSIENT_FOR);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X11_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
SDL_VideoData *video_data = _this->internal;
|
||||
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(window);
|
||||
Display *display = video_data->display;
|
||||
Uint32 flags = 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) {
|
||||
if (modal) {
|
||||
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)) {
|
||||
if (X11_IsWindowMapped(_this, window)) {
|
||||
XEvent e;
|
||||
|
||||
SDL_zero(e);
|
||||
@ -1262,8 +1281,7 @@ bool X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL
|
||||
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[0] = modal ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||
e.xclient.data.l[1] = _NET_WM_STATE_MODAL;
|
||||
e.xclient.data.l[3] = 0l;
|
||||
|
||||
|
@ -118,7 +118,8 @@ extern void X11_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
extern void X11_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_GetWindowBordersSize(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
|
||||
extern bool X11_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
extern bool X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern bool X11_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool X11_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
extern void X11_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
@ -66,8 +66,10 @@ int main(int argc, char *argv[])
|
||||
goto sdl_quit;
|
||||
}
|
||||
|
||||
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
if (SDL_SetWindowParent(w2, w1)) {
|
||||
if (SDL_SetWindowModal(w2, true)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
@ -98,8 +100,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (e.key.key == SDLK_M) {
|
||||
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
if (SDL_SetWindowParent(w2, w2)) {
|
||||
if (SDL_SetWindowModal(w2, true)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_ShowWindow(w2);
|
||||
@ -123,13 +127,17 @@ int main(int argc, char *argv[])
|
||||
} else if (e.key.key == SDLK_P && w2) {
|
||||
if (SDL_GetWindowFlags(w2) & SDL_WINDOW_MODAL) {
|
||||
/* Unparent the window */
|
||||
if (!SDL_SetWindowModalFor(w2, NULL)) {
|
||||
SDL_SetWindowTitle(w2, "Non-Modal Window");
|
||||
if (SDL_SetWindowModal(w2, false)) {
|
||||
if (SDL_SetWindowParent(w2, NULL)) {
|
||||
SDL_SetWindowTitle(w2, "Non-Modal Window");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Reparent the window */
|
||||
if (!SDL_SetWindowModalFor(w2, w1)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
if (SDL_SetWindowParent(w2, w1)) {
|
||||
if (SDL_SetWindowModal(w2, true)) {
|
||||
SDL_SetWindowTitle(w2, "Modal Window");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user