Merge pull request #4621 from alexanderkyte/strdup_env
[mono.git] / mcs / class / System.Drawing / System.Drawing / macFunctions.cs
1 //
2 // System.Drawing.carbonFunctions.cs
3 //
4 // Authors:
5 //      Geoff Norton (gnorton@customerdna.com>
6 //
7 // Copyright (C) 2007 Novell, Inc. (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 #undef DEBUG_CLIPPING
29
30 using System.Collections;
31 using System.Reflection;
32 using System.Runtime.InteropServices;
33 using System.Security;
34
35 namespace System.Drawing {
36
37         internal static class MacSupport {
38                 internal static Hashtable contextReference = new Hashtable ();
39                 internal static object lockobj = new object ();
40
41                 internal static Delegate hwnd_delegate;
42
43 #if DEBUG_CLIPPING
44                 internal static float red = 1.0f;
45                 internal static float green = 0.0f;
46                 internal static float blue = 0.0f;
47                 internal static int debug_threshold = 1;
48 #endif
49
50                 static MacSupport () {
51                         foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ()) {
52                                 if (String.Equals (asm.GetName ().Name, "System.Windows.Forms")) {
53                                         Type driver_type = asm.GetType ("System.Windows.Forms.XplatUICarbon");
54                                         if (driver_type != null) {
55                                                 hwnd_delegate = (Delegate) driver_type.GetField ("HwndDelegate", BindingFlags.NonPublic | BindingFlags.Static).GetValue (null);
56                                         }
57                                 }
58                         }
59                 }
60
61                 internal static CocoaContext GetCGContextForNSView (IntPtr handle) {
62                         IntPtr graphicsContext = objc_msgSend (objc_getClass ("NSGraphicsContext"), sel_registerName ("currentContext"));
63                         IntPtr ctx = objc_msgSend (graphicsContext, sel_registerName ("graphicsPort"));
64                         Rect bounds = new Rect ();
65
66                         CGContextSaveGState (ctx);
67
68                         objc_msgSend_stret (ref bounds, handle, sel_registerName ("bounds"));
69
70                         var isFlipped = bool_objc_msgSend (handle, sel_registerName ("isFlipped"));
71                         if (isFlipped) {
72                                 CGContextTranslateCTM (ctx, bounds.origin.x, bounds.size.height);
73                                 CGContextScaleCTM (ctx,1.0f,-1.0f);
74                         }
75
76                         return new CocoaContext (ctx, (int) bounds.size.width, (int) bounds.size.height);
77                 }
78
79                 internal static CarbonContext GetCGContextForView (IntPtr handle) {
80                         IntPtr context = IntPtr.Zero;
81                         IntPtr port = IntPtr.Zero;
82                         IntPtr window = IntPtr.Zero;
83
84                         window = GetControlOwner (handle);
85
86                         if (handle == IntPtr.Zero || window == IntPtr.Zero) {
87                                 // FIXME: Can we actually get a CGContextRef for the desktop?  this makes context IntPtr.Zero
88                                 port = GetQDGlobalsThePort ();
89                                 CreateCGContextForPort (port, ref context);
90
91                                 Rect desktop_bounds = CGDisplayBounds (CGMainDisplayID ());
92
93                                 return new CarbonContext (port, context, (int)desktop_bounds.size.width, (int)desktop_bounds.size.height);
94                         }
95
96                         QDRect window_bounds = new QDRect ();
97                         Rect view_bounds = new Rect ();
98
99                         port = GetWindowPort (window);
100                         
101                         context = GetContext (port);
102
103                         GetWindowBounds (window, 32, ref window_bounds);
104
105                         HIViewGetBounds (handle, ref view_bounds);
106
107                         HIViewConvertRect (ref view_bounds, handle, IntPtr.Zero);
108                         
109                         if (view_bounds.size.height < 0) view_bounds.size.height = 0;
110                         if (view_bounds.size.width < 0) view_bounds.size.width = 0;
111
112                         CGContextTranslateCTM (context, view_bounds.origin.x, (window_bounds.bottom - window_bounds.top) - (view_bounds.origin.y + view_bounds.size.height));
113
114                         // Create the original rect path and clip to it
115                         Rect rc_clip = new Rect (0, 0, view_bounds.size.width, view_bounds.size.height);
116
117                         CGContextSaveGState (context);
118
119                         Rectangle [] clip_rectangles = (Rectangle []) hwnd_delegate.DynamicInvoke (new object [] {handle});
120                         if (clip_rectangles != null && clip_rectangles.Length > 0) {
121                                 int length = clip_rectangles.Length;
122                                 
123                                 CGContextBeginPath (context);
124                                 CGContextAddRect (context, rc_clip);
125
126                                 for (int i = 0; i < length; i++) {
127                                         CGContextAddRect (context, new Rect (clip_rectangles [i].X, view_bounds.size.height - clip_rectangles [i].Y - clip_rectangles [i].Height, clip_rectangles [i].Width, clip_rectangles [i].Height));
128                                 }
129                                 CGContextClosePath (context);
130                                 CGContextEOClip (context);
131 #if DEBUG_CLIPPING
132                                 if (clip_rectangles.Length >= debug_threshold) {
133                                         CGContextSetRGBFillColor (context, red, green, blue, 0.5f);
134                                         CGContextFillRect (context, rc_clip);
135                                         CGContextFlush (context);
136                                         System.Threading.Thread.Sleep (500);
137                                         if (red == 1.0f) { red = 0.0f; blue = 1.0f; } 
138                                         else if (blue == 1.0f) { blue = 0.0f; green = 1.0f; } 
139                                         else if (green == 1.0f) { green = 0.0f; red = 1.0f; } 
140                                 }
141 #endif
142                         } else {
143                                 CGContextBeginPath (context);
144                                 CGContextAddRect (context, rc_clip);
145                                 CGContextClosePath (context);
146                                 CGContextClip (context);
147                         }
148
149                         return new CarbonContext (port, context, (int)view_bounds.size.width, (int)view_bounds.size.height);
150                 }
151
152                 internal static IntPtr GetContext (IntPtr port) {
153                         IntPtr context = IntPtr.Zero;
154
155                         lock (lockobj) { 
156 #if FALSE
157                                 if (contextReference [port] != null) {
158                                         CreateCGContextForPort (port, ref context);
159                                 } else {
160                                         QDBeginCGContext (port, ref context);
161                                         contextReference [port] = context;
162                                 }
163 #else
164                                 CreateCGContextForPort (port, ref context);
165 #endif
166                         }
167
168                         return context;
169                 }
170
171                 internal static void ReleaseContext (IntPtr port, IntPtr context) {
172                         CGContextRestoreGState (context);
173
174                         lock (lockobj) { 
175 #if FALSE
176                                 if (contextReference [port] != null && context == (IntPtr) contextReference [port]) { 
177                                         QDEndCGContext (port, ref context);
178                                         contextReference [port] = null;
179                                 } else {
180                                         CFRelease (context);
181                                 }
182 #else
183                                 CFRelease (context);
184 #endif
185                         }
186                 }
187
188                 #region Cocoa Methods
189                 [DllImport("libobjc.dylib")]
190                 public static extern IntPtr objc_getClass(string className); 
191                 [DllImport("libobjc.dylib")]
192                 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, string argument);  
193                 [DllImport("libobjc.dylib")]
194                 public static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector);        
195                 [DllImport("libobjc.dylib")]
196                 public static extern void objc_msgSend_stret(ref Rect arect, IntPtr basePtr, IntPtr selector);        
197                 [DllImport ("libobjc.dylib", EntryPoint = "objc_msgSend")]
198                 public static extern bool bool_objc_msgSend (IntPtr handle, IntPtr selector);
199                 [DllImport("libobjc.dylib")]
200                 public static extern IntPtr sel_registerName(string selectorName);         
201                 #endregion
202
203                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
204                 internal static extern IntPtr CGMainDisplayID ();
205                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
206                 internal static extern Rect CGDisplayBounds (IntPtr display);
207
208                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
209                 internal static extern int HIViewGetBounds (IntPtr vHnd, ref Rect r);
210                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
211                 internal static extern int HIViewConvertRect (ref Rect r, IntPtr a, IntPtr b);
212
213                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
214                 internal static extern IntPtr GetControlOwner (IntPtr aView);
215
216                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
217                 internal static extern int GetWindowBounds (IntPtr wHnd, uint reg, ref QDRect rect);
218                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
219                 internal static extern IntPtr GetWindowPort (IntPtr hWnd);
220                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
221                 internal static extern IntPtr GetQDGlobalsThePort ();
222                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
223                 internal static extern void CreateCGContextForPort (IntPtr port, ref IntPtr context);
224                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
225                 internal static extern void CFRelease (IntPtr context);
226                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
227                 internal static extern void QDBeginCGContext (IntPtr port, ref IntPtr context);
228                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
229                 internal static extern void QDEndCGContext (IntPtr port, ref IntPtr context);
230                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
231                 internal static extern int CGContextClipToRect (IntPtr context, Rect clip);
232                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
233                 internal static extern int CGContextClipToRects (IntPtr context, Rect [] clip_rects, int count);
234                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
235                 internal static extern void CGContextTranslateCTM (IntPtr context, float tx, float ty);
236                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
237                 internal static extern void CGContextScaleCTM (IntPtr context, float x, float y);
238                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
239                 internal static extern void CGContextFlush (IntPtr context);
240                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
241                 internal static extern void CGContextSynchronize (IntPtr context);
242                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
243                 internal static extern IntPtr CGPathCreateMutable ();
244                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
245                 internal static extern void CGPathAddRects (IntPtr path, IntPtr _void, Rect [] rects, int count);
246                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
247                 internal static extern void CGPathAddRect (IntPtr path, IntPtr _void, Rect rect);
248                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
249                 internal static extern void CGContextAddRects (IntPtr context, Rect [] rects, int count);
250                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
251                 internal static extern void CGContextAddRect (IntPtr context, Rect rect);
252                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
253                 internal static extern void CGContextBeginPath (IntPtr context);
254                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
255                 internal static extern void CGContextClosePath (IntPtr context);
256                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
257                 internal static extern void CGContextAddPath (IntPtr context, IntPtr path);
258                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
259                 internal static extern void CGContextClip (IntPtr context);
260                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
261                 internal static extern void CGContextEOClip (IntPtr context);
262                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
263                 internal static extern void CGContextEOFillPath (IntPtr context);
264                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
265                 internal static extern void CGContextSaveGState (IntPtr context);
266                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
267                 internal static extern void CGContextRestoreGState (IntPtr context);
268
269 #if DEBUG_CLIPPING
270                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
271                 internal static extern void CGContextSetRGBFillColor (IntPtr context, float red, float green, float blue, float alpha);
272                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
273                 internal static extern void CGContextFillRect (IntPtr context, Rect rect);
274 #endif
275         }
276
277         internal struct CGSize {
278                 public float width;
279                 public float height;
280         }
281
282         internal struct CGPoint {
283                 public float x;
284                 public float y;
285         }
286
287         internal struct Rect {
288                 public Rect (float x, float y, float width, float height) {
289                         this.origin.x = x;
290                         this.origin.y = y;
291                         this.size.width = width;
292                         this.size.height = height;
293                 }
294
295                 public CGPoint origin;
296                 public CGSize size;
297         }
298
299         internal struct QDRect
300         {
301                 public short top;
302                 public short left;
303                 public short bottom;
304                 public short right;
305         }
306
307         internal struct CarbonContext : IMacContext
308         {
309                 public IntPtr port;
310                 public IntPtr ctx;
311                 public int width;
312                 public int height;
313
314                 public CarbonContext (IntPtr port, IntPtr ctx, int width, int height)
315                 {
316                         this.port = port;
317                         this.ctx = ctx;
318                         this.width = width;
319                         this.height = height;
320                 }
321
322                 public void Synchronize ()
323                 {
324                         MacSupport.CGContextSynchronize (ctx);
325                 }
326
327                 public void Release ()
328                 {
329                         MacSupport.ReleaseContext (port, ctx);
330                 }
331         }
332
333         internal struct CocoaContext : IMacContext
334         {
335                 public IntPtr ctx;
336                 public int width;
337                 public int height;
338
339                 public CocoaContext (IntPtr ctx, int width, int height)
340                 {
341                         this.ctx = ctx;
342                         this.width = width;
343                         this.height = height;
344                 }
345
346                 public void Synchronize ()
347                 {
348                         MacSupport.CGContextSynchronize (ctx);
349                 }
350
351                 public void Release ()
352                 {
353                         MacSupport.CGContextRestoreGState(ctx);
354                 }
355         }
356
357         internal interface IMacContext
358         {
359                 void Synchronize ();
360                 void Release ();
361         }
362 }