9#include <QtGui/qwindow.h>
10#include <QtGui/private/qpixmap_win_p.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qvariant.h>
13#include <QtCore/qmetaobject.h>
14#include <QtCore/qpointer.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
36static uint nextId = 1;
40template <
class Derived,
class Needle>
41static int indexOf(
const QList<Derived *> &v,
const Needle *needle)
43 for (
int i = 0, size = v.size(); i < size; ++i) {
44 if (v.at(i) == needle)
51template <
class Derived,
class Base>
52static int insertBefore(QList<Derived *> *v, Base *newItemIn,
const Base *before =
nullptr)
54 int index = before ? indexOf(*v, before) : -1;
56 v->insert(index,
static_cast<Derived *>(newItemIn));
59 v->append(
static_cast<Derived *>(newItemIn));
66 return reinterpret_cast<
const wchar_t *>(s.utf16());
71template <
class Predicate>
74 const QWindowsMenu::MenuItems &items = menu->menuItems();
75 for (QWindowsMenuItem *item : items) {
78 if (item->subMenu()) {
79 if (QWindowsMenuItem *subMenuItem = traverseMenuItems(item->subMenu(), p))
88template <
class Predicate>
91 const QWindowsMenuBar::Menus &menus = menuBar->menus();
92 for (QWindowsMenu *menu : menus) {
93 if (QWindowsMenuItem *item = traverseMenuItems(menu, p))
102 return traverseMenuItems(menu, [id] (
const QWindowsMenuItem *i) {
return i->id() == id; });
107template <
class Predicate>
110 const QWindowsMenu::MenuItems &items = menu->menuItems();
111 for (QWindowsMenuItem *item : items) {
112 if (QWindowsMenu *subMenu = item->subMenu()) {
115 if (QWindowsMenu *menu = traverseMenus(subMenu, p))
124template <
class Predicate>
127 const QWindowsMenuBar::Menus &menus = menuBar->menus();
128 for (QWindowsMenu *menu : menus) {
131 if (QWindowsMenu *subMenu = traverseMenus(menu, p))
137template <
class Menu >
140 return traverseMenus(menu, [hMenu] (
const QWindowsMenu *i) {
return i->menuHandle() == hMenu; });
143template <
class MenuType>
146 for (
int i = pos, size = entries.size(); i < size; ++i) {
147 if (entries.at(i)->isVisible())
155 memset(&menuItemInfo, 0,
sizeof(MENUITEMINFO));
156 menuItemInfo.cbSize =
sizeof(MENUITEMINFO);
161 menuItemInfoInit(menuItemInfo);
162 menuItemInfo.fMask = MIIM_STRING;
163 menuItemInfo.dwTypeData =
const_cast<
wchar_t *>(qStringToWChar(text));
164 menuItemInfo.cch = UINT(text.size());
169 MENUITEMINFO menuItemInfo;
170 menuItemInfoInit(menuItemInfo);
171 menuItemInfo.fMask = MIIM_STATE;
172 return GetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo) == TRUE ? menuItemInfo.fState : 0;
177 MENUITEMINFO menuItemInfo;
178 menuItemInfoInit(menuItemInfo);
179 menuItemInfo.fMask = MIIM_STATE;
180 menuItemInfo.fState = flags;
181 SetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo);
185 bool value, UINT trueState, UINT falseState)
187 const UINT oldState = menuItemState(hMenu, uItem, fByPosition);
188 UINT newState = oldState;
190 newState |= trueState;
191 newState &= ~falseState;
193 newState &= ~trueState;
194 newState |= falseState;
196 if (oldState != newState)
197 menuItemSetState(hMenu, uItem, fByPosition, newState);
202 : m_parentMenu(parentMenu)
205 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this)
206 <<
"parentMenu=" << parentMenu;
211 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
219 DeleteObject(m_hbitmap);
226 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << icon <<
')' <<
this;
227 if (m_icon.cacheKey() == icon.cacheKey())
230 if (m_parentMenu !=
nullptr)
237 if (!m_icon.isNull()) {
238 const int size = m_iconSize ? m_iconSize : GetSystemMetrics(SM_CYMENUCHECK);
241 m_hbitmap = qt_pixmapToWinHBITMAP(m_icon.pixmap(QSize(size, size), 1.0), 1);
243 MENUITEMINFO itemInfo;
244 menuItemInfoInit(itemInfo);
245 itemInfo.fMask = MIIM_BITMAP;
246 itemInfo.hbmpItem = m_hbitmap;
247 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &itemInfo);
252 qCDebug(lcQpaMenus).nospace().noquote()
253 <<
__FUNCTION__ <<
"(\"" << text <<
"\") " <<
this;
257 if (m_parentMenu !=
nullptr)
263 MENUITEMINFO menuItemInfo;
264 const QString &text = nativeText();
265 menuItemInfoSetText(menuItemInfo, text);
266 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &menuItemInfo);
271 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuIn <<
')' <<
this;
272 if (menuIn == m_subMenu)
274 const uint oldId = m_id;
275 if (menuIn !=
nullptr) {
278 m_id = m_subMenu->id();
279 if (m_parentMenu !=
nullptr) {
280 ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND | MF_POPUP,
281 m_id, qStringToWChar(m_text));
287 if (m_parentMenu !=
nullptr) {
289 ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND,
290 m_id, qStringToWChar(m_text));
298 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isVisible <<
')' <<
this;
299 if (m_visible == isVisible)
301 m_visible = isVisible;
302 if (m_parentMenu ==
nullptr)
307 insertIntoMenuHelper(m_parentMenu,
false, m_parentMenu->menuItems().indexOf(
this));
309 RemoveMenu(parentMenuHandle(), m_id, MF_BYCOMMAND);
314 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isSeparator <<
')' <<
this;
315 if (m_separator == isSeparator)
317 m_separator = isSeparator;
318 if (m_parentMenu ==
nullptr)
320 MENUITEMINFO menuItemInfo;
321 menuItemInfoInit(menuItemInfo);
322 menuItemInfo.fMask = MIIM_FTYPE;
323 menuItemInfo.fType = isSeparator ? MFT_SEPARATOR : MFT_STRING;
324 SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &menuItemInfo);
329 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << checkable <<
')' <<
this;
330 if (m_checkable == checkable)
332 m_checkable = checkable;
333 if (m_parentMenu ==
nullptr)
335 UINT state = menuItemState(parentMenuHandle(), m_id, FALSE);
337 state |= m_checked ? MF_CHECKED : MF_UNCHECKED;
339 state &= ~(MF_CHECKED | MF_UNCHECKED);
340 menuItemSetState(parentMenuHandle(), m_id, FALSE, state);
345 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << isChecked <<
')' <<
this;
346 if (m_checked == isChecked)
348 m_checked = isChecked;
353 if (m_parentMenu ==
nullptr || !m_checkable)
355 menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_checked, MF_CHECKED, MF_UNCHECKED);
358#if QT_CONFIG(shortcut)
359void QWindowsMenuItem::setShortcut(
const QKeySequence &shortcut)
361 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << shortcut <<
')' <<
this;
362 if (m_shortcut == shortcut)
364 m_shortcut = shortcut;
365 if (m_parentMenu !=
nullptr)
372 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << enabled <<
')' <<
this;
373 if (m_enabled == enabled)
376 if (m_parentMenu !=
nullptr)
377 menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
382 if (m_iconSize == size)
385 if (m_parentMenu !=
nullptr)
391 return m_parentMenu ? m_parentMenu->menuHandle() :
nullptr;
398 UINT result = MF_STRING | (m_enabled ? MF_ENABLED : MF_GRAYED);
399 if (m_subMenu !=
nullptr)
402 result |= m_checked ? MF_CHECKED : MF_UNCHECKED;
403 if (QGuiApplication::layoutDirection() == Qt::RightToLeft)
404 result |= MFT_RIGHTORDER;
410 QString result = m_text;
411#if QT_CONFIG(shortcut)
412 if (!m_shortcut.isEmpty()) {
414 result += m_shortcut.toString(QKeySequence::NativeText);
422 if (m_id == 0 && m_subMenu ==
nullptr)
424 insertIntoMenuHelper(menu, append, index);
430 const QString &text = nativeText();
432 UINT_PTR idBefore = 0;
435 const int nextIndex = findNextVisibleEntry(menu->menuItems(), index + 1);
437 idBefore = menu->menuItems().at(nextIndex)->id();
441 InsertMenu(menu->menuHandle(), idBefore, state(), m_id, qStringToWChar(text));
443 AppendMenu(menu->menuHandle(), state(), m_id, qStringToWChar(text));
451 m_parentMenu =
nullptr;
452 RemoveMenu(parentMenu->menuHandle(), m_id, MF_BYCOMMAND);
466 : m_parentMenu(parentMenu)
469 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this)
470 <<
"parentMenu=" << parentMenu <<
"HMENU=" << m_hMenu;
475 qCDebug(lcQpaMenus).noquote().nospace() <<
__FUNCTION__
476 <<
" \"" <<m_text <<
"\", " <<
static_cast<
const void *>(
this);
477 for (
int i = m_menuItems.size() - 1; i>= 0; --i)
478 m_menuItems.at(i)->removeFromMenu();
480 DestroyMenu(m_hMenu);
485 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuItemIn <<
", before=" << before <<
')' <<
this;
487 const int index = insertBefore(&m_menuItems, menuItemIn, before);
488 const bool append = index == m_menuItems.size() - 1;
489 menuItem->insertIntoMenu(
this, append, index);
494 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menuItemIn <<
')' <<
this;
500 qCDebug(lcQpaMenus).nospace().noquote()
501 <<
__FUNCTION__ <<
"(\"" << text <<
"\") " <<
this;
507 const HMENU ph = parentHandle();
510 MENUITEMINFO menuItemInfo;
511 menuItemInfoSetText(menuItemInfo, m_text);
512 SetMenuItemInfo(ph, id(), FALSE, &menuItemInfo);
517 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << icon <<
')' <<
this;
523 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << enabled <<
')' <<
this;
524 if (m_enabled == enabled)
529 if (
const HMENU ph = parentHandle())
530 menuItemSetChangeState(ph, id(), FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
535 const auto it =
std::find_if(m_menuItems.cbegin(), m_menuItems.cend(),
537 return it != m_menuItems.cend() ? *it :
nullptr;
542 UINT_PTR idBefore = 0;
545 const int nextIndex = findNextVisibleEntry(bar->menus(), index + 1);
547 idBefore = bar->menus().at(nextIndex)->id();
549 m_parentMenuBar = bar;
550 m_parentMenu =
nullptr;
552 InsertMenu(bar->menuBarHandle(), idBefore, MF_POPUP | MF_BYCOMMAND, id(), qStringToWChar(m_text));
554 AppendMenu(bar->menuBarHandle(), MF_POPUP, id(), qStringToWChar(m_text));
560 m_parentMenuBar =
nullptr;
562 return RemoveMenu(bar->menuBarHandle(), id(), MF_BYCOMMAND) == TRUE;
565 m_parentMenu =
nullptr;
568 item->setMenu(
nullptr);
569 return item !=
nullptr;
576 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << visible <<
')' <<
this;
577 if (m_visible == visible)
580 const HMENU ph = parentHandle();
589 RemoveMenu(ph, id(), MF_BYCOMMAND);
597 qCDebug(lcQpaMenus) <<
__FUNCTION__ << position;
598 return position >= 0 && position < m_menuItems.size()
599 ? m_menuItems.at(position) :
nullptr;
604 return traverseMenuItems(
this, [tag] (
const QPlatformMenuItem *i) {
return i->tag() == tag; });
610 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
617 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
628 return m_parentMenu ? m_parentMenu->menuHandle() :
nullptr;
633 return m_parentMenuBar ? m_parentMenuBar->menuBarHandle() :
nullptr;
639 return m_parentMenuBar->menuBarHandle();
641 return m_parentMenu->menuHandle();
654 const QPlatformMenuItem *item)
656 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'>' <<
this << parentWindow << targetRect << item;
658 const QPoint globalPos = window->mapToGlobal(targetRect.topLeft());
659 trackPopupMenu(window->handle(), globalPos.x(), globalPos.y());
670 TrackPopupMenu(menuHandle(),
671 QGuiApplication::layoutDirection() == Qt::RightToLeft ? UINT(TPM_RIGHTALIGN) : UINT(0),
672 x, y, 0, windowHandle,
nullptr) == TRUE;
679 QPlatformMenuItem *result = lastShownPopupMenu.isNull()
681 : findMenuItemById(lastShownPopupMenu.data(), id);
682 if (result !=
nullptr) {
683 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
"id=" << id;
684 emit result->activated();
687 return result !=
nullptr;
695 emit lastShownPopupMenu->aboutToShow();
698 if (
QWindowsMenu *menu = findMenuByHandle(lastShownPopupMenu.data(), hmenu)) {
699 emit menu->aboutToShow();
709 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
714 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
static_cast<
const void *>(
this);
715 for (
int m = m_menus.size() - 1; m >= 0; --m)
716 m_menus.at(m)->removeFromParent();
718 DestroyMenu(m_hMenuBar);
723 qCDebug(lcQpaMenus) <<
__FUNCTION__ << menuIn <<
"before=" << before;
725 const int index = insertBefore(&m_menus, menuIn, before);
726 menu->insertIntoMenuBar(
this, index == m_menus.size() - 1, index);
731 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << menu <<
')' <<
this;
732 const int index = indexOf(m_menus, menu);
734 m_menus[index]->removeFromParent();
744 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
'(' << newParentWindow <<
')' <<
this;
745 if (newParentWindow ==
nullptr) {
749 if (QPlatformWindow *platWin = newParentWindow->handle())
750 install(
static_cast<QWindowsWindow *>(platWin));
758 return menuBarV.canConvert<QObject *>()
759 ? qobject_cast<QWindowsMenuBar *>(menuBarV.value<QObject *>()) :
nullptr;
764 const HWND hwnd = window->handle();
765 const BOOL result = SetMenu(hwnd, m_hMenuBar);
768 QWindowsContext::forceNcCalcSize(hwnd);
775 const HWND hwnd = window->handle();
776 SetMenu(hwnd,
nullptr);
778 QWindowsContext::forceNcCalcSize(hwnd);
784 return traverseMenus(
this, [tag] (
const QWindowsMenu *m) {
return m->tag() == tag; });
790 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
this <<
"returns" << result;
796 QPlatformMenuItem *result = findMenuItemById(
this, id);
797 if (result !=
nullptr) {
798 qCDebug(lcQpaMenus) <<
__FUNCTION__ <<
"id=" << id;
799 emit result->activated();
801 return result !=
nullptr;
806 if (
QWindowsMenu *menu = findMenuByHandle(
this, hmenu)) {
807 emit menu->aboutToShow();
825 DrawMenuBar(window->handle());
828#ifndef QT_NO_DEBUG_STREAM
833 if (
const int size = v.size()) {
834 d <<
'[' << size <<
"](";
835 for (
int i = 0; i < size; ++i) {
838 if (!v.at(i)->isVisible())
840 d <<
'"' << v.at(i)->text() <<
'"';
851 d <<
'"' << m_text <<
"\", ";
852 d <<
static_cast<
const void *>(
this);
854 d <<
", parentMenu=" <<
static_cast<
const void *>(m_parentMenu);
856 d <<
", subMenu=" <<
static_cast<
const void *>(m_subMenu);
857 d <<
", tag=" << Qt::showbase << Qt::hex
858 << tag() << Qt::noshowbase << Qt::dec <<
", id=" << m_id;
859#if QT_CONFIG(shortcut)
860 if (!m_shortcut.isEmpty())
861 d <<
", shortcut=" << m_shortcut;
868 d <<
", checked=" << m_checked;
871QDebug operator<<(QDebug d,
const QPlatformMenuItem *i)
873 QDebugStateSaver saver(d);
876 d <<
"QPlatformMenuItem(";
887 d <<
'"' << m_text <<
"\", " <<
static_cast<
const void *>(
this)
888 <<
", handle=" << m_hMenu;
889 if (m_parentMenuBar !=
nullptr)
890 d <<
" [on menubar]";
891 if (m_parentMenu !=
nullptr)
894 d <<
", tag=" << Qt::showbase << Qt::hex << tag() << Qt::noshowbase << Qt::dec;
900 formatTextSequence(d, m_menuItems);
905 d <<
static_cast<
const void *>(
this) <<
' ';
906 formatTextSequence(d, m_menus);
909QDebug operator<<(QDebug d,
const QPlatformMenu *m)
911 QDebugStateSaver saver(d);
915 d << m->metaObject()->className() <<
'(';
919 d <<
"QPlatformMenu(0x0)";
924QDebug operator<<(QDebug d,
const QPlatformMenuBar *mb)
926 QDebugStateSaver saver(d);
929 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)