public X11Display (IntPtr display) { if (display == IntPtr.Zero) { throw new ArgumentNullException("Display", "Could not open display (X-Server required. Check your DISPLAY environment variable)"); } this.display = display; // Debugging support if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) { Xlib.XSynchronize (display, true); } if (Environment.GetEnvironmentVariable ("MONO_XEXCEPTIONS") != null) { ErrorExceptions = true; } atoms = new X11Atoms (this); DoubleClickInterval = 500; HoverState.Interval = 500; HoverState.Timer = new Timer(); HoverState.Timer.Enabled = false; HoverState.Timer.Interval = HoverState.Interval; HoverState.Timer.Tick += new EventHandler(MouseHover); HoverState.Size = new Size(4, 4); HoverState.X = -1; HoverState.Y = -1; ActiveWindow = null; FocusWindow = null; ModalWindows = new Stack(3); MouseState = MouseButtons.None; MousePosition = new Point(0, 0); Caret.Timer = new Timer(); Caret.Timer.Interval = 500; // FIXME - where should this number come from? Caret.Timer.Tick += new EventHandler(CaretCallback); // XXX multiscreen work here root_hwnd = new X11RootHwnd (this, Xlib.XRootWindow (display, DefaultScreen)); // XXX do we need a per-screen foster parent? // Create the foster parent foster_hwnd = new X11Hwnd (this, Xlib.XCreateSimpleWindow (display, root_hwnd.WholeWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero)); pollfds = new Pollfd [1]; pollfds [0] = new Pollfd (); pollfds [0].fd = Xlib.XConnectionNumber (display); pollfds [0].events = PollEvents.POLLIN; Keyboard = new X11Keyboard(display, foster_hwnd.Handle); Dnd = new X11Dnd (display, Keyboard); ErrorExceptions = false; // Handle any upcoming errors ErrorHandler = new XErrorHandler (HandleError); Xlib.XSetErrorHandler (ErrorHandler); X11DesktopColors.Initialize(); // XXX we need to figure out how to make this display specific? // Disable keyboard autorepeat try { Xlib.XkbSetDetectableAutoRepeat (display, true, IntPtr.Zero); detectable_key_auto_repeat = true; } catch { Console.Error.WriteLine ("Could not disable keyboard auto repeat, will attempt to disable manually."); detectable_key_auto_repeat = false; } // we re-set our error handler here, X11DesktopColor stuff might have stolen it (gtk does) Xlib.XSetErrorHandler (ErrorHandler); // create our event thread (just sits on the X socket waiting for events) event_thread = new Thread (new ThreadStart (XEventThread)); event_thread.IsBackground = true; event_thread.Start (); }
public void SetModal (X11Hwnd hwnd, bool Modal) { if (Modal) { ModalWindows.Push(hwnd); } else { // XXX do we need to pop until the // hwnd is off the stack? or just the // most recently pushed hwnd? if (ModalWindows.Contains(hwnd)) { ModalWindows.Pop(); } if (ModalWindows.Count > 0) { X11Hwnd top_hwnd = (X11Hwnd)ModalWindows.Peek(); top_hwnd.Activate(); } } }
public void SetFocus (X11Hwnd new_focus) { if (new_focus == FocusWindow) return; X11Hwnd prev_focus = FocusWindow; FocusWindow = new_focus; if (prev_focus != null) SendMessage (prev_focus.Handle, Msg.WM_KILLFOCUS, FocusWindow == null ? IntPtr.Zero : FocusWindow.Handle, IntPtr.Zero); if (FocusWindow != null) SendMessage (FocusWindow.Handle, Msg.WM_SETFOCUS, prev_focus == null ? IntPtr.Zero : prev_focus.Handle, IntPtr.Zero); //XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).ClientWindow, RevertTo.None, IntPtr.Zero); }
public bool GetMessage (object queue_id, ref MSG msg, IntPtr handle, int wFilterMin, int wFilterMax) { X11ThreadQueue queue = (X11ThreadQueue)queue_id; XEvent xevent; bool client; bool got_xevent = false; X11Hwnd hwnd; ProcessNextMessage: do { got_xevent = queue.Dequeue (out xevent); if (!got_xevent) { #if spew Console.WriteLine (">"); Console.Out.Flush (); #endif break; } #if spew Console.Write ("-"); Console.Out.Flush (); #endif hwnd = (X11Hwnd)Hwnd.GetObjectFromWindow (xevent.AnyEvent.window); // 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.PendingExpose = hwnd.PendingNCExpose = false; 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 // ClientWindow, 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) { #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; } client = hwnd.ClientWindow == xevent.AnyEvent.window; msg.hwnd = hwnd.Handle; switch (xevent.type) { case XEventName.KeyPress: Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg); return true; case XEventName.KeyRelease: Keyboard.KeyEvent (FocusWindow.Handle, xevent, ref msg); return true; case XEventName.ButtonPress: { switch(xevent.ButtonEvent.button) { case 1: MouseState |= MouseButtons.Left; if (client) { msg.message = Msg.WM_LBUTTONDOWN; } else { msg.message = Msg.WM_NCLBUTTONDOWN; hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down msg.wParam=GetMousewParam(0); break; case 2: MouseState |= MouseButtons.Middle; if (client) { msg.message = Msg.WM_MBUTTONDOWN; } else { msg.message = Msg.WM_NCMBUTTONDOWN; hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } msg.wParam=GetMousewParam(0); break; case 3: MouseState |= MouseButtons.Right; if (client) { msg.message = Msg.WM_RBUTTONDOWN; } else { msg.message = Msg.WM_NCRBUTTONDOWN; hwnd.MenuToScreen (ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } msg.wParam=GetMousewParam(0); break; case 4: msg.hwnd = FocusWindow.Handle; msg.message=Msg.WM_MOUSEWHEEL; msg.wParam=GetMousewParam(120); break; case 5: msg.hwnd = FocusWindow.Handle; msg.message=Msg.WM_MOUSEWHEEL; msg.wParam=GetMousewParam(-120); break; } msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); MousePosition.X = xevent.ButtonEvent.x; MousePosition.Y = xevent.ButtonEvent.y; if (!hwnd.Enabled) { RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } 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) { hwnd.SendParentNotify (msg.message, MousePosition.X, MousePosition.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* XEvent motionEvent = new XEvent (); motionEvent.type = XEventName.MotionNotify; motionEvent.MotionEvent.display = display; motionEvent.MotionEvent.window = xevent.ButtonEvent.window; motionEvent.MotionEvent.x = xevent.ButtonEvent.x; motionEvent.MotionEvent.y = xevent.ButtonEvent.y; hwnd.Queue.Enqueue (motionEvent); } return true; } case XEventName.ButtonRelease: switch(xevent.ButtonEvent.button) { case 1: if (client) { msg.message = Msg.WM_LBUTTONUP; } else { msg.message = Msg.WM_NCLBUTTONUP; hwnd.MenuToScreen (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; hwnd.MenuToScreen (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; hwnd.MenuToScreen (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) { RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, ref xevent.ButtonEvent.x, ref xevent.ButtonEvent.y); } if (Grab.Hwnd != IntPtr.Zero) msg.hwnd = Grab.Hwnd; msg.lParam=(IntPtr) (xevent.ButtonEvent.y << 16 | xevent.ButtonEvent.x); MousePosition.X = xevent.ButtonEvent.x; MousePosition.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 = display; motionEvent.MotionEvent.window = xevent.ButtonEvent.window; motionEvent.MotionEvent.x = xevent.ButtonEvent.x; motionEvent.MotionEvent.y = xevent.ButtonEvent.y; hwnd.Queue.Enqueue (motionEvent); } return true; case XEventName.MotionNotify: /* XXX move the compression stuff here */ if (client) { #if DriverDebugExtra Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); #endif if (Grab.Hwnd != IntPtr.Zero) msg.hwnd = Grab.Hwnd; else NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT); msg.message = Msg.WM_MOUSEMOVE; msg.wParam = GetMousewParam(0); msg.lParam = (IntPtr) (xevent.MotionEvent.y << 16 | xevent.MotionEvent.x & 0xFFFF); if (!hwnd.Enabled) { RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, ref xevent.MotionEvent.x, ref xevent.MotionEvent.y); } MousePosition.X = xevent.MotionEvent.x; MousePosition.Y = xevent.MotionEvent.y; if ((HoverState.Timer.Enabled) && (((MousePosition.X + HoverState.Size.Width) < HoverState.X) || ((MousePosition.X - HoverState.Size.Width) > HoverState.X) || ((MousePosition.Y + HoverState.Size.Height) < HoverState.Y) || ((MousePosition.Y - HoverState.Size.Height) > HoverState.Y))) { HoverState.Timer.Stop(); HoverState.Timer.Start(); HoverState.X = MousePosition.X; HoverState.Y = MousePosition.Y; } } else { HitTest ht; IntPtr dummy; int screen_x; int screen_y; #if DriverDebugExtra Console.WriteLine("GetMessage(): non-client area {0:X} MotionNotify x={1} y={2}", client ? hwnd.ClientWindow.ToInt32() : hwnd.WholeWindow.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y); #endif msg.message = Msg.WM_NCMOUSEMOVE; if (!hwnd.Enabled) { RedirectMsgToEnabledAncestor (hwnd, msg, xevent.AnyEvent.window, ref xevent.MotionEvent.x, ref xevent.MotionEvent.y); } // The hit test is sent in screen coordinates Xlib.XTranslateCoordinates (display, xevent.AnyEvent.window, RootWindow.Handle, xevent.MotionEvent.x, xevent.MotionEvent.y, out screen_x, out screen_y, out dummy); msg.lParam = (IntPtr) (screen_y << 16 | screen_x & 0xFFFF); ht = (HitTest)NativeWindow.WndProc (hwnd.ClientWindow, Msg.WM_NCHITTEST, IntPtr.Zero, msg.lParam).ToInt32 (); NativeWindow.WndProc(hwnd.ClientWindow, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)ht); MousePosition.X = xevent.MotionEvent.x; MousePosition.Y = xevent.MotionEvent.y; } return true; case XEventName.EnterNotify: if (!hwnd.Enabled) goto ProcessNextMessage; if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) goto ProcessNextMessage; 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; return true; case XEventName.LeaveNotify: if (!hwnd.Enabled) goto ProcessNextMessage; if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.ClientWindow)) goto ProcessNextMessage; msg.message=Msg.WM_MOUSELEAVE; HoverState.Timer.Enabled = false; HoverState.Window = IntPtr.Zero; return true; case XEventName.ReparentNotify: if (hwnd.parent == null) { // Toplevel if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.WholeWindow)) { // We need to adjust x/y // This sucks ass, part 2 // Every WM does the reparenting of toplevel windows different, so there's // no standard way of getting our adjustment considering frames/decorations // The code below is needed for metacity. KDE doesn't works just fine without this int dummy_int; IntPtr dummy_ptr; int new_x; int new_y; int frame_left; int frame_top; hwnd.Reparented = true; Xlib.XGetGeometry(display, XGetParent(hwnd.WholeWindow), out dummy_ptr, out new_x, out new_y, out dummy_int, out dummy_int, out dummy_int, out dummy_int); hwnd.FrameExtents(out frame_left, out frame_top); if ((frame_left != 0) && (frame_top != 0) && (new_x != frame_left) && (new_y != frame_top)) { hwnd.x = new_x; hwnd.y = new_y; hwnd.whacky_wm = true; } if (hwnd.opacity != 0xffffffff) { IntPtr opacity; opacity = (IntPtr)(Int32)hwnd.opacity; Xlib.XChangeProperty (display, XGetParent(hwnd.WholeWindow), Atoms._NET_WM_WINDOW_OPACITY, Atoms.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: hwnd.HandleConfigureNotify (xevent); goto ProcessNextMessage; 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.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 == null) { Control c = Control.FromHandle (hwnd.ClientWindow); if (c == null) goto ProcessNextMessage; Form form = c.FindForm (); if (form == null) goto ProcessNextMessage; X11Hwnd new_active = (X11Hwnd)Hwnd.ObjectFromHandle (form.Handle); if (ActiveWindow != new_active) { ActiveWindow = new_active; SendMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr) WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); } goto ProcessNextMessage; } Keyboard.FocusIn(FocusWindow.Handle); SendMessage(FocusWindow.Handle, 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; if (FocusWindow == null) goto ProcessNextMessage; Keyboard.FocusOut(FocusWindow.Handle); while (Keyboard.ResetKeyState(FocusWindow.Handle, ref msg)) SendMessage(FocusWindow.Handle, msg.message, msg.wParam, msg.lParam); SendMessage(FocusWindow.Handle, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); goto ProcessNextMessage; case XEventName.Expose: if (!hwnd.Mapped) { hwnd.PendingExpose = hwnd.PendingNCExpose = false; continue; } msg.hwnd = hwnd.Handle; if (client) { #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 msg.message = Msg.WM_PAINT; } else { Graphics g; switch (hwnd.border_style) { case FormBorderStyle.Fixed3D: g = Graphics.FromHwnd(hwnd.WholeWindow); ControlPaint.DrawBorder3D(g, new Rectangle(0, 0, hwnd.Width, hwnd.Height), Border3DStyle.Sunken); g.Dispose(); break; case FormBorderStyle.FixedSingle: g = Graphics.FromHwnd(hwnd.WholeWindow); 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.ClientWindow.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; } return true; case XEventName.DestroyNotify: // This is a bit tricky, we don't receive our own DestroyNotify, we only get those for our children hwnd = (X11Hwnd)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.ClientWindow == xevent.DestroyWindowEvent.window)) { CleanupCachedWindows (hwnd); #if DriverDebugDestroy Console.WriteLine("Received X11 Destroy Notification for {0}", XplatUI.Window(hwnd.ClientWindow)); #endif msg.hwnd = hwnd.ClientWindow; msg.message=Msg.WM_DESTROY; hwnd.Dispose(); } else goto ProcessNextMessage; return true; case XEventName.ClientMessage: if (Dnd.HandleClientMessage (ref xevent)) goto ProcessNextMessage; if (xevent.ClientMessageEvent.message_type == Atoms.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 == Atoms.PostAtom) { msg.hwnd = xevent.ClientMessageEvent.ptr1; msg.message = (Msg) xevent.ClientMessageEvent.ptr2.ToInt32 (); msg.wParam = xevent.ClientMessageEvent.ptr3; msg.lParam = xevent.ClientMessageEvent.ptr4; // if we posted a WM_QUIT message, make sure we return // false here as well. if (msg.message == (Msg)Msg.WM_QUIT) return false; else return true; } if (xevent.ClientMessageEvent.message_type == Atoms._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; Xlib.XGetWMNormalHints (display, hwnd.WholeWindow, 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 == Atoms.WM_PROTOCOLS) { if (xevent.ClientMessageEvent.ptr1 == Atoms.WM_DELETE_WINDOW) { 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 == Atoms.WM_TAKE_FOCUS) { goto ProcessNextMessage; } } goto ProcessNextMessage; case XEventName.PropertyNotify: // The Hwnd's themselves handle this hwnd.PropertyChanged (xevent); goto ProcessNextMessage; } } while (true); msg.hwnd= IntPtr.Zero; msg.message = Msg.WM_ENTERIDLE; return true; }
public void ResetMouseHover (X11Hwnd hovering) { HoverState.Timer.Enabled = hovering != null; HoverState.X = MousePosition.X; HoverState.Y = MousePosition.Y; HoverState.Window = hovering == null ? IntPtr.Zero : hovering.Handle; }
public void UngrabWindow (X11Hwnd hwnd) { Xlib.XUngrabPointer (display, IntPtr.Zero); Xlib.XFlush (display); // XXX make sure hwnd is what should have the grab and throw if not Grab.Hwnd = IntPtr.Zero; Grab.Confined = false; }
private void RedirectMsgToEnabledAncestor (X11Hwnd hwnd, MSG msg, IntPtr window, ref int event_x, ref int event_y) { int x, y; IntPtr dummy; msg.hwnd = hwnd.EnabledHwnd; Xlib.XTranslateCoordinates (display, window, Hwnd.ObjectFromHandle(msg.hwnd).ClientWindow, event_x, event_y, out x, out y, out dummy); event_x = x; event_y = y; msg.lParam = (IntPtr)(MousePosition.Y << 16 | MousePosition.X); }
public void GetCursorPos (X11Hwnd hwnd, out int x, out int y) { IntPtr use_handle; IntPtr root; IntPtr child; int root_x; int root_y; int win_x; int win_y; int keys_buttons; if (hwnd != null) use_handle = hwnd.Handle; else use_handle = RootWindow.Handle; QueryPointer (use_handle, out root, out child, out root_x, out root_y, out win_x, out win_y, out keys_buttons); if (hwnd != null) { x = win_x; y = win_y; } else { x = root_x; y = root_y; } }
public void GrabWindow (X11Hwnd hwnd, X11Hwnd confine_to) { IntPtr confine_to_window; confine_to_window = IntPtr.Zero; if (confine_to != null) { Console.WriteLine (Environment.StackTrace); XWindowAttributes attributes = new XWindowAttributes(); Xlib.XGetWindowAttributes (display, confine_to.ClientWindow, ref attributes); Grab.Area.X = attributes.x; Grab.Area.Y = attributes.y; Grab.Area.Width = attributes.width; Grab.Area.Height = attributes.height; Grab.Confined = true; confine_to_window = confine_to.ClientWindow; } Grab.Hwnd = hwnd.ClientWindow; Xlib.XGrabPointer (display, hwnd.ClientWindow, false, EventMask.ButtonPressMask | EventMask.ButtonMotionMask | EventMask.ButtonReleaseMask | EventMask.PointerMotionMask, GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero); }
public void DestroyWindow (X11Hwnd hwnd) { CleanupCachedWindows (hwnd); hwnd.SendParentNotify (Msg.WM_DESTROY, int.MaxValue, int.MaxValue); ArrayList windows = new ArrayList (); AccumulateDestroyedHandles (Control.ControlNativeWindow.ControlFromHandle(hwnd.Handle), windows); hwnd.DestroyWindow (); foreach (X11Hwnd h in windows) { SendMessage (h.Handle, Msg.WM_DESTROY, IntPtr.Zero, IntPtr.Zero); } }
public void SetActiveWindow (X11Hwnd new_active_window) { if (new_active_window != ActiveWindow) { if (ActiveWindow != null) PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); ActiveWindow = new_active_window; if (ActiveWindow != null) PostMessage (ActiveWindow.Handle, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_ACTIVE, IntPtr.Zero); } if (ModalWindows.Count > 0) { // Modality handling, if we are modal and the new active window is one // of ours but not the modal one, switch back to the modal window if (ActiveWindow != null && NativeWindow.FromHandle (ActiveWindow.Handle) != null) { if (ActiveWindow != (X11Hwnd)ModalWindows.Peek()) ((X11Hwnd)ModalWindows.Peek()).Activate (); } } }
void CleanupCachedWindows (X11Hwnd hwnd) { if (ActiveWindow == hwnd) { SendMessage (hwnd.ClientWindow, Msg.WM_ACTIVATE, (IntPtr)WindowActiveFlags.WA_INACTIVE, IntPtr.Zero); ActiveWindow = null; } if (FocusWindow == hwnd) { SendMessage (hwnd.ClientWindow, Msg.WM_KILLFOCUS, IntPtr.Zero, IntPtr.Zero); FocusWindow = null; } if (Grab.Hwnd == hwnd.Handle) { Grab.Hwnd = IntPtr.Zero; Grab.Confined = false; } DestroyCaret (hwnd.Handle); }
internal override IntPtr CreateWindow (CreateParams cp) { X11Hwnd hwnd = new X11Hwnd (display); hwnd.CreateWindow (cp); return hwnd.Handle; }
public bool SetZOrder (X11Hwnd after_hwnd, bool top, bool bottom) { if (top) { Xlib.XRaiseWindow (display.Handle, WholeWindow); return true; } else if (bottom) { Xlib.XLowerWindow (display.Handle, WholeWindow); return true; } else { if (after_hwnd == null) { Update_USER_TIME (); Xlib.XRaiseWindow (display.Handle, WholeWindow); display.SendNetWMMessage (WholeWindow, display.Atoms._NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero); return true; } XWindowChanges values = new XWindowChanges(); values.sibling = after_hwnd.WholeWindow; values.stack_mode = StackMode.Below; Xlib.XConfigureWindow (display.Handle, WholeWindow, ChangeWindowFlags.CWStackMode | ChangeWindowFlags.CWSibling, ref values); } return false; }
public bool SetOwner (X11Hwnd owner) { if (owner != null) { WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL; if (owner != null) Xlib.XSetTransientForHint (display.Handle, WholeWindow, owner.WholeWindow); else Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.WholeWindow); } else { Xlib.XDeleteProperty (display.Handle, WholeWindow, display.Atoms.XA_WM_TRANSIENT_FOR); } return true; }
public void SetParent (X11Hwnd parent_hwnd) { Parent = parent_hwnd; #if DriverDebug || DriverDebugParent Console.WriteLine("Parent for window {0} = {1}", XplatUI.Window(Handle), XplatUI.Window(hwnd.parent != null ? parent_hwnd.Handle : IntPtr.Zero)); #endif Xlib.XReparentWindow (display.Handle, WholeWindow, parent_hwnd == null ? display.FosterParent.ClientWindow : parent_hwnd.ClientWindow, X, Y); }