[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Konqueror crash when closing tabs caused by KAccel
From:       Vladimir Prus <ghost () cs ! msu ! su>
Date:       2004-12-28 16:27:00
Message-ID: 200412281927.01336.ghost () cs ! msu ! su
[Download RAW message or body]


Hello,
we've run into konqueror crash, and after some investigation the problem
boils down to a question about accelerator handling in KDE and QT.

When typing Ctrl-W in konqueror, it should close the current tab. However, in 
some cases, when I type that when keyboard is in russian layout, konqueror 
crashes.

Tracing the event handling in debugger shows some differences between handling 
of event in english and russian layouts.

When I type Ctrl-W in english layout, the QApplication::x11ProcessEvent
arrives at this code block:

 if ( qt_x11EventFilter(event) )  // send through app filter
 return 1;

The qt_x11EventFilter indirectly calls KAccelEventHandler::x11Event, KAccel 
for Ctrl-W is invoked and tab is closed. The call to qt_x11EventFilter 
returns 1 and x11ProcessEvent immediately exits.

When I type Ctrl-W in russian layout, the call to KAccelEventHandle::x11Event 
does not find the accelerator, and the above "return" is not executed.

Later, QApplication::x11ProcessEvent calls QETWidget::translateKeyEvent, which 
has this code:

  if ( qt_tryAccelEvent( this, &a ) )
      return TRUE;
  }

This code finds the KAccel for Ctrl-W, and closes the tab. But, 
qt_tryAcelEvent returns false. The reason is unclear -- here's the relevant 
code:

  bool QAccelManager::tryAccelEvent( QWidget* w, QKeyEvent* e )
  {
    if ( Qt::NoMatch == currentState ) {
           ........
       QApplication::sendSpontaneousEvent( w, e );
       if ( e->isAccepted() )
          return FALSE;
    }

This "return FALSE" is actually executed. I'd expect that if event is 
accepted, it means accelerator is found, so TRUE should be returned. But if I 
change this to "return TRUE" this code is activated for every keypress, not 
only accelerators, and keyboard does not work at all.


So, tryAccelEvent and qt_tryAcelEvent return false, and 
QETWidget::translateKeyEvent goes on, 
and eventually ends with segfault in KApplication::notify:

    if ((t == QEvent::AccelOverride) || (t == QEvent::KeyPress))
    {
       static const KShortcut& _selectAll = KStdAccel::selectAll();
       QLineEdit *edit = ::qt_cast<QLineEdit *>(receiver);

The crash happens on the last line, supposedly because 'receiever' was part of 
just destroyed tab.

The reason why Qt finds the accelerator while KDE does not is that Qt, when 
searching the accelerator for KeyPress event with keycode==25, explicitly 
tries both Ctrl-W and Ctrl-CyrillicTse keys. As far as I can tell, KDE tries 
only Ctrl-CyrillicTse. Here's the relevant code:

  bool KAccelEventHandler::x11Event( XEvent* pEvent )
  {
     ....
     if( pEvent->type == XKeyPress ) {
       KKeyNative keyNative( pEvent );

Constructor of KKeyNative does XLookupString, which gives different result in 
english and cyrillic keyboard mode (XK_W for english keyboard, 
XK_Cyrillic_Tse for russian keyboard). If the code is modified to be:

  bool KAccelEventHandler::x11Event( XEvent* pEvent )
  {
     ....
     if( pEvent->type == XKeyPress ) {
        unsigned int tmp = pEvent->xkey.state;
        pEvent->xkey.state &= ~0x2000;
        KKeyNative keyNative( pEvent );
        pEvent->xkey.state = tmp;

Konqueror no longer crashes. However, this does not look like an acceptable 
solution. So the question is: what is the real solution?

TIA,
Volodya



 
>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic