public override void PropertyChanged (XEvent xevent) { if (xevent.PropertyEvent.atom == Display.Atoms._NET_ACTIVE_WINDOW) { IntPtr actual_atom; int actual_format; IntPtr nitems; IntPtr bytes_after; IntPtr prop = IntPtr.Zero; Xlib.XGetWindowProperty (Display.Handle, WholeWindow, Display.Atoms._NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, Display.Atoms.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); if (((long)nitems > 0) && (prop != IntPtr.Zero)) { // FIXME - is this 64 bit clean? Display.SetActiveWindow ((X11Hwnd)Hwnd.ObjectFromHandle((IntPtr)Marshal.ReadInt32(prop))); Xlib.XFree(prop); } } else if (xevent.PropertyEvent.atom == Display.Atoms._NET_SUPPORTED) { // we'll need to refetch the supported protocols list refetch_net_supported = true; _net_supported = null; } else base.PropertyChanged (xevent); }
public void Enqueue (XEvent xevent) { if (Thread.CurrentThread != thread) { Console.WriteLine ("Hwnd.Queue.Enqueue called from a different thread without locking."); Console.WriteLine (Environment.StackTrace); } xqueue.Enqueue (xevent); }
internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) { XEvent xev; xev = new XEvent(); xev.ClientMessageEvent.type = XEventName.ClientMessage; xev.ClientMessageEvent.send_event = true; xev.ClientMessageEvent.window = window; xev.ClientMessageEvent.message_type = message_type; xev.ClientMessageEvent.format = 32; xev.ClientMessageEvent.ptr1 = l0; xev.ClientMessageEvent.ptr2 = l1; xev.ClientMessageEvent.ptr3 = l2; XSendEvent(DisplayHandle, window, false, new IntPtr ((int)EventMask.NoEventMask), ref xev); }
void SendNetWMMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2, IntPtr l3) { XEvent xev; xev = new XEvent(); xev.ClientMessageEvent.type = XEventName.ClientMessage; xev.ClientMessageEvent.send_event = true; xev.ClientMessageEvent.window = window; xev.ClientMessageEvent.message_type = message_type; xev.ClientMessageEvent.format = 32; xev.ClientMessageEvent.ptr1 = l0; xev.ClientMessageEvent.ptr2 = l1; xev.ClientMessageEvent.ptr3 = l2; xev.ClientMessageEvent.ptr4 = l3; XSendEvent(DisplayHandle, RootWindow, false, new IntPtr ((int) (EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask)), ref xev); }
internal static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg) { DebugHelper.TraceWriteLine ("XIfEvent"); _XIfEvent (display, ref xevent, event_predicate, arg); }
internal static bool XFilterEvent(ref XEvent xevent, IntPtr window) { DebugHelper.TraceWriteLine ("XFilterEvent"); return _XFilterEvent(ref xevent, window); }
internal static IntPtr XNextEvent(IntPtr display, ref XEvent xevent) { DebugHelper.TraceWriteLine ("XNextEvent"); return _XNextEvent(display, ref xevent); }
void AddConfigureNotify (XEvent xevent) { Hwnd hwnd; hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window); // Don't waste time if (hwnd == null || hwnd.zombie) { return; } if ((xevent.ConfigureEvent.window == hwnd.whole_window)/* && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)*/) { if (hwnd.parent == null) { // 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; } // XXX this sucks. this isn't thread safe Control ctrl = Control.FromHandle (hwnd.Handle); Size TranslatedSize; if (ctrl != null) { TranslatedSize = TranslateXWindowSizeToWindowSize (ctrl.GetCreateParams (), xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); } else { TranslatedSize = new Size (xevent.ConfigureEvent.width, xevent.ConfigureEvent.height); } hwnd.width = TranslatedSize.Width; hwnd.height = TranslatedSize.Height; hwnd.ClientRect = Rectangle.Empty; DriverDebug ("AddConfigureNotify (hwnd.Handle = {1}, final hwnd.rect = {0}, reported rect={2})", new Rectangle (hwnd.x, hwnd.y, hwnd.width, hwnd.height), hwnd.Handle, new Rectangle (xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.width)); lock (hwnd.configure_lock) { if (!hwnd.configure_pending) { hwnd.Queue.EnqueueLocked (xevent); hwnd.configure_pending = true; } } } // We drop configure events for Client windows }
private bool HandleFinishedEvent (ref XEvent xevent) { return true; }
private bool HandleStatusEvent (ref XEvent xevent) { if (drag_data != null && drag_data.State == DragState.Entered) { if (!QueryContinue (false, DragAction.Continue)) return true; drag_data.WillAccept = ((int) xevent.ClientMessageEvent.ptr2 & 0x1) != 0; GiveFeedback (xevent.ClientMessageEvent.ptr5); } return true; }
private bool Accepting_HandleLeaveEvent (ref XEvent xevent) { if (control != null && drag_event != null) control.DndLeave (drag_event); // Reset (); return true; }
private bool Accepting_HandleDropEvent (ref XEvent xevent) { if (control != null && drag_event != null) { drag_event = new DragEventArgs (data, 0, pos_x, pos_y, allowed, drag_event.Effect); control.DndDrop (drag_event); } SendFinished (); return true; }
private bool Accepting_HandlePositionEvent (ref XEvent xevent) { pos_x = (int) xevent.ClientMessageEvent.ptr3 >> 16; pos_y = (int) xevent.ClientMessageEvent.ptr3 & 0xFFFF; // Copy is implicitly allowed Control source_control = MwfWindow (source); if (source_control == null) allowed = EffectsFromX11Source (source, xevent.ClientMessageEvent.ptr5) | DragDropEffects.Copy; else allowed = drag_data.AllowedEffects; IntPtr parent, child, new_child, last_drop_child; parent = XplatUIX11.XRootWindow (display, 0); child = toplevel; last_drop_child = IntPtr.Zero; while (true) { int xd, yd; new_child = IntPtr.Zero; if (!XplatUIX11.XTranslateCoordinates (display, parent, child, pos_x, pos_y, out xd, out yd, out new_child)) break; if (new_child == IntPtr.Zero) break; child = new_child; Hwnd h = Hwnd.ObjectFromHandle (child); if (h != null) { Control d = Control.FromHandle (h.client_window); if (d != null && d.allow_drop) last_drop_child = child; } } if (last_drop_child != IntPtr.Zero) child = last_drop_child; if (target != child) { // We have moved into a new control // or into a control for the first time Finish (); } target = child; Hwnd hwnd = Hwnd.ObjectFromHandle (target); if (hwnd == null) return true; Control c = Control.FromHandle (hwnd.client_window); if (c == null) return true; if (!c.allow_drop) { SendStatus (source, DragDropEffects.None); Finish (); return true; } control = c; position_recieved = true; if (converts_pending > 0) return true; if (!status_sent) { drag_event = new DragEventArgs (data, 0, pos_x, pos_y, allowed, DragDropEffects.None); control.DndEnter (drag_event); SendStatus (source, drag_event.Effect); status_sent = true; } else { drag_event.x = pos_x; drag_event.y = pos_y; control.DndOver (drag_event); SendStatus (source, drag_event.Effect); } return true; }
private bool Accepting_HandleEnterEvent (ref XEvent xevent) { Reset (); source = xevent.ClientMessageEvent.ptr1; toplevel = xevent.AnyEvent.window; target = IntPtr.Zero; ConvertData (ref xevent); return true; }
internal override int SendInput(IntPtr handle, Queue keys) { if (handle == IntPtr.Zero) return 0; int count = keys.Count; Hwnd hwnd = Hwnd.ObjectFromHandle(handle); while (keys.Count > 0) { MSG msg = (MSG)keys.Dequeue(); XEvent xevent = new XEvent (); xevent.type = (msg.message == Msg.WM_KEYUP ? XEventName.KeyRelease : XEventName.KeyPress); xevent.KeyEvent.display = DisplayHandle; if (hwnd != null) { xevent.KeyEvent.window = hwnd.whole_window; } else { xevent.KeyEvent.window = IntPtr.Zero; } xevent.KeyEvent.keycode = Keyboard.ToKeycode((int)msg.wParam); hwnd.Queue.EnqueueLocked (xevent); } return count; }
internal override void SetCursorPos(IntPtr handle, int x, int y) { if (handle == IntPtr.Zero) { lock (XlibLock) { IntPtr root, child; int root_x, root_y, child_x, child_y, mask; /* we need to do a * QueryPointer before warping * because if the warp is on * the RootWindow, the x/y are * relative to the current * mouse position */ QueryPointer (DisplayHandle, RootWindow, out root, out child, out root_x, out root_y, out child_x, out child_y, out mask); XWarpPointer(DisplayHandle, IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, x - root_x, y - root_y); XFlush (DisplayHandle); /* then we need to a * QueryPointer after warping * to manually generate a * motion event for the window * we move into. */ QueryPointer (DisplayHandle, RootWindow, out root, out child, out root_x, out root_y, out child_x, out child_y, out mask); Hwnd child_hwnd = Hwnd.ObjectFromHandle(child); if (child_hwnd == null) { return; } XEvent xevent = new XEvent (); xevent.type = XEventName.MotionNotify; xevent.MotionEvent.display = DisplayHandle; xevent.MotionEvent.window = child_hwnd.client_window; xevent.MotionEvent.root = RootWindow; xevent.MotionEvent.x = child_x; xevent.MotionEvent.y = child_y; xevent.MotionEvent.x_root = root_x; xevent.MotionEvent.y_root = root_y; xevent.MotionEvent.state = mask; child_hwnd.Queue.EnqueueLocked (xevent); } } else { Hwnd hwnd; hwnd = Hwnd.ObjectFromHandle(handle); lock (XlibLock) { XWarpPointer(DisplayHandle, IntPtr.Zero, hwnd.client_window, 0, 0, 0, 0, x, y); } } }
void UpdateMessageQueue (XEventQueue queue, bool allowIdle) { DateTime now; int pending; Hwnd hwnd; now = DateTime.UtcNow; lock (XlibLock) { pending = XPending (DisplayHandle); } if (pending == 0 && allowIdle) { if ((queue == null || queue.DispatchIdle) && Idle != null) { Idle (this, EventArgs.Empty); } lock (XlibLock) { pending = XPending (DisplayHandle); } } if (pending == 0) { int timeout = 0; if (queue != null) { if (queue.Paint.Count > 0) return; timeout = NextTimeout (queue.timer_list, now); } if (timeout > 0) { #if __MonoCS__ int length = pollfds.Length - 1; lock (wake_waiting_lock) { if (wake_waiting == false) { length ++; wake_waiting = true; } } Syscall.poll (pollfds, (uint)length, timeout); // Clean out buffer, so we're not busy-looping on the same data if (length == pollfds.Length) { if (pollfds[1].revents != 0) wake_receive.Receive(network_buffer, 0, 1, SocketFlags.None); lock (wake_waiting_lock) { wake_waiting = false; } } #endif lock (XlibLock) { pending = XPending (DisplayHandle); } } } if (queue != null) CheckTimers (queue.timer_list, now); while (true) { XEvent xevent = new XEvent (); lock (XlibLock) { if (XPending (DisplayHandle) == 0) break; XNextEvent (DisplayHandle, ref xevent); if (xevent.AnyEvent.type == XEventName.KeyPress || xevent.AnyEvent.type == XEventName.KeyRelease) { // PreFilter() handles "shift key state updates. Keyboard.PreFilter (xevent); if (XFilterEvent (ref xevent, Keyboard.ClientWindow)) { // probably here we could raise WM_IME_KEYDOWN and // WM_IME_KEYUP, but I'm not sure it is worthy. continue; } } else if (XFilterEvent (ref xevent, IntPtr.Zero)) continue; } hwnd = Hwnd.GetObjectFromWindow(xevent.AnyEvent.window); if (hwnd == null) continue; DebugHelper.WriteLine ("UpdateMessageQueue got Event: " + xevent.ToString ()); switch (xevent.type) { case XEventName.Expose: AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.ExposeEvent.x, xevent.ExposeEvent.y, xevent.ExposeEvent.width, xevent.ExposeEvent.height); break; case XEventName.SelectionClear: { // Should we do something? break; } case XEventName.SelectionRequest: { if (Dnd.HandleSelectionRequestEvent (ref xevent)) break; XEvent sel_event; sel_event = new XEvent(); sel_event.SelectionEvent.type = XEventName.SelectionNotify; sel_event.SelectionEvent.send_event = true; sel_event.SelectionEvent.display = DisplayHandle; sel_event.SelectionEvent.selection = xevent.SelectionRequestEvent.selection; sel_event.SelectionEvent.target = xevent.SelectionRequestEvent.target; sel_event.SelectionEvent.requestor = xevent.SelectionRequestEvent.requestor; sel_event.SelectionEvent.time = xevent.SelectionRequestEvent.time; sel_event.SelectionEvent.property = IntPtr.Zero; IntPtr format_atom = xevent.SelectionRequestEvent.target; // Seems that some apps support asking for supported types if (format_atom == TARGETS) { int[] atoms; int atom_count; atoms = new int[5]; atom_count = 0; if (Clipboard.IsSourceText) { atoms[atom_count++] = (int)Atom.XA_STRING; atoms[atom_count++] = (int)OEMTEXT; atoms[atom_count++] = (int)UTF8_STRING; atoms[atom_count++] = (int)UTF16_STRING; atoms[atom_count++] = (int)RICHTEXTFORMAT; } else if (Clipboard.IsSourceImage) { atoms[atom_count++] = (int)Atom.XA_PIXMAP; atoms[atom_count++] = (int)Atom.XA_BITMAP; } else { // FIXME - handle other types } XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 32, PropertyMode.Replace, atoms, atom_count); sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; } else if (format_atom == (IntPtr)RICHTEXTFORMAT) { string rtf_text = Clipboard.GetRtfText (); if (rtf_text != null) { // The RTF spec mentions that ascii is enough to contain it Byte [] bytes = Encoding.ASCII.GetBytes (rtf_text); int buflen = bytes.Length; IntPtr buffer = Marshal.AllocHGlobal (buflen); for (int i = 0; i < buflen; i++) Marshal.WriteByte (buffer, i, bytes[i]); XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; Marshal.FreeHGlobal(buffer); } } else if (Clipboard.IsSourceText && (format_atom == (IntPtr)Atom.XA_STRING || format_atom == OEMTEXT || format_atom == UTF16_STRING || format_atom == UTF8_STRING)) { IntPtr buffer = IntPtr.Zero; int buflen; Encoding encoding = null; buflen = 0; // Select an encoding depending on the target IntPtr target_atom = xevent.SelectionRequestEvent.target; if (target_atom == (IntPtr)Atom.XA_STRING || target_atom == OEMTEXT) // FIXME - EOMTEXT should encode into ISO2022 encoding = Encoding.ASCII; else if (target_atom == UTF16_STRING) encoding = Encoding.Unicode; else if (target_atom == UTF8_STRING) encoding = Encoding.UTF8; Byte [] bytes; bytes = encoding.GetBytes (Clipboard.GetPlainText ()); buffer = Marshal.AllocHGlobal (bytes.Length); buflen = bytes.Length; for (int i = 0; i < buflen; i++) Marshal.WriteByte (buffer, i, bytes [i]); if (buffer != IntPtr.Zero) { XChangeProperty(DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; Marshal.FreeHGlobal(buffer); } } else if (Clipboard.GetSource (format_atom.ToInt32 ()) != null) { // check if we have an available value of this format if (DataFormats.GetFormat (format_atom.ToInt32 ()).is_serializable) { object serializable = Clipboard.GetSource (format_atom.ToInt32 ()); BinaryFormatter formatter = new BinaryFormatter (); MemoryStream memory_stream = new MemoryStream (); formatter.Serialize (memory_stream, serializable); int buflen = (int)memory_stream.Length; IntPtr buffer = Marshal.AllocHGlobal (buflen); memory_stream.Position = 0; for (int i = 0; i < buflen; i++) Marshal.WriteByte (buffer, i, (byte)memory_stream.ReadByte ()); memory_stream.Close (); XChangeProperty (DisplayHandle, xevent.SelectionRequestEvent.requestor, (IntPtr)xevent.SelectionRequestEvent.property, (IntPtr)xevent.SelectionRequestEvent.target, 8, PropertyMode.Replace, buffer, buflen); sel_event.SelectionEvent.property = xevent.SelectionRequestEvent.property; Marshal.FreeHGlobal (buffer); } } else if (Clipboard.IsSourceImage) { if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { // FIXME - convert image and store as property } else if (xevent.SelectionEvent.target == (IntPtr)Atom.XA_PIXMAP) { // FIXME - convert image and store as property } } XSendEvent(DisplayHandle, xevent.SelectionRequestEvent.requestor, false, new IntPtr ((int)EventMask.NoEventMask), ref sel_event); break; } case XEventName.SelectionNotify: { if (Clipboard.Enumerating) { Clipboard.Enumerating = false; if (xevent.SelectionEvent.property != IntPtr.Zero) { XDeleteProperty(DisplayHandle, FosterParent, (IntPtr)xevent.SelectionEvent.property); if (!Clipboard.Formats.Contains(xevent.SelectionEvent.property)) { Clipboard.Formats.Add(xevent.SelectionEvent.property); DriverDebug("Got supported clipboard atom format: {0}", xevent.SelectionEvent.property); } } } else if (Clipboard.Retrieving) { Clipboard.Retrieving = false; if (xevent.SelectionEvent.property != IntPtr.Zero) { TranslatePropertyToClipboard(xevent.SelectionEvent.property); } else { Clipboard.ClearSources (); Clipboard.Item = null; } } else { Dnd.HandleSelectionNotifyEvent (ref xevent); } break; } case XEventName.KeyRelease: if (!detectable_key_auto_repeat && XPending (DisplayHandle) != 0) { XEvent nextevent = new XEvent (); XPeekEvent (DisplayHandle, ref nextevent); if (nextevent.type == XEventName.KeyPress && nextevent.KeyEvent.keycode == xevent.KeyEvent.keycode && nextevent.KeyEvent.time == xevent.KeyEvent.time) { continue; } } goto case XEventName.KeyPress; case XEventName.MotionNotify: { XEvent peek; /* we can't do motion compression across threads, so just punt if we don't match up */ if (Thread.CurrentThread == hwnd.Queue.Thread && hwnd.Queue.Count > 0) { peek = hwnd.Queue.Peek(); if (peek.AnyEvent.type == XEventName.MotionNotify) { continue; } } goto case XEventName.KeyPress; } case XEventName.KeyPress: hwnd.Queue.EnqueueLocked (xevent); /* Process KeyPresses immediately. Otherwise multiple Compose messages as a result of a * single physical keypress are not processed correctly */ return; case XEventName.ButtonPress: case XEventName.ButtonRelease: case XEventName.EnterNotify: case XEventName.LeaveNotify: case XEventName.CreateNotify: case XEventName.DestroyNotify: case XEventName.FocusIn: case XEventName.FocusOut: case XEventName.ClientMessage: case XEventName.ReparentNotify: case XEventName.MapNotify: case XEventName.UnmapNotify: hwnd.Queue.EnqueueLocked (xevent); break; case XEventName.ConfigureNotify: AddConfigureNotify(xevent); break; case XEventName.PropertyNotify: DriverDebug ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ()); if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) { IntPtr actual_atom; int actual_format; IntPtr nitems; IntPtr bytes_after; IntPtr prop = IntPtr.Zero; IntPtr prev_active; prev_active = ActiveWindow; XGetWindowProperty(DisplayHandle, RootWindow, _NET_ACTIVE_WINDOW, IntPtr.Zero, new IntPtr (1), false, (IntPtr)Atom.XA_WINDOW, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); if (((long)nitems > 0) && (prop != IntPtr.Zero)) { ActiveWindow = Hwnd.GetHandleFromWindow((IntPtr)Marshal.ReadInt32(prop)); XFree(prop); DebugHelper.WriteLine ("PropertyNotify: _NET_ACTIVE_WINDOW: previous = 0x{0:x}, new = 0x{1:x}", prev_active.ToInt32 (), ActiveWindow.ToInt32 ()); if (prev_active != ActiveWindow) { if (prev_active != IntPtr.Zero) { PostMessage(prev_active, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); } if (ActiveWindow != IntPtr.Zero) { PostMessage(ActiveWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); } } if (ModalWindows.Count == 0) { break; } else { // Modality Handling // // If there is a modal window on the stack and the new active // window is MWF window, but not the modal one and not a non-modal // child of the modal one, switch back to the modal window. // // To identify if a non-modal form is child of a modal form // we match their ApplicationContexts, which will be the same. // This is because each modal form runs the loop with a // new ApplicationContext, which is inherited by the non-modal // forms. Form activeForm = Control.FromHandle (ActiveWindow) as Form; if (activeForm != null) { Form modalForm = Control.FromHandle ((IntPtr)ModalWindows.Peek()) as Form; if (ActiveWindow != (IntPtr)ModalWindows.Peek() && (modalForm == null || activeForm.context == modalForm.context)) { Activate((IntPtr)ModalWindows.Peek()); } } break; } } } else if (xevent.PropertyEvent.atom == _NET_WM_STATE) { // invalidate our cache - we'll query again the next time someone does GetWindowState. hwnd.cached_window_state = (FormWindowState)(-1); PostMessage (hwnd.Handle, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero); } break; } } }
internal static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event) { DebugHelper.TraceWriteLine ("XSendEvent"); return _XSendEvent(display, window, propagate, event_mask, ref send_event); }
void MouseHover(object sender, EventArgs e) { XEvent xevent; Hwnd hwnd; HoverState.Timer.Enabled = false; if (HoverState.Window != IntPtr.Zero) { hwnd = Hwnd.GetObjectFromWindow(HoverState.Window); if (hwnd != null) { xevent = new XEvent (); xevent.type = XEventName.ClientMessage; xevent.ClientMessageEvent.display = DisplayHandle; xevent.ClientMessageEvent.window = HoverState.Window; xevent.ClientMessageEvent.message_type = HoverState.Atom; xevent.ClientMessageEvent.format = 32; xevent.ClientMessageEvent.ptr1 = (IntPtr) (HoverState.Y << 16 | HoverState.X); hwnd.Queue.EnqueueLocked (xevent); WakeupMain (); } } }
internal static void XPeekEvent (IntPtr display, ref XEvent xevent) { DebugHelper.TraceWriteLine ("XPeekEvent"); _XPeekEvent (display, ref xevent); }
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; }
internal extern static IntPtr XNextEvent(IntPtr display, ref XEvent xevent);
internal override bool PostMessage (IntPtr handle, Msg message, IntPtr wparam, IntPtr lparam) { XEvent xevent = new XEvent (); Hwnd hwnd = Hwnd.ObjectFromHandle(handle); xevent.type = XEventName.ClientMessage; xevent.ClientMessageEvent.display = DisplayHandle; if (hwnd != null) { xevent.ClientMessageEvent.window = hwnd.whole_window; } else { xevent.ClientMessageEvent.window = IntPtr.Zero; } xevent.ClientMessageEvent.message_type = (IntPtr) PostAtom; xevent.ClientMessageEvent.format = 32; xevent.ClientMessageEvent.ptr1 = handle; xevent.ClientMessageEvent.ptr2 = (IntPtr) message; xevent.ClientMessageEvent.ptr3 = wparam; xevent.ClientMessageEvent.ptr4 = lparam; if (hwnd != null) hwnd.Queue.EnqueueLocked (xevent); else ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent); return true; }
internal extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask, ref XEvent send_event);
bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg) { return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) && arg == xevent.GraphicsExposeEvent.drawable; }
internal extern static bool XFilterEvent(ref XEvent xevent, IntPtr window);
void ProcessGraphicsExpose (Hwnd hwnd) { XEvent xevent = new XEvent (); IntPtr handle = Hwnd.HandleFromObject (hwnd); EventPredicate predicate = GraphicsExposePredicate; for (;;) { XIfEvent (Display, ref xevent, predicate, handle); if (xevent.type != XEventName.GraphicsExpose) break; AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y, xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height); if (xevent.GraphicsExposeEvent.count == 0) break; } }
internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);
internal override void SendAsyncMethod (AsyncMethodData method) { Hwnd hwnd; XEvent xevent = new XEvent (); hwnd = Hwnd.ObjectFromHandle(method.Handle); xevent.type = XEventName.ClientMessage; xevent.ClientMessageEvent.display = DisplayHandle; xevent.ClientMessageEvent.window = method.Handle; xevent.ClientMessageEvent.message_type = (IntPtr)AsyncAtom; xevent.ClientMessageEvent.format = 32; xevent.ClientMessageEvent.ptr1 = (IntPtr) GCHandle.Alloc (method); hwnd.Queue.EnqueueLocked (xevent); WakeupMain (); }