55 // directly into qcocoawindow_mac_p.h and qcocoapanel_mac_p.h |
55 // directly into qcocoawindow_mac_p.h and qcocoapanel_mac_p.h |
56 |
56 |
57 QT_BEGIN_NAMESPACE |
57 QT_BEGIN_NAMESPACE |
58 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm |
58 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm |
59 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp |
59 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp |
|
60 extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp |
|
61 |
|
62 Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget); |
|
63 |
60 QT_END_NAMESPACE |
64 QT_END_NAMESPACE |
|
65 |
|
66 - (id)initWithContentRect:(NSRect)contentRect |
|
67 styleMask:(NSUInteger)windowStyle |
|
68 backing:(NSBackingStoreType)bufferingType |
|
69 defer:(BOOL)deferCreation |
|
70 { |
|
71 self = [super initWithContentRect:contentRect styleMask:windowStyle |
|
72 backing:bufferingType defer:deferCreation]; |
|
73 if (self) { |
|
74 currentCustomDragTypes = 0; |
|
75 } |
|
76 return self; |
|
77 } |
|
78 |
|
79 - (void)dealloc |
|
80 { |
|
81 delete currentCustomDragTypes; |
|
82 [super dealloc]; |
|
83 } |
61 |
84 |
62 - (BOOL)canBecomeKeyWindow |
85 - (BOOL)canBecomeKeyWindow |
63 { |
86 { |
64 QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; |
87 QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; |
65 |
88 |
66 bool isToolTip = (widget->windowType() == Qt::ToolTip); |
89 bool isToolTip = (widget->windowType() == Qt::ToolTip); |
67 bool isPopup = (widget->windowType() == Qt::Popup); |
90 bool isPopup = (widget->windowType() == Qt::Popup); |
68 return !(isPopup || isToolTip); |
91 return !(isPopup || isToolTip); |
69 } |
92 } |
70 |
93 |
|
94 - (BOOL)canBecomeMainWindow |
|
95 { |
|
96 QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; |
|
97 |
|
98 bool isToolTip = (widget->windowType() == Qt::ToolTip); |
|
99 bool isPopup = (widget->windowType() == Qt::Popup); |
|
100 bool isTool = (widget->windowType() == Qt::Tool); |
|
101 return !(isPopup || isToolTip || isTool); |
|
102 } |
|
103 |
|
104 - (void)becomeMainWindow |
|
105 { |
|
106 [super becomeMainWindow]; |
|
107 // Cocoa sometimes tell a hidden window to become the |
|
108 // main window (and as such, show it). This can e.g |
|
109 // happend when the application gets activated. If |
|
110 // this is the case, we tell it to hide again: |
|
111 if (![self isVisible]) |
|
112 [self orderOut:self]; |
|
113 } |
|
114 |
71 - (void)toggleToolbarShown:(id)sender |
115 - (void)toggleToolbarShown:(id)sender |
72 { |
116 { |
73 macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
117 macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
74 [super toggleToolbarShown:sender]; |
118 [super toggleToolbarShown:sender]; |
75 } |
119 } |
76 |
120 |
77 /* |
|
78 The methods keyDown, keyUp, and flagsChanged... These really shouldn't ever |
|
79 get hit. We automatically say we can be first responder if we are a window. |
|
80 So, the handling should get handled by the view. This is here more as a |
|
81 last resort (i.e., this is code that can potentially be removed). |
|
82 */ |
|
83 - (void)keyDown:(NSEvent *)theEvent |
|
84 { |
|
85 bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
|
86 if (!keyOK) |
|
87 [super keyDown:theEvent]; |
|
88 } |
|
89 |
|
90 - (void)keyUp:(NSEvent *)theEvent |
|
91 { |
|
92 bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
|
93 if (!keyOK) |
|
94 [super keyUp:theEvent]; |
|
95 } |
|
96 |
|
97 - (void)flagsChanged:(NSEvent *)theEvent |
121 - (void)flagsChanged:(NSEvent *)theEvent |
98 { |
122 { |
99 qt_dispatchModifiersChanged(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
123 qt_dispatchModifiersChanged(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); |
100 [super flagsChanged:theEvent]; |
124 [super flagsChanged:theEvent]; |
101 } |
125 } |
104 - (void)tabletProximity:(NSEvent *)tabletEvent |
128 - (void)tabletProximity:(NSEvent *)tabletEvent |
105 { |
129 { |
106 qt_dispatchTabletProximityEvent(tabletEvent); |
130 qt_dispatchTabletProximityEvent(tabletEvent); |
107 } |
131 } |
108 |
132 |
|
133 - (void)qtDispatcherToQAction:(id)sender |
|
134 { |
|
135 // If this window is modal, the menu bar will be modally shaddowed. |
|
136 // In that case, since the window will be in the first responder chain, |
|
137 // we can still catch the trigger here and forward it to the menu bar. |
|
138 // This is needed as a single modal dialog on Qt should be able to access |
|
139 // the application menu (e.g. quit). |
|
140 [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender]; |
|
141 } |
|
142 |
|
143 - (void)terminate:(id)sender |
|
144 { |
|
145 // This function is called from the quit item in the menubar when this window |
|
146 // is in the first responder chain (see also qtDispatcherToQAction above) |
|
147 [NSApp terminate:sender]; |
|
148 } |
|
149 |
109 - (void)sendEvent:(NSEvent *)event |
150 - (void)sendEvent:(NSEvent *)event |
110 { |
151 { |
|
152 if ([event type] == NSApplicationDefined) { |
|
153 switch ([event subtype]) { |
|
154 case QtCocoaEventSubTypePostMessage: |
|
155 [NSApp qt_sendPostedMessage:event]; |
|
156 return; |
|
157 default: |
|
158 break; |
|
159 } |
|
160 return; |
|
161 } |
|
162 |
111 QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; |
163 QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; |
112 |
|
113 // Cocoa can hold onto the window after we've disavowed its knowledge. So, |
164 // Cocoa can hold onto the window after we've disavowed its knowledge. So, |
114 // if we get sent an event afterwards just have it go through the super's |
165 // if we get sent an event afterwards just have it go through the super's |
115 // version and don't do any stuff with Qt. |
166 // version and don't do any stuff with Qt. |
116 if (!widget) { |
167 if (!widget) { |
117 [super sendEvent:event]; |
168 [super sendEvent:event]; |
186 if (styleMask & QtMacCustomizeWindow) |
237 if (styleMask & QtMacCustomizeWindow) |
187 return [QT_MANGLE_NAMESPACE(QCocoaWindowCustomThemeFrame) class]; |
238 return [QT_MANGLE_NAMESPACE(QCocoaWindowCustomThemeFrame) class]; |
188 return [super frameViewClassForStyleMask:styleMask]; |
239 return [super frameViewClassForStyleMask:styleMask]; |
189 } |
240 } |
190 |
241 |
|
242 -(void)registerDragTypes |
|
243 { |
|
244 // Calling registerForDraggedTypes below is slow, so only do |
|
245 // it once for each window, or when the custom types change. |
|
246 QMacCocoaAutoReleasePool pool; |
|
247 const QStringList& customTypes = qEnabledDraggedTypes(); |
|
248 if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) { |
|
249 if (currentCustomDragTypes == 0) |
|
250 currentCustomDragTypes = new QStringList(); |
|
251 *currentCustomDragTypes = customTypes; |
|
252 const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; |
|
253 NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, |
|
254 NSFilenamesPboardType, NSStringPboardType, |
|
255 NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, |
|
256 NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, |
|
257 NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, |
|
258 NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, |
|
259 NSURLPboardType, NSPDFPboardType, NSVCardPboardType, |
|
260 NSFilesPromisePboardType, NSInkTextPboardType, |
|
261 NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; |
|
262 // Add custom types supported by the application. |
|
263 for (int i = 0; i < customTypes.size(); i++) { |
|
264 [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))]; |
|
265 } |
|
266 [self registerForDraggedTypes:supportedTypes]; |
|
267 } |
|
268 } |
|
269 |
|
270 - (QWidget *)dragTargetHitTest:(id <NSDraggingInfo>)sender |
|
271 { |
|
272 // Do a hittest to find the NSView under the |
|
273 // mouse, and return the corresponding QWidget: |
|
274 NSPoint windowPoint = [sender draggingLocation]; |
|
275 NSView *candidateView = [[self contentView] hitTest:windowPoint]; |
|
276 if (![candidateView isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) |
|
277 return 0; |
|
278 return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(candidateView) qt_qwidget]; |
|
279 } |
|
280 |
|
281 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender |
|
282 { |
|
283 // The user dragged something into the window. Send a draggingEntered message |
|
284 // to the QWidget under the mouse. As the drag moves over the window, and over |
|
285 // different widgets, we will handle enter and leave events from within |
|
286 // draggingUpdated below. The reason why we handle this ourselves rather than |
|
287 // subscribing for drag events directly in QCocoaView is that calling |
|
288 // registerForDraggedTypes on the views will severly degrade initialization time |
|
289 // for an application that uses a lot of drag subscribing widgets. |
|
290 |
|
291 QWidget *target = [self dragTargetHitTest:sender]; |
|
292 if (!target) |
|
293 return [super draggingEntered:sender]; |
|
294 if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) |
|
295 return NSDragOperationNone; |
|
296 |
|
297 *currentDragTarget() = target; |
|
298 return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender]; |
|
299 } |
|
300 |
|
301 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender |
|
302 { |
|
303 QWidget *target = [self dragTargetHitTest:sender]; |
|
304 if (!target) |
|
305 return [super draggingUpdated:sender]; |
|
306 |
|
307 if (target == *currentDragTarget()) { |
|
308 // The drag continues to move over the widget that we have sendt |
|
309 // a draggingEntered message to. So just update the view: |
|
310 return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingUpdated:sender]; |
|
311 } else { |
|
312 // The widget under the mouse has changed. |
|
313 // So we need to fake enter/leave events: |
|
314 if (*currentDragTarget()) |
|
315 [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender]; |
|
316 if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) { |
|
317 *currentDragTarget() = 0; |
|
318 return NSDragOperationNone; |
|
319 } |
|
320 *currentDragTarget() = target; |
|
321 return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender]; |
|
322 } |
|
323 } |
|
324 |
|
325 - (void)draggingExited:(id < NSDraggingInfo >)sender |
|
326 { |
|
327 QWidget *target = [self dragTargetHitTest:sender]; |
|
328 if (!target) |
|
329 return [super draggingExited:sender]; |
|
330 |
|
331 if (*currentDragTarget()) { |
|
332 [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender]; |
|
333 *currentDragTarget() = 0; |
|
334 } |
|
335 } |
|
336 |
|
337 - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender |
|
338 { |
|
339 QWidget *target = [self dragTargetHitTest:sender]; |
|
340 if (!target) |
|
341 return [super performDragOperation:sender]; |
|
342 |
|
343 BOOL dropResult = NO; |
|
344 if (*currentDragTarget()) { |
|
345 dropResult = [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) performDragOperation:sender]; |
|
346 *currentDragTarget() = 0; |
|
347 } |
|
348 return dropResult; |
|
349 } |
|
350 |
191 - (void)displayIfNeeded |
351 - (void)displayIfNeeded |
192 { |
352 { |
193 |
353 |
194 QWidget *qwidget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; |
354 QWidget *qwidget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; |
195 if (qwidget == 0) { |
355 if (qwidget == 0) { |
202 bs->sync(qwidget, qwidget->rect()); |
362 bs->sync(qwidget, qwidget->rect()); |
203 } |
363 } |
204 [super displayIfNeeded]; |
364 [super displayIfNeeded]; |
205 } |
365 } |
206 |
366 |
207 |
367 // This is a hack and it should be removed once we find the real cause for |
|
368 // the painting problems. |
|
369 // We have a static variable that signals if we have been called before or not. |
|
370 static bool firstDrawingInvocation = true; |
|
371 |
|
372 // The method below exists only as a workaround to draw/not draw the baseline |
|
373 // in the title bar. This is to support unifiedToolbar look. |
|
374 |
|
375 // This method is very special. To begin with, it is a |
|
376 // method that will get called only if we enable documentMode. |
|
377 // Furthermore, it won't get called as a normal method, we swap |
|
378 // this method with the normal implementation of drawRect in |
|
379 // _NSThemeFrame. When this method is active, its mission is to |
|
380 // first call the original drawRect implementation so the widget |
|
381 // gets proper painting. After that, it needs to detect if there |
|
382 // is a toolbar or not, in order to decide how to handle the unified |
|
383 // look. The distinction is important since the presence and |
|
384 // visibility of a toolbar change the way we enter into unified mode. |
|
385 // When there is a toolbar and that toolbar is visible, the problem |
|
386 // is as simple as to tell the toolbar not to draw its baseline. |
|
387 // However when there is not toolbar or the toolbar is not visible, |
|
388 // we need to draw a line on top of the baseline, because the baseline |
|
389 // in that case will belong to the title. For this case we need to draw |
|
390 // a line on top of the baseline. |
|
391 // As usual, there is a special case. When we first are called, we might |
|
392 // need to repaint ourselves one more time. We only need that if we |
|
393 // didn't get the activation, i.e. when we are launched via the command |
|
394 // line. And this only if the toolbar is visible from the beginning, |
|
395 // so we have a special flag that signals if we need to repaint or not. |
|
396 - (void)drawRectSpecial:(NSRect)rect |
|
397 { |
|
398 // Call the original drawing method. |
|
399 [self drawRectOriginal:rect]; |
|
400 NSWindow *window = [self window]; |
|
401 NSToolbar *toolbar = [window toolbar]; |
|
402 if(!toolbar) { |
|
403 // There is no toolbar, we have to draw a line on top of the line drawn by Cocoa. |
|
404 macDrawRectOnTop((void *)window); |
|
405 } else { |
|
406 if([toolbar isVisible]) { |
|
407 // We tell Cocoa to avoid drawing the line at the end. |
|
408 if(firstDrawingInvocation) { |
|
409 firstDrawingInvocation = false; |
|
410 macSyncDrawingOnFirstInvocation((void *)window); |
|
411 } else |
|
412 [toolbar setShowsBaselineSeparator:NO]; |
|
413 } else { |
|
414 // There is a toolbar but it is not visible so |
|
415 // we have to draw a line on top of the line drawn by Cocoa. |
|
416 macDrawRectOnTop((void *)window); |
|
417 } |
|
418 } |
|
419 } |