Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region License
2
//
3
// The Open Toolkit Library License
4
//
5
// Copyright (c) 2006 - 2009 the Open Toolkit library.
6
//
7
// Permission is hereby granted, free of charge, to any person obtaining a copy
8
// of this software and associated documentation files (the "Software"), to deal
9
// in the Software without restriction, including without limitation the rights to 
10
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
// the Software, and to permit persons to whom the Software is furnished to do
12
// so, subject to the following conditions:
13
//
14
// The above copyright notice and this permission notice shall be included in all
15
// copies or substantial portions of the Software.
16
//
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
// OTHER DEALINGS IN THE SOFTWARE.
25
//
26
#endregion
27
 
28
using System;
29
using System.Collections.Generic;
30
using System.ComponentModel;
31
using System.Diagnostics;
32
using System.Drawing;
33
using System.Text;
34
 
35
namespace OpenTK.Platform.MacOS
36
{
37
    using Carbon;
38
    using Graphics;
39
 
40
    class CarbonGLNative : INativeWindow
41
    {
42
        #region Fields
43
 
44
        CarbonWindowInfo window;
45
        CarbonInput mInputDriver;
46
 
47
        static MacOSKeyMap Keymap = new MacOSKeyMap();
48
 
49
        IntPtr uppHandler;
50
 
51
        string title = "OpenTK Window";
52
        Rectangle bounds, clientRectangle;
53
                Rectangle windowedBounds;
54
        bool mIsDisposed = false;
55
                bool mExists = true;
56
                DisplayDevice mDisplayDevice;
57
 
58
        WindowAttributes mWindowAttrib;
59
        WindowClass mWindowClass;
60
        WindowPositionMethod mPositionMethod = WindowPositionMethod.CenterOnMainScreen;
61
        int mTitlebarHeight;
62
        private WindowBorder windowBorder = WindowBorder.Resizable;
63
        private WindowState windowState = WindowState.Normal;
64
 
65
        static Dictionary<IntPtr, WeakReference> mWindows = new Dictionary<IntPtr, WeakReference>();
66
 
67
                KeyPressEventArgs mKeyPressArgs = new KeyPressEventArgs((char)0);
68
 
69
                bool mMouseIn = false;
70
                bool mIsActive = false;
71
 
72
                Icon mIcon;
73
 
74
        #endregion
75
 
76
                #region AGL Device Hack
77
 
78
                static internal Dictionary<IntPtr, WeakReference> WindowRefMap { get { return mWindows; } }
79
                internal DisplayDevice TargetDisplayDevice { get { return mDisplayDevice; } }
80
 
81
                #endregion
82
 
83
                #region Constructors
84
 
85
                static CarbonGLNative()
86
        {
87
            Application.Initialize();
88
        }
89
 
90
        CarbonGLNative()
91
            : this(WindowClass.Document,
92
            WindowAttributes.StandardDocument |
93
            WindowAttributes.StandardHandler |
94
            WindowAttributes.InWindowMenu |
95
            WindowAttributes.LiveResize)
96
        { }
97
 
98
 
99
        CarbonGLNative(WindowClass @class, WindowAttributes attrib)
100
        {
101
            mWindowClass = @class;
102
            mWindowAttrib = attrib;
103
        }
104
 
105
        public CarbonGLNative(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
106
        {
107
                        CreateNativeWindow(WindowClass.Document,
108
                WindowAttributes.StandardDocument | WindowAttributes.StandardHandler |
109
                WindowAttributes.InWindowMenu | WindowAttributes.LiveResize,
110
                new Rect((short)x, (short)y, (short)width, (short)height));
111
 
112
                        mDisplayDevice = device;
113
        }
114
 
115
        #endregion
116
 
117
        #region IDisposable
118
 
119
        public void Dispose()
120
        {
121
            Dispose(true);
122
            GC.SuppressFinalize(this);
123
        }
124
 
125
        protected virtual void Dispose(bool disposing)
126
        {
127
            if (mIsDisposed)
128
                return;
129
 
130
            Debug.Print("Disposing of CarbonGLNative window.");
131
 
132
                        API.DisposeWindow(window.WindowRef);
133
 
134
            mIsDisposed = true;
135
                        mExists = false;
136
 
137
            if (disposing)
138
            {
139
                mWindows.Remove(window.WindowRef);
140
 
141
                window.Dispose();
142
                window = null;
143
            }
144
 
145
            DisposeUPP();
146
 
147
        }
148
 
149
        ~CarbonGLNative()
150
        {
151
            Dispose(false);
152
        }
153
 
154
        #endregion
155
 
156
        #region Private Members
157
 
158
        void DisposeUPP()
159
        {
160
            if (uppHandler != IntPtr.Zero)
161
            {
162
                //API.RemoveEventHandler(uppHandler);
163
                //API.DisposeEventHandlerUPP(uppHandler);
164
            }
165
 
166
            uppHandler = IntPtr.Zero;
167
        }
168
 
169
        void CreateNativeWindow(WindowClass @class, WindowAttributes attrib, Rect r)
170
        {
171
            Debug.Print("Creating window...");
172
            Debug.Indent();
173
 
174
            IntPtr windowRef = API.CreateNewWindow(@class, attrib, r);
175
            API.SetWindowTitle(windowRef, title);
176
 
177
            window = new CarbonWindowInfo(windowRef, true, false);
178
 
179
            SetLocation(r.X, r.Y);
180
            SetSize(r.Width, r.Height);
181
 
182
            Debug.Unindent();
183
            Debug.Print("Created window.");
184
 
185
            mWindows.Add(windowRef, new WeakReference(this));
186
 
187
            LoadSize();
188
 
189
            Rect titleSize = API.GetWindowBounds(window.WindowRef, WindowRegionCode.TitleBarRegion);
190
            mTitlebarHeight = titleSize.Height;
191
 
192
            Debug.Print("Titlebar size: {0}", titleSize);
193
 
194
            ConnectEvents();
195
 
196
            System.Diagnostics.Debug.Print("Attached window events.");
197
        }
198
 
199
        void ConnectEvents()
200
        {
201
            mInputDriver = new CarbonInput();
202
 
203
            EventTypeSpec[] eventTypes = new EventTypeSpec[]
204
            {
205
                new EventTypeSpec(EventClass.Window, WindowEventKind.WindowClose),
206
                new EventTypeSpec(EventClass.Window, WindowEventKind.WindowClosed),
207
                new EventTypeSpec(EventClass.Window, WindowEventKind.WindowBoundsChanged),
208
                                new EventTypeSpec(EventClass.Window, WindowEventKind.WindowActivate),
209
                                new EventTypeSpec(EventClass.Window, WindowEventKind.WindowDeactivate),
210
 
211
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseDown),
212
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseUp),
213
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseMoved),
214
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseDragged),
215
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseEntered),
216
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.MouseExited),
217
                //new EventTypeSpec(EventClass.Mouse, MouseEventKind.WheelMoved),
