mettli / guichan

Automatically exported from code.google.com/p/guichan
Other
0 stars 0 forks source link

sometimes dropdown halts applications when dropdown is clicked #59

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago

using SDL with guichan 0.8.1 when some applications reach gui->logic()
they hang out (i dont know why this happened, sometimes it hangs, other not)
i commented that and now it is working

---

    void Gui::logic()
    {
        if (mTop == NULL)
        {
            throw GCN_EXCEPTION("No top widget set");
        }

        handleModalFocus();

        // fix on dropdowns halt...
    //handleModalMouseInputFocus();

        if (mInput != NULL)
        {
            mInput->_pollInput();

            handleKeyInput();
            handleMouseInput();

        } // end if

        mTop->logic();
    }

Original issue reported on code.google.com by thenetce...@gmail.com on 24 Jul 2008 at 10:49

GoogleCodeExporter commented 9 years ago
Hi, im a developer of openanno (www.openanno.org) and we use the fife engine, 
which 
uses guichan.
We have the same issues with dropdown boxes, i just want to confirm this but 
cant 
give a more detailed bug description, all i know is that an excaption is thrown 
and 
that the logic function by this does not do anything anymore.

Original comment by kristoff...@googlemail.com on 12 Aug 2008 at 11:01

GoogleCodeExporter commented 9 years ago
I need to be able to reproduce the problem to fix it. What is the exception 
thrown?
Can you use a debugger to see where the problem occurs?

Original comment by olof.nae...@gmail.com on 18 Aug 2008 at 1:20

GoogleCodeExporter commented 9 years ago
the problem occurs in handleModalMouseInputFocus();
when the dropdown box is clicked

i don't know why this happened
apparently is a null pointer exception

Original comment by thenetce...@gmail.com on 19 Aug 2008 at 12:59

GoogleCodeExporter commented 9 years ago
I have a similar problem.  I am using guichan 8.1 .

To reproduce create a TabbedArea with two Tabs: Tab1 and Tab2. In each tab 
place a 
dropdown, DD1 and DD2 populated with some items.
Click Tab2
Click DD2 and select an item from the list
Click Tab1
Click DD1

At this point an exception is thrown from Tab2's isModalMouseInputFocused() 
complaining that there is no focus handler.  There is no focus handler because 
we 
set the focus handler to NULL when Tab2 was removed from the TabbedArea after 
clicking Tab1.  A pointer to Tab2 seems to be still lingering in the 
mWidgetWithMouseQueue after the widget had been removed from the widget 
hierarchy.

Original comment by esm...@gmail.com on 3 Sep 2008 at 6:14

GoogleCodeExporter commented 9 years ago

In guichan-0.8.1/src/gui.cpp
problem occurs here

    void Gui::handleModalMouseInputFocus()
    {
        // Check if modal mouse input focus has been gained by a widget.
        if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() 
                != mFocusHandler->getModalMouseInputFocused())
             && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() == NULL))
        {
            handleModalFocusGained();

mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMous
eInputFocused());
        }
        // Check if modal mouse input focus has been released.
        else if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus()
                    != mFocusHandler->getModalMouseInputFocused())
                    && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() != NULL))
        {
            handleModalFocusReleased();
            mFocusHandler->setLastWidgetWithModalMouseInputFocus(NULL);
        }
    }

Original comment by thenetce...@gmail.com on 3 Sep 2008 at 11:56

GoogleCodeExporter commented 9 years ago
I can't recreate it with the latest Guichan SVN version. I fixed a possible 
segfault 
concerning modal mouse input some time ago, perhaps it took care of the problem?

Note, I always work with the latest SVN version. If you have a bug you should 
try the 
SVN version as things might have been taken care of.

Original comment by olof.nae...@gmail.com on 3 Sep 2008 at 1:41

GoogleCodeExporter commented 9 years ago
I have had the same over the weekend, SVN version, and after some debugging I 
think 
I know where it comes from. 

