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
qquicklabsplatformmenu.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
8
9#include <QtCore/qloggingcategory.h>
10#include <QtGui/qicon.h>
11#include <QtGui/qcursor.h>
12#include <QtGui/qpa/qplatformtheme.h>
13#include <QtGui/private/qguiapplication_p.h>
14#include <QtGui/private/qhighdpiscaling_p.h>
15#include <QtQml/private/qqmlengine_p.h>
16#include <QtQml/private/qv4scopedvalue_p.h>
17#include <QtQml/private/qv4qobjectwrapper_p.h>
18#include <QtQuick/qquickrendercontrol.h>
19#include <QtQuick/qquickwindow.h>
20#include <QtQuick/qquickitem.h>
21
23
24#if QT_CONFIG(systemtrayicon)
26#endif
27
29
34
132Q_LOGGING_CATEGORY(qtLabsPlatformMenus, "qt.labs.platform.menus")
133
135 : QObject(parent),
136 m_complete(false),
137 m_enabled(true),
138 m_visible(true),
139 m_minimumWidth(-1),
140 m_type(QPlatformMenu::DefaultMenu),
141 m_menuBar(nullptr),
142 m_parentMenu(nullptr),
143 m_systemTrayIcon(nullptr),
144 m_menuItem(nullptr),
145 m_iconLoader(nullptr),
146 m_handle(nullptr)
147{
148}
149
151{
152 if (m_menuBar)
153 m_menuBar->removeMenu(this);
154 if (m_parentMenu)
155 m_parentMenu->removeMenu(this);
156
157 unparentSubmenus();
158
159 delete m_iconLoader;
160 m_iconLoader = nullptr;
161 delete m_handle;
162 m_handle = nullptr;
163}
164
165void QQuickLabsPlatformMenu::unparentSubmenus()
166{
167 for (QQuickLabsPlatformMenuItem *item : std::as_const(m_items)) {
168 if (QQuickLabsPlatformMenu *subMenu = item->subMenu())
169 subMenu->setParentMenu(nullptr);
170 item->setMenu(nullptr);
171 }
172}
173
175{
176 return m_handle;
177}
178
180{
181 if (!m_handle) {
182 if (m_menuBar && m_menuBar->handle())
183 m_handle = m_menuBar->handle()->createMenu();
184 else if (m_parentMenu && m_parentMenu->handle())
185 m_handle = m_parentMenu->handle()->createSubMenu();
186#if QT_CONFIG(systemtrayicon)
187 else if (m_systemTrayIcon && m_systemTrayIcon->handle())
188 m_handle = m_systemTrayIcon->handle()->createMenu();
189#endif
190
191 // TODO: implement ^
192 // - QCocoaMenuBar::createMenu()
193 // - QCocoaMenu::createSubMenu()
194 // - QCocoaSystemTrayIcon::createMenu()
195 if (!m_handle)
196 m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
197
198 if (!m_handle)
199 m_handle = QWidgetPlatform::createMenu();
200
201 qCDebug(qtLabsPlatformMenus) << "Menu ->" << m_handle;
202
203 if (m_handle) {
206
207 for (QQuickLabsPlatformMenuItem *item : std::as_const(m_items))
208 m_handle->insertMenuItem(item->create(), nullptr);
209
210 if (m_menuItem) {
211 if (QPlatformMenuItem *handle = m_menuItem->create())
212 handle->setMenu(m_handle);
213 }
214 }
215 }
216 return m_handle;
217}
218
220{
221 if (!m_handle)
222 return;
223
224 // Ensure that all submenus are unparented before we are destroyed,
225 // so that they don't try to access a destroyed menu.
226 unparentSubmenus();
227
228 delete m_handle;
229 m_handle = nullptr;
230}
231
233{
234 if (!m_complete || !create())
235 return;
236
237 m_handle->setText(m_title);
238 m_handle->setEnabled(m_enabled);
239 m_handle->setVisible(m_visible);
240 m_handle->setMinimumWidth(m_minimumWidth);
241 m_handle->setMenuType(m_type);
242 m_handle->setFont(m_font);
243
244 if (m_menuBar && m_menuBar->handle())
245 m_menuBar->handle()->syncMenu(m_handle);
246#if QT_CONFIG(systemtrayicon)
247 else if (m_systemTrayIcon && m_systemTrayIcon->handle())
248 m_systemTrayIcon->handle()->updateMenu(m_handle);
249#endif
250
251 for (QQuickLabsPlatformMenuItem *item : std::as_const(m_items))
252 item->sync();
253}
254
265QQmlListProperty<QObject> QQuickLabsPlatformMenu::data()
266{
267 return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
268}
269
275QQmlListProperty<QQuickLabsPlatformMenuItem> QQuickLabsPlatformMenu::items()
276{
277 return QQmlListProperty<QQuickLabsPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
278}
279
288{
289 return m_menuBar;
290}
291
293{
294 if (m_menuBar == menuBar)
295 return;
296
297 m_menuBar = menuBar;
298 destroy();
300}
301
310{
311 return m_parentMenu;
312}
313
315{
316 if (m_parentMenu == menu)
317 return;
318
319 m_parentMenu = menu;
320 destroy();
322}
323
324#if QT_CONFIG(systemtrayicon)
332QQuickLabsPlatformSystemTrayIcon *QQuickLabsPlatformMenu::systemTrayIcon() const
333{
334 return m_systemTrayIcon;
335}
336
337void QQuickLabsPlatformMenu::setSystemTrayIcon(QQuickLabsPlatformSystemTrayIcon *icon)
338{
339 if (m_systemTrayIcon == icon)
340 return;
341
342 m_systemTrayIcon = icon;
343 destroy();
345}
346#endif
347
355{
356 if (!m_menuItem) {
357 QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
358 m_menuItem = new QQuickLabsPlatformMenuItem(that);
359 m_menuItem->setSubMenu(that);
360 m_menuItem->setText(m_title);
361 m_menuItem->setIcon(icon());
362 m_menuItem->setVisible(m_visible);
363 m_menuItem->setEnabled(m_enabled);
364 m_menuItem->componentComplete();
365 }
366 return m_menuItem;
367}
368
375{
376 return m_enabled;
377}
378
380{
381 if (m_enabled == enabled)
382 return;
383
384 if (m_menuItem)
385 m_menuItem->setEnabled(enabled);
386
387 m_enabled = enabled;
388 sync();
390}
391
398{
399 return m_visible;
400}
401
403{
404 if (m_visible == visible)
405 return;
406
407 if (m_menuItem)
408 m_menuItem->setVisible(visible);
409
410 m_visible = visible;
411 sync();
413}
414
421{
422 return m_minimumWidth;
423}
424
426{
427 if (m_minimumWidth == width)
428 return;
429
430 m_minimumWidth = width;
431 sync();
433}
434
445{
446 return m_type;
447}
448
450{
451 if (m_type == type)
452 return;
453
454 m_type = type;
455 sync();
457}
458
465{
466 return m_title;
467}
468
470{
471 if (m_title == title)
472 return;
473
474 if (m_menuItem)
475 m_menuItem->setText(title);
476
477 m_title = title;
478 sync();
480}
481
490{
491 return m_font;
492}
493
495{
496 if (m_font == font)
497 return;
498
499 m_font = font;
500 sync();
502}
503
513{
514 if (!m_iconLoader)
515 return QQuickLabsPlatformIcon();
516
517 return iconLoader()->icon();
518}
519
521{
522 if (iconLoader()->icon() == icon)
523 return;
524
525 if (m_menuItem)
526 m_menuItem->setIcon(icon);
527
529 emit iconChanged();
530}
531
541
548{
549 if (!item || m_items.contains(item))
550 return;
551
552 m_items.insert(index, item);
553 m_data.append(item);
554 item->setMenu(this);
555 if (m_handle && item->create()) {
556 QQuickLabsPlatformMenuItem *before = m_items.value(index + 1);
557 m_handle->insertMenuItem(item->handle(), before ? before->create() : nullptr);
558 }
559 sync();
561}
562
569{
570 if (!item || !m_items.removeOne(item))
571 return;
572
573 m_data.removeOne(item);
574 if (m_handle)
575 m_handle->removeMenuItem(item->handle());
576 item->setMenu(nullptr);
577 sync();
579}
580
590
597{
598 if (!menu)
599 return;
600
601 menu->setParentMenu(this);
602 insertItem(index, menu->menuItem());
603}
604
611{
612 if (!menu)
613 return;
614
615 menu->setParentMenu(nullptr);
616 removeItem(menu->menuItem());
617}
618
625{
626 if (m_items.isEmpty())
627 return;
628
629 for (QQuickLabsPlatformMenuItem *item : std::as_const(m_items)) {
630 m_data.removeOne(item);
631 if (m_handle)
632 m_handle->removeMenuItem(item->handle());
633 item->setMenu(nullptr);
634 delete item;
635 }
636
637 m_items.clear();
638 sync();
640}
641
654{
655 if (!m_handle)
656 return;
657
658 if (args->length() > 2) {
659 args->v4engine()->throwTypeError();
660 return;
661 }
662
663 QV4::ExecutionEngine *v4 = args->v4engine();
664 QV4::Scope scope(v4);
665
666 QQuickItem *targetItem = nullptr;
667 if (args->length() > 0) {
668 QV4::ScopedValue value(scope, (*args)[0]);
670 if (object)
671 targetItem = qobject_cast<QQuickItem *>(object->object());
672 }
673
675 if (args->length() > 1) {
676 QV4::ScopedValue value(scope, (*args)[1]);
678 if (object)
679 menuItem = qobject_cast<QQuickLabsPlatformMenuItem *>(object->object());
680 }
681
683 QWindow *window = findWindow(targetItem, &offset);
684
685 QRect targetRect;
686 if (targetItem) {
687 QRectF sceneBounds = targetItem->mapRectToScene(targetItem->boundingRect());
688 targetRect = sceneBounds.toAlignedRect().translated(offset);
689 } else {
690#if QT_CONFIG(cursor)
692 if (window)
693 pos = window->mapFromGlobal(pos);
694 targetRect.moveTo(pos);
695#endif
696 }
697 m_handle->showPopup(window,
698 QHighDpi::toNativePixels(targetRect, window),
699 menuItem ? menuItem->handle() : nullptr);
700}
701
708{
709 if (m_handle)
710 m_handle->dismiss();
711}
712
716
718{
719 m_complete = true;
720 if (m_handle && m_iconLoader)
721 m_iconLoader->setEnabled(true);
722 sync();
723}
724
726{
727 if (!m_iconLoader) {
728 QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
729 static int slot = staticMetaObject.indexOfSlot("updateIcon()");
730 m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
731 m_iconLoader->setEnabled(m_complete);
732 }
733 return m_iconLoader;
734}
735
737{
738 QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
739 if (quickWindow) {
740 QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
741 if (renderWindow)
742 return renderWindow;
743 }
744 return window;
745}
746
748{
749 if (target)
750 return effectiveWindow(target->window(), offset);
751
752 if (m_menuBar && m_menuBar->window())
753 return effectiveWindow(m_menuBar->window(), offset);
754
755 QObject *obj = parent();
756 while (obj) {
758 if (window)
760
762 if (item && item->window())
763 return effectiveWindow(item->window(), offset);
764
765 obj = obj->parent();
766 }
767 return nullptr;
768}
769
770void QQuickLabsPlatformMenu::data_append(QQmlListProperty<QObject> *property, QObject *object)
771{
772 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
773 if (QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem *>(object))
774 menu->addItem(item);
775 else if (QQuickLabsPlatformMenu *subMenu = qobject_cast<QQuickLabsPlatformMenu *>(object))
776 menu->addMenu(subMenu);
777 else
778 menu->m_data.append(object);
779}
780
782{
783 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
784 return menu->m_data.size();
785}
786
788{
789 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
790 return menu->m_data.value(index);
791}
792
793void QQuickLabsPlatformMenu::data_clear(QQmlListProperty<QObject> *property)
794{
795 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
796 menu->m_data.clear();
797}
798
799void QQuickLabsPlatformMenu::items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, QQuickLabsPlatformMenuItem *item)
800{
801 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
802 menu->addItem(item);
803}
804
805qsizetype QQuickLabsPlatformMenu::items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
806{
807 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
808 return menu->m_items.size();
809}
810
812{
813 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
814 return menu->m_items.value(index);
815}
816
817void QQuickLabsPlatformMenu::items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
818{
819 QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
820 menu->clear();
821}
822
823void QQuickLabsPlatformMenu::updateIcon()
824{
825 if (!m_handle || !m_iconLoader)
826 return;
827
828 m_handle->setIcon(m_iconLoader->toQIcon());
829 sync();
830}
831
833
834#include "moc_qquicklabsplatformmenu_p.cpp"
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
\reentrant
Definition qfont.h:22
QGraphicsWidget * window() const
static QPlatformTheme * platformTheme()
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
bool removeOne(const AT &t)
Definition qlist.h:598
qsizetype length() const noexcept
Definition qlist.h:399
T value(qsizetype i) const
Definition qlist.h:664
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
void clear()
Removes all the menu's actions.
Definition qmenu.cpp:2225
QAction * addMenu(QMenu *menu)
This convenience function adds menu as a submenu to this menu.
Definition qmenu.cpp:1877
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual void syncMenu(QPlatformMenu *menuItem)=0
virtual QPlatformMenu * createMenu() const
virtual QPlatformMenu * createSubMenu() const
virtual void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)=0
virtual void setText(const QString &text)=0
virtual void removeMenuItem(QPlatformMenuItem *menuItem)=0
virtual void setIcon(const QIcon &icon)=0
void aboutToHide()
virtual void setMenuType(MenuType type)
virtual void setMinimumWidth(int width)
virtual void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
virtual void setEnabled(bool enabled)=0
virtual void dismiss()
virtual void setVisible(bool visible)=0
void aboutToShow()
virtual void setFont(const QFont &font)
virtual QPlatformMenu * createMenu() const
This method allows platforms to use a different QPlatformMenu for system tray menus than what would n...
virtual void updateMenu(QPlatformMenu *menu)=0
This method is called when the system tray menu did change.
\inmodule QtCore\reentrant
Definition qpoint.h:25
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
virtual QRectF boundingRect() const
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
QRectF mapRectToScene(const QRectF &rect) const
Maps the given rect in this item's coordinate system to the equivalent rectangular area within the sc...
void setIcon(const QQuickLabsPlatformIcon &icon)
QQuickLabsPlatformIcon icon() const
Q_INVOKABLE void removeMenu(QQuickLabsPlatformMenu *menu)
\qmlmethod void Qt.labs.platform::MenuBar::removeMenu(Menu menu)
QPlatformMenuBar * handle() const
void setIcon(const QQuickLabsPlatformIcon &icon)
void setSubMenu(QQuickLabsPlatformMenu *menu)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
static QQuickLabsPlatformMenuItem * items_at(QQmlListProperty< QQuickLabsPlatformMenuItem > *property, qsizetype index)
static QObject * data_at(QQmlListProperty< QObject > *property, qsizetype index)
static void items_append(QQmlListProperty< QQuickLabsPlatformMenuItem > *property, QQuickLabsPlatformMenuItem *item)
bool isVisible() const
\qmlproperty bool Qt.labs.platform::Menu::visible
Q_INVOKABLE void insertItem(int index, QQuickLabsPlatformMenuItem *item)
\qmlmethod void Qt.labs.platform::Menu::insertItem(int index, MenuItem item)
static void items_clear(QQmlListProperty< QQuickLabsPlatformMenuItem > *property)
Q_INVOKABLE void removeMenu(QQuickLabsPlatformMenu *menu)
\qmlmethod void Qt.labs.platform::Menu::removeMenu(Menu submenu)
static qsizetype data_count(QQmlListProperty< QObject > *property)
QQuickLabsPlatformIconLoader * iconLoader() const
QQmlListProperty< QObject > data
\qmldefault \qmlproperty list<QtObject> Qt.labs.platform::Menu::data
Q_INVOKABLE void addMenu(QQuickLabsPlatformMenu *menu)
\qmlmethod void Qt.labs.platform::Menu::addMenu(Menu submenu)
Q_INVOKABLE void removeItem(QQuickLabsPlatformMenuItem *item)
\qmlmethod void Qt.labs.platform::Menu::removeItem(MenuItem item)
void setIcon(const QQuickLabsPlatformIcon &icon)
static qsizetype items_count(QQmlListProperty< QQuickLabsPlatformMenuItem > *property)
QQuickLabsPlatformMenuItem * menuItem
Q_INVOKABLE void clear()
\qmlmethod void Qt.labs.platform::Menu::clear()
void setFont(const QFont &font)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
Q_INVOKABLE void addItem(QQuickLabsPlatformMenuItem *item)
\qmlmethod void Qt.labs.platform::Menu::addItem(MenuItem item)
void setType(QPlatformMenu::MenuType type)
static void data_append(QQmlListProperty< QObject > *property, QObject *object)
Q_INVOKABLE void insertMenu(int index, QQuickLabsPlatformMenu *menu)
\qmlmethod void Qt.labs.platform::Menu::insertMenu(int index, Menu submenu)
QQmlListProperty< QQuickLabsPlatformMenuItem > items
\qmlproperty list<MenuItem> Qt.labs.platform::Menu::items
QQuickLabsPlatformIcon icon
QQuickLabsPlatformMenuBar * menuBar
QQuickLabsPlatformMenu * parentMenu
void open(QQmlV4FunctionPtr args)
\qmlmethod void Qt.labs.platform::Menu::open(MenuItem item)
static void data_clear(QQmlListProperty< QObject > *property)
QPlatformMenu * handle() const
void close()
\qmlmethod void Qt.labs.platform::Menu::close()
bool isEnabled() const
\qmlproperty bool Qt.labs.platform::Menu::enabled
void classBegin() override
Invoked after class creation, but before any properties have been set.
void setMenuBar(QQuickLabsPlatformMenuBar *menuBar)
void setTitle(const QString &title)
QPlatformMenu::MenuType type
void setParentMenu(QQuickLabsPlatformMenu *menu)
QWindow * findWindow(QQuickItem *target, QPoint *offset) const
static QWindow * renderWindowFor(QQuickWindow *win, QPoint *offset=nullptr)
Returns the real window that win is being rendered to, if any.
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:484
QRect toAlignedRect() const noexcept
Definition qrect.cpp:2338
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QRect translated(int dx, int dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:261
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
\inmodule QtGui
Definition qwindow.h:63
T toNativePixels(const T &value, const C *context)
Combined button and popup list for selecting options.
static QPlatformMenu * createMenu(QObject *parent=nullptr)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLuint64 GLenum void * handle
GLuint index
[2]
GLuint object
[3]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLsizei width
GLenum type
GLenum target
GLenum GLuint GLintptr offset
GLhandleARB obj
[2]
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:492
static QWindow * effectiveWindow(QWindow *window, QPoint *offset)
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
QWindow * qobject_cast< QWindow * >(QObject *o)
Definition qwindow.h:367
const char property[13]
Definition qwizard.cpp:101
QString title
[35]
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
QMenu menu
[5]
QMenuBar * menuBar
[0]
QJSValueList args
bool contains(const AT &t) const noexcept
Definition qlist.h:45