8#include <QtGui/qwindow.h>
9#include <QtGui/private/qpixmap_win_p.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qvariant.h>
12#include <QtCore/qmetaobject.h>
13#include <QtCore/qpointer.h>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
35static uint nextId = 1;
39template <
class Derived,
class Needle>
40static int indexOf(
const QList<Derived *> &v,
const Needle *needle)
42 for (
int i = 0, size = v.size(); i < size; ++i) {
43 if (v.at(i) == needle)
50template <
class Derived,
class Base>
51static int insertBefore(QList<Derived *> *v, Base *newItemIn,
const Base *before =
nullptr)
53 int index = before ? indexOf(*v, before) : -1;
55 v->insert(index,
static_cast<Derived *>(newItemIn));
58 v->append(
static_cast<Derived *>(newItemIn));
65 return reinterpret_cast<
const wchar_t *>(s.utf16());
70template <
class Predicate>
73 const QWindowsMenu::MenuItems &items = menu->menuItems();
74 for (QWindowsMenuItem *item : items) {
77 if (item->subMenu()) {
78 if (QWindowsMenuItem *subMenuItem = traverseMenuItems(item->subMenu(), p))
87template <
class Predicate>
90 const QWindowsMenuBar::Menus &menus = menuBar->menus();
91 for (QWindowsMenu *menu : menus) {
92 if (QWindowsMenuItem *item = traverseMenuItems(menu, p))
101 return traverseMenuItems(menu, [id] (
const QWindowsMenuItem *i) {
return i->id() == id; });
106template <
class Predicate>
109 const QWindowsMenu::MenuItems &items = menu->menuItems();
110 for (QWindowsMenuItem *item : items) {
111 if (QWindowsMenu *subMenu = item->subMenu()) {
114 if (QWindowsMenu *menu = traverseMenus(subMenu, p))
123template <
class Predicate>
126 const QWindowsMenuBar::Menus &menus = menuBar->menus();
127 for (QWindowsMenu *menu : menus) {
130 if (QWindowsMenu *subMenu = traverseMenus(menu, p))
136template <
class Menu >
139 return traverseMenus(menu, [hMenu] (
const QWindowsMenu *i) {
return i->menuHandle() == hMenu; });
142template <
class MenuType>
145 for (
int i = pos, size = entries.size(); i < size; ++i) {
146 if (entries.at(i)->isVisible())
154 memset(&menuItemInfo, 0,
sizeof(MENUITEMINFO));
155 menuItemInfo.cbSize =
sizeof(MENUITEMINFO);
160 menuItemInfoInit(menuItemInfo);
161 menuItemInfo.fMask = MIIM_STRING;
162 menuItemInfo.dwTypeData =
const_cast<
wchar_t *>(qStringToWChar(text));
163 menuItemInfo.cch = UINT(text.size());
168 MENUITEMINFO menuItemInfo;
169 menuItemInfoInit(menuItemInfo);
170 menuItemInfo.fMask = MIIM_STATE;
171 return GetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo) == TRUE ? menuItemInfo.fState : 0;
176 MENUITEMINFO menuItemInfo;
177 menuItemInfoInit(menuItemInfo);
178 menuItemInfo.fMask = MIIM_STATE;
179 menuItemInfo.fState = flags;
180 SetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo);
184 bool value, UINT trueState, UINT falseState)
186 const UINT oldState = menuItemState(hMenu, uItem, fByPosition);
187 UINT newState = oldState;
189 newState |= trueState;
190 newState &= ~falseState;
192 newState &= ~trueState;
193 newState |= falseState;
195 if (oldState != newState)
196 menuItemSetState(hMenu, uItem, fByPosition, newState);
201 : m_parentMenu(parentMenu)
204 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this)
205 <<
"parentMenu=" << parentMenu;
210 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
218 DeleteObject(m_hbitmap);
225 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << icon <<
')' <<
this;
226 if (m_icon.cacheKey() == icon.cacheKey())
229 if (m_parentMenu !=
nullptr)
236 if (!m_icon.isNull()) {
237 const int size = m_iconSize ? m_iconSize : GetSystemMetrics(SM_CYMENUCHECK);
240 m_hbitmap = qt_pixmapToWinHBITMAP(m_icon.pixmap(QSize(size, size), 1.0), 1);
242 MENUITEMINFO itemInfo;
243 menuItemInfoInit(itemInfo);
244 itemInfo.fMask = MIIM_BITMAP;
245 itemInfo.hbmpItem = m_hbitmap;
246 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &itemInfo);
251 qCDebug(lcQpaMenus).nospace().noquote()
252 <<
__FUNCTION__ <<
"(\"" << text <<
"\") " <<
this;
256 if (m_parentMenu !=
nullptr)
262 MENUITEMINFO menuItemInfo;
263 const QString &text = nativeText();
264 menuItemInfoSetText(menuItemInfo, text);
265 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &menuItemInfo);
270 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuIn <<
')' <<
this;
271 if (menuIn == m_subMenu)
273 const uint oldId = m_id;
274 if (menuIn !=
nullptr) {
277 m_id = m_subMenu->id();
278 if (m_parentMenu !=
nullptr) {
279 ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND | MF_POPUP,
280 m_id, qStringToWChar(m_text));
286 if (m_parentMenu !=
nullptr) {
288 ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND,
289 m_id, qStringToWChar(m_text));
297 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isVisible <<
')' <<
this;
298 if (m_visible == isVisible)
300 m_visible = isVisible;
301 if (m_parentMenu ==
nullptr)
306 insertIntoMenuHelper(m_parentMenu,
false, m_parentMenu->menuItems().indexOf(
this));
308 RemoveMenu(parentMenuHandle(), m_id, MF_BYCOMMAND);
313 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isSeparator <<
')' <<
this;
314 if (m_separator == isSeparator)
316 m_separator = isSeparator;
317 if (m_parentMenu ==
nullptr)
319 MENUITEMINFO menuItemInfo;
320 menuItemInfoInit(menuItemInfo);
321 menuItemInfo.fMask = MIIM_FTYPE;
322 menuItemInfo.fType = isSeparator ? MFT_SEPARATOR : MFT_STRING;
323 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &menuItemInfo);
328 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << checkable <<
')' <<
this;
329 if (m_checkable == checkable)
331 m_checkable = checkable;
332 if (m_parentMenu ==
nullptr)
334 UINT state = menuItemState(parentMenuHandle(), m_id, FALSE);
336 state |= m_checked ? MF_CHECKED : MF_UNCHECKED;
338 state &= ~(MF_CHECKED | MF_UNCHECKED);
339 menuItemSetState(parentMenuHandle(), m_id, FALSE, state);
344 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isChecked <<
')' <<
this;
345 if (m_checked == isChecked)
347 m_checked = isChecked;
352 if (m_parentMenu ==
nullptr || !m_checkable)
354 menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_checked, MF_CHECKED, MF_UNCHECKED);
357#if QT_CONFIG(shortcut)
358void QWindowsMenuItem::setShortcut(
const QKeySequence &shortcut)
360 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << shortcut <<
')' <<
this;
361 if (m_shortcut == shortcut)
363 m_shortcut = shortcut;
364 if (m_parentMenu !=
nullptr)
371 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << enabled <<
')' <<
this;
372 if (m_enabled == enabled)
375 if (m_parentMenu !=
nullptr)
376 menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
381 if (m_iconSize == size)
384 if (m_parentMenu !=
nullptr)
390 return m_parentMenu ? m_parentMenu->menuHandle() :
nullptr;
397 UINT result = MF_STRING | (m_enabled ? MF_ENABLED : MF_GRAYED);
398 if (m_subMenu !=
nullptr)
401 result |= m_checked ? MF_CHECKED : MF_UNCHECKED;
402 if (QGuiApplication::layoutDirection() == Qt::RightToLeft)
403 result |= MFT_RIGHTORDER;
409 QString result = m_text;
410#if QT_CONFIG(shortcut)
411 if (!m_shortcut.isEmpty()) {
413 result += m_shortcut.toString(QKeySequence::NativeText);
421 if (m_id == 0 && m_subMenu ==
nullptr)
423 insertIntoMenuHelper(menu, append, index);
429 const QString &text = nativeText();
431 UINT_PTR idBefore = 0;
434 const int nextIndex = findNextVisibleEntry(menu->menuItems(), index + 1);
436 idBefore = menu->menuItems().at(nextIndex)->id();
440 InsertMenu(menu->menuHandle(), idBefore, state(), m_id, qStringToWChar(text));
442 AppendMenu(menu->menuHandle(), state(), m_id, qStringToWChar(text));
450 m_parentMenu =
nullptr;
451 RemoveMenu(parentMenu->menuHandle(), m_id, MF_BYCOMMAND);
465 : m_parentMenu(parentMenu)
468 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this)
469 <<
"parentMenu=" << parentMenu <<
"HMENU=" << m_hMenu;
474 qCDebug(lcQpaMenus).noquote().nospace() <<
__FUNCTION__
475 <<
" \"" <<m_text <<
"\", " <<
static_cast<
const void *>(
this);
476 for (
int i = m_menuItems.size() - 1; i>= 0; --i)
477 m_menuItems.at(i)->removeFromMenu();
479 DestroyMenu(m_hMenu);
484 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuItemIn <<
", before=" << before <<
')' <<
this;
486 const int index = insertBefore(&m_menuItems, menuItemIn, before);
487 const bool append = index == m_menuItems.size() - 1;
488 menuItem->insertIntoMenu(
this, append, index);
493 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuItemIn <<
')' <<
this;
499 qCDebug(lcQpaMenus).nospace().noquote()
500 <<
__FUNCTION__ <<
"(\"" << text <<
"\") " <<
this;
506 const HMENU ph = parentHandle();
509 MENUITEMINFO menuItemInfo;
510 menuItemInfoSetText(menuItemInfo, m_text);
511 SetMenuItemInfo(ph, id(), FALSE, &menuItemInfo);
516 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << icon <<
')' <<
this;
522 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << enabled <<
')' <<
this;
523 if (m_enabled == enabled)
528 if (
const HMENU ph = parentHandle())
529 menuItemSetChangeState(ph, id(), FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
534 const auto it = std::find_if(m_menuItems.cbegin(), m_menuItems.cend(),
535 [subMenu] (
const QWindowsMenuItem *i) {
return i->subMenu() == subMenu; });
536 return it != m_menuItems.cend() ? *it :
nullptr;
541 UINT_PTR idBefore = 0;
544 const int nextIndex = findNextVisibleEntry(bar->menus(), index + 1);
546 idBefore = bar->menus().at(nextIndex)->id();
548 m_parentMenuBar = bar;
549 m_parentMenu =
nullptr;
551 InsertMenu(bar->menuBarHandle(), idBefore, MF_POPUP | MF_BYCOMMAND, id(), qStringToWChar(m_text));
553 AppendMenu(bar->menuBarHandle(), MF_POPUP, id(), qStringToWChar(m_text));
559 m_parentMenuBar =
nullptr;
561 return RemoveMenu(bar->menuBarHandle(), id(), MF_BYCOMMAND) == TRUE;
564 m_parentMenu =
nullptr;
567 item->setMenu(
nullptr);
568 return item !=
nullptr;
575 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << visible <<
')' <<
this;
576 if (m_visible == visible)
579 const HMENU ph = parentHandle();
588 RemoveMenu(ph, id(), MF_BYCOMMAND);
596 qCDebug(lcQpaMenus) <<
__FUNCTION__ << position;
597 return position >= 0 && position < m_menuItems.size()
598 ? m_menuItems.at(position) :
nullptr;
603 return traverseMenuItems(
this, [tag] (
const QPlatformMenuItem *i) {
return i->tag() == tag; });
609 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
616 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
627 return m_parentMenu ? m_parentMenu->menuHandle() :
nullptr;
632 return m_parentMenuBar ? m_parentMenuBar->menuBarHandle() :
nullptr;
638 return m_parentMenuBar->menuBarHandle();
640 return m_parentMenu->menuHandle();
653 const QPlatformMenuItem *item)
655 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'>' <<
this << parentWindow << targetRect << item;
657 const QPoint globalPos = window->mapToGlobal(targetRect.topLeft());
658 trackPopupMenu(window->handle(), globalPos.x(), globalPos.y());
669 TrackPopupMenu(menuHandle(),
670 QGuiApplication::layoutDirection() == Qt::RightToLeft ? UINT(TPM_RIGHTALIGN) : UINT(0),
671 x, y, 0, windowHandle,
nullptr) == TRUE;
678 QPlatformMenuItem *result = lastShownPopupMenu.isNull()
680 : findMenuItemById(lastShownPopupMenu.data(), id);
681 if (result !=
nullptr) {
682 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
"id=" << id;
683 emit result->activated();
686 return result !=
nullptr;
694 emit lastShownPopupMenu->aboutToShow();
697 if (
QWindowsMenu *menu = findMenuByHandle(lastShownPopupMenu.data(), hmenu)) {
698 emit menu->aboutToShow();
708 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
713 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
714 for (
int m = m_menus.size() - 1; m >= 0; --m)
715 m_menus.at(m)->removeFromParent();
717 DestroyMenu(m_hMenuBar);
722 qCDebug(lcQpaMenus) <<
__FUNCTION__ << menuIn <<
"before=" << before;
724 const int index = insertBefore(&m_menus, menuIn, before);
725 menu->insertIntoMenuBar(
this, index == m_menus.size() - 1, index);
730 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menu <<
')' <<
this;
731 const int index = indexOf(m_menus, menu);
733 m_menus[index]->removeFromParent();
743 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << newParentWindow <<
')' <<
this;
744 if (newParentWindow ==
nullptr) {
748 if (QPlatformWindow *platWin = newParentWindow->handle())
749 install(
static_cast<QWindowsWindow *>(platWin));
751 newParentWindow->setProperty(menuBarPropertyName, QVariant::fromValue<QObject *>(
this));
757 return menuBarV.canConvert<QObject *>()
758 ? qobject_cast<QWindowsMenuBar *>(menuBarV.value<QObject *>()) :
nullptr;
763 const HWND hwnd = window->handle();
764 const BOOL result = SetMenu(hwnd, m_hMenuBar);
767 QWindowsContext::forceNcCalcSize(hwnd);
774 const HWND hwnd = window->handle();
775 SetMenu(hwnd,
nullptr);
777 QWindowsContext::forceNcCalcSize(hwnd);
783 return traverseMenus(
this, [tag] (
const QWindowsMenu *m) {
return m->tag() == tag; });
789 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
795 QPlatformMenuItem *result = findMenuItemById(
this, id);
796 if (result !=
nullptr) {
797 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
"id=" << id;
798 emit result->activated();
800 return result !=
nullptr;
805 if (
QWindowsMenu *menu = findMenuByHandle(
this, hmenu)) {
806 emit menu->aboutToShow();
824 DrawMenuBar(window->handle());
827#ifndef QT_NO_DEBUG_STREAM
832 if (
const int size = v.size()) {
833 d <<
'[' << size <<
"](";
834 for (
int i = 0; i < size; ++i) {
837 if (!v.at(i)->isVisible())
839 d <<
'"' << v.at(i)->text() <<
'"';
850 d <<
'"' << m_text <<
"\", ";
851 d <<
static_cast<
const void *>(
this);
853 d <<
", parentMenu=" <<
static_cast<
const void *>(m_parentMenu);
855 d <<
", subMenu=" <<
static_cast<
const void *>(m_subMenu);
856 d <<
", tag=" << Qt::showbase << Qt::hex
857 << tag() << Qt::noshowbase << Qt::dec <<
", id=" << m_id;
858#if QT_CONFIG(shortcut)
859 if (!m_shortcut.isEmpty())
860 d <<
", shortcut=" << m_shortcut;
867 d <<
", checked=" << m_checked;
870QDebug operator<<(QDebug d,
const QPlatformMenuItem *i)
872 QDebugStateSaver saver(d);
875 d <<
"QPlatformMenuItem(";
886 d <<
'"' << m_text <<
"\", " <<
static_cast<
const void *>(
this)
887 <<
", handle=" << m_hMenu;
888 if (m_parentMenuBar !=
nullptr)
889 d <<
" [on menubar]";
890 if (m_parentMenu !=
nullptr)
893 d <<
", tag=" << Qt::showbase << Qt::hex << tag() << Qt::noshowbase << Qt::dec;
899 formatTextSequence(d, m_menuItems);
904 d <<
static_cast<
const void *>(
this) <<
' ';
905 formatTextSequence(d, m_menus);
908QDebug operator<<(QDebug d,
const QPlatformMenu *m)
910 QDebugStateSaver saver(d);
914 d << m->metaObject()->className() <<
'(';
918 d <<
"QPlatformMenu(0x0)";
923QDebug operator<<(QDebug d,
const QPlatformMenuBar *mb)
925 QDebugStateSaver saver(d);
928 d <<
"QPlatformMenuBar(";
\inmodule QtCore\reentrant
Base class for QWindowsForeignWindow, QWindowsWindow.
Singleton container for all relevant information.
QWindowsWindow * findPlatformWindow(const QWindowsMenuBar *mb) const
static QWindowsContext * instance()
void setMenuBar(QWindowsMenuBar *mb)