Here's what I did: I have two containers which serve as top level widgets, one 
for 
each screen. My gameloop can switch screens by calling 
gui->setTop(new_toplevel); 
Now, each of these containers has widgets as children, but top2 has a dropdown 
somewhere as child. Now I start with top1, all is fine, then gui->setTop(top2) 
is 
called, I can see the dropdown, but when I click it, I get the exception. It 
complains about a widget not having a focus handler, and I really wondered... 
and 
then the debugger told me that it's top1 that complains here!!! 

Why is that? Simple, there's a double bookkeeping hidden in gcn::Gui. On the 
one 
hand you have mTop (and its children), but for focus handling you use 
mWidgetWithMouseQueue, which may contain widgets that are not children of the 
current top level widget. Voila! 

Several solutions, as I see it, though I don't know exactly how this is 
intended to 
work. The simplest is to ask for existing focus handler in line 939, which 
would 
then read 
            if (Widget::widgetExists(widget) && widget->_getFocusHandler())
That works for my example, but I guess that that would only be a workaround, 
not a 
real solution. 

It might be a better solution to get rid of the extra bookkeeping and traverse 
the 
widgets starting with the current top level widget instead of using 
mWidgetWithMouseQueue. 

Or you would have to make sure that the current widget hierarchy is in sync 
with the 
widgets in mWidgetWithMouseQueue. 

Hopefully this helps to nail down this problem and solve it! 

Original comment by tobias.s...@gmx.net on 15 Sep 2008 at 12:00

GoogleCodeExporter commented 9 years ago
I'm actually thinking about removing the top widget and let the Gui already 
contain a
top widget that is a Container. That way your problem shouldn't occur. Instead 
of
Removing the top container you would instead remove a container from the top.

This solution also makes it possible for widgets to add widgets to the top at
runtime, such as the drop down adding it's dropped down part to the top or a 
menu
adding it's display part to the top.

Original comment by olof.nae...@gmail.com on 15 Sep 2008 at 9:51

GoogleCodeExporter commented 9 years ago
Hm. Sounds good at first glance. How do you make sure that there's only one top 
widget at a time? Now, when I setTop(p) the existing top widget is removed and 
p is 
set. There shouldn't be more than one top widget, even in case that something 
adds a 
(temporary) additional widget 'on top' of all others. 

Also I'm not completely sure if that really solves the problem here. When I 
remove a 
widget from the container, what happens to the focus handler of that widget? If 
it 
remains, then why is the focus handler reset to 0 in setTop(0)? If it doesn't 
remain, the problem would persist... 

Why is to necessary to have an extra deque of widgets mWidgetWithMouseQueue? 

Original comment by tobias.s...@gmx.net on 16 Sep 2008 at 6:10

GoogleCodeExporter commented 9 years ago
The real issue here is that making Guichan work with dynamic behaviour, like 
removing
things and deleting things runtime, is very difficult. At first Guichan was 
designed
for more or less static GUIs, but over time we have enhanced it to be more 
flexible.
The mWidgetWithMouseQueue is a typical example of something at least I have 
overlooked.

mWidgetWithMouseQueue is necessary when dealing with focus. When you hover a 
widget
there might be several widgets under the mouse that should receive a focus 
gained
event, or more importantly several widgets should receive a focus lost event as 
soon
as the mouse exits the widget, thus they need to be remembered.

Consider a container with a button at coordinate (0, 0). When the mouse enters 
the
button area from left to right at the top of the button area both the container 
under
the button and the button has the mouse. This is all tracked by Guichan using 
the
mWidgetWithMouseQueue. 

By design Guichan does most of the advanced stuff in the Gui class so end users 
don't
have to worry about it when making widgets. Deleting a widget is all fine as 
the Gui
class will be notified whenever a widget is deleted. Removing a widget from a
container on the other hand is another matter. Somehow the Gui class needs to be
notified upon these events to update it's internal state.

A solution might be to let every widget hold a reference to the Gui they belong 
to
and notify the Gui upon changes, just like every widget holds a reference to the
Gui's focus handler.

Original comment by olof.nae...@gmail.com on 16 Sep 2008 at 10:56

GoogleCodeExporter commented 9 years ago
I'm also thinking about merging Widget and BasicContainer. If every widget is 
treated
like container making container widgets of your own will be much easier as all
notifications to the Gui class could be handled by Widget.

