Logo ROOT   6.16/01
Reference Guide
QuartzWindow.mm
Go to the documentation of this file.
1// @(#)root/graf2d:$Id$
2// Author: Timur Pocheptsov 16/02/2012
3
4/*************************************************************************
5 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//#define DEBUG_ROOT_COCOA
13
14//#define NDEBUG
15
16#ifdef DEBUG_ROOT_COCOA
17#include <iostream>
18#include <fstream>
19
20#include "TClass.h"
21#endif
22
23#include <algorithm>
24#include <stdexcept>
25#include <cassert>
26#include <vector>
27
28#include <Availability.h>
29
30#include "ROOTOpenGLView.h"
31#include "CocoaConstants.h"
32#include "QuartzWindow.h"
33#include "QuartzPixmap.h"
34#include "QuartzUtils.h"
35#include "CocoaUtils.h"
36#include "RConfigure.h"
37#include "X11Colors.h"
38#include "X11Buffer.h"
39#include "TGWindow.h"
40#include "TGClient.h"
41#include "TSystem.h"
42#include "TGCocoa.h"
43#include "TROOT.h"
44#include "TGTextView.h"
45#include "TGView.h"
46#include "TGCanvas.h"
47
48
49namespace ROOT {
50namespace MacOSX {
51namespace X11 {
52
53#pragma mark - Create a window or a view.
54
55//______________________________________________________________________________
57 UInt_t clss, void */*visual*/, SetWindowAttributes_t *attr, UInt_t)
58{
59 using namespace Details;
60
61 NSRect winRect = {};
62 winRect.origin.x = GlobalXROOTToCocoa(x);
63 winRect.origin.y = GlobalYROOTToCocoa(y + h);
64 winRect.size.width = w;
65 winRect.size.height = h;
66
67 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
69
70 QuartzWindow * const newWindow = [[QuartzWindow alloc] initWithContentRect : winRect
71 styleMask : styleMask
72 backing : NSBackingStoreBuffered
73 defer : YES
74 windowAttributes : attr];
75 if (!newWindow)
76 throw std::runtime_error("CreateTopLevelWindow failed");
77
78 newWindow.fDepth = depth;
79 newWindow.fClass = clss;
80
81 return newWindow;
82}
83
84//______________________________________________________________________________
85QuartzView *CreateChildView(QuartzView * /*parent*/, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t /*depth*/,
86 UInt_t /*clss*/, void * /*visual*/, SetWindowAttributes_t *attr, UInt_t /*wtype*/)
87{
88 NSRect viewRect = {};
89 viewRect.origin.x = x;
90 viewRect.origin.y = y;
91 viewRect.size.width = w;
92 viewRect.size.height = h;
93
94 QuartzView * const view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
95 if (!view)
96 throw std::runtime_error("CreateChildView failed");
97
98 return view;
99}
100
101#pragma mark - root window (does not really exist, it's our desktop built of all screens).
102
103//______________________________________________________________________________
105{
106 //'root' window does not exist, but we can request its attributes.
107 assert(attr != 0 && "GetRootWindowAttributes, parameter 'attr' is null");
108
109
110 NSArray * const screens = [NSScreen screens];
111 assert(screens != nil && "screens array is nil");
112 NSScreen * const mainScreen = [screens objectAtIndex : 0];
113 assert(mainScreen != nil && "screen with index 0 is nil");
114
115 *attr = WindowAttributes_t();
116
117 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
118 "GetRootWindowAttributes, gVirtualX is either null or has a wrong type");
119
120 TGCocoa * const gCocoa = static_cast<TGCocoa *>(gVirtualX);
121
122 const Rectangle &frame = gCocoa->GetDisplayGeometry();
123
124 attr->fX = 0;
125 attr->fY = 0;
126 attr->fWidth = frame.fWidth;
127 attr->fHeight = frame.fHeight;
128 attr->fBorderWidth = 0;
129 attr->fYourEventMask = 0;
130 attr->fAllEventMasks = 0;//???
131
132 attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
133 attr->fVisual = 0;
134 attr->fRoot = 0;
135}
136
137
138#pragma mark - Coordinate conversions.
139
140//______________________________________________________________________________
141NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
142{
143 assert(window != nil && "ConvertPointFromBaseToScreen, parameter 'window' is nil");
144
145 //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
146 //point conversion seems to produce wrong results with HiDPI.
147
148 NSRect tmpRect = {};
149 tmpRect.origin = windowPoint;
150 tmpRect.size = NSMakeSize(1., 1.);//This is strange size :) But if they require rect, 0,0 - will not work?
151 tmpRect = [window convertRectToScreen : tmpRect];
152
153 return tmpRect.origin;
154}
155
156//______________________________________________________________________________
157NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
158{
159 assert(window != nil && "ConvertPointFromScreenToBase, parameter 'window' is nil");
160
161 //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
162 //point conversion seems to produce wrong results with HiDPI.
163
164 NSRect tmpRect = {};
165 tmpRect.origin = screenPoint;
166 tmpRect.size = NSMakeSize(1., 1.);
167 tmpRect = [window convertRectFromScreen : tmpRect];
168
169 return tmpRect.origin;
170}
171
172//______________________________________________________________________________
173int GlobalYCocoaToROOT(CGFloat yCocoa)
174{
175 //We can have several physical displays and thus several NSScreens in some arbitrary order.
176 //With Cocoa, some screens can have negative coordinates - to the left ro down to the primary
177 //screen (whatever it means). With X11 (XQuartz) though it's always 0,0.
178
179 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
180 "GlobalYCocoaToROOT, gVirtualX is either nul or has a wrong type");
181
182 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
183
184 return int(frame.fHeight - (yCocoa - frame.fY));
185}
186
187//______________________________________________________________________________
188int GlobalXCocoaToROOT(CGFloat xCocoa)
189{
190 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
191 "GlobalXCocoaToROOT, gVirtualX is either nul or has a wrong type");
192 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
193 //With X11 coordinate space always starts from 0, 0
194 return int(xCocoa - frame.fX);
195}
196
197//______________________________________________________________________________
198int GlobalYROOTToCocoa(CGFloat yROOT)
199{
200 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
201 "GlobalYROOTToCocoa, gVirtualX is either nul or has a wrong type");
202 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
203
204 return int(frame.fY + (frame.fHeight - yROOT));
205}
206
207//______________________________________________________________________________
208int GlobalXROOTToCocoa(CGFloat xROOT)
209{
210 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
211 "GlobalXROOTToCocoa, gVirtualX is either nul or has a wrong type");
212 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
213 //With X11 coordinate space always starts from 0, 0
214 return int(frame.fX + xROOT);
215}
216
217//______________________________________________________________________________
218int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
219{
220 assert(parentView != nil && "LocalYCocoaToROOT, parent view is nil");
221
222 return int(parentView.frame.size.height - yCocoa);
223}
224
225//______________________________________________________________________________
226int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
227{
228 //:)
229 assert(parentView != nil && "LocalYROOTToCocoa, parent view is nil");
230
231 return int(parentView.frame.size.height - yROOT);
232}
233
234
235//______________________________________________________________________________
236int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
237{
238 //:)
239 assert(drawable != nil && "LocalYROOTToCocoa, drawable is nil");
240
241 return int(drawable.fHeight - yROOT);
242}
243
244//______________________________________________________________________________
245NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
246{
247 assert(from != nil && "TranslateToScreen, parameter 'from' is nil");
248
249 const NSPoint winPoint = [from convertPoint : point toView : nil];
250
251 NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], winPoint);
252 screenPoint.x = GlobalXCocoaToROOT(screenPoint.x);
253 screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);
254
255 return screenPoint;
256}
257
258//______________________________________________________________________________
259NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
260{
261 assert(to != nil && "TranslateFromScreen, parameter 'to' is nil");
262
263 point.x = GlobalXROOTToCocoa(point.x);
264 point.y = GlobalYROOTToCocoa(point.y);
265 point = ConvertPointFromScreenToBase(point, [to window]);
266
267 return [to convertPoint : point fromView : nil];
268}
269
270//______________________________________________________________________________
271NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
272{
273 //Both views are valid.
274 assert(from != nil && "TranslateCoordinates, parameter 'from' is nil");
275 assert(to != nil && "TranslateCoordinates, parameter 'to' is nil");
276
277 if ([from window] == [to window]) {
278 //Both views are in the same window.
279 return [to convertPoint : sourcePoint fromView : from];
280 } else {
281 //May be, I can do it in one call, but it's not obvious for me
282 //what is 'pixel aligned backing store coordinates' and
283 //if they are the same as screen coordinates.
284
285 //Many thanks to Apple for deprecated functions!!!
286
287 const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
288 const NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], win1Point);
289 const NSPoint win2Point = ConvertPointFromScreenToBase(screenPoint, [to window]);
290
291 return [to convertPoint : win2Point fromView : nil];
292 }
293}
294
295//______________________________________________________________________________
296bool ScreenPointIsInView(NSView<X11Window> *view, Int_t x, Int_t y)
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//______________________________________________________________________________
337NSView<X11Window> *FindDNDAwareViewInPoint(NSArray *children, Window_t dragWinID,
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//______________________________________________________________________________
362NSView<X11Window> *FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID,
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//______________________________________________________________________________
436NSView<X11Window> *FindViewUnderPointer()
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//______________________________________________________________________________
497NSView<X11Window> *FindViewForPointerEvent(NSEvent *pointerEvent)
498{
499 //FindViewForPointerEvent is required because of grabs - the receiver of the
500 //event can be different from the actual window under cursor.
501
502 assert(pointerEvent != nil &&
503 "FindViewForPointerEvent, parameter 'pointerEvent' is nil");
504
505 const Util::AutoreleasePool pool;
506
507 if (QuartzWindow *topLevel = FindWindowForPointerEvent(pointerEvent)) {
508 NSPoint mousePosition = [pointerEvent locationInWindow];
509 if ([pointerEvent window])
510 mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
511
512 //convertScreenToBase is deprecated.
513 //mousePosition = [topLevel convertScreenToBase : mousePosition];
514 mousePosition = ConvertPointFromScreenToBase(mousePosition, topLevel);
515
516 return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
517 }
518
519 return nil;
520}
521
522#pragma mark - Downscale image ("reading color bits" on retina macs).
523
524//Hoho, we support C++11?? Let's return by value then!!!
525std::vector<unsigned char> DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
526{
527 assert(w != 0 && h != 0 && "DownscaledImageData, invalid geometry");
528 assert(image != nullptr && "DonwscaledImageData, invalid parameter 'image'");
529
530 std::vector<unsigned char> result;
531 try {
532 result.resize(w * h * 4);
533 } catch (const std::bad_alloc &) {
534 NSLog(@"DownscaledImageData, memory allocation failed");
535 return result;
536 }
537
538 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());//[1]
539 if (!colorSpace.Get()) {
540 NSLog(@"DownscaledImageData, CGColorSpaceCreateDeviceRGB failed");
541 return result;
542 }
543
544 Util::CFScopeGuard<CGContextRef> ctx(CGBitmapContextCreateWithData(&result[0], w, h, 8,
545 w * 4, colorSpace.Get(),
546 kCGImageAlphaPremultipliedLast, NULL, 0));
547 if (!ctx.Get()) {
548 NSLog(@"DownscaledImageData, CGBitmapContextCreateWithData failed");
549 return result;
550 }
551
552 CGContextDrawImage(ctx.Get(), CGRectMake(0, 0, w, h), image);
553
554 return result;
555}
556
557#pragma mark - "Focus management" - just make another window key window.
558
559//______________________________________________________________________________
561{
562 //XQuartz (and other X11
563 if (![NSApp isActive])
564 return;
565
566 const Util::AutoreleasePool pool;
567
568 NSArray * const orderedWindows = [NSApp orderedWindows];
569 for (NSWindow *nsWindow in orderedWindows) {
570 if (![nsWindow isKindOfClass : [QuartzWindow class]])
571 continue;
572
573 QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
574
575 if (qWindow.fIsDeleted || qWindow.fMapState != kIsViewable || qWindow.fID == winID)
576 continue;
577
579 continue;
580
581 [qWindow makeKeyAndOrderFront : qWindow];
582 break;
583 }
584}
585
586#pragma mark - 'shape mask' - to create a window with arbitrary (probably non-rectangle) shape.
587
588//______________________________________________________________________________
589void ClipToShapeMask(NSView<X11Window> *view, CGContextRef ctx)
590{
591 assert(view != nil && "ClipToShapeMask, parameter 'view' is nil");
592 assert(ctx != 0 && "ClipToShapeMask, parameter 'ctx' is null");
593
594 QuartzWindow * const topLevelParent = view.fQuartzWindow;
595 assert(topLevelParent.fShapeCombineMask != nil &&
596 "ClipToShapeMask, fShapeCombineMask is nil on a top-level window");
597 assert(topLevelParent.fShapeCombineMask.fImage != 0 &&
598 "ClipToShapeMask, shape mask is null");
599
600 //Important: shape mask should have the same width and height as
601 //a top-level window. In ROOT it does not :( Say hello to visual artifacts.
602
603 //Attach clip mask to the context.
604 if (!view.fParentView) {
605 //'view' is a top-level view.
606 const CGRect clipRect = CGRectMake(0, 0, topLevelParent.fShapeCombineMask.fWidth,
607 topLevelParent.fShapeCombineMask.fHeight);
608 CGContextClipToMask(ctx, clipRect, topLevelParent.fShapeCombineMask.fImage);
609 } else {
610 NSRect clipRect = view.frame;
611 //More complex case: 'self' is a child view, we have to create a subimage from shape mask.
612 clipRect.origin = [view.fParentView convertPoint : clipRect.origin
613 toView : [view window].contentView];
614 clipRect.origin.y = X11::LocalYROOTToCocoa((NSView<X11Window> *)[view window].contentView,
615 clipRect.origin.y + clipRect.size.height);
616
617 if (AdjustCropArea(topLevelParent.fShapeCombineMask, clipRect)) {
619 clipImageGuard(CGImageCreateWithImageInRect(topLevelParent.fShapeCombineMask.fImage,
620 NSRectToCGRect(clipRect)));
621 clipRect.origin = NSPoint();
622 CGContextClipToMask(ctx, NSRectToCGRect(clipRect), clipImageGuard.Get());
623 } else {
624 //View is invisible.
625 CGRect rect = {};
626 CGContextClipToRect(ctx, rect);
627 }
628 }
629}
630
631#pragma mark - Window's geometry and attributes.
632
633//______________________________________________________________________________
634void SetWindowAttributes(const SetWindowAttributes_t *attr, NSObject<X11Window> *window)
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//______________________________________________________________________________
665void GetWindowGeometry(NSObject<X11Window> *win, WindowAttributes_t *dst)
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//______________________________________________________________________________
678void GetWindowAttributes(NSObject<X11Window> *window, WindowAttributes_t *dst)
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//______________________________________________________________________________
909bool ViewIsTextView(NSView<X11Window> *view)
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//______________________________________________________________________________
953bool ViewIsHtmlView(NSView<X11Window> *view)
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//______________________________________________________________________________
986NSView<X11Window> *FrameForTextView(NSView<X11Window> *textView)
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//______________________________________________________________________________
999NSView<X11Window> *FrameForHtmlView(NSView<X11Window> *htmlView)
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//______________________________________________________________________________
1014bool LockFocus(NSView<X11Window> *view)
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//______________________________________________________________________________
1035void UnlockFocus(NSView<X11Window> *view)
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
1126@implementation QuartzWindow
1127
1128@synthesize fMainWindow;
1129@synthesize fHasFocus;
1130
1131#pragma mark - QuartzWindow's life cycle.
1132
1133//______________________________________________________________________________
1134- (id) initWithContentRect : (NSRect) contentRect styleMask : (NSUInteger) windowStyle
1135 backing : (NSBackingStoreType) bufferingType defer : (BOOL) deferCreation
1136 windowAttributes : (const SetWindowAttributes_t *) attr
1137{
1138 self = [super initWithContentRect : contentRect styleMask : windowStyle
1139 backing : bufferingType defer : deferCreation];
1140
1141 if (self) {
1142 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1143 [self setAllowsConcurrentViewDrawing : NO];
1144
1145 self.delegate = self;
1146 //create content view here.
1147 NSRect contentViewRect = contentRect;
1148 contentViewRect.origin.x = 0.f;
1149 contentViewRect.origin.y = 0.f;
1150
1151 fContentView = [[QuartzView alloc] initWithFrame : contentViewRect windowAttributes : 0];
1152
1153 [self setContentView : fContentView];
1154
1155 [fContentView release];
1156 fDelayedTransient = NO;
1157
1158 if (attr)
1159 X11::SetWindowAttributes(attr, self);
1160
1161 fIsDeleted = NO;
1162 fHasFocus = NO;
1163 }
1164
1165 return self;
1166}
1167
1168//______________________________________________________________________________
1169- (id) initWithGLView : (ROOTOpenGLView *) glView
1170{
1171 using namespace Details;
1172
1173 assert(glView != nil && "-initWithGLView, parameter 'glView' is nil");
1174
1175 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
1177
1178 NSRect contentRect = glView.frame;
1179 contentRect.origin = NSPoint();
1180
1181 self = [super initWithContentRect : contentRect styleMask : styleMask
1182 backing : NSBackingStoreBuffered defer : NO];
1183
1184 if (self) {
1185 //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1186 [self setAllowsConcurrentViewDrawing : NO];
1187 self.delegate = self;
1188 fContentView = glView;
1189 [self setContentView : fContentView];
1190 fDelayedTransient = NO;
1191 fIsDeleted = NO;
1192 fHasFocus = NO;
1193 }
1194
1195 return self;
1196}
1197
1198//______________________________________________________________________________
1199- (void) dealloc
1200{
1201 [fShapeCombineMask release];
1202 [super dealloc];
1203}
1204
1205//______________________________________________________________________________
1206- (BOOL) fIsDeleted
1207{
1208 return fIsDeleted;
1209}
1210
1211//______________________________________________________________________________
1212- (void) setContentView:(NSView *)cv
1213{
1214 [super setContentView:cv];
1215 if ([cv isKindOfClass:[QuartzView class]])
1216 fContentView = (QuartzView *)cv;
1217 else
1218 fContentView = nil;
1219}
1220
1221//______________________________________________________________________________
1222- (void) setFIsDeleted : (BOOL) deleted
1223{
1224 fIsDeleted = deleted;
1225}
1226
1227#pragma mark - Forwaring: I want to forward a lot of property setters/getters to the content view.
1228
1229//______________________________________________________________________________
1230- (void) forwardInvocation : (NSInvocation *) anInvocation
1231{
1232 if (!fContentView)
1233 return;
1234
1235 if ([fContentView respondsToSelector : [anInvocation selector]]) {
1236 [anInvocation invokeWithTarget : fContentView];
1237 } else {
1238 [super forwardInvocation : anInvocation];
1239 }
1240}
1241
1242//______________________________________________________________________________
1243- (NSMethodSignature*) methodSignatureForSelector : (SEL) selector
1244{
1245 NSMethodSignature *signature = [super methodSignatureForSelector : selector];
1246
1247 if (!signature) {
1248 if (fContentView)
1249 signature = [fContentView methodSignatureForSelector : selector];
1250 }
1251
1252 return signature;
1253}
1254
1255//______________________________________________________________________________
1256- (void) addTransientWindow : (QuartzWindow *) window
1257{
1258 //Transient window: all the popups (menus, dialogs, popups, comboboxes, etc.)
1259 //always should be on the top of its 'parent' window.
1260 //To enforce this ordering, I have to connect such windows with parent/child
1261 //relation (it's not the same as a view hierarchy - both child and parent
1262 //windows are top-level windows).
1263
1264 assert(window != nil && "-addTransientWindow:, parameter 'window' is nil");
1265
1266 window.fMainWindow = self;
1267
1268 if (window.fMapState != kIsViewable) {
1269 //If I add it as child, it'll immediately make a window visible
1270 //and this thing sucks.
1271 window.fDelayedTransient = YES;
1272 } else {
1273 [self addChildWindow : window ordered : NSWindowAbove];
1274 window.fDelayedTransient = NO;
1275 }
1276}
1277
1278//______________________________________________________________________________
1279- (void) makeKeyAndOrderFront : (id) sender
1280{
1281#pragma unused(sender)
1282
1283 //The more I know Cocoa, the less I like it.
1284 //Window behavior between spaces is a total mess.
1285 //Set the window to join all spaces.
1286#ifdef MAC_OS_X_VERSION_10_9
1287 [self setCollectionBehavior : NSWindowCollectionBehaviorMoveToActiveSpace];
1288#else
1289 [self setCollectionBehavior : NSWindowCollectionBehaviorCanJoinAllSpaces];
1290#endif
1291 //now bring it to the front, it will appear on the active space.
1292 [super makeKeyAndOrderFront : self];
1293 //then reset the collection behavior to default, so the window
1294 [self setCollectionBehavior : NSWindowCollectionBehaviorDefault];
1295}
1296
1297//______________________________________________________________________________
1298- (void) setFDelayedTransient : (BOOL) d
1299{
1301}
1302
1303//______________________________________________________________________________
1305{
1306 return fShapeCombineMask;
1307}
1308
1309//______________________________________________________________________________
1310- (void) setFShapeCombineMask : (QuartzImage *) mask
1311{
1312 if (mask != fShapeCombineMask) {
1313 [fShapeCombineMask release];
1314 if (mask) {
1315 fShapeCombineMask = [mask retain];
1316 //TODO: Check window's shadow???
1317 }
1318 }
1319}
1320
1321#pragma mark - X11Drawable's protocol.
1322
1323//______________________________________________________________________________
1324- (BOOL) fIsPixmap
1325{
1326 //Never.
1327 return NO;
1328}
1329
1330//______________________________________________________________________________
1331- (BOOL) fIsOpenGLWidget
1332{
1333 //Never.
1334 return NO;
1335}
1336
1337//______________________________________________________________________________
1338- (CGFloat) fScaleFactor
1339{
1340 if (!self.screen)
1341 return 1.;
1342 return self.screen.backingScaleFactor;
1343}
1344
1345//______________________________________________________________________________
1346- (int) fX
1347{
1348 return X11::GlobalXCocoaToROOT(self.frame.origin.x);
1349}
1350
1351//______________________________________________________________________________
1352- (int) fY
1353{
1354 return X11::GlobalYCocoaToROOT(self.frame.origin.y + self.frame.size.height);
1355}
1356
1357//______________________________________________________________________________
1358- (unsigned) fWidth
1359{
1360 return self.frame.size.width;
1361}
1362
1363//______________________________________________________________________________
1364- (unsigned) fHeight
1365{
1366 //NSWindow's frame (height component) also includes title-bar.
1367 //So I have to use content view's height.
1368 //Obviously, there is a "hole" == 22 pixels.
1369 assert(fContentView != nil && "-fHeight:, content view is nil");
1370
1371 return fContentView.frame.size.height;
1372}
1373
1374//______________________________________________________________________________
1375- (void) setDrawableSize : (NSSize) newSize
1376{
1377 //Can not simply do self.frame.size = newSize.
1378 assert(!(newSize.width < 0) && "-setDrawableSize:, width is negative");
1379 assert(!(newSize.height < 0) && "-setDrawableSize:, height is negative");
1380
1381 NSRect frame = self.frame;
1382 //dY is potentially a titlebar height.
1383 const CGFloat dY = fContentView ? frame.size.height - fContentView.frame.size.height : 0.;
1384 //Adjust the frame.
1385 frame.origin.y = frame.origin.y + frame.size.height - newSize.height - dY;
1386 frame.size = newSize;
1387 frame.size.height += dY;
1388 [self setFrame : frame display : YES];
1389}
1390
1391//______________________________________________________________________________
1392- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
1393{
1394 NSSize newSize = {};
1395 newSize.width = w;
1396 newSize.height = h;
1397 [self setContentSize : newSize];
1398
1399 //Check how this is affected by title bar's height.
1400 NSPoint topLeft = {};
1401 topLeft.x = X11::GlobalXROOTToCocoa(x);
1402 topLeft.y = X11::GlobalYROOTToCocoa(y);
1403
1404 [self setFrameTopLeftPoint : topLeft];
1405}
1406
1407//______________________________________________________________________________
1408- (void) setX : (int) x Y : (int) y
1409{
1410 NSPoint topLeft = {};
1411 topLeft.x = X11::GlobalXROOTToCocoa(x);
1412 topLeft.y = X11::GlobalYROOTToCocoa(y);
1413
1414 [self setFrameTopLeftPoint : topLeft];
1415}
1416
1417//______________________________________________________________________________
1418- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area withMask : (QuartzImage *) mask
1419 clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
1420{
1421 if (!fContentView)
1422 return;
1423
1424 [fContentView copy : src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
1425}
1426
1427//______________________________________________________________________________
1428- (unsigned char *) readColorBits : (X11::Rectangle) area
1429{
1430 if (!fContentView)
1431 return nullptr;
1432
1433 return [fContentView readColorBits : area];
1434}
1435
1436#pragma mark - X11Window protocol's implementation.
1437
1438//______________________________________________________________________________
1440{
1441 return nil;
1442}
1443
1444//______________________________________________________________________________
1445- (void) setFParentView : (QuartzView *) parent
1446{
1447#pragma unused(parent)
1448}
1449
1450//______________________________________________________________________________
1451- (NSView<X11Window> *) fContentView
1452{
1453 return fContentView;
1454}
1455
1456//______________________________________________________________________________
1458{
1459 return self;
1460}
1461
1462//... many forwards to fContentView.
1463
1464//______________________________________________________________________________
1465- (void) setFBackgroundPixel : (unsigned long) backgroundColor
1466{
1467 if (!fContentView)
1468 return;
1469
1470 if (!fShapeCombineMask) {
1471 CGFloat rgba[] = {0., 0., 0., 1.};
1472 X11::PixelToRGB(backgroundColor, rgba);
1473
1474 [self setBackgroundColor : [NSColor colorWithColorSpace : [NSColorSpace deviceRGBColorSpace] components : rgba count : 4]];
1475 }
1476
1477 fContentView.fBackgroundPixel = backgroundColor;
1478}
1479
1480//______________________________________________________________________________
1481- (unsigned long) fBackgroundPixel
1482{
1483 if (!fContentView)
1484 return 0;
1485
1487}
1488
1489//______________________________________________________________________________
1490- (int) fMapState
1491{
1492 //Top-level window can be only kIsViewable or kIsUnmapped (not unviewable).
1493 if (!fContentView)
1494 return kIsUnmapped;
1495
1496 if ([fContentView isHidden])
1497 return kIsUnmapped;
1498
1499 return kIsViewable;
1500}
1501
1502//______________________________________________________________________________
1503- (void) addChild : (NSView<X11Window> *) child
1504{
1505 assert(child != nil && "-addChild:, parameter 'child' is nil");
1506
1507 if (!fContentView) {
1508 //This can happen only in case of re-parent operation.
1509 assert([child isKindOfClass : [QuartzView class]] &&
1510 "-addChild: gl view in a top-level window as content view is not supported");
1511
1512 fContentView = (QuartzView *)child;
1513 [self setContentView : child];
1515 } else
1516 [fContentView addChild : child];
1517}
1518
1519//______________________________________________________________________________
1520- (void) getAttributes : (WindowAttributes_t *) attr
1521{
1522 if (!fContentView)
1523 return;
1524
1525 assert(attr && "-getAttributes:, parameter 'attr' is nil");
1526
1527 X11::GetWindowAttributes(self, attr);
1528}
1529
1530//______________________________________________________________________________
1531- (void) setAttributes : (const SetWindowAttributes_t *) attr
1532{
1533 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
1534
1535#ifdef DEBUG_ROOT_COCOA
1536 log_attributes(attr, self.fID);
1537#endif
1538
1539 X11::SetWindowAttributes(attr, self);
1540}
1541
1542//______________________________________________________________________________
1543- (void) mapRaised
1544{
1545 if (!fContentView)
1546 return;
1547
1548 const Util::AutoreleasePool pool;
1549
1550 [fContentView setHidden : NO];
1551 [self makeKeyAndOrderFront : self];
1552 [fContentView configureNotifyTree];
1553
1554 if (fDelayedTransient) {
1555 fDelayedTransient = NO;
1556 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1557 }
1558}
1559
1560//______________________________________________________________________________
1561- (void) mapWindow
1562{
1563 if (!fContentView)
1564 return;
1565
1566 const Util::AutoreleasePool pool;
1567
1568 [fContentView setHidden : NO];
1569 [self makeKeyAndOrderFront : self];
1570 [fContentView configureNotifyTree];
1571
1572 if (fDelayedTransient) {
1573 fDelayedTransient = NO;
1574 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1575 }
1576}
1577
1578//______________________________________________________________________________
1580{
1581 if (!fContentView)
1582 return;
1583
1584 const Util::AutoreleasePool pool;
1585
1586 [fContentView mapSubwindows];
1587 [fContentView configureNotifyTree];
1588}
1589
1590//______________________________________________________________________________
1591- (void) unmapWindow
1592{
1593 if (!fContentView)
1594 return;
1595
1596 [fContentView setHidden : YES];
1597 [self orderOut : self];
1598
1600 [fMainWindow removeChildWindow : self];
1601 fMainWindow = nil;
1602 }
1603}
1604
1605#pragma mark - Events.
1606
1607//______________________________________________________________________________
1608- (void) sendEvent : (NSEvent *) theEvent
1609{
1610 //With XQuartz, if you open a menu and try to move a window without closing this menu,
1611 //window does not move, menu closes, and after that you can start draggin a window again.
1612 //With Cocoa I can not do such a thing (window WILL move), but still can report button release event
1613 //to close a menu.
1614 if (!fContentView)
1615 return;
1616
1617 if (theEvent.type == Details::kLeftMouseDown || theEvent.type == Details::kRightMouseDown) {
1618 bool generateFakeRelease = false;
1619
1620 const NSPoint windowPoint = [theEvent locationInWindow];
1621
1622 if (windowPoint.x <= 4 || windowPoint.x >= self.fWidth - 4)
1623 generateFakeRelease = true;
1624
1625 if (windowPoint.y <= 4 || windowPoint.y >= self.fHeight - 4)
1626 generateFakeRelease = true;
1627
1628 const NSPoint viewPoint = [fContentView convertPoint : windowPoint fromView : nil];
1629
1630 if (viewPoint.y <= 0 && windowPoint.y >= 0)
1631 generateFakeRelease = true;
1632
1633 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1634 "-sendEvent:, gVirtualX is either null or not of TGCocoa type");
1635
1636 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1637 if (vx->GetEventTranslator()->HasPointerGrab() && generateFakeRelease) {
1639 theEvent.type == Details::kLeftMouseDown ?
1640 kButton1 : kButton3);
1641 //Yes, ignore this event completely (this means, you are not able to immediately start
1642 //resizing a window, if some popup is open. Actually, this is more or less
1643 //the same as with XQuartz and X11 version.
1644 return;
1645 }
1646 }
1647
1648 [super sendEvent : theEvent];
1649}
1650
1651#pragma mark - NSWindowDelegate's methods.
1652
1653//______________________________________________________________________________
1654- (BOOL) windowShouldClose : (id) sender
1655{
1656#pragma unused(sender)
1657 if (!fContentView)
1658 return NO;
1659
1660 if ([[self childWindows] count])
1661 return NO;
1662
1663 //Prepare client message for a window.
1664 Event_t closeEvent = {};
1665 closeEvent.fWindow = fContentView.fID;
1666 closeEvent.fType = kClientMessage;
1667 closeEvent.fFormat = 32;//Taken from GUI classes.
1669 closeEvent.fUser[0] = TGCocoa::fgDeleteWindowAtom;
1670 //Place it into the queue.
1671 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1672 "-windowShouldClose:, gVirtualX is either null or has a type different from TGCocoa");
1673 ((TGCocoa *)gVirtualX)->SendEvent(fContentView.fID, &closeEvent);
1674
1675 //Do not let AppKit to close a window,
1676 //ROOT will do.
1677 return NO;
1678}
1679
1680//______________________________________________________________________________
1681- (void) windowDidBecomeKey : (NSNotification *) aNotification
1682{
1683#pragma unused(aNotification)
1684
1685 if (!fContentView)
1686 return;
1687
1689 fHasFocus = YES;
1690 //
1691 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1692 "-windowDidBecomeKey:, gVirtualX is null or not of TGCocoa type");
1693 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1694 vx->GetEventTranslator()->GenerateFocusChangeEvent(self.fContentView);
1695 }
1696}
1697
1698
1699//______________________________________________________________________________
1700- (void) windowDidResignKey : (NSNotification *) aNotification
1701{
1702#pragma unused(aNotification)
1703 fHasFocus = NO;
1704}
1705
1706@end
1707
1708#pragma mark - Passive key grab info.
1709
1710@implementation PassiveKeyGrab
1711
1712//______________________________________________________________________________
1713- (id) initWithKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1714{
1715 if (self = [super init]) {
1716 fKeyCode = keyCode;
1717 fModifiers = modifiers;
1718 }
1719
1720 return self;
1721}
1722
1723//______________________________________________________________________________
1724- (BOOL) matchKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1725{
1726 return keyCode == fKeyCode && modifiers == fModifiers;
1727}
1728
1729//______________________________________________________________________________
1730- (BOOL) matchKey : (unichar) keyCode
1731{
1732 return keyCode == fKeyCode;
1733}
1734
1735//______________________________________________________________________________
1736- (unichar) fKeyCode
1737{
1738 return fKeyCode;
1739}
1740
1741//______________________________________________________________________________
1742- (NSUInteger) fModifiers
1743{
1744 return fModifiers;
1745}
1746
1747@end
1748
1749#pragma mark - X11 property emulation.
1750
1751@interface QuartzWindowProperty : NSObject {
1752 NSData *fPropertyData;
1753 Atom_t fType;
1754 unsigned fFormat;
1755}
1756
1757@property (nonatomic, readonly) Atom_t fType;
1758
1759@end
1760
1761@implementation QuartzWindowProperty
1762
1763@synthesize fType;
1764
1765//______________________________________________________________________________
1766- (id) initWithData : (unsigned char *) data size : (unsigned) dataSize type : (Atom_t) type format : (unsigned) format
1767{
1768 if (self = [super init]) {
1769 //Memory is zero-initialized, but just to make it explicit:
1770 fPropertyData = nil;
1771 fType = 0;
1772 fFormat = 0;
1773
1774 [self resetPropertyData : data size : dataSize type : type format : format];
1775 }
1776
1777 return self;
1778}
1779
1780//______________________________________________________________________________
1781- (void) dealloc
1782{
1783 [fPropertyData release];
1784
1785 [super dealloc];
1786}
1787
1788//______________________________________________________________________________
1789- (void) resetPropertyData : (unsigned char *) data size : (unsigned) dataSize
1790 type : (Atom_t) type format : (unsigned) format
1791{
1792 [fPropertyData release];
1793
1794 fFormat = format;
1795 if (format == 16)
1796 dataSize *= 2;
1797 else if (format == 32)
1798 dataSize *= 4;
1799
1800 fPropertyData = [[NSData dataWithBytes : data length : dataSize] retain];
1801
1802 fType = type;
1803}
1804
1805//______________________________________________________________________________
1806- (NSData *) fPropertyData
1807{
1808 return fPropertyData;
1809}
1810
1811//______________________________________________________________________________
1812- (unsigned) fFormat
1813{
1814 return fFormat;
1815}
1816
1817@end
1818
1819#pragma mark - QuartzView.
1820
1821//
1822//QuartzView is a children view (also is a content view for a top-level QuartzWindow).
1823//
1824
1825@implementation QuartzView
1826
1827@synthesize fID;
1828@synthesize fContext;
1829/////////////////////
1830//SetWindowAttributes_t/WindowAttributes_t
1831@synthesize fEventMask;
1832@synthesize fClass;
1833@synthesize fDepth;
1834@synthesize fBitGravity;
1835@synthesize fWinGravity;
1836@synthesize fBackgroundPixel;
1837@synthesize fOverrideRedirect;
1838//SetWindowAttributes_t/WindowAttributes_t
1839/////////////////////
1840@synthesize fHasFocus;
1841@synthesize fParentView;
1842
1843@synthesize fPassiveGrabButton;
1844@synthesize fPassiveGrabEventMask;
1845@synthesize fPassiveGrabKeyModifiers;
1846@synthesize fActiveGrabEventMask;
1847@synthesize fPassiveGrabOwnerEvents;
1848@synthesize fSnapshotDraw;
1849@synthesize fCurrentCursor;
1850@synthesize fIsDNDAware;
1851
1852#pragma mark - Lifetime.
1853
1854//______________________________________________________________________________
1855- (id) initWithFrame : (NSRect) frame windowAttributes : (const SetWindowAttributes_t *)attr
1856{
1857 if (self = [super initWithFrame : frame]) {
1858 //Make this explicit (though memory is zero initialized).
1859 fBackBuffer = nil;
1860 fID = 0;
1861
1862 //Passive grab parameters.
1863 fPassiveGrabButton = -1;//0 is kAnyButton.
1866
1867 fPassiveKeyGrabs = [[NSMutableArray alloc] init];
1868
1869 [self setCanDrawConcurrently : NO];
1870
1871 [self setHidden : YES];
1872 //Actually, check if view need this.
1873 //
1874 if (attr)
1875 X11::SetWindowAttributes(attr, self);
1876
1878 fX11Properties = [[NSMutableDictionary alloc] init];
1879
1883 }
1884
1885 return self;
1886}
1887
1888//______________________________________________________________________________
1889- (void) dealloc
1890{
1891 [fBackBuffer release];
1892 [fPassiveKeyGrabs release];
1893 [fX11Properties release];
1894 [fBackgroundPixmap release];
1895 [super dealloc];
1896}
1897
1898#pragma mark - Tracking area.
1899
1900//Tracking area is required to ... track mouse motion events inside a view.
1901
1902//______________________________________________________________________________
1903- (void) updateTrackingAreas
1904{
1905 [super updateTrackingAreas];
1906
1907 if (!fID)
1908 return;
1909
1910 const Util::AutoreleasePool pool;
1911
1912 if (NSArray *trackingArray = [self trackingAreas]) {
1913 const NSUInteger size = [trackingArray count];
1914 for (NSUInteger i = 0; i < size; ++i) {
1915 NSTrackingArea * const t = [trackingArray objectAtIndex : i];
1916 [self removeTrackingArea : t];
1917 }
1918 }
1919
1920 const NSUInteger trackerOptions = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
1921 NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
1922 NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate;
1923
1924 NSRect frame = {};
1925 frame.size.width = self.fWidth;
1926 frame.size.height = self.fHeight;
1927
1928 NSTrackingArea * const tracker = [[NSTrackingArea alloc] initWithRect : frame
1929 options : trackerOptions owner : self userInfo : nil];
1930 [self addTrackingArea : tracker];
1931 [tracker release];
1932}
1933
1934//______________________________________________________________________________
1935- (void) updateTrackingAreasAfterRaise
1936{
1937 [self updateTrackingAreas];
1938
1939 for (QuartzView *childView in [self subviews])
1940 [childView updateTrackingAreasAfterRaise];
1941}
1942
1943#pragma mark - X11Drawable protocol.
1944
1945//______________________________________________________________________________
1946- (BOOL) fIsPixmap
1947{
1948 return NO;
1949}
1950
1951//______________________________________________________________________________
1952- (BOOL) fIsOpenGLWidget
1953{
1954 return NO;
1955}
1956
1957//______________________________________________________________________________
1958- (CGFloat) fScaleFactor
1959{
1960 return self.fQuartzWindow.fScaleFactor;
1961}
1962
1963//______________________________________________________________________________
1964- (int) fX
1965{
1966 return self.frame.origin.x;
1967}
1968
1969//______________________________________________________________________________
1970- (int) fY
1971{
1972 return self.frame.origin.y;
1973}
1974
1975//______________________________________________________________________________
1976- (unsigned) fWidth
1977{
1978 return self.frame.size.width;
1979}
1980
1981//______________________________________________________________________________
1982- (unsigned) fHeight
1983{
1984 return self.frame.size.height;
1985}
1986
1987//______________________________________________________________________________
1988- (void) setDrawableSize : (NSSize) newSize
1989{
1990 assert(!(newSize.width < 0) && "-setDrawableSize, width is negative");
1991 assert(!(newSize.height < 0) && "-setDrawableSize, height is negative");
1992
1993 //This will cause redraw(?)
1994
1995 //In X11, resize changes the size, but upper-left corner is not changed.
1996 //In Cocoa, bottom-left is fixed.
1997 NSRect frame = self.frame;
1998 frame.size = newSize;
1999
2000 self.frame = frame;
2001}
2002
2003//______________________________________________________________________________
2004- (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
2005{
2006 NSRect newFrame = {};
2007 newFrame.origin.x = x;
2008 newFrame.origin.y = y;
2009 newFrame.size.width = w;
2010 newFrame.size.height = h;
2011
2012 self.frame = newFrame;
2013}
2014
2015//______________________________________________________________________________
2016- (void) setX : (int) x Y : (int) y
2017{
2018 NSRect newFrame = self.frame;
2019 newFrame.origin.x = x;
2020 newFrame.origin.y = y;
2021
2022 self.frame = newFrame;
2023}
2024
2025//______________________________________________________________________________
2026- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2027 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY
2028 toPoint : (X11::Point) dstPoint
2029{
2030 //Check parameters.
2031 assert(srcImage != nil &&
2032 "-copyImage:area:withMask:clipOrigin:toPoint:, parameter 'srcImage' is nil");
2033 assert(srcImage.fImage != nil &&
2034 "-copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
2035
2036 //Check self.
2037 assert(self.fContext != 0 &&
2038 "-copyImage:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2039
2040 if (!X11::AdjustCropArea(srcImage, area)) {
2041 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2042 " srcRect and copyRect do not intersect");
2043 return;
2044 }
2045
2046 //No RAII for subImage, since it can be really subimage or image itself and
2047 //in these cases there is no need to release image.
2048 CGImageRef subImage = 0;
2049 bool needSubImage = false;
2050 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2051 needSubImage = true;
2052 subImage = X11::CreateSubImage(srcImage, area);
2053 if (!subImage) {
2054 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2055 " subimage creation failed");
2056 return;
2057 }
2058 } else
2059 subImage = srcImage.fImage;
2060
2061 //Save context state.
2062 const Quartz::CGStateGuard ctxGuard(self.fContext);
2063
2064 //Scale and translate to undo isFlipped.
2065 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2066 CGContextScaleCTM(self.fContext, 1., -1.);
2067 //Set clip mask on a context.
2068
2069 if (mask) {
2070 assert(mask.fImage != nil &&
2071 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2072 assert(CGImageIsMask(mask.fImage) == true &&
2073 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2074 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2075 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2076 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2077 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2078 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2079 }
2080
2081 //Convert from X11 to Cocoa (as soon as we scaled y * -1).
2082 //dstPoint.fY = X11::LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
2083 const CGFloat dstY = X11::LocalYROOTToCocoa(self, CGFloat(dstPoint.fY) + area.fHeight);
2084 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2085 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2086 CGContextDrawImage(self.fContext, imageRect, subImage);
2087
2088 if (needSubImage)
2089 CGImageRelease(subImage);
2090}
2091
2092//______________________________________________________________________________
2093- (void) copyView : (QuartzView *) srcView area : (X11::Rectangle) area toPoint : (X11::Point) dstPoint
2094{
2095 //To copy one "window" to another "window", I have to ask source QuartzView to draw intself into
2096 //bitmap, and copy this bitmap into the destination view.
2097
2098 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2099
2100 const NSRect frame = [srcView frame];
2101 //imageRep is in autorelease pool now.
2102 NSBitmapImageRep * const imageRep = [srcView bitmapImageRepForCachingDisplayInRect : frame];
2103 if (!imageRep) {
2104 NSLog(@"QuartzView: -copyView:area:toPoint failed");
2105 return;
2106 }
2107
2108 assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2109 assert(self.fContext != 0 && "-copyView:area:toPoint, self.fContext is null");
2110
2111 //It can happen, that src and self are the same.
2112 //cacheDisplayInRect calls drawRect with bitmap context
2113 //(and this will reset self.fContext: I have to save/restore it.
2114 CGContextRef ctx = srcView.fContext;
2115 srcView.fSnapshotDraw = YES;
2116 [srcView cacheDisplayInRect : frame toBitmapImageRep : imageRep];
2117 srcView.fSnapshotDraw = NO;
2118 srcView.fContext = ctx;
2119
2120 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fWidth, area.fHeight);
2121 const Util::CFScopeGuard<CGImageRef> subImage(CGImageCreateWithImageInRect(imageRep.CGImage, subImageRect));
2122
2123 if (!subImage.Get()) {
2124 NSLog(@"QuartzView: -copyView:area:toPoint, CGImageCreateWithImageInRect failed");
2125 return;
2126 }
2127
2128 const Quartz::CGStateGuard ctxGuard(self.fContext);
2129 const CGRect imageRect = CGRectMake(dstPoint.fX,
2130 [self visibleRect].size.height - (CGFloat(dstPoint.fY) + area.fHeight),
2131 area.fWidth, area.fHeight);
2132
2133 CGContextTranslateCTM(self.fContext, 0., [self visibleRect].size.height);
2134 CGContextScaleCTM(self.fContext, 1., -1.);
2135
2136 CGContextDrawImage(self.fContext, imageRect, subImage.Get());
2137}
2138
2139//______________________________________________________________________________
2140- (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
2141 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2142{
2143 //Check parameters.
2144 assert(srcPixmap != nil && "-copyPixmap:area:withMask:clipOrigin:toPoint:, parameter 'srcPixmap' is nil");
2145
2146 if (!X11::AdjustCropArea(srcPixmap, area)) {
2147 NSLog(@"QuartzView: -copyPixmap:area:withMask:clipOrigin:toPoint,"
2148 " no intersection between pixmap rectangle and cropArea");
2149 return;
2150 }
2151
2152 //Check self.
2153 assert(self.fContext != 0 &&
2154 "-copyPixmap:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2155
2156 //Save context state.
2157 const Quartz::CGStateGuard ctxGuard(self.fContext);
2158
2159 CGContextTranslateCTM(self.fContext, 0., self.frame.size.height);//???
2160 CGContextScaleCTM(self.fContext, 1., -1.);
2161
2162 const Util::CFScopeGuard<CGImageRef> imageFromPixmap([srcPixmap createImageFromPixmap]);
2163 assert(imageFromPixmap.Get() != 0 &&
2164 "-copyPixmap:area:withMask:clipOrigin:toPoint:, createImageFromPixmap failed");
2165
2166 CGImageRef subImage = 0;
2167 bool needSubImage = false;
2168 if (area.fX || area.fY || area.fWidth != srcPixmap.fWidth || area.fHeight != srcPixmap.fHeight) {
2169 needSubImage = true;
2170 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
2171 subImage = CGImageCreateWithImageInRect(imageFromPixmap.Get(), subImageRect);
2172 if (!subImage) {
2173 NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2174 " subimage creation failed");
2175 return;
2176 }
2177 } else
2178 subImage = imageFromPixmap.Get();
2179
2180 if (mask) {
2181 assert(mask.fImage != nil &&
2182 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2183 assert(CGImageIsMask(mask.fImage) == true &&
2184 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2185
2186 //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2187 const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2188 //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2189 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2190 CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2191 }
2192
2193 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2194 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2195 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2196 CGContextDrawImage(self.fContext, imageRect, imageFromPixmap.Get());
2197
2198 if (needSubImage)
2199 CGImageRelease(subImage);
2200}
2201
2202
2203//______________________________________________________________________________
2204- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2205 toPoint : (X11::Point) dstPoint
2206{
2207 assert(srcImage != nil && "-copyImage:area:toPoint:, parameter 'srcImage' is nil");
2208 assert(srcImage.fImage != nil && "-copyImage:area:toPoint:, srcImage.fImage is nil");
2209 assert(self.fContext != 0 && "-copyImage:area:toPoint:, fContext is null");
2210
2211 if (!X11::AdjustCropArea(srcImage, area)) {
2212 NSLog(@"QuartzView: -copyImage:area:toPoint, image and copy area do not intersect");
2213 return;
2214 }
2215
2216 CGImageRef subImage = 0;
2217 bool needSubImage = false;
2218 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2219 needSubImage = true;
2220 subImage = X11::CreateSubImage(srcImage, area);
2221 if (!subImage) {
2222 NSLog(@"QuartzView: -copyImage:area:toPoint:, subimage creation failed");
2223 return;
2224 }
2225 } else
2226 subImage = srcImage.fImage;
2227
2228 const Quartz::CGStateGuard ctxGuard(self.fContext);
2229
2230 CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2231 CGContextScaleCTM(self.fContext, 1., -1.);
2232
2233 //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2234 const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2235 //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2236 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2237 CGContextDrawImage(self.fContext, imageRect, subImage);
2238
2239 if (needSubImage)
2240 CGImageRelease(subImage);
2241}
2242
2243//______________________________________________________________________________
2244- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
2245 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2246{
2247 assert(src != nil && "-copy:area:withMask:clipOrigin:toPoint:, parameter 'src' is nil");
2248 assert(area.fWidth && area.fHeight && "-copy:area:withMask:clipOrigin:toPoint:, area to copy is empty");
2249
2250 if ([src isKindOfClass : [QuartzWindow class]]) {
2251 //Forget about mask (can I have it???)
2252 QuartzWindow * const qw = (QuartzWindow *)src;
2253 //Will not work with OpenGL.
2254 [self copyView : (QuartzView *)qw.fContentView area : area toPoint : dstPoint];
2255 } else if ([src isKindOfClass : [QuartzView class]]) {
2256 //Forget about mask (can I have it???)
2257 [self copyView : (QuartzView *)src area : area toPoint : dstPoint];
2258 } else if ([src isKindOfClass : [QuartzPixmap class]]) {
2259 [self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2260 } else if ([src isKindOfClass : [QuartzImage class]]) {
2261 [self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2262 } else {
2263 assert(0 && "-copy:area:withMask:clipOrigin:toPoint:, src is of unknown type");
2264 }
2265}
2266
2267//______________________________________________________________________________
2268- (unsigned char *) readColorBits : (X11::Rectangle) area
2269{
2270 //This is quite a bad idea - to read pixels back from a view,
2271 //but our GUI does exactly this. In case of Cocoa it's expensive
2272 //and not guaranteed to work.
2273
2274 assert(area.fWidth && area.fHeight && "-readColorBits:, area to copy is empty");
2275
2276 //int, not unsigned or something - to keep it simple.
2277 const NSRect visRect = [self visibleRect];
2278 const X11::Rectangle srcRect(int(visRect.origin.x), int(visRect.origin.y),
2279 unsigned(visRect.size.width), unsigned(visRect.size.height));
2280
2281 if (!X11::AdjustCropArea(srcRect, area)) {
2282 NSLog(@"QuartzView: -readColorBits:, visible rect of view and copy area do not intersect");
2283 return nullptr;
2284 }
2285
2286 //imageRep is autoreleased.
2287 NSBitmapImageRep * const imageRep = [self bitmapImageRepForCachingDisplayInRect : visRect];
2288 if (!imageRep) {
2289 NSLog(@"QuartzView: -readColorBits:, bitmapImageRepForCachingDisplayInRect failed");
2290 return nullptr;
2291 }
2292
2293 CGContextRef ctx = self.fContext; //Save old context if any.
2294 [self cacheDisplayInRect : visRect toBitmapImageRep : imageRep];
2295 self.fContext = ctx; //Restore old context.
2296 //
2297 const NSInteger bitsPerPixel = [imageRep bitsPerPixel];
2298
2299 assert(bitsPerPixel == 32 && "-readColorBits:, no alpha channel???");
2300 const NSInteger bytesPerRow = [imageRep bytesPerRow];
2301 unsigned dataWidth = bytesPerRow / (bitsPerPixel / 8);//assume an octet :(
2302
2303 unsigned char *srcData = nullptr;
2304 std::vector<unsigned char> downscaled;
2305 if ([self.window.screen backingScaleFactor] > 1 && imageRep.CGImage) {
2306 downscaled = X11::DownscaledImageData(area.fWidth, area.fHeight, imageRep.CGImage);
2307 if (downscaled.size())
2308 srcData = &downscaled[0];
2309 dataWidth = area.fWidth;
2310 } else
2311 srcData = [imageRep bitmapData];
2312
2313 if (!srcData) {
2314 NSLog(@"QuartzView: -readColorBits:, failed to obtain backing store contents");
2315 return nullptr;
2316 }
2317
2318 //We have a source data now. Let's allocate buffer for ROOT's GUI and convert source data.
2319 unsigned char *data = nullptr;
2320
2321 try {
2322 data = new unsigned char[area.fWidth * area.fHeight * 4];//bgra?
2323 } catch (const std::bad_alloc &) {
2324 NSLog(@"QuartzView: -readColorBits:, memory allocation failed");
2325 return nullptr;
2326 }
2327
2328 unsigned char *dstPixel = data;
2329 const unsigned char *line = srcData + area.fY * dataWidth * 4;
2330 const unsigned char *srcPixel = line + area.fX * 4;
2331
2332 for (unsigned i = 0; i < area.fHeight; ++i) {
2333 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
2334 dstPixel[0] = srcPixel[2];
2335 dstPixel[1] = srcPixel[1];
2336 dstPixel[2] = srcPixel[0];
2337 dstPixel[3] = srcPixel[3];
2338 }
2339
2340 line += dataWidth * 4;
2341 srcPixel = line + area.fX * 4;
2342 }
2343
2344 return data;
2345}
2346
2347//______________________________________________________________________________
2348- (void) setFBackgroundPixmap : (QuartzImage *) pixmap
2349{
2350 if (fBackgroundPixmap != pixmap) {
2351 [fBackgroundPixmap release];
2352 if (pixmap)
2353 fBackgroundPixmap = [pixmap retain];
2354 else
2355 fBackgroundPixmap = nil;
2356 }
2357}
2358
2359//______________________________________________________________________________
2361{
2362 //I do not autorelease, screw this idiom!
2363
2364 return fBackgroundPixmap;
2365}
2366
2367//______________________________________________________________________________
2368- (int) fMapState
2369{
2370 if ([self isHidden])
2371 return kIsUnmapped;
2372
2373 for (QuartzView *parent = fParentView; parent; parent = parent.fParentView) {
2374 if ([parent isHidden])
2375 return kIsUnviewable;
2376 }
2377
2378 return kIsViewable;
2379}
2380
2381//______________________________________________________________________________
2382- (BOOL) fHasFocus
2383{
2384 //With the latest update clang became a bit more stupid.
2385 //Let's write a stupid useless cargo cult code
2386 //to make IT SHUT THE F... UP.
2387 (void)fHasFocus;
2388 return NO;
2389}
2390
2391//______________________________________________________________________________
2392- (void) setFHasFocus : (BOOL) focus
2393{
2394#pragma unused(focus)
2395 //With the latest update clang became a bit more stupid.
2396 //Let's write a stupid useless cargo cult code
2397 //to make IT SHUT THE F... UP.
2398 (void)fHasFocus;
2399}
2400
2401//______________________________________________________________________________
2403{
2404 return fBackBuffer;//No autorelease, I know the object's lifetime myself.
2405}
2406
2407//______________________________________________________________________________
2408- (void) setFBackBuffer : (QuartzPixmap *) backBuffer
2409{
2410 if (fBackBuffer != backBuffer) {
2411 [fBackBuffer release];
2412
2413 if (backBuffer)
2414 fBackBuffer = [backBuffer retain];
2415 else
2416 fBackBuffer = nil;
2417 }
2418}
2419
2420//______________________________________________________________________________
2421- (NSView<X11Window> *) fContentView
2422{
2423 return self;
2424}
2425
2426//______________________________________________________________________________
2428{
2429 return (QuartzWindow *)[self window];
2430}
2431
2432//______________________________________________________________________________
2434{
2436}
2437
2438//______________________________________________________________________________
2440{
2442}
2443
2444//______________________________________________________________________________
2445- (void) activateGrab : (unsigned) eventMask ownerEvents : (BOOL) ownerEvents
2446{
2448 fActiveGrabEventMask = eventMask;
2449 fActiveGrabOwnerEvents = ownerEvents;
2450}
2451
2452//______________________________________________________________________________
2453- (void) cancelGrab
2454{
2458}
2459
2460//______________________________________________________________________________
2461- (BOOL) acceptsCrossingEvents : (unsigned) eventMask
2462{
2463 bool accepts = fEventMask & eventMask;
2464
2465 //In ROOT passive grabs are always with owner_events == true.
2467 accepts = accepts || (fPassiveGrabEventMask & eventMask);
2468
2471 accepts = accepts || (fActiveGrabOwnerEvents & eventMask);
2472 else
2473 accepts = fActiveGrabOwnerEvents & eventMask;
2474 }
2475
2476 return accepts;
2477}
2478
2479//______________________________________________________________________________
2480- (void) addChild : (NSView<X11Window> *) child
2481{
2482 assert(child != nil && "-addChild:, parameter 'child' is nil");
2483
2484 [self addSubview : child];
2485 child.fParentView = self;
2486}
2487
2488//______________________________________________________________________________
2489- (void) getAttributes : (WindowAttributes_t *) attr
2490{
2491 assert(attr != 0 && "-getAttributes:, parameter 'attr' is null");
2492
2493 X11::GetWindowAttributes(self, attr);
2494}
2495
2496//______________________________________________________________________________
2497- (void) setAttributes : (const SetWindowAttributes_t *)attr
2498{
2499 assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
2500
2501#ifdef DEBUG_ROOT_COCOA
2502 log_attributes(attr, fID);
2503#endif
2504
2505 X11::SetWindowAttributes(attr, self);
2506}
2507
2508//______________________________________________________________________________
2509- (void) mapRaised
2510{
2511 //Move view to the top of subviews.
2512 QuartzView * const parent = fParentView;
2513 [self removeFromSuperview];
2514 [parent addSubview : self];
2515 [self setHidden : NO];
2516}
2517
2518//______________________________________________________________________________
2519- (void) mapWindow
2520{
2521 [self setHidden : NO];
2522}
2523
2524//______________________________________________________________________________
2526{
2527 for (QuartzView * v in [self subviews])
2528 [v setHidden : NO];
2529}
2530
2531//______________________________________________________________________________
2532- (void) unmapWindow
2533{
2534 [self setHidden : YES];
2535}
2536
2537//______________________________________________________________________________
2538- (BOOL) fIsOverlapped
2539{
2540 return fIsOverlapped;
2541}
2542
2543//______________________________________________________________________________
2544- (void) setOverlapped : (BOOL) overlap
2545{
2546 fIsOverlapped = overlap;
2547 for (NSView<X11Window> *child in [self subviews])
2548 [child setOverlapped : overlap];
2549}
2550
2551//______________________________________________________________________________
2552- (void) raiseWindow
2553{
2554 //Now, I can not remove window and add it ...
2555 //For example, if you click on a tab, this:
2556 //1. Creates (potentially) a passive button grab
2557 //2. Raises this tab - changes the window order.
2558 //3. On a button release - grab is release.
2559 //The tough problem is, if I remove a view from subviews
2560 //and add it ... it will never receve the
2561 //release event thus a grab will 'hang' on
2562 //view leading to bugs and artifacts.
2563 //So instead I have to ... SORT!!!!!
2564
2565 using namespace X11;//Comparators.
2566
2567 for (QuartzView *sibling in [fParentView subviews]) {
2568 if (self == sibling)
2569 continue;
2570 if ([sibling isHidden])
2571 continue;
2572
2573 if (NSEqualRects(sibling.frame, self.frame)) {
2574 [sibling setOverlapped : YES];
2575 [sibling setHidden : YES];
2576 }
2577 }
2578
2579 [self setOverlapped : NO];
2580 //
2581 [self setHidden : NO];
2582 //
2583 [fParentView sortSubviewsUsingFunction : CompareViewsToRaise context : (void *)self];
2584 //
2585 [self updateTrackingAreasAfterRaise];
2586 //
2587 [self setNeedsDisplay : YES];
2588}
2589
2590//______________________________________________________________________________
2591- (void) lowerWindow
2592{
2593 //See comment about sorting in -raiseWindow.
2594
2595 using namespace X11;
2596
2597 NSEnumerator * const reverseEnumerator = [[fParentView subviews] reverseObjectEnumerator];
2598 for (QuartzView *sibling in reverseEnumerator) {
2599 if (sibling == self)
2600 continue;
2601
2602 if (NSEqualRects(sibling.frame, self.frame)) {
2603 [sibling setOverlapped : NO];
2604 //
2605 [sibling setHidden : NO];
2606 //
2607 [sibling setNeedsDisplay : YES];
2608 [self setOverlapped : YES];
2609 //
2610 [self setHidden : YES];
2611 //
2612 break;
2613 }
2614 }
2615
2616 [fParentView sortSubviewsUsingFunction : CompareViewsToLower context : (void*)self];
2617}
2618
2619//______________________________________________________________________________
2620- (BOOL) isFlipped
2621{
2622 //Now view's placement, geometry, moving and resizing can be
2623 //done with ROOT's (X11) coordinates without conversion - we're are 'flipped'.
2624 return YES;
2625}
2626
2627//______________________________________________________________________________
2629{
2630 if (self.fMapState == kIsViewable || fIsOverlapped == YES) {
2632 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2633 "-configureNotifyTree, gVirtualX is either null or has type different from TGCocoa");
2634 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2635 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2636 }
2637
2638 for (NSView<X11Window> *v in [self subviews])
2639 [v configureNotifyTree];
2640 }
2641}
2642
2643#pragma mark - Key grabs.
2644
2645//______________________________________________________________________________
2646- (void) addPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2647{
2648 [self removePassiveKeyGrab : keyCode modifiers : modifiers];
2649 PassiveKeyGrab * const newGrab = [[PassiveKeyGrab alloc] initWithKey : keyCode
2650 modifiers : modifiers];
2651 [fPassiveKeyGrabs addObject : newGrab];
2652 [newGrab release];
2653}
2654
2655//______________________________________________________________________________
2656- (void) removePassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2657{
2658 const NSUInteger count = [fPassiveKeyGrabs count];
2659 for (NSUInteger i = 0; i < count; ++i) {
2660 PassiveKeyGrab *grab = [fPassiveKeyGrabs objectAtIndex : i];
2661 if ([grab matchKey : keyCode modifiers : modifiers]) {
2662 [fPassiveKeyGrabs removeObjectAtIndex : i];
2663 break;
2664 }
2665 }
2666}
2667
2668//______________________________________________________________________________
2669- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2670{
2671 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2672 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2673 if ([grab matchKey : keyCode modifiers : modifiers])
2674 return grab;
2675 }
2676
2677 return nil;
2678}
2679
2680//______________________________________________________________________________
2681- (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode
2682{
2683 //Do not check modifiers.
2684 NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2685 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2686 if ([grab matchKey : keyCode])
2687 return grab;
2688 }
2689
2690 return nil;
2691}
2692
2693#pragma mark - Painting mechanics.
2694
2695//______________________________________________________________________________
2696- (void) drawRect : (NSRect) dirtyRect
2697{
2698#pragma unused(dirtyRect)
2699
2700 using namespace X11;
2701
2702 if (fID) {
2703 if (TGWindow * const window = gClient->GetWindowById(fID)) {
2704 //It's never painted, parent renders child. true == check the parent also.
2705 if (ViewIsTextViewFrame(self, true) ||ViewIsHtmlViewFrame(self, true))
2706 return;
2707
2708 NSGraphicsContext * const nsContext = [NSGraphicsContext currentContext];
2709 assert(nsContext != nil && "-drawRect:, currentContext returned nil");
2710
2711 TGCocoa * const vx = (TGCocoa *)gVirtualX;
2712 vx->CocoaDrawON();
2713
2714 fContext = (CGContextRef)[nsContext graphicsPort];
2715 assert(fContext != 0 && "-drawRect:, graphicsPort returned null");
2716
2717 const Quartz::CGStateGuard ctxGuard(fContext);
2718
2719 //Non-rectangular windows.
2720 if (self.fQuartzWindow.fShapeCombineMask)
2722
2723 // This code used to use TObject::InheritsFrom, however since this is
2724 // run under the AppKit, we can not call core/meta functions, otherwise
2725 // we will run into deadlocks.
2726 if (dynamic_cast<const TGContainer*>(window))//It always has an ExposureMask.
2727 vx->GetEventTranslator()->GenerateExposeEvent(self, [self visibleRect]);
2728
2729 if (fEventMask & kExposureMask) {
2730 if (ViewIsTextView(self)) {
2731 //Send Expose event, using child view (this is how it's done in GUI :( ).
2732 NSView<X11Window> * const viewFrame = FrameForTextView(self);
2733 if (viewFrame)//Now we set fExposedRegion for TGView.
2734 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, [viewFrame visibleRect]);
2735 }
2736
2737 if (ViewIsHtmlView(self)) {
2738 NSView<X11Window> *const viewFrame = FrameForHtmlView(self);
2739 if (viewFrame)
2740 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, [viewFrame visibleRect]);
2741 }
2742
2743 //Ask ROOT's widget/window to draw itself.
2744 gClient->NeedRedraw(window, kTRUE);
2745
2746 if (!fSnapshotDraw && !ViewIsTextView(self) && !ViewIsHtmlView(self)) {
2747 //If Cocoa repaints widget, cancel all ROOT's "outside of paint event"
2748 //rendering into this widget ... Except it's a text view :)
2749 gClient->CancelRedraw(window);
2751 }
2752 }
2753
2754 if (fBackBuffer) {
2755 //Very "special" window.
2756 const X11::Rectangle copyArea(0, 0, fBackBuffer.fWidth, fBackBuffer.fHeight);
2757 [self copy : fBackBuffer area : copyArea withMask : nil
2758 clipOrigin : X11::Point() toPoint : X11::Point()];
2759 }
2760
2761 vx->CocoaDrawOFF();
2762#ifdef DEBUG_ROOT_COCOA
2763 CGContextSetRGBStrokeColor(fContext, 1., 0., 0., 1.);
2764 CGContextStrokeRect(fContext, dirtyRect);
2765#endif
2766
2767 fContext = 0;
2768 } else {
2769#ifdef DEBUG_ROOT_COCOA
2770 NSLog(@"QuartzView: -drawRect: method, no window for id %u was found", fID);
2771#endif
2772 }
2773 }
2774}
2775
2776#pragma mark - Geometry.
2777
2778//______________________________________________________________________________
2779- (void) setFrame : (NSRect) newFrame
2780{
2781 //In case of TBrowser, setFrame started infinite recursion:
2782 //HandleConfigure for embedded main frame emits signal, slot
2783 //calls layout, layout calls setFrame -> HandleConfigure and etc. etc.
2784 if (NSEqualRects(newFrame, self.frame))
2785 return;
2786
2787 [super setFrame : newFrame];
2788}
2789
2790//______________________________________________________________________________
2791- (void) setFrameSize : (NSSize) newSize
2792{
2793 //Check, if setFrameSize calls setFrame.
2794
2795 [super setFrameSize : newSize];
2796
2797 if ((fEventMask & kStructureNotifyMask) && (self.fMapState == kIsViewable || fIsOverlapped == YES)) {
2798 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2799 "setFrameSize:, gVirtualX is either null or has a type, different from TGCocoa");
2800 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2801 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2802 }
2803
2804 [self setNeedsDisplay : YES];//?
2805}
2806
2807#pragma mark - Event handling.
2808
2809//______________________________________________________________________________
2810- (void) mouseDown : (NSEvent *) theEvent
2811{
2812 assert(fID != 0 && "-mouseDown:, fID is 0");
2813
2814 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2815 "-mouseDown:, gVirtualX is either null or has a type, different from TGCocoa");
2816 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2818}
2819
2820//______________________________________________________________________________
2821- (void) scrollWheel : (NSEvent*) theEvent
2822{
2823 assert(fID != 0 && "-scrollWheel:, fID is 0");
2824
2825
2826 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2827 "-scrollWheel:, gVirtualX is either null or has a type, different from TGCocoa");
2828
2829 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2830 const CGFloat deltaY = [theEvent deltaY];
2831 if (deltaY < 0) {
2834 } else if (deltaY > 0) {
2837 }
2838}
2839
2840#ifdef DEBUG_ROOT_COCOA
2841//______________________________________________________________________________
2842- (void) printViewInformation
2843{
2844 assert(fID != 0 && "-printWindowInformation, fID is 0");
2845 const TGWindow * const window = gClient->GetWindowById(fID);
2846 assert(window != 0 && "printWindowInformation, window not found");
2847
2848 NSLog(@"-----------------View %u info:---------------------", fID);
2849 NSLog(@"ROOT's window class is %s", window->IsA()->GetName());
2850 NSLog(@"event mask is:");
2851 print_mask_info(fEventMask);
2852 NSLog(@"grab mask is:");
2853 print_mask_info(fPassiveGrabEventMask);
2854 NSLog(@"view's geometry: x == %g, y == %g, w == %g, h == %g", self.frame.origin.x,
2855 self.frame.origin.y, self.frame.size.width, self.frame.size.height);
2856 NSLog(@"----------------End of view info------------------");
2857}
2858#endif
2859
2860//______________________________________________________________________________
2861- (void) rightMouseDown : (NSEvent *) theEvent
2862{
2863 assert(fID != 0 && "-rightMouseDown:, fID is 0");
2864
2865#ifdef DEBUG_ROOT_COCOA
2866 [self printViewInformation];
2867#endif
2868
2869 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2870 "-rightMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2871 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2873}
2874
2875//______________________________________________________________________________
2876- (void) otherMouseDown : (NSEvent *) theEvent
2877{
2878 assert(fID != 0 && "-otherMouseDown:, fID is 0");
2879
2880 //Funny enough, [theEvent buttonNumber] is not the same thing as button masked in [NSEvent pressedMouseButtons],
2881 //button number actually is a kind of right operand for bitshift for pressedMouseButtons.
2882 if ([theEvent buttonNumber] == 2) {//this '2' will correspond to '4' in pressedMouseButtons.
2883 //I do not care about mouse buttons after left/right/wheel - ROOT does not have
2884 //any code for this.
2885 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2886 "-otherMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2887 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2889 }
2890}
2891
2892//______________________________________________________________________________
2893- (void) mouseUp : (NSEvent *) theEvent
2894{
2895 assert(fID != 0 && "-mouseUp:, fID is 0");
2896
2897 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2898 "-mouseUp:, gVirtualX is either null or has type different from TGCocoa");
2899 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2901}
2902
2903//______________________________________________________________________________
2904- (void) rightMouseUp : (NSEvent *) theEvent
2905{
2906
2907 assert(fID != 0 && "-rightMouseUp:, fID is 0");
2908
2909 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2910 "-rightMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2911
2912 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2914}
2915
2916//______________________________________________________________________________
2917- (void) otherMouseUp : (NSEvent *) theEvent
2918{
2919 assert(fID != 0 && "-otherMouseUp:, fID is 0");
2920
2921 //Here I assume it's always kButton2.
2922 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2923 "-otherMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2924 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2926}
2927
2928//______________________________________________________________________________
2929- (void) mouseEntered : (NSEvent *) theEvent
2930{
2931 assert(fID != 0 && "-mouseEntered:, fID is 0");
2932 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2933 "-mouseEntered:, gVirtualX is null or not of TGCocoa type");
2934
2935 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2937}
2938
2939//______________________________________________________________________________
2940- (void) mouseExited : (NSEvent *) theEvent
2941{
2942 assert(fID != 0 && "-mouseExited:, fID is 0");
2943
2944 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2945 "-mouseExited:, gVirtualX is null or not of TGCocoa type");
2946
2947 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2949}
2950
2951//______________________________________________________________________________
2952- (void) mouseMoved : (NSEvent *) theEvent
2953{
2954 assert(fID != 0 && "-mouseMoved:, fID is 0");
2955
2956 if (fParentView)//Suppress events in all views, except the top-level one.
2957 return;
2958
2959 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2960 "-mouseMoved:, gVirtualX is null or not of TGCocoa type");
2961
2962 TGCocoa *vx = static_cast<TGCocoa *>(gVirtualX);
2964}
2965
2966//______________________________________________________________________________
2967- (void) mouseDragged : (NSEvent *) theEvent
2968{
2969 assert(fID != 0 && "-mouseDragged:, fID is 0");
2970
2971 TGCocoa * const vx = dynamic_cast<TGCocoa *>(gVirtualX);
2972 assert(vx != 0 && "-mouseDragged:, gVirtualX is null or not of TGCocoa type");
2973
2975}
2976
2977//______________________________________________________________________________
2978- (void) rightMouseDragged : (NSEvent *) theEvent
2979{
2980 assert(fID != 0 && "-rightMouseDragged:, fID is 0");
2981
2982 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2983 "-rightMouseDragged:, gVirtualX is null or not of TGCocoa type");
2984
2985 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2987}
2988
2989//______________________________________________________________________________
2990- (void) otherMouseDragged : (NSEvent *) theEvent
2991{
2992 assert(fID != 0 && "-otherMouseDragged:, fID is 0");
2993
2994 if ([theEvent buttonNumber] == 2) {
2995 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2996 "-otherMouseDragged:, gVirtualX is null or not of TGCocoa type");
2997 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2999 }
3000}
3001
3002//______________________________________________________________________________
3003- (void) keyDown : (NSEvent *) theEvent
3004{
3005 assert(fID != 0 && "-keyDown:, fID is 0");
3006
3007 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3008 "-keyDown:, gVirtualX is null or not of TGCocoa type");
3009
3010 NSView<X11Window> *eventView = self;
3011 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3012 eventView = pointerView;
3013
3014 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3015 vx->GetEventTranslator()->GenerateKeyPressEvent(eventView, theEvent);
3016}
3017
3018//______________________________________________________________________________
3019- (void) keyUp : (NSEvent *) theEvent
3020{
3021 assert(fID != 0 && "-keyUp:, fID is 0");
3022
3023 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3024 "-keyUp:, gVirtualX is null or not of TGCocoa type");
3025
3026 TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
3027 NSView<X11Window> *eventView = self;
3028 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3029 eventView = pointerView;
3030
3031 vx->GetEventTranslator()->GenerateKeyReleaseEvent(eventView, theEvent);
3032}
3033
3034#pragma mark - First responder stuff.
3035
3036//______________________________________________________________________________
3037- (BOOL) acceptsFirstMouse : (NSEvent *) theEvent
3038{
3039#pragma unused(theEvent)
3040 return YES;
3041}
3042
3043//______________________________________________________________________________
3044- (BOOL) acceptsFirstResponder
3045{
3046 return YES;
3047}
3048
3049#pragma mark - Cursors.
3050
3051//______________________________________________________________________________
3052- (void) setFCurrentCursor : (ECursor) cursor
3053{
3054 if (cursor != fCurrentCursor) {
3055 fCurrentCursor = cursor;
3056 [self.fQuartzWindow invalidateCursorRectsForView : self];
3057 }
3058}
3059
3060//______________________________________________________________________________
3061- (NSCursor *) createCustomCursor
3062{
3063 const char *pngFileName = 0;
3064
3065 switch (fCurrentCursor) {
3066 case kMove:
3067 pngFileName = "move_cursor.png";
3068 break;
3069 case kArrowHor:
3070 pngFileName = "hor_arrow_cursor.png";
3071 break;
3072 case kArrowVer:
3073 pngFileName = "ver_arrow_cursor.png";
3074 break;
3075 case kArrowRight:
3076 pngFileName = "right_arrow_cursor.png";
3077 break;
3078 case kRotate:
3079 pngFileName = "rotate.png";
3080 break;
3081 case kBottomLeft:
3082 case kTopRight:
3083 pngFileName = "top_right_cursor.png";
3084 break;
3085 case kTopLeft:
3086 case kBottomRight:
3087 pngFileName = "top_left_cursor.png";
3088 break;
3089 default:;
3090 }
3091
3092 if (pngFileName) {
3093 const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
3094 const Util::ScopedArray<const char> arrayGuard(path);
3095
3096 if (!path || path[0] == 0) {
3097 //File was not found.
3098 return nil;
3099 }
3100
3101 NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
3102 NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
3103
3104 if (!cursorImage)
3105 return nil;
3106
3107 NSPoint hotSpot = X11::GetCursorHotStop(cursorImage, fCurrentCursor);
3108 NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
3109 hotSpot : hotSpot] autorelease];
3110
3111 [cursorImage release];
3112
3113 return customCursor;
3114 }
3115
3116 return nil;
3117}
3118
3119//______________________________________________________________________________
3120- (void) resetCursorRects
3121{
3122 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor))
3123 [self addCursorRect : self.visibleRect cursor : cursor];
3124}
3125
3126//______________________________________________________________________________
3127- (void) cursorUpdate
3128{
3129 if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor)) {
3130 // NB: [window invalidateCursorRectsForView] called here has the
3131 // same problem as commented below in -cursorUpdate:.
3132 [cursor set];
3133 }
3134}
3135
3136//______________________________________________________________________________
3137- (void) cursorUpdate : (NSEvent *) event
3138{
3139#pragma unused(event)
3140 // It looks like [NSCursor set] method does not work properly when called from
3141 // cursorUpdate:, having, say, a parent frame with 'arrow' cursor and a child (completely
3142 // filling its parent's area) with 'cross', it happens the 'cross' cursor is not always
3143 // set correctly, for example:
3144 // if we have a TCanvas and resize it, cursor is 'arrow' inside this canvas,
3145 // though it must be 'cross'. This all, as it always happesn with "thinking different"
3146 // Apple is somehow related to run loop or something. As always, it's not documented,
3147 // so Apple can continue to think different. The idea with performSelector comes from:
3148 // http://stackoverflow.com/questions/8430236/nscursor-set-method-has-no-effect
3149 // Or may be it's just a bug:
3150 // http://stackoverflow.com/questions/13901232/nscursor-set-not-working-on-unfocused-window
3151 [self performSelector : @selector(cursorUpdate) withObject : nil afterDelay : 0.05f];
3152}
3153
3154#pragma mark - Emulated X11 properties.
3155
3156//______________________________________________________________________________
3157- (void) setProperty : (const char *) propName data : (unsigned char *) propData
3158 size : (unsigned) dataSize forType : (Atom_t) dataType format : (unsigned) format
3159{
3160 assert(propName != 0 && "-setProperty:data:size:forType:, parameter 'propName' is null");
3161 assert(propData != 0 && "-setProperty:data:size:forType:, parameter 'propData' is null");
3162 assert(dataSize != 0 && "-setProperty:data:size:forType:, parameter 'dataSize' is 0");
3163
3164 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3165 QuartzWindowProperty * property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3166
3167 //At the moment (and I think this will never change) TGX11 always calls XChangeProperty with PropModeReplace.
3168 if (property)
3169 [property resetPropertyData : propData size : dataSize type : dataType format : format];
3170 else {
3171 //No property found, add a new one.
3172 property = [[QuartzWindowProperty alloc] initWithData : propData size : dataSize
3173 type : dataType format : format];
3174 [fX11Properties setObject : property forKey : key];
3175 [property release];
3176 }
3177}
3178
3179//______________________________________________________________________________
3180- (BOOL) hasProperty : (const char *) propName
3181{
3182 assert(propName != 0 && "-hasProperty:, propName parameter is null");
3183
3184 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3185 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3186
3187 return property != nil;
3188}
3189
3190//______________________________________________________________________________
3191- (unsigned char *) getProperty : (const char *) propName returnType : (Atom_t *) type
3192 returnFormat : (unsigned *) format nElements : (unsigned *) nElements
3193{
3194 assert(propName != 0 &&
3195 "-getProperty:returnType:returnFormat:nElements:, parameter 'propName' is null");
3196 assert(type != 0 &&
3197 "-getProperty:returnType:returnFormat:nElements:, parameter 'type' is null");
3198 assert(format != 0 &&
3199 "-getProperty:returnType:returnFormat:nElements:, parameter 'format' is null");
3200 assert(nElements != 0 &&
3201 "-getProperty:returnType:returnFormat:nElements:, parameter 'nElements' is null");
3202
3203 NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3204 QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3205 assert(property != 0 &&
3206 "-getProperty:returnType:returnFormat:nElements, property not found");
3207
3208 NSData * const propData = property.fPropertyData;
3209
3210 const NSUInteger dataSize = [propData length];
3211 unsigned char *buff = 0;
3212 try {
3213 buff = new unsigned char[dataSize]();
3214 } catch (const std::bad_alloc &) {
3215 //Hmm, can I log, if new failed? :)
3216 NSLog(@"QuartzWindow: -getProperty:returnType:returnFormat:nElements:,"
3217 " memory allocation failed");
3218 return 0;
3219 }
3220
3221 [propData getBytes : buff length : dataSize];
3222 *format = property.fFormat;
3223
3224 *nElements = dataSize;
3225
3226 if (*format == 16)
3227 *nElements= dataSize / 2;
3228 else if (*format == 32)
3229 *nElements = dataSize / 4;
3230
3231 *type = property.fType;
3232
3233 return buff;
3234}
3235
3236//______________________________________________________________________________
3237- (void) removeProperty : (const char *) propName
3238{
3239 assert(propName != 0 && "-removeProperty:, parameter 'propName' is null");
3240
3241 NSString * const key = [NSString stringWithCString : propName
3242 encoding : NSASCIIStringEncoding];
3243 [fX11Properties removeObjectForKey : key];
3244}
3245
3246//DND
3247//______________________________________________________________________________
3248- (NSDragOperation) draggingEntered : (id<NSDraggingInfo>) sender
3249{
3250 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3251 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3252
3253 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy))
3254 return NSDragOperationCopy;
3255
3256 return NSDragOperationNone;
3257}
3258
3259//______________________________________________________________________________
3260- (BOOL) performDragOperation : (id<NSDraggingInfo>) sender
3261{
3262 //We can drag some files (images, pdfs, source code files) from
3263 //finder to ROOT's window (mainly TCanvas or text editor).
3264 //The logic is totally screwed here :((( - ROOT will try to
3265 //read a property of some window (not 'self', unfortunately) -
3266 //this works since on Window all data is in a global clipboard
3267 //(on X11 it simply does not work at all).
3268 //I'm attaching the file name as a property for the top level window,
3269 //there is no other way to make this data accessible for ROOT.
3270
3271 NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3272 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3273
3274 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy)) {
3275
3276 //Here I try to put string ("file://....") into window's property to make
3277 //it accesible from ROOT's GUI.
3278 const Atom_t textUriAtom = gVirtualX->InternAtom("text/uri-list", kFALSE);
3279
3280 NSArray * const files = [pasteBoard propertyListForType : NSFilenamesPboardType];
3281 for (NSString *path in files) {
3282 //ROOT can not process several files, use the first one.
3283 NSString * const item = [@"file://" stringByAppendingString : path];
3284 //Yes, only ASCII encoding, but after all, ROOT's not able to work with NON-ASCII strings.
3285 const NSUInteger len = [item lengthOfBytesUsingEncoding : NSASCIIStringEncoding] + 1;
3286 try {
3287 std::vector<unsigned char> propertyData(len);
3288 [item getCString : (char *)&propertyData[0] maxLength : propertyData.size()
3289 encoding : NSASCIIStringEncoding];
3290 //There is no any guarantee, that this will ever work, logic in TGDNDManager is totally crazy.
3291 NSView<X11Window> * const targetView = self.fQuartzWindow.fContentView;
3292 [targetView setProperty : "_XC_DND_DATA" data : &propertyData[0]
3293 size : propertyData.size() forType : textUriAtom format : 8];
3294 } catch (const std::bad_alloc &) {
3295 //Hehe, can I log something in case of bad_alloc??? ;)
3296 NSLog(@"QuartzView: -performDragOperation:, memory allocation failed");
3297 return NO;
3298 }
3299
3300 break;
3301 }
3302
3303 //Property is attached now.
3304
3305 //Gdk on windows creates three events on file drop (WM_DROPFILES): XdndEnter, XdndPosition, XdndDrop.
3306 //1. Dnd enter.
3307 Event_t event1 = {};
3308 event1.fType = kClientMessage;
3309 event1.fWindow = fID;
3310 event1.fHandle = gVirtualX->InternAtom("XdndEnter", kFALSE);
3311 event1.fUser[0] = long(fID);
3312 event1.fUser[2] = textUriAtom;//gVirtualX->InternAtom("text/uri-list", kFALSE);
3313 //
3314 gVirtualX->SendEvent(fID, &event1);
3315
3316 //2. Dnd position.
3317 Event_t event2 = {};
3318 event2.fType = kClientMessage;
3319 event2.fWindow = fID;
3320 event2.fHandle = gVirtualX->InternAtom("XdndPosition", kFALSE);
3321 event2.fUser[0] = long(fID);
3322 event2.fUser[2] = 0;//Here I have to pack x and y for drop coordinates, shifting by 16 bits.
3323 NSPoint dropPoint = [sender draggingLocation];
3324 //convertPointFromBase is deprecated.
3325 //dropPoint = [self convertPointFromBase : dropPoint];
3326 dropPoint = [self convertPoint : dropPoint fromView : nil];
3327 //
3328 dropPoint = X11::TranslateToScreen(self, dropPoint);
3329 event2.fUser[2] = UShort_t(dropPoint.y) | (UShort_t(dropPoint.x) << 16);
3330
3331 gVirtualX->SendEvent(fID, &event2);
3332
3333 Event_t event3 = {};
3334 event3.fType = kClientMessage;
3335 event3.fWindow = fID;
3336 event3.fHandle = gVirtualX->InternAtom("XdndDrop", kFALSE);
3337
3338 gVirtualX->SendEvent(fID, &event3);
3339 }
3340
3341 return YES;//Always ok, even if file type is not supported - no need in "animation".
3342}
3343
3344@end
SVector< double, 2 > v
Definition: Dict.h:5
@ kClientMessage
Definition: GuiTypes.h:62
const Mask_t kWABorderPixel
Definition: GuiTypes.h:141
const Mask_t kWAOverrideRedirect
Definition: GuiTypes.h:148
const Mask_t kWABitGravity
Definition: GuiTypes.h:143
const Mask_t kWADontPropagate
Definition: GuiTypes.h:151
const Mask_t kWAColormap
Definition: GuiTypes.h:152
const Mask_t kButtonMotionMask
Definition: GuiTypes.h:163
const Mask_t kWABackingStore
Definition: GuiTypes.h:145
const Mask_t kButtonPressMask
Definition: GuiTypes.h:160
const Mask_t kExposureMask
Definition: GuiTypes.h:164
const Mask_t kWAEventMask
Definition: GuiTypes.h:150
const Mask_t kWASaveUnder
Definition: GuiTypes.h:149
const Mask_t kWABackPixel
Definition: GuiTypes.h:139
const Mask_t kWAWinGravity
Definition: GuiTypes.h:144
const Mask_t kWABackingPixel
Definition: GuiTypes.h:147
const Mask_t kPointerMotionMask
Definition: GuiTypes.h:162
Handle_t Atom_t
Definition: GuiTypes.h:36
const Mask_t kLeaveWindowMask
Definition: GuiTypes.h:167
const Mask_t kStructureNotifyMask
Definition: GuiTypes.h:165
@ kIsViewable
Definition: GuiTypes.h:45
@ kIsUnviewable
Definition: GuiTypes.h:45
@ kIsUnmapped
Definition: GuiTypes.h:45
@ kAlways
Definition: GuiTypes.h:44
UInt_t Mask_t
Definition: GuiTypes.h:40
const Mask_t kButtonReleaseMask
Definition: GuiTypes.h:161
const Mask_t kWABorderPixmap
Definition: GuiTypes.h:140
const Mask_t kEnterWindowMask
Definition: GuiTypes.h:166
const Mask_t kWACursor
Definition: GuiTypes.h:153
@ kButton4
Definition: GuiTypes.h:214
@ kButton2
Definition: GuiTypes.h:213
@ kButton5
Definition: GuiTypes.h:214
@ kButton3
Definition: GuiTypes.h:213
@ kButton1
Definition: GuiTypes.h:213
Handle_t Window_t
Definition: GuiTypes.h:28
const Mask_t kWABackPixmap
Definition: GuiTypes.h:138
const Mask_t kWABorderWidth
Definition: GuiTypes.h:142
const Mask_t kWABackingPlanes
Definition: GuiTypes.h:146
PyObject * fType
#define d(i)
Definition: RSha256.hxx:102
#define h(i)
Definition: RSha256.hxx:106
static Int_t init()
unsigned short UShort_t
Definition: RtypesCore.h:36
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define gClient
Definition: TGClient.h:166
int type
Definition: TGX11.cxx:120
typedef void((*Func_t)())
@ kReadPermission
Definition: TSystem.h:48
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
#define gVirtualX
Definition: TVirtualX.h:345
ECursor
Definition: TVirtualX.h:44
@ kRightSide
Definition: TVirtualX.h:45
@ kBottomSide
Definition: TVirtualX.h:45
@ kArrowRight
Definition: TVirtualX.h:47
@ kTopLeft
Definition: TVirtualX.h:44
@ kBottomRight
Definition: TVirtualX.h:44
@ kArrowVer
Definition: TVirtualX.h:46
@ kCaret
Definition: TVirtualX.h:47
@ kTopSide
Definition: TVirtualX.h:45
@ kLeftSide
Definition: TVirtualX.h:45
@ kWatch
Definition: TVirtualX.h:47
@ kMove
Definition: TVirtualX.h:46
@ kTopRight
Definition: TVirtualX.h:44
@ kBottomLeft
Definition: TVirtualX.h:44
@ kHand
Definition: TVirtualX.h:46
@ kCross
Definition: TVirtualX.h:46
@ kRotate
Definition: TVirtualX.h:46
@ kArrowHor
Definition: TVirtualX.h:46
@ kPointer
Definition: TVirtualX.h:47
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:674
void GenerateFocusChangeEvent(NSView< X11Window > *eventView)
Definition: X11Events.mm:1321
void GenerateExposeEvent(NSView< X11Window > *view, const NSRect &exposedRect)
Definition: X11Events.mm:1174
void GenerateConfigureNotifyEvent(NSView< X11Window > *view, const NSRect &newFrame)
Definition: X11Events.mm:1149
void GenerateCrossingEvent(NSEvent *theEvent)
Definition: X11Events.mm:1192
void GenerateKeyReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1301
void GenerateKeyPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1285
void GenerateButtonPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1257
void GeneratePointerMotionEvent(NSEvent *theEvent)
Definition: X11Events.mm:1244
void GenerateButtonReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1270
This class implements TVirtualX interface for MacOS X, using Cocoa and Quartz 2D.
Definition: TGCocoa.h:58
ROOT::MacOSX::X11::CommandBuffer * GetCommandBuffer() const
Definition: TGCocoa.mm:4398
void CocoaDrawOFF()
Definition: TGCocoa.mm:4410
static Atom_t fgDeleteWindowAtom
Definition: TGCocoa.h:469
ROOT::MacOSX::X11::Rectangle GetDisplayGeometry() const
Definition: TGCocoa.mm:550
ROOT::MacOSX::X11::EventTranslator * GetEventTranslator() const
Definition: TGCocoa.mm:4392
void CocoaDrawON()
Definition: TGCocoa.mm:4404
virtual const char * GetName() const
Return unique name, used in SavePrimitive methods.
Definition: TGWindow.cxx:221
@ kIsHtmlView
Definition: TGWindow.h:71
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
static const TString & GetIconPath()
Get the icon path in the installation. Static utility function.
Definition: TROOT.cxx:3126
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition: TSystem.cxx:1536
TLine * line
unichar fKeyCode
Definition: QuartzWindow.h:134
NSUInteger fModifiers
Definition: QuartzWindow.h:135
ROOT::MacOSX::Util::CFScopeGuard< CGImageRef > fImage
Definition: QuartzPixmap.h:96
unsigned fWidth
Definition: QuartzPixmap.h:93
unsigned fHeight
Definition: QuartzPixmap.h:94
unsigned fHeight
Definition: QuartzPixmap.h:38
unsigned fWidth
Definition: QuartzPixmap.h:37
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:176
unsigned fPassiveGrabKeyModifiers
Definition: QuartzWindow.h:169
void raiseWindow()
ECursor fCurrentCursor
Definition: QuartzWindow.h:173
void activateImplicitGrab()
BOOL fSnapshotDraw
Definition: QuartzWindow.h:172
BOOL fIsDNDAware
Definition: QuartzWindow.h:174
NSMutableArray * fPassiveKeyGrabs
Definition: QuartzWindow.h:177
int fPassiveGrabButton
Definition: QuartzWindow.h:167
CGFloat fScaleFactor()
BOOL fHasFocus
Definition: QuartzWindow.h:164
BOOL fActiveGrabOwnerEvents
Definition: QuartzWindow.h:185
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:238
void mapSubwindows()
void configureNotifyTree()
void activatePassiveGrab()
CGContextRef fContext
Definition: QuartzWindow.h:155
NSMutableDictionary * fX11Properties
Definition: QuartzWindow.h:180
BOOL fPassiveGrabOwnerEvents
Definition: QuartzWindow.h:171
void lowerWindow()
BOOL fIsOpenGLWidget()
unsigned fWidth()
QuartzView * fParentView
Definition: QuartzWindow.h:165
unsigned fID
Definition: QuartzWindow.h:154
unsigned fPassiveGrabEventMask
Definition: QuartzWindow.h:168
QuartzImage * fBackgroundPixmap
Definition: QuartzWindow.h:181
void unmapWindow()
ROOT::MacOSX::X11::PointerGrab fCurrentGrabType
Definition: QuartzWindow.h:183
BOOL fIsOverlapped
Definition: QuartzWindow.h:178
long fEventMask
Definition: QuartzWindow.h:156
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:161
unsigned fActiveGrabEventMask
Definition: QuartzWindow.h:170
unsigned fHeight()
BOOL fOverrideRedirect
Definition: QuartzWindow.h:162
NSView< X11Window > * fContentView
Definition: QuartzWindow.h:237
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:98
QuartzView * fParentView
Definition: QuartzWindow.h:107
BOOL fIsOpenGLWidget()
unsigned fHeight()
CGFloat fScaleFactor()
BOOL fDelayedTransient
Definition: QuartzWindow.h:37
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:109
QuartzView * fContentView
Definition: QuartzWindow.h:36
QuartzWindow * fMainWindow
Definition: QuartzWindow.h:33
unsigned fWidth()
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:38
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
bool ViewIsTextView(NSView< X11Window > *view)
NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
NSPoint TranslateToScreen(NSView< X11Window > *from, NSPoint point)
CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
bool ScreenPointIsInView(NSView< X11Window > *view, Int_t x, Int_t y)
NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
void GetWindowGeometry(NSObject< X11Window > *win, WindowAttributes_t *dst)
void GetWindowAttributes(NSObject< X11Window > *window, WindowAttributes_t *dst)
NSView< X11Window > * FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
NSView< X11Window > * FrameForHtmlView(NSView< X11Window > *htmlView)
QuartzWindow * FindWindowInPoint(Int_t x, Int_t y)
int GlobalXCocoaToROOT(CGFloat xCocoa)
void WindowLostFocus(Window_t winID)
int LocalYROOTToCocoa(NSView< X11Window > *parentView, CGFloat yROOT)
NSView< X11Window > * FindViewForPointerEvent(NSEvent *pointerEvent)
NSView< X11Window > * FrameForTextView(NSView< X11Window > *textView)
NSComparisonResult CompareViewsToLower(id view1, id view2, void *context)
int LocalYCocoaToROOT(NSView< X11Window > *parentView, CGFloat yCocoa)
NSPoint TranslateCoordinates(NSView< X11Window > *fromView, NSView< X11Window > *toView, NSPoint sourcePoint)
QuartzWindow * CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t)
Definition: QuartzWindow.mm:56
NSView< X11Window > * FindViewUnderPointer()
void UnlockFocus(NSView< X11Window > *view)
int GlobalXROOTToCocoa(CGFloat xROOT)
bool ViewIsHtmlView(NSView< X11Window > *view)
QuartzView * CreateChildView(QuartzView *parent, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t wtype)
Definition: QuartzWindow.mm:85
bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
QuartzWindow * FindWindowForPointerEvent(NSEvent *pointerEvent)
bool ViewIsTextView(unsigned viewID)
void GetRootWindowAttributes(WindowAttributes_t *attr)
bool ViewIsHtmlView(unsigned viewID)
QuartzWindow * FindWindowUnderPointer()
bool ViewIsTextViewFrame(NSView< X11Window > *view, bool checkParent)
NSPoint TranslateFromScreen(NSPoint point, NSView< X11Window > *to)
void ClipToShapeMask(NSView< X11Window > *view, CGContextRef ctx)
void SetWindowAttributes(const SetWindowAttributes_t *attr, NSObject< X11Window > *window)
NSCursor * CreateCursor(ECursor currentCursor)
bool LockFocus(NSView< X11Window > *view)
NSComparisonResult CompareViewsToRaise(id view1, id view2, void *context)
std::vector< unsigned char > DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
unsigned fID
Definition: X11Drawable.h:37
QuartzView * fParentView
Definition: X11Drawable.h:100
BOOL fOverrideRedirect
Definition: X11Drawable.h:89
EGEventType fType
Definition: GuiTypes.h:174
Handle_t fHandle
Definition: GuiTypes.h:184
Int_t fFormat
Definition: GuiTypes.h:185
Window_t fWindow
Definition: GuiTypes.h:175
Long_t fUser[5]
Definition: GuiTypes.h:186
ULong_t fBackgroundPixel
Definition: GuiTypes.h:94
Window_t fRoot
Definition: GuiTypes.h:119
ULong_t fBackingPlanes
Definition: GuiTypes.h:124
Long_t fAllEventMasks
Definition: GuiTypes.h:130
ULong_t fBackingPixel
Definition: GuiTypes.h:125
Long_t fYourEventMask
Definition: GuiTypes.h:131
Bool_t fMapInstalled
Definition: GuiTypes.h:128
Colormap_t fColormap
Definition: GuiTypes.h:127
Bool_t fOverrideRedirect
Definition: GuiTypes.h:133