In .:
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms.CarbonInternal / MouseHandler.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2007 Novell, Inc.
21 //
22 // Authors:
23 //      Geoff Norton  <gnorton@novell.com>
24 //
25 //
26
27 using System;
28 using System.Runtime.InteropServices;
29
30 namespace System.Windows.Forms.CarbonInternal {
31         internal class MouseHandler : EventHandlerBase, IEventHandler {
32                 internal const uint kEventMouseDown = 1;
33                 internal const uint kEventMouseUp = 2;
34                 internal const uint kEventMouseMoved = 5;
35                 internal const uint kEventMouseDragged = 6;
36                 internal const uint kEventMouseEntered = 8;
37                 internal const uint kEventMouseExited = 9;
38                 internal const uint kEventMouseWheelMoved = 10;
39
40                 internal const uint kEventParamMouseLocation = 1835822947;
41                 internal const uint kEventParamMouseButton = 1835168878;
42                 internal const uint typeMouseButton = 1835168878;
43                 internal const uint typeQDPoint = 1363439732;
44
45                 internal const uint DoubleClickInterval = 7500000;
46                 internal static ClickStruct ClickPending;
47                 
48                 internal MouseHandler (XplatUICarbon driver) : base (driver) {}
49
50                 public bool ProcessEvent (IntPtr callref, IntPtr eventref, IntPtr handle, uint kind, ref MSG msg) {
51                         QDPoint qdpoint = new QDPoint ();
52                         CGPoint point = new CGPoint ();
53                         Rect window_bounds = new Rect ();
54                         IntPtr view_handle = IntPtr.Zero;
55                         IntPtr window_handle = IntPtr.Zero;
56                         bool client = true;
57                         ushort button = 0;
58                         Hwnd hwnd;
59
60                         GetEventParameter (eventref, kEventParamMouseLocation, typeQDPoint, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (QDPoint)), IntPtr.Zero, ref qdpoint);
61                         GetEventParameter (eventref, kEventParamMouseButton, typeMouseButton, IntPtr.Zero, (uint)Marshal.SizeOf (typeof (ushort)), IntPtr.Zero, ref button);
62                         
63                         if (button == 1 && ((Driver.ModifierKeys & Keys.Control) != 0))
64                                 button = 2;
65
66
67                         point.x = qdpoint.x;
68                         point.y = qdpoint.y;
69
70                         GetWindowBounds (handle, 33, ref window_bounds);
71                         HIViewFindByID (HIViewGetRoot (handle), new HIViewID (EventHandler.kEventClassWindow, 1), ref window_handle);
72
73                         point.x -= window_bounds.left;
74                         point.y -= window_bounds.top;
75
76                         HIViewGetSubviewHit (window_handle, ref point, true, ref view_handle);
77                         HIViewConvertPoint (ref point, window_handle, view_handle);
78
79                         hwnd = Hwnd.ObjectFromHandle (view_handle);
80
81                         if (hwnd != null)
82                                 client = (hwnd.ClientWindow == view_handle ? true : false);
83
84                         if (XplatUICarbon.Grab.Hwnd != IntPtr.Zero) {
85                                 hwnd = Hwnd.ObjectFromHandle (XplatUICarbon.Grab.Hwnd); 
86                                 client = true;
87                         }
88                         if (hwnd == null)
89                                 return true;
90                         
91                         if (client) {
92                                 qdpoint.x = (short) point.x;
93                                 qdpoint.y = (short) point.y;
94
95                                 Driver.ScreenToClient (hwnd.Handle, ref qdpoint);
96                         } else {
97                                 point.x = qdpoint.x;
98                                 point.y = qdpoint.y;
99                         }
100
101                         msg.hwnd = hwnd.Handle;
102                         msg.lParam = (IntPtr) ((ushort) point.y << 16 | (ushort) point.x);
103
104                         switch (kind) {
105                                 case kEventMouseDown:
106                                         msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 1;
107                                         msg.wParam = ButtonTowParam (button);
108                                         if (ClickPending.Pending && (((DateTime.Now.Ticks - ClickPending.Time) < DoubleClickInterval) && (msg.hwnd == ClickPending.Hwnd) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) {
109                                                 msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((button - 1) * 3) + 3;
110                                                 ClickPending.Pending = false;
111                                         } else {
112                                                 ClickPending.Pending = true;
113                                                 ClickPending.Hwnd = msg.hwnd;
114                                                 ClickPending.Message = msg.message;
115                                                 ClickPending.wParam = msg.wParam;
116                                                 ClickPending.lParam = msg.lParam;
117                                                 ClickPending.Time = DateTime.Now.Ticks;
118                                         }
119                                         break;
120                                 case kEventMouseUp:
121                                         msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE) + ((StateToButton (XplatUICarbon.MouseState) - 1) * 3) + 2;
122                                         msg.wParam = StateTowParam (XplatUICarbon.MouseState);
123                                         break;
124                                 case kEventMouseDragged:
125                                 case kEventMouseMoved:
126                                         msg.message = (client ? Msg.WM_MOUSEMOVE : Msg.WM_NCMOUSEMOVE);
127                                         msg.wParam = Driver.GetMousewParam (0);
128                                         break;
129                                 default:
130                                         return false;
131                         }
132                         Driver.mouse_position.X = (int) point.x;
133                         Driver.mouse_position.Y = (int) point.y;
134                         return true;
135                 }
136                 
137                 internal bool TranslateMessage (ref MSG msg) {
138                         if (msg.message == Msg.WM_MOUSEMOVE || msg.message == Msg.WM_NCMOUSEMOVE) {
139                                 Hwnd hwnd = Hwnd.ObjectFromHandle (msg.hwnd);
140                                 if (XplatUICarbon.MouseHwnd == null) 
141                                         Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
142                                 else if (XplatUICarbon.MouseHwnd.Handle != hwnd.Handle) {
143                                         Driver.PostMessage (XplatUICarbon.MouseHwnd.Handle, Msg.WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
144                                         Driver.PostMessage (hwnd.Handle, Msg.WM_MOUSE_ENTER, IntPtr.Zero, IntPtr.Zero);
145                                 }
146                                 XplatUICarbon.MouseHwnd = hwnd;
147                         }
148                         
149                         return false;
150                 }
151
152                 private int StateToButton (MouseButtons state) {
153                         int button = 0;
154
155                         switch (state) {
156                                 case MouseButtons.Left: 
157                                         button = 1;
158                                         break;
159                                 case MouseButtons.Right: 
160                                         button = 2;
161                                         break;
162                                 case MouseButtons.Middle:
163                                         button = 3;
164                                         break;
165                         }
166                         
167                         return button;
168                 }
169
170                 private IntPtr StateTowParam (MouseButtons state) {
171                         int wparam = (int) Driver.GetMousewParam (0);
172
173                         switch (state) {
174                                 case MouseButtons.Left: 
175                                         XplatUICarbon.MouseState &= ~MouseButtons.Left;
176                                         wparam &= (int)MsgButtons.MK_LBUTTON;
177                                         break;
178                                 case MouseButtons.Right: 
179                                         XplatUICarbon.MouseState &= ~MouseButtons.Right;
180                                         wparam &= (int)MsgButtons.MK_RBUTTON;
181                                         break;
182                                 case MouseButtons.Middle:
183                                         XplatUICarbon.MouseState &= ~MouseButtons.Middle;
184                                         wparam &= (int)MsgButtons.MK_MBUTTON;
185                                         break;
186                         }
187                         
188                         return (IntPtr) wparam;
189                 }
190
191                 private IntPtr ButtonTowParam (ushort button) {
192                         int wparam = (int) Driver.GetMousewParam (0);
193
194                         switch (button) {
195                                 case 1:
196                                         XplatUICarbon.MouseState |= MouseButtons.Left;
197                                         wparam |= (int)MsgButtons.MK_LBUTTON;
198                                         break;
199                                 case 2:
200                                         XplatUICarbon.MouseState |= MouseButtons.Right;
201                                         wparam |= (int)MsgButtons.MK_RBUTTON;
202                                         break;
203                                 case 3:
204                                         XplatUICarbon.MouseState |= MouseButtons.Middle;
205                                         wparam |= (int)MsgButtons.MK_MBUTTON;
206                                         break;
207                         }
208                         
209                         return (IntPtr) wparam;
210                 }
211
212
213                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
214                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref QDPoint data);
215                 [DllImport ("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
216                 static extern int GetEventParameter (IntPtr eventref, uint name, uint type, IntPtr outtype, uint size, IntPtr outsize, ref ushort data);
217
218                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
219                 internal static extern int GetWindowBounds (IntPtr handle, uint region, ref Rect bounds);
220                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
221                 internal static extern int HIViewConvertPoint (ref CGPoint point, IntPtr source_view, IntPtr target_view);
222                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
223                 internal static extern IntPtr HIViewGetRoot (IntPtr handle);
224                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
225                 internal static extern int HIViewGetSubviewHit (IntPtr content_view, ref CGPoint point, bool tval, ref IntPtr hit_view);
226                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
227                 internal static extern int HIViewFindByID (IntPtr root_window, HIViewID id, ref IntPtr view_handle);
228                 
229                 [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
230                 internal static extern int GetCurrentEventButtonState ();
231         }
232 }