218
 
219
                //new EventTypeSpec(EventClass.Keyboard, KeyboardEventKind.RawKeyDown),
220
                //new EventTypeSpec(EventClass.Keyboard, KeyboardEventKind.RawKeyRepeat),
221
                //new EventTypeSpec(EventClass.Keyboard, KeyboardEventKind.RawKeyUp),
222
                //new EventTypeSpec(EventClass.Keyboard, KeyboardEventKind.RawKeyModifiersChanged),
223
            };
224
 
225
            MacOSEventHandler handler = EventHandler;
226
            uppHandler = API.NewEventHandlerUPP(handler);
227
 
228
            API.InstallWindowEventHandler(window.WindowRef, uppHandler, eventTypes, window.WindowRef, IntPtr.Zero);
229
 
230
            Application.WindowEventHandler = this;
231
        }
232
 
233
        void Activate()
234
        {
235
            API.SelectWindow(window.WindowRef);
236
        }
237
 
238
        void Show()
239
        {
240
            IntPtr parent = IntPtr.Zero;
241
 
242
            API.ShowWindow(window.WindowRef);
243
            API.RepositionWindow(window.WindowRef, parent, WindowPositionMethod);
244
            API.SelectWindow(window.WindowRef);
245
        }
246
 
247
        void Hide()
248
        {
249
            API.HideWindow(window.WindowRef);
250
        }
251
 
252
        internal void SetFullscreen(AglContext context)
253
        {
254
            windowedBounds = bounds;
255
 
256
                        int width, height;
257
 
258
            context.SetFullScreen(window, out width, out height);
259
 
260
            Debug.Print("Prev Size: {0}, {1}", Width, Height);
261
                        clientRectangle.Size = new Size(width, height);
262
                        Debug.Print("New Size: {0}, {1}", Width, Height);
263
 
264
                        // TODO: if we go full screen we need to make this use the device specified.
265
            bounds = mDisplayDevice.Bounds;
266
 
267
 
268
                        windowState = WindowState.Fullscreen;
269
        }
270
 
271
        internal void UnsetFullscreen(AglContext context)
272
        {
273
            context.UnsetFullScreen(window);
274
 
275
                        Debug.Print("Telling Carbon to reset window state to " + windowState.ToString());
276
                        SetCarbonWindowState();
277
 
278
            SetSize((short)windowedBounds.Width, (short)windowedBounds.Height);
279
        }
