Show a window from a modal dialog

I did take this approach for something but I found impractical for my general need. Some controls would require to completely reinvent the wheel and requiring too much time.
And btw, we handle a code base of 100+ (growing) applications :wink:

But thanks for your suggestion.

Just getting my head around what you’re trying to do. So you have a window, you then open a modal window, you then open a window from the modal? That last window would be a popup type window that would auto-close if focus was lost?

If I’ve not got this right could you pop up a quick demo app that I could tweak?

[quote=427993:@Massimo Valle]I tried to replicate the above, and wrote this:
[…]
but seems to do nothing. Worse, the SWP_NOACTIVATE completely prevent the window to get keyboard focus. Removing it, the above code behave like if it’s not called, that is, the window is set to front, the keyboard input is active, only the mouse is not captured.[/quote]

Can you try it without SWP_NOACTIVATE but with addition of SetCapture to capture mouse events?

My last comment probably isn’t going to work, apparently only the active window can capture the mouse. Working through an old SDK example to see if I can find something that will work.

It sounds like what you want is a tool window. Something like this should do it.

[code]Private Sub SetToolWindow(w as Window)
#if TargetWindows
Dim oldFlags, newFlags, styleFlags As Integer

Const WS_EX_TOOLWINDOW = &h00000080

Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const SWP_NOZORDER = &H4
Const SWP_FRAMECHANGED = &H20

Const GWL_EXSTYLE = -20

dim flag as Integer = WS_EX_TOOLWINDOW

Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (hwnd As Integer,  _
nIndex As Integer) As Integer
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (hwnd As Integer, _
nIndex As Integer, dwNewLong As Integer) As Integer
Declare Function SetWindowPos Lib "user32" (hwnd as Integer, hWndInstertAfter as Integer, _
x as Integer, y as Integer, cx as Integer, cy as Integer, flags as Integer) as Integer

oldFlags = GetWindowLong(w.Handle, GWL_EXSTYLE)
newFlags = BitwiseOr( oldFlags, flag )


styleFlags = SetWindowLong( w.Handle, GWL_EXSTYLE, newFlags )
styleFlags = SetWindowPos( w.Handle, 0, 0, 0, 0, 0, SWP_NOMOVE +_
SWP_NOSIZE + SWP_NOZORDER + SWP_FRAMECHANGED )

#endif
End Sub
[/code]

Some really old code there, and could probably be finessed to be a bit more efficient. I think I last worked on that when Aaron Ballman was around.

EDIT: Cleaned it up a bit. Then it’s just a matter of parent/child positioning.

[quote=428115:@Anthony Cyphers]It sounds like what you want is a tool window. Something like this should do it.

[code]Private Sub SetToolWindow(w as Window)
#if TargetWindows
Dim oldFlags, newFlags, styleFlags As Integer

Const WS_EX_TOOLWINDOW = &h00000080

Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const SWP_NOZORDER = &H4
Const SWP_FRAMECHANGED = &H20

Const GWL_EXSTYLE = -20

dim flag as Integer = WS_EX_TOOLWINDOW

Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (hwnd As Integer,  _
nIndex As Integer) As Integer
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (hwnd As Integer, _
nIndex As Integer, dwNewLong As Integer) As Integer
Declare Function SetWindowPos Lib "user32" (hwnd as Integer, hWndInstertAfter as Integer, _
x as Integer, y as Integer, cx as Integer, cy as Integer, flags as Integer) as Integer

oldFlags = GetWindowLong(w.Handle, GWL_EXSTYLE)
newFlags = BitwiseOr( oldFlags, flag )


styleFlags = SetWindowLong( w.Handle, GWL_EXSTYLE, newFlags )
styleFlags = SetWindowPos( w.Handle, 0, 0, 0, 0, 0, SWP_NOMOVE +_
SWP_NOSIZE + SWP_NOZORDER + SWP_FRAMECHANGED )

#endif
End Sub
[/code]

Some really old code there, and could probably be finessed to be a bit more efficient. I think I last worked on that when Aaron Ballman was around.

