Bug 310476 - Clicking on appmenu window button causes window to lost focus
Summary: Clicking on appmenu window button causes window to lost focus
Status: RESOLVED FIXED
Alias: None
Product: kwin
Classification: Plasma
Component: appmenu (show other bugs)
Version: 4.9.80
Platform: Arch Linux Linux
: NOR minor
Target Milestone: ---
Assignee: Cédric Bellegarde
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-11-22 04:27 UTC by Jem Orgun
Modified: 2012-12-14 22:17 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In: 4.10
thomas.luebking: ReviewRequest+


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jem Orgun 2012-11-22 04:27:03 UTC
As stated in the summary, clicking on the new title bar appmenu button causes the parent window to lose focus. Exiting the appmenu causes the window to regain focus, as you might expect.

This doesn't really affect interactions in any way, but as a cosmetics issue it's kind of annoying.

Reproducible: Always

Steps to Reproduce:
1.Enable new title bar window button
2. Click on menu button in title bar of focused window.
Actual Results:  
Window loses focus.

Expected Results:  
Window retains focus, like normal KWin options menu.
Comment 1 Cédric Bellegarde 2012-11-22 08:05:23 UTC
This can't be fixed now... Kwin isn't drawing menu and kded module need to give popup menu focus...

Look at klipper popup, it is doing the same thing ;)

In future, switching to wayland will help us fixing this issue.
Comment 2 Martin Flöser 2012-11-22 08:10:14 UTC
normally menus are unmanaged or better said "overwrite redirect" windows. There is a flag you can pass to QWidget to get that behavior (Qt::X11BypassWindowManagerHint)
Comment 3 Cédric Bellegarde 2012-11-22 08:15:51 UTC
Passing Qt::X11BypassWindowManagerHint break keyboard focus.
Comment 4 Martin Flöser 2012-11-22 08:18:00 UTC
(In reply to comment #3)
> Passing Qt::X11BypassWindowManagerHint break keyboard focus.
see the documentation: (i.e., no keyboard input unless you call QWidget::activateWindow() manually).
Comment 5 Cédric Bellegarde 2012-11-22 08:31:08 UTC
This does not work :-(

This issue has been discuted on #kde-devel:

 [09:17:22] <gnumdk>     If i popup a menu from my application (that just popup a menu) while button1 mouse is pressed, QMenu never get keyboard/mouse focus, any idea how to deal with this ? Qt return no mouseGrabber() and sending mouse release event have no effect. Calling all activ*() functions have no effect.
[09:19:51] <thiago>     gnumdk: use Wayland instead of X
[09:19:55] <thiago>     there's no solution in X
[09:20:19] <gnumdk>     It's working with klipper :)
[09:20:23] <gnumdk>     So there is a solution
[09:20:37] <thiago>     usually, don't show menus unless through the existing functionality
[09:20:42] <thiago>     popups are evil
Comment 6 Martin Flöser 2012-11-22 08:33:39 UTC
maybe open the menu on release instead of press? That would be more consistent with the window menu icon anyway
Comment 7 Cédric Bellegarde 2012-11-22 08:59:40 UTC
Make  menu popup() with a dbus call have the issue, this is not related to button click :-(

void VerticalMenu::popup(QPoint p)
{
    // This flags are mandatory to get focus.
    // Qt::Popup will fail to grab input here
    setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowStaysOnTopHint);
    QMenu::popup(p);
    KWindowSystem::forceActiveWindow(winId());
}

But i can change click behaviour anyway :) On my TODO list ;)
Comment 8 Martin Flöser 2012-11-22 09:09:36 UTC
give it a try with the X11BypassWindowManagerHint and call setActive manually. It *should* work, we use such things inside KWin
Comment 9 Thomas Lübking 2012-11-22 09:29:38 UTC
The entire approach is broken.

