Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 |
68 kMiniaturizableWindowMask | kResizableWindowMask;
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//______________________________________________________________________________
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 XorDrawingView
1126{
1127 std::vector<ROOT::MacOSX::X11::Command *> xorOps;
1128}
1129
1130- (void) setXorOperations : (const std::vector<ROOT::MacOSX::X11::Command *> &) primitives
1131{
1132 xorOps = primitives;
1133}
1134
1135- (void) drawRect : (NSRect) dirtyRect
1136{
1137 [super drawRect:dirtyRect];
1138 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
1139 if (!nsContext)
1140 return;
1141
1142 CGContextRef cgContext = nsContext.CGContext;
1143 if (!cgContext)
1144 return;
1145
1146 const Quartz::CGStateGuard ctxGuard(cgContext);
1147
1148 CGContextSetRGBStrokeColor(cgContext, 0., 0., 0., 1.);
1149 CGContextSetLineWidth(cgContext, 1.);
1150
1151 for (auto *command : xorOps) {
1152 command->Execute(cgContext);
1153 delete command;
1154 }
1155
1156 xorOps.clear();
1157}
1158
1159@end
1160
1161@implementation XorDrawingWindow
1162
1163- (instancetype) init
1164{
1165 if (self = [super init])
1166 {
1167 self.styleMask = NSWindowStyleMaskBorderless; // No titlebar, buttons, etc.
1168 self.opaque = NO;
1169 self.hasShadow = NO;
1170 self.backgroundColor = NSColor.clearColor; // No background.
1171 self.ignoresMouseEvents = YES; // Lets mouse events pass through.
1172 self.contentView = [[XorDrawingView alloc] init];
1173 }
1174 return self;
1175}
1176
1177#pragma mark - suppress the normal window behavior.
1178- (BOOL)canBecomeKeyWindow
1179{
1180 return NO;
1181}
1182- (BOOL)canBecomeMainWindow
1183{
1184 return NO;
1185}
1186
1187@end
1188
1189
1190@implementation QuartzWindow
1191
1192@synthesize fMainWindow;
1193@synthesize fHasFocus;
1194
1195#pragma mark - QuartzWindow's life cycle.
1196
1197//______________________________________________________________________________
1198- (id) initWithContentRect : (NSRect) contentRect styleMask : (NSUInteger) windowStyle
1199 backing : (NSBackingStoreType) bufferingType defer : (BOOL) deferCreation
1200 windowAttributes : (const SetWindowAttributes_t *) attr
1201{
1202 self = [super initWithContentRect : contentRect styleMask : windowStyle
1203 backing : bufferingType defer : deferCreation];
1204
1205 if (self) {
1206 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1207 [self setAllowsConcurrentViewDrawing : NO];
1208
1209 self.delegate = self;
1210 //create content view here.
1211 NSRect contentViewRect = contentRect;
1212 contentViewRect.origin.x = 0.f;
1213 contentViewRect.origin.y = 0.f;
1214
1215 fContentView = [[QuartzView alloc] initWithFrame : contentViewRect windowAttributes : 0];
1216
1217 [self setContentView : fContentView];
1218
1219 [fContentView release];
1220 fDelayedTransient = NO;
1221
1222 if (attr)
1223 X11::SetWindowAttributes(attr, self);
1224
1225 fIsDeleted = NO;
1226 fHasFocus = NO;
1227 }
1228
1229 return self;
1230}
1231
1232//______________________________________________________________________________
1233- (id) initWithGLView : (ROOTOpenGLView *) glView
1234{
1235 using namespace Details;
1236
1237 assert(glView != nil && "-initWithGLView, parameter 'glView' is nil");
1238
1239 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
1241
1242 NSRect contentRect = glView.frame;
1243 contentRect.origin = NSPoint();
1244
1245 self = [super initWithContentRect : contentRect styleMask : styleMask
1246 backing : NSBackingStoreBuffered defer : NO];
1247
1248 if (self) {
1249 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1250 [self setAllowsConcurrentViewDrawing : NO];
1251 self.delegate = self;
1252 fContentView = glView;
1253 [self setContentView : fContentView];
1254 fDelayedTransient = NO;
1255 fIsDeleted = NO;
1256 fHasFocus = NO;
1257 }
1258
1259 return self;
1260}
1261
1262//______________________________________________________________________________
1263- (void) dealloc
1264{
1265 [fShapeCombineMask release];
1266 [super dealloc];
1267}
1268
1269//______________________________________________________________________________
1270- (BOOL) fIsDeleted
1271{
1272 return fIsDeleted;
1273}
1274
1275//______________________________________________________________________________
1276- (void) setContentView:(NSView *)cv
1277{
1278 [super setContentView:cv];
1279 if ([cv isKindOfClass:[QuartzView class]])
1280 fContentView = (QuartzView *)cv;
1281 else
1282 fContentView = nil;
1283}
1284
1285//______________________________________________________________________________
1286- (void) setFIsDeleted : (BOOL) deleted
1287{
1288 fIsDeleted = deleted;
1289}
1290
1291#pragma mark - Forwaring: I want to forward a lot of property setters/getters to the content view.
1292
1293//______________________________________________________________________________
1294- (void) forwardInvocation : (NSInvocation *) anInvocation
1295{
1296 if (!fContentView)
1297 return;
1298
1299 if ([fContentView respondsToSelector : [anInvocation selector]]) {
1300 [anInvocation invokeWithTarget : fContentView];
1301 } else {
1302 [super forwardInvocation : anInvocation];
1303 }
1304}
1305
1306//______________________________________________________________________________
1307- (NSMethodSignature*) methodSignatureForSelector : (SEL) selector
1308{
1309 NSMethodSignature *signature = [super methodSignatureForSelector : selector];
1310
1311 if (!signature) {
1312 if (fContentView)
1313 signature = [fContentView methodSignatureForSelector : selector];
1314 }
1315
1316 return signature;
1317}
1318
1319//______________________________________________________________________________
1320- (void) addTransientWindow : (QuartzWindow *) window
1321{
1322 //Transient window: all the popups (menus, dialogs, popups, comboboxes, etc.)
1323 //always should be on the top of its 'parent' window.
1324 //To enforce this ordering, I have to connect such windows with parent/child
1325 //relation (it's not the same as a view hierarchy - both child and parent
1326 //windows are top-level windows).
1327
1328 assert(window != nil && "-addTransientWindow:, parameter 'window' is nil");
1329
1330 window.fMainWindow = self;
1331
1332 if (window.fMapState != kIsViewable) {
1333 //If I add it as child, it'll immediately make a window visible
1334 //and this thing sucks.
1335 window.fDelayedTransient = YES;
1336 } else {
1337 [self addChildWindow : window ordered : NSWindowAbove];
1338 window.fDelayedTransient = NO;
1339 }
1340}
1341
1342//______________________________________________________________________________
1343- (void) makeKeyAndOrderFront : (id) sender
1344{
1345#pragma unused(sender)
1346
1347 //The more I know Cocoa, the less I like it.
1348 //Window behavior between spaces is a total mess.
1349 //Set the window to join all spaces.
1350#ifdef MAC_OS_X_VERSION_10_9
1351 [self setCollectionBehavior : NSWindowCollectionBehaviorMoveToActiveSpace];
1352#else
1353 [self setCollectionBehavior : NSWindowCollectionBehaviorCanJoinAllSpaces];
1354#endif
1355 //now bring it to the front, it will appear on the active space.
1356 [super makeKeyAndOrderFront : self];
1357 //then reset the collection behavior to default, so the window
1358 [self setCollectionBehavior : NSWindowCollectionBehaviorDefault];
1359}
1360
1361//______________________________________________________________________________
1362- (void) setFDelayedTransient : (BOOL) d
1363{
1365}
1366
1367//______________________________________________________________________________
1369{
1370 return fShapeCombineMask;
1371}
1372
1373//______________________________________________________________________________
1374- (void) setFShapeCombineMask : (QuartzImage *) mask
1375{
1376 if (mask != fShapeCombineMask) {
1377 [fShapeCombineMask release];
1378 if (mask) {
1379 fShapeCombineMask = [mask retain];
1380 //TODO: Check window's shadow???
1381 }
1382 }
1383}
1384
1385#pragma mark - X11Drawable's protocol.
1386
1387//______________________________________________________________________________
1388- (BOOL) fIsPixmap
1389{
1390 //Never.
1391 return NO;
1392}
1393
1394//______________________________________________________________________________
1396{
1397 //Never.
1398 return NO;
1399}
1400
1401//______________________________________________________________________________
1402- (CGFloat) fScaleFactor
1403{
1404 if (!self.screen)
1405 return 1.;
1406 return self.screen.backingScaleFactor;
1407}
1408
1409//______________________________________________________________________________
1410- (int) fX
1411{
1412 return X11::GlobalXCocoaToROOT(self.frame.origin.x);
1413}
1414
1415//______________________________________________________________________________
1416- (int) fY
1417{
1418 return X11::GlobalYCocoaToROOT(self.frame.origin.y + self.frame.size.height);
1419}
1420
1421//______________________________________________________________________________
1422- (unsigned) fWidth
1423{
1424 return self.frame.size.width;
1425}
1426
1427//______________________________________________________________________________
1428- (unsigned) fHeight
1429{
1430 //NSWindow's frame (height component) also includes title-bar.
1431 //So I have to use content view's height.
1432 //Obviously, there is a "hole" == 22 pixels.
1433 assert(fContentView != nil && "-fHeight:, content view is nil");
1434
1435 return fContentView.frame.size.height;
1436}
1437
1438//______________________________________________________________________________
1439- (void) setDrawableSize : (NSSize) newSize
1440{
1441 //Can not simply do self.frame.size = newSize.
1442 assert(!(newSize.width < 0) && "-setDrawableSize:, width is negative");
1443 assert(!(newSize.height < 0) && "-setDrawableSize:, height is negative");
1444
1445 NSRect frame = self.frame;
1446 // Some sanity check (rather random and inconsistent, based on the recent M1 crash/assert):
1447 if (frame.origin.x < -100000. || frame.origin.x > 100000.) {
1448 // Hope nobody has screens like this!
1449 NSLog(@"Attempting to set a frame with X: %g", frame.origin.x);
1450 frame.origin.x = 0.; // Otherwise, AppKit seems to use uint(-1) to initialise frames ... sometimes?
1451 }
1452 //dY is potentially a titlebar height.
1453 const CGFloat dY = fContentView ? frame.size.height - fContentView.frame.size.height : 0.;
1454 //Adjust the frame.
1455 frame.origin.y = frame.origin.y + frame.size.height - newSize.height - dY;
1456 frame.size = newSize;
1457 frame.size.height += dY;
1458 [self setFrame : frame display : YES];
1459}
1460
1461//______________________________________________________________________________
1462- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
1463{
1464 NSSize newSize = {};
1465 newSize.width = w;
1466 newSize.height = h;
1467 [self setContentSize : newSize];
1468
1469 //Check how this is affected by title bar's height.
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) setX : (int) x Y : (int) y
1479{
1480 NSPoint topLeft = {};
1481 topLeft.x = X11::GlobalXROOTToCocoa(x);
1482 topLeft.y = X11::GlobalYROOTToCocoa(y);
1483
1484 [self setFrameTopLeftPoint : topLeft];
1485}
1486
1487//______________________________________________________________________________
1488- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area withMask : (QuartzImage *) mask
1489 clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
1490{
1491 if (!fContentView)
1492 return;
1493
1494 [fContentView copy : src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
1495}
1496
1497//______________________________________________________________________________
1498- (unsigned char *) readColorBits : (X11::Rectangle) area
1499{
1500 if (!fContentView)
1501 return nullptr;
1502
1503 return [fContentView readColorBits : area];
1504}
1505
1506#pragma mark - XorDrawinWindow/View
1507
1508//______________________________________________________________________________
1510{
1511 if ([self findXorWindow])
1512 return;
1513
1514 XorDrawingWindow *special = [[XorDrawingWindow alloc] init];
1515 [self adjustXorWindowGeometry:special];
1516 [self addChildWindow : special ordered : NSWindowAbove];
1517 [special release];
1518}
1519
1520//______________________________________________________________________________
1522{
1523 if (auto win = [self findXorWindow])
1524 [self adjustXorWindowGeometry:win];
1525}
1526
1527//______________________________________________________________________________
1529{
1530 assert(win && "invalid (nil) parameter 'win'");
1531 auto frame = self.contentView.frame;
1532 frame = [self convertRectToScreen:frame];
1533 [win setFrame:frame display:NO];
1534}
1535
1536//______________________________________________________________________________
1538{
1539 if (auto win = [self findXorWindow]) {
1540 // For some reason, without ordeing out, the crosshair window's content stays
1541 // in the parent's window. Thus we first have to order out the crosshair window.
1542 [win orderOut:nil];
1543 [self removeChildWindow : win];
1544 }
1545}
1546
1547//______________________________________________________________________________
1549{
1550 auto children = [self childWindows];
1551 for (NSWindow *child in children) {
1552 if ([child isKindOfClass : XorDrawingWindow.class])
1553 return (XorDrawingWindow *)child;
1554 }
1555 return nil;
1556}
1557
1558
1559#pragma mark - X11Window protocol's implementation.
1560
1561//______________________________________________________________________________
1563{
1564 return nil;
1565}
1566
1567//______________________________________________________________________________
1568- (void) setFParentView : (QuartzView *) parent
1569{
1570#pragma unused(parent)
1571}
1572
1573//______________________________________________________________________________
1574- (NSView<X11Window> *) fContentView
1575{
1576 return fContentView;
1577}
1578
1579//______________________________________________________________________________
1581{
1582 return self;
1583}
1584
1585//... many forwards to fContentView.
1586
1587//______________________________________________________________________________
1588- (void) setFBackgroundPixel : (unsigned long) backgroundColor
1589{
1590 if (!fContentView)
1591 return;
1592
1593 if (!fShapeCombineMask) {
1594 CGFloat rgba[] = {0., 0., 0., 1.};
1595 X11::PixelToRGB(backgroundColor, rgba);
1596
1597 [self setBackgroundColor : [NSColor colorWithColorSpace : [NSColorSpace deviceRGBColorSpace] components : rgba count : 4]];
1598 }
1599
1600 fContentView.fBackgroundPixel = backgroundColor;
1601}
1602
1603//______________________________________________________________________________
1604- (unsigned long) fBackgroundPixel
1605{
1606 if (!fContentView)
1607 return 0;
1608
1610}
1611
1612//______________________________________________________________________________
1613- (int) fMapState
1614{
1615 //Top-level window can be only kIsViewable or kIsUnmapped (not unviewable).
1616 if (!fContentView)
1617 return kIsUnmapped;
1618
1619 if ([fContentView isHidden])
1620 return kIsUnmapped;
1621
1622 return kIsViewable;
1623}
1624
1625//______________________________________________________________________________
1626- (void) addChild : (NSView<X11Window> *) child
1627{
1628 assert(child != nil && "-addChild:, parameter 'child' is nil");
1629
1630 if (!fContentView) {
1631 //This can happen only in case of re-parent operation.
1632 assert([child isKindOfClass : [QuartzView class]] &&
1633 "-addChild: gl view in a top-level window as content view is not supported");
1634
1635 fContentView = (QuartzView *)child;
1636 [self setContentView : child];
1638 } else
1639 [fContentView addChild : child];
1640}
1641
1642//______________________________________________________________________________
1643- (void) getAttributes : (WindowAttributes_t *) attr
1644{
1645 if (!fContentView)
1646 return;
1647
1648 assert(attr && "-getAttributes:, parameter 'attr' is nil");
1649
1650 X11::GetWindowAttributes(self, attr);
1651}
1652
1653//______________________________________________________________________________
1654- (void) setAttributes : (const SetWindowAttributes_t *) attr
1655{
1656 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
1657
1658#ifdef DEBUG_ROOT_COCOA
1659 log_attributes(attr, self.fID);
1660#endif
1661
1662 X11::SetWindowAttributes(attr, self);
1663}
1664
1665//______________________________________________________________________________
1666- (void) mapRaised
1667{
1668 if (!fContentView)
1669 return;
1670
1671 const Util::AutoreleasePool pool;
1672
1673 [fContentView setHidden : NO];
1674 [self makeKeyAndOrderFront : self];
1675 [fContentView configureNotifyTree];
1676
1677 if (fDelayedTransient) {
1678 fDelayedTransient = NO;
1679 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1680 }
1681}
1682
1683//______________________________________________________________________________
1684- (void) mapWindow
1685{
1686 if (!fContentView)
1687 return;
1688
1689 const Util::AutoreleasePool pool;
1690
1691 [fContentView setHidden : NO];
1692 [self makeKeyAndOrderFront : self];
1693 [fContentView configureNotifyTree];
1694
1695 if (fDelayedTransient) {
1696 fDelayedTransient = NO;
1697 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1698 }
1699}
1700
1701//______________________________________________________________________________
1703{
1704 if (!fContentView)
1705 return;
1706
1707 const Util::AutoreleasePool pool;
1708
1709 [fContentView mapSubwindows];
1710 [fContentView configureNotifyTree];
1711}
1712
1713//______________________________________________________________________________
1714- (void) unmapWindow
1715{
1716 if (!fContentView)
1717 return;
1718
1719 [fContentView setHidden : YES];
1720 [self orderOut : self];
1721
1723 [fMainWindow removeChildWindow : self];
1724 fMainWindow = nil;
1725 }
1726}
1727
1728#pragma mark - Events.
1729
1730//______________________________________________________________________________
1731- (void) sendEvent : (NSEvent *) theEvent
1732{
1733 //With XQuartz, if you open a menu and try to move a window without closing this menu,
1734 //window does not move, menu closes, and after that you can start draggin a window again.
1735 //With Cocoa I can not do such a thing (window WILL move), but still can report button release event
1736 //to close a menu.
1737 if (!fContentView)
1738 return;
1739
1740 if (theEvent.type == Details::kLeftMouseDown || theEvent.type == Details::kRightMouseDown) {
1741 bool generateFakeRelease = false;
1742
1743 const NSPoint windowPoint = [theEvent locationInWindow];
1744
1745 if (windowPoint.x <= 4 || windowPoint.x >= self.fWidth - 4)
1746 generateFakeRelease = true;
1747
1748 if (windowPoint.y <= 4 || windowPoint.y >= self.fHeight - 4)
1749 generateFakeRelease = true;
1750
1751 const NSPoint viewPoint = [fContentView convertPoint : windowPoint fromView : nil];
1752
1753 if (viewPoint.y <= 0 && windowPoint.y >= 0)
1754 generateFakeRelease = true;
1755
1756 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1757 "-sendEvent:, gVirtualX is either null or not of TGCocoa type");
1758
1759 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1760 if (vx->GetEventTranslator()->HasPointerGrab() && generateFakeRelease) {
1762 theEvent.type == Details::kLeftMouseDown ?
1763 kButton1 : kButton3);
1764 //Yes, ignore this event completely (this means, you are not able to immediately start
1765 //resizing a window, if some popup is open. Actually, this is more or less
1766 //the same as with XQuartz and X11 version.
1767 return;
1768 }
1769 }
1770
1771 [super sendEvent : theEvent];
1772}
1773
1774#pragma mark - NSWindowDelegate's methods.
1775
1776//______________________________________________________________________________
1777- (BOOL) windowShouldClose : (id) sender
1778{
1779#pragma unused(sender)
1780 if (!fContentView)
1781 return NO;
1782
1783 if ([[self childWindows] count])
1784 return NO;
1785
1786 //Prepare client message for a window.
1787 Event_t closeEvent = {};
1788 closeEvent.fWindow = fContentView.fID;
1789 closeEvent.fType = kClientMessage;
1790 closeEvent.fFormat = 32;//Taken from GUI classes.
1792 closeEvent.fUser[0] = TGCocoa::fgDeleteWindowAtom;
1793 //Place it into the queue.
1794 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1795 "-windowShouldClose:, gVirtualX is either null or has a type different from TGCocoa");
1796 ((TGCocoa *)gVirtualX)->SendEvent(fContentView.fID, &closeEvent);
1797
1798 //Do not let AppKit to close a window,
1799 //ROOT will do.
1800 return NO;
1801}
1802
1803//______________________________________________________________________________
1804- (void) windowDidBecomeKey : (NSNotification *) aNotification
1805{
1806#pragma unused(aNotification)
1807
1808 if (!fContentView)
1809 return;
1810
1812 fHasFocus = YES;
1813 //
1814 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1815 "-windowDidBecomeKey:, gVirtualX is null or not of TGCocoa type");
1816 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1817 vx->GetEventTranslator()->GenerateFocusChangeEvent(self.fContentView);
1818 }
1819}
1820
1821
1822//______________________________________________________________________________
1823- (void) windowDidResignKey : (NSNotification *) aNotification
1824{
1825#pragma unused(aNotification)
1826 fHasFocus = NO;
1827}
1828
1829@end
1830
1831#pragma mark - Passive key grab info.
1832
1833@implementation PassiveKeyGrab
1834
1835//______________________________________________________________________________
1836- (id) initWithKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1837{
1838 if (self = [super init]) {
1839 fKeyCode = keyCode;
1840 fModifiers = modifiers;
1841 }
1842
1843 return self;
1844}
1845
1846//______________________________________________________________________________
1847- (BOOL) matchKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1848{
1849 return keyCode == fKeyCode && modifiers == fModifiers;
1850}
1851
1852//______________________________________________________________________________
1853- (BOOL) matchKey : (unichar) keyCode
1854{
1855 return keyCode == fKeyCode;
1856}
1857
1858//______________________________________________________________________________
1859- (unichar) fKeyCode
1860{
1861 return fKeyCode;
1862}
1863
1864//______________________________________________________________________________
1865- (NSUInteger) fModifiers
1866{
1867 return fModifiers;
1868}
1869
1870@end
1871
1872#pragma mark - X11 property emulation.
1873
1877 unsigned fFormat;
1878}
1879
1880@property (nonatomic, readonly) Atom_t fType;
1881
1882@end
1883
1884@implementation QuartzWindowProperty
1885
1886@synthesize fType;
1887
1888//______________________________________________________________________________
1889- (id) initWithData : (unsigned char *) data size : (unsigned) dataSize type : (Atom_t) type format : (unsigned) format
1890{
1891 if (self = [super init]) {
1892 //Memory is zero-initialized, but just to make it explicit:
1893 fPropertyData = nil;
1894 fType = 0;
1895 fFormat = 0;
1896
1897 [self resetPropertyData : data size : dataSize type : type format : format];
1898 }
1899
1900 return self;
1901}
1902
1903//______________________________________________________________________________
1904- (void) dealloc
1905{
1906 [fPropertyData release];
1907
1908 [super dealloc];
1909}
1910
1911//______________________________________________________________________________
1912- (void) resetPropertyData : (unsigned char *) data size : (unsigned) dataSize
1913 type : (Atom_t) type format : (unsigned) format
1914{
1915 [fPropertyData release];
1916
1917 fFormat = format;
1918 if (format == 16)
1919 dataSize *= 2;
1920 else if (format == 32)
1921 dataSize *= 4;
1922
1923 fPropertyData = [[NSData dataWithBytes : data length : dataSize] retain];
1924
1925 fType = type;
1926}
1927
1928//______________________________________________________________________________
1929- (NSData *) fPropertyData
1930{
1931 return fPropertyData;
1932}
1933
1934//______________________________________________________________________________
1935- (unsigned) fFormat
1936{
1937 return fFormat;
1938}
1939
1940@end
1941
1942#pragma mark - QuartzView.
1943
1944//
1945//QuartzView is a children view (also is a content view for a top-level QuartzWindow).
1946//
1947
1948@implementation QuartzView
1949
1950@synthesize fID;
1951@synthesize fContext;
1952/////////////////////
1953//SetWindowAttributes_t/WindowAttributes_t
1954@synthesize fEventMask;
1955@synthesize fClass;
1956@synthesize fDepth;
1957@synthesize fBitGravity;
1958@synthesize fWinGravity;
1959@synthesize fBackgroundPixel;
1960@synthesize fOverrideRedirect;
1961//SetWindowAttributes_t/WindowAttributes_t
1962/////////////////////
1963@synthesize fHasFocus;
1964@synthesize fParentView;
1965
1966@synthesize fPassiveGrabButton;
1967@synthesize fPassiveGrabEventMask;
1968@synthesize fPassiveGrabKeyModifiers;
1969@synthesize fActiveGrabEventMask;
1970@synthesize fPassiveGrabOwnerEvents;
1971@synthesize fSnapshotDraw;
1972@synthesize fCurrentCursor;
1973@synthesize fIsDNDAware;
1974
1975#pragma mark - Lifetime.
1976
1977//______________________________________________________________________________
1978- (id) initWithFrame : (NSRect) frame windowAttributes : (const SetWindowAttributes_t *)attr
1979{
1980 if (self = [super initWithFrame : frame]) {
1981 //Make this explicit (though memory is zero initialized).
1982 fBackBuffer = nil;
1983 fID = 0;
1984
1985 //Passive grab parameters.
1986 fPassiveGrabButton = -1;//0 is kAnyButton.
1989
1990 fPassiveKeyGrabs = [[NSMutableArray alloc] init];
1991
1992 [self setCanDrawConcurrently : NO];
1993
1994 [self setHidden : YES];
1995 //Actually, check if view need this.
1996 //
1997 if (attr)
1998 X11::SetWindowAttributes(attr, self);
1999
2001 fX11Properties = [[NSMutableDictionary alloc] init];
2002
2006 }
2007
2008 return self;
2009}
2010
2011//______________________________________________________________________________
2012- (void) dealloc
2013{
2014 [fBackBuffer release];
2015 [fPassiveKeyGrabs release];
2016 [fX11Properties release];
2017 [fBackgroundPixmap release];
2018 [super dealloc];
2019}
2020
2021#pragma mark - Tracking area.
2022
2023//Tracking area is required to ... track mouse motion events inside a view.
2024
2025//______________________________________________________________________________
2026- (void) updateTrackingAreas
2027{
2028 [super updateTrackingAreas];
2029
2030 if (!fID)
2031 return;
2032
2033 const Util::AutoreleasePool pool;
2034
2035 if (NSArray *trackingArray = [self trackingAreas]) {
2036 const NSUInteger size = [trackingArray count];
2037 for (NSUInteger i = 0; i < size; ++i) {
2038 NSTrackingArea * const t = [trackingArray objectAtIndex : i];
2039 [self removeTrackingArea : t];
2040 }
2041 }
2042
2043 const NSUInteger trackerOptions = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
2044 NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
2045 NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate;
2046
2047 NSRect frame = {};
2048 frame.size.width = self.fWidth;
2049 frame.size.height = self.fHeight;
2050
2051 NSTrackingArea * const tracker = [[NSTrackingArea alloc] initWithRect : frame
2052 options : trackerOptions owner : self userInfo : nil];
2053 [self addTrackingArea : tracker];
2054 [tracker release];
2055}
2056
2057//______________________________________________________________________________
2058- (void) updateTrackingAreasAfterRaise
2059{
2060 [self updateTrackingAreas];
2061
2062 for (QuartzView *childView in [self subviews])
2063 [childView updateTrackingAreasAfterRaise];
2064}
2065
2066#pragma mark - X11Drawable protocol.
2067
2068//______________________________________________________________________________
2069- (BOOL) fIsPixmap
2070{
2071 return NO;
2072}
2073
2074//______________________________________________________________________________
2076{
2077 return NO;
2078}
2079
2080//______________________________________________________________________________
2081- (CGFloat) fScaleFactor
2082{
2083 return self.fQuartzWindow.fScaleFactor;
2084}
2085
2086//______________________________________________________________________________
2087- (int) fX
2088{
2089 return self.frame.origin.x;
2090}
2091
2092//______________________________________________________________________________
2093- (int) fY
2094{
2095 return self.frame.origin.y;
2096}
2097
2098//______________________________________________________________________________
2099- (unsigned) fWidth
2100{
2101 return self.frame.size.width;
2102}
2103
2104//______________________________________________________________________________
2105- (unsigned) fHeight
2106{
2107 return self.frame.size.height;
2108}
2109
2110//______________________________________________________________________________
2111- (void) setDrawableSize : (NSSize) newSize
2112{
2113 assert(!(newSize.width < 0) && "-setDrawableSize, width is negative");
2114 assert(!(newSize.height < 0) && "-setDrawableSize, height is negative");
2115
2116 //This will cause redraw(?)
2117
2118 //In X11, resize changes the size, but upper-left corner is not changed.
2119 //In Cocoa, bottom-left is fixed.
2120 NSRect frame = self.frame;
2121 frame.size = newSize;
2122
2123 self.frame = frame;
2124}
2125
2126//______________________________________________________________________________
2127- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
2128{
2129 NSRect newFrame = {};
2130 newFrame.origin.x = x;
2131 newFrame.origin.y = y;
2132 newFrame.size.width = w;
2133 newFrame.size.height = h;
2134
2135 self.frame = newFrame;
2136}
2137
2138//______________________________________________________________________________
2139- (void) setX : (int) x Y : (int) y
2140{
2141 NSRect newFrame = self.frame;
2142 newFrame.origin.x = x;
2143 newFrame.origin.y = y;
2144
2145 self.frame = newFrame;
2146}
2147
2148//______________________________________________________________________________
2149- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2150 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY
2151 toPoint : (X11::Point) dstPoint
2152{
2153 //Check parameters.
2154 assert(srcImage != nil &&
2155 "-copyImage:area:withMask:clipOrigin:toPoint:, parameter 'srcImage' is nil");
2156 assert(srcImage.fImage != nil &&
2157 "-copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
2158
2159 //Check self.
2160 assert(self.fContext != 0 &&
2161 "-copyImage:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2162
2163 if (!X11::AdjustCropArea(srcImage, area)) {
2164 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2165 " srcRect and copyRect do not intersect");
2166 return;
2167 }
2168
2169 //No RAII for subImage, since it can be really subimage or image itself and
2170 //in these cases there is no need to release image.
2171 CGImageRef subImage = 0;
2172 bool needSubImage = false;
2173 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2174 needSubImage = true;
2175 subImage = X11::CreateSubImage(srcImage, area);
2176 if (!subImage) {
2177 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2178 " subimage creation failed");
2179 return;
2180 }
2181 } else
2182 subImage = srcImage.fImage;
2183
2184 //Save context state.
2185 const Quartz::CGStateGuard ctxGuard(self.fContext);
2186
2187 //Scale and translate to undo isFlipped.
2188 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2189 CGContextScaleCTM(self.fContext, 1., -1.);
2190 //Set clip mask on a context.
2191
2192 if (mask) {
2193 assert(mask.fImage != nil &&
2194 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2195 assert(CGImageIsMask(mask.fImage) == true &&
2196 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2197 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2198 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2199 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2200 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2201 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2202 }
2203
2204 //Convert from X11 to Cocoa (as soon as we scaled y * -1).
2205 //dstPoint.fY = X11::LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
2206 const CGFloat dstY = X11::LocalYROOTToCocoa(self, CGFloat(dstPoint.fY) + area.fHeight);
2207 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2208 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2209 CGContextDrawImage(self.fContext, imageRect, subImage);
2210
2211 if (needSubImage)
2212 CGImageRelease(subImage);
2213}
2214
2215//______________________________________________________________________________
2216- (void) copyView : (QuartzView *) srcView area : (X11::Rectangle) area toPoint : (X11::Point) dstPoint
2217{
2218 //To copy one "window" to another "window", I have to ask source QuartzView to draw intself into
2219 //bitmap, and copy this bitmap into the destination view.
2220
2221 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2222
2223 const NSRect frame = [srcView frame];
2224 //imageRep is in autorelease pool now.
2225 NSBitmapImageRep * const imageRep = [srcView bitmapImageRepForCachingDisplayInRect : frame];
2226 if (!imageRep) {
2227 NSLog(@"QuartzView: -copyView:area:toPoint failed");
2228 return;
2229 }
2230
2231 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2232 assert(self.fContext != 0 && "-copyView:area:toPoint, self.fContext is null");
2233
2234 //It can happen, that src and self are the same.
2235 //cacheDisplayInRect calls drawRect with bitmap context
2236 //(and this will reset self.fContext: I have to save/restore it.
2237 CGContextRef ctx = srcView.fContext;
2238 srcView.fSnapshotDraw = YES;
2239 [srcView cacheDisplayInRect : frame toBitmapImageRep : imageRep];
2240 srcView.fSnapshotDraw = NO;
2241 srcView.fContext = ctx;
2242
2243 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fWidth, area.fHeight);
2244 const Util::CFScopeGuard<CGImageRef> subImage(CGImageCreateWithImageInRect(imageRep.CGImage, subImageRect));
2245
2246 if (!subImage.Get()) {
2247 NSLog(@"QuartzView: -copyView:area:toPoint, CGImageCreateWithImageInRect failed");
2248 return;
2249 }
2250
2251 const Quartz::CGStateGuard ctxGuard(self.fContext);
2252 const CGRect imageRect = CGRectMake(dstPoint.fX,
2253 [self visibleRect].size.height - (CGFloat(dstPoint.fY) + area.fHeight),
2254 area.fWidth, area.fHeight);
2255
2256 CGContextTranslateCTM(self.fContext, 0., [self visibleRect].size.height);
2257 CGContextScaleCTM(self.fContext, 1., -1.);
2258
2259 CGContextDrawImage(self.fContext, imageRect, subImage.Get());
2260}
2261
2262//______________________________________________________________________________
2263- (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
2264 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2265{
2266 //Check parameters.
2267 assert(srcPixmap != nil && "-copyPixmap:area:withMask:clipOrigin:toPoint:, parameter 'srcPixmap' is nil");
2268
2269 if (!X11::AdjustCropArea(srcPixmap, area)) {
2270 NSLog(@"QuartzView: -copyPixmap:area:withMask:clipOrigin:toPoint,"
2271 " no intersection between pixmap rectangle and cropArea");
2272 return;
2273 }
2274
2275 //Check self.
2276 assert(self.fContext != 0 &&
2277 "-copyPixmap:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2278
2279 //Save context state.
2280 const Quartz::CGStateGuard ctxGuard(self.fContext);
2281
2282 CGContextTranslateCTM(self.fContext, 0., self.frame.size.height);//???
2283 CGContextScaleCTM(self.fContext, 1., -1.);
2284
2285 const Util::CFScopeGuard<CGImageRef> imageFromPixmap([srcPixmap createImageFromPixmap]);
2286 assert(imageFromPixmap.Get() != 0 &&
2287 "-copyPixmap:area:withMask:clipOrigin:toPoint:, createImageFromPixmap failed");
2288
2289 CGImageRef subImage = 0;
2290 bool needSubImage = false;
2291 if (area.fX || area.fY || area.fWidth != srcPixmap.fWidth || area.fHeight != srcPixmap.fHeight) {
2292 needSubImage = true;
2293 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
2294 subImage = CGImageCreateWithImageInRect(imageFromPixmap.Get(), subImageRect);
2295 if (!subImage) {
2296 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2297 " subimage creation failed");
2298 return;
2299 }
2300 } else
2301 subImage = imageFromPixmap.Get();
2302
2303 if (mask) {
2304 assert(mask.fImage != nil &&
2305 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2306 assert(CGImageIsMask(mask.fImage) == true &&
2307 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2308
2309 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2310 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2311 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2312 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2313 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2314 }
2315
2316 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2317 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2318 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2319 CGContextDrawImage(self.fContext, imageRect, imageFromPixmap.Get());
2320
2321 if (needSubImage)
2322 CGImageRelease(subImage);
2323}
2324
2325
2326//______________________________________________________________________________
2327- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2328 toPoint : (X11::Point) dstPoint
2329{
2330 assert(srcImage != nil && "-copyImage:area:toPoint:, parameter 'srcImage' is nil");
2331 assert(srcImage.fImage != nil && "-copyImage:area:toPoint:, srcImage.fImage is nil");
2332 assert(self.fContext != 0 && "-copyImage:area:toPoint:, fContext is null");
2333
2334 if (!X11::AdjustCropArea(srcImage, area)) {
2335 NSLog(@"QuartzView: -copyImage:area:toPoint, image and copy area do not intersect");
2336 return;
2337 }
2338
2339 CGImageRef subImage = 0;
2340 bool needSubImage = false;
2341 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2342 needSubImage = true;
2343 subImage = X11::CreateSubImage(srcImage, area);
2344 if (!subImage) {
2345 NSLog(@"QuartzView: -copyImage:area:toPoint:, subimage creation failed");
2346 return;
2347 }
2348 } else
2349 subImage = srcImage.fImage;
2350
2351 const Quartz::CGStateGuard ctxGuard(self.fContext);
2352
2353 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2354 CGContextScaleCTM(self.fContext, 1., -1.);
2355
2356 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2357 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2358 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2359 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2360 CGContextDrawImage(self.fContext, imageRect, subImage);
2361
2362 if (needSubImage)
2363 CGImageRelease(subImage);
2364}
2365
2366//______________________________________________________________________________
2367- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
2368 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2369{
2370 assert(src != nil && "-copy:area:withMask:clipOrigin:toPoint:, parameter 'src' is nil");
2371 assert(area.fWidth && area.fHeight && "-copy:area:withMask:clipOrigin:toPoint:, area to copy is empty");
2372
2373 if ([src isKindOfClass : [QuartzWindow class]]) {
2374 //Forget about mask (can I have it???)
2375 QuartzWindow * const qw = (QuartzWindow *)src;
2376 //Will not work with OpenGL.
2377 [self copyView : (QuartzView *)qw.fContentView area : area toPoint : dstPoint];
2378 } else if ([src isKindOfClass : [QuartzView class]]) {
2379 //Forget about mask (can I have it???)
2380 [self copyView : (QuartzView *)src area : area toPoint : dstPoint];
2381 } else if ([src isKindOfClass : [QuartzPixmap class]]) {
2382 [self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2383 } else if ([src isKindOfClass : [QuartzImage class]]) {
2384 [self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2385 } else {
2386 assert(0 && "-copy:area:withMask:clipOrigin:toPoint:, src is of unknown type");
2387 }
2388}
2389
2390//______________________________________________________________________________
2391- (unsigned char *) readColorBits : (X11::Rectangle) area
2392{
2393 //This is quite a bad idea - to read pixels back from a view,
2394 //but our GUI does exactly this. In case of Cocoa it's expensive
2395 //and not guaranteed to work.
2396
2397 assert(area.fWidth && area.fHeight && "-readColorBits:, area to copy is empty");
2398
2399 //int, not unsigned or something - to keep it simple.
2400 const NSRect visRect = [self visibleRect];
2401 const X11::Rectangle srcRect(int(visRect.origin.x), int(visRect.origin.y),
2402 unsigned(visRect.size.width), unsigned(visRect.size.height));
2403
2404 if (!X11::AdjustCropArea(srcRect, area)) {
2405 NSLog(@"QuartzView: -readColorBits:, visible rect of view and copy area do not intersect");
2406 return nullptr;
2407 }
2408
2409 //imageRep is autoreleased.
2410 NSBitmapImageRep * const imageRep = [self bitmapImageRepForCachingDisplayInRect : visRect];
2411 if (!imageRep) {
2412 NSLog(@"QuartzView: -readColorBits:, bitmapImageRepForCachingDisplayInRect failed");
2413 return nullptr;
2414 }
2415
2416 CGContextRef ctx = self.fContext; //Save old context if any.
2417 [self cacheDisplayInRect : visRect toBitmapImageRep : imageRep];
2418 self.fContext = ctx; //Restore old context.
2419 //
2420 const NSInteger bitsPerPixel = [imageRep bitsPerPixel];
2421
2422 assert(bitsPerPixel == 32 && "-readColorBits:, no alpha channel???");
2423 const NSInteger bytesPerRow = [imageRep bytesPerRow];
2424 unsigned dataWidth = bytesPerRow / (bitsPerPixel / 8);//assume an octet :(
2425
2426 unsigned char *srcData = nullptr;
2427 std::vector<unsigned char> downscaled;
2428 if ([self.window.screen backingScaleFactor] > 1 && imageRep.CGImage) {
2429 downscaled = X11::DownscaledImageData(area.fWidth, area.fHeight, imageRep.CGImage);
2430 if (downscaled.size())
2431 srcData = &downscaled[0];
2432 dataWidth = area.fWidth;
2433 } else
2434 srcData = [imageRep bitmapData];
2435
2436 if (!srcData) {
2437 NSLog(@"QuartzView: -readColorBits:, failed to obtain backing store contents");
2438 return nullptr;
2439 }
2440
2441 //We have a source data now. Let's allocate buffer for ROOT's GUI and convert source data.
2442 unsigned char *data = nullptr;
2443
2444 try {
2445 data = new unsigned char[area.fWidth * area.fHeight * 4];//bgra?
2446 } catch (const std::bad_alloc &) {
2447 NSLog(@"QuartzView: -readColorBits:, memory allocation failed");
2448 return nullptr;
2449 }
2450
2451 unsigned char *dstPixel = data;
2452 const unsigned char *line = srcData + area.fY * dataWidth * 4;
2453 const unsigned char *srcPixel = line + area.fX * 4;
2454
2455 for (unsigned i = 0; i < area.fHeight; ++i) {
2456 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
2457 dstPixel[0] = srcPixel[2];
2458 dstPixel[1] = srcPixel[1];
2459 dstPixel[2] = srcPixel[0];
2460 dstPixel[3] = srcPixel[3];
2461 }
2462
2463 line += dataWidth * 4;
2464 srcPixel = line + area.fX * 4;
2465 }
2466
2467 return data;
2468}
2469
2470//______________________________________________________________________________
2471- (void) setFBackgroundPixmap : (QuartzImage *) pixmap
2472{
2473 if (fBackgroundPixmap != pixmap) {
2474 [fBackgroundPixmap release];
2475 if (pixmap)
2476 fBackgroundPixmap = [pixmap retain];
2477 else
2478 fBackgroundPixmap = nil;
2479 }
2480}
2481
2482//______________________________________________________________________________
2484{
2485 //I do not autorelease, screw this idiom!
2486
2487 return fBackgroundPixmap;
2488}
2489
2490//______________________________________________________________________________
2491- (int) fMapState
2492{
2493 if ([self isHidden])
2494 return kIsUnmapped;
2495
2496 for (QuartzView *parent = fParentView; parent; parent = parent.fParentView) {
2497 if ([parent isHidden])
2498 return kIsUnviewable;
2499 }
2500
2501 return kIsViewable;
2502}
2503
2504//______________________________________________________________________________
2505- (BOOL) fHasFocus
2506{
2507 //With the latest update clang became a bit more stupid.
2508 //Let's write a stupid useless cargo cult code
2509 //to make IT SHUT THE F... UP.
2510 (void)fHasFocus;
2511 return NO;
2512}
2513
2514//______________________________________________________________________________
2515- (void) setFHasFocus : (BOOL) focus
2516{
2517#pragma unused(focus)
2518 //With the latest update clang became a bit more stupid.
2519 //Let's write a stupid useless cargo cult code
2520 //to make IT SHUT THE F... UP.
2521 (void)fHasFocus;
2522}
2523
2524//______________________________________________________________________________
2526{
2527 return fBackBuffer;//No autorelease, I know the object's lifetime myself.
2528}
2529
2530//______________________________________________________________________________
2531- (void) setFBackBuffer : (QuartzPixmap *) backBuffer
2532{
2533 if (fBackBuffer != backBuffer) {
2534 [fBackBuffer release];
2535
2536 if (backBuffer)
2537 fBackBuffer = [backBuffer retain];
2538 else
2539 fBackBuffer = nil;
2540 }
2541}
2542
2543//______________________________________________________________________________
2544- (NSView<X11Window> *) fContentView
2545{
2546 return self;
2547}
2548
2549//______________________________________________________________________________
2551{
2552 return (QuartzWindow *)[self window];
2553}
2554
2555//______________________________________________________________________________
2557{
2559}
2560
2561//______________________________________________________________________________
2563{
2565}
2566
2567//______________________________________________________________________________
2568- (void) activateGrab : (unsigned) eventMask ownerEvents : (BOOL) ownerEvents
2569{
2571 fActiveGrabEventMask = eventMask;
2572 fActiveGrabOwnerEvents = ownerEvents;
2573}
2574
2575//______________________________________________________________________________
2576- (void) cancelGrab
2577{
2581}
2582
2583//______________________________________________________________________________
2584- (BOOL) acceptsCrossingEvents : (unsigned) eventMask
2585{
2586 bool accepts = fEventMask & eventMask;
2587
2588 //In ROOT passive grabs are always with owner_events == true.
2590 accepts = accepts || (fPassiveGrabEventMask & eventMask);
2591
2594 accepts = accepts || (fActiveGrabOwnerEvents & eventMask);
2595 else
2596 accepts = fActiveGrabOwnerEvents & eventMask;
2597 }
2598
2599 return accepts;
2600}
2601
2602//______________________________________________________________________________
2603- (void) addChild : (NSView<X11Window> *) child
2604{
2605 assert(child != nil && "-addChild:, parameter 'child' is nil");
2606
2607 [self addSubview : child];
2608 child.fParentView = self;
2609}
2610
2611//______________________________________________________________________________
2612- (void) getAttributes : (WindowAttributes_t *) attr
2613{
2614 assert(attr != 0 && "-getAttributes:, parameter 'attr' is null");
2615
2616 X11::GetWindowAttributes(self, attr);
2617}
2618
2619//______________________________________________________________________________
2620- (void) setAttributes : (const SetWindowAttributes_t *)attr
2621{
2622 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
2623
2624#ifdef DEBUG_ROOT_COCOA
2625 log_attributes(attr, fID);
2626#endif
2627
2628 X11::SetWindowAttributes(attr, self);
2629}
2630
2631//______________________________________________________________________________
2632- (void) mapRaised
2633{
2634 //Move view to the top of subviews.
2635 QuartzView * const parent = fParentView;
2636 [self removeFromSuperview];
2637 [parent addSubview : self];
2638 [self setHidden : NO];
2639}
2640
2641//______________________________________________________________________________
2642- (void) mapWindow
2643{
2644 [self setHidden : NO];
2645}
2646
2647//______________________________________________________________________________
2649{
2650 for (QuartzView * v in [self subviews])
2651 [v setHidden : NO];
2652}
2653
2654//______________________________________________________________________________
2655- (void) unmapWindow
2656{
2657 [self setHidden : YES];
2658}
2659
2660//______________________________________________________________________________
2662{
2663 return fIsOverlapped;
2664}
2665
2666//______________________________________________________________________________
2667- (void) setOverlapped : (BOOL) overlap
2668{
2669 fIsOverlapped = overlap;
2670 for (NSView<X11Window> *child in [self subviews])
2671 [child setOverlapped : overlap];
2672}
2673
2674//______________________________________________________________________________
2675- (void) raiseWindow
2676{
2677 //Now, I can not remove window and add it ...
2678 //For example, if you click on a tab, this:
2679 //1. Creates (potentially) a passive button grab
2680 //2. Raises this tab - changes the window order.
2681 //3. On a button release - grab is release.
2682 //The tough problem is, if I remove a view from subviews
2683 //and add it ... it will never receve the
2684 //release event thus a grab will 'hang' on
2685 //view leading to bugs and artifacts.
2686 //So instead I have to ... SORT!!!!!
2687
2688 using namespace X11;//Comparators.
2689
2690 for (QuartzView *sibling in [fParentView subviews]) {
2691 if (self == sibling)
2692 continue;
2693 if ([sibling isHidden])
2694 continue;
2695
2696 if (NSEqualRects(sibling.frame, self.frame)) {
2697 [sibling setOverlapped : YES];
2698 [sibling setHidden : YES];
2699 }
2700 }
2701
2702 [self setOverlapped : NO];
2703 //
2704 [self setHidden : NO];
2705 //
2706 [fParentView sortSubviewsUsingFunction : CompareViewsToRaise context : (void *)self];
2707 //
2708 [self updateTrackingAreasAfterRaise];
2709 //
2710 [self setNeedsDisplay : YES];
2711}
2712
2713//______________________________________________________________________________
2714- (void) lowerWindow
2715{
2716 //See comment about sorting in -raiseWindow.
2717
2718 using namespace X11;
2719
2720 NSEnumerator * const reverseEnumerator = [[fParentView subviews] reverseObjectEnumerator];
2721 for (QuartzView *sibling in reverseEnumerator) {
2722 if (sibling == self)
2723 continue;
2724
2725 if (NSEqualRects(sibling.frame, self.frame)) {
2726 [sibling setOverlapped : NO];
2727 //
2728 [sibling setHidden : NO];
2729 //
2730 [sibling setNeedsDisplay : YES];
2731 [self setOverlapped : YES];
2732 //
2733 [self setHidden : YES];
2734 //
2735 break;
2736 }
2737 }
2738
2739 [fParentView sortSubviewsUsingFunction : CompareViewsToLower context : (void*)self];
2740}
2741
2742//______________________________________________________________________________
2743- (BOOL) isFlipped
2744{
2745 //Now view's placement, geometry, moving and resizing can be
2746 //done with ROOT's (X11) coordinates without conversion - we're are 'flipped'.
2747 return YES;
2748}
2749
2750//______________________________________________________________________________
2752{
2753 if (self.fMapState == kIsViewable || fIsOverlapped == YES) {
2755 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2756 "-configureNotifyTree, gVirtualX is either null or has type different from TGCocoa");
2757 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2758 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2759 }
2760
2761 for (NSView<X11Window> *v in [self subviews])
2762 [v configureNotifyTree];
2763 }
2764}
2765
2766#pragma mark - Key grabs.
2767
2768//______________________________________________________________________________
2769- (void) addPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2770{
2771 [self removePassiveKeyGrab : keyCode modifiers : modifiers];
2772 PassiveKeyGrab * const newGrab = [[PassiveKeyGrab alloc] initWithKey : keyCode
2773 modifiers : modifiers];
2774 [fPassiveKeyGrabs addObject : newGrab];
2775 [newGrab release];
2776}
2777
2778//______________________________________________________________________________
2779- (void) removePassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2780{
2781 const NSUInteger count = [fPassiveKeyGrabs count];
2782 for (NSUInteger i = 0; i < count; ++i) {
2783 PassiveKeyGrab *grab = [fPassiveKeyGrabs objectAtIndex : i];
2784 if ([grab matchKey : keyCode modifiers : modifiers]) {
2785 [fPassiveKeyGrabs removeObjectAtIndex : i];
2786 break;
2787 }
2788 }
2789}
2790
2791//______________________________________________________________________________
2792- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2793{
2794 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2795 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2796 if ([grab matchKey : keyCode modifiers : modifiers])
2797 return grab;
2798 }
2799
2800 return nil;
2801}
2802
2803//______________________________________________________________________________
2804- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode
2805{
2806 //Do not check modifiers.
2807 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2808 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2809 if ([grab matchKey : keyCode])
2810 return grab;
2811 }
2812
2813 return nil;
2814}
2815
2816#pragma mark - Painting mechanics.
2817
2818//______________________________________________________________________________
2819- (void) drawRect : (NSRect) dirtyRect
2820{
2821#pragma unused(dirtyRect)
2822
2823 using namespace X11;
2824
2825 if (fID) {
2826 if (TGWindow * const window = gClient->GetWindowById(fID)) {
2827 //It's never painted, parent renders child. true == check the parent also.
2828 if (ViewIsTextViewFrame(self, true) ||ViewIsHtmlViewFrame(self, true))
2829 return;
2830
2831 NSGraphicsContext * const nsContext = [NSGraphicsContext currentContext];
2832 assert(nsContext != nil && "-drawRect:, currentContext returned nil");
2833
2834 TGCocoa * const vx = (TGCocoa *)gVirtualX;
2835 vx->CocoaDrawON();
2836
2837 fContext = (CGContextRef)[nsContext graphicsPort];
2838 assert(fContext != 0 && "-drawRect:, graphicsPort returned null");
2839
2840 const Quartz::CGStateGuard ctxGuard(fContext);
2841
2842 //Non-rectangular windows.
2843 if (self.fQuartzWindow.fShapeCombineMask)
2845
2846 // This code used to use TObject::InheritsFrom, however since this is
2847 // run under the AppKit, we can not call core/meta functions, otherwise
2848 // we will run into deadlocks.
2849 if (dynamic_cast<const TGContainer*>(window))//It always has an ExposureMask.
2850 vx->GetEventTranslator()->GenerateExposeEvent(self, [self visibleRect]);
2851
2852 if (fEventMask & kExposureMask) {
2853 if (ViewIsTextView(self)) {
2854 //Send Expose event, using child view (this is how it's done in GUI :( ).
2855 [NSColor.whiteColor setFill];
2856 NSRectFill(dirtyRect);
2857 NSView<X11Window> * const viewFrame = FrameForTextView(self);
2858 if (viewFrame)//Now we set fExposedRegion for TGView.
2859 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2860 }
2861
2862 if (ViewIsHtmlView(self)) {
2863 NSView<X11Window> *const viewFrame = FrameForHtmlView(self);
2864 if (viewFrame)
2865 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2866 }
2867
2868 //Ask ROOT's widget/window to draw itself.
2869 gClient->NeedRedraw(window, kTRUE);
2870
2871 if (!fSnapshotDraw) {
2872 //If Cocoa repaints widget, cancel all ROOT's "outside of paint event"
2873 //rendering into this widget.
2874 gClient->CancelRedraw(window);
2876 }
2877 }
2878
2879 if (fBackBuffer) {
2880 //Very "special" window.
2881 const X11::Rectangle copyArea(0, 0, fBackBuffer.fWidth, fBackBuffer.fHeight);
2882 [self copy : fBackBuffer area : copyArea withMask : nil
2883 clipOrigin : X11::Point() toPoint : X11::Point()];
2884 }
2885
2886 vx->CocoaDrawOFF();
2887#ifdef DEBUG_ROOT_COCOA
2888 CGContextSetRGBStrokeColor(fContext, 1., 0., 0., 1.);
2889 CGContextStrokeRect(fContext, dirtyRect);
2890#endif
2891
2892 fContext = 0;
2893 } else {
2894#ifdef DEBUG_ROOT_COCOA
2895 NSLog(@"QuartzView: -drawRect: method, no window for id %u was found", fID);
2896#endif
2897 }
2898 }
2899}
2900
2901#pragma mark - Geometry.
2902
2903//______________________________________________________________________________
2904- (void) setFrame : (NSRect) newFrame
2905{
2906 //In case of TBrowser, setFrame started infinite recursion:
2907 //HandleConfigure for embedded main frame emits signal, slot
2908 //calls layout, layout calls setFrame -> HandleConfigure and etc. etc.
2909 if (NSEqualRects(newFrame, self.frame))
2910 return;
2911
2912 [super setFrame : newFrame];
2913}
2914
2915//______________________________________________________________________________
2916- (void) setFrameSize : (NSSize) newSize
2917{
2918 //Check, if setFrameSize calls setFrame.
2919
2920 [super setFrameSize : newSize];
2921
2922 if ((fEventMask & kStructureNotifyMask) && (self.fMapState == kIsViewable || fIsOverlapped == YES)) {
2923 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2924 "setFrameSize:, gVirtualX is either null or has a type, different from TGCocoa");
2925 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2926 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2927 }
2928
2929 [self setNeedsDisplay : YES];//?
2930}
2931
2932#pragma mark - Event handling.
2933
2934//______________________________________________________________________________
2935- (void) mouseDown : (NSEvent *) theEvent
2936{
2937 assert(fID != 0 && "-mouseDown:, fID is 0");
2938
2939 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2940 "-mouseDown:, gVirtualX is either null or has a type, different from TGCocoa");
2941 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2943}
2944
2945//______________________________________________________________________________
2946- (void) scrollWheel : (NSEvent*) theEvent
2947{
2948 assert(fID != 0 && "-scrollWheel:, fID is 0");
2949
2950
2951 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2952 "-scrollWheel:, gVirtualX is either null or has a type, different from TGCocoa");
2953
2954 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2955 const CGFloat deltaY = [theEvent deltaY];
2956 if (deltaY < 0) {
2959 } else if (deltaY > 0) {
2962 }
2963}
2964
2965#ifdef DEBUG_ROOT_COCOA
2966//______________________________________________________________________________
2967- (void) printViewInformation
2968{
2969 assert(fID != 0 && "-printWindowInformation, fID is 0");
2970 const TGWindow * const window = gClient->GetWindowById(fID);
2971 assert(window != 0 && "printWindowInformation, window not found");
2972
2973 NSLog(@"-----------------View %u info:---------------------", fID);
2974 NSLog(@"ROOT's window class is %s", window->IsA()->GetName());
2975 NSLog(@"event mask is:");
2976 print_mask_info(fEventMask);
2977 NSLog(@"grab mask is:");
2978 print_mask_info(fPassiveGrabEventMask);
2979 NSLog(@"view's geometry: x == %g, y == %g, w == %g, h == %g", self.frame.origin.x,
2980 self.frame.origin.y, self.frame.size.width, self.frame.size.height);
2981 NSLog(@"----------------End of view info------------------");
2982}
2983#endif
2984
2985//______________________________________________________________________________
2986- (void) rightMouseDown : (NSEvent *) theEvent
2987{
2988 assert(fID != 0 && "-rightMouseDown:, fID is 0");
2989
2990#ifdef DEBUG_ROOT_COCOA
2991 [self printViewInformation];
2992#endif
2993
2994 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2995 "-rightMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2996 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2998}
2999
3000//______________________________________________________________________________
3001- (void) otherMouseDown : (NSEvent *) theEvent
3002{
3003 assert(fID != 0 && "-otherMouseDown:, fID is 0");
3004
3005 //Funny enough, [theEvent buttonNumber] is not the same thing as button masked in [NSEvent pressedMouseButtons],
3006 //button number actually is a kind of right operand for bitshift for pressedMouseButtons.
3007 if ([theEvent buttonNumber] == 2) {//this '2' will correspond to '4' in pressedMouseButtons.
3008 //I do not care about mouse buttons after left/right/wheel - ROOT does not have
3009 //any code for this.
3010 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3011 "-otherMouseDown:, gVirtualX is either null or has type different from TGCocoa");
3012 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3014 }
3015}
3016
3017//______________________________________________________________________________
3018- (void) mouseUp : (NSEvent *) theEvent
3019{
3020 assert(fID != 0 && "-mouseUp:, fID is 0");
3021
3022 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
3023 "-mouseUp:, gVirtualX is either null or has type different from TGCocoa");
3024 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3026}
3027
3028//______________________________________________________________________________
3029- (void) rightMouseUp : (NSEvent *) theEvent
3030{
3031
3032 assert(fID != 0 && "-rightMouseUp:, fID is 0");
3033
3034 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3035 "-rightMouseUp:, gVirtualX is either null or has type different from TGCocoa");
3036
3037 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3039}
3040
3041//______________________________________________________________________________
3042- (void) otherMouseUp : (NSEvent *) theEvent
3043{
3044 assert(fID != 0 && "-otherMouseUp:, fID is 0");
3045
3046 //Here I assume it's always kButton2.
3047 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3048 "-otherMouseUp:, gVirtualX is either null or has type different from TGCocoa");
3049 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3051}
3052
3053//______________________________________________________________________________
3054- (void) mouseEntered : (NSEvent *) theEvent
3055{
3056 assert(fID != 0 && "-mouseEntered:, fID is 0");
3057 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3058 "-mouseEntered:, gVirtualX is null or not of TGCocoa type");
3059
3060 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3062}
3063
3064//______________________________________________________________________________
3065- (void) mouseExited : (NSEvent *) theEvent
3066{
3067 assert(fID != 0 && "-mouseExited:, fID is 0");
3068
3069 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3070 "-mouseExited:, gVirtualX is null or not of TGCocoa type");
3071
3072 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3074}
3075
3076//______________________________________________________________________________
3077- (void) mouseMoved : (NSEvent *) theEvent
3078{
3079 assert(fID != 0 && "-mouseMoved:, fID is 0");
3080
3081 if (fParentView)//Suppress events in all views, except the top-level one.
3082 return;
3083
3084 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3085 "-mouseMoved:, gVirtualX is null or not of TGCocoa type");
3086
3087 TGCocoa *vx = static_cast<TGCocoa *>(gVirtualX);
3089}
3090
3091//______________________________________________________________________________
3092- (void) mouseDragged : (NSEvent *) theEvent
3093{
3094 assert(fID != 0 && "-mouseDragged:, fID is 0");
3095
3096 TGCocoa * const vx = dynamic_cast<TGCocoa *>(gVirtualX);
3097 assert(vx != 0 && "-mouseDragged:, gVirtualX is null or not of TGCocoa type");
3098
3100}
3101
3102//______________________________________________________________________________
3103- (void) rightMouseDragged : (NSEvent *) theEvent
3104{
3105 assert(fID != 0 && "-rightMouseDragged:, fID is 0");
3106
3107 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3108 "-rightMouseDragged:, gVirtualX is null or not of TGCocoa type");
3109
3110 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3112}
3113
3114//______________________________________________________________________________
3115- (void) otherMouseDragged : (NSEvent *) theEvent
3116{
3117 assert(fID != 0 && "-otherMouseDragged:, fID is 0");
3118
3119 if ([theEvent buttonNumber] == 2) {
3120 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3121 "-otherMouseDragged:, gVirtualX is null or not of TGCocoa type");
3122 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3124 }
3125}
3126
3127//______________________________________________________________________________
3128- (void) keyDown : (NSEvent *) theEvent
3129{
3130 assert(fID != 0 && "-keyDown:, fID is 0");
3131
3132 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3133 "-keyDown:, gVirtualX is null or not of TGCocoa type");
3134
3135 NSView<X11Window> *eventView = self;
3136 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3137 eventView = pointerView;
3138
3139 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3140 vx->GetEventTranslator()->GenerateKeyPressEvent(eventView, theEvent);
3141}
3142
3143//______________________________________________________________________________
3144- (void) keyUp : (NSEvent *) theEvent
3145{
3146 assert(fID != 0 && "-keyUp:, fID is 0");
3147
3148 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3149 "-keyUp:, gVirtualX is null or not of TGCocoa type");
3150
3151 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3152 NSView<X11Window> *eventView = self;
3153 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3154 eventView = pointerView;
3155
3156 vx->GetEventTranslator()->GenerateKeyReleaseEvent(eventView, theEvent);
3157}
3158
3159#pragma mark - First responder stuff.
3160
3161//______________________________________________________________________________
3162- (BOOL) acceptsFirstMouse : (NSEvent *) theEvent
3163{
3164#pragma unused(theEvent)
3165 return YES;
3166}
3167
3168//______________________________________________________________________________
3169- (BOOL) acceptsFirstResponder
3170{
3171 return YES;
3172}
3173
3174#pragma mark - Cursors.
3175
3176//______________________________________________________________________________
3177- (void) setFCurrentCursor : (ECursor) cursor
3178{
3179 if (cursor != fCurrentCursor) {
3180 fCurrentCursor = cursor;
3181 [self.fQuartzWindow invalidateCursorRectsForView : self];
3182 }
3183}
3184
3185//______________________________________________________________________________
3186- (NSCursor *) createCustomCursor
3187{
3188 const char *pngFileName = 0;
3189
3190 switch (fCurrentCursor) {
3191 case kMove:
3192 pngFileName = "move_cursor.png";
3193 break;
3194 case kArrowHor:
3195 pngFileName = "hor_arrow_cursor.png";
3196 break;
3197 case kArrowVer:
3198 pngFileName = "ver_arrow_cursor.png";
3199 break;
3200 case kArrowRight:
3201 pngFileName = "right_arrow_cursor.png";
3202 break;
3203 case kRotate:
3204 pngFileName = "rotate.png";
3205 break;
3206 case kBottomLeft:
3207 case kTopRight:
3208 pngFileName = "top_right_cursor.png";
3209 break;
3210 case kTopLeft:
3211 case kBottomRight:
3212 pngFileName = "top_left_cursor.png";
3213 break;
3214 default:;
3215 }
3216
3217 if (pngFileName) {
3218 const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
3219 const Util::ScopedArray<const char> arrayGuard(path);
3220
3221 if (!path || path[0] == 0) {
3222 //File was not found.
3223 return nil;
3224 }
3225
3226 NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
3227 NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
3228
3229 if (!cursorImage)
3230 return nil;
3231
3232 NSPoint hotSpot = X11::GetCursorHotStop(cursorImage, fCurrentCursor);
3233 NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
3234 hotSpot : hotSpot] autorelease];
3235
3236 [cursorImage release];
3237
3238 return customCursor;
3239 }
3240
3241 return nil;
3242}
3243
3244//______________________________________________________________________________
3245- (void) resetCursorRects
3246{
3247 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor))
3248 [self addCursorRect : self.visibleRect cursor : cursor];
3249}
3250
3251//______________________________________________________________________________
3252- (void) cursorUpdate
3253{
3254 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor)) {
3255 // NB: [window invalidateCursorRectsForView] called here has the
3256 // same problem as commented below in -cursorUpdate:.
3257 [cursor set];
3258 }
3259}
3260
3261//______________________________________________________________________________
3262- (void) cursorUpdate : (NSEvent *) event
3263{
3264#pragma unused(event)
3265 // It looks like [NSCursor set] method does not work properly when called from
3266 // cursorUpdate:, having, say, a parent frame with 'arrow' cursor and a child (completely
3267 // filling its parent's area) with 'cross', it happens the 'cross' cursor is not always
3268 // set correctly, for example:
3269 // if we have a TCanvas and resize it, cursor is 'arrow' inside this canvas,
3270 // though it must be 'cross'. This all, as it always happesn with "thinking different"
3271 // Apple is somehow related to run loop or something. As always, it's not documented,
3272 // so Apple can continue to think different. The idea with performSelector comes from:
3273 // http://stackoverflow.com/questions/8430236/nscursor-set-method-has-no-effect
3274 // Or may be it's just a bug:
3275 // http://stackoverflow.com/questions/13901232/nscursor-set-not-working-on-unfocused-window
3276 [self performSelector : @selector(cursorUpdate) withObject : nil afterDelay : 0.05f];
3277}
3278
3279#pragma mark - Emulated X11 properties.
3280
3281//______________________________________________________________________________
3282- (void) setProperty : (const char *) propName data : (unsigned char *) propData
3283 size : (unsigned) dataSize forType : (Atom_t) dataType format : (unsigned) format
3284{
3285 assert(propName != 0 && "-setProperty:data:size:forType:, parameter 'propName' is null");
3286 assert(propData != 0 && "-setProperty:data:size:forType:, parameter 'propData' is null");
3287 assert(dataSize != 0 && "-setProperty:data:size:forType:, parameter 'dataSize' is 0");
3288
3289 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3290 QuartzWindowProperty * property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3291
3292 //At the moment (and I think this will never change) TGX11 always calls XChangeProperty with PropModeReplace.
3293 if (property)
3294 [property resetPropertyData : propData size : dataSize type : dataType format : format];
3295 else {
3296 //No property found, add a new one.
3297 property = [[QuartzWindowProperty alloc] initWithData : propData size : dataSize
3298 type : dataType format : format];
3299 [fX11Properties setObject : property forKey : key];
3300 [property release];
3301 }
3302}
3303
3304//______________________________________________________________________________
3305- (BOOL) hasProperty : (const char *) propName
3306{
3307 assert(propName != 0 && "-hasProperty:, propName parameter is null");
3308
3309 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3310 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3311
3312 return property != nil;
3313}
3314
3315//______________________________________________________________________________
3316- (unsigned char *) getProperty : (const char *) propName returnType : (Atom_t *) type
3317 returnFormat : (unsigned *) format nElements : (unsigned *) nElements
3318{
3319 assert(propName != 0 &&
3320 "-getProperty:returnType:returnFormat:nElements:, parameter 'propName' is null");
3321 assert(type != 0 &&
3322 "-getProperty:returnType:returnFormat:nElements:, parameter 'type' is null");
3323 assert(format != 0 &&
3324 "-getProperty:returnType:returnFormat:nElements:, parameter 'format' is null");
3325 assert(nElements != 0 &&
3326 "-getProperty:returnType:returnFormat:nElements:, parameter 'nElements' is null");
3327
3328 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3329 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3330 assert(property != 0 &&
3331 "-getProperty:returnType:returnFormat:nElements, property not found");
3332
3333 NSData * const propData = property.fPropertyData;
3334
3335 const NSUInteger dataSize = [propData length];
3336 unsigned char *buff = 0;
3337 try {
3338 buff = new unsigned char[dataSize]();
3339 } catch (const std::bad_alloc &) {
3340 //Hmm, can I log, if new failed? :)
3341 NSLog(@"QuartzWindow: -getProperty:returnType:returnFormat:nElements:,"
3342 " memory allocation failed");
3343 return 0;
3344 }
3345
3346 [propData getBytes : buff length : dataSize];
3347 *format = property.fFormat;
3348
3349 *nElements = dataSize;
3350
3351 if (*format == 16)
3352 *nElements= dataSize / 2;
3353 else if (*format == 32)
3354 *nElements = dataSize / 4;
3355
3356 *type = property.fType;
3357
3358 return buff;
3359}
3360
3361//______________________________________________________________________________
3362- (void) removeProperty : (const char *) propName
3363{
3364 assert(propName != 0 && "-removeProperty:, parameter 'propName' is null");
3365
3366 NSString * const key = [NSString stringWithCString : propName
3367 encoding : NSASCIIStringEncoding];
3368 [fX11Properties removeObjectForKey : key];
3369}
3370
3371//DND
3372//______________________________________________________________________________
3373- (NSDragOperation) draggingEntered : (id<NSDraggingInfo>) sender
3374{
3375 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3376 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3377
3378 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy))
3379 return NSDragOperationCopy;
3380
3381 return NSDragOperationNone;
3382}
3383
3384//______________________________________________________________________________
3385- (BOOL) performDragOperation : (id<NSDraggingInfo>) sender
3386{
3387 //We can drag some files (images, pdfs, source code files) from
3388 //finder to ROOT's window (mainly TCanvas or text editor).
3389 //The logic is totally screwed here :((( - ROOT will try to
3390 //read a property of some window (not 'self', unfortunately) -
3391 //this works since on Window all data is in a global clipboard
3392 //(on X11 it simply does not work at all).
3393 //I'm attaching the file name as a property for the top level window,
3394 //there is no other way to make this data accessible for ROOT.
3395
3396 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3397 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3398
3399 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy)) {
3400
3401 //Here I try to put string ("file://....") into window's property to make
3402 //it accesible from ROOT's GUI.
3403 const Atom_t textUriAtom = gVirtualX->InternAtom("text/uri-list", kFALSE);
3404
3405 NSArray * const files = [pasteBoard propertyListForType : NSFilenamesPboardType];
3406 for (NSString *path in files) {
3407 //ROOT can not process several files, use the first one.
3408 NSString * const item = [@"file://" stringByAppendingString : path];
3409 //Yes, only ASCII encoding, but after all, ROOT's not able to work with NON-ASCII strings.
3410 const NSUInteger len = [item lengthOfBytesUsingEncoding : NSASCIIStringEncoding] + 1;
3411 try {
3412 std::vector<unsigned char> propertyData(len);
3413 [item getCString : (char *)&propertyData[0] maxLength : propertyData.size()
3414 encoding : NSASCIIStringEncoding];
3415 //There is no any guarantee, that this will ever work, logic in TGDNDManager is totally crazy.
3416 NSView<X11Window> * const targetView = self.fQuartzWindow.fContentView;
3417 [targetView setProperty : "_XC_DND_DATA" data : &propertyData[0]
3418 size : propertyData.size() forType : textUriAtom format : 8];
3419 } catch (const std::bad_alloc &) {
3420 //Hehe, can I log something in case of bad_alloc??? ;)
3421 NSLog(@"QuartzView: -performDragOperation:, memory allocation failed");
3422 return NO;
3423 }
3424
3425 break;
3426 }
3427
3428 //Property is attached now.
3429
3430 //Gdk on windows creates three events on file drop (WM_DROPFILES): XdndEnter, XdndPosition, XdndDrop.
3431 //1. Dnd enter.
3432 Event_t event1 = {};
3433 event1.fType = kClientMessage;
3434 event1.fWindow = fID;
3435 event1.fHandle = gVirtualX->InternAtom("XdndEnter", kFALSE);
3436 event1.fUser[0] = long(fID);
3437 event1.fUser[2] = textUriAtom;//gVirtualX->InternAtom("text/uri-list", kFALSE);
3438 //
3439 gVirtualX->SendEvent(fID, &event1);
3440
3441 //2. Dnd position.
3442 Event_t event2 = {};
3443 event2.fType = kClientMessage;
3444 event2.fWindow = fID;
3445 event2.fHandle = gVirtualX->InternAtom("XdndPosition", kFALSE);
3446 event2.fUser[0] = long(fID);
3447 event2.fUser[2] = 0;//Here I have to pack x and y for drop coordinates, shifting by 16 bits.
3448 NSPoint dropPoint = [sender draggingLocation];
3449 //convertPointFromBase is deprecated.
3450 //dropPoint = [self convertPointFromBase : dropPoint];
3451 dropPoint = [self convertPoint : dropPoint fromView : nil];
3452 //
3453 dropPoint = X11::TranslateToScreen(self, dropPoint);
3454 event2.fUser[2] = UShort_t(dropPoint.y) | (UShort_t(dropPoint.x) << 16);
3455
3456 gVirtualX->SendEvent(fID, &event2);
3457
3458 Event_t event3 = {};
3459 event3.fType = kClientMessage;
3460 event3.fWindow = fID;
3461 event3.fHandle = gVirtualX->InternAtom("XdndDrop", kFALSE);
3462
3463 gVirtualX->SendEvent(fID, &event3);
3464 }
3465
3466 return YES;//Always ok, even if file type is not supported - no need in "animation".
3467}
3468
3469@end
long
Cppyy::TCppType_t fClass
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
@ kClientMessage
Definition GuiTypes.h:63
const Mask_t kWABorderPixel
Definition GuiTypes.h:142
const Mask_t kWAOverrideRedirect
Definition GuiTypes.h:149
const Mask_t kWABitGravity
Definition GuiTypes.h:144
const Mask_t kWADontPropagate
Definition GuiTypes.h:152
const Mask_t kWAColormap
Definition GuiTypes.h:153
const Mask_t kButtonMotionMask
Definition GuiTypes.h:164
const Mask_t kWABackingStore
Definition GuiTypes.h:146
const Mask_t kButtonPressMask
Definition GuiTypes.h:161
const Mask_t kExposureMask
Definition GuiTypes.h:165
const Mask_t kWAEventMask
Definition GuiTypes.h:151
const Mask_t kWASaveUnder
Definition GuiTypes.h:150
const Mask_t kWABackPixel
Definition GuiTypes.h:140
const Mask_t kWAWinGravity
Definition GuiTypes.h:145
const Mask_t kWABackingPixel
Definition GuiTypes.h:148
const Mask_t kPointerMotionMask
Definition GuiTypes.h:163
Handle_t Atom_t
WM token.
Definition GuiTypes.h:37
const Mask_t kLeaveWindowMask
Definition GuiTypes.h:168
const Mask_t kStructureNotifyMask
Definition GuiTypes.h:166
@ kIsViewable
Definition GuiTypes.h:46
@ kIsUnviewable
Definition GuiTypes.h:46
@ kIsUnmapped
Definition GuiTypes.h:46
@ kAlways
Definition GuiTypes.h:45
const Mask_t kButtonReleaseMask
Definition GuiTypes.h:162
ECursor
Definition GuiTypes.h:372
@ kRightSide
Definition GuiTypes.h:373
@ kBottomSide
Definition GuiTypes.h:373
@ kArrowRight
Definition GuiTypes.h:375
@ kTopLeft
Definition GuiTypes.h:372
@ kBottomRight
Definition GuiTypes.h:372
@ kArrowVer
Definition GuiTypes.h:374
@ kCaret
Definition GuiTypes.h:375
@ kTopSide
Definition GuiTypes.h:373
@ kLeftSide
Definition GuiTypes.h:373
@ kWatch
Definition GuiTypes.h:375
@ kMove
Definition GuiTypes.h:374
@ kTopRight
Definition GuiTypes.h:372
@ kBottomLeft
Definition GuiTypes.h:372
@ kHand
Definition GuiTypes.h:374
@ kCross
Definition GuiTypes.h:374
@ kRotate
Definition GuiTypes.h:374
@ kArrowHor
Definition GuiTypes.h:374
@ kPointer
Definition GuiTypes.h:375
const Mask_t kWABorderPixmap
Definition GuiTypes.h:141
const Mask_t kEnterWindowMask
Definition GuiTypes.h:167
const Mask_t kWACursor
Definition GuiTypes.h:154
@ kButton4
Definition GuiTypes.h:215
@ kButton2
Definition GuiTypes.h:214
@ kButton5
Definition GuiTypes.h:215
@ kButton3
Definition GuiTypes.h:214
@ kButton1
Definition GuiTypes.h:214
Handle_t Window_t
Window handle.
Definition GuiTypes.h:29
const Mask_t kWABackPixmap
Definition GuiTypes.h:139
const Mask_t kWABorderWidth
Definition GuiTypes.h:143
const Mask_t kWABackingPlanes
Definition GuiTypes.h:147
#define d(i)
Definition RSha256.hxx:102
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned short UShort_t
Definition RtypesCore.h:40
int Int_t
Definition RtypesCore.h:45
unsigned int UInt_t
Definition RtypesCore.h:46
const Bool_t kFALSE
Definition RtypesCore.h:101
unsigned long ULong_t
Definition RtypesCore.h:55
const Bool_t kTRUE
Definition RtypesCore.h:100
#define gClient
Definition TGClient.h:157
XFontStruct * id
Definition TGX11.cxx:109
int type
Definition TGX11.cxx:121
@ kReadPermission
Definition TSystem.h:47
R__EXTERN TSystem * gSystem
Definition TSystem.h:559
#define gVirtualX
Definition TVirtualX.h:338
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition X11Buffer.mm:662
void GenerateFocusChangeEvent(NSView< X11Window > *eventView)
void GenerateExposeEvent(NSView< X11Window > *view, const NSRect &exposedRect)
void GenerateConfigureNotifyEvent(NSView< X11Window > *view, const NSRect &newFrame)
void GenerateCrossingEvent(NSEvent *theEvent)
void GenerateKeyReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
void GenerateKeyPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
void GenerateButtonPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
void GeneratePointerMotionEvent(NSEvent *theEvent)
void GenerateButtonReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
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:4408
void CocoaDrawOFF()
Definition TGCocoa.mm:4420
static Atom_t fgDeleteWindowAtom
Definition TGCocoa.h:469
ROOT::MacOSX::X11::Rectangle GetDisplayGeometry() const
Definition TGCocoa.mm:609
ROOT::MacOSX::X11::EventTranslator * GetEventTranslator() const
Definition TGCocoa.mm:4402
void CocoaDrawON()
Definition TGCocoa.mm:4414
Manages a content area.
Definition TGCanvas.h:31
A TGTextView is a text viewer widget.
Definition TGTextView.h:22
ROOT GUI Window base class.
Definition TGWindow.h:23
virtual const char * GetName() const
Return unique name, used in SavePrimitive methods.
Definition TGWindow.cxx:336
@ kIsHtmlView
Definition TGWindow.h:62
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:201
static const TString & GetIconPath()
Get the icon path in the installation. Static utility function.
Definition TROOT.cxx:3085
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1546
unsigned int fModifiers
Definition cppyy.h:12
TLine * line
NSUInteger fModifiers
ROOT::MacOSX::Util::CFScopeGuard< CGImageRef > fImage
unsigned fWidth
unsigned fHeight
unsigned fHeight
unsigned fWidth
QuartzPixmap * fBackBuffer
unsigned fPassiveGrabKeyModifiers
ECursor fCurrentCursor
void activateImplicitGrab()
BOOL fSnapshotDraw
NSMutableArray * fPassiveKeyGrabs
int fPassiveGrabButton
CGFloat fScaleFactor()
BOOL fActiveGrabOwnerEvents
QuartzWindow * fQuartzWindow
void configureNotifyTree()
void activatePassiveGrab()
CGContextRef fContext
NSMutableDictionary * fX11Properties
BOOL fPassiveGrabOwnerEvents
BOOL fIsOpenGLWidget()
unsigned fWidth()
QuartzView * fParentView
unsigned fID
unsigned fPassiveGrabEventMask
QuartzImage * fBackgroundPixmap
ROOT::MacOSX::X11::PointerGrab fCurrentGrabType
BOOL fIsOverlapped
unsigned long fBackgroundPixel
unsigned fActiveGrabEventMask
unsigned fHeight()
BOOL fOverrideRedirect
NSView< X11Window > * fContentView
unsigned long fBackgroundPixel
QuartzView * fParentView
unsigned fHeight()
CGFloat fScaleFactor()
BOOL fDelayedTransient
QuartzWindow * fQuartzWindow
void adjustXorWindowGeometry()
XorDrawingWindow * findXorWindow()
QuartzWindow * fMainWindow
QuartzView * fContentView
unsigned fWidth()
QuartzImage * fShapeCombineMask
instancetype init()
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
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
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)
NSView< X11Window > * FindViewUnderPointer()
void UnlockFocus(NSView< X11Window > *view)
int GlobalXROOTToCocoa(CGFloat xROOT)
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)
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...
unsigned fID
Definition X11Drawable.h:37
Event structure.
Definition GuiTypes.h:174
EGEventType fType
of event (see EGEventType)
Definition GuiTypes.h:175
Handle_t fHandle
general resource handle (used for atoms or windows)
Definition GuiTypes.h:185
Int_t fFormat
Next fields only used by kClientMessageEvent.
Definition GuiTypes.h:186
Window_t fWindow
window reported event is relative to
Definition GuiTypes.h:176
Longptr_t fUser[5]
5 longs can be used by client message events NOTE: only [0], [1] and [2] may be used.
Definition GuiTypes.h:187
Attributes that can be used when creating or changing a window.
Definition GuiTypes.h:93
Long_t fEventMask
set of events that should be saved
Definition GuiTypes.h:105
Mask_t fMask
bit mask specifying which fields are valid
Definition GuiTypes.h:110
Int_t fWinGravity
one of the window gravity values
Definition GuiTypes.h:100
ULong_t fBackgroundPixel
background pixel
Definition GuiTypes.h:95
Int_t fBitGravity
one of bit gravity values
Definition GuiTypes.h:99
Window attributes that can be inquired.
Definition GuiTypes.h:114
Window_t fRoot
root of screen containing window
Definition GuiTypes.h:120
Int_t fMapState
kIsUnmapped, kIsUnviewable, kIsViewable
Definition GuiTypes.h:130
ULong_t fBackingPlanes
planes to be preserved if possible
Definition GuiTypes.h:125
Long_t fAllEventMasks
set of events all people have interest in
Definition GuiTypes.h:131
ULong_t fBackingPixel
value to be used when restoring planes
Definition GuiTypes.h:126
Long_t fYourEventMask
my event mask
Definition GuiTypes.h:132
Int_t fHeight
width and height of window
Definition GuiTypes.h:116
Bool_t fMapInstalled
boolean, is color map currently installed
Definition GuiTypes.h:129
Int_t fBorderWidth
border width of window
Definition GuiTypes.h:117
Int_t fWinGravity
one of the window gravity values
Definition GuiTypes.h:123
void * fScreen
back pointer to correct screen
Definition GuiTypes.h:135
Colormap_t fColormap
color map to be associated with window
Definition GuiTypes.h:128
Int_t fClass
kInputOutput, kInputOnly
Definition GuiTypes.h:121
Int_t fBitGravity
one of bit gravity values
Definition GuiTypes.h:122
void * fVisual
the associated visual structure
Definition GuiTypes.h:119
Int_t fBackingStore
kNotUseful, kWhenMapped, kAlways
Definition GuiTypes.h:124
Int_t fY
location of window
Definition GuiTypes.h:115
Int_t fDepth
depth of window
Definition GuiTypes.h:118
Bool_t fOverrideRedirect
boolean value for override-redirect
Definition GuiTypes.h:134
Bool_t fSaveUnder
boolean, should bits under be saved?
Definition GuiTypes.h:127