Original comment by olof.nae...@gmail.com on 16 Sep 2008 at 11:03

GoogleCodeExporter commented 9 years ago
ad 10) another reference from the widget to gui? Why not keep 
mWidgetWithMouseQueue 
in sync with the current widget hierarchy in setTop()? Or traverse the widget 
hierarchy instead of using mWidgetWithMouseQueue? 

ad 11) it might make creating custom containers easier (i haven't had any big 
problems with my custom containers), but it feels wrong nevertheless. Because 
in 
general a widget IS NOT a container, and people are also making custom widgets 
that 
are not containers (at least I am). 

I appreciate that gui does all the hard work, which is one of the great 
advantages 
of using guichan. I also appreciate the flexibility guichan gives me, so I 
really 
would like to see a good solution here that supports all the dynamic uses 
people 
have. Currently I can live with the additional check for the widget having a 
focus 
listener, even if that's not a final solution. For that, I would try to get rid 
of 
double bookkeeping, and probably try to get rid of mWidgetWithMouseQueue 
altogether. 

Original comment by tobias.s...@gmx.net on 16 Sep 2008 at 11:33

GoogleCodeExporter commented 9 years ago
For comparison with Qt, the QWidget can contain child widgets and as such is a
container. Of course many widgets don't actually have child widgets, but that 
really
doesn't matter.

However, note that QWidget does not have a container interface or anything. 
There is
no QWidget::addWidget/removeWidget. Widget A is the child of widget B if B is 
set as
the parent of widget A (and this also defines ownership). You can do this 
either in
the contructor or using QWidget::setParent(). This is part of what makes Qt 
really
easy to use.

Original comment by b.lindeijer on 16 Sep 2008 at 12:38

GoogleCodeExporter commented 9 years ago
"Why not keep mWidgetWithMouseQueue 
in sync with the current widget hierarchy in setTop()?"

Of course, that's what we want to do, but the question is how? The Gui class 
needs to
be informed whenever a widget is disconnected from the Gui, and it can be if 
Widget
informs the Gui via a Gui reference in Widget.

"a widget IS NOT a container"