Popups do not take the input focus, but grab input (this also allows them to close on external clicks) but this does not happen for eg. faked input events (XSendEvent) and apparently neither for dbus triggered synthetic calls?

However, since you're writing popup AND client you should have complete control and grab the input state (have that code reviewed *twice*) either using Qt, or - if it has some preventing sanity checks - X11 directly.

If you don't get get desired results with this, please post  a link to the sources (path, file, line)
Comment 10 Cédric Bellegarde 2012-11-22 10:15:24 UTC
I've tried to use grabMouse() and grabKeyboard() but with no sucess...

Calling QMenu::grabKeyboard() from kded module, then QWidget::keyboardGrabber () return 0  => no widget in this application is currently grabbing the keyboard

This works great in applications with a window but not from a kded module :-(

Will give another try to confirm...
Comment 11 Cédric Bellegarde 2012-11-22 10:34:13 UTC
Ok, i was wrong... (keyboard input is working with grabKeyboard())

The problem is that even with:
    QMenu::grabMouse();
    QMenu::grabKeyboard();
    QMenu::popup(p);

QMenu do not receive event QEvent::MouseButtonPress when clicking outside the menu... Navigation through the submenus fix the issue...

But if user click on menu button with no navigation in submenus, closing menu works only by clicking on button again.

Any idea ?
Comment 12 Thomas Lübking 2012-11-22 10:54:43 UTC
QMenu::popup(p);
QMenu::grabKeyboard();
QMenu::grabMouse();


from QMenu  API
Note: Only visible widgets can grab mouse input. If isVisible() returns false for a widget, that widget cannot call grabMouse().

If that does not work as well, you'll have to http://linux.die.net/man/3/xgrabpointer
Comment 13 Cédric Bellegarde 2012-11-22 12:47:57 UTC
Ok, i have a better idea of what is happening:
http://ubuntuone.com/6wLRntRRurFzZs6Rxuiewd

If you launch Menu executable while mouse button is pressed, QMenu will fail to grab input...

If someone find a solution, it will fix this issue.

@Martin Gräßlin  i tried on release event but do not work.
Comment 14 Cédric Bellegarde 2012-11-22 13:09:25 UTC
Popup() an empty menu before dbus call to kded-appmenu fix the issue.

KCommonDecoration::appMenuButtonPressed() 
{
    QMenu menu;
    menu.popup(wanted_position);
}

Is this acceptable ?
Comment 15 Martin Flöser 2012-11-22 13:19:50 UTC
wtf? Quite hacky but should help find the real solution. I mean showing an 
empty popup doesn't fix the issue, but something that the QMenu is doing 
obviously does the right thing. So if we can do identify the correct command, 
we should use that one.

Sidenote: should be in KDecoration
Comment 16 Thomas Lübking 2012-11-22 14:03:03 UTC
(In reply to comment #13)

> If you launch Menu executable while mouse button is pressed, QMenu will fail
> to grab input...

yes, because the button has it.

Since you cannot share events (forward from button to menu) in this case you'll have to release the mouse from the button in the deco before calling the menu (or make buttons not autospawn menus)
Comment 17 Cédric Bellegarde 2012-11-23 10:54:59 UTC
>yes, because the button has it.

qDebug() << m_button[AppMenuButton]->mouseGrabber();
QObject(0x0)

Strange no?

But, Qt documentation say:
«Pressing the mouse without releasing it is effectively the same as calling grabMouse()»

Can i assume that pressing the mouse button make pointer grabbing implicit ?

>you'll have to release the mouse from the button in the deco before calling the menu

I've tried to send release events to the button with no success...

The workaround is (not QMenu finally):
QWidget fake;
fake.show();

I looked at qwidget source code but can't find what is making input ungrabbed.
Comment 18 Cédric Bellegarde 2012-11-23 11:40:20 UTC
Hmm, in fact, workaround really work with 100% success with a QMenu...
Comment 19 Thomas Lübking 2012-11-23 21:42:03 UTC
1. The button is "grabbed" by the server as long as the mousebutton is, cannot be grabbed and all events go to the window under the mouse when the button was grabbed.
Either fire on button release event or release the mouse on X11 before attempting the grab. I don't frankly see how showing another window would change this. What it does is to make kwin to pass the focus on to that window (what shall explicitly be avoided here)

2. Once you managed to get around the pointer grabbing condition issue (fire - on - release, resp. click!) a QMenu popup (or any popup-type window) should "just work" (ie. it can grab pointer and keyboard and operate like a regular menu despite the focus remains on the decorated client)

Bottom line and in case that didn't get clear: fire on release ;-)
Comment 20 Cédric Bellegarde 2012-11-24 13:56:46 UTC
>Either fire on button release event

I tried to use
 QMouseEvent event(QEvent::MouseButtonRelease, pos, 0, 0, 0);
 QApplication::sendEvent(menuButton, &event);

with no sucess.

> or release the mouse on X11 before attempting the grab.

I tried XungrabPointer() with no sucess

Thanks for help...
Comment 21 Thomas Lübking 2012-11-24 15:52:30 UTC
(In reply to comment #20)
> >Either fire on button release event
> 
> I tried to use
>  QMouseEvent event(QEvent::MouseButtonRelease, pos, 0, 0, 0);
>  QApplication::sendEvent(menuButton, &event);
> 
> with no sucess.

No, as much as X11 is concerned (and only that matters) the button is still pressed. Whether you inject an event into Qt's internal eventloop is irrelevant.

I did not mean "relase the button before firing the event", but "fire on release", ie. connect your trigger to the clicked() signal, not the pressed() one.

> > or release the mouse on X11 before attempting the grab.
> I tried XungrabPointer() with no sucess

No, the pointer is not grabbed explicitly by the client but implicitly by the server.
I frankly do not know at hand how and whether at all it's possible to convince it to release that "grab" (but using possibly the xtest extension, which is not guaranteed to be available and afaik we currently don't link Xtst atm. and are in dep freeze for sure)

-> Fire on release ;-)
Comment 22 Cédric Bellegarde 2012-11-24 16:35:13 UTC
>ie. connect your trigger to the clicked()

I already tried with click() and release() signals but it seems Qt send signal before X11 ungrab pointer :-(
Comment 23 Thomas Lübking 2012-11-24 16:36:38 UTC
Do i still need ubuntu to test the appmenu daemon?
Comment 24 Martin Flöser 2012-11-24 16:41:05 UTC
On Saturday 24 November 2012 16:36:38 you wrote:
> Do i still need ubuntu to test the appmenu daemon?
no, Qt 4.8 should do (works here on Debian and they don't use Ubuntu patches)
Comment 25 Thomas Lübking 2012-11-24 17:33:24 UTC
Is there some hidden config key for this?
The kded module is running but the menu does not show up in the oxygen deco (using oxygen style from 2 weeks ago or so) and [kinda severe bug] calling
qdbus org.kde.kded /modules/appmenu showMenu 0 0 20973313

crashes kded:

#6  value (akey=<synthetic pointer>, this=0x10) at /usr/include/QtCore/qhash.h:609
#7  serviceForWindow (id=20973313, this=0x0) at /home/src/KDE4/kde-workspace/appmenu/menuimporter.h:63
#8  AppMenuModule::getImporter (this=this@entry=0xa3afce0, id=id@entry=20973313, force=force@entry=false) at /home/src/KDE4/kde-workspace/appmenu/appmenu.cpp:356
#9  0xad0965f4 in AppMenuModule::slotShowMenu (this=0xa3afce0, x=0, y=0, id=20973313) at /home/src/KDE4/kde-workspace/appmenu/appmenu.cpp:111
#10 0xb60c6b66 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () from /usr/lib/libQtCore.so.4
#11 0xad0939a5 in AppmenuDBus::appShowMenu (this=0xa38a218, _t1=0, _t2=0, _t3=20973313) at /home/src/KDE4/BUILD_stable/workspace/appmenu/moc_appmenu_dbus.cpp:119
#12 0xad09e683 in AppmenuDBus::showMenu (this=0xa38a218, x=0, y=0, id=20973313) at /home/src/KDE4/kde-workspace/appmenu/appmenu_dbus.cpp:63
#13 0xad0a2169 in AppmenuAdaptor::showMenu (this=this@entry=0xa399d48, x=0, y=0, WId=20973313) at /home/src/KDE4/BUILD_stable/workspace/appmenu/appmenuadaptor.cpp:45
#14 0xad0a251a in qt_static_metacall (_a=0xbfb26b6c, _id=7, _o=0xa399d48, _c=<optimized out>) at /home/src/KDE4/BUILD_stable/workspace/appmenu/appmenuadaptor.moc:91
#15 AppmenuAdaptor::qt_static_metacall (_o=0xa399d48, _c=QMetaObject::InvokeMetaMethod, _id=7, _a=0xbfb26b6c) at /home/src/KDE4/BUILD_stable/workspace/appmenu/appmenuadaptor.moc:78
#16 0xad0a25ac in AppmenuAdaptor::qt_metacall (this=0xa399d48, _c=QMetaObject::InvokeMetaMethod, _id=<optimized out>, _a=0xbfb26b6c) at /home/src/KDE4/BUILD_stable/workspace/appmenu/appmenuadaptor.moc:130

While external calls should pass a sanity check, i guess this means that the menu is not registered?!
Comment 26 Cédric Bellegarde 2012-11-24 18:52:39 UTC
>While external calls should pass a sanity check

Sanity check added ;)

For appmenu working, you need to install appmenu-qt and then configure it in kcm_style

Workaround is in:
void KDecoration::showApplicationMenu(const QPoint &p) {}

Button pressed slot is:
void KCommonDecoration::appMenuButtonPressed() {}

Thanks for looking at this bug
Comment 27 Thomas Lübking 2012-11-24 21:37:14 UTC
Know problem. Gonna fix.
Comment 28 Thomas Lübking 2012-11-24 22:51:00 UTC
https://git.reviewboard.kde.org/r/107455/
Comment 29 Thomas Lübking 2012-11-24 22:59:35 UTC
Would you mind placing another mail address to your reviewboard account or do you seriously want me to place that string into the review description?
Comment 30 Cédric Bellegarde 2012-11-27 10:44:40 UTC
Git commit d96fffd6b4f1e3422c4bc2dda3e0d651192bc06b by Cedric Bellegarde.
Committed on 27/11/2012 at 11:43.
Pushed by cedric into branch 'master'.

Remove workaround, grab keyboard/mouse manually.
REVIEW: 107455

M  +41   -4    appmenu/verticalmenu.cpp
M  +6    -0    appmenu/verticalmenu.h
M  +1    -1    kwin/libkdecorations/kcommondecoration.cpp
M  +0    -7    kwin/libkdecorations/kdecoration.cpp

http://commits.kde.org/kde-workspace/d96fffd6b4f1e3422c4bc2dda3e0d651192bc06b
Comment 31 Thomas Lübking 2012-12-14 21:55:11 UTC
Git commit 7cd45390e8f11ec2be6b1733db2a0edf0b592367 by Thomas Lübking.
Committed on 23/11/2012 at 22:05.
Pushed by luebking into branch 'master'.

special tab/backtab handling to align kglobalaccel
FIXED-IN: 4.10
REVIEW: 107441

M  +46   -1    kwin/tabbox/tabbox.cpp

http://commits.kde.org/kde-workspace/7cd45390e8f11ec2be6b1733db2a0edf0b592367
Comment 32 Thomas Lübking 2012-12-14 22:17:19 UTC
sorry, wrong bug in commit...