diff --git a/src/dialogxml/dialogs/dialog.cpp b/src/dialogxml/dialogs/dialog.cpp index 543bd195..7a44dea0 100644 --- a/src/dialogxml/dialogs/dialog.cpp +++ b/src/dialogxml/dialogs/dialog.cpp @@ -544,9 +544,11 @@ void cDialog::run(std::function onopen){ if(onopen) onopen(*this); animTimer.restart(); + has_focus = true; handle_events(); win.setVisible(false); + // Flush events on parent window from while this one was running while(pollEvent(parentWin, currentEvent)); set_cursor(former_curs); topWindow = formerTop; @@ -625,6 +627,9 @@ void cDialog::handleTab(bool reverse) { } } +extern sf::RenderWindow& mini_map(); +extern bool map_visible; + // This method handles one event received by the dialog. void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& fps_limiter) { using Key = sf::Keyboard::Key; @@ -737,10 +742,31 @@ void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& where = {(int)(currentEvent.mouseButton.x / get_ui_scale()), (int)(currentEvent.mouseButton.y / get_ui_scale())}; process_click(where, key.mod, fps_limiter); break; - default: // To silence warning of unhandled enum values + case sf::Event::LostFocus: + has_focus = false; + setWindowFloating(mini_map(), false); break; case sf::Event::GainedFocus: - case sf::Event::MouseMoved: + if(!has_focus){ + has_focus = true; + setWindowFloating(mini_map(), true); + makeFrontWindow(mainPtr()); + if(map_visible) + makeFrontWindow(mini_map()); + std::vector dialog_stack; + cDialog* next = this; + while(next != nullptr){ + dialog_stack.push_back(&(next->win)); + next = next->parent; + } + for(int i = dialog_stack.size() - 1; i >= 0; --i){ + makeFrontWindow(*(dialog_stack[i])); + } + // that generates a LostFocus and a GainedFocus event + sf::Event evt; + while(pollEvent(win, evt)); + } + case sf::Event::MouseMoved:{ // Did the window move, potentially dirtying the canvas below it? if(check_window_moved(win, winLastX, winLastY)) if (redraw_everything != NULL) @@ -755,6 +781,8 @@ void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& } } if(!inField) set_cursor(sword_curs); + }break; + default: // To silence warning of unhandled enum values break; } } diff --git a/src/dialogxml/dialogs/dialog.hpp b/src/dialogxml/dialogs/dialog.hpp index 7009d5e8..219d9692 100644 --- a/src/dialogxml/dialogs/dialog.hpp +++ b/src/dialogxml/dialogs/dialog.hpp @@ -77,6 +77,7 @@ class cDialog : public iComponent, public iNameGiver { static bool initCalled; int anim_pict_fps = 2; bool doAnimations; + bool has_focus = false; public: static void (*redraw_everything)(); /// Performs essential startup initialization. Generally should not be called directly. diff --git a/src/game/boe.main.cpp b/src/game/boe.main.cpp index 74e1bbea..fe728067 100644 --- a/src/game/boe.main.cpp +++ b/src/game/boe.main.cpp @@ -1199,6 +1199,13 @@ static void update_delayed_keys() { } } +bool game_has_focus = true; +bool game_had_focus = true; +bool main_window_lost_focus = false; +bool main_window_gained_focus = false; +bool map_window_lost_focus = false; +bool map_window_gained_focus = false; + void handle_events() { sf::Event currentEvent; cFramerateLimiter fps_limiter; @@ -1243,6 +1250,7 @@ void handle_events() { fake_event_queue.pop_front(); handle_one_event(next_event, fps_limiter); } + while(pollEvent(mainPtr(), currentEvent)) handle_one_event(currentEvent, fps_limiter); // It would be nice to have minimap inside the main game window (we have lots of screen space in fullscreen mode). @@ -1267,6 +1275,30 @@ void handle_events() { // Ideally, this should be the only draw call that is done in a cycle. redraw_everything(); + bool any_lost_focus = main_window_lost_focus || map_window_lost_focus; + bool any_gained_focus = main_window_gained_focus || map_window_gained_focus; + + if(game_had_focus && any_lost_focus && !any_gained_focus){ + game_has_focus = false; + // The game completely lost focus. The map floating is going to block + // other applications and be annoying. + setWindowFloating(mini_map(), false); + }else if(!game_had_focus && any_gained_focus){ + game_has_focus = true; + + // The game regained focus + setWindowFloating(mini_map(), true); + if(map_visible){ + makeFrontWindow(mini_map()); + makeFrontWindow(mainPtr()); + } + } + + main_window_lost_focus = main_window_gained_focus = + map_window_lost_focus = map_window_gained_focus = false; + + game_had_focus = game_has_focus; + // Prevent the loop from executing too fast. fps_limiter.frame_finished(); } @@ -1338,10 +1370,15 @@ void handle_one_event(const sf::Event& event, cFramerateLimiter& fps_limiter) { case sf::Event::GainedFocus: check_window_moved(mainPtr(), last_window_x, last_window_y, "MainWindow"); + main_window_gained_focus = true; makeFrontWindow(mainPtr()); change_cursor({event.mouseMove.x, event.mouseMove.y}); return; + case sf::Event::LostFocus: + main_window_lost_focus = true; + return; + case sf::Event::MouseMoved: check_window_moved(mainPtr(), last_window_x, last_window_y, "MainWindow"); change_cursor({event.mouseMove.x, event.mouseMove.y}); @@ -1371,12 +1408,15 @@ int last_map_y = 0; void handle_one_minimap_event(const sf::Event& event) { if(event.type == sf::Event::Closed) { close_map(true); - } else if(event.type == sf::Event::GainedFocus) { + }else if(event.type == sf::Event::GainedFocus){ + map_window_gained_focus = true; check_window_moved(mini_map(), last_map_x, last_map_y, "MapWindow"); makeFrontWindow(mainPtr()); + }else if(event.type == sf::Event::LostFocus){ + map_window_lost_focus = true; }else if(event.type == sf::Event::MouseMoved){ check_window_moved(mini_map(), last_map_x, last_map_y, "MapWindow"); - }else if(event.type == sf::Event::KeyPressed) { + }else if(event.type == sf::Event::KeyPressed){ switch(event.key.code){ case sf::Keyboard::Escape: close_map(true);