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) {
#if DriverDebug || DriverDebugDestroy
Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
#endif
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) {
#if DriverDebugExtra
Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y);
#endif
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;
#if DriverDebugExtra
Console.WriteLine("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);
#endif
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
#if DriverDebugExtra
Console.WriteLine("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);
#endif
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;
}
SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
Keyboard.FocusIn (FocusWindow);
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;
}
}
#if DriverDebugExtra
Console.WriteLine("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);
#endif
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;
}
#if DriverDebugExtra
Console.WriteLine("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);
#endif
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);
#if DriverDebugDestroy
Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.client_window));
#endif
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;
}