1
/****************************************************************************
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the QtGui module of the Qt Toolkit.
9
** $QT_BEGIN_LICENSE:LGPL$
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
16
** GNU Lesser General Public License Usage
17
** Alternatively, this file may be used under the terms of the GNU Lesser
18
** General Public License version 2.1 as published by the Free Software
19
** Foundation and appearing in the file LICENSE.LGPL included in the
20
** packaging of this file. Please review the following information to
21
** ensure the GNU Lesser General Public License version 2.1 requirements
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
40
****************************************************************************/
42
//Native menubars are only supported for Windows Mobile not the standard SDK/generic WinCE
45
#include "qt_windows.h"
46
#include "qapplication.h"
47
#include "qmainwindow.h"
52
#include "qwidgetaction.h"
53
#include <private/qapplication_p.h>
54
#include <private/qmenu_p.h>
55
#include <private/qmenubar_p.h>
57
#include "qmenu_wince_resource_p.h"
59
#include <QtCore/qlibrary.h>
62
# include <windowsm.h>
65
#include "qguifunctions_wince.h"
69
#ifndef SHCMBF_EMPTYBAR
70
#define SHCMBF_EMPTYBAR 0x0001
73
#ifndef SHCMBM_GETSUBMENU
74
#define SHCMBM_GETSUBMENU (WM_USER + 401)
78
# define SHMBOF_NODEFAULT 0x00000001
79
# define SHMBOF_NOTIFY 0x00000002
80
# define SHCMBM_OVERRIDEKEY (WM_USER + 0x193)
83
extern bool qt_wince_is_smartphone();//defined in qguifunctions_wce.cpp
84
extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wce.cpp
88
static uint qt_wce_menu_static_cmd_id = 200;
89
static QList<QMenuBar*> nativeMenuBars;
91
struct qt_SHMENUBARINFO
104
typedef int (WINAPI *superfunc)(int, int);
105
typedef BOOL (WINAPI *AygCreateMenuBar)(qt_SHMENUBARINFO*);
106
typedef HRESULT (WINAPI *AygEnableSoftKey)(HWND,UINT,BOOL,BOOL);
108
static bool aygResolved = false;
109
static AygCreateMenuBar ptrCreateMenuBar = 0;
110
static AygEnableSoftKey ptrEnableSoftKey = 0;
112
static void resolveAygLibs()
116
QLibrary aygLib(QLatin1String("aygshell"));
119
ptrCreateMenuBar = (AygCreateMenuBar) aygLib.resolve("SHCreateMenuBar");
120
ptrEnableSoftKey = (AygEnableSoftKey) aygLib.resolve("SHEnableSoftkey");
124
static void qt_wce_enable_soft_key(HWND handle, uint command)
127
if (ptrEnableSoftKey)
128
ptrEnableSoftKey(handle, command, false, true);
130
static void qt_wce_disable_soft_key(HWND handle, uint command)
133
if (ptrEnableSoftKey)
134
ptrEnableSoftKey(handle, command, false, false);
137
static void qt_wce_delete_action_list(QList<QWceMenuAction*> *list) {
138
for(QList<QWceMenuAction*>::Iterator it = list->begin(); it != list->end(); ++it) {
139
QWceMenuAction *action = (*it);
146
//search for first QuitRole in QMenuBar
147
static QAction* qt_wce_get_quit_action(QList<QAction *> actionItems) {
148
QAction *returnAction = 0;
149
for (int i = 0; i < actionItems.size(); ++i) {
150
QAction *action = actionItems.at(i);
151
if (action->menuRole() == QAction::QuitRole)
152
returnAction = action;
155
returnAction = qt_wce_get_quit_action(action->menu()->actions());
157
return returnAction; //return first action found
159
return 0; //nothing found;
162
static QAction* qt_wce_get_quit_action(QList<QWceMenuAction*> actionItems) {
163
for (int i = 0; i < actionItems.size(); ++i) {
164
if (actionItems.at(i)->action->menuRole() == QAction::QuitRole)
165
return actionItems.at(i)->action;
166
else if (actionItems.at(i)->action->menu()) {
167
QAction *returnAction = qt_wce_get_quit_action(actionItems.at(i)->action->menu()->actions());
175
static HMODULE qt_wce_get_module_handle() {
176
HMODULE module = 0; //handle to resources
177
if (!(module = GetModuleHandle(L"QtGui4"))) //release dynamic
178
if (!(module = GetModuleHandle(L"QtGuid4"))) //debug dynamic
179
module = (HINSTANCE)qWinAppInst(); //static
180
Q_ASSERT_X(module, "qt_wce_get_module_handle()", "cannot get handle to module?");
184
static void qt_wce_change_command(HWND menuHandle, int item, int command) {
186
memset(&tbbi,0,sizeof(tbbi));
187
tbbi.cbSize = sizeof(tbbi);
188
tbbi.dwMask = TBIF_COMMAND;
189
tbbi.idCommand = command;
190
SendMessage(menuHandle, TB_SETBUTTONINFO, item, (LPARAM)&tbbi);
193
static void qt_wce_rename_menu_item(HWND menuHandle, int item, const QString &newText) {
195
memset(&tbbi,0,sizeof(tbbi));
196
tbbi.cbSize = sizeof(tbbi);
197
tbbi.dwMask = TBIF_TEXT;
198
QString text = newText;
199
text.remove(QChar::fromLatin1('&'));
200
tbbi.pszText = (LPSTR) text.utf16();
201
SendMessage(menuHandle, TB_SETBUTTONINFO, item, (LPARAM)&tbbi);
204
static HWND qt_wce_create_menubar(HWND parentHandle, HINSTANCE resourceHandle, int toolbarID, int flags = 0) {
207
if (ptrCreateMenuBar) {
208
qt_SHMENUBARINFO mbi;
209
memset(&mbi, 0, sizeof(qt_SHMENUBARINFO));
210
mbi.cbSize = sizeof(qt_SHMENUBARINFO);
211
mbi.hwndParent = parentHandle;
212
mbi.hInstRes = resourceHandle;
214
mbi.nToolBarId = toolbarID;
216
if (ptrCreateMenuBar(&mbi)) {
218
// Tell the menu bar that we want to override hot key behaviour.
219
LPARAM lparam = MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY,
220
SHMBOF_NODEFAULT | SHMBOF_NOTIFY);
221
SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, lparam);
229
static void qt_wce_insert_action(HMENU menu, QWceMenuAction *action, bool created) {
231
Q_ASSERT_X(menu, "AppendMenu", "menu is 0");
232
if (action->action->isVisible()) {
234
action->action->isEnabled() ? flags = MF_ENABLED : flags = MF_GRAYED;
236
QString text = action->action->iconText();
237
text.remove(QChar::fromLatin1('&'));
238
if (action->action->isSeparator()) {
239
AppendMenu (menu, MF_SEPARATOR , 0, 0);
241
else if (action->action->menu()) {
242
text.remove(QChar::fromLatin1('&'));
243
AppendMenu (menu, MF_STRING | flags | MF_POPUP,
244
(UINT) action->action->menu()->wceMenu(created), reinterpret_cast<const wchar_t *> (text.utf16()));
247
AppendMenu (menu, MF_STRING | flags, action->command, reinterpret_cast<const wchar_t *> (text.utf16()));
249
if (action->action->isCheckable())
250
if (action->action->isChecked())
251
CheckMenuItem(menu, action->command, MF_BYCOMMAND | MF_CHECKED);
253
CheckMenuItem(menu, action->command, MF_BYCOMMAND | MF_UNCHECKED);
260
This function refreshes the native Windows CE menu.
263
void QMenuBar::wceRefresh() {
264
for (int i = 0; i < nativeMenuBars.size(); ++i)
265
nativeMenuBars.at(i)->d_func()->wceRefresh();
268
void QMenuBarPrivate::wceRefresh() {
269
DrawMenuBar(wce_menubar->menubarHandle);
275
This function sends native Windows CE commands to Qt menus.
278
QAction* QMenu::wceCommands(uint command) {
280
return d->wceCommands(command);
286
This function sends native Windows CE commands to Qt menu bars
287
and all their child menus.
290
void QMenuBar::wceCommands(uint command, HWND) {
291
for (int i = 0; i < nativeMenuBars.size(); ++i)
292
nativeMenuBars.at(i)->d_func()->wceCommands(command);
295
bool QMenuBarPrivate::wceEmitSignals(QList<QWceMenuAction*> actions, uint command) {
296
QAction *foundAction = 0;
297
for (int i = 0; i < actions.size(); ++i) {
300
QWceMenuAction *action = actions.at(i);
301
if (action->action->menu()) {
302
foundAction = action->action->menu()->wceCommands(command);
304
else if (action->command == command) {
305
emit q_func()->triggered(action->action);
306
action->action->activate(QAction::Trigger);
311
emit q_func()->triggered(foundAction);
317
void QMenuBarPrivate::wceCommands(uint command) {
318
if (wceClassicMenu) {
319
for (int i = 0; i < wce_menubar->actionItemsClassic.size(); ++i)
320
wceEmitSignals(wce_menubar->actionItemsClassic.at(i), command);
322
if (wceEmitSignals(wce_menubar->actionItems, command)) {
325
else if (wce_menubar->leftButtonIsMenu) {//check if command is on the left quick button
326
wceEmitSignals(wce_menubar->actionItemsLeftButton, command);
328
else if ((wce_menubar->leftButtonAction) && (command == wce_menubar->leftButtonCommand)) {
329
emit q_func()->triggered(wce_menubar->leftButtonAction);
330
wce_menubar->leftButtonAction->activate(QAction::Trigger);
335
QAction *QMenuPrivate::wceCommands(uint command) {
336
QAction *foundAction = 0;
337
for (int i = 0; i < wce_menu->actionItems.size(); ++i) {
340
QWceMenuAction *action = wce_menu->actionItems.at(i);
341
if (action->action->menu()) {
342
foundAction = action->action->menu()->d_func()->wceCommands(command);
344
else if (action->command == command) {
345
action->action->activate(QAction::Trigger);
346
return action->action;
350
emit q_func()->triggered(foundAction);
354
void QMenuBarPrivate::wceCreateMenuBar(QWidget *parent) {
357
wce_menubar = new QWceMenuBarPrivate(this);
359
wce_menubar->parentWindowHandle = parent ? parent->winId() : q->winId();
360
wce_menubar->leftButtonAction = defaultAction;
362
wce_menubar->menubarHandle = qt_wce_create_menubar(wce_menubar->parentWindowHandle, (HINSTANCE)qWinAppInst(), 0, SHCMBF_EMPTYBAR);
363
Q_ASSERT_X(wce_menubar->menubarHandle, "wceCreateMenuBar", "cannot create empty menu bar");
364
DrawMenuBar(wce_menubar->menubarHandle);
365
nativeMenuBars.append(q);
366
wceClassicMenu = (!qt_wince_is_smartphone() && !qt_wince_is_pocket_pc());
369
void QMenuBarPrivate::wceDestroyMenuBar() {
371
int index = nativeMenuBars.indexOf(q);
372
nativeMenuBars.removeAt(index);
378
QMenuBarPrivate::QWceMenuBarPrivate::QWceMenuBarPrivate(QMenuBarPrivate *menubar) :
379
menubarHandle(0), menuHandle(0),leftButtonMenuHandle(0) ,
380
leftButtonAction(0), leftButtonIsMenu(false), d(menubar) {
383
QMenuBarPrivate::QWceMenuBarPrivate::~QWceMenuBarPrivate() {
385
DestroyWindow(menubarHandle);
386
qt_wce_delete_action_list(&actionItems);
387
qt_wce_delete_action_list(&actionItemsLeftButton);
389
for (int i=0; i<actionItemsClassic.size(); ++i)
390
if (!actionItemsClassic.value(i).empty())
391
qt_wce_delete_action_list(&actionItemsClassic[i]);
392
actionItemsClassic.clear();
396
leftButtonMenuHandle = 0;
397
leftButtonCommand = 0;
398
QMenuBar::wceRefresh();
401
QMenuPrivate::QWceMenuPrivate::QWceMenuPrivate() {
405
QMenuPrivate::QWceMenuPrivate::~QWceMenuPrivate() {
406
qt_wce_delete_action_list(&actionItems);
410
void QMenuPrivate::QWceMenuPrivate::addAction(QAction *a, QWceMenuAction *before) {
411
QWceMenuAction *action = new QWceMenuAction;
413
action->command = qt_wce_menu_static_cmd_id++;
414
addAction(action, before);
417
void QMenuPrivate::QWceMenuPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before) {
420
int before_index = actionItems.indexOf(before);
421
if (before_index < 0) {
423
before_index = actionItems.size();
425
actionItems.insert(before_index, action);
432
This function will return the HMENU used to create the native
433
Windows CE menu bar bindings.
436
HMENU QMenu::wceMenu(bool create) { return d_func()->wceMenu(create); }
438
HMENU QMenuPrivate::wceMenu(bool create) {
440
wce_menu = new QWceMenuPrivate;
441
if (!wce_menu->menuHandle || create)
442
wce_menu->rebuild(create);
443
return wce_menu->menuHandle;
446
void QMenuPrivate::QWceMenuPrivate::rebuild(bool reCreate) {
447
if (menuHandle && !reCreate)
448
DestroyMenu(menuHandle);
449
menuHandle = CreatePopupMenu();
450
for (int i = 0; i < actionItems.size(); ++i) {
451
QWceMenuAction *action = actionItems.at(i);
452
action->menuHandle = menuHandle;
453
qt_wce_insert_action(menuHandle, action, true);
455
QMenuBar::wceRefresh();
458
void QMenuPrivate::QWceMenuPrivate::syncAction(QWceMenuAction *) {
462
void QMenuPrivate::QWceMenuPrivate::removeAction(QWceMenuAction *action) {
463
actionItems.removeAll(action);
469
void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QWceMenuAction *before) {
470
QWceMenuAction *action = new QWceMenuAction;
472
action->command = qt_wce_menu_static_cmd_id++;
473
addAction(action, before);
476
void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before) {
479
int before_index = actionItems.indexOf(before);
480
if (before_index < 0) {
482
before_index = actionItems.size();
484
actionItems.insert(before_index, action);
488
void QMenuBarPrivate::QWceMenuBarPrivate::syncAction(QWceMenuAction*) {
489
QMenuBar::wceRefresh();
493
void QMenuBarPrivate::QWceMenuBarPrivate::removeAction(QWceMenuAction *action) {
494
actionItems.removeAll(action);
500
void QMenuBarPrivate::_q_updateDefaultAction() {
502
wce_menubar->rebuild();
505
void QMenuBarPrivate::QWceMenuBarPrivate::rebuild() {
507
d->q_func()->resize(0,0);
508
parentWindowHandle = d->q_func()->parentWidget() ? d->q_func()->parentWidget()->winId() : d->q_func()->winId();
509
if (d->wceClassicMenu) {
510
QList<QAction*> actions = d->actions;
513
if (actions.size() < 5) {
515
resourceHandle = IDR_MAIN_MENU3;
516
} else if (actions.size() < 7) {
518
resourceHandle = IDR_MAIN_MENU4;
522
resourceHandle = IDR_MAIN_MENU5;
524
Q_ASSERT_X(menubarHandle, "rebuild !created", "menubar already deleted");
525
DestroyWindow(menubarHandle);
526
menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), resourceHandle);
527
Q_ASSERT_X(menubarHandle, "rebuild classic menu", "cannot create menubar from resource");
528
DrawMenuBar(menubarHandle);
531
menu_ids << IDM_MENU1 << IDM_MENU2 << IDM_MENU3 << IDM_MENU4 << IDM_MENU5 << IDM_MENU6 << IDM_MENU7 << IDM_MENU8;
532
item_ids << IDM_ITEM1 << IDM_ITEM2 << IDM_ITEM3 << IDM_ITEM4 << IDM_ITEM5 << IDM_ITEM6 << IDM_ITEM7 << IDM_ITEM8;
534
for (int i = 0; i < actionItemsClassic.size(); ++i)
535
if (!actionItemsClassic.value(i).empty())
536
qt_wce_delete_action_list(&actionItemsClassic[i]);
537
actionItemsClassic.clear();
539
for (int i = 0; i < actions.size(); ++i) {
540
qt_wce_rename_menu_item(menubarHandle, menu_ids.at(i), actions.at(i)->text());
541
QList<QAction *> subActions = actions.at(i)->menu()->actions();
542
HMENU subMenuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0 , menu_ids.at(i));
543
DeleteMenu(subMenuHandle, item_ids.at(i), MF_BYCOMMAND);
544
for (int c = 0; c < subActions.size(); ++c) {
545
QList<QWceMenuAction*> list;
546
actionItemsClassic.append(list);
547
QWceMenuAction *action = new QWceMenuAction;
548
action->action = subActions.at(c);
549
action->command = qt_wce_menu_static_cmd_id++;
550
action->menuHandle = subMenuHandle;
551
actionItemsClassic.last().append(action);
552
qt_wce_insert_action(subMenuHandle, action, true);
555
for (int i = actions.size();i<maxEntries;++i) {
556
qt_wce_rename_menu_item(menubarHandle, menu_ids.at(i), QString());
557
qt_wce_disable_soft_key(menubarHandle, menu_ids.at(i));
560
leftButtonAction = d->defaultAction;
561
if (!leftButtonAction)
562
leftButtonAction = qt_wce_get_quit_action(actionItems);
564
leftButtonIsMenu = (leftButtonAction && leftButtonAction->menu());
565
Q_ASSERT_X(menubarHandle, "rebuild !created", "menubar already deleted");
566
DestroyWindow(menubarHandle);
567
if (leftButtonIsMenu) {
568
menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), IDR_MAIN_MENU2);
569
Q_ASSERT_X(menubarHandle, "rebuild !created left menubar", "cannot create menubar from resource");
570
menuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_MENU);
571
Q_ASSERT_X(menuHandle, "rebuild !created", "IDM_MENU not found - invalid resource?");
572
DeleteMenu(menuHandle, IDM_ABOUT, MF_BYCOMMAND);
573
leftButtonMenuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_LEFTMENU);
574
Q_ASSERT_X(leftButtonMenuHandle, "rebuild !created", "IDM_LEFTMENU not found - invalid resource?");
575
DeleteMenu(leftButtonMenuHandle, IDM_VIEW, MF_BYCOMMAND);
577
menubarHandle = qt_wce_create_menubar(parentWindowHandle, qt_wce_get_module_handle(), IDR_MAIN_MENU);
578
Q_ASSERT_X(menubarHandle, "rebuild !created no left menubar", "cannot create menubar from resource");
579
menuHandle = (HMENU) SendMessage(menubarHandle, SHCMBM_GETSUBMENU,0,IDM_MENU);
580
Q_ASSERT_X(menuHandle, "rebuild !created", "IDM_MENU not found - invalid resource?");
581
DeleteMenu(menuHandle, IDM_ABOUT, MF_BYCOMMAND);
582
leftButtonMenuHandle = 0;
583
leftButtonCommand = qt_wce_menu_static_cmd_id++;
584
qt_wce_change_command(menubarHandle, IDM_EXIT, leftButtonCommand);
587
if (actionItems.size() == 0) {
588
qt_wce_rename_menu_item(menubarHandle, IDM_MENU, QLatin1String(""));
589
qt_wce_disable_soft_key(menubarHandle, IDM_MENU);
591
for (int i = 0; i < actionItems.size(); ++i) {
592
QWceMenuAction *action = actionItems.at(i);
593
action->menuHandle = menuHandle;
594
qt_wce_insert_action(menuHandle, action, true);
596
if (!leftButtonIsMenu) {
597
if (leftButtonAction) {
598
qt_wce_rename_menu_item(menubarHandle, leftButtonCommand, leftButtonAction->text());
599
qt_wce_enable_soft_key(menubarHandle, leftButtonCommand);
601
qt_wce_rename_menu_item(menubarHandle, leftButtonCommand, QLatin1String(""));
602
qt_wce_disable_soft_key(menubarHandle, leftButtonCommand);
605
qt_wce_rename_menu_item(menubarHandle, IDM_LEFTMENU, leftButtonAction->text());
606
QList<QAction *> actions = leftButtonAction->menu()->actions();
607
qt_wce_delete_action_list(&actionItemsLeftButton);
608
for (int i=0; i<actions.size(); ++i) {
609
QWceMenuAction *action = new QWceMenuAction;
610
action->action = actions.at(i);
611
action->command = qt_wce_menu_static_cmd_id++;
612
action->menuHandle = leftButtonMenuHandle;
613
actionItemsLeftButton.append(action);
614
qt_wce_insert_action(leftButtonMenuHandle, action, true);
618
DrawMenuBar(menubarHandle);
623
#endif //QT_NO_MENUBAR