EDIT: Cleaned it up a bit. Then it’s just a matter of parent/child positioning.[/quote]

Thanks for sharing this. Unfortunately this doesn’t work for my case.

[quote=428055:@]Just getting my head around what you’re trying to do. So you have a window, you then open a modal window, you then open a window from the modal? That last window would be a popup type window that would auto-close if focus was lost?

If I’ve not got this right could you pop up a quick demo app that I could tweak?[/quote]

Here it’s a test project showing what I need to do. It’s a fictionary project, just to exemplify my use.
It basically have a base window where you can open Modal dialog and from it open a “popup” window.
There are two example popup windows, one without anything special which works for everything except it doesn’t capture the mouse events (clicks truly).
A second one just use a Timer to set SetCapture() continuosly. It’s a bit clunky, but so far this is the only solution I found.

Thanks for everyone helping me on finding a solution.

I dug in to this a bit. It looks like Xojo is doing something when creating the Sheet Window, Moveable Modal, and Modal DIalog window types that’s borking things here (that I remember working). If I set the Window.Type to Document, then use the SetToolWindow method I supplied above, everything works as expected in my testing. You can use ShowModalWithin on the parent, and you call SetToolWindow in the desired window’s Constructor.

So you mean this will never work?

I’m not sure to understand if this works for you, sorry.
I tried to use the call to SetToolWindow in the Constructor as you suggested on my example linked above, but still doesn’t work.

If this works for you, can you please explain me how?
You can download the above example, it already has the method you posted, just not used at the moment.

Thanks anyway.

This as good as I could get it, it’s not 100% correct.

https://www.dropbox.com/s/sok4hws650l1pzq/PopWindowTest.xojo_binary_project?dl=0

There are a few limitations of the framework that won’t allow me to do this 100% correctly, I can do it in other languages but the inability to click on those controls on the popup is, from my limited knowledge of the framework, a fundamental issue in the framework when modal windows are shown. At a guess, it’s not responding to the events of controls that are not on the last opened modal window, which is an oversight that this use case highlights. I could be wrong (it wouldn’t be the first time) this is just my gut feeling.

It might be possible to get around all the above with a custom WndProc, I don’t know without trying but I’ve spent enough time on this one, I’ll let someone else try that :wink:

Yeah I’m coming to similar conclusions, something doesn’t seem right in the modal window’s event processing but it’s hard to nail down. I have an example that almost works, with a custom message pump loop, but I can’t quite get it to work so far. Going to keep fiddling with it for awhile.

I think the problem might be something to do with the fact that the message pump can’t be in a Xojo event, otherwise it blocks further Xojo event processing on that thread. That’s barely more than a guess though. Might have to go multithreaded.

After a quick chat and RubberDuck with @Anthony Cyphers he suggested trying Floating Windows.

That looks like its done the job as its setting the parent, which is needed, then some liberal declare sprinkles sort out the enable/disable of parent windows.

You’ll just need to move the windows into the correct positions for your popups and you should be good to go, we think :slight_smile:

https://www.dropbox.com/s/gv3pdyf8g3trlqs/PopWindowTest2.xojo_binary_project?dl=0

[quote=428450:@]After a quick chat and RubberDuck with @Anthony Cyphers he suggested trying Floating Windows.

That looks like its done the job as its setting the parent, which is needed, then some liberal declare sprinkles sort out the enable/disable of parent windows.

You’ll just need to move the windows into the correct positions for your popups and you should be good to go, we think :slight_smile:

https://www.dropbox.com/s/gv3pdyf8g3trlqs/PopWindowTest2.xojo_binary_project?dl=0[/quote]

I am getting this on macOS Mojave Version 10.14.3 and Xojo 2018 Release 4
x86 64 bit

Linking Executable
ld: framework not found User32

