Skip to content

Commit

Permalink
Fix child windows unfocusing parent
Browse files Browse the repository at this point in the history
  • Loading branch information
HaSa1002 committed Apr 10, 2021
1 parent 8b6e3d6 commit 3a56f52
Show file tree
Hide file tree
Showing 15 changed files with 233 additions and 70 deletions.
48 changes: 40 additions & 8 deletions platform/linuxbsd/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,12 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
case WINDOW_FLAG_TRANSPARENT: {
//todo reimplement
} break;
case WINDOW_FLAG_INPUT_WITHOUT_FOCUS: {
wd.input_without_focus = p_enabled;
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
default: {
}
}
Expand Down Expand Up @@ -1743,6 +1749,12 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
case WINDOW_FLAG_TRANSPARENT: {
//todo reimplement
} break;
case WINDOW_FLAG_INPUT_WITHOUT_FOCUS: {
return wd.input_without_focus;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
default: {
}
}
Expand Down Expand Up @@ -1781,6 +1793,9 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) {

ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
if (wd.no_focus) {
return;
}

XEvent xev;
Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
Expand Down Expand Up @@ -2631,13 +2646,26 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {

Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
//send to a window
ERR_FAIL_COND(!windows.has(event_from_window->get_window_id()));
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_null()) {
return;
{
//send to a window
ERR_FAIL_COND(!windows.has(event_from_window->get_window_id()));
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_null()) {
return;
}
callable.call((const Variant **)&evp, 1, ret, ce);
}
//send to all windows, that request to always get input and have no focus
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
if (E->key() == event_from_window->get_window_id() || E->key() == MAIN_WINDOW_ID || (!E->get().input_without_focus && E->get().no_focus)) {
continue;
}
Callable callable = E->get().input_event_callback;
if (callable.is_null()) {
continue;
}
callable.call((const Variant **)&evp, 1, ret, ce);
}
callable.call((const Variant **)&evp, 1, ret, ce);
} else {
//send to all windows
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
Expand Down Expand Up @@ -3176,7 +3204,7 @@ void DisplayServerX11::process_events() {
} else {
DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());

if (!wd.focused) {
if (!wd.focused && !wd.input_without_focus) {
// Propagate the event to the focused window,
// because it's received only on the topmost window.
// Note: This is needed for drag & drop to work between windows,
Expand Down Expand Up @@ -3317,7 +3345,7 @@ void DisplayServerX11::process_events() {
// Don't propagate the motion event unless we have focus
// this is so that the relative motion doesn't get messed up
// after we regain focus.
if (focused) {
if (focused || wd.input_without_focus) {
Input::get_singleton()->accumulate_input_event(mm);
} else {
// Propagate the event to the focused window,
Expand Down Expand Up @@ -3673,6 +3701,10 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
wd.no_focus = true;
}

if (p_flags & WINDOW_FLAG_INPUT_WITHOUT_FOCUS_BIT) {
wd.input_without_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.
Expand Down
1 change: 1 addition & 0 deletions platform/linuxbsd/display_server_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class DisplayServerX11 : public DisplayServer {

bool menu_type = false;
bool no_focus = false;
bool input_without_focus = false;

//better to guess on the fly, given WM can change it
//WindowMode mode;
Expand Down
1 change: 1 addition & 0 deletions platform/osx/display_server_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class DisplayServerOSX : public DisplayServer {
bool borderless = false;
bool resize_disabled = false;
bool no_focus = false;
bool input_without_focus = false;
};

Point2i im_selection;
Expand Down
31 changes: 26 additions & 5 deletions platform/osx/display_server_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2921,6 +2921,9 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
case WINDOW_FLAG_INPUT_WITHOUT_FOCUS: {
wd.input_without_focus = p_enabled;
} break;
default: {
}
}
Expand Down Expand Up @@ -2948,6 +2951,9 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
case WINDOW_FLAG_INPUT_WITHOUT_FOCUS: {
return wd.input_without_focus;
} break;
default: {
}
}
Expand Down Expand Up @@ -3684,14 +3690,29 @@ void _update_keyboard_layouts() {

Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
//send to a window
if (windows.has(event_from_window->get_window_id())) {
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_null()) {
return;
{
//send to a window
Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
if (callable.is_null()) {
return;
}
callable.call((const Variant **)&evp, 1, ret, ce);
}

//send to all windows, that request to always get input and have no focus
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
if (E->key() == event_from_window->get_window_id() || E->key() == MAIN_WINDOW_ID || (!E->get().input_without_focus && E->get().no_focus)) {
continue;
}
Callable callable = E->get().input_event_callback;
if (callable.is_null()) {
continue;
}
callable.call((const Variant **)&evp, 1, ret, ce);
}
callable.call((const Variant **)&evp, 1, ret, ce);
}

} else {
//send to all windows
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
Expand Down
Loading

0 comments on commit 3a56f52

Please sign in to comment.