Actually, Guichan uses the composite design pattern
(http://en.wikipedia.org/wiki/Composite_pattern). Therefore a widget should have
container methods. Why that is is quite simple, it makes everything so easy to 
always
be able to treat a Widget as a container. Now, the ability to contain other 
widgets
doesn't necessary have to mean a widget contains other widgets. 

Björn, the QT way seems interesting, but I have a question. How is the 
container
informed that it is not any longer an owner of a widget? To me it seems 
important
that a container is informed. Also, how is the widget tree traversed? In 
Guichan a
container draws its children by iterating over its children list, but how is 
this
done in QT where it doesn't seem to be a two way relation between a container 
and a
widget, but rather a one way relation between widget and a container.

Original comment by olof.nae...@gmail.com on 16 Sep 2008 at 1:20

GoogleCodeExporter commented 9 years ago
"The Gui class needs to
be informed whenever a widget is disconnected from the Gui, and it can be if 
Widget
informs the Gui via a Gui reference in Widget."

I see, you're already thinking in more general terms. For my use case, I'm 
thinking 
about setTop(), and that replaces the complete widget hierarchy by another one. 
So 
in a more general situation, things get even more complicated... 

I still don't really udnerstand what mWidgetWithMouseQueue is doing. Could it 
be 
possible, instead of iterating that deque when needed, to traverse the current 
widget hierarchy instead? That way, the widget hierarchy would be seen as it is 
in 
that moment, so only widgets that are active below the current top level widget 
are 
traversed (and only they can react on events and stuff). 

Original comment by tobias.s...@gmx.net on 16 Sep 2008 at 1:47

GoogleCodeExporter commented 9 years ago
"Could it be possible, instead of iterating that deque when needed"

Perhaps, if the last mouse position was remembered it might be possible. The 
whole
thing is quite complicated and there are a lot of cases to consider, like when a
widget is removed from the Gui when having the mouse and after a while added to 
the
Gui again, it might still think it has the mouse.

Another good thing with having a Gui reference is that we can force a widget 
only to
reside in one GUI and in one container in the GUI by checking the Gui reference 
and
the parent reference. 

Original comment by olof.nae...@gmail.com on 16 Sep 2008 at 4:21

GoogleCodeExporter commented 9 years ago
About the children in Qt: The parent is notified using events 
(QEvent::ChildAdded,
QEvent::ChildRemoved) in QObject::childEvent. The actual list of children is
maintained internally and is available via QObject::children(), and you can 
search it
using QObject::findChild/findChildren to find children of a specific type or 
with a
specific name. All this stuff is in QObject and not in QWidget, since the 
ownership
isn't only about widgets.

Original comment by b.lindeijer on 19 Sep 2008 at 11:59

GoogleCodeExporter commented 9 years ago
I've now removed mWidgetWithMouseQueue and changed Gui so the widgets with the 
mouse 
and the last widgets with the mouse is computed at runtime with the help of the 
mouse 
position and the last known mouse position.

The new implementation is a lot cleaner than the old one and it will hopefully 
solve 
some issues with dynamic behaviour, although I am aware of other places that 
needs 
work (such as adding and removing widgets at runtime from a container).

Original comment by olof.nae...@gmail.com on 19 Sep 2008 at 3:40

GoogleCodeExporter commented 9 years ago

Original comment by olof.nae...@gmail.com on 19 Sep 2008 at 3:40

GoogleCodeExporter commented 9 years ago
Hi, i am a guy of unknown-horizons.org and made a complete backtrace of this 
bug,
maybe it's helpfull:

...
terminate called after throwing an instance of 'gcn::Exception'

Program received signal SIGABRT, Aborted.
[Switching to Thread 0x7f9be79196e0 (LWP 20356)]
0x00007f9be6b48095 in raise () from /lib/libc.so.6
(gdb) backtrace
#0  0x00007f9be6b48095 in raise () from /lib/libc.so.6
#1  0x00007f9be6b49af0 in abort () from /lib/libc.so.6
#2  0x00007f9be38640e4 in __gnu_cxx::__verbose_terminate_handler ()
   from /usr/lib/libstdc++.so.6
#3  0x00007f9be3862076 in ?? () from /usr/lib/libstdc++.so.6
#4  0x00007f9be38620a3 in std::terminate () from /usr/lib/libstdc++.so.6
#5  0x00007f9be386218a in __cxa_throw () from /usr/lib/libstdc++.so.6
#6  0x00007f9be43ce4f4 in gcn::Widget::isModalMouseInputFocused (
    this=<value optimized out>) at widget.cpp:617
#7  0x00007f9be43c6bae in gcn::Gui::distributeMouseEvent (this=0x1052fc0, 
    source=0x8171170, type=7, button=1, x=593, y=280, force=true, 
    toSourceOnly=true) at gui.cpp:687
#8  0x00007f9be43c5448 in gcn::Gui::handleModalFocusGained (this=0x1052fc0)
    at gui.cpp:939
#9  0x00007f9be43c49d5 in gcn::Gui::handleModalMouseInputFocus (this=0x1052fc0)
    at gui.cpp:891
#10 0x00007f9be43c6157 in gcn::Gui::logic (this=0x1052fc0) at gui.cpp:139
#11 0x00007f9be5e13c40 in FIFE::GUIManager::turn (this=0x1052c20)
    at engine/core/gui/guimanager.cpp:223
#12 0x00007f9be5dda3f3 in FIFE::Engine::pump (this=0xe84ca0)
    at engine/core/controller/engine.cpp:298
#13 0x00007f9be5fa718e in _wrap_Engine_pump (args=0x4572c10)
    at engine/swigwrappers/python/fife_wrap.cxx:24383