280
 
281
        bool IsDisposed
282
        {
283
            get { return mIsDisposed; }
284
        }
285
 
286
        WindowPositionMethod WindowPositionMethod
287
        {
288
            get { return mPositionMethod; }
289
            set { mPositionMethod = value; }
290
        }
291
 
292
        internal OSStatus DispatchEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
293
        {
294
            switch (evt.EventClass)
295
            {
296
                case EventClass.Window:
297
                    return ProcessWindowEvent(inCaller, inEvent, evt, userData);
298
 
299
                case EventClass.Mouse:
300
                    return ProcessMouseEvent(inCaller, inEvent, evt, userData);
301
 
302
                case EventClass.Keyboard:
303
                    return ProcessKeyboardEvent(inCaller, inEvent, evt, userData);
304
 
305
                default:
306
                    return OSStatus.EventNotHandled;
307
            }
308
        }
309
 
310
        protected static OSStatus EventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData)
311
        {
312
            // bail out if the window passed in is not actually our window.
313
            // I think this happens if using winforms with a GameWindow sometimes.
314
            if (mWindows.ContainsKey(userData) == false)
315
                return OSStatus.EventNotHandled;
316
 
317
            WeakReference reference = mWindows[userData];
318
 
319
            // bail out if the CarbonGLNative window has been garbage collected.
320
            if (reference.IsAlive == false)
321
            {
322
                mWindows.Remove(userData);
323
                return OSStatus.EventNotHandled;
324
            }
325
 
326
                        CarbonGLNative window = (CarbonGLNative)reference.Target;
327
                        EventInfo evt = new EventInfo(inEvent);
328
 
329
            //Debug.Print("Processing {0} event for {1}.", evt, window.window);
330
 
331
            if (window == null)
332
            {
333
                Debug.WriteLine("Window for event not found.");
334
                return OSStatus.EventNotHandled;
335
            }
336
 
337
            switch (evt.EventClass)
338
            {
339
                case EventClass.Window:
340
                    return window.ProcessWindowEvent(inCaller, inEvent, evt, userData);
341
 
342
                case EventClass.Mouse:
343
                    return window.ProcessMouseEvent(inCaller, inEvent, evt, userData);
344
 
345
                case EventClass.Keyboard:
346
                    return window.ProcessKeyboardEvent(inCaller, inEvent, evt, userData);
347
 
348
                default:
349
                    return OSStatus.EventNotHandled;
350
            }
351
        }
352
 
353
        private OSStatus ProcessKeyboardEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
354
        {
355
            System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Keyboard);
356
            MacOSKeyCode code = (MacOSKeyCode)0;
357
            char charCode = '\0';
358
 
359
                        //Debug.Print("Processing keyboard event {0}", evt.KeyboardEventKind);
360
 
361
                        switch (evt.KeyboardEventKind)
362
                        {
363
                                case KeyboardEventKind.RawKeyDown:
364
                                case KeyboardEventKind.RawKeyRepeat:
365
                                case KeyboardEventKind.RawKeyUp:
366
                                        GetCharCodes(inEvent, out code, out charCode);
367
                                        mKeyPressArgs.KeyChar = charCode;
368
                                        break;
369
                        }
370
 
371
            switch (evt.KeyboardEventKind)
372
            {
373
                case KeyboardEventKind.RawKeyRepeat:
374
                    InputDriver.Keyboard[0].KeyRepeat = true;
375
                    goto case KeyboardEventKind.RawKeyDown;
376
 
377
                case KeyboardEventKind.RawKeyDown:
378
                                        OnKeyPress(mKeyPressArgs);
379
                    InputDriver.Keyboard[0][Keymap[code]] = true;
380
                    return OSStatus.NoError;
381
 
382
                case KeyboardEventKind.RawKeyUp:
383
                    InputDriver.Keyboard[0][Keymap[code]] = false;
384
 
385
                                        return OSStatus.NoError;
386
 
387
                case KeyboardEventKind.RawKeyModifiersChanged:
388
                    ProcessModifierKey(inEvent);
389
                                        return OSStatus.NoError;
390
 
391
                default:
392
                    return OSStatus.EventNotHandled;
393
            }
394
 
395
 
396
        }
397
 
398
        private OSStatus ProcessWindowEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
399
        {
400
            System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Window);
401
 
402
            switch (evt.WindowEventKind)
