![]() |
|
[4.20] 'd_shadow_box_proc' crashes 'popup_dialog' |
Dennis
Member #1,090
July 2003
![]() |
I think I've found a bug. [4.20] 'd_shadow_box_proc' crashes 'popup_dialog' "popup_crash.c"
I compiled this using mingw32 version 3.4.2 gcc -O2 -Wall -c popup_crash.c gcc -o popup.exe *.o -mwindows -lalleg gcc -o popupd.exe *.o -mwindwos -lalld So popup.exe was linked to the release version of the Allegro 4.20 library, while popupd.exe was linked to the debug version. Now what this should demonstrate is that running popup.exe will show two popup dialogs one after another and then exit normally. popupd.exe should crash on the second popup, which I believe is directly related to the d_shadow_box_proc, which dimensions are 0 in that second popup dialog. I get the same behaviour when I compile everything with MSVC 2005,(crash in debug version, no crash in release version) so I believe this is a bug in Allegro. not necessarily important background info: (I found this on investigating a crash in one of my apps that never happened in the release build and always in the debug build. The reason why my d_shadow_box_proc s are per default dimensioned as 0, was simply that i'm using a custom d_stretch_dialog_proc as the second last object in each of my dialogs to adjust the dimensions of the first object to always be large enough to include all other objects.) --- 0xDB | @dennisbusch_de --- |
Kitty Cat
Member #2,815
October 2002
![]() |
Quote: popupd.exe should crash on the second popup, which I believe is directly related to the d_shadow_box_proc, which dimensions are 0 in that second popup dialog The "crash" is actually a failed ASSERT. Under Unix, you'd get a nice "Aborted" message in the console (as opposed to Segment Violation, Illegal Instruction, or whatever else). Trying to create a 0-sized bitmap will trigger an ASSERT which will immediately SIGABRT the program. -- |
Dennis
Member #1,090
July 2003
![]() |
Well windows says "Runtime Error! Application terminated in an unusual way." and I thought that's the same as a crash. There is another thing that should get corrected in popup dialog though. Of course I could send that message myself before calling popup_dialog. for viewing convenience, here's a copy of 'popup_dialog' in src/gui.proc
--- 0xDB | @dennisbusch_de --- |
Kitty Cat
Member #2,815
October 2002
![]() |
Quote: for viewing convenience, here's a copy of 'popup_dialog' in src/gui.proc And as you can see, there's no real way for it to safely send the MSG_START message itself without re-implmenting the dialog player loop. TFM said:
Like do_dialog(), but it stores the data on the screen before drawing the dialog and restores it when the dialog is closed. The screen area to be stored is calcu- lated from the dimensions of the first object in the dialog, so all the other objects should lie within this one.
Double check the last sentence. -- |
Dennis
Member #1,090
July 2003
![]() |
Quote:
Quote:
Like do_dialog(), but it stores the data on the screen before drawing the dialog Double check the last sentence.
"...before drawing the dialog..." yes. The docs for MSG_START said: "Tells the object to initialise itself. The dialog manager sends this to all objects in the dialog just before it displays the dialog."
Quote: And as you can see, there's no real way for it to safely send the MSG_START message itself without re-implmenting the dialog player loop.
What would be wrong about adding a single line, in front of 'bmp = create_..' that says something like if(dialog!=NULL) dialog_message(dialog,MSG_START,...);? --- 0xDB | @dennisbusch_de --- |
Kitty Cat
Member #2,815
October 2002
![]() |
A dialog object should not receive MSG_START multiple times in a row. More often than not, MSG_START will cause some objects to allocate memory, so multiple start messages will cause memory leaks. The only way to get around that would be to call a MSG_CLOSE right after, and that's.. ugly (and could just as easilly negate the resize). -- |
Evert
Member #794
November 2000
![]() |
Quote: The dialog manager sends this to all objects in the dialog just before it displays the dialog.
Which is what it does. What it does not do is send MSG_START again if it redraws the dialog. Quote: Why it doesn't terminate abnormally in the release version is beyond my scope. The error isn't caught. In my experience, 0-sized bitmaps don't (always) generate a crash; they're still not allowed though. Quote: What would be wrong about adding a single line, in front of 'bmp = create_..' that says something like if(dialog!=NULL) dialog_message(dialog,MSG_START,...);? What would be wrong is that do_dialog() already does that. As I said, you can easily write your own wrapper that does more advanced stuff if youwant to do that, but doing this from within Allegro's function changes the behavior of the function, which might break existing programmes. |
Ron Novy
Member #6,982
March 2006
![]() |
Kitty Cat said: The only way to get around that would be to call a MSG_CLOSE right after, and that's.. ugly (and could just as easilly negate the resize). I believe it's actually MSG_END and not MSG_CLOSE. If you are not happy with the way popup_dialog is working then the best thing to do is copy the popup_dialog function out of 'gui.c', and any relevant static functions into a new file and add it to your project. Just remember to change the name of the function and then you can modify it as much as you like without affecting the library itself. All the d_xxx_proc objects rely on the current functionality so the wrong change could mean more crashes. You could also create a dummy object at the start of the dialog with a default size but you would probably be better off using the allegro popup_dialog function as it was intended. ---- |
Dennis
Member #1,090
July 2003
![]() |
Quote: Which is what it does. What it does not do is send MSG_START again if it redraws the dialog. I did not think it would do that before every redraw. I'm not having an issue with that. I just assumed that MSG_START is send at least once, before the dialog is displayed for the first time. I still think that popup_dialog is not functioning properly, let me explain: popup_dialog saves a portion of the bitmap the dialog is to be drawn onto before running the dialog(via do_dialog) to later restore this portion. So popup_dialog should be conceptually related to anything that's related to displaying the dialog correctly and to clean up (restoring) the display area underneath it after running it. If a dialog object does stretch itself, because it assumes that (as mentioned in the manual) it gets a one time chance to initialize itself before the dialog is displayed for the first time then the saving of that screen portion should respect that, because the dimensions of an object are directly display behaviour related and the saving of a bitmap portion to later restore it, is also directly display behaviour related. I do understand now by your arguments that sending MSG_START twice could break stuff, but that doesn't change my mind that popup_dialog is behaving wrong, because of the aforementioned logic(display behaviour) which I think is a valid point. The easiest way out of the issue for me, as suggested by KittyCat on IRC, is to not use popup_dialog and instead use do_dialog and just redrawing the previous dialog below it after it exits. The current implementation of popup_dialog feels obsolete to me then, because it does not respect objects that stretch on initialization of a dialog and thus can't save and restore the used display space properly.:-/ I agree though that I have to write my own function now or use do_dialog. I would just appreciate it, if my arguments were at least heard and understood right. --- 0xDB | @dennisbusch_de --- |
Ron Novy
Member #6,982
March 2006
![]() |
You could use do_dialog and write an object proc to use at the top of a dialog that would calculate the stretch and size of the dialog and save the background (if needed) at MSG_START and draw the shadow_box. Store the bmp pointer in dp... Since its the first object and contains all other objects it could handle the stretching and only save/restore the necessary parts of the screen.... I'm sure lex gui does something like that. ---- |
Dennis
Member #1,090
July 2003
![]() |
That would be hackish. I prefer to write a proper implementation of popup_dialog instead, which is easier because, as you said, all the code is already there. I just need to copy and modify it slightly.:) --- 0xDB | @dennisbusch_de --- |
Evert
Member #794
November 2000
![]() |
I disagree. That said, it's possible to work around all of these issues without too much trouble. You run into the same issue if you try to implement moving dialogs. I worked around that by creating a custom dialog object, at the start of the dialog, that does the double buffer itself. It's what I'd recommend you to do. I should note that I use neither do_dialog() nor popup_dialog() because I want to continue running the logic loop while the dialog is displayed, which in a way bypasses the issue. |
Ron Novy
Member #6,982
March 2006
![]() |
Not that this would help but I've been working on a non-blocking windowing system for allegro that uses modified versions of the dialog procedures and uses an AL_DESKTOP structure to store all the global menu, window and dialog stuff. It's pretty cool because it uses the allegro style objects (slightly modified) so it would be easy to create a window template but it's no where near completion. If anyone has any ideas or info on how coding a windowing gui let me know but I'm out for the day so I'm marking this thread just in case. ---- |
Dennis
Member #1,090
July 2003
![]() |
Quote: Resizable widgets are something the Allegro GUI can't do, popup_dialog() is consistent with that.
But the API allows and encourages having custom dialog objects, so it should at least respect that some objects might want to do some initialization that affects displaying behaviour, which is why I think popup_dialog is not sufficiently advanced. Quote: The behavior also isn't inconsistent with the documentation, so it doesn't qualify as a bug either.
The initial thing I thought was a bug wasn't the behaviour, but the crash(or failed ASSERT) that I know now is because of that implicit create_bitmap(0,0) call. The behaviour of popup_dialog however, even if it doesn't crash, I would also not call a bug, but a wrong(or insufficient) implementation of a desired behaviour. Both changes to the documentation will look very ugly and hilarious of course, so a proper implementation of popup_dialog is preferred. Quote: [..]It's what I'd recommend you to do. I should note that I use neither do_dialog() nor popup_dialog() because I want to continue running the logic loop while the dialog is displayed, which in a way bypasses the issue. Thanks for your suggestions. I'm using popup_dialog only for very few sub dialogs that require to be answered before the programme can go on. I think I can live with making them use do_dialog instead. For my advanced main dialog that used lots of customized objects and behaviours, I am already using a customized dialog runner. --- 0xDB | @dennisbusch_de --- |
Evert
Member #794
November 2000
![]() |
Quote: But the API allows and encourages having custom dialog objects, so it should at least respect that some objects might want to do some initialization that affects displaying behaviour You can, there's no problem with the GUI code per se; but it's impossible to foresee all possible things a user might want to do in a function like popup_dialog(). popup_dialog() stumbles on dialogs that do not have the size that they are declared with, or are drawn to a different location. It's just not designed to handle those situations. Quote: It's true that the documentation says that popup_dialog uses the dimensions of the first object to do the saving/restoring, but it doesn't say that it will use the dimensions that are in there, before the object actually got a chance to properly initialize itself. Right, so the order is undefined by the documentation. Quote:
I hope you can at least agree that the documentation of popup_dialog should probably mention that the objects don't get a chance to initialize themselves properly, before the dimensions of the first object are being taken for the saving and restoring of the overdrawn bitmap area. Both changes to the documentation will look very ugly and hilarious of course,
The latter certainly, the former depends on how you word it. Quote:
Like do_dialog(), but it stores the data on the screen before drawing
Quote: so a proper implementation of popup_dialog is preferred. I maintain that the current implementation is fine: it does what it's supposed to do. Quote: Note that I'm not trying to irritate you
Good. Quote: I'm only interested in making it actually better and I think with a rewrite of popup_dialog(that does not send MSG_START twice and does not rely on do_dialog), this could be done without breaking existing programmes. Probably. However, it will duplicate a lot of code and it means possible fixes to do_dialog() would need to be applied to both functions, making it harder to maintain. Quote: Under that light, your statement "That said, it's possible to work around all of these issues without too much trouble." actually also applies to changing the popup_dialog function. You can do it without changing popup_dialog() by using a custom dialog object that handles the creation and maintenance of the backbuffer. |
Dennis
Member #1,090
July 2003
![]() |
Quote: Probably. However, it will duplicate a lot of code and it means possible fixes to do_dialog() would need to be applied to both functions, making it harder to maintain.
It could be done without duplicating code and thus the point of harder maintainability becomes void. I've prepared a little something. (untested but if my eyes don't fool me, calling that new do_dialog_ex function with the third parameter as false will not change the behaviour of the current do_dialog at all, while calling it with that parameter as true will be nearly the same behaviour as the current popup_dialog(with the improvement that it respects initialization of the dialog prior to saving the display area)) all functions taken from src\gui.c of Allegro 4.20:
--- 0xDB | @dennisbusch_de --- |
|