---Type <return> to continue, or q <return> to quit---
#14 0x0000000000417e33 in PyObject_Call ()
#15 0x0000000000487073 in PyEval_EvalFrameEx ()
#16 0x000000000048a406 in PyEval_EvalCodeEx ()
#17 0x0000000000488075 in PyEval_EvalFrameEx ()
#18 0x0000000000488c07 in PyEval_EvalFrameEx ()
#19 0x000000000048a406 in PyEval_EvalCodeEx ()
#20 0x0000000000488075 in PyEval_EvalFrameEx ()
#21 0x000000000048a406 in PyEval_EvalCodeEx ()
#22 0x0000000000488075 in PyEval_EvalFrameEx ()
#23 0x000000000048a406 in PyEval_EvalCodeEx ()
#24 0x00000000004d5223 in ?? ()
#25 0x0000000000417e33 in PyObject_Call ()
#26 0x0000000000487073 in PyEval_EvalFrameEx ()
#27 0x000000000048a406 in PyEval_EvalCodeEx ()
#28 0x0000000000488075 in PyEval_EvalFrameEx ()
#29 0x000000000048a406 in PyEval_EvalCodeEx ()
#30 0x0000000000488075 in PyEval_EvalFrameEx ()
#31 0x0000000000488c07 in PyEval_EvalFrameEx ()
#32 0x000000000048a406 in PyEval_EvalCodeEx ()
#33 0x00000000004d528a in ?? ()
#34 0x0000000000417e33 in PyObject_Call ()
#35 0x000000000041e66f in ?? ()
#36 0x00000000004191aa in ?? ()
---Type <return> to continue, or q <return> to quit---
#37 0x000000000041b090 in PyObject_CallMethod ()
#38 0x00007f9be5ebe6ca in SwigDirector_ActionListener::action (this=0x11eebd0, 
    actionEvent=@0x7fffef936c40)
    at engine/swigwrappers/python/fife_wrap.cxx:7239
#39 0x00007f9be43ccf4e in gcn::Widget::distributeActionEvent (this=0x11ee150)
    at widget.cpp:713
#40 0x00007f9be43cf901 in gcn::Button::mouseReleased (this=0x11ee150, 
    mouseEvent=@0x7fffef936d10) at button.cpp:238
#41 0x00007f9be43c6f29 in gcn::Gui::distributeMouseEvent (this=0x1052fc0, 
    source=0x597d710, type=<value optimized out>, 
    button=<value optimized out>, x=672, y=339, force=false, 
    toSourceOnly=false) at gui.cpp:746
#42 0x00007f9be43c4c74 in gcn::Gui::handleMouseReleased (this=0x1052fc0, 
    mouseInput=@0x7fffef936e30) at gui.cpp:600
#43 0x00007f9be43c7314 in gcn::Gui::handleMouseInput (this=0x1052fc0)
    at gui.cpp:234
#44 0x00007f9be43c617b in gcn::Gui::logic (this=0x1052fc0) at gui.cpp:146
#45 0x00007f9be5e13c40 in FIFE::GUIManager::turn (this=0x1052c20)
    at engine/core/gui/guimanager.cpp:223
#46 0x00007f9be5dda3f3 in FIFE::Engine::pump (this=0xe84ca0)
    at engine/core/controller/engine.cpp:298
#47 0x00007f9be5fa718e in _wrap_Engine_pump (args=0x14a48d0)
    at engine/swigwrappers/python/fife_wrap.cxx:24383