403
            {
404
                case WindowEventKind.WindowClose:
405
                    CancelEventArgs cancel = new CancelEventArgs();
406
                    OnClosing(cancel);
407
 
408
                    if (cancel.Cancel)
409
                        return OSStatus.NoError;
410
                    else
411
                        return OSStatus.EventNotHandled;
412
 
413
                case WindowEventKind.WindowClosed:
414
                                        mExists = false;
415
                                        OnClosed();
416
 
417
                    return OSStatus.NoError;
418
 
419
                case WindowEventKind.WindowBoundsChanged:
420
                    int thisWidth = Width;
421
                    int thisHeight = Height;
422
 
423
                    LoadSize();
424
 
425
                    if (thisWidth != Width || thisHeight != Height)
426
                        OnResize();
427
 
428
                    return OSStatus.EventNotHandled;
429
 
430
                                case WindowEventKind.WindowActivate:
431
                                        OnActivate();
432
                                        return OSStatus.EventNotHandled;
433
 
434
                                case WindowEventKind.WindowDeactivate:
435
                                        OnDeactivate();
436
                                        return OSStatus.EventNotHandled;
437
 
438
                default:
439
                    Debug.Print("{0}", evt);
440
 
441
                    return OSStatus.EventNotHandled;
442
            }
443
        }
444
        protected OSStatus ProcessMouseEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
445
        {
446
            System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Mouse);
447
            MouseButton button = MouseButton.Primary;
448
            HIPoint pt = new HIPoint();
449
                        HIPoint screenLoc =  new HIPoint();
450
 
451
                        OSStatus err = API.GetEventMouseLocation(inEvent, out screenLoc);
452
 
453
            if (this.windowState == WindowState.Fullscreen)
454
            {
455
                                pt = screenLoc;
456
            }
457
            else
458
            {
459
                err = API.GetEventWindowMouseLocation(inEvent, out pt);
460
            }
461
 
462
            if (err != OSStatus.NoError)
463
            {
464
                // this error comes up from the application event handler.
465
                if (err != OSStatus.EventParameterNotFound)
466
                {
467
                    throw new MacOSException(err);
468
                }
469
            }
470
 
471
                        Point mousePosInClient = new Point((int)pt.X, (int)pt.Y);
472
                        if (this.windowState != WindowState.Fullscreen)
473
                        {
474
                                mousePosInClient.Y -= mTitlebarHeight;
475
                        }
476
 
477
                        // check for enter/leave events
478
                        IntPtr thisEventWindow;
479
                        API.GetEventWindowRef(inEvent, out thisEventWindow);
480
                        CheckEnterLeaveEvents(thisEventWindow, mousePosInClient);
481
 
482
            switch (evt.MouseEventKind)
483
            {
484
                case MouseEventKind.MouseDown:
485
                    button = API.GetEventMouseButton(inEvent);
486
 
487
                    switch (button)
488
                    {
489
                        case MouseButton.Primary:
490
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Left] = true;
491
                            break;
492
 
493
                        case MouseButton.Secondary:
494
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Right] = true;
495
                            break;
496
 
497
                        case MouseButton.Tertiary:
498
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Middle] = true;
499
                            break;
500
                    }
501
 
502
 
503
                                        return OSStatus.NoError;
504
 
505
                case MouseEventKind.MouseUp:
506
                                        button = API.GetEventMouseButton(inEvent);
507
 
508
                    switch (button)
509
                    {
510
                        case MouseButton.Primary:
511
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Left] = false;
512
                            break;
513
 
514
                        case MouseButton.Secondary:
515
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Right] = false;
516
                            break;
517
 
518
                        case MouseButton.Tertiary:
519
                            InputDriver.Mouse[0][OpenTK.Input.MouseButton.Middle] = false;
520
                            break;
521
                    }
522
 
523
                    button = API.GetEventMouseButton(inEvent);
524
 
525
                                        return OSStatus.NoError;
526
 
527
                                case MouseEventKind.WheelMoved:
528
 
529
                                        int delta = API.GetEventMouseWheelDelta(inEvent) / 3;
530
 
531
                                        InputDriver.Mouse[0].Wheel += delta;
532
 
533
                                        return OSStatus.NoError;
534
 
535
                case MouseEventKind.MouseMoved:
536
                case MouseEventKind.MouseDragged:
537
 
538
                                        //Debug.Print("Mouse Location: {0}, {1}", pt.X, pt.Y);
539
 
540
                                        if (this.windowState == WindowState.Fullscreen)
541
                                        {
542
                                                if (mousePosInClient.X != InputDriver.Mouse[0].X ||
543
                                                        mousePosInClient.Y != InputDriver.Mouse[0].Y)
544
                                                {
545
                                                        InputDriver.Mouse[0].Position = mousePosInClient;
546
                                                }
547
                                        }
