Logo ROOT  
Reference Guide
QuartzWindow.mm
Go to the documentation of this file.
1// @(#)root/graf2d:$Id$
2// Author: Timur Pocheptsov 16/02/2012
3
4/*************************************************************************
5 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//#define DEBUG_ROOT_COCOA
13
14//#define NDEBUG
15
16#ifdef DEBUG_ROOT_COCOA
17#include <iostream>
18#include <fstream>
19
20#include "TClass.h"
21#endif
22
23#include <algorithm>
24#include <stdexcept>
25#include <cassert>
26#include <vector>
27
28#include <Availability.h>
29
30#include "ROOTOpenGLView.h"
31#include "CocoaConstants.h"
32#include "QuartzWindow.h"
33#include "QuartzPixmap.h"
34#include "QuartzUtils.h"
35#include "CocoaUtils.h"
36#include "RConfigure.h"
37#include "X11Colors.h"
38#include "X11Buffer.h"
39#include "TGWindow.h"
40#include "TGClient.h"
41#include "TSystem.h"
42#include "TGCocoa.h"
43#include "TROOT.h"
44#include "TGTextView.h"
45#include "TGView.h"
46#include "TGCanvas.h"
47
48
49namespace ROOT {
50namespace MacOSX {
51namespace X11 {
52
53#pragma mark - Create a window or a view.
54
55//______________________________________________________________________________
57 UInt_t clss, void */*visual*/, SetWindowAttributes_t *attr, UInt_t)
58{
59 using namespace Details;
60
61 NSRect winRect = {};
62 winRect.origin.x = GlobalXROOTToCocoa(x);
63 winRect.origin.y = GlobalYROOTToCocoa(y + h);
64 winRect.size.width = w;
65 winRect.size.height = h;
66
67 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
69
70 QuartzWindow * const newWindow = [[QuartzWindow alloc] initWithContentRect : winRect
71 styleMask : styleMask
72 backing : NSBackingStoreBuffered
73 defer : YES
74 windowAttributes : attr];
75 if (!newWindow)
76 throw std::runtime_error("CreateTopLevelWindow failed");
77
78 newWindow.fDepth = depth;
79 newWindow.fClass = clss;
80
81 return newWindow;
82}
83
84//______________________________________________________________________________
85QuartzView *CreateChildView(QuartzView * /*parent*/, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t /*depth*/,
86 UInt_t /*clss*/, void * /*visual*/, SetWindowAttributes_t *attr, UInt_t /*wtype*/)
87{
88 NSRect viewRect = {};
89 viewRect.origin.x = x;
90 viewRect.origin.y = y;
91 viewRect.size.width = w;
92 viewRect.size.height = h;
93
94 QuartzView * const view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
95 if (!view)
96 throw std::runtime_error("CreateChildView failed");
97
98 return view;
99}
100
101#pragma mark - root window (does not really exist, it's our desktop built of all screens).
102
103//______________________________________________________________________________
105{
106 //'root' window does not exist, but we can request its attributes.
107 assert(attr != 0 && "GetRootWindowAttributes, parameter 'attr' is null");
108
109
110 NSArray * const screens = [NSScreen screens];
111 assert(screens != nil && "screens array is nil");
112 NSScreen * const mainScreen = [screens objectAtIndex : 0];
113 assert(mainScreen != nil && "screen with index 0 is nil");
114
115 *attr = WindowAttributes_t();
116
117 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
118 "GetRootWindowAttributes, gVirtualX is either null or has a wrong type");
119
120 TGCocoa * const gCocoa = static_cast<TGCocoa *>(gVirtualX);
121
122 const Rectangle &frame = gCocoa->GetDisplayGeometry();
123
124 attr->fX = 0;
125 attr->fY = 0;
126 attr->fWidth = frame.fWidth;
127 attr->fHeight = frame.fHeight;
128 attr->fBorderWidth = 0;
129 attr->fYourEventMask = 0;
130 attr->fAllEventMasks = 0;//???
131
132 attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
133 attr->fVisual = 0;
134 attr->fRoot = 0;
135}
136
137
138#pragma mark - Coordinate conversions.
139
140//______________________________________________________________________________
141NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
142{
143 assert(window != nil && "ConvertPointFromBaseToScreen, parameter 'window' is nil");
144
145 //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
146 //point conversion seems to produce wrong results with HiDPI.
147
148 NSRect tmpRect = {};
149 tmpRect.origin = windowPoint;
150 tmpRect.size = NSMakeSize(1., 1.);//This is strange size :) But if they require rect, 0,0 - will not work?
151 tmpRect = [window convertRectToScreen : tmpRect];
152
153 return tmpRect.origin;
154}
155
156//______________________________________________________________________________
157NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
158{
159 assert(window != nil && "ConvertPointFromScreenToBase, parameter 'window' is nil");
160
161 //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
162 //point conversion seems to produce wrong results with HiDPI.
163
164 NSRect tmpRect = {};
165 tmpRect.origin = screenPoint;
166 tmpRect.size = NSMakeSize(1., 1.);
167 tmpRect = [window convertRectFromScreen : tmpRect];
168
169 return tmpRect.origin;
170}
171
172//______________________________________________________________________________
173int GlobalYCocoaToROOT(CGFloat yCocoa)
174{
175 //We can have several physical displays and thus several NSScreens in some arbitrary order.
176 //With Cocoa, some screens can have negative coordinates - to the left ro down to the primary
177 //screen (whatever it means). With X11 (XQuartz) though it's always 0,0.
178
179 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
180 "GlobalYCocoaToROOT, gVirtualX is either nul or has a wrong type");
181
182 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
183
184 return int(frame.fHeight - (yCocoa - frame.fY));
185}
186
187//______________________________________________________________________________
188int GlobalXCocoaToROOT(CGFloat xCocoa)
189{
190 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
191 "GlobalXCocoaToROOT, gVirtualX is either nul or has a wrong type");
192 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
193 //With X11 coordinate space always starts from 0, 0
194 return int(xCocoa - frame.fX);
195}
196
197//______________________________________________________________________________
198int GlobalYROOTToCocoa(CGFloat yROOT)
199{
200 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
201 "GlobalYROOTToCocoa, gVirtualX is either nul or has a wrong type");
202 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
203
204 return int(frame.fY + (frame.fHeight - yROOT));
205}
206
207//______________________________________________________________________________
208int GlobalXROOTToCocoa(CGFloat xROOT)
209{
210 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
211 "GlobalXROOTToCocoa, gVirtualX is either nul or has a wrong type");
212 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
213 //With X11 coordinate space always starts from 0, 0
214 return int(frame.fX + xROOT);
215}
216
217//______________________________________________________________________________
218int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
219{
220 assert(parentView != nil && "LocalYCocoaToROOT, parent view is nil");
221
222 return int(parentView.frame.size.height - yCocoa);
223}
224
225//______________________________________________________________________________
226int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
227{
228 //:)
229 assert(parentView != nil && "LocalYROOTToCocoa, parent view is nil");
230
231 return int(parentView.frame.size.height - yROOT);
232}
233
234
235//______________________________________________________________________________
236int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
237{
238 //:)
239 assert(drawable != nil && "LocalYROOTToCocoa, drawable is nil");
240
241 return int(drawable.fHeight - yROOT);
242}
243
244//______________________________________________________________________________
245NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
246{
247 assert(from != nil && "TranslateToScreen, parameter 'from' is nil");
248
249 const NSPoint winPoint = [from convertPoint : point toView : nil];
250
251 NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], winPoint);
252 screenPoint.x = GlobalXCocoaToROOT(screenPoint.x);
253 screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);
254
255 return screenPoint;
256}
257
258//______________________________________________________________________________
259NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
260{
261 assert(to != nil && "TranslateFromScreen, parameter 'to' is nil");
262
263 point.x = GlobalXROOTToCocoa(point.x);
264 point.y = GlobalYROOTToCocoa(point.y);
265 point = ConvertPointFromScreenToBase(point, [to window]);
266
267 return [to convertPoint : point fromView : nil];
268}
269
270//______________________________________________________________________________
271NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
272{
273 //Both views are valid.
274 assert(from != nil && "TranslateCoordinates, parameter 'from' is nil");
275 assert(to != nil && "TranslateCoordinates, parameter 'to' is nil");
276
277 if ([from window] == [to window]) {
278 //Both views are in the same window.
279 return [to convertPoint : sourcePoint fromView : from];
280 } else {
281 //May be, I can do it in one call, but it's not obvious for me
282 //what is 'pixel aligned backing store coordinates' and
283 //if they are the same as screen coordinates.
284
285 //Many thanks to Apple for deprecated functions!!!
286
287 const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
288 const NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], win1Point);
289 const NSPoint win2Point = ConvertPointFromScreenToBase(screenPoint, [to window]);
290
291 return [to convertPoint : win2Point fromView : nil];
292 }
293}
294
295//______________________________________________________________________________
297{
298 assert(view != nil && "ScreenPointIsInView, parameter 'view' is nil");
299
300 NSPoint point = {};
301 point.x = x, point.y = y;
302 point = TranslateFromScreen(point, view);
303 const NSRect viewFrame = view.frame;
304
305 if (point.x < 0 || point.x > viewFrame.size.width)
306 return false;
307 if (point.y < 0 || point.y > viewFrame.size.height)
308 return false;
309
310 return true;
311}
312
313#pragma mark - Different FindView/Window functions iterating on the ROOT's windows/views.
314
315//______________________________________________________________________________
317{
318 //array's counter is increased, all object in array are also retained.
319 const Util::AutoreleasePool pool;
320
321 NSArray * const orderedWindows = [NSApp orderedWindows];
322 for (NSWindow *window in orderedWindows) {
323 if (![window isKindOfClass : [QuartzWindow class]])
324 continue;
325 QuartzWindow * const qw = (QuartzWindow *)window;
326 if (qw.fIsDeleted)//Because of reference counting this can happen.
327 continue;
328 //Check if point is inside.
330 return qw;
331 }
332
333 return nil;
334}
335
336//______________________________________________________________________________
338 Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
339{
340 assert(children != nil && "FindDNDAwareViewInPoint, parameter 'children' is nil");
341
342 if (maxDepth <= 0)
343 return nil;
344
345 NSEnumerator * const reverseEnumerator = [children reverseObjectEnumerator];
346 for (NSView<X11Window> *child in reverseEnumerator) {
347 if (!ScreenPointIsInView(child, x, y))
348 continue;
349 if (child.fIsDNDAware && child.fID != dragWinID && child.fID != inputWinID)
350 return child;//got it!
351
352 NSView<X11Window> * const testView = FindDNDAwareViewInPoint([child subviews], dragWinID,
353 inputWinID, x, y, maxDepth - 1);
354 if (testView)
355 return testView;
356 }
357
358 return nil;
359}
360
361//______________________________________________________________________________
363 Int_t x, Int_t y, Int_t maxDepth)
364{
365 //X and Y are ROOT's screen coordinates (Y is inverted).
366 if (maxDepth <= 0)
367 return nil;
368
369 const Util::AutoreleasePool pool;
370
371 if (!parentView) {//Start from the screen as a 'root' window.
372 NSArray * const orderedWindows = [NSApp orderedWindows];
373 for (NSWindow *window in orderedWindows) {
374 if (![window isKindOfClass : [QuartzWindow class]])
375 continue;
376 QuartzWindow * const qw = (QuartzWindow *)window;
377
378 if (qw.fIsDeleted)//Because of reference counting this can happen.
379 continue;
380
381 if (qw.fMapState != kIsViewable)
382 continue;
383
384 //First, check this view itself, my be we found what we need already.
385 NSView<X11Window> *testView = qw.fContentView;
386 if (!ScreenPointIsInView(testView, x, y))
387 continue;
388
389 if (testView.fIsDNDAware && testView.fID != dragWinID && testView.fID != inputWinID)
390 return testView;
391
392 //Recursive part, check children.
393 NSArray * const children = [testView subviews];
394 testView = FindDNDAwareViewInPoint(children, dragWinID, inputWinID, x, y, maxDepth - 1);
395 if (testView)
396 return testView;
397 }
398
399 //We did not find anything for 'root' window as parent.
400 return nil;
401 } else {
402 //Parent view is tested already (or should not be tested at all, check children.
403 return FindDNDAwareViewInPoint([parentView subviews], dragWinID, inputWinID, x, y, maxDepth);
404 }
405}
406
407//______________________________________________________________________________
409{
410 const Util::AutoreleasePool pool;
411
412 NSArray * const orderedWindows = [NSApp orderedWindows];
413 for (NSWindow *nsWindow in orderedWindows) {
414 if (![nsWindow isKindOfClass : [QuartzWindow class]])
415 continue;
416
417 QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
418
419 if (qWindow.fIsDeleted)//Because of reference counting this can happen.
420 continue;
421
422 if (qWindow.fMapState != kIsViewable)//Can it be false and still in this array???
423 continue;
424
425 const NSPoint mousePosition = [qWindow mouseLocationOutsideOfEventStream];
426 const NSSize windowSize = qWindow.frame.size;
427 if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
428 mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
429 return qWindow;
430 }
431
432 return nil;
433}
434
435//______________________________________________________________________________
437{
438 const Util::AutoreleasePool pool;
439
440 if (QuartzWindow *topLevel = FindWindowUnderPointer()) {
441 const NSPoint mousePosition = [topLevel mouseLocationOutsideOfEventStream];
442 return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
443 }
444
445 return nil;
446}
447
448//______________________________________________________________________________
450{
451 //FindWindowForPointerEvent is required because due to grabs
452 //the receiver of the event can be different from the actual
453 //window under cursor.
454
455 assert(pointerEvent != nil &&
456 "FindWindowForPointerEvent, parameter 'pointerEvent' is nil");
457
458 const Util::AutoreleasePool pool;
459
460 NSArray * const orderedWindows = [NSApp orderedWindows];
461 for (NSWindow *nsWindow in orderedWindows) {
462 if (![nsWindow isKindOfClass : [QuartzWindow class]])
463 continue;
464
465 QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
466
467 if (qWindow.fIsDeleted)//Because of reference counting this can happen.
468 continue;
469
470 //Can it be false and still in this array???
471 if (qWindow.fMapState != kIsViewable)
472 continue;
473
474 NSPoint mousePosition = [pointerEvent locationInWindow];
475 //The event has a window, so position is in this window's coordinate system,
476 //convert it into screen point first.
477 if ([pointerEvent window]) {
478 //convertBaseToScreen is deprecated.
479 //mousePosition = [[pointerEvent window] convertBaseToScreen : mousePosition];
480 mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
481 }
482
483 //convertScreenToBase is deprecated.
484 //mousePosition = [qWindow convertScreenToBase : mousePosition];
485 mousePosition = ConvertPointFromScreenToBase(mousePosition, qWindow);
486
487 const NSSize windowSize = qWindow.frame.size;
488 if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
489 mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
490 return qWindow;
491 }
492
493 return nil;
494}
495
496//______________________________________________________________________________
498{
499 //FindViewForPointerEvent is required because of grabs - the receiver of the
500 //event can be different from the actual window under cursor.
501
502 assert(pointerEvent != nil &&
503 "FindViewForPointerEvent, parameter 'pointerEvent' is nil");
504
505 const Util::AutoreleasePool pool;
506
507 if (QuartzWindow *topLevel = FindWindowForPointerEvent(pointerEvent)) {
508 NSPoint mousePosition = [pointerEvent locationInWindow];
509 if ([pointerEvent window])
510 mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
511
512 //convertScreenToBase is deprecated.
513 //mousePosition = [topLevel convertScreenToBase : mousePosition];
514 mousePosition = ConvertPointFromScreenToBase(mousePosition, topLevel);
515
516 return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
517 }
518
519 return nil;
520}
521
522#pragma mark - Downscale image ("reading color bits" on retina macs).
523
524//Hoho, we support C++11?? Let's return by value then!!!
525std::vector<unsigned char> DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
526{
527 assert(w != 0 && h != 0 && "DownscaledImageData, invalid geometry");
528 assert(image != nullptr && "DonwscaledImageData, invalid parameter 'image'");
529
530 std::vector<unsigned char> result;
531 try {
532 result.resize(w * h * 4);
533 } catch (const std::bad_alloc &) {
534 NSLog(@"DownscaledImageData, memory allocation failed");
535 return result;
536 }
537
538 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());//[1]
539 if (!colorSpace.Get()) {
540 NSLog(@"DownscaledImageData, CGColorSpaceCreateDeviceRGB failed");
541 return result;
542 }
543
544 Util::CFScopeGuard<CGContextRef> ctx(CGBitmapContextCreateWithData(&result[0], w, h, 8,
545 w * 4, colorSpace.Get(),
546 kCGImageAlphaPremultipliedLast, NULL, 0));
547 if (!ctx.Get()) {
548 NSLog(@"DownscaledImageData, CGBitmapContextCreateWithData failed");
549 return result;
550 }
551
552 CGContextDrawImage(ctx.Get(), CGRectMake(0, 0, w, h), image);
553
554 return result;
555}
556
557#pragma mark - "Focus management" - just make another window key window.
558
559//______________________________________________________________________________
561{
562 //XQuartz (and other X11
563 if (![NSApp isActive])
564 return;
565
566 const Util::AutoreleasePool pool;
567
568 NSArray * const orderedWindows = [NSApp orderedWindows];
569 for (NSWindow *nsWindow in orderedWindows) {
570 if (![nsWindow isKindOfClass : [QuartzWindow class]])
571 continue;
572
573 QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
574
575 if (qWindow.fIsDeleted || qWindow.fMapState != kIsViewable || qWindow.fID == winID)
576 continue;
577
579 continue;
580
581 [qWindow makeKeyAndOrderFront : qWindow];
582 break;
583 }
584}
585
586#pragma mark - 'shape mask' - to create a window with arbitrary (probably non-rectangle) shape.
587
588//______________________________________________________________________________
589void ClipToShapeMask(NSView<X11Window> *view, CGContextRef ctx)
590{
591 assert(view != nil && "ClipToShapeMask, parameter 'view' is nil");
592 assert(ctx != 0 && "ClipToShapeMask, parameter 'ctx' is null");
593
594 QuartzWindow * const topLevelParent = view.fQuartzWindow;
595 assert(topLevelParent.fShapeCombineMask != nil &&
596 "ClipToShapeMask, fShapeCombineMask is nil on a top-level window");
597 assert(topLevelParent.fShapeCombineMask.fImage != 0 &&
598 "ClipToShapeMask, shape mask is null");
599
600 //Important: shape mask should have the same width and height as
601 //a top-level window. In ROOT it does not :( Say hello to visual artifacts.
602
603 //Attach clip mask to the context.
604 if (!view.fParentView) {
605 //'view' is a top-level view.
606 const CGRect clipRect = CGRectMake(0, 0, topLevelParent.fShapeCombineMask.fWidth,
607 topLevelParent.fShapeCombineMask.fHeight);
608 CGContextClipToMask(ctx, clipRect, topLevelParent.fShapeCombineMask.fImage);
609 } else {
610 NSRect clipRect = view.frame;
611 //More complex case: 'self' is a child view, we have to create a subimage from shape mask.
612 clipRect.origin = [view.fParentView convertPoint : clipRect.origin
613 toView : [view window].contentView];
614 clipRect.origin.y = X11::LocalYROOTToCocoa((NSView<X11Window> *)[view window].contentView,
615 clipRect.origin.y + clipRect.size.height);
616
617 if (AdjustCropArea(topLevelParent.fShapeCombineMask, clipRect)) {
619 clipImageGuard(CGImageCreateWithImageInRect(topLevelParent.fShapeCombineMask.fImage,
620 NSRectToCGRect(clipRect)));
621 clipRect.origin = NSPoint();
622 CGContextClipToMask(ctx, NSRectToCGRect(clipRect), clipImageGuard.Get());
623 } else {
624 //View is invisible.
625 CGRect rect = {};
626 CGContextClipToRect(ctx, rect);
627 }
628 }
629}
630
631#pragma mark - Window's geometry and attributes.
632
633//______________________________________________________________________________
635{
636 assert(attr != 0 && "SetWindowAttributes, parameter 'attr' is null");
637 assert(window != nil && "SetWindowAttributes, parameter 'window' is nil");
638
639 const Mask_t mask = attr->fMask;
640
641 if (mask & kWABackPixel)
642 window.fBackgroundPixel = attr->fBackgroundPixel;
643
644 if (mask & kWAEventMask)
645 window.fEventMask = attr->fEventMask;
646
647 if (mask & kWABitGravity)
648 window.fBitGravity = attr->fBitGravity;
649
650 if (mask & kWAWinGravity)
651 window.fWinGravity = attr->fWinGravity;
652
653 if (mask & kWAOverrideRedirect) {
654 if ([(NSObject *)window isKindOfClass : [QuartzWindow class]]) {
655 QuartzWindow * const qw = (QuartzWindow *)window;
656 [qw setStyleMask : Details::kBorderlessWindowMask];
657 [qw setAlphaValue : 0.95];
658 }
659
660 window.fOverrideRedirect = YES;
661 }
662}
663
664//______________________________________________________________________________
666{
667 assert(win != nil && "GetWindowGeometry, parameter 'win' is nil");
668 assert(dst != 0 && "GetWindowGeometry, parameter 'dst' is null");
669
670 dst->fX = win.fX;
671 dst->fY = win.fY;
672
673 dst->fWidth = win.fWidth;
674 dst->fHeight = win.fHeight;
675}
676
677//______________________________________________________________________________
679{
680 assert(window != nil && "GetWindowAttributes, parameter 'window' is nil");
681 assert(dst != 0 && "GetWindowAttributes, parameter 'attr' is null");
682
683 *dst = WindowAttributes_t();
684
685 //fX, fY, fWidth, fHeight.
686 GetWindowGeometry(window, dst);
687
688 //Actually, most of them are not used by GUI.
689 dst->fBorderWidth = 0;
690 dst->fDepth = window.fDepth;
691 //Dummy value.
692 dst->fVisual = 0;
693 //Dummy value.
694 dst->fRoot = 0;
695 dst->fClass = window.fClass;
696 dst->fBitGravity = window.fBitGravity;
697 dst->fWinGravity = window.fWinGravity;
698 //Dummy value.
699 dst->fBackingStore = kAlways;//??? CHECK
700 dst->fBackingPlanes = 0;
701
702 //Dummy value.
703 dst->fBackingPixel = 0;
704
705 dst->fSaveUnder = 0;
706
707 //Dummy value.
708 dst->fColormap = 0;
709 //Dummy value.
710 dst->fMapInstalled = kTRUE;
711
712 dst->fMapState = window.fMapState;
713
714 dst->fAllEventMasks = window.fEventMask;
715 dst->fYourEventMask = window.fEventMask;
716
717 //Not used by GUI.
718 //dst->fDoNotPropagateMask
719
720 dst->fOverrideRedirect = window.fOverrideRedirect;
721 //Dummy value.
722 dst->fScreen = 0;
723}
724
725//With Apple's poor man's objective C/C++ + "brilliant" Cocoa you never know, what should be
726//the linkage of callback functions, API + language dialects == MESS. I declare/define this comparators here
727//as having "C++" linkage. If one good day clang will start to complane, I'll have to change this.
728
729#pragma mark - Comparators (I need them when changing a window's z-order).
730
731//______________________________________________________________________________
732// SDK 10.11 and above ...
733#ifdef MAC_OS_X_VERSION_10_11
734NSComparisonResult CompareViewsToLower(__kindof NSView *view1, __kindof NSView *view2, void *context)
735#else
736NSComparisonResult CompareViewsToLower(id view1, id view2, void *context)
737#endif
738{
739 id topView = (id)context;
740 if (view1 == topView)
741 return NSOrderedAscending;
742 if (view2 == topView)
743 return NSOrderedDescending;
744
745 return NSOrderedSame;
746}
747
748//______________________________________________________________________________
749// SDK 10.11 and above ...
750#ifdef MAC_OS_X_VERSION_10_11
751NSComparisonResult CompareViewsToRaise(__kindof NSView *view1, __kindof NSView *view2, void *context)
752#else
753NSComparisonResult CompareViewsToRaise(id view1, id view2, void *context)
754#endif
755{
756 id topView = (id)context;
757 if (view1 == topView)
758 return NSOrderedDescending;
759 if (view2 == topView)
760 return NSOrderedAscending;
761
762 return NSOrderedSame;
763}
764
765#pragma mark - Cursor's area.
766
767//______________________________________________________________________________
768NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
769{
770 assert(image != nil && "CursroHotSpot, parameter 'image' is nil");
771
772 const NSSize imageSize = image.size;
773
774 if (cursor == kArrowRight)
775 return NSMakePoint(imageSize.width, imageSize.height / 2);
776
777 return NSMakePoint(imageSize.width / 2, imageSize.height / 2);
778}
779
780//______________________________________________________________________________
781NSCursor *CreateCustomCursor(ECursor currentCursor)
782{
783 // Returns auto-released cursor object.
784 const char *pngFileName = 0;
785
786 switch (currentCursor) {
787 case kMove:
788 pngFileName = "move_cursor.png";
789 break;
790 case kArrowHor:
791 pngFileName = "hor_arrow_cursor.png";
792 break;
793 case kArrowVer:
794 pngFileName = "ver_arrow_cursor.png";
795 break;
796 case kArrowRight:
797 pngFileName = "right_arrow_cursor.png";
798 break;
799 case kRotate:
800 pngFileName = "rotate.png";
801 break;
802 case kBottomLeft:
803 case kTopRight:
804 pngFileName = "top_right_cursor.png";
805 break;
806 case kTopLeft:
807 case kBottomRight:
808 pngFileName = "top_left_cursor.png";
809 break;
810 default:;
811 }
812
813 if (pngFileName) {
814 const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
815 const Util::ScopedArray<const char> arrayGuard(path);
816
817 if (!path || path[0] == 0) {
818 //File was not found.
819 return nil;
820 }
821
822 NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
823 NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
824
825 if (!cursorImage)
826 return nil;
827
828 const NSPoint hotSpot(X11::GetCursorHotStop(cursorImage, currentCursor));
829 NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
830 hotSpot : hotSpot] autorelease];
831
832 [cursorImage release];
833
834 return customCursor;
835 }
836
837 return nil;
838}
839
840//______________________________________________________________________________
841NSCursor *CreateCursor(ECursor currentCursor)
842{
843 // Returns auto-released cursor object.
844
845 //Cursors from TVirtaulX:
846 // kBottomLeft, kBottomRight, kTopLeft, kTopRight,
847 // kBottomSide, kLeftSide, kTopSide, kRightSide,
848 // kMove, kCross, kArrowHor, kArrowVer,
849 // kHand, kRotate, kPointer, kArrowRight,
850 // kCaret, kWatch
851
852 NSCursor *cursor = nil;
853 switch (currentCursor) {
854 case kCross:
855 cursor = [NSCursor crosshairCursor];
856 break;
857 case kPointer:
858 cursor = [NSCursor arrowCursor];
859 break;
860 case kHand:
861 cursor = [NSCursor openHandCursor];
862 break;
863 case kLeftSide:
864 cursor = [NSCursor resizeLeftCursor];
865 break;
866 case kRightSide:
867 cursor = [NSCursor resizeRightCursor];
868 break;
869 case kTopSide:
870 cursor = [NSCursor resizeUpCursor];
871 break;
872 case kBottomSide:
873 cursor = [NSCursor resizeDownCursor];
874 break;
875 case kCaret:
876 cursor = [NSCursor IBeamCursor];
877 break;
878 case kRotate:
879 case kWatch:
880 default:
881 cursor = CreateCustomCursor(currentCursor);
882 }
883
884 return cursor;
885}
886
887//TGTextView/TGHtml is a very special window: it's a TGCompositeFrame,
888//which has TGCompositeFrame inside (TGViewFrame). This TGViewFrame
889//delegates Expose events to its parent, and parent tries to draw
890//inside a TGViewFrame. This does not work with default
891//QuartzView -drawRect/TGCocoa. So I need a trick to identify
892//this special window.
893
894#pragma mark - Workarounds for a text view and its descendants.
895
896//______________________________________________________________________________
897bool ViewIsTextView(unsigned viewID)
898{
899 const TGWindow * const window = gClient->GetWindowById(viewID);
900 if (!window)
901 return false;
902 // This code used to use TObject::InheritsFrom, however since this is
903 // run under the AppKit, we can not call core/meta functions, otherwise
904 // we will run into deadlocks.
905 return dynamic_cast<const TGTextView*>(window);
906}
907
908//______________________________________________________________________________
910{
911 assert(view != nil && "ViewIsTextView, parameter 'view' is nil");
912
913 return ViewIsTextView(view.fID);
914}
915
916//______________________________________________________________________________
917bool ViewIsTextViewFrame(NSView<X11Window> *view, bool checkParent)
918{
919 assert(view != nil && "ViewIsTextViewFrame, parameter 'view' is nil");
920
921 const TGWindow * const window = gClient->GetWindowById(view.fID);
922 if (!window)
923 return false;
924
925 // This code used to use TObject::InheritsFrom, however since this is
926 // run under the AppKit, we can not call core/meta functions, otherwise
927 // we will run into deadlocks.
928 if (!dynamic_cast<const TGViewFrame*>(window))
929 return false;
930
931 if (!checkParent)
932 return true;
933
934 if (!view.fParentView)
935 return false;
936
937 return ViewIsTextView(view.fParentView);
938}
939
940//______________________________________________________________________________
941bool ViewIsHtmlView(unsigned viewID)
942{
943 const TGWindow * const window = gClient->GetWindowById(viewID);
944 if (!window)
945 return false;
946 // This code used to use TObject::InheritsFrom, however since this is
947 // run under the AppKit, we can not call core/meta functions, otherwise
948 // we will run into deadlocks.
949 return window->TestBit(TGWindow::kIsHtmlView);
950}
951
952//______________________________________________________________________________
954{
955 assert(view != nil && "ViewIsHtmlView, parameter 'view' is nil");
956
957 return ViewIsHtmlView(view.fID);
958}
959
960//______________________________________________________________________________
961bool ViewIsHtmlViewFrame(NSView<X11Window> *view, bool checkParent)
962{
963 //
964 assert(view != nil && "ViewIsHtmlViewFrame, parameter 'view' is nil");
965
966 const TGWindow * const window = gClient->GetWindowById(view.fID);
967 if (!window)
968 return false;
969
970 // This code used to use TObject::InheritsFrom, however since this is
971 // run under the AppKit, we can not call core/meta functions, otherwise
972 // we will run into deadlocks.
973 if (!dynamic_cast<const TGViewFrame*>(window))
974 return false;
975
976 if (!checkParent)
977 return true;
978
979 if (!view.fParentView)
980 return false;
981
982 return ViewIsHtmlView(view.fParentView);
983}
984
985//______________________________________________________________________________
987{
988 assert(textView != nil && "FrameForTextView, parameter 'textView' is nil");
989
990 for (NSView<X11Window> *child in [textView subviews]) {
991 if (ViewIsTextViewFrame(child, false))
992 return child;
993 }
994
995 return nil;
996}
997
998//______________________________________________________________________________
1000{
1001 assert(htmlView != nil && "FrameForHtmlView, parameter 'htmlView' is nil");
1002
1003 for (NSView<X11Window> *child in [htmlView subviews]) {
1004 if (ViewIsHtmlViewFrame(child, false))
1005 return child;
1006 }
1007
1008 return nil;
1009}
1010
1011#pragma mark - Workarounds for 'paint out of paint events'.
1012
1013//______________________________________________________________________________
1015{
1016 assert(view != nil && "LockFocus, parameter 'view' is nil");
1017 assert([view isKindOfClass : [QuartzView class]] &&
1018 "LockFocus, QuartzView is expected");
1019
1020 if ([view lockFocusIfCanDraw]) {
1021 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
1022 assert(nsContext != nil && "LockFocus, currentContext is nil");
1023 CGContextRef currContext = (CGContextRef)[nsContext graphicsPort];
1024 assert(currContext != 0 && "LockFocus, graphicsPort is null");//remove this assert?
1025
1026 ((QuartzView *)view).fContext = currContext;
1027
1028 return true;
1029 }
1030
1031 return false;
1032}
1033
1034//______________________________________________________________________________
1036{
1037 assert(view != nil && "UnlockFocus, parameter 'view' is nil");
1038 assert([view isKindOfClass : [QuartzView class]] &&
1039 "UnlockFocus, QuartzView is expected");
1040
1041 [view unlockFocus];
1042 ((QuartzView *)view).fContext = 0;
1043}
1044
1045}//X11
1046}//MacOSX
1047}//ROOT
1048
1049namespace Quartz = ROOT::Quartz;
1050namespace Util = ROOT::MacOSX::Util;
1051namespace X11 = ROOT::MacOSX::X11;
1052namespace Details = ROOT::MacOSX::Details;
1053
1054#ifdef DEBUG_ROOT_COCOA
1055
1056#pragma mark - 'loggers'.
1057
1058namespace {
1059
1060//______________________________________________________________________________
1061void log_attributes(const SetWindowAttributes_t *attr, unsigned winID)
1062{
1063 //This function is loggin requests, at the moment I can not set all
1064 //of these attributes, so I first have to check, what is actually
1065 //requested by ROOT.
1066 static std::ofstream logfile("win_attr.txt");
1067
1068 const Mask_t mask = attr->fMask;
1069 if (mask & kWABackPixmap)
1070 logfile<<"win "<<winID<<": BackPixmap\n";
1071 if (mask & kWABackPixel)
1072 logfile<<"win "<<winID<<": BackPixel\n";
1073 if (mask & kWABorderPixmap)
1074 logfile<<"win "<<winID<<": BorderPixmap\n";
1075 if (mask & kWABorderPixel)
1076 logfile<<"win "<<winID<<": BorderPixel\n";
1077 if (mask & kWABorderWidth)
1078 logfile<<"win "<<winID<<": BorderWidth\n";
1079 if (mask & kWABitGravity)
1080 logfile<<"win "<<winID<<": BitGravity\n";
1081 if (mask & kWAWinGravity)
1082 logfile<<"win "<<winID<<": WinGravity\n";
1083 if (mask & kWABackingStore)
1084 logfile<<"win "<<winID<<": BackingStore\n";
1085 if (mask & kWABackingPlanes)
1086 logfile<<"win "<<winID<<": BackingPlanes\n";
1087 if (mask & kWABackingPixel)
1088 logfile<<"win "<<winID<<": BackingPixel\n";
1089 if (mask & kWAOverrideRedirect)
1090 logfile<<"win "<<winID<<": OverrideRedirect\n";
1091 if (mask & kWASaveUnder)
1092 logfile<<"win "<<winID<<": SaveUnder\n";
1093 if (mask & kWAEventMask)
1094 logfile<<"win "<<winID<<": EventMask\n";
1095 if (mask & kWADontPropagate)
1096 logfile<<"win "<<winID<<": DontPropagate\n";
1097 if (mask & kWAColormap)
1098 logfile<<"win "<<winID<<": Colormap\n";
1099 if (mask & kWACursor)
1100 logfile<<"win "<<winID<<": Cursor\n";
1101}
1102
1103//______________________________________________________________________________
1104void print_mask_info(ULong_t mask)
1105{
1106 if (mask & kButtonPressMask)
1107 NSLog(@"button press mask");
1108 if (mask & kButtonReleaseMask)
1109 NSLog(@"button release mask");
1110 if (mask & kExposureMask)
1111 NSLog(@"exposure mask");
1112 if (mask & kPointerMotionMask)
1113 NSLog(@"pointer motion mask");
1114 if (mask & kButtonMotionMask)
1115 NSLog(@"button motion mask");
1116 if (mask & kEnterWindowMask)
1117 NSLog(@"enter notify mask");
1118 if (mask & kLeaveWindowMask)
1119 NSLog(@"leave notify mask");
1120}
1121
1122}
1123#endif
1124
1125@implementation CrosshairView
1126
1127- (void) drawRect : (NSRect) dirtyRect
1128{
1129 [super drawRect:dirtyRect];
1130
1131 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
1132 if (!nsContext)
1133 return;
1134
1135 CGContextRef cgContext = nsContext.CGContext;
1136 if (!cgContext)
1137 return;
1138
1139 const Quartz::CGStateGuard ctxGuard(cgContext);
1140
1141 CGContextSetRGBStrokeColor(cgContext, 0., 0., 0., 1.);
1142 CGContextSetLineWidth(cgContext, 1.);
1143 // Horizontal line:
1144 CGContextBeginPath(cgContext);
1145 CGContextMoveToPoint(cgContext, self.start1.x, self.start1.y);
1146 CGContextAddLineToPoint(cgContext, self.end1.x, self.end1.y);
1147 CGContextStrokePath(cgContext);
1148 // Vertical line:
1149 CGContextBeginPath(cgContext);
1150 CGContextMoveToPoint(cgContext, self.start2.x, self.start2.y);
1151 CGContextAddLineToPoint(cgContext, self.end2.x, self.end2.y);
1152 CGContextStrokePath(cgContext);
1153}
1154
1155@end
1156
1157@implementation CrosshairWindow
1158
1159- (instancetype) init
1160{
1161 if (self = [super init])
1162 {
1163 self.styleMask = NSWindowStyleMaskBorderless; // No titlebar, buttons, etc.
1164 self.opaque = NO;
1165 self.hasShadow = NO;
1166 self.backgroundColor = NSColor.clearColor; // No background.
1167 self.ignoresMouseEvents = YES; // Lets mouse events pass through.
1168 self.contentView = [[CrosshairView alloc] init];
1169 }
1170 return self;
1171}
1172
1173#pragma mark - suppress the normal window behavior.
1174- (BOOL)canBecomeKeyWindow
1175{
1176 return NO;
1177}
1178- (BOOL)canBecomeMainWindow
1179{
1180 return NO;
1181}
1182
1183@end
1184
1185
1186@implementation QuartzWindow
1187
1188@synthesize fMainWindow;
1189@synthesize fHasFocus;
1190
1191#pragma mark - QuartzWindow's life cycle.
1192
1193//______________________________________________________________________________
1194- (id) initWithContentRect : (NSRect) contentRect styleMask : (NSUInteger) windowStyle
1195 backing : (NSBackingStoreType) bufferingType defer : (BOOL) deferCreation
1196 windowAttributes : (const SetWindowAttributes_t *) attr
1197{
1198 self = [super initWithContentRect : contentRect styleMask : windowStyle
1199 backing : bufferingType defer : deferCreation];
1200
1201 if (self) {
1202 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1203 [self setAllowsConcurrentViewDrawing : NO];
1204
1205 self.delegate = self;
1206 //create content view here.
1207 NSRect contentViewRect = contentRect;
1208 contentViewRect.origin.x = 0.f;
1209 contentViewRect.origin.y = 0.f;
1210
1211 fContentView = [[QuartzView alloc] initWithFrame : contentViewRect windowAttributes : 0];
1212
1213 [self setContentView : fContentView];
1214
1215 [fContentView release];
1216 fDelayedTransient = NO;
1217
1218 if (attr)
1219 X11::SetWindowAttributes(attr, self);
1220
1221 fIsDeleted = NO;
1222 fHasFocus = NO;
1223 }
1224
1225 return self;
1226}
1227
1228//______________________________________________________________________________
1229- (id) initWithGLView : (ROOTOpenGLView *) glView
1230{
1231 using namespace Details;
1232
1233 assert(glView != nil && "-initWithGLView, parameter 'glView' is nil");
1234
1235 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
1237
1238 NSRect contentRect = glView.frame;
1239 contentRect.origin = NSPoint();
1240
1241 self = [super initWithContentRect : contentRect styleMask : styleMask
1242 backing : NSBackingStoreBuffered defer : NO];
1243
1244 if (self) {
1245 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1246 [self setAllowsConcurrentViewDrawing : NO];
1247 self.delegate = self;
1248 fContentView = glView;
1249 [self setContentView : fContentView];
1250 fDelayedTransient = NO;
1251 fIsDeleted = NO;
1252 fHasFocus = NO;
1253 }
1254
1255 return self;
1256}
1257
1258//______________________________________________________________________________
1259- (void) dealloc
1260{
1261 [fShapeCombineMask release];
1262 [super dealloc];
1263}
1264
1265//______________________________________________________________________________
1266- (BOOL) fIsDeleted
1267{
1268 return fIsDeleted;
1269}
1270
1271//______________________________________________________________________________
1272- (void) setContentView:(NSView *)cv
1273{
1274 [super setContentView:cv];
1275 if ([cv isKindOfClass:[QuartzView class]])
1276 fContentView = (QuartzView *)cv;
1277 else
1278 fContentView = nil;
1279}
1280
1281//______________________________________________________________________________
1282- (void) setFIsDeleted : (BOOL) deleted
1283{
1284 fIsDeleted = deleted;
1285}
1286
1287#pragma mark - Forwaring: I want to forward a lot of property setters/getters to the content view.
1288
1289//______________________________________________________________________________
1290- (void) forwardInvocation : (NSInvocation *) anInvocation
1291{
1292 if (!fContentView)
1293 return;
1294
1295 if ([fContentView respondsToSelector : [anInvocation selector]]) {
1296 [anInvocation invokeWithTarget : fContentView];
1297 } else {
1298 [super forwardInvocation : anInvocation];
1299 }
1300}
1301
1302//______________________________________________________________________________
1303- (NSMethodSignature*) methodSignatureForSelector : (SEL) selector
1304{
1305 NSMethodSignature *signature = [super methodSignatureForSelector : selector];
1306
1307 if (!signature) {
1308 if (fContentView)
1309 signature = [fContentView methodSignatureForSelector : selector];
1310 }
1311
1312 return signature;
1313}
1314
1315//______________________________________________________________________________
1316- (void) addTransientWindow : (QuartzWindow *) window
1317{
1318 //Transient window: all the popups (menus, dialogs, popups, comboboxes, etc.)
1319 //always should be on the top of its 'parent' window.
1320 //To enforce this ordering, I have to connect such windows with parent/child
1321 //relation (it's not the same as a view hierarchy - both child and parent
1322 //windows are top-level windows).
1323
1324 assert(window != nil && "-addTransientWindow:, parameter 'window' is nil");
1325
1326 window.fMainWindow = self;
1327
1328 if (window.fMapState != kIsViewable) {
1329 //If I add it as child, it'll immediately make a window visible
1330 //and this thing sucks.
1331 window.fDelayedTransient = YES;
1332 } else {
1333 [self addChildWindow : window ordered : NSWindowAbove];
1334 window.fDelayedTransient = NO;
1335 }
1336}
1337
1338//______________________________________________________________________________
1339- (void) makeKeyAndOrderFront : (id) sender
1340{
1341#pragma unused(sender)
1342
1343 //The more I know Cocoa, the less I like it.
1344 //Window behavior between spaces is a total mess.
1345 //Set the window to join all spaces.
1346#ifdef MAC_OS_X_VERSION_10_9
1347 [self setCollectionBehavior : NSWindowCollectionBehaviorMoveToActiveSpace];
1348#else
1349 [self setCollectionBehavior : NSWindowCollectionBehaviorCanJoinAllSpaces];
1350#endif
1351 //now bring it to the front, it will appear on the active space.
1352 [super makeKeyAndOrderFront : self];
1353 //then reset the collection behavior to default, so the window
1354 [self setCollectionBehavior : NSWindowCollectionBehaviorDefault];
1355}
1356
1357//______________________________________________________________________________
1358- (void) setFDelayedTransient : (BOOL) d
1359{
1361}
1362
1363//______________________________________________________________________________
1365{
1366 return fShapeCombineMask;
1367}
1368
1369//______________________________________________________________________________
1370- (void) setFShapeCombineMask : (QuartzImage *) mask
1371{
1372 if (mask != fShapeCombineMask) {
1373 [fShapeCombineMask release];
1374 if (mask) {
1375 fShapeCombineMask = [mask retain];
1376 //TODO: Check window's shadow???
1377 }
1378 }
1379}
1380
1381#pragma mark - X11Drawable's protocol.
1382
1383//______________________________________________________________________________
1384- (BOOL) fIsPixmap
1385{
1386 //Never.
1387 return NO;
1388}
1389
1390//______________________________________________________________________________
1391- (BOOL) fIsOpenGLWidget
1392{
1393 //Never.
1394 return NO;
1395}
1396
1397//______________________________________________________________________________
1398- (CGFloat) fScaleFactor
1399{
1400 if (!self.screen)
1401 return 1.;
1402 return self.screen.backingScaleFactor;
1403}
1404
1405//______________________________________________________________________________
1406- (int) fX
1407{
1408 return X11::GlobalXCocoaToROOT(self.frame.origin.x);
1409}
1410
1411//______________________________________________________________________________
1412- (int) fY
1413{
1414 return X11::GlobalYCocoaToROOT(self.frame.origin.y + self.frame.size.height);
1415}
1416
1417//______________________________________________________________________________
1418- (unsigned) fWidth
1419{
1420 return self.frame.size.width;
1421}
1422
1423//______________________________________________________________________________
1424- (unsigned) fHeight
1425{
1426 //NSWindow's frame (height component) also includes title-bar.
1427 //So I have to use content view's height.
1428 //Obviously, there is a "hole" == 22 pixels.
1429 assert(fContentView != nil && "-fHeight:, content view is nil");
1430
1431 return fContentView.frame.size.height;
1432}
1433
1434//______________________________________________________________________________
1435- (void) setDrawableSize : (NSSize) newSize
1436{
1437 //Can not simply do self.frame.size = newSize.
1438 assert(!(newSize.width < 0) && "-setDrawableSize:, width is negative");
1439 assert(!(newSize.height < 0) && "-setDrawableSize:, height is negative");
1440
1441 NSRect frame = self.frame;
1442 //dY is potentially a titlebar height.
1443 const CGFloat dY = fContentView ? frame.size.height - fContentView.frame.size.height : 0.;
1444 //Adjust the frame.
1445 frame.origin.y = frame.origin.y + frame.size.height - newSize.height - dY;
1446 frame.size = newSize;
1447 frame.size.height += dY;
1448 [self setFrame : frame display : YES];
1449}
1450
1451//______________________________________________________________________________
1452- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
1453{
1454 NSSize newSize = {};
1455 newSize.width = w;
1456 newSize.height = h;
1457 [self setContentSize : newSize];
1458
1459 //Check how this is affected by title bar's height.
1460 NSPoint topLeft = {};
1461 topLeft.x = X11::GlobalXROOTToCocoa(x);
1462 topLeft.y = X11::GlobalYROOTToCocoa(y);
1463
1464 [self setFrameTopLeftPoint : topLeft];
1465}
1466
1467//______________________________________________________________________________
1468- (void) setX : (int) x Y : (int) y
1469{
1470 NSPoint topLeft = {};
1471 topLeft.x = X11::GlobalXROOTToCocoa(x);
1472 topLeft.y = X11::GlobalYROOTToCocoa(y);
1473
1474 [self setFrameTopLeftPoint : topLeft];
1475}
1476
1477//______________________________________________________________________________
1478- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area withMask : (QuartzImage *) mask
1479 clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
1480{
1481 if (!fContentView)
1482 return;
1483
1484 [fContentView copy : src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
1485}
1486
1487//______________________________________________________________________________
1488- (unsigned char *) readColorBits : (X11::Rectangle) area
1489{
1490 if (!fContentView)
1491 return nullptr;
1492
1493 return [fContentView readColorBits : area];
1494}
1495
1496#pragma mark - CrosshairWindow/View
1497
1498//______________________________________________________________________________
1500{
1501 if ([self findCrosshairWindow])
1502 return;
1503
1504 CrosshairWindow *special = [[CrosshairWindow alloc] init];
1505 [self adjustCrosshairWindowGeometry:special];
1506 [self addChildWindow : special ordered : NSWindowAbove];
1507 [special release];
1508}
1509
1510//______________________________________________________________________________
1512{
1513 if (auto win = [self findCrosshairWindow])
1514 [self adjustCrosshairWindowGeometry:win];
1515}
1516
1517//______________________________________________________________________________
1519{
1520 assert(win && "invalid (nil) parameter 'win'");
1521 auto frame = self.contentView.frame;
1522 frame = [self convertRectToScreen:frame];
1523 [win setFrame:frame display:NO];
1524}
1525
1526//______________________________________________________________________________
1528{
1529 if (auto win = [self findCrosshairWindow]) {
1530 // For some reason, without ordeing out, the crosshair window's content stays
1531 // in the parent's window. Thus we first have to order out the crosshair window.
1532 [win orderOut:nil];
1533 [self removeChildWindow : win];
1534 }
1535}
1536
1537//______________________________________________________________________________
1539{
1540 auto children = [self childWindows];
1541 for (NSWindow *child in children) {
1542 if ([child isKindOfClass : CrosshairWindow.class])
1543 return (CrosshairWindow *)child;
1544 }
1545 return nil;
1546}
1547
1548
1549#pragma mark - X11Window protocol's implementation.
1550
1551//______________________________________________________________________________
1553{
1554 return nil;
1555}
1556
1557//______________________________________________________________________________
1558- (void) setFParentView : (QuartzView *) parent
1559{
1560#pragma unused(parent)
1561}
1562
1563//______________________________________________________________________________
1565{
1566 return fContentView;
1567}
1568
1569//______________________________________________________________________________
1571{
1572 return self;
1573}
1574
1575//... many forwards to fContentView.
1576
1577//______________________________________________________________________________
1578- (void) setFBackgroundPixel : (unsigned long) backgroundColor
1579{
1580 if (!fContentView)
1581 return;
1582
1583 if (!fShapeCombineMask) {
1584 CGFloat rgba[] = {0., 0., 0., 1.};
1585 X11::PixelToRGB(backgroundColor, rgba);
1586
1587 [self setBackgroundColor : [NSColor colorWithColorSpace : [NSColorSpace deviceRGBColorSpace] components : rgba count : 4]];
1588 }
1589
1590 fContentView.fBackgroundPixel = backgroundColor;
1591}
1592
1593//______________________________________________________________________________
1594- (unsigned long) fBackgroundPixel
1595{
1596 if (!fContentView)
1597 return 0;
1598
1600}
1601
1602//______________________________________________________________________________
1603- (int) fMapState
1604{
1605 //Top-level window can be only kIsViewable or kIsUnmapped (not unviewable).
1606 if (!fContentView)
1607 return kIsUnmapped;
1608
1609 if ([fContentView isHidden])
1610 return kIsUnmapped;
1611
1612 return kIsViewable;
1613}
1614
1615//______________________________________________________________________________
1616- (void) addChild : (NSView<X11Window> *) child
1617{
1618 assert(child != nil && "-addChild:, parameter 'child' is nil");
1619
1620 if (!fContentView) {
1621 //This can happen only in case of re-parent operation.
1622 assert([child isKindOfClass : [QuartzView class]] &&
1623 "-addChild: gl view in a top-level window as content view is not supported");
1624
1625 fContentView = (QuartzView *)child;
1626 [self setContentView : child];
1628 } else
1629 [fContentView addChild : child];
1630}
1631
1632//______________________________________________________________________________
1633- (void) getAttributes : (WindowAttributes_t *) attr
1634{
1635 if (!fContentView)
1636 return;
1637
1638 assert(attr && "-getAttributes:, parameter 'attr' is nil");
1639
1640 X11::GetWindowAttributes(self, attr);
1641}
1642
1643//______________________________________________________________________________
1644- (void) setAttributes : (const SetWindowAttributes_t *) attr
1645{
1646 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
1647
1648#ifdef DEBUG_ROOT_COCOA
1649 log_attributes(attr, self.fID);
1650#endif
1651
1652 X11::SetWindowAttributes(attr, self);
1653}
1654
1655//______________________________________________________________________________
1656- (void) mapRaised
1657{
1658 if (!fContentView)
1659 return;
1660
1661 const Util::AutoreleasePool pool;
1662
1663 [fContentView setHidden : NO];
1664 [self makeKeyAndOrderFront : self];
1665 [fContentView configureNotifyTree];
1666
1667 if (fDelayedTransient) {
1668 fDelayedTransient = NO;
1669 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1670 }
1671}
1672
1673//______________________________________________________________________________
1674- (void) mapWindow
1675{
1676 if (!fContentView)
1677 return;
1678
1679 const Util::AutoreleasePool pool;
1680
1681 [fContentView setHidden : NO];
1682 [self makeKeyAndOrderFront : self];
1683 [fContentView configureNotifyTree];
1684
1685 if (fDelayedTransient) {
1686 fDelayedTransient = NO;
1687 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1688 }
1689}
1690
1691//______________________________________________________________________________
1693{
1694 if (!fContentView)
1695 return;
1696
1697 const Util::AutoreleasePool pool;
1698
1699 [fContentView mapSubwindows];
1700 [fContentView configureNotifyTree];
1701}
1702
1703//______________________________________________________________________________
1704- (void) unmapWindow
1705{
1706 if (!fContentView)
1707 return;
1708
1709 [fContentView setHidden : YES];
1710 [self orderOut : self];
1711
1713 [fMainWindow removeChildWindow : self];
1714 fMainWindow = nil;
1715 }
1716}
1717
1718#pragma mark - Events.
1719
1720//______________________________________________________________________________
1721- (void) sendEvent : (NSEvent *) theEvent
1722{
1723 //With XQuartz, if you open a menu and try to move a window without closing this menu,
1724 //window does not move, menu closes, and after that you can start draggin a window again.
1725 //With Cocoa I can not do such a thing (window WILL move), but still can report button release event
1726 //to close a menu.
1727 if (!fContentView)
1728 return;
1729
1730 if (theEvent.type == Details::kLeftMouseDown || theEvent.type == Details::kRightMouseDown) {
1731 bool generateFakeRelease = false;
1732
1733 const NSPoint windowPoint = [theEvent locationInWindow];
1734
1735 if (windowPoint.x <= 4 || windowPoint.x >= self.fWidth - 4)
1736 generateFakeRelease = true;
1737
1738 if (windowPoint.y <= 4 || windowPoint.y >= self.fHeight - 4)
1739 generateFakeRelease = true;
1740
1741 const NSPoint viewPoint = [fContentView convertPoint : windowPoint fromView : nil];
1742
1743 if (viewPoint.y <= 0 && windowPoint.y >= 0)
1744 generateFakeRelease = true;
1745
1746 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1747 "-sendEvent:, gVirtualX is either null or not of TGCocoa type");
1748
1749 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1750 if (vx->GetEventTranslator()->HasPointerGrab() && generateFakeRelease) {
1752 theEvent.type == Details::kLeftMouseDown ?
1753 kButton1 : kButton3);
1754 //Yes, ignore this event completely (this means, you are not able to immediately start
1755 //resizing a window, if some popup is open. Actually, this is more or less
1756 //the same as with XQuartz and X11 version.
1757 return;
1758 }
1759 }
1760
1761 [super sendEvent : theEvent];
1762}
1763
1764#pragma mark - NSWindowDelegate's methods.
1765
1766//______________________________________________________________________________
1767- (BOOL) windowShouldClose : (id) sender
1768{
1769#pragma unused(sender)
1770 if (!fContentView)
1771 return NO;
1772
1773 if ([[self childWindows] count])
1774 return NO;
1775
1776 //Prepare client message for a window.
1777 Event_t closeEvent = {};
1778 closeEvent.fWindow = fContentView.fID;
1779 closeEvent.fType = kClientMessage;
1780 closeEvent.fFormat = 32;//Taken from GUI classes.
1782 closeEvent.fUser[0] = TGCocoa::fgDeleteWindowAtom;
1783 //Place it into the queue.
1784 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1785 "-windowShouldClose:, gVirtualX is either null or has a type different from TGCocoa");
1786 ((TGCocoa *)gVirtualX)->SendEvent(fContentView.fID, &closeEvent);
1787
1788 //Do not let AppKit to close a window,
1789 //ROOT will do.
1790 return NO;
1791}
1792
1793//______________________________________________________________________________
1794- (void) windowDidBecomeKey : (NSNotification *) aNotification
1795{
1796#pragma unused(aNotification)
1797
1798 if (!fContentView)
1799 return;
1800
1802 fHasFocus = YES;
1803 //
1804 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1805 "-windowDidBecomeKey:, gVirtualX is null or not of TGCocoa type");
1806 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1807 vx->GetEventTranslator()->GenerateFocusChangeEvent(self.fContentView);
1808 }
1809}
1810
1811
1812//______________________________________________________________________________
1813- (void) windowDidResignKey : (NSNotification *) aNotification
1814{
1815#pragma unused(aNotification)
1816 fHasFocus = NO;
1817}
1818
1819@end
1820
1821#pragma mark - Passive key grab info.
1822
1823@implementation PassiveKeyGrab
1824
1825//______________________________________________________________________________
1826- (id) initWithKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1827{
1828 if (self = [super init]) {
1829 fKeyCode = keyCode;
1830 fModifiers = modifiers;
1831 }
1832
1833 return self;
1834}
1835
1836//______________________________________________________________________________
1837- (BOOL) matchKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1838{
1839 return keyCode == fKeyCode && modifiers == fModifiers;
1840}
1841
1842//______________________________________________________________________________
1843- (BOOL) matchKey : (unichar) keyCode
1844{
1845 return keyCode == fKeyCode;
1846}
1847
1848//______________________________________________________________________________
1849- (unichar) fKeyCode
1850{
1851 return fKeyCode;
1852}
1853
1854//______________________________________________________________________________
1855- (NSUInteger) fModifiers
1856{
1857 return fModifiers;
1858}
1859
1860@end
1861
1862#pragma mark - X11 property emulation.
1863
1864@interface QuartzWindowProperty : NSObject {
1865 NSData *fPropertyData;
1866 Atom_t fType;
1867 unsigned fFormat;
1868}
1869
1870@property (nonatomic, readonly) Atom_t fType;
1871
1872@end
1873
1874@implementation QuartzWindowProperty
1875
1876@synthesize fType;
1877
1878//______________________________________________________________________________
1879- (id) initWithData : (unsigned char *) data size : (unsigned) dataSize type : (Atom_t) type format : (unsigned) format
1880{
1881 if (self = [super init]) {
1882 //Memory is zero-initialized, but just to make it explicit:
1883 fPropertyData = nil;
1884 fType = 0;
1885 fFormat = 0;
1886
1887 [self resetPropertyData : data size : dataSize type : type format : format];
1888 }
1889
1890 return self;
1891}
1892
1893//______________________________________________________________________________
1894- (void) dealloc
1895{
1896 [fPropertyData release];
1897
1898 [super dealloc];
1899}
1900
1901//______________________________________________________________________________
1902- (void) resetPropertyData : (unsigned char *) data size : (unsigned) dataSize
1903 type : (Atom_t) type format : (unsigned) format
1904{
1905 [fPropertyData release];
1906
1907 fFormat = format;
1908 if (format == 16)
1909 dataSize *= 2;
1910 else if (format == 32)
1911 dataSize *= 4;
1912
1913 fPropertyData = [[NSData dataWithBytes : data length : dataSize] retain];
1914
1915 fType = type;
1916}
1917
1918//______________________________________________________________________________
1919- (NSData *) fPropertyData
1920{
1921 return fPropertyData;
1922}
1923
1924//______________________________________________________________________________
1925- (unsigned) fFormat
1926{
1927 return fFormat;
1928}
1929
1930@end
1931
1932#pragma mark - QuartzView.
1933
1934//
1935//QuartzView is a children view (also is a content view for a top-level QuartzWindow).
1936//
1937
1938@implementation QuartzView
1939
1940@synthesize fID;
1941@synthesize fContext;
1942/////////////////////
1943//SetWindowAttributes_t/WindowAttributes_t
1944@synthesize fEventMask;
1945@synthesize fClass;
1946@synthesize fDepth;
1947@synthesize fBitGravity;
1948@synthesize fWinGravity;
1949@synthesize fBackgroundPixel;
1950@synthesize fOverrideRedirect;
1951//SetWindowAttributes_t/WindowAttributes_t
1952/////////////////////
1953@synthesize fHasFocus;
1954@synthesize fParentView;
1955
1956@synthesize fPassiveGrabButton;
1957@synthesize fPassiveGrabEventMask;
1958@synthesize fPassiveGrabKeyModifiers;
1959@synthesize fActiveGrabEventMask;
1960@synthesize fPassiveGrabOwnerEvents;
1961@synthesize fSnapshotDraw;
1962@synthesize fCurrentCursor;
1963@synthesize fIsDNDAware;
1964
1965#pragma mark - Lifetime.
1966
1967//______________________________________________________________________________
1968- (id) initWithFrame : (NSRect) frame windowAttributes : (const SetWindowAttributes_t *)attr
1969{
1970 if (self = [super initWithFrame : frame]) {
1971 //Make this explicit (though memory is zero initialized).
1972 fBackBuffer = nil;
1973 fID = 0;
1974
1975 //Passive grab parameters.
1976 fPassiveGrabButton = -1;//0 is kAnyButton.
1979
1980 fPassiveKeyGrabs = [[NSMutableArray alloc] init];
1981
1982 [self setCanDrawConcurrently : NO];
1983
1984 [self setHidden : YES];
1985 //Actually, check if view need this.
1986 //
1987 if (attr)
1988 X11::SetWindowAttributes(attr, self);
1989
1991 fX11Properties = [[NSMutableDictionary alloc] init];
1992
1996 }
1997
1998 return self;
1999}
2000
2001//______________________________________________________________________________
2002- (void) dealloc
2003{
2004 [fBackBuffer release];
2005 [fPassiveKeyGrabs release];
2006 [fX11Properties release];
2007 [fBackgroundPixmap release];
2008 [super dealloc];
2009}
2010
2011#pragma mark - Tracking area.
2012
2013//Tracking area is required to ... track mouse motion events inside a view.
2014
2015//______________________________________________________________________________
2016- (void) updateTrackingAreas
2017{
2018 [super updateTrackingAreas];
2019
2020 if (!fID)
2021 return;
2022
2023 const Util::AutoreleasePool pool;
2024
2025 if (NSArray *trackingArray = [self trackingAreas]) {
2026 const NSUInteger size = [trackingArray count];
2027 for (NSUInteger i = 0; i < size; ++i) {
2028 NSTrackingArea * const t = [trackingArray objectAtIndex : i];
2029 [self removeTrackingArea : t];
2030 }
2031 }
2032
2033 const NSUInteger trackerOptions = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
2034 NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
2035 NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate;
2036
2037 NSRect frame = {};
2038 frame.size.width = self.fWidth;
2039 frame.size.height = self.fHeight;
2040
2041 NSTrackingArea * const tracker = [[NSTrackingArea alloc] initWithRect : frame
2042 options : trackerOptions owner : self userInfo : nil];
2043 [self addTrackingArea : tracker];
2044 [tracker release];
2045}
2046
2047//______________________________________________________________________________
2048- (void) updateTrackingAreasAfterRaise
2049{
2050 [self updateTrackingAreas];
2051
2052 for (QuartzView *childView in [self subviews])
2053 [childView updateTrackingAreasAfterRaise];
2054}
2055
2056#pragma mark - X11Drawable protocol.
2057
2058//______________________________________________________________________________
2059- (BOOL) fIsPixmap
2060{
2061 return NO;
2062}
2063
2064//______________________________________________________________________________
2065- (BOOL) fIsOpenGLWidget
2066{
2067 return NO;
2068}
2069
2070//______________________________________________________________________________
2071- (CGFloat) fScaleFactor
2072{
2073 return self.fQuartzWindow.fScaleFactor;
2074}
2075
2076//______________________________________________________________________________
2077- (int) fX
2078{
2079 return self.frame.origin.x;
2080}
2081
2082//______________________________________________________________________________
2083- (int) fY
2084{
2085 return self.frame.origin.y;
2086}
2087
2088//______________________________________________________________________________
2089- (unsigned) fWidth
2090{
2091 return self.frame.size.width;
2092}
2093
2094//______________________________________________________________________________
2095- (unsigned) fHeight
2096{
2097 return self.frame.size.height;
2098}
2099
2100//______________________________________________________________________________
2101- (void) setDrawableSize : (NSSize) newSize
2102{
2103 assert(!(newSize.width < 0) && "-setDrawableSize, width is negative");
2104 assert(!(newSize.height < 0) && "-setDrawableSize, height is negative");
2105
2106 //This will cause redraw(?)
2107
2108 //In X11, resize changes the size, but upper-left corner is not changed.
2109 //In Cocoa, bottom-left is fixed.
2110 NSRect frame = self.frame;
2111 frame.size = newSize;
2112
2113 self.frame = frame;
2114}
2115
2116//______________________________________________________________________________
2117- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
2118{
2119 NSRect newFrame = {};
2120 newFrame.origin.x = x;
2121 newFrame.origin.y = y;
2122 newFrame.size.width = w;
2123 newFrame.size.height = h;
2124
2125 self.frame = newFrame;
2126}
2127
2128//______________________________________________________________________________
2129- (void) setX : (int) x Y : (int) y
2130{
2131 NSRect newFrame = self.frame;
2132 newFrame.origin.x = x;
2133 newFrame.origin.y = y;
2134
2135 self.frame = newFrame;
2136}
2137
2138//______________________________________________________________________________
2139- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2140 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY
2141 toPoint : (X11::Point) dstPoint
2142{
2143 //Check parameters.
2144 assert(srcImage != nil &&
2145 "-copyImage:area:withMask:clipOrigin:toPoint:, parameter 'srcImage' is nil");
2146 assert(srcImage.fImage != nil &&
2147 "-copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
2148
2149 //Check self.
2150 assert(self.fContext != 0 &&
2151 "-copyImage:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2152
2153 if (!X11::AdjustCropArea(srcImage, area)) {
2154 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2155 " srcRect and copyRect do not intersect");
2156 return;
2157 }
2158
2159 //No RAII for subImage, since it can be really subimage or image itself and
2160 //in these cases there is no need to release image.
2161 CGImageRef subImage = 0;
2162 bool needSubImage = false;
2163 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2164 needSubImage = true;
2165 subImage = X11::CreateSubImage(srcImage, area);
2166 if (!subImage) {
2167 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2168 " subimage creation failed");
2169 return;
2170 }
2171 } else
2172 subImage = srcImage.fImage;
2173
2174 //Save context state.
2175 const Quartz::CGStateGuard ctxGuard(self.fContext);
2176
2177 //Scale and translate to undo isFlipped.
2178 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2179 CGContextScaleCTM(self.fContext, 1., -1.);
2180 //Set clip mask on a context.
2181
2182 if (mask) {
2183 assert(mask.fImage != nil &&
2184 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2185 assert(CGImageIsMask(mask.fImage) == true &&
2186 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2187 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2188 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2189 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2190 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2191 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2192 }
2193
2194 //Convert from X11 to Cocoa (as soon as we scaled y * -1).
2195 //dstPoint.fY = X11::LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
2196 const CGFloat dstY = X11::LocalYROOTToCocoa(self, CGFloat(dstPoint.fY) + area.fHeight);
2197 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2198 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2199 CGContextDrawImage(self.fContext, imageRect, subImage);
2200
2201 if (needSubImage)
2202 CGImageRelease(subImage);
2203}
2204
2205//______________________________________________________________________________
2206- (void) copyView : (QuartzView *) srcView area : (X11::Rectangle) area toPoint : (X11::Point) dstPoint
2207{
2208 //To copy one "window" to another "window", I have to ask source QuartzView to draw intself into
2209 //bitmap, and copy this bitmap into the destination view.
2210
2211 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2212
2213 const NSRect frame = [srcView frame];
2214 //imageRep is in autorelease pool now.
2215 NSBitmapImageRep * const imageRep = [srcView bitmapImageRepForCachingDisplayInRect : frame];
2216 if (!imageRep) {
2217 NSLog(@"QuartzView: -copyView:area:toPoint failed");
2218 return;
2219 }
2220
2221 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2222 assert(self.fContext != 0 && "-copyView:area:toPoint, self.fContext is null");
2223
2224 //It can happen, that src and self are the same.
2225 //cacheDisplayInRect calls drawRect with bitmap context
2226 //(and this will reset self.fContext: I have to save/restore it.
2227 CGContextRef ctx = srcView.fContext;
2228 srcView.fSnapshotDraw = YES;
2229 [srcView cacheDisplayInRect : frame toBitmapImageRep : imageRep];
2230 srcView.fSnapshotDraw = NO;
2231 srcView.fContext = ctx;
2232
2233 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fWidth, area.fHeight);
2234 const Util::CFScopeGuard<CGImageRef> subImage(CGImageCreateWithImageInRect(imageRep.CGImage, subImageRect));
2235
2236 if (!subImage.Get()) {
2237 NSLog(@"QuartzView: -copyView:area:toPoint, CGImageCreateWithImageInRect failed");
2238 return;
2239 }
2240
2241 const Quartz::CGStateGuard ctxGuard(self.fContext);
2242 const CGRect imageRect = CGRectMake(dstPoint.fX,
2243 [self visibleRect].size.height - (CGFloat(dstPoint.fY) + area.fHeight),
2244 area.fWidth, area.fHeight);
2245
2246 CGContextTranslateCTM(self.fContext, 0., [self visibleRect].size.height);
2247 CGContextScaleCTM(self.fContext, 1., -1.);
2248
2249 CGContextDrawImage(self.fContext, imageRect, subImage.Get());
2250}
2251
2252//______________________________________________________________________________
2253- (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
2254 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2255{
2256 //Check parameters.
2257 assert(srcPixmap != nil && "-copyPixmap:area:withMask:clipOrigin:toPoint:, parameter 'srcPixmap' is nil");
2258
2259 if (!X11::AdjustCropArea(srcPixmap, area)) {
2260 NSLog(@"QuartzView: -copyPixmap:area:withMask:clipOrigin:toPoint,"
2261 " no intersection between pixmap rectangle and cropArea");
2262 return;
2263 }
2264
2265 //Check self.
2266 assert(self.fContext != 0 &&
2267 "-copyPixmap:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2268
2269 //Save context state.
2270 const Quartz::CGStateGuard ctxGuard(self.fContext);
2271
2272 CGContextTranslateCTM(self.fContext, 0., self.frame.size.height);//???
2273 CGContextScaleCTM(self.fContext, 1., -1.);
2274
2275 const Util::CFScopeGuard<CGImageRef> imageFromPixmap([srcPixmap createImageFromPixmap]);
2276 assert(imageFromPixmap.Get() != 0 &&
2277 "-copyPixmap:area:withMask:clipOrigin:toPoint:, createImageFromPixmap failed");
2278
2279 CGImageRef subImage = 0;
2280 bool needSubImage = false;
2281 if (area.fX || area.fY || area.fWidth != srcPixmap.fWidth || area.fHeight != srcPixmap.fHeight) {
2282 needSubImage = true;
2283 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
2284 subImage = CGImageCreateWithImageInRect(imageFromPixmap.Get(), subImageRect);
2285 if (!subImage) {
2286 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2287 " subimage creation failed");
2288 return;
2289 }
2290 } else
2291 subImage = imageFromPixmap.Get();
2292
2293 if (mask) {
2294 assert(mask.fImage != nil &&
2295 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2296 assert(CGImageIsMask(mask.fImage) == true &&
2297 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2298
2299 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2300 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2301 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2302 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2303 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2304 }
2305
2306 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2307 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2308 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2309 CGContextDrawImage(self.fContext, imageRect, imageFromPixmap.Get());
2310
2311 if (needSubImage)
2312 CGImageRelease(subImage);
2313}
2314
2315
2316//______________________________________________________________________________
2317- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2318 toPoint : (X11::Point) dstPoint
2319{
2320 assert(srcImage != nil && "-copyImage:area:toPoint:, parameter 'srcImage' is nil");
2321 assert(srcImage.fImage != nil && "-copyImage:area:toPoint:, srcImage.fImage is nil");
2322 assert(self.fContext != 0 && "-copyImage:area:toPoint:, fContext is null");
2323
2324 if (!X11::AdjustCropArea(srcImage, area)) {
2325 NSLog(@"QuartzView: -copyImage:area:toPoint, image and copy area do not intersect");
2326 return;
2327 }
2328
2329 CGImageRef subImage = 0;
2330 bool needSubImage = false;
2331 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2332 needSubImage = true;
2333 subImage = X11::CreateSubImage(srcImage, area);
2334 if (!subImage) {
2335 NSLog(@"QuartzView: -copyImage:area:toPoint:, subimage creation failed");
2336 return;
2337 }
2338 } else
2339 subImage = srcImage.fImage;
2340
2341 const Quartz::CGStateGuard ctxGuard(self.fContext);
2342
2343 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2344 CGContextScaleCTM(self.fContext, 1., -1.);
2345
2346 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2347 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2348 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2349 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2350 CGContextDrawImage(self.fContext, imageRect, subImage);
2351
2352 if (needSubImage)
2353 CGImageRelease(subImage);
2354}
2355
2356//______________________________________________________________________________
2357- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
2358 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2359{
2360 assert(src != nil && "-copy:area:withMask:clipOrigin:toPoint:, parameter 'src' is nil");
2361 assert(area.fWidth && area.fHeight && "-copy:area:withMask:clipOrigin:toPoint:, area to copy is empty");
2362
2363 if ([src isKindOfClass : [QuartzWindow class]]) {
2364 //Forget about mask (can I have it???)
2365 QuartzWindow * const qw = (QuartzWindow *)src;
2366 //Will not work with OpenGL.
2367 [self copyView : (QuartzView *)qw.fContentView area : area toPoint : dstPoint];
2368 } else if ([src isKindOfClass : [QuartzView class]]) {
2369 //Forget about mask (can I have it???)
2370 [self copyView : (QuartzView *)src area : area toPoint : dstPoint];
2371 } else if ([src isKindOfClass : [QuartzPixmap class]]) {
2372 [self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2373 } else if ([src isKindOfClass : [QuartzImage class]]) {
2374 [self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2375 } else {
2376 assert(0 && "-copy:area:withMask:clipOrigin:toPoint:, src is of unknown type");
2377 }
2378}
2379
2380//______________________________________________________________________________
2381- (unsigned char *) readColorBits : (X11::Rectangle) area
2382{
2383 //This is quite a bad idea - to read pixels back from a view,
2384 //but our GUI does exactly this. In case of Cocoa it's expensive
2385 //and not guaranteed to work.
2386
2387 assert(area.fWidth && area.fHeight && "-readColorBits:, area to copy is empty");
2388
2389 //int, not unsigned or something - to keep it simple.
2390 const NSRect visRect = [self visibleRect];
2391 const X11::Rectangle srcRect(int(visRect.origin.x), int(visRect.origin.y),
2392 unsigned(visRect.size.width), unsigned(visRect.size.height));
2393
2394 if (!X11::AdjustCropArea(srcRect, area)) {
2395 NSLog(@"QuartzView: -readColorBits:, visible rect of view and copy area do not intersect");
2396 return nullptr;
2397 }
2398
2399 //imageRep is autoreleased.
2400 NSBitmapImageRep * const imageRep = [self bitmapImageRepForCachingDisplayInRect : visRect];
2401 if (!imageRep) {
2402 NSLog(@"QuartzView: -readColorBits:, bitmapImageRepForCachingDisplayInRect failed");
2403 return nullptr;
2404 }
2405
2406 CGContextRef ctx = self.fContext; //Save old context if any.
2407 [self cacheDisplayInRect : visRect toBitmapImageRep : imageRep];
2408 self.fContext = ctx; //Restore old context.
2409 //
2410 const NSInteger bitsPerPixel = [imageRep bitsPerPixel];
2411
2412 assert(bitsPerPixel == 32 && "-readColorBits:, no alpha channel???");
2413 const NSInteger bytesPerRow = [imageRep bytesPerRow];
2414 unsigned dataWidth = bytesPerRow / (bitsPerPixel / 8);//assume an octet :(
2415
2416 unsigned char *srcData = nullptr;
2417 std::vector<unsigned char> downscaled;
2418 if ([self.window.screen backingScaleFactor] > 1 && imageRep.CGImage) {
2419 downscaled = X11::DownscaledImageData(area.fWidth, area.fHeight, imageRep.CGImage);
2420 if (downscaled.size())
2421 srcData = &downscaled[0];
2422 dataWidth = area.fWidth;
2423 } else
2424 srcData = [imageRep bitmapData];
2425
2426 if (!srcData) {
2427 NSLog(@"QuartzView: -readColorBits:, failed to obtain backing store contents");
2428 return nullptr;
2429 }
2430
2431 //We have a source data now. Let's allocate buffer for ROOT's GUI and convert source data.
2432 unsigned char *data = nullptr;
2433
2434 try {
2435 data = new unsigned char[area.fWidth * area.fHeight * 4];//bgra?
2436 } catch (const std::bad_alloc &) {
2437 NSLog(@"QuartzView: -readColorBits:, memory allocation failed");
2438 return nullptr;
2439 }
2440
2441 unsigned char *dstPixel = data;
2442 const unsigned char *line = srcData + area.fY * dataWidth * 4;
2443 const unsigned char *srcPixel = line + area.fX * 4;
2444
2445 for (unsigned i = 0; i < area.fHeight; ++i) {
2446 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
2447 dstPixel[0] = srcPixel[2];
2448 dstPixel[1] = srcPixel[1];
2449 dstPixel[2] = srcPixel[0];
2450 dstPixel[3] = srcPixel[3];
2451 }
2452
2453 line += dataWidth * 4;
2454 srcPixel = line + area.fX * 4;
2455 }
2456
2457 return data;
2458}
2459
2460//______________________________________________________________________________
2461- (void) setFBackgroundPixmap : (QuartzImage *) pixmap
2462{
2463 if (fBackgroundPixmap != pixmap) {
2464 [fBackgroundPixmap release];
2465 if (pixmap)
2466 fBackgroundPixmap = [pixmap retain];
2467 else
2468 fBackgroundPixmap = nil;
2469 }
2470}
2471
2472//______________________________________________________________________________
2474{
2475 //I do not autorelease, screw this idiom!
2476
2477 return fBackgroundPixmap;
2478}
2479
2480//______________________________________________________________________________
2481- (int) fMapState
2482{
2483 if ([self isHidden])
2484 return kIsUnmapped;
2485
2486 for (QuartzView *parent = fParentView; parent; parent = parent.fParentView) {
2487 if ([parent isHidden])
2488 return kIsUnviewable;
2489 }
2490
2491 return kIsViewable;
2492}
2493
2494//______________________________________________________________________________
2495- (BOOL) fHasFocus
2496{
2497 //With the latest update clang became a bit more stupid.
2498 //Let's write a stupid useless cargo cult code
2499 //to make IT SHUT THE F... UP.
2500 (void)fHasFocus;
2501 return NO;
2502}
2503
2504//______________________________________________________________________________
2505- (void) setFHasFocus : (BOOL) focus
2506{
2507#pragma unused(focus)
2508 //With the latest update clang became a bit more stupid.
2509 //Let's write a stupid useless cargo cult code
2510 //to make IT SHUT THE F... UP.
2511 (void)fHasFocus;
2512}
2513
2514//______________________________________________________________________________
2516{
2517 return fBackBuffer;//No autorelease, I know the object's lifetime myself.
2518}
2519
2520//______________________________________________________________________________
2521- (void) setFBackBuffer : (QuartzPixmap *) backBuffer
2522{
2523 if (fBackBuffer != backBuffer) {
2524 [fBackBuffer release];
2525
2526 if (backBuffer)
2527 fBackBuffer = [backBuffer retain];
2528 else
2529 fBackBuffer = nil;
2530 }
2531}
2532
2533//______________________________________________________________________________
2535{
2536 return self;
2537}
2538
2539//______________________________________________________________________________
2541{
2542 return (QuartzWindow *)[self window];
2543}
2544
2545//______________________________________________________________________________
2547{
2549}
2550
2551//______________________________________________________________________________
2553{
2555}
2556
2557//______________________________________________________________________________
2558- (void) activateGrab : (unsigned) eventMask ownerEvents : (BOOL) ownerEvents
2559{
2561 fActiveGrabEventMask = eventMask;
2562 fActiveGrabOwnerEvents = ownerEvents;
2563}
2564
2565//______________________________________________________________________________
2566- (void) cancelGrab
2567{
2571}
2572
2573//______________________________________________________________________________
2574- (BOOL) acceptsCrossingEvents : (unsigned) eventMask
2575{
2576 bool accepts = fEventMask & eventMask;
2577
2578 //In ROOT passive grabs are always with owner_events == true.
2580 accepts = accepts || (fPassiveGrabEventMask & eventMask);
2581
2584 accepts = accepts || (fActiveGrabOwnerEvents & eventMask);
2585 else
2586 accepts = fActiveGrabOwnerEvents & eventMask;
2587 }
2588
2589 return accepts;
2590}
2591
2592//______________________________________________________________________________
2593- (void) addChild : (NSView<X11Window> *) child
2594{
2595 assert(child != nil && "-addChild:, parameter 'child' is nil");
2596
2597 [self addSubview : child];
2598 child.fParentView = self;
2599}
2600
2601//______________________________________________________________________________
2602- (void) getAttributes : (WindowAttributes_t *) attr
2603{
2604 assert(attr != 0 && "-getAttributes:, parameter 'attr' is null");
2605
2606 X11::GetWindowAttributes(self, attr);
2607}
2608
2609//______________________________________________________________________________
2610- (void) setAttributes : (const SetWindowAttributes_t *)attr
2611{
2612 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
2613
2614#ifdef DEBUG_ROOT_COCOA
2615 log_attributes(attr, fID);
2616#endif
2617
2618 X11::SetWindowAttributes(attr, self);
2619}
2620
2621//______________________________________________________________________________
2622- (void) mapRaised
2623{
2624 //Move view to the top of subviews.
2625 QuartzView * const parent = fParentView;
2626 [self removeFromSuperview];
2627 [parent addSubview : self];
2628 [self setHidden : NO];
2629}
2630
2631//______________________________________________________________________________
2632- (void) mapWindow
2633{
2634 [self setHidden : NO];
2635}
2636
2637//______________________________________________________________________________
2639{
2640 for (QuartzView * v in [self subviews])
2641 [v setHidden : NO];
2642}
2643
2644//______________________________________________________________________________
2645- (void) unmapWindow
2646{
2647 [self setHidden : YES];
2648}
2649
2650//______________________________________________________________________________
2651- (BOOL) fIsOverlapped
2652{
2653 return fIsOverlapped;
2654}
2655
2656//______________________________________________________________________________
2657- (void) setOverlapped : (BOOL) overlap
2658{
2659 fIsOverlapped = overlap;
2660 for (NSView<X11Window> *child in [self subviews])
2661 [child setOverlapped : overlap];
2662}
2663
2664//______________________________________________________________________________
2665- (void) raiseWindow
2666{
2667 //Now, I can not remove window and add it ...
2668 //For example, if you click on a tab, this:
2669 //1. Creates (potentially) a passive button grab
2670 //2. Raises this tab - changes the window order.
2671 //3. On a button release - grab is release.
2672 //The tough problem is, if I remove a view from subviews
2673 //and add it ... it will never receve the
2674 //release event thus a grab will 'hang' on
2675 //view leading to bugs and artifacts.
2676 //So instead I have to ... SORT!!!!!
2677
2678 using namespace X11;//Comparators.
2679
2680 for (QuartzView *sibling in [fParentView subviews]) {
2681 if (self == sibling)
2682 continue;
2683 if ([sibling isHidden])
2684 continue;
2685
2686 if (NSEqualRects(sibling.frame, self.frame)) {
2687 [sibling setOverlapped : YES];
2688 [sibling setHidden : YES];
2689 }
2690 }
2691
2692 [self setOverlapped : NO];
2693 //
2694 [self setHidden : NO];
2695 //
2696 [fParentView sortSubviewsUsingFunction : CompareViewsToRaise context : (void *)self];
2697 //
2698 [self updateTrackingAreasAfterRaise];
2699 //
2700 [self setNeedsDisplay : YES];
2701}
2702
2703//______________________________________________________________________________
2704- (void) lowerWindow
2705{
2706 //See comment about sorting in -raiseWindow.
2707
2708 using namespace X11;
2709
2710 NSEnumerator * const reverseEnumerator = [[fParentView subviews] reverseObjectEnumerator];
2711 for (QuartzView *sibling in reverseEnumerator) {
2712 if (sibling == self)
2713 continue;
2714
2715 if (NSEqualRects(sibling.frame, self.frame)) {
2716 [sibling setOverlapped : NO];
2717 //
2718 [sibling setHidden : NO];
2719 //
2720 [sibling setNeedsDisplay : YES];
2721 [self setOverlapped : YES];
2722 //
2723 [self setHidden : YES];
2724 //
2725 break;
2726 }
2727 }
2728
2729 [fParentView sortSubviewsUsingFunction : CompareViewsToLower context : (void*)self];
2730}
2731
2732//______________________________________________________________________________
2733- (BOOL) isFlipped
2734{
2735 //Now view's placement, geometry, moving and resizing can be
2736 //done with ROOT's (X11) coordinates without conversion - we're are 'flipped'.
2737 return YES;
2738}
2739
2740//______________________________________________________________________________
2742{
2743 if (self.fMapState == kIsViewable || fIsOverlapped == YES) {
2745 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2746 "-configureNotifyTree, gVirtualX is either null or has type different from TGCocoa");
2747 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2748 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2749 }
2750
2751 for (NSView<X11Window> *v in [self subviews])
2752 [v configureNotifyTree];
2753 }
2754}
2755
2756#pragma mark - Key grabs.
2757
2758//______________________________________________________________________________
2759- (void) addPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2760{
2761 [self removePassiveKeyGrab : keyCode modifiers : modifiers];
2762 PassiveKeyGrab * const newGrab = [[PassiveKeyGrab alloc] initWithKey : keyCode
2763 modifiers : modifiers];
2764 [fPassiveKeyGrabs addObject : newGrab];
2765 [newGrab release];
2766}
2767
2768//______________________________________________________________________________
2769- (void) removePassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2770{
2771 const NSUInteger count = [fPassiveKeyGrabs count];
2772 for (NSUInteger i = 0; i < count; ++i) {
2773 PassiveKeyGrab *grab = [fPassiveKeyGrabs objectAtIndex : i];
2774 if ([grab matchKey : keyCode modifiers : modifiers]) {
2775 [fPassiveKeyGrabs removeObjectAtIndex : i];
2776 break;
2777 }
2778 }
2779}
2780
2781//______________________________________________________________________________
2782- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2783{
2784 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2785 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2786 if ([grab matchKey : keyCode modifiers : modifiers])
2787 return grab;
2788 }
2789
2790 return nil;
2791}
2792
2793//______________________________________________________________________________
2794- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode
2795{
2796 //Do not check modifiers.
2797 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2798 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2799 if ([grab matchKey : keyCode])
2800 return grab;
2801 }
2802
2803 return nil;
2804}
2805
2806#pragma mark - Painting mechanics.
2807
2808//______________________________________________________________________________
2809- (void) drawRect : (NSRect) dirtyRect
2810{
2811#pragma unused(dirtyRect)
2812
2813 using namespace X11;
2814
2815 if (fID) {
2816 if (TGWindow * const window = gClient->GetWindowById(fID)) {
2817 //It's never painted, parent renders child. true == check the parent also.
2818 if (ViewIsTextViewFrame(self, true) ||ViewIsHtmlViewFrame(self, true))
2819 return;
2820
2821 NSGraphicsContext * const nsContext = [NSGraphicsContext currentContext];
2822 assert(nsContext != nil && "-drawRect:, currentContext returned nil");
2823
2824 TGCocoa * const vx = (TGCocoa *)gVirtualX;
2825 vx->CocoaDrawON();
2826
2827 fContext = (CGContextRef)[nsContext graphicsPort];
2828 assert(fContext != 0 && "-drawRect:, graphicsPort returned null");
2829
2830 const Quartz::CGStateGuard ctxGuard(fContext);
2831
2832 //Non-rectangular windows.
2833 if (self.fQuartzWindow.fShapeCombineMask)
2835
2836 // This code used to use TObject::InheritsFrom, however since this is
2837 // run under the AppKit, we can not call core/meta functions, otherwise
2838 // we will run into deadlocks.
2839 if (dynamic_cast<const TGContainer*>(window))//It always has an ExposureMask.
2840 vx->GetEventTranslator()->GenerateExposeEvent(self, [self visibleRect]);
2841
2842 if (fEventMask & kExposureMask) {
2843 if (ViewIsTextView(self)) {
2844 //Send Expose event, using child view (this is how it's done in GUI :( ).
2845 [NSColor.whiteColor setFill];
2846 NSRectFill(dirtyRect);
2847 NSView<X11Window> * const viewFrame = FrameForTextView(self);
2848 if (viewFrame)//Now we set fExposedRegion for TGView.
2849 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2850 }
2851
2852 if (ViewIsHtmlView(self)) {
2853 NSView<X11Window> *const viewFrame = FrameForHtmlView(self);
2854 if (viewFrame)
2855 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2856 }
2857
2858 //Ask ROOT's widget/window to draw itself.
2859 gClient->NeedRedraw(window, kTRUE);
2860
2861 if (!fSnapshotDraw) {
2862 //If Cocoa repaints widget, cancel all ROOT's "outside of paint event"
2863 //rendering into this widget.
2864 gClient->CancelRedraw(window);
2866 }
2867 }
2868
2869 if (fBackBuffer) {
2870 //Very "special" window.
2871 const X11::Rectangle copyArea(0, 0, fBackBuffer.fWidth, fBackBuffer.fHeight);
2872 [self copy : fBackBuffer area : copyArea withMask : nil
2873 clipOrigin : X11::Point() toPoint : X11::Point()];
2874 }
2875
2876 vx->CocoaDrawOFF();
2877#ifdef DEBUG_ROOT_COCOA
2878 CGContextSetRGBStrokeColor(fContext, 1., 0., 0., 1.);
2879 CGContextStrokeRect(fContext, dirtyRect);
2880#endif
2881
2882 fContext = 0;
2883 } else {
2884#ifdef DEBUG_ROOT_COCOA
2885 NSLog(@"QuartzView: -drawRect: method, no window for id %u was found", fID);
2886#endif
2887 }
2888 }
2889}
2890
2891#pragma mark - Geometry.
2892
2893//______________________________________________________________________________
2894- (void) setFrame : (NSRect) newFrame
2895{
2896 //In case of TBrowser, setFrame started infinite recursion:
2897 //HandleConfigure for embedded main frame emits signal, slot
2898 //calls layout, layout calls setFrame -> HandleConfigure and etc. etc.
2899 if (NSEqualRects(newFrame, self.frame))
2900 return;
2901
2902 [super setFrame : newFrame];
2903}
2904
2905//______________________________________________________________________________
2906- (void) setFrameSize : (NSSize) newSize
2907{
2908 //Check, if setFrameSize calls setFrame.
2909
2910 [super setFrameSize : newSize];
2911
2912 if ((fEventMask & kStructureNotifyMask) && (self.fMapState == kIsViewable || fIsOverlapped == YES)) {
2913 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2914 "setFrameSize:, gVirtualX is either null or has a type, different from TGCocoa");
2915 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2916 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2917 }
2918
2919 [self setNeedsDisplay : YES];//?
2920}
2921
2922#pragma mark - Event handling.
2923
2924//______________________________________________________________________________
2925- (void) mouseDown : (NSEvent *) theEvent
2926{
2927 assert(fID != 0 && "-mouseDown:, fID is 0");
2928
2929 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2930 "-mouseDown:, gVirtualX is either null or has a type, different from TGCocoa");
2931 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2933}
2934
2935//______________________________________________________________________________
2936- (void) scrollWheel : (NSEvent*) theEvent
2937{
2938 assert(fID != 0 && "-scrollWheel:, fID is 0");
2939
2940
2941 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2942 "-scrollWheel:, gVirtualX is either null or has a type, different from TGCocoa");
2943
2944 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2945 const CGFloat deltaY = [theEvent deltaY];
2946 if (deltaY < 0) {
2949 } else if (deltaY > 0) {
2952 }
2953}
2954
2955#ifdef DEBUG_ROOT_COCOA
2956//______________________________________________________________________________
2957- (void) printViewInformation
2958{
2959 assert(fID != 0 && "-printWindowInformation, fID is 0");
2960 const TGWindow * const window = gClient->GetWindowById(fID);
2961 assert(window != 0 && "printWindowInformation, window not found");
2962
2963 NSLog(@"-----------------View %u info:---------------------", fID);
2964 NSLog(@"ROOT's window class is %s", window->IsA()->GetName());
2965 NSLog(@"event mask is:");
2966 print_mask_info(fEventMask);
2967 NSLog(@"grab mask is:");
2968 print_mask_info(fPassiveGrabEventMask);
2969 NSLog(@"view's geometry: x == %g, y == %g, w == %g, h == %g", self.frame.origin.x,
2970 self.frame.origin.y, self.frame.size.width, self.frame.size.height);
2971 NSLog(@"----------------End of view info------------------");
2972}
2973#endif
2974
2975//______________________________________________________________________________
2976- (void) rightMouseDown : (NSEvent *) theEvent
2977{
2978 assert(fID != 0 && "-rightMouseDown:, fID is 0");
2979
2980#ifdef DEBUG_ROOT_COCOA
2981 [self printViewInformation];
2982#endif
2983
2984 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2985 "-rightMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2986 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2988}
2989
2990//______________________________________________________________________________
2991- (void) otherMouseDown : (NSEvent *) theEvent
2992{
2993 assert(fID != 0 && "-otherMouseDown:, fID is 0");
2994
2995 //Funny enough, [theEvent buttonNumber] is not the same thing as button masked in [NSEvent pressedMouseButtons],
2996 //button number actually is a kind of right operand for bitshift for pressedMouseButtons.
2997 if ([theEvent buttonNumber] == 2) {//this '2' will correspond to '4' in pressedMouseButtons.
2998 //I do not care about mouse buttons after left/right/wheel - ROOT does not have
2999 //any code for this.
3000 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3001 "-otherMouseDown:, gVirtualX is either null or has type different from TGCocoa");
3002 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3004 }
3005}
3006
3007//______________________________________________________________________________
3008- (void) mouseUp : (NSEvent *) theEvent
3009{
3010 assert(fID != 0 && "-mouseUp:, fID is 0");
3011
3012 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
3013 "-mouseUp:, gVirtualX is either null or has type different from TGCocoa");
3014 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3016}
3017
3018//______________________________________________________________________________
3019- (void) rightMouseUp : (NSEvent *) theEvent
3020{
3021
3022 assert(fID != 0 && "-rightMouseUp:, fID is 0");
3023
3024 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3025 "-rightMouseUp:, gVirtualX is either null or has type different from TGCocoa");
3026
3027 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3029}
3030
3031//______________________________________________________________________________
3032- (void) otherMouseUp : (NSEvent *) theEvent
3033{
3034 assert(fID != 0 && "-otherMouseUp:, fID is 0");
3035
3036 //Here I assume it's always kButton2.
3037 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3038 "-otherMouseUp:, gVirtualX is either null or has type different from TGCocoa");
3039 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3041}
3042
3043//______________________________________________________________________________
3044- (void) mouseEntered : (NSEvent *) theEvent
3045{
3046 assert(fID != 0 && "-mouseEntered:, fID is 0");
3047 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3048 "-mouseEntered:, gVirtualX is null or not of TGCocoa type");
3049
3050 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3052}
3053
3054//______________________________________________________________________________
3055- (void) mouseExited : (NSEvent *) theEvent
3056{
3057 assert(fID != 0 && "-mouseExited:, fID is 0");
3058
3059 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3060 "-mouseExited:, gVirtualX is null or not of TGCocoa type");
3061
3062 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3064}
3065
3066//______________________________________________________________________________
3067- (void) mouseMoved : (NSEvent *) theEvent
3068{
3069 assert(fID != 0 && "-mouseMoved:, fID is 0");
3070
3071 if (fParentView)//Suppress events in all views, except the top-level one.
3072 return;
3073
3074 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3075 "-mouseMoved:, gVirtualX is null or not of TGCocoa type");
3076
3077 TGCocoa *vx = static_cast<TGCocoa *>(gVirtualX);
3079}
3080
3081//______________________________________________________________________________
3082- (void) mouseDragged : (NSEvent *) theEvent
3083{
3084 assert(fID != 0 && "-mouseDragged:, fID is 0");
3085
3086 TGCocoa * const vx = dynamic_cast<TGCocoa *>(gVirtualX);
3087 assert(vx != 0 && "-mouseDragged:, gVirtualX is null or not of TGCocoa type");
3088
3090}
3091
3092//______________________________________________________________________________
3093- (void) rightMouseDragged : (NSEvent *) theEvent
3094{
3095 assert(fID != 0 && "-rightMouseDragged:, fID is 0");
3096
3097 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3098 "-rightMouseDragged:, gVirtualX is null or not of TGCocoa type");
3099
3100 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3102}
3103
3104//______________________________________________________________________________
3105- (void) otherMouseDragged : (NSEvent *) theEvent
3106{
3107 assert(fID != 0 && "-otherMouseDragged:, fID is 0");
3108
3109 if ([theEvent buttonNumber] == 2) {
3110 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3111 "-otherMouseDragged:, gVirtualX is null or not of TGCocoa type");
3112 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3114 }
3115}
3116
3117//______________________________________________________________________________
3118- (void) keyDown : (NSEvent *) theEvent
3119{
3120 assert(fID != 0 && "-keyDown:, fID is 0");
3121
3122 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3123 "-keyDown:, gVirtualX is null or not of TGCocoa type");
3124
3125 NSView<X11Window> *eventView = self;
3126 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3127 eventView = pointerView;
3128
3129 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3130 vx->GetEventTranslator()->GenerateKeyPressEvent(eventView, theEvent);
3131}
3132
3133//______________________________________________________________________________
3134- (void) keyUp : (NSEvent *) theEvent
3135{
3136 assert(fID != 0 && "-keyUp:, fID is 0");
3137
3138 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3139 "-keyUp:, gVirtualX is null or not of TGCocoa type");
3140
3141 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3142 NSView<X11Window> *eventView = self;
3143 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3144 eventView = pointerView;
3145
3146 vx->GetEventTranslator()->GenerateKeyReleaseEvent(eventView, theEvent);
3147}
3148
3149#pragma mark - First responder stuff.
3150
3151//______________________________________________________________________________
3152- (BOOL) acceptsFirstMouse : (NSEvent *) theEvent
3153{
3154#pragma unused(theEvent)
3155 return YES;
3156}
3157
3158//______________________________________________________________________________
3159- (BOOL) acceptsFirstResponder
3160{
3161 return YES;
3162}
3163
3164#pragma mark - Cursors.
3165
3166//______________________________________________________________________________
3167- (void) setFCurrentCursor : (ECursor) cursor
3168{
3169 if (cursor != fCurrentCursor) {
3170 fCurrentCursor = cursor;
3171 [self.fQuartzWindow invalidateCursorRectsForView : self];
3172 }
3173}
3174
3175//______________________________________________________________________________
3176- (NSCursor *) createCustomCursor
3177{
3178 const char *pngFileName = 0;
3179
3180 switch (fCurrentCursor) {
3181 case kMove:
3182 pngFileName = "move_cursor.png";
3183 break;
3184 case kArrowHor:
3185 pngFileName = "hor_arrow_cursor.png";
3186 break;
3187 case kArrowVer:
3188 pngFileName = "ver_arrow_cursor.png";
3189 break;
3190 case kArrowRight:
3191 pngFileName = "right_arrow_cursor.png";
3192 break;
3193 case kRotate:
3194 pngFileName = "rotate.png";
3195 break;
3196 case kBottomLeft:
3197 case kTopRight:
3198 pngFileName = "top_right_cursor.png";
3199 break;
3200 case kTopLeft:
3201 case kBottomRight:
3202 pngFileName = "top_left_cursor.png";
3203 break;
3204 default:;
3205 }
3206
3207 if (pngFileName) {
3208 const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
3209 const Util::ScopedArray<const char> arrayGuard(path);
3210
3211 if (!path || path[0] == 0) {
3212 //File was not found.
3213 return nil;
3214 }
3215
3216 NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
3217 NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
3218
3219 if (!cursorImage)
3220 return nil;
3221
3222 NSPoint hotSpot = X11::GetCursorHotStop(cursorImage, fCurrentCursor);
3223 NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
3224 hotSpot : hotSpot] autorelease];
3225
3226 [cursorImage release];
3227
3228 return customCursor;
3229 }
3230
3231 return nil;
3232}
3233
3234//______________________________________________________________________________
3235- (void) resetCursorRects
3236{
3237 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor))
3238 [self addCursorRect : self.visibleRect cursor : cursor];
3239}
3240
3241//______________________________________________________________________________
3242- (void) cursorUpdate
3243{
3244 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor)) {
3245 // NB: [window invalidateCursorRectsForView] called here has the
3246 // same problem as commented below in -cursorUpdate:.
3247 [cursor set];
3248 }
3249}
3250
3251//______________________________________________________________________________
3252- (void) cursorUpdate : (NSEvent *) event
3253{
3254#pragma unused(event)
3255 // It looks like [NSCursor set] method does not work properly when called from
3256 // cursorUpdate:, having, say, a parent frame with 'arrow' cursor and a child (completely
3257 // filling its parent's area) with 'cross', it happens the 'cross' cursor is not always
3258 // set correctly, for example:
3259 // if we have a TCanvas and resize it, cursor is 'arrow' inside this canvas,
3260 // though it must be 'cross'. This all, as it always happesn with "thinking different"
3261 // Apple is somehow related to run loop or something. As always, it's not documented,
3262 // so Apple can continue to think different. The idea with performSelector comes from:
3263 // http://stackoverflow.com/questions/8430236/nscursor-set-method-has-no-effect
3264 // Or may be it's just a bug:
3265 // http://stackoverflow.com/questions/13901232/nscursor-set-not-working-on-unfocused-window
3266 [self performSelector : @selector(cursorUpdate) withObject : nil afterDelay : 0.05f];
3267}
3268
3269#pragma mark - Emulated X11 properties.
3270
3271//______________________________________________________________________________
3272- (void) setProperty : (const char *) propName data : (unsigned char *) propData
3273 size : (unsigned) dataSize forType : (Atom_t) dataType format : (unsigned) format
3274{
3275 assert(propName != 0 && "-setProperty:data:size:forType:, parameter 'propName' is null");
3276 assert(propData != 0 && "-setProperty:data:size:forType:, parameter 'propData' is null");
3277 assert(dataSize != 0 && "-setProperty:data:size:forType:, parameter 'dataSize' is 0");
3278
3279 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3280 QuartzWindowProperty * property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3281
3282 //At the moment (and I think this will never change) TGX11 always calls XChangeProperty with PropModeReplace.
3283 if (property)
3284 [property resetPropertyData : propData size : dataSize type : dataType format : format];
3285 else {
3286 //No property found, add a new one.
3287 property = [[QuartzWindowProperty alloc] initWithData : propData size : dataSize
3288 type : dataType format : format];
3289 [fX11Properties setObject : property forKey : key];
3290 [property release];
3291 }
3292}
3293
3294//______________________________________________________________________________
3295- (BOOL) hasProperty : (const char *) propName
3296{
3297 assert(propName != 0 && "-hasProperty:, propName parameter is null");
3298
3299 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3300 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3301
3302 return property != nil;
3303}
3304
3305//______________________________________________________________________________
3306- (unsigned char *) getProperty : (const char *) propName returnType : (Atom_t *) type
3307 returnFormat : (unsigned *) format nElements : (unsigned *) nElements
3308{
3309 assert(propName != 0 &&
3310 "-getProperty:returnType:returnFormat:nElements:, parameter 'propName' is null");
3311 assert(type != 0 &&
3312 "-getProperty:returnType:returnFormat:nElements:, parameter 'type' is null");
3313 assert(format != 0 &&
3314 "-getProperty:returnType:returnFormat:nElements:, parameter 'format' is null");
3315 assert(nElements != 0 &&
3316 "-getProperty:returnType:returnFormat:nElements:, parameter 'nElements' is null");
3317
3318 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3319 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3320 assert(property != 0 &&
3321 "-getProperty:returnType:returnFormat:nElements, property not found");
3322
3323 NSData * const propData = property.fPropertyData;
3324
3325 const NSUInteger dataSize = [propData length];
3326 unsigned char *buff = 0;
3327 try {
3328 buff = new unsigned char[dataSize]();
3329 } catch (const std::bad_alloc &) {
3330 //Hmm, can I log, if new failed? :)
3331 NSLog(@"QuartzWindow: -getProperty:returnType:returnFormat:nElements:,"
3332 " memory allocation failed");
3333 return 0;
3334 }
3335
3336 [propData getBytes : buff length : dataSize];
3337 *format = property.fFormat;
3338
3339 *nElements = dataSize;
3340
3341 if (*format == 16)
3342 *nElements= dataSize / 2;
3343 else if (*format == 32)
3344 *nElements = dataSize / 4;
3345
3346 *type = property.fType;
3347
3348 return buff;
3349}
3350
3351//______________________________________________________________________________
3352- (void) removeProperty : (const char *) propName
3353{
3354 assert(propName != 0 && "-removeProperty:, parameter 'propName' is null");
3355
3356 NSString * const key = [NSString stringWithCString : propName
3357 encoding : NSASCIIStringEncoding];
3358 [fX11Properties removeObjectForKey : key];
3359}
3360
3361//DND
3362//______________________________________________________________________________
3363- (NSDragOperation) draggingEntered : (id<NSDraggingInfo>) sender
3364{
3365 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3366 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3367
3368 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy))
3369 return NSDragOperationCopy;
3370
3371 return NSDragOperationNone;
3372}
3373
3374//______________________________________________________________________________
3375- (BOOL) performDragOperation : (id<NSDraggingInfo>) sender
3376{
3377 //We can drag some files (images, pdfs, source code files) from
3378 //finder to ROOT's window (mainly TCanvas or text editor).
3379 //The logic is totally screwed here :((( - ROOT will try to
3380 //read a property of some window (not 'self', unfortunately) -
3381 //this works since on Window all data is in a global clipboard
3382 //(on X11 it simply does not work at all).
3383 //I'm attaching the file name as a property for the top level window,
3384 //there is no other way to make this data accessible for ROOT.
3385
3386 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3387 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3388
3389 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy)) {
3390
3391 //Here I try to put string ("file://....") into window's property to make
3392 //it accesible from ROOT's GUI.
3393 const Atom_t textUriAtom = gVirtualX->InternAtom("text/uri-list", kFALSE);
3394
3395 NSArray * const files = [pasteBoard propertyListForType : NSFilenamesPboardType];
3396 for (NSString *path in files) {
3397 //ROOT can not process several files, use the first one.
3398 NSString * const item = [@"file://" stringByAppendingString : path];
3399 //Yes, only ASCII encoding, but after all, ROOT's not able to work with NON-ASCII strings.
3400 const NSUInteger len = [item lengthOfBytesUsingEncoding : NSASCIIStringEncoding] + 1;
3401 try {
3402 std::vector<unsigned char> propertyData(len);
3403 [item getCString : (char *)&propertyData[0] maxLength : propertyData.size()
3404 encoding : NSASCIIStringEncoding];
3405 //There is no any guarantee, that this will ever work, logic in TGDNDManager is totally crazy.
3406 NSView<X11Window> * const targetView = self.fQuartzWindow.fContentView;
3407 [targetView setProperty : "_XC_DND_DATA" data : &propertyData[0]
3408 size : propertyData.size() forType : textUriAtom format : 8];
3409 } catch (const std::bad_alloc &) {
3410 //Hehe, can I log something in case of bad_alloc??? ;)
3411 NSLog(@"QuartzView: -performDragOperation:, memory allocation failed");
3412 return NO;
3413 }
3414
3415 break;
3416 }
3417
3418 //Property is attached now.
3419
3420 //Gdk on windows creates three events on file drop (WM_DROPFILES): XdndEnter, XdndPosition, XdndDrop.
3421 //1. Dnd enter.
3422 Event_t event1 = {};
3423 event1.fType = kClientMessage;
3424 event1.fWindow = fID;
3425 event1.fHandle = gVirtualX->InternAtom("XdndEnter", kFALSE);
3426 event1.fUser[0] = long(fID);
3427 event1.fUser[2] = textUriAtom;//gVirtualX->InternAtom("text/uri-list", kFALSE);
3428 //
3429 gVirtualX->SendEvent(fID, &event1);
3430
3431 //2. Dnd position.
3432 Event_t event2 = {};
3433 event2.fType = kClientMessage;
3434 event2.fWindow = fID;
3435 event2.fHandle = gVirtualX->InternAtom("XdndPosition", kFALSE);
3436 event2.fUser[0] = long(fID);
3437 event2.fUser[2] = 0;//Here I have to pack x and y for drop coordinates, shifting by 16 bits.
3438 NSPoint dropPoint = [sender draggingLocation];
3439 //convertPointFromBase is deprecated.
3440 //dropPoint = [self convertPointFromBase : dropPoint];
3441 dropPoint = [self convertPoint : dropPoint fromView : nil];
3442 //
3443 dropPoint = X11::TranslateToScreen(self, dropPoint);
3444 event2.fUser[2] = UShort_t(dropPoint.y) | (UShort_t(dropPoint.x) << 16);
3445
3446 gVirtualX->SendEvent(fID, &event2);
3447
3448 Event_t event3 = {};
3449 event3.fType = kClientMessage;
3450 event3.fWindow = fID;
3451 event3.fHandle = gVirtualX->InternAtom("XdndDrop", kFALSE);
3452
3453 gVirtualX->SendEvent(fID, &event3);
3454 }
3455
3456 return YES;//Always ok, even if file type is not supported - no need in "animation".
3457}
3458
3459@end
long
Definition: Converters.cxx:858
Cppyy::TCppType_t fClass
@ kClientMessage
Definition: GuiTypes.h:62
const Mask_t kWABorderPixel
Definition: GuiTypes.h:141
const Mask_t kWAOverrideRedirect
Definition: GuiTypes.h:148
const Mask_t kWABitGravity
Definition: GuiTypes.h:143
const Mask_t kWADontPropagate
Definition: GuiTypes.h:151
const Mask_t kWAColormap
Definition: GuiTypes.h:152
const Mask_t kButtonMotionMask
Definition: GuiTypes.h:163
const Mask_t kWABackingStore
Definition: GuiTypes.h:145
const Mask_t kButtonPressMask
Definition: GuiTypes.h:160
const Mask_t kExposureMask
Definition: GuiTypes.h:164
const Mask_t kWAEventMask
Definition: GuiTypes.h:150
const Mask_t kWASaveUnder
Definition: GuiTypes.h:149
const Mask_t kWABackPixel
Definition: GuiTypes.h:139
const Mask_t kWAWinGravity
Definition: GuiTypes.h:144
const Mask_t kWABackingPixel
Definition: GuiTypes.h:147
const Mask_t kPointerMotionMask
Definition: GuiTypes.h:162
Handle_t Atom_t
Definition: GuiTypes.h:36
const Mask_t kLeaveWindowMask
Definition: GuiTypes.h:167
const Mask_t kStructureNotifyMask
Definition: GuiTypes.h:165
@ kIsViewable
Definition: GuiTypes.h:45
@ kIsUnviewable
Definition: GuiTypes.h:45
@ kIsUnmapped
Definition: GuiTypes.h:45
@ kAlways
Definition: GuiTypes.h:44
UInt_t Mask_t
Definition: GuiTypes.h:40
const Mask_t kButtonReleaseMask
Definition: GuiTypes.h:161
ECursor
Definition: GuiTypes.h:371
@ kRightSide
Definition: GuiTypes.h:372
@ kBottomSide
Definition: GuiTypes.h:372
@ kArrowRight
Definition: GuiTypes.h:374
@ kTopLeft
Definition: GuiTypes.h:371
@ kBottomRight
Definition: GuiTypes.h:371
@ kArrowVer
Definition: GuiTypes.h:373
@ kCaret
Definition: GuiTypes.h:374
@ kTopSide
Definition: GuiTypes.h:372
@ kLeftSide
Definition: GuiTypes.h:372
@ kWatch
Definition: GuiTypes.h:374
@ kMove
Definition: GuiTypes.h:373
@ kTopRight
Definition: GuiTypes.h:371
@ kBottomLeft
Definition: GuiTypes.h:371
@ kHand
Definition: GuiTypes.h:373
@ kCross
Definition: GuiTypes.h:373
@ kRotate
Definition: GuiTypes.h:373
@ kArrowHor
Definition: GuiTypes.h:373
@ kPointer
Definition: GuiTypes.h:374
const Mask_t kWABorderPixmap
Definition: GuiTypes.h:140
const Mask_t kEnterWindowMask
Definition: GuiTypes.h:166
const Mask_t kWACursor
Definition: GuiTypes.h:153
@ kButton4
Definition: GuiTypes.h:214
@ kButton2
Definition: GuiTypes.h:213
@ kButton5
Definition: GuiTypes.h:214
@ kButton3
Definition: GuiTypes.h:213
@ kButton1
Definition: GuiTypes.h:213
Handle_t Window_t
Definition: GuiTypes.h:28
const Mask_t kWABackPixmap
Definition: GuiTypes.h:138
const Mask_t kWABorderWidth
Definition: GuiTypes.h:142
const Mask_t kWABackingPlanes
Definition: GuiTypes.h:146
#define d(i)
Definition: RSha256.hxx:102
#define h(i)
Definition: RSha256.hxx:106
unsigned short UShort_t
Definition: RtypesCore.h:38
int Int_t
Definition: RtypesCore.h:43
unsigned int UInt_t
Definition: RtypesCore.h:44
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
const Bool_t kTRUE
Definition: RtypesCore.h:89
#define gClient
Definition: TGClient.h:166
XFontStruct * id
Definition: TGX11.cxx:108
int type
Definition: TGX11.cxx:120
typedef void((*Func_t)())
@ kReadPermission
Definition: TSystem.h:46
R__EXTERN TSystem * gSystem
Definition: TSystem.h:556
#define gVirtualX
Definition: TVirtualX.h:338
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:674
void GenerateFocusChangeEvent(NSView< X11Window > *eventView)
Definition: X11Events.mm:1321
void GenerateExposeEvent(NSView< X11Window > *view, const NSRect &exposedRect)
Definition: X11Events.mm:1174
void GenerateConfigureNotifyEvent(NSView< X11Window > *view, const NSRect &newFrame)
Definition: X11Events.mm:1149
void GenerateCrossingEvent(NSEvent *theEvent)
Definition: X11Events.mm:1192
void GenerateKeyReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1301
void GenerateKeyPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1285
void GenerateButtonPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1257
void GeneratePointerMotionEvent(NSEvent *theEvent)
Definition: X11Events.mm:1244
void GenerateButtonReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1270
This class implements TVirtualX interface for MacOS X, using Cocoa and Quartz 2D.
Definition: TGCocoa.h:58
ROOT::MacOSX::X11::CommandBuffer * GetCommandBuffer() const
Definition: TGCocoa.mm:4370
void CocoaDrawOFF()
Definition: TGCocoa.mm:4382
static Atom_t fgDeleteWindowAtom
Definition: TGCocoa.h:469
ROOT::MacOSX::X11::Rectangle GetDisplayGeometry() const
Definition: TGCocoa.mm:576
ROOT::MacOSX::X11::EventTranslator * GetEventTranslator() const
Definition: TGCocoa.mm:4364
void CocoaDrawON()
Definition: TGCocoa.mm:4376
virtual const char * GetName() const
Return unique name, used in SavePrimitive methods.
Definition: TGWindow.cxx:326
@ kIsHtmlView
Definition: TGWindow.h:70
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
static const TString & GetIconPath()
Get the icon path in the installation. Static utility function.
Definition: TROOT.cxx:3055
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition: TSystem.cxx:1541
unsigned int fModifiers
Definition: cppyy.h:12
TLine * line
instancetype init()
unichar fKeyCode
Definition: QuartzWindow.h:165
NSUInteger fModifiers
Definition: QuartzWindow.h:166
ROOT::MacOSX::Util::CFScopeGuard< CGImageRef > fImage
Definition: QuartzPixmap.h:96
unsigned fWidth
Definition: QuartzPixmap.h:93
unsigned fHeight
Definition: QuartzPixmap.h:94
unsigned fHeight
Definition: QuartzPixmap.h:38
unsigned fWidth
Definition: QuartzPixmap.h:37
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:207
unsigned fPassiveGrabKeyModifiers
Definition: QuartzWindow.h:200
void raiseWindow()
ECursor fCurrentCursor
Definition: QuartzWindow.h:204
void activateImplicitGrab()
BOOL fSnapshotDraw
Definition: QuartzWindow.h:203
BOOL fIsDNDAware
Definition: QuartzWindow.h:205
NSMutableArray * fPassiveKeyGrabs
Definition: QuartzWindow.h:208
int fPassiveGrabButton
Definition: QuartzWindow.h:198
CGFloat fScaleFactor()
BOOL fHasFocus
Definition: QuartzWindow.h:195
BOOL fActiveGrabOwnerEvents
Definition: QuartzWindow.h:216
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:269
void mapSubwindows()
void configureNotifyTree()
void activatePassiveGrab()
CGContextRef fContext
Definition: QuartzWindow.h:186
NSMutableDictionary * fX11Properties
Definition: QuartzWindow.h:211
BOOL fPassiveGrabOwnerEvents
Definition: QuartzWindow.h:202
void lowerWindow()
BOOL fIsOpenGLWidget()
unsigned fWidth()
QuartzView * fParentView
Definition: QuartzWindow.h:196
unsigned fID
Definition: QuartzWindow.h:185
unsigned fPassiveGrabEventMask
Definition: QuartzWindow.h:199
QuartzImage * fBackgroundPixmap
Definition: QuartzWindow.h:212
void unmapWindow()
ROOT::MacOSX::X11::PointerGrab fCurrentGrabType
Definition: QuartzWindow.h:214
BOOL fIsOverlapped
Definition: QuartzWindow.h:209
long fEventMask
Definition: QuartzWindow.h:187
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:192
unsigned fActiveGrabEventMask
Definition: QuartzWindow.h:201
unsigned fHeight()
BOOL fOverrideRedirect
Definition: QuartzWindow.h:193
NSView< X11Window > * fContentView
Definition: QuartzWindow.h:268
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:129
QuartzView * fParentView
Definition: QuartzWindow.h:138
void addCrosshairWindow()
BOOL fIsOpenGLWidget()
unsigned fHeight()
CGFloat fScaleFactor()
BOOL fDelayedTransient
Definition: QuartzWindow.h:62
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:140
CrosshairWindow * findCrosshairWindow()
QuartzWindow * fMainWindow
Definition: QuartzWindow.h:58
void adjustCrosshairWindowGeometry()
void removeCrosshairWindow()
QuartzView * fContentView
Definition: QuartzWindow.h:61
unsigned fWidth()
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:63
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
EvaluateInfo init(std::vector< RooRealProxy > parameters, std::vector< ArrayWrapper * > wrappers, std::vector< double * > arrays, size_t begin, size_t batchSize)
const NSUInteger kMiniaturizableWindowMask
const NSEventType kLeftMouseDown
const NSEventType kRightMouseDown
const NSUInteger kTitledWindowMask
const NSUInteger kResizableWindowMask
const NSUInteger kClosableWindowMask
const NSUInteger kBorderlessWindowMask
NSCursor * CreateCustomCursor(ECursor currentCursor)
int GlobalYROOTToCocoa(CGFloat yROOT)
NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
bool ViewIsHtmlViewFrame(NSView< X11Window > *view, bool checkParent)
int GlobalYCocoaToROOT(CGFloat yCocoa)
void PixelToRGB(Pixel_t pixelColor, CGFloat *rgb)
Definition: X11Colors.mm:920
bool ViewIsTextView(NSView< X11Window > *view)
NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
NSPoint TranslateToScreen(NSView< X11Window > *from, NSPoint point)
CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
bool ScreenPointIsInView(NSView< X11Window > *view, Int_t x, Int_t y)
NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
void GetWindowGeometry(NSObject< X11Window > *win, WindowAttributes_t *dst)
void GetWindowAttributes(NSObject< X11Window > *window, WindowAttributes_t *dst)
NSView< X11Window > * FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
NSView< X11Window > * FrameForHtmlView(NSView< X11Window > *htmlView)
QuartzWindow * FindWindowInPoint(Int_t x, Int_t y)
int GlobalXCocoaToROOT(CGFloat xCocoa)
void WindowLostFocus(Window_t winID)
int LocalYROOTToCocoa(NSView< X11Window > *parentView, CGFloat yROOT)
NSView< X11Window > * FindViewForPointerEvent(NSEvent *pointerEvent)
NSView< X11Window > * FrameForTextView(NSView< X11Window > *textView)
NSComparisonResult CompareViewsToLower(id view1, id view2, void *context)
int LocalYCocoaToROOT(NSView< X11Window > *parentView, CGFloat yCocoa)
NSPoint TranslateCoordinates(NSView< X11Window > *fromView, NSView< X11Window > *toView, NSPoint sourcePoint)
QuartzWindow * CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t)
Definition: QuartzWindow.mm:56
NSView< X11Window > * FindViewUnderPointer()
void UnlockFocus(NSView< X11Window > *view)
int GlobalXROOTToCocoa(CGFloat xROOT)
bool ViewIsHtmlView(NSView< X11Window > *view)
QuartzView * CreateChildView(QuartzView *parent, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t wtype)
Definition: QuartzWindow.mm:85
bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
QuartzWindow * FindWindowForPointerEvent(NSEvent *pointerEvent)
bool ViewIsTextView(unsigned viewID)
void GetRootWindowAttributes(WindowAttributes_t *attr)
bool ViewIsHtmlView(unsigned viewID)
QuartzWindow * FindWindowUnderPointer()
bool ViewIsTextViewFrame(NSView< X11Window > *view, bool checkParent)
NSPoint TranslateFromScreen(NSPoint point, NSView< X11Window > *to)
void ClipToShapeMask(NSView< X11Window > *view, CGContextRef ctx)
void SetWindowAttributes(const SetWindowAttributes_t *attr, NSObject< X11Window > *window)
NSCursor * CreateCursor(ECursor currentCursor)
bool LockFocus(NSView< X11Window > *view)
NSComparisonResult CompareViewsToRaise(id view1, id view2, void *context)
std::vector< unsigned char > DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
unsigned fID
Definition: X11Drawable.h:37
QuartzView * fParentView
Definition: X11Drawable.h:100
EGEventType fType
Definition: GuiTypes.h:174
Handle_t fHandle
Definition: GuiTypes.h:184
Int_t fFormat
Definition: GuiTypes.h:185
Window_t fWindow
Definition: GuiTypes.h:175
Long_t fUser[5]
Definition: GuiTypes.h:186
ULong_t fBackgroundPixel
Definition: GuiTypes.h:94
Window_t fRoot
Definition: GuiTypes.h:119
ULong_t fBackingPlanes
Definition: GuiTypes.h:124
Long_t fAllEventMasks
Definition: GuiTypes.h:130
ULong_t fBackingPixel
Definition: GuiTypes.h:125
Long_t fYourEventMask
Definition: GuiTypes.h:131
Bool_t fMapInstalled
Definition: GuiTypes.h:128
Colormap_t fColormap
Definition: GuiTypes.h:127
Bool_t fOverrideRedirect
Definition: GuiTypes.h:133