---Type <return> to continue, or q <return> to quit---
#48 0x0000000000417e33 in PyObject_Call ()
#49 0x0000000000487073 in PyEval_EvalFrameEx ()
#50 0x000000000048a406 in PyEval_EvalCodeEx ()
#51 0x0000000000488075 in PyEval_EvalFrameEx ()
#52 0x0000000000488c07 in PyEval_EvalFrameEx ()
#53 0x000000000048a406 in PyEval_EvalCodeEx ()
#54 0x0000000000488075 in PyEval_EvalFrameEx ()
#55 0x000000000048a406 in PyEval_EvalCodeEx ()
#56 0x0000000000488075 in PyEval_EvalFrameEx ()
#57 0x000000000048a406 in PyEval_EvalCodeEx ()
#58 0x00000000004d5223 in ?? ()
#59 0x0000000000417e33 in PyObject_Call ()
#60 0x0000000000487073 in PyEval_EvalFrameEx ()
#61 0x000000000048a406 in PyEval_EvalCodeEx ()
#62 0x0000000000488075 in PyEval_EvalFrameEx ()
#63 0x000000000048a406 in PyEval_EvalCodeEx ()
#64 0x0000000000488075 in PyEval_EvalFrameEx ()
#65 0x0000000000488c07 in PyEval_EvalFrameEx ()
#66 0x000000000048a406 in PyEval_EvalCodeEx ()
#67 0x00000000004d528a in ?? ()
#68 0x0000000000417e33 in PyObject_Call ()
#69 0x000000000041e66f in ?? ()
#70 0x00000000004191aa in ?? ()
---Type <return> to continue, or q <return> to quit---
#71 0x000000000041b090 in PyObject_CallMethod ()
#72 0x00007f9be5ebe6ca in SwigDirector_ActionListener::action (this=0x1205230, 
    actionEvent=@0x7fffef938d80)
    at engine/swigwrappers/python/fife_wrap.cxx:7239
#73 0x00007f9be43ccf4e in gcn::Widget::distributeActionEvent (this=0x12047b0)
    at widget.cpp:713
#74 0x00007f9be43cf901 in gcn::Button::mouseReleased (this=0x12047b0, 
    mouseEvent=@0x7fffef938e50) at button.cpp:238
#75 0x00007f9be43c6f29 in gcn::Gui::distributeMouseEvent (this=0x1052fc0, 
    source=0x1a91260, type=<value optimized out>, 
    button=<value optimized out>, x=399, y=232, force=false, 
    toSourceOnly=false) at gui.cpp:746
#76 0x00007f9be43c4c74 in gcn::Gui::handleMouseReleased (this=0x1052fc0, 
    mouseInput=@0x7fffef938f70) at gui.cpp:600
#77 0x00007f9be43c7314 in gcn::Gui::handleMouseInput (this=0x1052fc0)
    at gui.cpp:234
#78 0x00007f9be43c617b in gcn::Gui::logic (this=0x1052fc0) at gui.cpp:146
#79 0x00007f9be5e13c40 in FIFE::GUIManager::turn (this=0x1052c20)
    at engine/core/gui/guimanager.cpp:223
#80 0x00007f9be5dda3f3 in FIFE::Engine::pump (this=0xe84ca0)
    at engine/core/controller/engine.cpp:298
#81 0x00007f9be5fa718e in _wrap_Engine_pump (args=0xe3f190)
    at engine/swigwrappers/python/fife_wrap.cxx:24383
---Type <return> to continue, or q <return> to quit---
#82 0x0000000000417e33 in PyObject_Call ()
#83 0x0000000000487073 in PyEval_EvalFrameEx ()
#84 0x000000000048a406 in PyEval_EvalCodeEx ()
#85 0x0000000000488075 in PyEval_EvalFrameEx ()
#86 0x0000000000488c07 in PyEval_EvalFrameEx ()
#87 0x0000000000488c07 in PyEval_EvalFrameEx ()
#88 0x0000000000488c07 in PyEval_EvalFrameEx ()
#89 0x000000000048a406 in PyEval_EvalCodeEx ()
#90 0x000000000048a522 in PyEval_EvalCode ()
#91 0x00000000004abe2e in PyRun_FileExFlags ()
#92 0x00000000004ac0c9 in PyRun_SimpleFileExFlags ()
#93 0x00000000004145ad in Py_Main ()
#94 0x00007f9be6b341c4 in __libc_start_main () from /lib/libc.so.6
#95 0x0000000000413b29 in _start ()
(gdb) 

Original comment by geto...@googlemail.com on 27 Mar 2009 at 7:47

GoogleCodeExporter commented 9 years ago
Let me clarify: The issue is that in FIFE synchronous execution of dialogs is 
handled
via recursion of the main loop. The Gui logic function isn't robust enough for 
that.
A fix is pending where events won't get called directly from inside event 
handlers
but deferred by one frame.

That should close this issue.

Original comment by klaus.bl...@web.de on 27 Mar 2009 at 10:43