548
                                        else
549
                                        {
550
                                                // ignore clicks in the title bar
551
                                                if (pt.Y < 0)
552
                                                        return OSStatus.EventNotHandled;
553
 
554
                                                if (mousePosInClient.X != InputDriver.Mouse[0].X ||
555
                                                        mousePosInClient.Y != InputDriver.Mouse[0].Y)
556
                                                {
557
                                                        InputDriver.Mouse[0].Position = mousePosInClient;
558
                                                }
559
                                        }
560
 
561
                    return OSStatus.EventNotHandled;
562
 
563
                default:
564
                    Debug.Print("{0}", evt);
565
 
566
                    return OSStatus.EventNotHandled;
567
            }
568
        }
569
 
570
                private void CheckEnterLeaveEvents(IntPtr eventWindowRef, Point pt)
571
                {
572
                        if (window == null)
573
                                return;
574
 
575
                        bool thisIn = eventWindowRef == window.WindowRef;
576
 
577
                        if (pt.Y < 0)
578
                                thisIn = false;
579
 
580
                        if (thisIn != mMouseIn)
581
                        {
582
                                mMouseIn = thisIn;
583
 
584
                                if (mMouseIn)
585
                                        OnMouseEnter();
586
                                else
587
                                        OnMouseLeave();
588
                        }
589
                }
590
 
591
        private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode)
592
        {
593
            code = API.GetEventKeyboardKeyCode(inEvent);
594
            charCode = API.GetEventKeyboardChar(inEvent);
595
        }
596
        private void ProcessModifierKey(IntPtr inEvent)
597
        {
598
            MacOSKeyModifiers modifiers = API.GetEventKeyModifiers(inEvent);
599
 
600
            bool caps = (modifiers & MacOSKeyModifiers.CapsLock) != 0 ? true : false;
601
            bool control = (modifiers & MacOSKeyModifiers.Control) != 0 ? true : false;
602
            bool command = (modifiers & MacOSKeyModifiers.Command) != 0 ? true : false;
603
            bool option = (modifiers & MacOSKeyModifiers.Option) != 0 ? true : false;
604
            bool shift = (modifiers & MacOSKeyModifiers.Shift) != 0 ? true : false;
605
 
606
            Debug.Print("Modifiers Changed: {0}", modifiers);
607
 
608
            Input.KeyboardDevice keyboard = InputDriver.Keyboard[0];
609
 
610
            if (keyboard[OpenTK.Input.Key.AltLeft] ^ option)
611
                keyboard[OpenTK.Input.Key.AltLeft] = option;
612
 
613
            if (keyboard[OpenTK.Input.Key.ShiftLeft] ^ shift)
614
                keyboard[OpenTK.Input.Key.ShiftLeft] = shift;
615
 
616
            if (keyboard[OpenTK.Input.Key.WinLeft] ^ command)
617
                keyboard[OpenTK.Input.Key.WinLeft] = command;
618
 
619
            if (keyboard[OpenTK.Input.Key.ControlLeft] ^ control)
620
                keyboard[OpenTK.Input.Key.ControlLeft] = control;
621
 
622
            if (keyboard[OpenTK.Input.Key.CapsLock] ^ caps)
623
                keyboard[OpenTK.Input.Key.CapsLock] = caps;
624
 
625
        }
626
 
627
        Rect GetRegion()
628
        {
629
            Rect retval = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion);
630
 
631
            return retval;
632
        }
633
 
634
        void SetLocation(short x, short y)
635
        {
636
            if (windowState == WindowState.Fullscreen)
637
                return;
638
 
639
            API.MoveWindow(window.WindowRef, x, y, false);
640
        }
641
 
642
        void SetSize(short width, short height)
643
        {
644
            if (WindowState == WindowState.Fullscreen)
645
                return;
646
 
647
                        // The bounds of the window should be the size specified, but
648
                        // API.SizeWindow sets the content region size.  So
649
                        // we reduce the size to get the correct bounds.
650
                        width -= (short)(bounds.Width - clientRectangle.Width);
651
                        height -= (short)(bounds.Height - clientRectangle.Height);
652
 
653
            API.SizeWindow(window.WindowRef, width, height, true);
654
        }
655
 
656
                void SetClientSize(short width, short height)
657
                {
658
                        if (WindowState == WindowState.Fullscreen)
659
                                return;
660
 
661
                        API.SizeWindow(window.WindowRef, width, height, true);
662
                }
663
 
664
        protected void OnResize()
665
        {
666
            LoadSize();
667
 
668
            if (Resize != null)
669
            {
670
                Resize(this, EventArgs.Empty);
671
            }
672
        }
