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
#include <private/qmainwindowlayout_p.h>
44
#include <private/qtoolbarlayout_p.h>
45
#include <private/qt_cocoa_helpers_mac_p.h>
47
#ifndef QT_MAC_USE_COCOA
48
#include <Carbon/Carbon.h>
50
#include <private/qcocoatoolbardelegate_mac_p.h>
56
// namespace up the stuff
59
#define S "com.trolltech.qt-" S0(QT_NAMESPACE) ".qmainwindow.qtoolbarInHIToolbar"
60
#define SToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".hitoolbar-qtoolbar"
61
#define SNSToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".qtoolbarInNSToolbar"
62
#define MacToolbar "com.trolltech.qt-" S0(QT_NAMESPACE) ".qmainwindow.mactoolbar"
64
#ifndef QT_MAC_USE_COCOA
65
static CFStringRef kQToolBarHIToolbarItemClassID = CFSTR(S);
66
static CFStringRef kQToolBarHIToolbarIdentifier = CFSTR(SToolbar);
68
static NSString *kQToolBarNSToolbarIdentifier = @SNSToolbar;
70
static CFStringRef kQMainWindowMacToolbarID = CFSTR(MacToolbar);
79
#ifndef QT_MAC_USE_COCOA
80
static CFStringRef kQToolBarHIToolbarItemClassID = CFSTR("com.trolltech.qt.qmainwindow.qtoolbarInHIToolbar");
81
static CFStringRef kQToolBarHIToolbarIdentifier = CFSTR("com.trolltech.qt.hitoolbar-qtoolbar");
83
static NSString *kQToolBarNSToolbarIdentifier = @"com.trolltech.qt.qmainwindow.qtoolbarInNSToolbar";
85
static CFStringRef kQMainWindowMacToolbarID = CFSTR("com.trolltech.qt.qmainwindow.mactoolbar");
86
#endif // QT_NAMESPACE
88
#ifndef QT_MAC_USE_COCOA
90
static const int kEventParamQToolBar = 'QTBR';
91
static const int kEventParamQMainWindowLayout = 'QMWL';
93
const EventTypeSpec qtoolbarEvents[] =
95
{ kEventClassHIObject, kEventHIObjectConstruct },
96
{ kEventClassHIObject, kEventHIObjectDestruct },
97
{ kEventClassHIObject, kEventHIObjectInitialize },
98
{ kEventClassToolbarItem, kEventToolbarItemCreateCustomView }
101
struct QToolBarInHIToolbarInfo
103
QToolBarInHIToolbarInfo(HIToolbarItemRef item)
104
: toolbarItem(item), mainWindowLayout(0)
106
HIToolbarItemRef toolbarItem;
107
QMainWindowLayout *mainWindowLayout;
110
OSStatus QMainWindowLayout::qtoolbarInHIToolbarHandler(EventHandlerCallRef inCallRef,
111
EventRef event, void *data)
113
OSStatus result = eventNotHandledErr;
114
QToolBarInHIToolbarInfo *object = static_cast<QToolBarInHIToolbarInfo *>(data);
116
switch (GetEventClass(event)) {
117
case kEventClassHIObject:
118
switch (GetEventKind(event)) {
119
case kEventHIObjectConstruct:
121
HIObjectRef toolbarItem;
122
GetEventParameter(event, kEventParamHIObjectInstance, typeHIObjectRef,
123
0, sizeof( HIObjectRef ), 0, &toolbarItem);
125
QToolBarInHIToolbarInfo *item = new QToolBarInHIToolbarInfo(toolbarItem);
126
SetEventParameter(event, kEventParamHIObjectInstance, typeVoidPtr,
127
sizeof(void *), &item);
131
case kEventHIObjectInitialize:
132
result = CallNextEventHandler(inCallRef, event);
133
if (result == noErr) {
134
QToolBar *toolbar = 0;
135
QMainWindowLayout *layout = 0;
136
GetEventParameter(event, kEventParamQToolBar, typeVoidPtr,
137
0, sizeof(void *), 0, &toolbar);
138
GetEventParameter(event, kEventParamQMainWindowLayout, typeVoidPtr,
139
0, sizeof(void *), 0, &layout);
140
object->mainWindowLayout = layout;
141
object->mainWindowLayout->unifiedToolbarHash.insert(object->toolbarItem, toolbar);
142
HIToolbarItemChangeAttributes(object->toolbarItem,
143
kHIToolbarItemLabelDisabled, 0);
147
case kEventHIObjectDestruct:
154
case kEventClassToolbarItem:
155
switch (GetEventKind(event))
157
case kEventToolbarItemCreateCustomView:
160
= object->mainWindowLayout->unifiedToolbarHash.value(object->toolbarItem);
162
HIViewRef hiview = HIViewRef(toolbar->winId());
163
SetEventParameter(event, kEventParamControlRef, typeControlRef,
164
sizeof(HIViewRef), &hiview);
175
void QMainWindowLayout::qtMacHIToolbarRegisterQToolBarInHIToolborItemClass()
177
static bool registered = false;
180
HIObjectRegisterSubclass( kQToolBarHIToolbarItemClassID,
181
kHIToolbarItemClassID, 0, QMainWindowLayout::qtoolbarInHIToolbarHandler,
182
GetEventTypeCount(qtoolbarEvents), qtoolbarEvents, 0, 0 );
187
static void GetToolbarAllowedItems(CFMutableArrayRef array)
189
CFArrayAppendValue(array, kQToolBarHIToolbarIdentifier);
192
HIToolbarItemRef QMainWindowLayout::createQToolBarInHIToolbarItem(QToolBar *toolbar,
193
QMainWindowLayout *layout)
195
QMainWindowLayout::qtMacHIToolbarRegisterQToolBarInHIToolborItemClass();
198
HIToolbarItemRef result = 0;
200
CFStringRef identifier = kQToolBarHIToolbarIdentifier;
201
UInt32 options = kHIToolbarItemAllowDuplicates;
203
CreateEvent(0, kEventClassHIObject, kEventHIObjectInitialize,
204
GetCurrentEventTime(), 0, &event);
205
SetEventParameter(event, kEventParamToolbarItemIdentifier, typeCFStringRef,
206
sizeof(CFStringRef), &identifier);
207
SetEventParameter(event, kEventParamAttributes, typeUInt32, sizeof(UInt32), &options);
208
SetEventParameter(event, kEventParamQToolBar, typeVoidPtr, sizeof(void *), &toolbar);
209
SetEventParameter(event, kEventParamQMainWindowLayout, typeVoidPtr, sizeof(void *), &layout);
211
HIObjectCreate(kQToolBarHIToolbarItemClassID, event,
212
static_cast<HIObjectRef *>(&result));
219
HIToolbarItemRef QMainWindowLayout::CreateToolbarItemForIdentifier(CFStringRef identifier,
222
HIToolbarItemRef item = 0;
223
if (CFStringCompare(kQToolBarHIToolbarIdentifier, identifier,
224
kCFCompareBackwards) == kCFCompareEqualTo) {
225
if (data && CFGetTypeID(data) == CFArrayGetTypeID()) {
226
CFArrayRef array = static_cast<CFArrayRef>(data);
227
QToolBar *toolbar = static_cast<QToolBar *>(const_cast<void *>(CFArrayGetValueAtIndex(array, 0)));
228
QMainWindowLayout *layout = static_cast<QMainWindowLayout *>(const_cast<void *>(CFArrayGetValueAtIndex(array, 1)));
229
item = createQToolBarInHIToolbarItem(toolbar, layout);
235
static const EventTypeSpec kToolbarEvents[] = {
236
{ kEventClassToolbar, kEventToolbarGetDefaultIdentifiers },
237
{ kEventClassToolbar, kEventToolbarGetAllowedIdentifiers },
238
{ kEventClassToolbar, kEventToolbarCreateItemWithIdentifier },
239
{ kEventClassToolbar, kEventToolbarItemAdded },
240
{ kEventClassToolbar, kEventToolbarItemRemoved }
243
OSStatus QMainWindowLayout::qtmacToolbarDelegate(EventHandlerCallRef, EventRef event, void *data)
245
QMainWindowLayout *mainWindowLayout = static_cast<QMainWindowLayout *>(data);
246
OSStatus result = eventNotHandledErr;
247
CFMutableArrayRef array;
248
CFStringRef identifier;
249
switch (GetEventKind(event)) {
250
case kEventToolbarGetDefaultIdentifiers:
251
case kEventToolbarGetAllowedIdentifiers:
252
GetEventParameter(event, kEventParamMutableArray, typeCFMutableArrayRef, 0,
253
sizeof(CFMutableArrayRef), 0, &array);
254
GetToolbarAllowedItems(array);
257
case kEventToolbarCreateItemWithIdentifier: {
258
HIToolbarItemRef item;
260
OSStatus err = GetEventParameter(event, kEventParamToolbarItemIdentifier, typeCFStringRef,
261
0, sizeof(CFStringRef), 0, &identifier);
262
err = GetEventParameter(event, kEventParamToolbarItemConfigData, typeCFTypeRef,
263
0, sizeof(CFTypeRef), 0, &data);
264
item = CreateToolbarItemForIdentifier(identifier, data);
266
result = SetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
267
sizeof(HIToolbarItemRef), &item );
271
case kEventToolbarItemAdded: {
272
// Double check that our "view" of the toolbar is similar.
273
HIToolbarItemRef item;
275
if (GetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
276
0, sizeof(HIToolbarItemRef), 0, &item) == noErr
277
&& GetEventParameter(event, kEventParamIndex, typeCFIndex, 0,
278
sizeof(CFIndex), 0, &index) == noErr) {
279
CFRetain(item); // We will watch this until it's removed from the list (or bust).
280
mainWindowLayout->toolbarItemsCopy.insert(index, item);
281
QToolBar *toolbar = mainWindowLayout->unifiedToolbarHash.value(item);
283
int toolbarIndex = mainWindowLayout->qtoolbarsInUnifiedToolbarList.indexOf(toolbar);
284
if (index != toolbarIndex) {
285
// Dang, we must be out of sync, rebuild it from the "toolbarItemsCopy"
286
mainWindowLayout->qtoolbarsInUnifiedToolbarList.clear();
287
for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
288
// This will either append the correct toolbar or an
289
// null toolbar. This is fine because this list
290
// is really only kept to make sure that things are but in the right order.
291
mainWindowLayout->qtoolbarsInUnifiedToolbarList.append(
292
mainWindowLayout->unifiedToolbarHash.value(mainWindowLayout->
293
toolbarItemsCopy.at(i)));
300
case kEventToolbarItemRemoved: {
301
HIToolbarItemRef item;
302
if (GetEventParameter(event, kEventParamToolbarItem, typeHIToolbarItemRef,
303
0, sizeof(HIToolbarItemRef), 0, &item) == noErr) {
304
mainWindowLayout->unifiedToolbarHash.remove(item);
305
for (int i = 0; i < mainWindowLayout->toolbarItemsCopy.size(); ++i) {
306
if (mainWindowLayout->toolbarItemsCopy.at(i) == item) {
307
// I know about it, so release it.
308
mainWindowLayout->toolbarItemsCopy.removeAt(i);
309
mainWindowLayout->qtoolbarsInUnifiedToolbarList.removeAt(i);
320
#endif // ! QT_MAC_USE_COCOA
322
#ifndef kWindowUnifiedTitleAndToolbarAttribute
323
#define kWindowUnifiedTitleAndToolbarAttribute (1 << 7)
326
void QMainWindowLayout::updateHIToolBarStatus()
328
bool useMacToolbar = layoutState.mainWindow->unifiedTitleAndToolBarOnMac();
329
#ifndef QT_MAC_USE_COCOA
331
ChangeWindowAttributes(qt_mac_window_for(layoutState.mainWindow),
332
kWindowUnifiedTitleAndToolbarAttribute, 0);
334
ChangeWindowAttributes(qt_mac_window_for(layoutState.mainWindow),
335
0, kWindowUnifiedTitleAndToolbarAttribute);
339
layoutState.mainWindow->setUpdatesEnabled(false); // reduces a little bit of flicker, not all though
340
if (!useMacToolbar) {
341
macWindowToolbarShow(layoutState.mainWindow, false);
342
// Move everything out of the HIToolbar into the main toolbar.
343
while (!qtoolbarsInUnifiedToolbarList.isEmpty()) {
344
// Should shrink the list by one every time.
345
layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, qtoolbarsInUnifiedToolbarList.first());
347
macWindowToolbarSet(qt_mac_window_for(layoutState.mainWindow), 0);
349
QList<QToolBar *> toolbars = layoutState.mainWindow->findChildren<QToolBar *>();
350
for (int i = 0; i < toolbars.size(); ++i) {
351
QToolBar *toolbar = toolbars.at(i);
352
if (toolBarArea(toolbar) == Qt::TopToolBarArea) {
353
removeWidget(toolbar); // Do this here, because we are in an in-between state.
354
layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
357
syncUnifiedToolbarVisibility();
359
layoutState.mainWindow->setUpdatesEnabled(true);
362
void QMainWindowLayout::insertIntoMacToolbar(QToolBar *before, QToolBar *toolbar)
364
// This layering could go on to one more level, but I decided to stop here.
365
// The HIToolbar and NSToolbar APIs are fairly similar as you will see.
370
QToolBarLayout *toolbarLayout = static_cast<QToolBarLayout *>(toolbar->layout());
371
toolbarSaveState.insert(toolbar, ToolBarSaveState(toolbar->isMovable(),
372
toolbar->maximumSize()));
374
if (toolbarLayout->hasExpandFlag() == false)
375
toolbar->setMaximumSize(toolbar->sizeHint());
377
toolbar->setMovable(false);
378
toolbarLayout->setUsePopupMenu(true);
379
// Make the toolbar a child of the mainwindow to avoid creating a window.
380
toolbar->setParent(layoutState.mainWindow);
381
toolbar->createWinId(); // Now create the OSViewRef.
383
layoutState.mainWindow->createWinId();
385
OSWindowRef window = qt_mac_window_for(layoutState.mainWindow);
386
int beforeIndex = qtoolbarsInUnifiedToolbarList.indexOf(before);
387
if (beforeIndex == -1)
388
beforeIndex = qtoolbarsInUnifiedToolbarList.size();
390
int toolbarIndex = qtoolbarsInUnifiedToolbarList.indexOf(toolbar);
391
#ifndef QT_MAC_USE_COCOA
392
HIToolbarRef macToolbar = NULL;
393
if ((GetWindowToolbar(window, &macToolbar) == noErr) && !macToolbar) {
394
HIToolbarCreate(kQMainWindowMacToolbarID,
395
kHIToolbarItemAllowDuplicates, &macToolbar);
396
InstallEventHandler(HIObjectGetEventTarget(static_cast<HIToolbarRef>(macToolbar)),
397
QMainWindowLayout::qtmacToolbarDelegate, GetEventTypeCount(kToolbarEvents),
398
kToolbarEvents, this, 0);
399
HIToolbarSetDisplaySize(macToolbar, kHIToolbarDisplaySizeNormal);
400
HIToolbarSetDisplayMode(macToolbar, kHIToolbarDisplayModeIconOnly);
401
macWindowToolbarSet(window, macToolbar);
402
if (layoutState.mainWindow->isVisible())
403
macWindowToolbarShow(layoutState.mainWindow, true);
404
CFRelease(macToolbar);
407
QMacCocoaAutoReleasePool pool;
408
NSToolbar *macToolbar = [window toolbar];
409
if (macToolbar == nil) {
410
macToolbar = [[NSToolbar alloc] initWithIdentifier:(NSString *)kQMainWindowMacToolbarID];
411
[macToolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
412
[macToolbar setSizeMode:NSToolbarSizeModeRegular];
413
[macToolbar setDelegate:[[QCocoaToolBarDelegate alloc] initWithMainWindowLayout:this]];
414
[window setToolbar:macToolbar];
415
[macToolbar release];
418
if (toolbarIndex != -1) {
419
qtoolbarsInUnifiedToolbarList.removeAt(toolbarIndex);
420
#ifndef QT_MAC_USE_COCOA
421
HIToolbarRemoveItemAtIndex(macToolbar, toolbarIndex);
423
[macToolbar removeItemAtIndex:toolbarIndex];
426
qtoolbarsInUnifiedToolbarList.insert(beforeIndex, toolbar);
427
#ifndef QT_MAC_USE_COCOA
428
QCFType<HIToolbarItemRef> outItem;
429
const QObject *stupidArray[] = { toolbar, this };
430
QCFType<CFArrayRef> array = CFArrayCreate(0, reinterpret_cast<const void **>(&stupidArray),
432
HIToolbarCreateItemWithIdentifier(macToolbar, kQToolBarHIToolbarIdentifier,
434
HIToolbarInsertItemAtIndex(macToolbar, outItem, beforeIndex);
436
NSString *toolbarID = kQToolBarNSToolbarIdentifier;
437
toolbarID = [toolbarID stringByAppendingFormat:@"%p", toolbar];
438
cocoaItemIDToToolbarHash.insert(qt_mac_NSStringToQString(toolbarID), toolbar);
439
[macToolbar insertItemWithItemIdentifier:toolbarID atIndex:beforeIndex];
443
void QMainWindowLayout::removeFromMacToolbar(QToolBar *toolbar)
445
QHash<void *, QToolBar *>::iterator it = unifiedToolbarHash.begin();
446
while (it != unifiedToolbarHash.end()) {
447
if (it.value() == toolbar) {
448
// Rescue our HIView and set it on the mainWindow again.
449
bool saveVisible = !toolbar->isHidden();
450
toolbar->setParent(0);
451
toolbar->setParent(parentWidget());
452
toolbar->setVisible(saveVisible);
453
ToolBarSaveState saveState = toolbarSaveState.value(toolbar);
454
static_cast<QToolBarLayout *>(toolbar->layout())->setUsePopupMenu(false);
455
toolbar->setMovable(saveState.movable);
456
toolbar->setMaximumSize(saveState.maximumSize);
457
toolbarSaveState.remove(toolbar);
458
#ifndef QT_MAC_USE_COCOA
459
HIToolbarItemRef item = static_cast<HIToolbarItemRef>(it.key());
460
HIToolbarRemoveItemAtIndex(HIToolbarItemGetToolbar(item),
461
toolbarItemsCopy.indexOf(item));
463
NSToolbarItem *item = static_cast<NSToolbarItem *>(it.key());
464
[[qt_mac_window_for(layoutState.mainWindow->window()) toolbar]
465
removeItemAtIndex:toolbarItemsCopy.indexOf(item)];
466
// In Carbon this hash and list gets emptied via events. In Cocoa, we have to do it ourselves here.
467
it = unifiedToolbarHash.erase(it);
468
qtoolbarsInUnifiedToolbarList.removeAll(toolbar);
476
void QMainWindowLayout::cleanUpMacToolbarItems()
478
for (int i = 0; i < toolbarItemsCopy.size(); ++i)
479
CFRelease(toolbarItemsCopy.at(i));
480
toolbarItemsCopy.clear();
481
unifiedToolbarHash.clear();
484
void QMainWindowLayout::fixSizeInUnifiedToolbar(QToolBar *tb) const
486
#ifdef QT_MAC_USE_COCOA
487
QHash<void *, QToolBar *>::const_iterator it = unifiedToolbarHash.constBegin();
488
NSToolbarItem *item = nil;
489
while (it != unifiedToolbarHash.constEnd()) {
490
if (tb == it.value()) {
491
item = static_cast<NSToolbarItem *>(it.key());
497
QMacCocoaAutoReleasePool pool;
498
QWidgetItem layoutItem(tb);
499
QSize size = layoutItem.maximumSize();
500
NSSize nssize = NSMakeSize(size.width(), size.height() - 2);
501
[item setMaxSize:nssize];
502
size = layoutItem.minimumSize();
503
nssize.width = size.width();
504
nssize.height = size.height() - 2;
505
[item setMinSize:nssize];
512
void QMainWindowLayout::syncUnifiedToolbarVisibility()
514
if (blockVisiblityCheck)
517
Q_ASSERT(layoutState.mainWindow->unifiedTitleAndToolBarOnMac());
519
const int ToolBarCount = qtoolbarsInUnifiedToolbarList.count();
520
for (int i = 0; i < ToolBarCount; ++i) {
521
if (qtoolbarsInUnifiedToolbarList.at(i)->isVisible()) {
526
macWindowToolbarShow(layoutState.mainWindow, show);