Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qshortcut_widgets.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qshortcut.h"
5#include "private/qshortcut_p.h"
6
7#include "private/qwidget_p.h"
8
9#include <qevent.h>
10#if QT_CONFIG(whatsthis)
11#include <qwhatsthis.h>
12#endif
13#if QT_CONFIG(menu)
14#include <qmenu.h>
15#endif
16#if QT_CONFIG(menubar)
17#include <qmenubar.h>
18#endif
19#include <qapplication.h>
20#include <private/qapplication_p.h>
21#include <private/qshortcutmap_p.h>
22#if QT_CONFIG(action)
23# include <private/qaction_p.h>
24#endif
25#include <private/qwidgetwindow_p.h>
26#include <qpa/qplatformmenu.h>
27
29
31#if QT_CONFIG(graphicsview)
32static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window);
33#endif
34#if QT_CONFIG(action)
35static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window);
36#endif
37
38
44{
45 Q_ASSERT_X(object, "QShortcutMap", "Shortcut has no owner. Illegal map state!");
46
47 QWidget *active_window = QApplication::activeWindow();
48
49 // popups do not become the active window,
50 // so we fake it here to get the correct context
51 // for the shortcut system.
53 active_window = QApplication::activePopupWidget();
54
55 if (!active_window) {
57 if (qwindow && qwindow->isActive()) {
58 while (qwindow) {
59 if (auto widgetWindow = qobject_cast<QWidgetWindow *>(qwindow)) {
60 active_window = widgetWindow->widget();
61 break;
62 }
63 qwindow = qwindow->parent();
64 }
65 }
66 }
67
68#if QT_CONFIG(action)
69 if (auto a = qobject_cast<QAction *>(object))
70 return correctActionContext(context, a, active_window);
71#endif
72
73#if QT_CONFIG(graphicsview)
74 if (auto gw = qobject_cast<QGraphicsWidget *>(object))
75 return correctGraphicsWidgetContext(context, gw, active_window);
76#endif
77
78 auto w = qobject_cast<QWidget *>(object);
79 if (!w) {
80 if (auto s = qobject_cast<QShortcut *>(object))
81 w = qobject_cast<QWidget *>(s->parent());
82 }
83
84 if (!w) {
85 auto qwindow = qobject_cast<QWindow *>(object);
86 while (qwindow) {
87 if (auto widget_window = qobject_cast<QWidgetWindow *>(qwindow)) {
88 w = widget_window->widget();
89 break;
90 }
91 qwindow = qwindow->parent();
92 }
93 }
94
95 if (w)
96 return correctWidgetContext(context, w, active_window);
97
99}
100
102{
103 if (!active_window)
104 return false;
105
106 bool visible = w->isVisible();
107#if QT_CONFIG(menubar)
108 if (auto menuBar = qobject_cast<QMenuBar *>(w)) {
109 if (auto *pmb = menuBar->platformMenuBar()) {
110 if (menuBar->parentWidget()) {
111 visible = true;
112 } else {
113 if (auto *ww = qobject_cast<QWidgetWindow *>(pmb->parentWindow()))
114 w = ww->widget(); // Good enough since we only care about the window
115 else
116 return false; // This is not a QWidget window. We won't deliver
117 }
118 }
119 }
120#endif
121
122 if (!visible || !w->isEnabled())
123 return false;
124
126 return QApplicationPrivate::tryModalHelper(w, nullptr); // true, unless w is shadowed by a modal dialog
127
129 return w == QApplication::focusWidget();
130
133 while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup || tw->windowType() == Qt::SubWindow))
134 tw = tw->parentWidget();
135 return tw == w;
136 }
137
138 // Below is Qt::WindowShortcut context
139 QWidget *tlw = w->window();
140#if QT_CONFIG(graphicsview)
141 if (auto topData = static_cast<QWidgetPrivate *>(QObjectPrivate::get(tlw))->extra.get()) {
142 if (topData->proxyWidget) {
143 bool res = correctGraphicsWidgetContext(context, topData->proxyWidget, active_window);
144 return res;
145 }
146 }
147#endif
148
149 if (active_window && active_window != tlw) {
150 /* if a floating tool window is active, keep shortcuts on the parent working.
151 * and if a popup window is active (f.ex a completer), keep shortcuts on the
152 * focus proxy working */
153 if (active_window->windowType() == Qt::Tool && active_window->parentWidget()) {
154 active_window = active_window->parentWidget()->window();
155 } else if (active_window->windowType() == Qt::Popup && active_window->focusProxy()) {
156 active_window = active_window->focusProxy()->window();
157 }
158 }
159
160 if (active_window != tlw) {
161#if QT_CONFIG(menubar)
162 // If the tlw is a QMenuBar then we allow it to proceed as this indicates that
163 // the QMenuBar is a parentless one and is therefore used for multiple top level
164 // windows in the application. This is common on macOS platforms for example.
165 if (!qobject_cast<QMenuBar *>(tlw))
166#endif
167 return false;
168 }
169
170 /* if we live in a MDI subwindow, ignore the event if we are
171 not the active document window */
172 const QWidget* sw = w;
173 while (sw && !(sw->windowType() == Qt::SubWindow) && !sw->isWindow())
174 sw = sw->parentWidget();
175 if (sw && (sw->windowType() == Qt::SubWindow)) {
176 QWidget *focus_widget = QApplication::focusWidget();
177 while (focus_widget && focus_widget != sw)
178 focus_widget = focus_widget->parentWidget();
179 return sw == focus_widget;
180 }
181
182#if defined(DEBUG_QSHORTCUTMAP)
183 qDebug().nospace() << "..true [Pass-through]";
184#endif
185 return QApplicationPrivate::tryModalHelper(w, nullptr);
186}
187
188#if QT_CONFIG(graphicsview)
189static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window)
190{
191 if (!active_window)
192 return false;
193
194 bool visible = w->isVisible();
195#if defined(Q_OS_DARWIN) && QT_CONFIG(menubar)
196 if (!QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast<QMenuBar *>(w))
197 visible = true;
198#endif
199
200 if (!visible || !w->isEnabled() || !w->scene())
201 return false;
202
204 // Applicationwide shortcuts are always reachable unless their owner
205 // is shadowed by modality. In QGV there's no modality concept, but we
206 // must still check if all views are shadowed.
207 const auto &views = w->scene()->views();
208 for (auto view : views) {
210 return true;
211 }
212 return false;
213 }
214
216 return static_cast<QGraphicsItem *>(w) == w->scene()->focusItem();
217
219 const QGraphicsItem *ti = w->scene()->focusItem();
220 if (ti && ti->isWidget()) {
221 const auto *tw = static_cast<const QGraphicsWidget *>(ti);
222 while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup))
223 tw = tw->parentWidget();
224 return tw == w;
225 }
226 return false;
227 }
228
229 // Below is Qt::WindowShortcut context
230
231 // Find the active view (if any).
232 const auto &views = w->scene()->views();
233 QGraphicsView *activeView = nullptr;
234 for (auto view : views) {
235 if (view->window() == active_window) {
236 activeView = view;
237 break;
238 }
239 }
240 if (!activeView)
241 return false;
242
243 // The shortcut is reachable if owned by a windowless widget, or if the
244 // widget's window is the same as the focus item's window.
246 return !w->window() || a == w->window();
247}
248#endif
249
250#if QT_CONFIG(action)
251static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window)
252{
253 if (!active_window)
254 return false;
255
256 const QObjectList associatedObjects = a->associatedObjects();
257#if defined(DEBUG_QSHORTCUTMAP)
258 if (associatedObjects.isEmpty())
259 qDebug() << a << "not connected to any widgets; won't trigger";
260#endif
261 for (auto object : associatedObjects) {
262#if QT_CONFIG(menu)
263 if (auto menu = qobject_cast<QMenu *>(object)) {
264#ifdef Q_OS_DARWIN
265 // On Mac, menu item shortcuts are processed before reaching any window.
266 // That means that if a menu action shortcut has not been already processed
267 // (and reaches this point), then the menu item itself has been disabled.
268 // This occurs at the QPA level on Mac, where we disable all the Cocoa menus
269 // when showing a modal window. (Notice that only the QPA menu is disabled,
270 // not the QMenu.) Since we can also reach this code by climbing the menu
271 // hierarchy (see below), or when the shortcut is not a key-equivalent, we
272 // need to check whether the QPA menu is actually disabled.
273 // When there is no QPA menu, there will be no QCocoaMenuDelegate checking
274 // for the actual shortcuts. We can then fallback to our own logic.
276 if (pm && !pm->isEnabled())
277 continue;
278#endif
279 QAction *a = menu->menuAction();
280 if (a->isVisible() && a->isEnabled() && correctActionContext(context, a, active_window))
281 return true;
282 } else
283#endif
284 if (auto widget = qobject_cast<QWidget*>(object)) {
285 if (correctWidgetContext(context, widget, active_window))
286 return true;
287 }
288#if QT_CONFIG(graphicsview)
289 else if (auto graphicsWidget = qobject_cast<QGraphicsWidget*>(object)) {
290 if (correctGraphicsWidgetContext(context, graphicsWidget, active_window))
291 return true;
292 }
293#endif
294 }
295
296 return false;
297}
298#endif // QT_CONFIG(action)
299
301{
302 Q_DECLARE_PUBLIC(QShortcut)
303public:
305
308
309 bool handleWhatsThis() override;
310};
311
313{
314#if QT_CONFIG(whatsthis)
317 return true;
318 }
319#endif
320 return false;
321}
322
327
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition qaction.h:30
QShortcutPrivate * createShortcutPrivate() const override
static bool tryModalHelper(QWidget *widget, QWidget **rettop=nullptr)
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or \nullptr if no widget in this ap...
static QWidget * activePopupWidget()
Returns the active popup widget.
static QWidget * activeWindow()
Returns the application top-level window that has the keyboard input focus, or \nullptr if no applica...
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
The QGraphicsItem class is the base class for all graphical items in a QGraphicsScene.
QGraphicsWidget * parentWidget() const
QGraphicsScene * scene() const
Returns the current scene for the item, or \nullptr if the item is not stored in a scene.
QGraphicsWidget * window() const
QList< QGraphicsView * > views() const
Returns a list of all the views that display this scene.
QGraphicsWidget * activeWindow() const
QGraphicsItem * focusItem() const
When the scene is active, this functions returns the scene's current focus item, or \nullptr if no it...
The QGraphicsView class provides a widget for displaying the contents of a QGraphicsScene.
The QGraphicsWidget class is the base class for all widget items in a QGraphicsScene.
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
bool isEmpty() const noexcept
Definition qlist.h:401
QPlatformMenuBar * platformMenuBar()
QPlatformMenu * platformMenu()
Definition qmenu.cpp:3710
QAction * menuAction() const
Returns the action associated with this menu.
Definition qmenu.cpp:1069
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
virtual bool isEnabled() const
bool(* ContextMatcher)(QObject *object, Qt::ShortcutContext context)
QString sc_whatsthis
Definition qshortcut_p.h:49
static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context)
Definition qshortcut.cpp:99
The QShortcut class is used to create keyboard shortcuts.
Definition qshortcut.h:19
static void showText(const QPoint &pos, const QString &text, QWidget *w=nullptr)
Shows text as a "What's This?" window, at global position pos.
static bool inWhatsThisMode()
Returns true if the user interface is in "What's This?" mode; otherwise returns false.
static QWidgetPrivate * get(QWidget *w)
Definition qwidget_p.h:212
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4313
QWidget * focusProxy() const
Returns the focus proxy, or \nullptr if there is no focus proxy.
Definition qwidget.cpp:6427
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
Qt::WindowType windowType() const
Returns the window type of this widget.
Definition qwidget.h:801
\inmodule QtGui
Definition qwindow.h:63
QtWidgetsShortcutPrivate()=default
QShortcutMap::ContextMatcher contextMatcher() const override
QOpenGLWidget * widget
[1]
Combined button and popup list for selecting options.
@ AA_DontUseNativeMenuBar
Definition qnamespace.h:431
@ Widget
Definition qnamespace.h:206
@ Popup
Definition qnamespace.h:211
@ SubWindow
Definition qnamespace.h:216
@ Tool
Definition qnamespace.h:212
ShortcutContext
@ WidgetWithChildrenShortcut
@ WidgetShortcut
@ ApplicationShortcut
static void * context
#define qDebug
[1]
Definition qlogging.h:164
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context)
static QT_BEGIN_NAMESPACE bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window)
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
QWindow * qobject_cast< QWindow * >(QObject *o)
Definition qwindow.h:367
QMenu menu
[5]
QMenuBar * menuBar
[0]
QQuickView * view
[0]