673
 
674
        private void LoadSize()
675
        {
676
            if (WindowState == WindowState.Fullscreen)
677
                return;
678
 
679
                        Rect r = API.GetWindowBounds(window.WindowRef, WindowRegionCode.StructureRegion);
680
                        bounds = new Rectangle(r.X, r.Y, r.Width, r.Height);
681
 
682
                        r = API.GetWindowBounds(window.WindowRef, WindowRegionCode.GlobalPortRegion);
683
                        clientRectangle = new Rectangle(0, 0, r.Width, r.Height);
684
        }
685
 
686
        #endregion
687
 
688
                #region INativeWindow Members
689
 
690
                public void ProcessEvents()
691
        {
692
            Application.ProcessEvents();
693
        }
694
 
695
        public Point PointToClient(Point point)
696
        {
697
            IntPtr handle = window.WindowRef;
698
 
699
            Rect r = Carbon.API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion);
700
            Debug.Print("Rect: {0}", r);
701
 
702
            return new Point(point.X - r.X, point.Y - r.Y);
703
        }
704
        public Point PointToScreen(Point point)
705
        {
706
                        IntPtr handle = window.WindowRef;
707
 
708
                        Rect r = Carbon.API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion);
709
                        Debug.Print("Rect: {0}", r);
710
 
711
                        return new Point(point.X + r.X, point.Y + r.Y);
712
        }
713
 
714
        public bool Exists
715
        {
716
            get { return mExists; }
717
        }
718
 
719
        public IWindowInfo WindowInfo
720
        {
721
            get { return window; }
722
        }
723
 
724
        public bool IsIdle
725
        {
726
            get { return true; }
727
        }
728
 
729
        public OpenTK.Input.IInputDriver InputDriver
730
        {
731
            get
732
            {
733
                return mInputDriver;
734
            }
735
        }
736
 
737
 
738
        public Icon Icon
739
        {
740
                        get { return mIcon; }
741
            set {
742
                                SetIcon(value);
743
                        }
744
        }
745
 
746
                private void SetIcon(Icon icon)
747
                {
748
                        // The code for this function was adapted from Mono's 
749
                        // XplatUICarbon implementation, written by Geoff Norton
750
                        // http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/XplatUICarbon.cs?view=markup&pathrev=136932
751
                        if (icon == null)
752
                        {
753
                                API.RestoreApplicationDockTileImage();
754
                        }
755
                        else
756
                        {
757
                                Bitmap bitmap;
758
                                int size;
759
                                IntPtr[] data;
760
                                int index;
761
 
762
                                bitmap = new Bitmap(128, 128);
763
                                using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
764
                                {
765
                                        g.DrawImage(icon.ToBitmap(), 0, 0, 128, 128);
766
                                }
767
                                index = 0;
768
                                size = bitmap.Width * bitmap.Height;
769
                                data = new IntPtr[size];
770
 
771
                                for (int y = 0; y < bitmap.Height; y++)
772
                                {
773
                                        for (int x = 0; x < bitmap.Width; x++)
774
                                        {
775
                                                int pixel = bitmap.GetPixel(x, y).ToArgb();
776
                                                if (BitConverter.IsLittleEndian)
777
                                                {
778
                                                        byte a = (byte)((pixel >> 24) & 0xFF);
779
                                                        byte r = (byte)((pixel >> 16) & 0xFF);
780
                                                        byte g = (byte)((pixel >> 8) & 0xFF);
781
                                                        byte b = (byte)(pixel & 0xFF);
782
                                                        data[index++] = (IntPtr)(a + (r << 8) + (g << 16) + (b << 24));
783
                                                }
784
                                                else
785
                                                {
786
                                                        data[index++] = (IntPtr)pixel;
787
                                                }
788
                                        }
789
                                }
790
 
791
                                IntPtr provider = API.CGDataProviderCreateWithData(IntPtr.Zero, data, size * 4, IntPtr.Zero);
792
                                IntPtr image = API.CGImageCreate(128, 128, 8, 32, 4 * 128, API.CGColorSpaceCreateDeviceRGB(), 4, provider, IntPtr.Zero, 0, 0);
793
                                API.SetApplicationDockTileImage(image);
794
                        }
795
                }
796
 
797
        public string Title
798
        {
799
            get
800
            {
801
                return title;
802
            }
803
            set
804
            {
805
                API.SetWindowTitle(window.WindowRef, value);
806
                title = value;
807
            }
808
        }
809
 
810
        public bool Visible