and with x86 32 bit it compiles but “My Application cannot be opened because of a problem”.
Process: My Application [798]
Path: /Users/USER/Downloads/*/My Application.app/Contents/MacOS/My Application
Identifier: info.sacosoftwareconsultinggmbh.myapp
Version: ??? (1.0.0.0.0)
Code Type: X86 (Native)
Parent Process: ??? [1]
Responsible: My Application [798]
User ID: 501

Date/Time: 2019-03-14 07:41:51.723 -0500
OS Version: Mac OS X 10.14.3 (18D109)
Report Version: 12
Anonymous UUID: BDA6A01F-92C6-AC8E-17F0-7DDBFA91B9DA

Time Awake Since Boot: 4200 seconds

System Integrity Protection: enabled

Crashed Thread: 0

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY

Termination Reason: DYLD, [0x1] Library missing

Lennox

First of all, thank you @ @Anthony Cyphers and everyone else spent time and efforts for helping me on finding a solution.

@ your solution works pretty much well for this case.
However this solution has some major flaws for my prospected use that make it impossible or really hard to use it:

  • As I initially stated, this is a cross platform solution. Setting the modal dialog as a Floating window prevent to show it on Mac as a Sheet, and this is not acceptable for my requirements. Moreover, the floating window disappear when the whole app goes in background, but most important, with this approach it would require a Mac solution to behave like on Windows due the standard way is broken. That is, would be like fixing something which is already working.

  • The popup window I have to show is part of a component (actually many different components) which have no knowledge of the Base window that ultimately fired its execution. But this approach rely on disabling the base window before opening the popup and enabling it again from the popup on close. This means redesign everything to pass along the base window to modal dialogs and redesign as well the components to take this base window reference. This for something like 100+ applications. ugh…

  • The fake ModalDialog is indeed only mocking the modal UI behaviour but it remain modeless, that is the base window still execute code after showing the (fake) modal dialog. Again this can be handled in some way, but again this would be a huge amount of work on refactoring how applications works.

In the end, this would require a major refactor of my codebase that I can’t afford at this time. And still I feel there could be other unwanted side effects.
I guess at this point I will go with my solution of keeping a timer running and check/set the SetCapture method. Still far from perfect but at least easy to implement and effective.

Nonetheless, I do understand the problem (probably) lies on a limitation on the Xojo framework and/or the Win32 framework and this is probably one of the best solutions to solve the problem. I also do understand you guys tried hard to help me and spent time on it, so I wish to thank you all again for the efforts and please don’t feel offended by my critics.

:smiley:

I only worked on the windows part of it, it won’t run on the mac as it is.

No offence at all, I enjoy tinkering, I forgot you needed it xplat and its a shame we can’t alter Window Frame Type at runtime.

The Window class of the Xojo framework is one of the weakest point in general. As not being able to create windows by code in 2019 really set some limitations.

Thanks Julian, “no sweat”, it’s Ok.
Lennox

I’m attaching my project at this point since it might help with the frame type issues – I have logic to re-parent a Xojo window to a Win32 API window. This should allow you to leave the frame type as Sheet and act like it isn’t such on Windows (I think). You’ll need to extract that bit of the code, however, as this still has my message pump in it. The uploaded version actually does have this separated as the third button on wBackground, without a message pump.

Oh, and the code is an absolute mess of inconsistent styles, sorry about that.

https://www.dropbox.com/s/0jr0cs5x1x7yonu/PopupTest5.xojo_binary_project?dl=0

Thanks Isaac, I will check it.

[quote=427984:@Massimo Valle]Example: the dialog has some custom controls on it where the user has to make a choice before initiating some other action. Like a date field accepting a date and optionally with a button to open a date picker as a popup small window. This date picker field is a reusable container control.
Of course can’t close the dialog because this is where the user make a choice.[/quote]

I see a solution in plain Xojo that should work Xplat :

Instead of using a dialog, use a false modal :

Grab the screen content, then pop a window, maximize it and use the grabbed picture of the screen.

Then display a regular window instead of the dialog. Since the maximized window will prevent clicking underneath, the regular window is the only place where click has effect. So it behaves like a modal.

From that regular window, you can show any window or dialog you want.

When closing the false modal, close the maximized false screen background.