void C_MouseDown(object sender, MouseEventArgs e) { ((Control)sender).Capture = false; ((Control)sender).Dispose(); Control parent = form; Point pt = e.Location; while (true) { Control child = parent.GetChildAtPoint(pt); if (child == null || parent is ToolStrip) { HELPINFO hi = new HELPINFO(); hi.cbSize = Marshal.SizeOf(hi); hi.iContextType = HELPINFO_WINDOW; hi.iCtrlId = GetDlgCtrlID(parent.Handle); hi.hItemHandle = parent.Handle; hi.dwContextId = GetWindowContextHelpId(parent.Handle); hi.x = pt.X; hi.y = pt.Y; IntPtr pv = Marshal.AllocCoTaskMem(Marshal.SizeOf(hi)); try { Marshal.StructureToPtr(hi, pv, false); SendMessage(parent.Handle, WM_HELP, IntPtr.Zero, pv); } finally { Marshal.FreeCoTaskMem(pv); } break; } else { pt -= new Size(child.Location); parent = child; continue; } } }
internal override bool GetMessage(Object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) { XEvent xevent; bool client; Hwnd hwnd; ProcessNextMessage: if (((XEventQueue)queue_id).Count > 0) { xevent = (XEvent) ((XEventQueue)queue_id).Dequeue (); } else { UpdateMessageQueue ((XEventQueue)queue_id); if (((XEventQueue)queue_id).Count > 0) { xevent = (XEvent) ((XEventQueue)queue_id).Dequeue (); } else if (((XEventQueue)queue_id).Paint.Count > 0) { xevent = ((XEventQueue)queue_id).Paint.Dequeue(); } else { msg.hwnd= IntPtr.Zero; msg.message = Msg.WM_ENTERIDLE; return true; } } hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); #if DriverDebugDestroy if (hwnd != null) if (hwnd.zombie) Console.WriteLine ( "GetMessage zombie, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32()); else Console.WriteLine ( "GetMessage, got Event: " + xevent.ToString () + " for 0x{0:x}", hwnd.Handle.ToInt32()); #endif // Handle messages for windows that are already or are about to be destroyed. // we need a special block for this because unless we remove the hwnd from the paint // queue it will always stay there (since we don't handle the expose), and we'll // effectively loop infinitely trying to repaint a non-existant window. if (hwnd != null && hwnd.zombie && xevent.type == XEventName.Expose) { hwnd.expose_pending = hwnd.nc_expose_pending = false; hwnd.Queue.Paint.Remove (hwnd); goto ProcessNextMessage; } // We need to make sure we only allow DestroyNotify events through for zombie // hwnds, since much of the event handling code makes requests using the hwnd's // client_window, and that'll result in BadWindow errors if there's some lag // between the XDestroyWindow call and the DestroyNotify event. if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) { DriverDebug("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32()); goto ProcessNextMessage; } // If we get here, that means the window is no more but there are Client Messages // to be processed, probably a Posted message (for instance, an WM_ACTIVATE message) // We don't want anything else to run but the ClientMessage block, so reset all hwnd // properties that might cause other processing to occur. if (hwnd.zombie) { hwnd.resizing_or_moving = false; } if (hwnd.client_window == xevent.AnyEvent.window) { client = true; //Console.WriteLine("Client message {1}, sending to window {0:X}", msg.hwnd.ToInt32(), xevent.type); } else { client = false; //Console.WriteLine("Non-Client message, sending to window {0:X}", msg.hwnd.ToInt32()); } msg.hwnd = hwnd.Handle; // Windows sends WM_ENTERSIZEMOVE when a form resize/move operation starts and WM_EXITSIZEMOVE // when it is done. The problem in X11 is that there is no concept of start-end of a moving/sizing. // Configure events ("this window has resized/moved") are sent for each step of the resize. We send a // WM_ENTERSIZEMOVE when we get the first Configure event. The problem is the WM_EXITSIZEMOVE. // // - There is no way for us to know which is the last Configure event. We can't traverse the events // queue, because the next configure event might not be pending yet. // - We can't get ButtonPress/Release events for the window decorations, because they are not part // of the window(s) we manage. // - We can't rely on the mouse state to change to "up" before the last Configure event. It doesn't. // // We are almost 100% guaranteed to get another event (e.g Expose or other), but we can't know for sure // which, so we have here to check if the mouse buttons state is "up" and send the WM_EXITSIZEMOVE // if (hwnd.resizing_or_moving) { int root_x, root_y, win_x, win_y, keys_buttons; IntPtr root, child; XQueryPointer (DisplayHandle, hwnd.Handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); if ((keys_buttons & (int)MouseKeyMasks.Button1Mask) == 0 && (keys_buttons & (int)MouseKeyMasks.Button2Mask) == 0 && (keys_buttons & (int)MouseKeyMasks.Button3Mask) == 0) { hwnd.resizing_or_moving = false; SendMessage (hwnd.Handle, Msg.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero); } } // // If you add a new event to this switch make sure to add it in // UpdateMessage also unless it is not coming through the X event system. // switch(xevent.type) { case XEventName.KeyPress: { Keyboard.KeyEvent (FocusWindow, xevent, ref msg); // F1 key special case - WM_HELP sending if (msg.wParam == (IntPtr)VirtualKeys.VK_F1 || msg.wParam == (IntPtr)VirtualKeys.VK_HELP) { // Send wM_HELP and then return it as a keypress message in // case it needs to be preproccessed. HELPINFO helpInfo = new HELPINFO (); GetCursorPos (IntPtr.Zero, out helpInfo.MousePos.x, out helpInfo.MousePos.y); IntPtr helpInfoPtr = Marshal.AllocHGlobal (Marshal.SizeOf (helpInfo)); Marshal.StructureToPtr (helpInfo, helpInfoPtr, true); NativeWindow.WndProc (FocusWindow, Msg.WM_HELP, IntPtr.Zero, helpInfoPtr); Marshal.FreeHGlobal (helpInfoPtr); } break; } case XEventName.KeyRelease: { Keyboard.KeyEvent (FocusWindow, xevent, ref msg); break; } case XEventName.ButtonPress: { switch(xevent.ButtonEvent.button) { case 1: { MouseState |= MouseButtons.Left; if (client) { msg.message = Msg.WM_LBUTTONDOWN; msg.wParam = GetMousewParam (0); } else { msg.message = Msg.WM_NCLBUTTONDOWN; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } break; } case 2: { MouseState |= MouseButtons.Middle; if (client) { msg.message = Msg.WM_MBUTTONDOWN; msg.wParam = GetMousewParam (0); } else { msg.message = Msg.WM_NCMBUTTONDOWN; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } break; } case 3: { MouseState |= MouseButtons.Right; if (client) { msg.message = Msg.WM_RBUTTONDOWN; msg.wParam = GetMousewParam (0); } else { msg.message = Msg.WM_NCRBUTTONDOWN; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } break; } case 4: { msg.hwnd = FocusWindow; msg.message=Msg.WM_MOUSEWHEEL; msg.wParam=GetMousewParam(120); break; } case 5: { msg.hwnd = FocusWindow; msg.message=Msg.WM_MOUSEWHEEL; msg.wParam=GetMousewParam(-120); break; } } msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); mouse_position.X = xevent.ButtonEvent.x; mouse_position.Y = xevent.ButtonEvent.y; if (!hwnd.Enabled) { IntPtr dummy; msg.hwnd = hwnd.EnabledHwnd; XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); } if (Grab.Hwnd != IntPtr.Zero) { msg.hwnd = Grab.Hwnd; } if (ClickPending.Pending && ((((long)xevent.ButtonEvent.time - ClickPending.Time) < DoubleClickInterval) && (msg.wParam == ClickPending.wParam) && (msg.lParam == ClickPending.lParam) && (msg.message == ClickPending.Message))) { // Looks like a genuine double click, clicked twice on the same spot with the same keys switch(xevent.ButtonEvent.button) { case 1: { msg.message = client ? Msg.WM_LBUTTONDBLCLK : Msg.WM_NCLBUTTONDBLCLK; break; } case 2: { msg.message = client ? Msg.WM_MBUTTONDBLCLK : Msg.WM_NCMBUTTONDBLCLK; break; } case 3: { msg.message = client ? Msg.WM_RBUTTONDBLCLK : Msg.WM_NCRBUTTONDBLCLK; break; } } ClickPending.Pending = false; } else { ClickPending.Pending = true; ClickPending.Hwnd = msg.hwnd; ClickPending.Message = msg.message; ClickPending.wParam = msg.wParam; ClickPending.lParam = msg.lParam; ClickPending.Time = (long)xevent.ButtonEvent.time; } if (msg.message == Msg.WM_LBUTTONDOWN || msg.message == Msg.WM_MBUTTONDOWN || msg.message == Msg.WM_RBUTTONDOWN) { SendParentNotify(msg.hwnd, msg.message, mouse_position.X, mouse_position.Y); } break; } case XEventName.ButtonRelease: { switch(xevent.ButtonEvent.button) { case 1: { if (client) { msg.message = Msg.WM_LBUTTONUP; } else { msg.message = Msg.WM_NCLBUTTONUP; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } MouseState &= ~MouseButtons.Left; msg.wParam = GetMousewParam (0); break; } case 2: { if (client) { msg.message = Msg.WM_MBUTTONUP; } else { msg.message = Msg.WM_NCMBUTTONUP; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } MouseState &= ~MouseButtons.Middle; msg.wParam = GetMousewParam (0); break; } case 3: { if (client) { msg.message = Msg.WM_RBUTTONUP; } else { msg.message = Msg.WM_NCRBUTTONUP; msg.wParam = (IntPtr) NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); MenuToScreen (xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } MouseState &= ~MouseButtons.Right; msg.wParam = GetMousewParam (0); break; } case 4: { goto ProcessNextMessage; } case 5: { goto ProcessNextMessage; } } if (!hwnd.Enabled) { IntPtr dummy; msg.hwnd = hwnd.EnabledHwnd; XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.ButtonEvent.x, xevent.ButtonEvent.y, out xevent.ButtonEvent.x, out xevent.ButtonEvent.y, out dummy); msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); } if (Grab.Hwnd != IntPtr.Zero) { msg.hwnd = Grab.Hwnd; } msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); mouse_position.X = xevent.ButtonEvent.x; mouse_position.Y = xevent.ButtonEvent.y; // Win32 splurts MouseMove events all over the place, regardless of whether the mouse is actually moving or // not, especially after mousedown and mouseup. To support apps relying on mousemove events between and after // mouse clicks to repaint or whatever, we generate a mousemove event here. *sigh* if (msg.message == Msg.WM_LBUTTONUP || msg.message == Msg.WM_MBUTTONUP || msg.message == Msg.WM_RBUTTONUP) { XEvent motionEvent = new XEvent (); motionEvent.type = XEventName.MotionNotify; motionEvent.MotionEvent.display = DisplayHandle; motionEvent.MotionEvent.window = xevent.ButtonEvent.window; motionEvent.MotionEvent.x = xevent.ButtonEvent.x; motionEvent.MotionEvent.y = xevent.ButtonEvent.y; hwnd.Queue.EnqueueLocked (motionEvent); } break; } case XEventName.MotionNotify: { if (client) { DriverDebug("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); if (Grab.Hwnd != IntPtr.Zero) { msg.hwnd = Grab.Hwnd; } else { if (hwnd.Enabled) { NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); } } if (xevent.MotionEvent.is_hint != 0) { IntPtr root, child; int mask; XQueryPointer (DisplayHandle, xevent.AnyEvent.window, out root, out child, out xevent.MotionEvent.x_root, out xevent.MotionEvent.y_root, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out mask); } msg.message = Msg.WM_MOUSEMOVE; msg.wParam = GetMousewParam(0); msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); if (!hwnd.Enabled) { IntPtr dummy; msg.hwnd = hwnd.EnabledHwnd; XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); } mouse_position.X = xevent.MotionEvent.x; mouse_position.Y = xevent.MotionEvent.y; if ((HoverState.Timer.Enabled) && (((mouse_position.X + HoverState.Size.Width) < HoverState.X) || ((mouse_position.X - HoverState.Size.Width) > HoverState.X) || ((mouse_position.Y + HoverState.Size.Height) < HoverState.Y) || ((mouse_position.Y - HoverState.Size.Height) > HoverState.Y))) { HoverState.Timer.Stop(); HoverState.Timer.Start(); HoverState.X = mouse_position.X; HoverState.Y = mouse_position.Y; } break; } else { HitTest ht; IntPtr dummy; DriverDebug("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); msg.message = Msg.WM_NCMOUSEMOVE; if (!hwnd.Enabled) { msg.hwnd = hwnd.EnabledHwnd; XTranslateCoordinates(DisplayHandle, xevent.AnyEvent.window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, xevent.MotionEvent.x, xevent.MotionEvent.y, out xevent.MotionEvent.x, out xevent.MotionEvent.y, out dummy); msg.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X); } ht = NCHitTest (hwnd, xevent.MotionEvent.x, xevent.MotionEvent.y); NativeWindow.WndProc(hwnd.client_window, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht); mouse_position.X = xevent.MotionEvent.x; mouse_position.Y = xevent.MotionEvent.y; } break; } case XEventName.EnterNotify: { if (!hwnd.Enabled) { goto ProcessNextMessage; } if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || xevent.AnyEvent.window != hwnd.client_window) { goto ProcessNextMessage; } if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { // Pseudo motion caused by grabbing if (LastPointerWindow == xevent.AnyEvent.window) goto ProcessNextMessage; if (LastPointerWindow != IntPtr.Zero) { Point enter_loc = new Point (xevent.ButtonEvent.x, xevent.ButtonEvent.y); // We need this due to EnterNotify being fired on all the parent controls // of the Control being grabbed, and obviously in that scenario we are not // actuallty entering them Control ctrl = Control.FromHandle (hwnd.client_window); foreach (Control child_control in ctrl.Controls.GetAllControls ()) if (child_control.Bounds.Contains (enter_loc)) goto ProcessNextMessage; // A MouseLeave/LeaveNotify event is sent to the previous window // until the mouse is ungrabbed, not when actually leaving its bounds int x = xevent.CrossingEvent.x_root; int y = xevent.CrossingEvent.y_root; ScreenToClient (LastPointerWindow, ref x, ref y); XEvent leaveEvent = new XEvent (); leaveEvent.type = XEventName.LeaveNotify; leaveEvent.CrossingEvent.display = DisplayHandle; leaveEvent.CrossingEvent.window = LastPointerWindow; leaveEvent.CrossingEvent.x = x; leaveEvent.CrossingEvent.y = y; leaveEvent.CrossingEvent.mode = NotifyMode.NotifyNormal; Hwnd last_pointer_hwnd = Hwnd.ObjectFromHandle (LastPointerWindow); last_pointer_hwnd.Queue.EnqueueLocked (leaveEvent); } } LastPointerWindow = xevent.AnyEvent.window; msg.message = Msg.WM_MOUSE_ENTER; HoverState.X = xevent.CrossingEvent.x; HoverState.Y = xevent.CrossingEvent.y; HoverState.Timer.Enabled = true; HoverState.Window = xevent.CrossingEvent.window; // Win32 sends a WM_MOUSEMOVE after mouse enter XEvent motionEvent = new XEvent (); motionEvent.type = XEventName.MotionNotify; motionEvent.MotionEvent.display = DisplayHandle; motionEvent.MotionEvent.window = xevent.ButtonEvent.window; motionEvent.MotionEvent.x = xevent.ButtonEvent.x; motionEvent.MotionEvent.y = xevent.ButtonEvent.y; hwnd.Queue.EnqueueLocked (motionEvent); break; } case XEventName.LeaveNotify: { if (xevent.CrossingEvent.mode == NotifyMode.NotifyUngrab) { WindowUngrabbed (hwnd.Handle); goto ProcessNextMessage; } if (!hwnd.Enabled) { goto ProcessNextMessage; } if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) { goto ProcessNextMessage; } // If a grab is taking place, ignore it - we handle it in EnterNotify if (Grab.Hwnd != IntPtr.Zero) goto ProcessNextMessage; // Reset the cursor explicitly on X11. // X11 remembers the last set cursor for the window and in cases where // the control won't get a WM_SETCURSOR X11 will restore the last // known cursor, which we don't want. // SetCursor (hwnd.client_window, IntPtr.Zero); msg.message=Msg.WM_MOUSELEAVE; HoverState.Timer.Enabled = false; HoverState.Window = IntPtr.Zero; break; } #if later case XEventName.CreateNotify: { if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { msg.message = WM_CREATE; // Set up CreateStruct } else { goto ProcessNextMessage; } break; } #endif case XEventName.ReparentNotify: { if (hwnd.parent == null) { // Toplevel if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) { hwnd.Reparented = true; // The location given by the event is not reliable between different wm's, // so use an alternative way of getting it. Point location = GetTopLevelWindowLocation (hwnd); hwnd.X = location.X; hwnd.Y = location.Y; if (hwnd.opacity != 0xffffffff) { IntPtr opacity; opacity = (IntPtr)(Int32)hwnd.opacity; XChangeProperty(DisplayHandle, XGetParent(hwnd.whole_window), _NET_WM_WINDOW_OPACITY, (IntPtr)Atom.XA_CARDINAL, 32, PropertyMode.Replace, ref opacity, 1); } SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, msg.wParam, msg.lParam); goto ProcessNextMessage; } else { hwnd.Reparented = false; goto ProcessNextMessage; } } goto ProcessNextMessage; } case XEventName.ConfigureNotify: { if (!client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas DriverDebug("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); lock (hwnd.configure_lock) { Form form = Control.FromHandle (hwnd.client_window) as Form; if (form != null && !hwnd.resizing_or_moving) { if (hwnd.x != form.Bounds.X || hwnd.y != form.Bounds.Y) { SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_MOVE, IntPtr.Zero); hwnd.resizing_or_moving = true; } else if (hwnd.width != form.Bounds.Width || hwnd.height != form.Bounds.Height) { SendMessage (form.Handle, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_SIZE, IntPtr.Zero); hwnd.resizing_or_moving = true; } if (hwnd.resizing_or_moving) SendMessage (form.Handle, Msg.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero); } SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); hwnd.configure_pending = false; // We need to adjust our client window to track the resize of whole_window if (hwnd.whole_window != hwnd.client_window) PerformNCCalc(hwnd); } } goto ProcessNextMessage; } case XEventName.FocusIn: { // We received focus. We use X11 focus only to know if the app window does or does not have focus // We do not track the actual focussed window via it. Instead, this is done via FocusWindow internally // Receiving focus means we've gotten activated and therefore we need to let the actual FocusWindow know // about it having focus again if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) { goto ProcessNextMessage; } if (FocusWindow == IntPtr.Zero) { Control c = Control.FromHandle (hwnd.client_window); if (c == null) goto ProcessNextMessage; Form form = c.FindForm (); if (form == null) goto ProcessNextMessage; if (ActiveWindow != form.Handle) { ActiveWindow = form.Handle; SendMessage (ActiveWindow, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); } goto ProcessNextMessage; } Keyboard.FocusIn (FocusWindow); SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero); goto ProcessNextMessage; } case XEventName.FocusOut: { // Se the comment for our FocusIn handler if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) { goto ProcessNextMessage; } while (Keyboard.ResetKeyState(FocusWindow, ref msg)) { SendMessage(FocusWindow, msg.message, msg.wParam, msg.lParam); } Keyboard.FocusOut(hwnd.client_window); SendMessage(FocusWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); goto ProcessNextMessage; } // We are already firing WM_SHOWWINDOW messages in the proper places, but I'm leaving this code // in case we break a scenario not taken into account in the tests case XEventName.MapNotify: { /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas hwnd.mapped = true; msg.message = Msg.WM_SHOWWINDOW; msg.wParam = (IntPtr) 1; // XXX we're missing the lParam.. break; }*/ goto ProcessNextMessage; } case XEventName.UnmapNotify: { /*if (client && (xevent.ConfigureEvent.xevent == xevent.ConfigureEvent.window)) { // Ignore events for children (SubstructureNotify) and client areas hwnd.mapped = false; msg.message = Msg.WM_SHOWWINDOW; msg.wParam = (IntPtr) 0; // XXX we're missing the lParam.. break; }*/ goto ProcessNextMessage; } case XEventName.Expose: { if (!hwnd.Mapped) { if (client) { hwnd.expose_pending = false; } else { hwnd.nc_expose_pending = false; } goto ProcessNextMessage; } if (client) { if (!hwnd.expose_pending) { goto ProcessNextMessage; } } else { if (!hwnd.nc_expose_pending) { goto ProcessNextMessage; } switch (hwnd.border_style) { case FormBorderStyle.Fixed3D: { Graphics g; g = Graphics.FromHwnd(hwnd.whole_window); if (hwnd.border_static) ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.SunkenOuter); else ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken); g.Dispose(); break; } case FormBorderStyle.FixedSingle: { Graphics g; g = Graphics.FromHwnd(hwnd.whole_window); ControlPaint.DrawBorder(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Color.Black, ButtonBorderStyle.Solid); g.Dispose(); break; } } DriverDebug("GetMessage(): Window {0:X} Exposed non-client area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); Rectangle rect = new Rectangle (xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); Region region = new Region (rect); IntPtr hrgn = region.GetHrgn (null); // Graphics object isn't needed msg.message = Msg.WM_NCPAINT; msg.wParam = hrgn == IntPtr.Zero ? (IntPtr)1 : hrgn; msg.refobject = region; break; } DriverDebug("GetMessage(): Window {0:X} Exposed area {1},{2} {3}x{4}", hwnd.client_window.ToInt32(), xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); if (Caret.Visible == true) { Caret.Paused = true; HideCaret(); } if (Caret.Visible == true) { ShowCaret(); Caret.Paused = false; } msg.message = Msg.WM_PAINT; break; } case XEventName.DestroyNotify: { // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children hwnd = Hwnd.ObjectFromHandle(xevent.DestroyWindowEvent.window); // We may get multiple for the same window, act only one the first (when Hwnd still knows about it) if ((hwnd != null) && (hwnd.client_window == xevent.DestroyWindowEvent.window)) { CleanupCachedWindows (hwnd); DriverDebug("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window)); msg.hwnd = hwnd.client_window; msg.message=Msg.WM_DESTROY; hwnd.Dispose(); } else { goto ProcessNextMessage; } break; } case XEventName.ClientMessage: { if (Dnd.HandleClientMessage (ref xevent)) { goto ProcessNextMessage; } if (xevent.ClientMessageEvent.message_type == AsyncAtom) { XplatUIDriverSupport.ExecuteClientMessage((GCHandle)xevent.ClientMessageEvent.ptr1); goto ProcessNextMessage; } if (xevent.ClientMessageEvent.message_type == HoverState.Atom) { msg.message = Msg.WM_MOUSEHOVER; msg.wParam = GetMousewParam(0); msg.lParam = (IntPtr) (xevent.ClientMessageEvent.ptr1); return true; } if (xevent.ClientMessageEvent.message_type == (IntPtr)PostAtom) { DebugHelper.Indent (); DebugHelper.WriteLine (String.Format ("Posted message:" + (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 () + " for 0x{0:x}", xevent.ClientMessageEvent.ptr1.ToInt32 ())); DebugHelper.Unindent (); msg.hwnd = xevent.ClientMessageEvent.ptr1; msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); msg.wParam = xevent.ClientMessageEvent.ptr3; msg.lParam = xevent.ClientMessageEvent.ptr4; if (msg.message == (Msg)Msg.WM_QUIT) return false; else return true; } if (xevent.ClientMessageEvent.message_type == _XEMBED) { #if DriverDebugXEmbed Console.WriteLine("GOT EMBED MESSAGE {0:X}, detail {1:X}", xevent.ClientMessageEvent.ptr2.ToInt32(), xevent.ClientMessageEvent.ptr3.ToInt32()); #endif if (xevent.ClientMessageEvent.ptr2.ToInt32() == (int)XEmbedMessage.EmbeddedNotify) { XSizeHints hints = new XSizeHints(); IntPtr dummy; XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy); hwnd.width = hints.max_width; hwnd.height = hints.max_height; hwnd.ClientRect = Rectangle.Empty; SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); } } if (xevent.ClientMessageEvent.message_type == WM_PROTOCOLS) { if (xevent.ClientMessageEvent.ptr1 == WM_DELETE_WINDOW) { SendMessage (msg.hwnd, Msg.WM_SYSCOMMAND, (IntPtr)SystemCommands.SC_CLOSE, IntPtr.Zero); msg.message = Msg.WM_CLOSE; return true; } // We should not get this, but I'll leave the code in case we need it in the future if (xevent.ClientMessageEvent.ptr1 == WM_TAKE_FOCUS) { goto ProcessNextMessage; } } goto ProcessNextMessage; } default: { goto ProcessNextMessage; } } return true; }
private void ShowHelpInControl (SWF.Control ctrl) { MethodInfo methodInfo = ctrl.GetType ().GetMethod ("WndProc", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance); HELPINFO info = new HELPINFO (); SD.Rectangle rectangle = ctrl.TopLevelControl.RectangleToScreen (ctrl.Bounds); info.MousePos = new POINT (rectangle.X + 5, rectangle.Y + 5); IntPtr ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (HELPINFO))); Marshal.StructureToPtr (info, ptr, false); SWF.Message message = SWF.Message.Create (ctrl.Handle, (int) Msg.WM_HELP, IntPtr.Zero, ptr); methodInfo.Invoke (ctrl, new object[] { message }); }
private void WmHelp (ref Message m) { Point mouse_pos; if (m.LParam != IntPtr.Zero) { HELPINFO hi; hi = new HELPINFO(); hi = (HELPINFO) Marshal.PtrToStructure (m.LParam, typeof (HELPINFO)); mouse_pos = new Point(hi.MousePos.x, hi.MousePos.y); } else { mouse_pos = Control.MousePosition; } OnHelpRequested(new HelpEventArgs(mouse_pos)); m.Result = (IntPtr)1; }