811
        {
812
            get { return API.IsWindowVisible(window.WindowRef); }
813
            set
814
            {
815
                if (value && Visible == false)
816
                    Show();
817
                else
818
                    Hide();
819
            }
820
        }
821
 
822
        public bool Focused
823
        {
824
                        get { return this.mIsActive; }
825
        }
826
 
827
        public Rectangle Bounds
828
        {
829
            get
830
            {
831
 
832
                                return bounds;
833
            }
834
            set
835
            {
836
                Location = value.Location;
837
                Size = value.Size;
838
            }
839
        }
840
 
841
        public Point Location
842
        {
843
            get
844
            {
845
                return Bounds.Location;
846
            }
847
            set
848
            {
849
                SetLocation((short)value.X, (short)value.Y);
850
            }
851
        }
852
 
853
        public Size Size
854
        {
855
            get
856
            {
857
                return bounds.Size;
858
            }
859
            set
860
            {
861
                SetSize((short)value.Width, (short)value.Height);
862
            }
863
        }
864
 
865
        public int Width
866
        {
867
            get { return ClientRectangle.Width; }
868
            set { SetClientSize((short)value, (short)Height); }
869
        }
870
 
871
        public int Height
872
        {
873
            get { return ClientRectangle.Height; }
874
            set { SetClientSize((short)Width, (short)value); }
875
        }
876
 
877
        public int X
878
        {
879
            get
880
            {
881
                return ClientRectangle.X;
882
            }
883
            set
884
            {
885
                Location = new Point(value, Y);
886
            }
887
        }
888
 
889
        public int Y
890
        {
891
            get
892
            {
893
                return ClientRectangle.Y;
894
            }
895
            set
896
            {
897
                Location = new Point(X, value);
898
            }
899
        }
900
 
901
        public Rectangle ClientRectangle
902
        {
903
            get
904
            {
905
                                return clientRectangle;
906
            }
907
            set
908
            {
909
                                // just set the size, and ignore the location value.
910
                                // this is the behavior of the Windows WinGLNative.
911
                                ClientSize = value.Size;
912
            }
913
        }
914
 
915
        public Size ClientSize
916
        {
917
            get
918
            {
919
                return clientRectangle.Size;
920
            }
921
            set
922
            {
923
                                API.SizeWindow(window.WindowRef, (short)value.Width, (short)value.Height, true);
924
                                OnResize();
925
            }
926
        }
927
 
928
        public void Close()
929
        {
930
                        CancelEventArgs e = new CancelEventArgs();
931
                        OnClosing(e);
932
 
933
                        if (e.Cancel)
934
                                return;
935
 
936
                        OnClosed();
937
 
938
                        Dispose();
939
        }
940
 
941
        public WindowState WindowState
942
        {
943
            get
944
            {
945
                if (windowState == WindowState.Fullscreen)
946
                    return WindowState.Fullscreen;
947
 
948
                if (Carbon.API.IsWindowCollapsed(window.WindowRef))
949
                    return WindowState.Minimized;
950
 
951
                if (Carbon.API.IsWindowInStandardState(window.WindowRef))
952
                {
953
                    return WindowState.Maximized;
954
                }
955
 
956
                return WindowState.Normal;
957
            }
958
            set
959
            {
960
                if (value == WindowState)
961
                    return;
962
 
963
                Debug.Print("Switching window state from {0} to {1}", WindowState, value);
964
                                WindowState oldState = WindowState;
965
 
966
                                windowState = value;
967
 
968
                                if (oldState == WindowState.Fullscreen)
969
                {
970
                                        window.GoWindowedHack = true;
971
 
972
                                        // when returning from full screen, wait until the context is updated
973
                                        // to actually do the work.
974
                                        return;
975
                }
976
 
977
                if (oldState == WindowState.Minimized)
978
                {
979
                    API.CollapseWindow(window.WindowRef, false);
980
                }
981
 
982
                                SetCarbonWindowState();
983
            }
984
        }
985
 
986
                private void SetCarbonWindowState()
987
                {
988
                        CarbonPoint idealSize;
989
 
990
                        switch (windowState)
991
                        {
992
                                case WindowState.Fullscreen:
993
                                        window.GoFullScreenHack = true;
994
 
995
                                        break;
996
 
997
                                case WindowState.Maximized:
998
                                        // hack because mac os has no concept of maximized. Instead windows are "zoomed" 
999
                                        // meaning they are maximized up to their reported ideal size.  So we report a 
1000
                                        // large ideal size.
1001
                                        idealSize = new CarbonPoint(9000, 9000);
1002
                                        API.ZoomWindowIdeal(window.WindowRef, WindowPartCode.inZoomOut, ref idealSize);
1003
                                        break;
1004
 
1005
                                case WindowState.Normal:
1006
                                        if (WindowState == WindowState.Maximized)
1007
                                        {
1008
                                                idealSize = new CarbonPoint();
1009
                                                API.ZoomWindowIdeal(window.WindowRef, WindowPartCode.inZoomIn, ref idealSize);
1010
                                        }
1011
                                        break;
1012
 
1013
                                case WindowState.Minimized:
1014
                                        API.CollapseWindow(window.WindowRef, true);
1015
 
1016
                                        break;
1017
                        }
1018
 
1019
 
1020
                        OnWindowStateChanged();
1021
 
1022
                        OnResize();
1023
                }
