From 9d983dcf5293d883b269990c20d9829a3fbd6832 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Wed, 18 May 2016 12:33:48 +0300 Subject: [PATCH] fix window closing and input events handling if there is modal window above - fix #251 under windows --- src/dlangui/platforms/common/platform.d | 23 ++++++++++++++++++++ src/dlangui/platforms/sdl/sdlapp.d | 1 - src/dlangui/platforms/windows/winapp.d | 29 ++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index 9a61a1ff..c0b5702c 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -166,7 +166,9 @@ class Window : CustomEventTarget { protected uint _backgroundColor; protected Widget _mainWidget; protected EventList _eventList; + protected uint _flags; + @property uint flags() { return _flags; } @property uint backgroundColor() const { return _backgroundColor; } @property void backgroundColor(uint color) { _backgroundColor = color; } @property int width() const { return _dx; } @@ -304,8 +306,15 @@ class Window : CustomEventTarget { /// set handler for closing of window @property Window onClose(void delegate() handler) { _onClose = handler; return this; } + /// returns true if there is some modal window opened above this window, and this window should not process mouse/key input and should not allow closing + bool hasModalWindowsAbove() { + return platform.hasModalWindowsAbove(this); + } + /// calls onCanClose handler if set to check if system may close window bool handleCanClose() { + if (hasModalWindowsAbove()) + return false; if (!_onCanClose) return true; bool res = _onCanClose(); @@ -446,7 +455,10 @@ class Window : CustomEventTarget { static immutable int PERFORMANCE_LOGGING_THRESHOLD_MS = 20; + /// set when first draw is called: don't handle mouse/key input until draw (layout) is called + protected bool _firstDrawCalled = false; void onDraw(DrawBuf buf) { + _firstDrawCalled = true; static import std.datetime; try { bool needDraw = false; @@ -569,6 +581,8 @@ class Window : CustomEventTarget { /// dispatch keyboard event bool dispatchKeyEvent(KeyEvent event) { + if (hasModalWindowsAbove() || !_firstDrawCalled) + return false; bool res = false; hideTooltip(); PopupWidget modal = modalPopup(); @@ -874,6 +888,8 @@ class Window : CustomEventTarget { private int _lastMouseY; /// dispatch mouse event to window content widgets bool dispatchMouseEvent(MouseEvent event) { + if (hasModalWindowsAbove() || !_firstDrawCalled) + return false; // ignore events if there is no root if (_mainWidget is null) return false; @@ -1308,6 +1324,13 @@ class Platform { /// calls request layout for all windows abstract void requestLayout(); + /// returns true if there is some modal window opened above this window, and this window should not process mouse/key input and should not allow closing + bool hasModalWindowsAbove(Window w) { + // override in platform specific class + return false; + } + + protected string _uiLanguage; /// returns currently selected UI language code @property string uiLanguage() { diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index c66c60c5..8ede15e9 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -137,7 +137,6 @@ class SDLWindow : Window { } } - protected uint _flags; bool create(uint flags) { if (!_dx) _dx = 600; diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index f5822051..8177302a 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -237,7 +237,6 @@ class Win32Window : Window { dstring _caption; Win32ColorDrawBuf _drawbuf; bool useOpengl; - uint _flags; this(Win32Platform platform, dstring windowCaption, Window parent, uint flags, uint width = 0, uint height = 0) { Win32Window w32parent = cast(Win32Window)parent; HWND parenthwnd = w32parent ? w32parent._hwnd : null; @@ -833,11 +832,15 @@ class Win32Platform : Platform { } return cast(int)msg.wParam; } + private Win32Window[ulong] _windowMap; + private Win32Window[] _windowList; + /// add window to window map void onWindowCreated(HWND hwnd, Win32Window window) { Log.v("created window, adding to map"); _windowMap[cast(ulong)hwnd] = window; + _windowList ~= window; } /// remove window from window map, returns true if there are some more windows left in map bool onWindowDestroyed(HWND hwnd, Win32Window window) { @@ -848,6 +851,15 @@ class Win32Platform : Platform { _windowsToDestroy ~= window; //destroy(window); } + for (uint i = 0; i < _windowList.length; i++) { + if (window is _windowList[i]) { + for (uint j = i; j + 1 < _windowList.length; j++) + _windowList[j] = _windowList[j + 1]; + _windowList[$ - 1] = null; + _windowList.length--; + break; + } + } return _windowMap.length > 0; } /// returns number of currently active windows @@ -878,6 +890,21 @@ class Win32Platform : Platform { } } + /// returns true if there is some modal window opened above this window, and this window should not process mouse/key input and should not allow closing + override bool hasModalWindowsAbove(Window w) { + // override in platform specific class + for (uint i = 0; i + 1 < _windowList.length; i++) { + if (_windowList[i] is w) { + for (uint j = i + 1; j < _windowList.length; j++) { + if (_windowList[j].flags & WindowFlag.Modal) + return true; + } + return false; + } + } + return false; + } + /// handle theme change: e.g. reload some themed resources override void onThemeChanged() { foreach(w; _windowMap)