I want an app's main window to ignore mouse and keyboard events, passing them to applications underneath it in the window manager Z-order.
I see how to make child widgets ignore keyboard or mouse events, but how about the main window?
I'm trying to make a desktop widget that always sits just over the background and is totally invisible to keyboard and mouse events. (Pass through)
Qt::X11BypassWindowManagerHint gets me keyboard pass through (although sadly X11 specific, but fine for now), so how about mouse events?
Is there a OS-agnostic way to be transparent to keyboard events?
EDIT:
The key word here is transparency.
I don't want to EAT mouse and keyboard events, I want the window manager to know I don't want them at all. Those events should be directed to whatever application is under me in the zorder.
For example, I want to be able to click on desktop icons that are covered by my widget and interact with them as if the widget was not there.
On Windows you can set WS_EX_TRANSPARENT
To do this in Qt use the following code:
Include the header,
#if _WIN32
#include <windows.h>
#endif
and put the following code into the constructor.
#if _WIN32
HWND hwnd = (HWND) winId();
LONG styles = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, styles | WS_EX_TRANSPARENT);
#endif
Maybe what you want is
widget->setAttribute(Qt::WA_TransparentForMouseEvents)
? That's what QRubberBand uses to let it's parent handle the mouse events. As for keyboard events, a QWidget doesn't get any keyboard events unless it has set itself a focusPolicy().
setFocusPolicy( Qt::NoFocus );
should therefore take care of the keyboard events.
I found the following solution (tested on Linux, also works on Windows according to @TheSHEEEP):
setWindowFlags(windowFlags() | Qt::WindowTransparentForInput);
It has been added in more recent qt release (i did not find when)
see http://doc.qt.io/qt-5/qt.html
Maybe I'm missing something here, but have you tried subclassing the QMainWindow class and overriding the QWidget::event() method to always return false? If you need to handle some events, you could add that intelligence here as well.
This technique should allow you to inspect the events coming in to the application and ignore them if desired without having to eat them using an event filter.
If this doesn't work you could attempt to redirect the events to the desktop by calling QCoreApplication::notify() and passing the event to the desktop widget obtained by calling QApplication::desktop(). I have no idea if this would work, but it seemed like it might be worth giving a try.
I think that overriding is supposed to work:
bool YourMainWindow::event( QEvent *event )
{
event ->accept();
return true;
}
that's some of what the QWidget class documentation says about event() member function:
This function returns true if the
event was recognized, otherwise it
returns false. If the recognized event
was accepted (see QEvent::accepted),
any further processing such as event
propagation to the parent widget
stops.
Use Qt's event filters: they will allow your application to eat whichever events you specify (i.e. keyboard and mouse events) but still process other events such as paint events.
bool FilterObject::eventFilter(QObject* object, QEvent* event)
{
QKeyEvent* pKeyEvent = qobject_cast<QKeyEvent*>(event);
QMouseEvent* pMouseEvent = qobject_cast<QMouseEvent*>(event);
if (pKeyEvent || pMouseEvent)
{
// eat all keyboard and mouse events
return true;
}
return FilterObjectParent::eventFilter(object, event);
}