Merge pull request #41456 from nekomatata/x11-fix-popups
Popup fixes for X11 display server
This commit is contained in:
commit
2a8531cc56
|
@ -83,6 +83,13 @@
|
|||
#define VALUATOR_TILTX 3
|
||||
#define VALUATOR_TILTY 4
|
||||
|
||||
//#define DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
|
||||
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
|
||||
#define DEBUG_LOG_X11(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_LOG_X11(...)
|
||||
#endif
|
||||
|
||||
static const double abs_resolution_mult = 10000.0;
|
||||
static const double abs_resolution_range_mult = 10.0;
|
||||
|
||||
|
@ -681,6 +688,14 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, u
|
|||
return id;
|
||||
}
|
||||
|
||||
void DisplayServerX11::show_window(WindowID p_id) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
WindowData &wd = windows[p_id];
|
||||
|
||||
XMapWindow(x11_display, wd.x11_window);
|
||||
}
|
||||
|
||||
void DisplayServerX11::delete_sub_window(WindowID p_id) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
@ -689,6 +704,8 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
|
|||
|
||||
WindowData &wd = windows[p_id];
|
||||
|
||||
DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id);
|
||||
|
||||
while (wd.transient_children.size()) {
|
||||
window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
|
||||
}
|
||||
|
@ -842,24 +859,34 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
|
|||
ERR_FAIL_COND(!windows.has(p_window));
|
||||
WindowData &wd_window = windows[p_window];
|
||||
|
||||
ERR_FAIL_COND(wd_window.transient_parent == p_parent);
|
||||
WindowID prev_parent = wd_window.transient_parent;
|
||||
ERR_FAIL_COND(prev_parent == p_parent);
|
||||
|
||||
ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
|
||||
if (p_parent == INVALID_WINDOW_ID) {
|
||||
//remove transient
|
||||
|
||||
ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
|
||||
ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
|
||||
ERR_FAIL_COND(prev_parent == INVALID_WINDOW_ID);
|
||||
ERR_FAIL_COND(!windows.has(prev_parent));
|
||||
|
||||
WindowData &wd_parent = windows[wd_window.transient_parent];
|
||||
WindowData &wd_parent = windows[prev_parent];
|
||||
|
||||
wd_window.transient_parent = INVALID_WINDOW_ID;
|
||||
wd_parent.transient_children.erase(p_window);
|
||||
|
||||
XSetTransientForHint(x11_display, wd_window.x11_window, None);
|
||||
|
||||
// Set focus to parent sub window to avoid losing all focus with nested menus.
|
||||
// RevertToPointerRoot is used to make sure we don't lose all focus in case
|
||||
// a subwindow and its parent are both destroyed.
|
||||
if (wd_window.menu_type && !wd_window.no_focus) {
|
||||
if (!wd_parent.no_focus) {
|
||||
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_COND(!windows.has(p_parent));
|
||||
ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
|
||||
ERR_FAIL_COND_MSG(prev_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
|
||||
WindowData &wd_parent = windows[p_parent];
|
||||
|
||||
wd_window.transient_parent = p_parent;
|
||||
|
@ -2285,6 +2312,11 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
|
|||
void DisplayServerX11::process_events() {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
|
||||
static int frame = 0;
|
||||
++frame;
|
||||
#endif
|
||||
|
||||
if (app_focused) {
|
||||
//verify that one of the windows has focus, else send focus out notification
|
||||
bool focus_found = false;
|
||||
|
@ -2301,6 +2333,7 @@ void DisplayServerX11::process_events() {
|
|||
if (delta > 250) {
|
||||
//X11 can go between windows and have no focus for a while, when creating them or something else. Use this as safety to avoid unnecessary focus in/outs.
|
||||
if (OS::get_singleton()->get_main_loop()) {
|
||||
DEBUG_LOG_X11("All focus lost, triggering NOTIFICATION_APPLICATION_FOCUS_OUT\n");
|
||||
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
|
||||
}
|
||||
app_focused = false;
|
||||
|
@ -2323,6 +2356,10 @@ void DisplayServerX11::process_events() {
|
|||
XEvent event;
|
||||
XNextEvent(x11_display, &event);
|
||||
|
||||
if (XFilterEvent(&event, None)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WindowID window_id = MAIN_WINDOW_ID;
|
||||
|
||||
// Assign the event to the relevant window
|
||||
|
@ -2333,10 +2370,6 @@ void DisplayServerX11::process_events() {
|
|||
}
|
||||
}
|
||||
|
||||
if (XFilterEvent(&event, None)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (XGetEventData(x11_display, &event.xcookie)) {
|
||||
if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
|
||||
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
|
||||
|
@ -2499,32 +2532,63 @@ void DisplayServerX11::process_events() {
|
|||
XFreeEventData(x11_display, &event.xcookie);
|
||||
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
Main::force_redraw();
|
||||
break;
|
||||
case MapNotify: {
|
||||
DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id);
|
||||
|
||||
const WindowData &wd = windows[window_id];
|
||||
|
||||
// Set focus when menu window is started.
|
||||
// RevertToPointerRoot is used to make sure we don't lose all focus in case
|
||||
// a subwindow and its parent are both destroyed.
|
||||
if (wd.menu_type && !wd.no_focus) {
|
||||
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
|
||||
}
|
||||
} break;
|
||||
|
||||
case Expose: {
|
||||
DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count);
|
||||
|
||||
Main::force_redraw();
|
||||
} break;
|
||||
|
||||
case NoExpose: {
|
||||
DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
|
||||
|
||||
case NoExpose:
|
||||
windows[window_id].minimized = true;
|
||||
break;
|
||||
} break;
|
||||
|
||||
case VisibilityNotify: {
|
||||
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
|
||||
|
||||
XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
|
||||
windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
|
||||
} break;
|
||||
|
||||
case LeaveNotify: {
|
||||
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
|
||||
|
||||
if (!mouse_mode_grab) {
|
||||
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case EnterNotify: {
|
||||
DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
|
||||
|
||||
if (!mouse_mode_grab) {
|
||||
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
|
||||
}
|
||||
} break;
|
||||
case FocusIn:
|
||||
windows[window_id].focused = true;
|
||||
_send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
|
||||
|
||||
case FocusIn: {
|
||||
DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
|
||||
|
||||
WindowData &wd = windows[window_id];
|
||||
|
||||
wd.focused = true;
|
||||
|
||||
_send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
|
||||
|
||||
if (mouse_mode_grab) {
|
||||
// Show and update the cursor if confined and the window regained focus.
|
||||
|
@ -2548,8 +2612,8 @@ void DisplayServerX11::process_events() {
|
|||
XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
|
||||
}*/
|
||||
#endif
|
||||
if (windows[window_id].xic) {
|
||||
XSetICFocus(windows[window_id].xic);
|
||||
if (wd.xic) {
|
||||
XSetICFocus(wd.xic);
|
||||
}
|
||||
|
||||
if (!app_focused) {
|
||||
|
@ -2558,12 +2622,17 @@ void DisplayServerX11::process_events() {
|
|||
}
|
||||
app_focused = true;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case FocusOut: {
|
||||
DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
|
||||
|
||||
WindowData &wd = windows[window_id];
|
||||
|
||||
wd.focused = false;
|
||||
|
||||
case FocusOut:
|
||||
windows[window_id].focused = false;
|
||||
Input::get_singleton()->release_pressed_events();
|
||||
_send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
|
||||
_send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
|
||||
|
||||
if (mouse_mode_grab) {
|
||||
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
|
||||
|
@ -2592,14 +2661,26 @@ void DisplayServerX11::process_events() {
|
|||
}
|
||||
xi.state.clear();
|
||||
#endif
|
||||
if (windows[window_id].xic) {
|
||||
XSetICFocus(windows[window_id].xic);
|
||||
if (wd.xic) {
|
||||
XSetICFocus(wd.xic);
|
||||
}
|
||||
} break;
|
||||
|
||||
case ConfigureNotify: {
|
||||
DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect);
|
||||
|
||||
const WindowData &wd = windows[window_id];
|
||||
|
||||
// Set focus when menu window is re-used.
|
||||
// RevertToPointerRoot is used to make sure we don't lose all focus in case
|
||||
// a subwindow and its parent are both destroyed.
|
||||
if (wd.menu_type && !wd.no_focus) {
|
||||
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
|
||||
}
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
_window_changed(&event);
|
||||
break;
|
||||
} break;
|
||||
|
||||
case ButtonPress:
|
||||
case ButtonRelease: {
|
||||
/* exit in case of a mouse button press */
|
||||
|
@ -2627,6 +2708,17 @@ void DisplayServerX11::process_events() {
|
|||
mb->set_pressed((event.type == ButtonPress));
|
||||
|
||||
if (event.type == ButtonPress) {
|
||||
DEBUG_LOG_X11("[%u] ButtonPress window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
|
||||
|
||||
const WindowData &wd = windows[window_id];
|
||||
|
||||
// Ensure window focus on click.
|
||||
// RevertToPointerRoot is used to make sure we don't lose all focus in case
|
||||
// a subwindow and its parent are both destroyed.
|
||||
if (!wd.no_focus) {
|
||||
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
|
||||
}
|
||||
|
||||
uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
|
||||
|
||||
if (mb->get_button_index() == last_click_button_index) {
|
||||
|
@ -2645,6 +2737,8 @@ void DisplayServerX11::process_events() {
|
|||
last_click_ms += diff;
|
||||
last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
|
||||
}
|
||||
|
||||
Input::get_singleton()->accumulate_input_event(mb);
|
||||
|
@ -3140,12 +3234,37 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
|
|||
|
||||
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
|
||||
|
||||
WindowID id;
|
||||
WindowID id = window_id_counter++;
|
||||
WindowData &wd = windows[id];
|
||||
|
||||
if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
|
||||
wd.menu_type = true;
|
||||
}
|
||||
|
||||
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
|
||||
wd.menu_type = true;
|
||||
wd.no_focus = true;
|
||||
}
|
||||
|
||||
// Setup for menu subwindows:
|
||||
// - override_redirect forces the WM not to interfere with the window, to avoid delays due to
|
||||
// handling decorations and placement.
|
||||
// On the other hand, focus changes need to be handled manually when this is set.
|
||||
// - save_under is a hint for the WM to keep the content of windows behind to avoid repaint.
|
||||
if (wd.menu_type) {
|
||||
windowAttributes.override_redirect = True;
|
||||
windowAttributes.save_under = True;
|
||||
valuemask |= CWOverrideRedirect | CWSaveUnder;
|
||||
}
|
||||
|
||||
{
|
||||
WindowData wd;
|
||||
wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
|
||||
|
||||
XMapWindow(x11_display, wd.x11_window);
|
||||
// Enable receiving notification when the window is initialized (MapNotify)
|
||||
// so the focus can be set at the right time.
|
||||
if (wd.menu_type && !wd.no_focus) {
|
||||
XSelectInput(x11_display, wd.x11_window, StructureNotifyMask);
|
||||
}
|
||||
|
||||
//associate PID
|
||||
// make PID known to X11
|
||||
|
@ -3221,13 +3340,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
|
|||
|
||||
_update_context(wd);
|
||||
|
||||
id = window_id_counter++;
|
||||
|
||||
windows[id] = wd;
|
||||
|
||||
{
|
||||
bool make_utility = false;
|
||||
|
||||
if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
|
||||
Hints hints;
|
||||
Atom property;
|
||||
|
@ -3235,45 +3347,20 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
|
|||
hints.decorations = 0;
|
||||
property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
|
||||
XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
|
||||
|
||||
make_utility = true;
|
||||
}
|
||||
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
|
||||
make_utility = true;
|
||||
}
|
||||
|
||||
if (make_utility) {
|
||||
//this one seems to disable the fade animations for regular windows
|
||||
//but has the drawback that will not get focus by default, so
|
||||
//we need to force it, unless no focus requested
|
||||
|
||||
if (wd.menu_type) {
|
||||
// Set Utility type to disable fade animations.
|
||||
Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
|
||||
Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
|
||||
|
||||
XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
|
||||
|
||||
if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
|
||||
//but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested
|
||||
XEvent xev;
|
||||
Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
|
||||
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = wd.x11_window;
|
||||
xev.xclient.message_type = net_active_window;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = 1;
|
||||
xev.xclient.data.l[1] = CurrentTime;
|
||||
|
||||
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||
}
|
||||
} else {
|
||||
Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
|
||||
Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
|
||||
|
||||
XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
|
||||
}
|
||||
}
|
||||
|
||||
_update_size_hints(id);
|
||||
|
||||
|
@ -3293,8 +3380,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
|
|||
XFree(visualInfo);
|
||||
}
|
||||
|
||||
WindowData &wd = windows[id];
|
||||
|
||||
window_set_mode(p_mode, id);
|
||||
|
||||
//sync size
|
||||
|
@ -3316,6 +3401,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
|
|||
if (cursors[current_cursor] != None) {
|
||||
XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -3555,6 +3641,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
|
|||
window_set_flag(WindowFlags(i), true, main_window);
|
||||
}
|
||||
}
|
||||
show_window(main_window);
|
||||
|
||||
//create RenderingDevice if used
|
||||
#if defined(VULKAN_ENABLED)
|
||||
|
|
|
@ -132,6 +132,9 @@ class DisplayServerX11 : public DisplayServer {
|
|||
|
||||
ObjectID instance_id;
|
||||
|
||||
bool menu_type = false;
|
||||
bool no_focus = false;
|
||||
|
||||
//better to guess on the fly, given WM can change it
|
||||
//WindowMode mode;
|
||||
bool fullscreen = false; //OS can't exit from this mode
|
||||
|
@ -277,6 +280,7 @@ public:
|
|||
virtual Vector<DisplayServer::WindowID> get_window_list() const;
|
||||
|
||||
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
|
||||
virtual void show_window(WindowID p_id);
|
||||
virtual void delete_sub_window(WindowID p_id);
|
||||
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
|
||||
|
|
|
@ -230,6 +230,7 @@ public:
|
|||
virtual Vector<int> get_window_list() const override;
|
||||
|
||||
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
|
||||
virtual void show_window(WindowID p_id) override;
|
||||
virtual void delete_sub_window(WindowID p_id) override;
|
||||
|
||||
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
|
||||
|
|
|
@ -2314,18 +2314,23 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, u
|
|||
_THREAD_SAFE_METHOD_
|
||||
|
||||
WindowID id = _create_window(p_mode, p_rect);
|
||||
WindowData &wd = windows[id];
|
||||
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
|
||||
if (p_flags & (1 << i)) {
|
||||
window_set_flag(WindowFlags(i), true, id);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void DisplayServerOSX::show_window(WindowID p_id) {
|
||||
WindowData &wd = windows[p_id];
|
||||
|
||||
if (wd.no_focus) {
|
||||
[wd.window_object orderFront:nil];
|
||||
} else {
|
||||
[wd.window_object makeKeyAndOrderFront:nil];
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_event) {
|
||||
|
@ -3774,7 +3779,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
|
|||
window_set_flag(WindowFlags(i), true, main_window);
|
||||
}
|
||||
}
|
||||
[windows[main_window].window_object makeKeyAndOrderFront:nil];
|
||||
show_window(MAIN_WINDOW_ID);
|
||||
|
||||
#if defined(OPENGL_ENABLED)
|
||||
if (rendering_driver == "opengl_es") {
|
||||
|
|
|
@ -493,15 +493,21 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
|
|||
wd.no_focus = true;
|
||||
}
|
||||
|
||||
_update_window_style(window_id);
|
||||
return window_id;
|
||||
}
|
||||
|
||||
ShowWindow(wd.hWnd, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
|
||||
if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
|
||||
void DisplayServerWindows::show_window(WindowID p_id) {
|
||||
WindowData &wd = windows[p_id];
|
||||
|
||||
if (p_id != MAIN_WINDOW_ID) {
|
||||
_update_window_style(p_id);
|
||||
}
|
||||
|
||||
ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
|
||||
if (!wd.no_focus) {
|
||||
SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
|
||||
SetFocus(wd.hWnd); // Sets Keyboard Focus To
|
||||
}
|
||||
|
||||
return window_id;
|
||||
}
|
||||
|
||||
void DisplayServerWindows::delete_sub_window(WindowID p_window) {
|
||||
|
@ -3139,9 +3145,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
|
|||
}
|
||||
}
|
||||
|
||||
ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window
|
||||
SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority
|
||||
SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To
|
||||
show_window(MAIN_WINDOW_ID);
|
||||
|
||||
#if defined(VULKAN_ENABLED)
|
||||
|
||||
|
|
|
@ -461,6 +461,7 @@ public:
|
|||
virtual Vector<DisplayServer::WindowID> get_window_list() const;
|
||||
|
||||
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
|
||||
virtual void show_window(WindowID p_window);
|
||||
virtual void delete_sub_window(WindowID p_window);
|
||||
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
|
||||
|
|
|
@ -41,55 +41,71 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
|
|||
}
|
||||
}
|
||||
|
||||
void Popup::_parent_focused() {
|
||||
_close_pressed();
|
||||
void Popup::_initialize_visible_parents() {
|
||||
visible_parents.clear();
|
||||
|
||||
Window *parent_window = this;
|
||||
while (parent_window) {
|
||||
parent_window = parent_window->get_parent_visible_window();
|
||||
if (parent_window) {
|
||||
visible_parents.push_back(parent_window);
|
||||
parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Popup::_deinitialize_visible_parents() {
|
||||
for (uint32_t i = 0; i < visible_parents.size(); ++i) {
|
||||
visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
|
||||
}
|
||||
|
||||
visible_parents.clear();
|
||||
}
|
||||
|
||||
void Popup::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (is_visible()) {
|
||||
parent_visible = get_parent_visible_window();
|
||||
if (parent_visible) {
|
||||
parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
}
|
||||
_initialize_visible_parents();
|
||||
} else {
|
||||
if (parent_visible) {
|
||||
parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
parent_visible = nullptr;
|
||||
}
|
||||
|
||||
_deinitialize_visible_parents();
|
||||
emit_signal("popup_hide");
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
if (parent_visible) {
|
||||
parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
parent_visible = nullptr;
|
||||
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
|
||||
if (has_focus()) {
|
||||
popped_up = true;
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
_deinitialize_visible_parents();
|
||||
} break;
|
||||
case NOTIFICATION_WM_CLOSE_REQUEST: {
|
||||
_close_pressed();
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
|
||||
_close_pressed();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void Popup::_parent_focused() {
|
||||
if (popped_up) {
|
||||
_close_pressed();
|
||||
}
|
||||
}
|
||||
|
||||
void Popup::_close_pressed() {
|
||||
Window *parent_window = parent_visible;
|
||||
if (parent_visible) {
|
||||
parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
|
||||
parent_visible = nullptr;
|
||||
}
|
||||
popped_up = false;
|
||||
|
||||
_deinitialize_visible_parents();
|
||||
|
||||
call_deferred("hide");
|
||||
|
||||
emit_signal("cancelled");
|
||||
|
||||
if (parent_window) {
|
||||
//parent_window->grab_focus();
|
||||
}
|
||||
}
|
||||
|
||||
void Popup::set_as_minsize() {
|
||||
|
@ -152,8 +168,6 @@ Rect2i Popup::_popup_adjust_rect() const {
|
|||
}
|
||||
|
||||
Popup::Popup() {
|
||||
parent_visible = nullptr;
|
||||
|
||||
set_wrap_controls(true);
|
||||
set_visible(false);
|
||||
set_transient(true);
|
||||
|
|
|
@ -33,12 +33,19 @@
|
|||
|
||||
#include "scene/main/window.h"
|
||||
|
||||
#include "core/local_vector.h"
|
||||
|
||||
class Popup : public Window {
|
||||
GDCLASS(Popup, Window);
|
||||
|
||||
Window *parent_visible;
|
||||
LocalVector<Window *> visible_parents;
|
||||
bool popped_up = false;
|
||||
|
||||
void _input_from_window(const Ref<InputEvent> &p_event);
|
||||
|
||||
void _initialize_visible_parents();
|
||||
void _deinitialize_visible_parents();
|
||||
|
||||
void _parent_focused();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -246,7 +246,10 @@ void Window::_make_window() {
|
|||
}
|
||||
}
|
||||
|
||||
_update_window_callbacks();
|
||||
|
||||
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
|
||||
DisplayServer::get_singleton()->show_window(window_id);
|
||||
}
|
||||
|
||||
void Window::_update_from_window() {
|
||||
|
@ -378,7 +381,6 @@ void Window::set_visible(bool p_visible) {
|
|||
}
|
||||
if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
|
||||
_make_window();
|
||||
_update_window_callbacks();
|
||||
}
|
||||
} else {
|
||||
if (visible) {
|
||||
|
@ -737,7 +739,6 @@ void Window::_notification(int p_what) {
|
|||
//create
|
||||
if (visible) {
|
||||
_make_window();
|
||||
_update_window_callbacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,6 +186,10 @@ DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint
|
|||
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
|
||||
}
|
||||
|
||||
void DisplayServer::show_window(WindowID p_id) {
|
||||
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
|
||||
}
|
||||
|
||||
void DisplayServer::delete_sub_window(WindowID p_id) {
|
||||
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
|
||||
}
|
||||
|
|
|
@ -220,6 +220,7 @@ public:
|
|||
};
|
||||
|
||||
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
|
||||
virtual void show_window(WindowID p_id);
|
||||
virtual void delete_sub_window(WindowID p_id);
|
||||
|
||||
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0;
|
||||
|
|
Loading…
Reference in New Issue