1024
 
1025
                public WindowBorder WindowBorder
1026
                {
1027
                        get
1028
                        {
1029
                                return windowBorder;
1030
                        }
1031
                        set
1032
                        {
1033
                                if (windowBorder == value)
1034
                                        return;
1035
 
1036
                                windowBorder = value;
1037
 
1038
                                if (windowBorder == WindowBorder.Resizable)
1039
                                {
1040
                                        API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.Resizable | WindowAttributes.FullZoom,
1041
                                                                                           WindowAttributes.NoAttributes);
1042
                                }
1043
                                else if (windowBorder == WindowBorder.Fixed)
1044
                                {
1045
                                        API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.NoAttributes,
1046
                                                                                           WindowAttributes.Resizable | WindowAttributes.FullZoom);
1047
                                }
1048
 
1049
                                if (WindowBorderChanged != null)
1050
                                        WindowBorderChanged(this, EventArgs.Empty);
1051
                        }
1052
                }
1053
 
1054
                #region --- Event wrappers ---
1055
 
1056
                private void OnKeyPress(KeyPressEventArgs keyPressArgs)
1057
                {
1058
                        if (KeyPress != null)
1059
                                KeyPress(this, keyPressArgs);
1060
                }
1061
 
1062
 
1063
                private void OnWindowStateChanged()
1064
                {
1065
                        if (WindowStateChanged != null)
1066
                                WindowStateChanged(this, EventArgs.Empty);
1067
                }
1068
 
1069
                protected virtual void OnClosing(CancelEventArgs e)
1070
                {
1071
                        if (Closing != null)
1072
                                Closing(this, e);
1073
                }
1074
 
1075
                protected virtual void OnClosed()
1076
                {
1077
                        if (Closed != null)
1078
                                Closed(this, EventArgs.Empty);
1079
                }
1080
 
1081
 
1082
                private void OnMouseLeave()
1083
                {
1084
                        if (MouseLeave != null)
1085
                                MouseLeave(this, EventArgs.Empty);
1086
                }
1087
 
1088
                private void OnMouseEnter()
1089
                {
1090
                        if (MouseEnter != null)
1091
                                MouseEnter(this, EventArgs.Empty);
1092
                }
1093
 
1094
                private void OnActivate()
1095
                {
1096
                        mIsActive = true;
1097
                        if (FocusedChanged != null)
1098
                                FocusedChanged(this, EventArgs.Empty);
1099
                }
1100
                private void OnDeactivate()
1101
                {
1102
                        mIsActive = false;
1103
                        if (FocusedChanged != null)
1104
                                FocusedChanged(this, EventArgs.Empty);
1105
                }
1106
 
1107
                #endregion
1108
 
1109
                public event EventHandler<EventArgs> Idle;
1110
        public event EventHandler<EventArgs> Load;
1111
        public event EventHandler<EventArgs> Unload;
1112
        public event EventHandler<EventArgs> Move;
1113
        public event EventHandler<EventArgs> Resize;
1114
        public event EventHandler<CancelEventArgs> Closing;
1115
        public event EventHandler<EventArgs> Closed;
1116
        public event EventHandler<EventArgs> Disposed;
1117
        public event EventHandler<EventArgs> IconChanged;
1118
        public event EventHandler<EventArgs> TitleChanged;
1119
        public event EventHandler<EventArgs> ClientSizeChanged;
1120
        public event EventHandler<EventArgs> VisibleChanged;
1121
        public event EventHandler<EventArgs> WindowInfoChanged;
1122
        public event EventHandler<EventArgs> FocusedChanged;
1123
        public event EventHandler<EventArgs> WindowBorderChanged;
1124
        public event EventHandler<EventArgs> WindowStateChanged;
1125
        public event EventHandler<KeyPressEventArgs> KeyPress;
1126
        public event EventHandler<EventArgs> MouseEnter;
1127
        public event EventHandler<EventArgs> MouseLeave;
1128
 
1129
        #endregion
1130
    }
1131
}