internal extern static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return);
internal extern static void _XSetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints);
internal override bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) { GetSystrayManagerWindow(); if (SystrayMgrWindow != IntPtr.Zero) { XSizeHints size_hints; Hwnd hwnd; hwnd = Hwnd.ObjectFromHandle(handle); DriverDebug("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32()); // Oh boy. if (hwnd.client_window != hwnd.whole_window) { Keyboard.DestroyICForWindow (hwnd.client_window); XDestroyWindow(DisplayHandle, hwnd.client_window); hwnd.client_window = hwnd.whole_window; } /* by virtue of the way the tests are ordered when determining if it's PAINT or NCPAINT, client_window == whole_window will always be PAINT. So, if we're waiting on an nc_expose, drop it and remove the hwnd from the list (unless there's a pending expose). */ if (hwnd.nc_expose_pending) { hwnd.nc_expose_pending = false; if (!hwnd.expose_pending) hwnd.Queue.Paint.Remove (hwnd); } // We are going to be directly mapped by the system tray, so mark as mapped // so we can later properly unmap it. hwnd.mapped = true; size_hints = new XSizeHints(); size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); size_hints.min_width = 24; size_hints.min_height = 24; size_hints.max_width = 24; size_hints.max_height = 24; size_hints.base_width = 24; size_hints.base_height = 24; XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref size_hints); int[] atoms = new int[2]; atoms [0] = 1; // Version 1 atoms [1] = 1; // we want to be mapped // This line cost me 3 days... XChangeProperty(DisplayHandle, hwnd.whole_window, _XEMBED_INFO, _XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2); // Need to pick some reasonable defaults tt = new ToolTip(); tt.AutomaticDelay = 350; tt.InitialDelay = 250; tt.ReshowDelay = 250; tt.ShowAlways = true; if ((tip != null) && (tip != string.Empty)) { tt.SetToolTip(Control.FromHandle(handle), tip); tt.Active = true; } else { tt.Active = false; } SendNetClientMessage(SystrayMgrWindow, _NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window); return true; } tt = null; return false; }
internal extern static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints);
internal static void XGetWMNormalHints(IntPtr display, IntPtr window, ref XSizeHints hints, out IntPtr supplied_return) { DebugHelper.TraceWriteLine ("XGetWMNormalHints"); _XGetWMNormalHints(display, window, ref hints, out supplied_return); }
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 void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp) { Hwnd hwnd; XSizeHints hints; IntPtr dummy; hwnd = Hwnd.ObjectFromHandle(handle); if (hwnd == null) { return; } min.Width = Math.Max (min.Width, SystemInformation.MinimumWindowSize.Width); min.Height = Math.Max (min.Height, SystemInformation.MinimumWindowSize.Height); hints = new XSizeHints(); XGetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints, out dummy); if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) { if (cp != null) min = TranslateWindowSizeToXWindowSize (cp, min); hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); hints.min_width = min.Width; hints.min_height = min.Height; } if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) { if (cp != null) max = TranslateWindowSizeToXWindowSize (cp, max); hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); hints.max_width = max.Width; hints.max_height = max.Height; } if (hints.flags != IntPtr.Zero) { // The Metacity team has decided that they won't care about this when clicking the maximize icon, // they will maximize the window to fill the screen/parent no matter what. // http://bugzilla.ximian.com/show_bug.cgi?id=80021 XSetWMNormalHints(DisplayHandle, hwnd.whole_window, ref hints); } if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) { if (cp != null) maximized.Size = TranslateWindowSizeToXWindowSize (cp); hints.flags = (IntPtr)XSizeHintsFlags.PPosition; hints.x = maximized.X; hints.y = maximized.Y; hints.width = maximized.Width; hints.height = maximized.Height; // Metacity does not seem to follow this constraint for maximized (zoomed) windows XSetZoomHints(DisplayHandle, hwnd.whole_window, ref hints); } }
public bool SystrayAdd(IntPtr handle, string tip, Icon icon, out ToolTip tt) { IntPtr SystrayMgrWindow; Xlib.XGrabServer (display); SystrayMgrWindow = Xlib.XGetSelectionOwner (display, Atoms._NET_SYSTEM_TRAY_S); Xlib.XUngrabServer (display); if (SystrayMgrWindow != IntPtr.Zero) { XSizeHints size_hints; X11Hwnd hwnd; hwnd = (X11Hwnd)Hwnd.ObjectFromHandle(handle); #if DriverDebug Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.WholeWindow.ToInt32(), hwnd.ClientWindow.ToInt32()); #endif // Oh boy. if (hwnd.ClientWindow != hwnd.WholeWindow) { Xlib.XDestroyWindow (display, hwnd.ClientWindow); hwnd.ClientWindow = hwnd.WholeWindow; try { hwnd.Queue.Lock (); /* by virtue of the way the tests are ordered when determining if it's PAINT or NCPAINT, ClientWindow == WholeWindow will always be PAINT. So, if we're waiting on an nc_expose, drop it and remove the hwnd from the list (unless there's a pending expose). */ hwnd.PendingNCExpose = false; } finally { hwnd.Queue.Unlock (); } } size_hints = new XSizeHints(); size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); size_hints.min_width = 24; size_hints.min_height = 24; size_hints.max_width = 24; size_hints.max_height = 24; size_hints.base_width = 24; size_hints.base_height = 24; Xlib.XSetWMNormalHints (display, hwnd.WholeWindow, ref size_hints); int[] atoms = new int[2]; atoms [0] = 1; // Version 1 atoms [1] = 1; // we want to be mapped // This line cost me 3 days... Xlib.XChangeProperty (display, hwnd.WholeWindow, Atoms._XEMBED_INFO, Atoms._XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2); // Need to pick some reasonable defaults tt = new ToolTip(); tt.AutomaticDelay = 100; tt.InitialDelay = 250; tt.ReshowDelay = 250; tt.ShowAlways = true; if ((tip != null) && (tip != string.Empty)) { tt.SetToolTip(Control.FromHandle(handle), tip); tt.Active = true; } else { tt.Active = false; } SendNetClientMessage (SystrayMgrWindow, Atoms._NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.WholeWindow); return true; } tt = null; return false; }
internal override IntPtr CreateWindow (CreateParams cp) { XSetWindowAttributes Attributes; Hwnd hwnd; Hwnd parent_hwnd = null; int X; int Y; int Width; int Height; IntPtr ParentHandle; IntPtr WholeWindow; IntPtr ClientWindow; SetWindowValuemask ValueMask; int[] atoms; hwnd = new Hwnd(); Attributes = new XSetWindowAttributes(); X = cp.X; Y = cp.Y; Width = cp.Width; Height = cp.Height; if (Width<1) Width=1; if (Height<1) Height=1; if (cp.Parent != IntPtr.Zero) { parent_hwnd = Hwnd.ObjectFromHandle(cp.Parent); ParentHandle = parent_hwnd.client_window; } else { if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) { // We need to use our foster parent window until this poor child gets it's parent assigned ParentHandle=FosterParent; } else { ParentHandle=RootWindow; } } // Set the default location location for forms. Point next; if (cp.control is Form) { next = Hwnd.GetNextStackedFormLocation (cp, parent_hwnd); X = next.X; Y = next.Y; } ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; Attributes.bit_gravity = Gravity.NorthWestGravity; Attributes.win_gravity = Gravity.NorthWestGravity; // Save what's under the toolwindow if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { Attributes.save_under = true; ValueMask |= SetWindowValuemask.SaveUnder; } // If we're a popup without caption we override the WM if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { Attributes.override_redirect = true; ValueMask |= SetWindowValuemask.OverrideRedirect; } hwnd.x = X; hwnd.y = Y; hwnd.width = Width; hwnd.height = Height; hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent); hwnd.initial_style = cp.WindowStyle; hwnd.initial_ex_style = cp.WindowExStyle; if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) { hwnd.enabled = false; } ClientWindow = IntPtr.Zero; Size XWindowSize = TranslateWindowSizeToXWindowSize (cp); Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control); lock (XlibLock) { WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, XWindowSize.Width, XWindowSize.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes); if (WholeWindow != IntPtr.Zero) { ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder); if (CustomVisual != IntPtr.Zero && CustomColormap != IntPtr.Zero) { ValueMask = SetWindowValuemask.ColorMap; Attributes.colormap = CustomColormap; } ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, XClientRect.X, XClientRect.Y, XClientRect.Width, XClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes); } } if ((WholeWindow == IntPtr.Zero) || (ClientWindow == IntPtr.Zero)) { throw new Exception("Could not create X11 windows"); } hwnd.Queue = ThreadQueue(Thread.CurrentThread); hwnd.WholeWindow = WholeWindow; hwnd.ClientWindow = ClientWindow; DriverDebug("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), hwnd.parent != null ? hwnd.parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle); if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) { if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) { XSizeHints hints; hints = new XSizeHints(); hints.x = X; hints.y = Y; hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition); XSetWMNormalHints(DisplayHandle, WholeWindow, ref hints); } } lock (XlibLock) { XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask | Keyboard.KeyEventMask))); if (hwnd.whole_window != hwnd.client_window) XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask))); } if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) SetTopmost(hwnd.whole_window, true); SetWMStyles(hwnd, cp); // set the group leader XWMHints wm_hints = new XWMHints (); wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint); wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState; if (ParentHandle != RootWindow) { wm_hints.window_group = hwnd.whole_window; } else { wm_hints.window_group = ParentHandle; } lock (XlibLock) { XSetWMHints(DisplayHandle, hwnd.whole_window, ref wm_hints ); } if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) { SetWindowState(hwnd.Handle, FormWindowState.Minimized); } else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) { SetWindowState(hwnd.Handle, FormWindowState.Maximized); } // for now make all windows dnd enabled Dnd.SetAllowDrop (hwnd, true); // Set caption/window title Text(hwnd.Handle, cp.Caption); SendMessage (hwnd.Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); SendParentNotify (hwnd.Handle, Msg.WM_CREATE, int.MaxValue, int.MaxValue); if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { hwnd.visible = true; MapWindow(hwnd, WindowType.Both); if (!(Control.FromHandle(hwnd.Handle) is Form)) SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); } return hwnd.Handle; }
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; }
internal override bool SystrayAdd (IntPtr handle, string tip, Icon icon, out ToolTip tt) { GetSystrayManagerWindow (); if (SystrayMgrWindow != IntPtr.Zero) { uint[] atoms; XSizeHints size_hints; Hwnd hwnd; hwnd = Hwnd.ObjectFromHandle (handle); #if DriverDebug Console.WriteLine("Adding Systray Whole:{0:X}, Client:{1:X}", hwnd.whole_window.ToInt32(), hwnd.client_window.ToInt32()); #endif XUnmapWindow (DisplayHandle, hwnd.whole_window); XUnmapWindow (DisplayHandle, hwnd.client_window); // Oh boy. gdk_window_destroy (gdk_window_lookup (hwnd.client_window)); hwnd.client_window = hwnd.whole_window; size_hints = new XSizeHints (); size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize); size_hints.min_width = icon.Width; size_hints.min_height = icon.Height; size_hints.max_width = icon.Width; size_hints.max_height = icon.Height; size_hints.base_width = icon.Width; size_hints.base_height = icon.Height; XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref size_hints); atoms = new uint [2]; atoms [0] = 1; // Version 1 atoms [1] = 0; // We're not mapped // This line cost me 3 days... XChangeProperty (DisplayHandle, hwnd.whole_window, NetAtoms [(int)NA._XEMBED_INFO], NetAtoms [(int)NA._XEMBED_INFO], 32, PropertyMode.Replace, atoms, 2); // Need to pick some reasonable defaults tt = new ToolTip (); tt.AutomaticDelay = 100; tt.InitialDelay = 250; tt.ReshowDelay = 250; tt.ShowAlways = true; if ((tip != null) && (tip != string.Empty)) { tt.SetToolTip (Control.FromHandle (handle), tip); tt.Active = true; } else { tt.Active = false; } // Make sure the window exists XSync (DisplayHandle, hwnd.whole_window); SendNetClientMessage (SystrayMgrWindow, (IntPtr)NetAtoms [(int)NA._NET_SYSTEM_TRAY_OPCODE], IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, hwnd.whole_window); return true; } tt = null; return false; }
internal override void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max) { Hwnd hwnd; XSizeHints hints; hwnd = Hwnd.ObjectFromHandle (handle); if (hwnd == null) { return; } hints = new XSizeHints (); if (min != Size.Empty) { hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); hints.min_width = min.Width; hints.min_height = min.Height; } if (max != Size.Empty) { hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); hints.max_width = max.Width; hints.max_height = max.Height; } XSetWMNormalHints (DisplayHandle, hwnd.whole_window, ref hints); if (maximized != Rectangle.Empty) { hints.flags = (IntPtr)XSizeHintsFlags.PPosition; hints.x = maximized.X; hints.y = maximized.Y; hints.width = maximized.Width; hints.height = maximized.Height; // Metacity does not seem to follow this constraint for maximized (zoomed) windows XSetZoomHints (DisplayHandle, hwnd.whole_window, ref hints); } }
public virtual void CreateWindow (CreateParams cp) { if (WholeWindow != IntPtr.Zero || ClientWindow != IntPtr.Zero) throw new Exception ("createwindow called a second time on live X11Hwnd"); XSetWindowAttributes Attributes; int x; int y; int width; int height; IntPtr ParentHandle; SetWindowValuemask ValueMask; Attributes = new XSetWindowAttributes(); x = cp.X; y = cp.Y; width = cp.Width; height = cp.Height; initial_ex_style = (WindowExStyles) cp.ExStyle; /* Figure out our parent handle */ if (cp.Parent != IntPtr.Zero) // the parent handle is specified in the CreateParams ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).ClientWindow; else if (StyleSet (cp.Style, WindowStyles.WS_CHILD)) // a child control with an unassigned parent gets created under the FosterParent ParentHandle = display.FosterParent.Handle; else // for all other cases, the parent is the root window ParentHandle = display.RootWindow.Handle; ValueMask = SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity; Attributes.bit_gravity = Gravity.NorthWestGravity; Attributes.win_gravity = Gravity.NorthWestGravity; // Save what's under the toolwindow if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) { Attributes.save_under = true; ValueMask |= SetWindowValuemask.SaveUnder; } // If we're a popup without caption we override the WM if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && !StyleSet (cp.Style, WindowStyles.WS_CAPTION)) { Attributes.override_redirect = true; ValueMask |= SetWindowValuemask.OverrideRedirect; } // Default position on screen, if window manager doesn't place us somewhere else if (!StyleSet (cp.Style, WindowStyles.WS_CHILD) && !StyleSet (cp.Style, WindowStyles.WS_POPUP)) { if (x<0) x = 50; if (y<0) y = 50; } // minimum width/height if (width<1) width=1; if (height<1) height=1; X = x; Y = y; Width = width; Height = height; Parent = Hwnd.ObjectFromHandle (cp.Parent); Enabled = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); ClientWindow = IntPtr.Zero; WholeWindow = Xlib.XCreateWindow (display.Handle, ParentHandle, X, Y, Width, Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes); if (WholeWindow == IntPtr.Zero) throw new Exception ("Coult not create X11 nc window"); ValueMask &= ~(SetWindowValuemask.OverrideRedirect | SetWindowValuemask.SaveUnder); if (display.CustomVisual != IntPtr.Zero && display.CustomColormap != IntPtr.Zero) { ValueMask |= SetWindowValuemask.ColorMap; Attributes.colormap = display.CustomColormap; } ClientWindow = Xlib.XCreateWindow (display.Handle, WholeWindow, ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, display.CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes); if (ClientWindow == IntPtr.Zero) throw new Exception("Could not create X11 client window"); #if DriverDebug || DriverDebugCreate Console.WriteLine("Created window {0:X} / {1:X} parent {2:X}, Style {3}, ExStyle {4}", ClientWindow.ToInt32(), WholeWindow.ToInt32(), Parent != null ? Parent.Handle.ToInt32() : 0, (WindowStyles)cp.Style, (WindowExStyles)cp.ExStyle); #endif if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) { if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) { XSizeHints hints; hints = new XSizeHints(); hints.x = X; hints.y = Y; hints.flags = (IntPtr)(XSizeHintsFlags.USPosition | XSizeHintsFlags.PPosition); Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints); } } Xlib.XSelectInput (display.Handle, WholeWindow, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask))); if (WholeWindow != ClientWindow) Xlib.XSelectInput (display.Handle, ClientWindow, new IntPtr ((int)SelectInputMask)); if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) { WINDOW_TYPE = display.Atoms._NET_WM_WINDOW_TYPE_NORMAL; Xlib.XSetTransientForHint (display.Handle, WholeWindow, display.RootWindow.Handle); } SetWMStyles (cp); // set the group leader XWMHints wm_hints = new XWMHints (); wm_hints.flags = (IntPtr)(XWMHintsFlags.InputHint | XWMHintsFlags.StateHint | XWMHintsFlags.WindowGroupHint); wm_hints.input = !StyleSet (cp.Style, WindowStyles.WS_DISABLED); wm_hints.initial_state = StyleSet (cp.Style, WindowStyles.WS_MINIMIZE) ? XInitialState.IconicState : XInitialState.NormalState; wm_hints.window_group = ParentHandle == display.RootWindow.Handle ? ParentHandle : WholeWindow; Xlib.XSetWMHints (display.Handle, WholeWindow, ref wm_hints ); if (StyleSet (cp.Style, WindowStyles.WS_MINIMIZE)) SetWindowState (FormWindowState.Minimized); else if (StyleSet (cp.Style, WindowStyles.WS_MAXIMIZE)) SetWindowState (FormWindowState.Maximized); // for now make all windows dnd enabled display.Dnd.SetAllowDrop (this, true); // Set caption/window title Text = cp.Caption; display.SendMessage (Handle, Msg.WM_CREATE, (IntPtr)1, IntPtr.Zero /* XXX unused */); SendParentNotify (Msg.WM_CREATE, int.MaxValue, int.MaxValue); if (StyleSet (cp.Style, WindowStyles.WS_VISIBLE)) { visible = true; Map (); if (!(Control.FromHandle(Handle) is Form)) display.SendMessage (Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero); } }
public void SetMinMax (Rectangle maximized, Size min, Size max) { XSizeHints hints; IntPtr dummy; hints = new XSizeHints(); Xlib.XGetWMNormalHints (display.Handle, WholeWindow, ref hints, out dummy); if ((min != Size.Empty) && (min.Width > 0) && (min.Height > 0)) { hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize); hints.min_width = min.Width; hints.min_height = min.Height; } if ((max != Size.Empty) && (max.Width > 0) && (max.Height > 0)) { hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize); hints.max_width = max.Width; hints.max_height = max.Height; } if (hints.flags != IntPtr.Zero) Xlib.XSetWMNormalHints (display.Handle, WholeWindow, ref hints); if ((maximized != Rectangle.Empty) && (maximized.Width > 0) && (maximized.Height > 0)) { hints.flags = (IntPtr)XSizeHintsFlags.PPosition; hints.x = maximized.X; hints.y = maximized.Y; hints.width = maximized.Width; hints.height = maximized.Height; // Metacity does not seem to follow this constraint for maximized (zoomed) windows Xlib.XSetZoomHints (display.Handle, WholeWindow, ref hints); } }
internal static void XSetZoomHints(IntPtr display, IntPtr window, ref XSizeHints hints) { DebugHelper.TraceWriteLine ("XSetZoomHints"); _XSetZoomHints(display, window, ref hints); }