private static IntPtr FosterParent; // Container to hold child windows until their parent exists
private static XErrorHandler ErrorHandler; // Error handler delegate
private static bool ErrorExceptions; // Throw exceptions on X errors
+ private int render_major_opcode;
+ private int render_first_event;
+ private int render_first_error;
// Clipboard
private static IntPtr ClipMagic;
// Message Loop
private static Hashtable MessageQueues; // Holds our thread-specific XEventQueues
+ private static ArrayList unattached_timer_list; // holds timers that are enabled but not attached to a window.
#if __MonoCS__ //
private static Pollfd[] pollfds; // For watching the X11 socket
private static bool wake_waiting;
// Caret
private static CaretStruct Caret; //
+ // Last window containing the pointer
+ private static IntPtr LastPointerWindow; // The last window containing the pointer
+
// Our atoms
private static IntPtr WM_PROTOCOLS;
private static IntPtr WM_DELETE_WINDOW;
private static IntPtr _XEMBED_INFO;
private static IntPtr _MOTIF_WM_HINTS;
private static IntPtr _NET_WM_STATE_SKIP_TASKBAR;
- //private static IntPtr _NET_WM_STATE_ABOVE;
- //private static IntPtr _NET_WM_STATE_MODAL;
+ private static IntPtr _NET_WM_STATE_ABOVE;
+ private static IntPtr _NET_WM_STATE_MODAL;
private static IntPtr _NET_WM_STATE_HIDDEN;
private static IntPtr _NET_WM_CONTEXT_HELP;
private static IntPtr _NET_WM_WINDOW_OPACITY;
//private static IntPtr _NET_WM_WINDOW_TYPE_MENU;
private static IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
//private static IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
- //private static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
+ private static IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
private static IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
private static IntPtr CLIPBOARD;
private static IntPtr PRIMARY;
EventMask.ExposureMask |
EventMask.FocusChangeMask |
EventMask.PointerMotionMask |
+ EventMask.PointerMotionHintMask |
EventMask.SubstructureNotifyMask);
static readonly object lockobj = new object ();
// Now regular initialization
XlibLock = new object ();
+ X11Keyboard.XlibLock = XlibLock;
MessageQueues = Hashtable.Synchronized (new Hashtable(7));
+ unattached_timer_list = ArrayList.Synchronized (new ArrayList (3));
XInitThreads();
ErrorExceptions = false;
}
- error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Control: {6}", x_error_text, RequestCode, RequestCode, ResourceID.ToInt32(), Serial, hwnd_text, control_text);
+ error = String.Format("\n Error: {0}\n Request: {1:D} ({2})\n Resource ID: 0x{3:X}\n Serial: {4}\n Hwnd: {5}\n Control: {6}", x_error_text, RequestCode, MinorCode, ResourceID.ToInt32(), Serial, hwnd_text, control_text);
return error;
}
}
// been hacked to do this for us.
Graphics.FromHdcInternal (DisplayHandle);
+ // query for the render extension so
+ // we can ignore the spurious
+ // BadPicture errors that are
+ // generated by cairo/render.
+ XQueryExtension (DisplayHandle, "RENDER",
+ ref render_major_opcode, ref render_first_event, ref render_first_error);
+
// Debugging support
if (Environment.GetEnvironmentVariable ("MONO_XSYNC") != null) {
XSynchronize(DisplayHandle, true);
DefaultColormap = XDefaultColormap(DisplayHandle, ScreenNo);
// Create the foster parent
- FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 4, UIntPtr.Zero, UIntPtr.Zero);
+ // it is important that border_width is kept in synch with the other XCreateWindow calls
+ FosterParent=XCreateSimpleWindow(DisplayHandle, RootWindow, 0, 0, 1, 1, 0, UIntPtr.Zero, UIntPtr.Zero);
if (FosterParent==IntPtr.Zero) {
Console.WriteLine("XplatUIX11 Constructor failed to create FosterParent");
}
SetupAtoms();
// Grab atom changes off the root window to catch certain WM events
- XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int)EventMask.PropertyChangeMask));
+ XSelectInput(DisplayHandle, RootWindow, new IntPtr ((int) (EventMask.PropertyChangeMask | Keyboard.KeyEventMask)));
// Handle any upcoming errors
ErrorHandler = new XErrorHandler(HandleError);
"_XEMBED_INFO",
"_MOTIF_WM_HINTS",
"_NET_WM_STATE_SKIP_TASKBAR",
- //"_NET_WM_STATE_ABOVE",
- //"_NET_WM_STATE_MODAL",
+ "_NET_WM_STATE_ABOVE",
+ "_NET_WM_STATE_MODAL",
"_NET_WM_CONTEXT_HELP",
"_NET_WM_WINDOW_OPACITY",
//"_NET_WM_WINDOW_TYPE_DESKTOP",
//"_NET_WM_WINDOW_TYPE_TOOLBAR",
//"_NET_WM_WINDOW_TYPE_MENU",
"_NET_WM_WINDOW_TYPE_UTILITY",
- //"_NET_WM_WINDOW_TYPE_DIALOG",
+ "_NET_WM_WINDOW_TYPE_DIALOG",
//"_NET_WM_WINDOW_TYPE_SPLASH",
"_NET_WM_WINDOW_TYPE_NORMAL",
"CLIPBOARD",
_XEMBED_INFO = atoms [off++];
_MOTIF_WM_HINTS = atoms [off++];
_NET_WM_STATE_SKIP_TASKBAR = atoms [off++];
- //_NET_WM_STATE_ABOVE = atoms [off++];
- //_NET_WM_STATE_MODAL = atoms [off++];
+ _NET_WM_STATE_ABOVE = atoms [off++];
+ _NET_WM_STATE_MODAL = atoms [off++];
_NET_WM_CONTEXT_HELP = atoms [off++];
_NET_WM_WINDOW_OPACITY = atoms [off++];
//_NET_WM_WINDOW_TYPE_DESKTOP = atoms [off++];
//_NET_WM_WINDOW_TYPE_TOOLBAR = atoms [off++];
//_NET_WM_WINDOW_TYPE_MENU = atoms [off++];
_NET_WM_WINDOW_TYPE_UTILITY = atoms [off++];
- //_NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
+ _NET_WM_WINDOW_TYPE_DIALOG = atoms [off++];
//_NET_WM_WINDOW_TYPE_SPLASH = atoms [off++];
_NET_WM_WINDOW_TYPE_NORMAL = atoms [off++];
CLIPBOARD = atoms [off++];
return (ex & (int)exws) == (int)exws;
}
+ internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd)
+ {
+ return TranslateClientRectangleToXClientRectangle (hwnd, Control.FromHandle (hwnd.Handle));
+ }
+
+ internal static Rectangle TranslateClientRectangleToXClientRectangle (Hwnd hwnd, Control ctrl)
+ {
+ /*
+ * If this is a form with no window manager, X is handling all the border and caption painting
+ * so remove that from the area (since the area we set of the window here is the part of the window
+ * we're painting in only)
+ */
+ Rectangle rect = hwnd.ClientRect;
+ Form form = ctrl as Form;
+ CreateParams cp = null;
+
+ if (form != null)
+ cp = form.GetCreateParams ();
+
+ if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
+ Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
+ Rectangle xrect = rect;
+
+ xrect.Y -= borders.top;
+ xrect.X -= borders.left;
+ xrect.Width += borders.left + borders.right;
+ xrect.Height += borders.top + borders.bottom;
+
+ rect = xrect;
+ }
+
+ if (rect.Width < 1 || rect.Height < 1) {
+ rect.Width = 1;
+ rect.Height = 1;
+ rect.X = -5;
+ rect.Y = -5;
+ }
+
+ return rect;
+ }
+
+ internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp)
+ {
+ return TranslateWindowSizeToXWindowSize (cp, new Size (cp.Width, cp.Height));
+ }
+
+ internal static Size TranslateWindowSizeToXWindowSize (CreateParams cp, Size size)
+ {
+ /*
+ * If this is a form with no window manager, X is handling all the border and caption painting
+ * so remove that from the area (since the area we set of the window here is the part of the window
+ * we're painting in only)
+ */
+ Form form = cp.control as Form;
+ if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
+ Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
+ Size xrect = size;
+
+ xrect.Width -= borders.left + borders.right;
+ xrect.Height -= borders.top + borders.bottom;
+
+ size = xrect;
+ }
+ if (size.Height == 0)
+ size.Height = 1;
+ if (size.Width == 0)
+ size.Width = 1;
+ return size;
+ }
+
+ internal static Size TranslateXWindowSizeToWindowSize (CreateParams cp, int xWidth, int xHeight)
+ {
+ /*
+ * If this is a form with no window manager, X is handling all the border and caption painting
+ * so remove that from the area (since the area we set of the window here is the part of the window
+ * we're painting in only)
+ */
+ Size rect = new Size (xWidth, xHeight);
+ Form form = cp.control as Form;
+ if (form != null && (form.window_manager == null && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW))) {
+ Hwnd.Borders borders = Hwnd.GetBorders (cp, null);
+ Size xrect = rect;
+
+ xrect.Width += borders.left + borders.right;
+ xrect.Height += borders.top + borders.bottom;
+
+ rect = xrect;
+ }
+ return rect;
+ }
+
+ internal static Point GetTopLevelWindowLocation (Hwnd hwnd)
+ {
+ IntPtr dummy;
+ int x, y;
+ Hwnd.Borders frame;
+
+ XTranslateCoordinates (DisplayHandle, hwnd.whole_window, RootWindow, 0, 0, out x, out y, out dummy);
+ frame = FrameExtents (hwnd.whole_window);
+
+ x -= frame.left;
+ y -= frame.top;
+
+ return new Point (x, y);
+ }
+
private void DeriveStyles(int Style, int ExStyle, out FormBorderStyle border_style, out bool border_static, out TitleStyle title_style, out int caption_height, out int tool_caption_height) {
caption_height = 0;
int[] atoms;
int atom_count;
Rectangle client_rect;
-
+ Form form;
+ IntPtr window_type;
+ bool hide_from_taskbar;
+ IntPtr transient_for_parent;
+
// Windows we manage ourselves don't need WM window styles.
if (cp.HasWindowManager && !cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
return;
mwmHints = new MotifWmHints();
functions = 0;
decorations = 0;
+ window_type = _NET_WM_WINDOW_TYPE_NORMAL;
+ transient_for_parent = IntPtr.Zero;
mwmHints.flags = (IntPtr)(MotifFlags.Functions | MotifFlags.Decorations);
mwmHints.functions = (IntPtr)0;
mwmHints.decorations = (IntPtr)0;
- if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)
- || !StyleSet (cp.Style, WindowStyles.WS_CAPTION | WindowStyles.WS_BORDER | WindowStyles.WS_DLGFRAME)) {
+ form = cp.control as Form;
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
/* tool windows get no window manager
- decorations, and neither do windows
- which lack CAPTION/BORDER/DLGFRAME
- styles.
+ decorations.
*/
/* just because the window doesn't get any decorations doesn't
MotifFunctions.Maximize, changing the windowstate to Maximized
is ignored by metacity. */
functions |= MotifFunctions.Move | MotifFunctions.Resize | MotifFunctions.Minimize | MotifFunctions.Maximize;
- }
- else {
+ } else if (form != null && form.FormBorderStyle == FormBorderStyle.None) {
+ functions |= MotifFunctions.All;
+ } else {
if (StyleSet (cp.Style, WindowStyles.WS_CAPTION)) {
functions |= MotifFunctions.Move;
decorations |= MotifDecorations.Title | MotifDecorations.Menu;
if ((functions & MotifFunctions.Resize) == 0) {
hwnd.fixed_size = true;
- XplatUI.SetWindowMinMax(hwnd.Handle, new Rectangle(cp.X, cp.Y, cp.Width, cp.Height), new Size(cp.Width, cp.Height), new Size(cp.Width, cp.Height));
+ Rectangle fixed_rectangle = new Rectangle (cp.X, cp.Y, cp.Width, cp.Height);
+ SetWindowMinMax(hwnd.Handle, fixed_rectangle, fixed_rectangle.Size, fixed_rectangle.Size, cp);
} else {
hwnd.fixed_size = false;
}
mwmHints.functions = (IntPtr)functions;
mwmHints.decorations = (IntPtr)decorations;
+#if debug
+ Console.WriteLine ("SetWMStyles ({0}, {1}) functions = {2}, decorations = {3}", hwnd, cp, functions, decorations);
+#endif
+
+ if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
+ // and get those windows in front of their parents
+ window_type = _NET_WM_WINDOW_TYPE_UTILITY;
+ } else if (form != null && form.Modal) {
+ window_type = _NET_WM_WINDOW_TYPE_DIALOG;
+ } else {
+ window_type = _NET_WM_WINDOW_TYPE_NORMAL;
+ }
+
+ if (!cp.IsSet (WindowExStyles.WS_EX_APPWINDOW)) {
+ hide_from_taskbar = true;
+ } else if (cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW) && form != null && form.Parent != null && !form.ShowInTaskbar) {
+ hide_from_taskbar = true;
+ } else {
+ hide_from_taskbar = false;
+ }
+
+ if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ if (form != null && !hwnd.reparented) {
+ if (form.Owner != null && form.Owner.Handle != IntPtr.Zero) {
+ Hwnd owner_hwnd = Hwnd.ObjectFromHandle (form.Owner.Handle);
+ if (owner_hwnd != null)
+ transient_for_parent = owner_hwnd.whole_window;
+ }
+ }
+ }
+ if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
+ transient_for_parent = hwnd.parent.whole_window;
+ }
+
FormWindowState current_state = GetWindowState (hwnd.Handle);
if (current_state == (FormWindowState)(-1))
current_state = FormWindowState.Normal;
- client_rect = hwnd.ClientRect;
+ client_rect = TranslateClientRectangleToXClientRectangle (hwnd);
+
lock (XlibLock) {
atom_count = 0;
- // needed! map toolwindows to _NET_WM_WINDOW_TYPE_UTILITY to make newer metacity versions happy
- // and get those windows in front of their parents
- if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
- atoms [0] = _NET_WM_WINDOW_TYPE_UTILITY.ToInt32 ();
- XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE,
- (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
-
- Form f = Control.FromHandle(hwnd.Handle) as Form;
- if (f != null && !hwnd.reparented) {
- if (f.Owner != null && f.Owner.Handle != IntPtr.Zero) {
- Hwnd owner_hwnd = Hwnd.ObjectFromHandle(f.Owner.Handle);
- if (owner_hwnd != null)
- XSetTransientForHint(DisplayHandle, hwnd.whole_window,
- owner_hwnd.whole_window);
- }
- }
- }
-
+ atoms [0] = window_type.ToInt32 ();
+ XChangeProperty (DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+
XChangeProperty(DisplayHandle, hwnd.whole_window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropertyMode.Replace, ref mwmHints, 5);
- if (StyleSet (cp.Style, WindowStyles.WS_POPUP) && (hwnd.parent != null) && (hwnd.parent.whole_window != IntPtr.Zero)) {
- atoms[0] = _NET_WM_WINDOW_TYPE_NORMAL.ToInt32();
- XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_WINDOW_TYPE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
- XSetTransientForHint(DisplayHandle, hwnd.whole_window, hwnd.parent.whole_window);
- } else if (!ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_APPWINDOW)) {
- /* this line keeps the window from showing up in gnome's taskbar */
- atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
- }
- if ((client_rect.Width < 1) || (client_rect.Height < 1)) {
- XMoveResizeWindow(DisplayHandle, hwnd.client_window, -5, -5, 1, 1);
- } else {
- XMoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+ if (transient_for_parent != IntPtr.Zero) {
+ XSetTransientForHint (DisplayHandle, hwnd.whole_window, transient_for_parent);
}
- if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOOLWINDOW)) {
+ MoveResizeWindow(DisplayHandle, hwnd.client_window, client_rect.X, client_rect.Y, client_rect.Width, client_rect.Height);
+
+ if (hide_from_taskbar) {
+ /* this line keeps the window from showing up in gnome's taskbar */
atoms[atom_count++] = _NET_WM_STATE_SKIP_TASKBAR.ToInt32();
}
/* we need to add these atoms in the
atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_HORZ.ToInt32();
atoms[atom_count++] = _NET_WM_STATE_MAXIMIZED_VERT.ToInt32();
}
+
+ if (form != null && form.Modal) {
+ atoms[atom_count++] = _NET_WM_STATE_MODAL.ToInt32 ();
+ }
+
XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, atom_count);
atom_count = 0;
}
}
- private void FrameExtents(IntPtr window, out int left, out int top) {
- IntPtr actual_atom;
- int actual_format;
- IntPtr nitems;
- IntPtr bytes_after;
- IntPtr prop = IntPtr.Zero;
-
- XGetWindowProperty(DisplayHandle, window, _NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
- if (((long)nitems == 4) && (prop != IntPtr.Zero)) {
- left = Marshal.ReadIntPtr(prop, 0).ToInt32();
- //right = Marshal.ReadIntPtr(prop, IntPtr.Size).ToInt32();
- top = Marshal.ReadIntPtr(prop, IntPtr.Size * 2).ToInt32();
- //bottom = Marshal.ReadIntPtr(prop, IntPtr.Size * 3).ToInt32();
- } else {
- left = 0;
- top = 0;
- }
-
+ private static Hwnd.Borders FrameExtents (IntPtr window)
+ {
+ IntPtr actual_atom;
+ int actual_format;
+ IntPtr nitems;
+ IntPtr bytes_after;
+ IntPtr prop = IntPtr.Zero;
+ Hwnd.Borders rect = new Hwnd.Borders ();
+
+ XGetWindowProperty (DisplayHandle, window, _NET_FRAME_EXTENTS, IntPtr.Zero, new IntPtr (16), false, (IntPtr)Atom.XA_CARDINAL, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
if (prop != IntPtr.Zero) {
- XFree(prop);
+ if (nitems.ToInt32 () == 4) {
+ rect.left = Marshal.ReadInt32 (prop, 0);
+ rect.right = Marshal.ReadInt32 (prop, IntPtr.Size);
+ rect.top = Marshal.ReadInt32 (prop, 2 * IntPtr.Size);
+ rect.bottom = Marshal.ReadInt32 (prop, 3 * IntPtr.Size);
+ }
+ XFree (prop);
}
- return;
+
+ return rect;
}
private void AddConfigureNotify (XEvent xevent) {
hwnd = Hwnd.GetObjectFromWindow(xevent.ConfigureEvent.window);
// Don't waste time
- if (hwnd == null) {
+ if (hwnd == null || hwnd.zombie) {
return;
}
-
- if ((xevent.ConfigureEvent.window == hwnd.whole_window) && (xevent.ConfigureEvent.window == xevent.ConfigureEvent.xevent)) {
- if (!hwnd.reparented) {
- hwnd.x = xevent.ConfigureEvent.x;
- hwnd.y = xevent.ConfigureEvent.y;
- } else {
- // This sucks ass, part 1
- // Every WM does the ConfigureEvents of toplevel windows different, so there's
- // no standard way of getting our adjustment.
- // The code below is needed for KDE and FVWM, the 'whacky_wm' part is for metacity
- // Several other WMs do their decorations different yet again and we fail to deal
- // with that, since I couldn't find any frigging commonality between them.
- // The only sane WM seems to be KDE
-
- if (!xevent.ConfigureEvent.send_event) {
- IntPtr dummy_ptr;
-
- XTranslateCoordinates(DisplayHandle, hwnd.whole_window, RootWindow, -xevent.ConfigureEvent.x, -xevent.ConfigureEvent.y, out hwnd.x, out hwnd.y, out dummy_ptr);
- } else {
- // This is a synthetic event, coordinates are in root space
- hwnd.x = xevent.ConfigureEvent.x;
- hwnd.y = xevent.ConfigureEvent.y;
- if (hwnd.whacky_wm) {
- int frame_left;
- int frame_top;
-
- FrameExtents(hwnd.whole_window, out frame_left, out frame_top);
- hwnd.x -= frame_left;
- hwnd.y -= frame_top;
- }
- }
+ 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
- hwnd.width = xevent.ConfigureEvent.width;
- hwnd.height = xevent.ConfigureEvent.height;
+ 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;
+#if debug
+ Console.WriteLine ("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));
+#endif
lock (hwnd.configure_lock) {
if (!hwnd.configure_pending) {
hwnd.Queue.EnqueueLocked (xevent);
}
private int NextTimeout (ArrayList timers, DateTime now) {
- int timeout = Int32.MaxValue;
+ int timeout = 0;
foreach (Timer timer in timers) {
int next = (int) (timer.Expires - now).TotalMilliseconds;
timer = (Timer) timers [i];
- if (timer.Enabled && timer.Expires <= now) {
+ if (timer.Enabled && timer.Expires <= now && !timer.Busy) {
+ timer.Busy = true;
timer.Update (now);
timer.FireTick ();
+ timer.Busy = false;
}
}
}
private void MapWindow(Hwnd hwnd, WindowType windows) {
if (!hwnd.mapped) {
- if (Control.FromHandle(hwnd.Handle) is Form)
- SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+ Form f = Control.FromHandle(hwnd.Handle) as Form;
+ if (f != null) {
+ if (f.WindowState == FormWindowState.Normal) {
+ f.waiting_showwindow = true;
+ SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, (IntPtr)1, IntPtr.Zero);
+ }
+ }
// it's possible that our Hwnd is no
// longer valid after making that
if (hwnd.zombie)
return;
- bool need_to_wait = false;
-
if ((windows & WindowType.Whole) != 0) {
XMapWindow(DisplayHandle, hwnd.whole_window);
}
if ((windows & WindowType.Client) != 0) {
XMapWindow(DisplayHandle, hwnd.client_window);
-
- need_to_wait = true;
}
hwnd.mapped = true;
- if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
+ if (f != null && f.waiting_showwindow)
WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
}
}
private void UnmapWindow(Hwnd hwnd, WindowType windows) {
if (hwnd.mapped) {
- if (Control.FromHandle(hwnd.Handle) is Form)
- SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
+ Form f = null;
+ if (Control.FromHandle(hwnd.Handle) is Form) {
+ f = Control.FromHandle(hwnd.Handle) as Form;
+ if (f.WindowState == FormWindowState.Normal) {
+ f.waiting_showwindow = true;
+ SendMessage(hwnd.Handle, Msg.WM_SHOWWINDOW, IntPtr.Zero, IntPtr.Zero);
+ }
+ }
// it's possible that our Hwnd is no
// longer valid after making that
// SendMessage call, so check here.
+ // FIXME: it is likely wrong, as it has already sent WM_SHOWWINDOW
if (hwnd.zombie)
return;
- bool need_to_wait = false;
-
if ((windows & WindowType.Client) != 0) {
XUnmapWindow(DisplayHandle, hwnd.client_window);
-
- need_to_wait = true;
}
if ((windows & WindowType.Whole) != 0) {
XUnmapWindow(DisplayHandle, hwnd.whole_window);
hwnd.mapped = false;
- if (need_to_wait && Control.FromHandle(hwnd.Handle) is Form)
+ if (f != null && f.waiting_showwindow)
WaitForHwndMessage (hwnd, Msg.WM_SHOWWINDOW);
}
}
XNextEvent (DisplayHandle, ref xevent);
- if (xevent.AnyEvent.type == XEventName.KeyPress) {
- if (XFilterEvent(ref xevent, FosterParent)) {
+ 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;
+#if debug
+ Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
+#endif
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);
}
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:
break;
case XEventName.PropertyNotify:
+#if debug
+ Console.WriteLine ("UpdateMessageQueue (), got Event: {0}", xevent.ToString ());
+#endif
if (xevent.PropertyEvent.atom == _NET_ACTIVE_WINDOW) {
IntPtr actual_atom;
int actual_format;
// 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 (NativeWindow.FindWindow(ActiveWindow) != null) {
+ if (NativeWindow.FromHandle(ActiveWindow) != null) {
if (ActiveWindow != (IntPtr)ModalWindows.Peek()) {
Activate((IntPtr)ModalWindows.Peek());
}
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;
return Parent;
}
- private int HandleError(IntPtr display, ref XErrorEvent error_event) {
+ private int HandleError (IntPtr display, ref XErrorEvent error_event)
+ {
+ // we need to workaround a problem with the
+ // ordering of destruction of Drawables and
+ // Pictures that exists between cairo and
+ // RENDER on the server.
+ if (error_event.request_code == (XRequest)render_major_opcode
+ && error_event.minor_code == 7 /* X_RenderFreePicture from render.h */
+ && error_event.error_code == render_first_error + 1 /* BadPicture from render.h */) {
+ return 0;
+ }
+
if (ErrorExceptions) {
- throw new XException(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code);
+ XUngrabPointer (display, IntPtr.Zero);
+ throw new XException (error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code);
} else {
- Console.WriteLine("X11 Error encountered: {0}{1}\n", XException.GetMessage(error_event.display, error_event.resourceid, error_event.serial, error_event.error_code, error_event.request_code, error_event.minor_code), Environment.StackTrace);
+ Console.WriteLine("X11 Error encountered: {0}{1}\n",
+ XException.GetMessage (error_event.display, error_event.resourceid,
+ error_event.serial, error_event.error_code,
+ error_event.request_code, error_event.minor_code),
+ Environment.StackTrace);
}
return 0;
}
IntPtr ptr;
Rectangle rect;
- rect = hwnd.DefaultClientRect;
+ rect = new Rectangle (0, 0, hwnd.Width, hwnd.Height);
ncp = new XplatUIWin32.NCCALCSIZE_PARAMS();
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(ncp));
ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(ptr, typeof(XplatUIWin32.NCCALCSIZE_PARAMS));
Marshal.FreeHGlobal(ptr);
- // FIXME - debug this with Menus
rect = new Rectangle(ncp.rgrc1.left, ncp.rgrc1.top, ncp.rgrc1.right - ncp.rgrc1.left, ncp.rgrc1.bottom - ncp.rgrc1.top);
hwnd.ClientRect = rect;
+
+ rect = TranslateClientRectangleToXClientRectangle (hwnd);
if (hwnd.visible) {
- if ((rect.Width < 1) || (rect.Height < 1)) {
- XMoveResizeWindow(DisplayHandle, hwnd.client_window, -5, -5, 1, 1);
- } else {
- XMoveResizeWindow(DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
- }
+ MoveResizeWindow (DisplayHandle, hwnd.client_window, rect.X, rect.Y, rect.Width, rect.Height);
}
- AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
+ AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
}
#endregion // Private Methods
#region Public Properties
- internal override int Caption {
+ internal override int CaptionHeight {
get {
return 19;
}
get {
return new Size(4, 4);
}
- }
+ }
internal override Size FrameBorderSize {
get {
get {
return new Size (WorkingArea.Width, WorkingArea.Height);
}
- }
+ }
- internal override Size MinimizedWindowSize {
+ internal override bool MenuAccessKeysUnderlined {
get {
- return new Size(1, 1);
+ return false;
}
- }
+ }
internal override Size MinimizedWindowSpacingSize {
get {
internal override Size MinimumWindowSize {
get {
- return new Size(1, 1);
+ return new Size(110, 22);
}
}
- internal override Size MinWindowTrackSize {
- get {
- return new Size(1, 1);
- }
+ internal override Size MinimumFixedToolWindowSize {
+ get { return new Size (27, 22); }
}
+ internal override Size MinimumSizeableToolWindowSize {
+ get { return new Size (37, 22); }
+ }
+
+ internal override Size MinimumNoBorderWindowSize {
+ get { return new Size (2, 2); }
+ }
+
internal override Keys ModifierKeys {
get {
return Keyboard.ModifierKeys;
#endregion // Public properties
#region Public Static Methods
+ internal override void RaiseIdle (EventArgs e)
+ {
+ if (Idle != null)
+ Idle (this, e);
+ }
+
internal override IntPtr InitializeDriver() {
lock (this) {
if (DisplayHandle==IntPtr.Zero) {
lock (XlibLock) {
if (true /* the window manager supports NET_ACTIVE_WINDOW */) {
SendNetWMMessage(hwnd.whole_window, _NET_ACTIVE_WINDOW, (IntPtr)1, IntPtr.Zero, IntPtr.Zero);
+ XEventQueue q = null;
+ lock (unattached_timer_list) {
+ foreach (Timer t in unattached_timer_list) {
+ if (q == null)
+ q= (XEventQueue) MessageQueues [Thread.CurrentThread];
+ t.thread = q.Thread;
+ q.timer_list.Add (t);
+ }
+ unattached_timer_list.Clear ();
+ }
}
// else {
// XRaiseWindow(DisplayHandle, handle);
}
}
- internal override bool CalculateWindowRect(ref Rectangle ClientRect, int Style, int ExStyle, Menu menu, out Rectangle WindowRect) {
- FormBorderStyle border_style;
- TitleStyle title_style;
- bool border_static;
- int caption_height;
- int tool_caption_height;
-
- DeriveStyles(Style, ExStyle, out border_style, out border_static, out title_style,
- out caption_height, out tool_caption_height);
-
- WindowRect = Hwnd.GetWindowRectangle(border_style, border_static, menu, title_style,
- caption_height, tool_caption_height,
- ClientRect);
+ internal override bool CalculateWindowRect(ref Rectangle ClientRect, CreateParams cp, Menu menu, out Rectangle WindowRect) {
+ WindowRect = Hwnd.GetWindowRectangle (cp, menu, ClientRect);
return true;
}
{
XSetWindowAttributes Attributes;
Hwnd hwnd;
+ Hwnd parent_hwnd = null;
int X;
int Y;
int Width;
IntPtr ParentHandle;
IntPtr WholeWindow;
IntPtr ClientWindow;
- Rectangle ClientRect;
SetWindowValuemask ValueMask;
int[] atoms;
if (Height<1) Height=1;
if (cp.Parent != IntPtr.Zero) {
- ParentHandle = Hwnd.ObjectFromHandle(cp.Parent).client_window;
+ 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 if (StyleSet (cp.Style, WindowStyles.WS_POPUP)) {
- ParentHandle=RootWindow;
} else {
- // Default position on screen, if window manager doesn't place us somewhere else
- if (X<0) X = 50;
- if (Y<0) Y = 50;
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;
hwnd.width = Width;
hwnd.height = Height;
hwnd.parent = Hwnd.ObjectFromHandle(cp.Parent);
- hwnd.initial_ex_style = (WindowExStyles) cp.ExStyle;
+ hwnd.initial_style = cp.WindowStyle;
+ hwnd.initial_ex_style = cp.WindowExStyle;
if (StyleSet (cp.Style, WindowStyles.WS_DISABLED)) {
hwnd.enabled = false;
}
- ClientRect = hwnd.ClientRect;
ClientWindow = IntPtr.Zero;
+ Size XWindowSize = TranslateWindowSizeToXWindowSize (cp);
+ Rectangle XClientRect = TranslateClientRectangleToXClientRectangle (hwnd, cp.control);
+
lock (XlibLock) {
- WholeWindow = XCreateWindow(DisplayHandle, ParentHandle, X, Y, Width, Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, IntPtr.Zero, new UIntPtr ((uint)ValueMask), ref Attributes);
+ 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);
ValueMask = SetWindowValuemask.ColorMap;
Attributes.colormap = CustomColormap;
}
- ClientWindow = XCreateWindow(DisplayHandle, WholeWindow, ClientRect.X, ClientRect.Y, ClientRect.Width, ClientRect.Height, 0, (int)CreateWindowArgs.CopyFromParent, (int)CreateWindowArgs.InputOutput, CustomVisual, new UIntPtr ((uint)ValueMask), ref Attributes);
+ 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 DriverDebug || DriverDebugCreate
Console.WriteLine("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);
#endif
-
+
if (!StyleSet (cp.Style, WindowStyles.WS_CHILD)) {
if ((X != unchecked((int)0x80000000)) && (Y != unchecked((int)0x80000000))) {
XSizeHints hints;
}
lock (XlibLock) {
- XSelectInput(DisplayHandle, hwnd.whole_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | EventMask.PropertyChangeMask)));
+ 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)));
+ XSelectInput(DisplayHandle, hwnd.client_window, new IntPtr ((int)(SelectInputMask | EventMask.StructureNotifyMask | Keyboard.KeyEventMask)));
}
if (ExStyleSet (cp.ExStyle, WindowExStyles.WS_EX_TOPMOST)) {
return cursor;
}
+ internal override Bitmap DefineStdCursorBitmap (StdCursor id) {
+ CursorFontShape shape;
+ string name;
+ IntPtr theme;
+ int size;
+ Bitmap bmp = null;
+
+ try {
+ shape = StdCursorToFontShape (id);
+ name = shape.ToString ().Replace ("XC_", string.Empty);
+ size = XcursorGetDefaultSize (DisplayHandle);
+ theme = XcursorGetTheme (DisplayHandle);
+ IntPtr images_ptr = XcursorLibraryLoadImages (name, theme, size);
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, id={0}, #id={1}, name{2}, size={3}, theme: {4}, images_ptr={5}", id, (int) id, name, size, Marshal.PtrToStringAnsi (theme), images_ptr);
+#endif
+
+ if (images_ptr == IntPtr.Zero) {
+ return null;
+ }
+
+ XcursorImages images = (XcursorImages) Marshal.PtrToStructure (images_ptr, typeof (XcursorImages));
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, cursor has {0} images", images.nimage);
+#endif
+
+ if (images.nimage > 0) {
+ // We only care about the first image.
+ XcursorImage image = (XcursorImage)Marshal.PtrToStructure (Marshal.ReadIntPtr (images.images), typeof (XcursorImage));
+
+#if debug
+ Console.WriteLine ("DefineStdCursorBitmap, loaded image <size={0}, height={1}, width={2}, xhot={3}, yhot={4}, pixels={5}", image.size, image.height, image.width, image.xhot, image.yhot, image.pixels);
+#endif
+ // A sanity check
+ if (image.width <= short.MaxValue && image.height <= short.MaxValue) {
+ int [] pixels = new int [image.width * image.height];
+ Marshal.Copy (image.pixels, pixels, 0, pixels.Length);
+ bmp = new Bitmap (image.width, image.height);
+ for (int w = 0; w < image.width; w++) {
+ for (int h = 0; h < image.height; h++) {
+ bmp.SetPixel (w, h, Color.FromArgb (pixels [h * image.width + w]));
+ }
+ }
+ }
+ }
+
+ XcursorImagesDestroy (images_ptr);
+
+ } catch (DllNotFoundException ex) {
+ Console.WriteLine ("Could not load libXcursor: " + ex.Message + " (" + ex.GetType ().Name + ")");
+ return null;
+ }
+
+ return bmp;
+ }
+
+
internal override IntPtr DefineStdCursor(StdCursor id) {
CursorFontShape shape;
IntPtr cursor;
+ shape = StdCursorToFontShape (id);
+
+ lock (XlibLock) {
+ cursor = XCreateFontCursor(DisplayHandle, shape);
+ }
+ return cursor;
+ }
+
+ internal static CursorFontShape StdCursorToFontShape (StdCursor id) {
+ CursorFontShape shape;
// FIXME - define missing shapes
switch (id) {
}
default: {
- return IntPtr.Zero;
+ shape = (CursorFontShape) 0;
+ break;
}
}
-
- lock (XlibLock) {
- cursor = XCreateFontCursor(DisplayHandle, shape);
- }
- return cursor;
+
+ return shape;
}
internal override IntPtr DefWndProc(ref Message msg) {
switch ((Msg)msg.Msg) {
+
+ case Msg.WM_IME_COMPOSITION:
+ string s = Keyboard.GetCompositionString ();
+ foreach (char c in s)
+ SendMessage (msg.HWnd, Msg.WM_IME_CHAR, (IntPtr) c, msg.LParam);
+ return IntPtr.Zero;
+
+ case Msg.WM_IME_CHAR:
+ // On Windows API it sends two WM_CHAR messages for each byte, but
+ // I wonder if it is worthy to emulate it (also no idea how to
+ // reconstruct those bytes into chars).
+ SendMessage (msg.HWnd, Msg.WM_CHAR, msg.WParam, msg.LParam);
+ return IntPtr.Zero;
+
case Msg.WM_PAINT: {
Hwnd hwnd;
return IntPtr.Zero;
}
+ case Msg.WM_NCCALCSIZE: {
+ Hwnd hwnd;
+
+ if (msg.WParam == (IntPtr)1) {
+ hwnd = Hwnd.GetObjectFromWindow (msg.HWnd);
+
+ XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+ ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (msg.LParam, typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+
+ // Add all the stuff X is supposed to draw.
+ Control ctrl = Control.FromHandle (hwnd.Handle);
+
+ if (ctrl != null) {
+ Hwnd.Borders rect = Hwnd.GetBorders (ctrl.GetCreateParams (), null);
+
+ ncp.rgrc1.top += rect.top;
+ ncp.rgrc1.bottom -= rect.bottom;
+ ncp.rgrc1.left += rect.left;
+ ncp.rgrc1.right -= rect.right;
+
+ Marshal.StructureToPtr (ncp, msg.LParam, true);
+ }
+ }
+
+ return IntPtr.Zero;
+ }
+
case Msg.WM_CONTEXTMENU: {
Hwnd hwnd;
#if DriverDebug || DriverDebugDestroy
Console.WriteLine ("XDestroyWindow (whole_window = {0:X})", hwnd.whole_window.ToInt32());
#endif
+ Keyboard.DestroyICForWindow (hwnd.whole_window);
XDestroyWindow(DisplayHandle, hwnd.whole_window);
}
else if (hwnd.client_window != IntPtr.Zero) {
#if DriverDebug || DriverDebugDestroy
Console.WriteLine ("XDestroyWindow (client_window = {0:X})", hwnd.client_window.ToInt32());
#endif
+ Keyboard.DestroyICForWindow (hwnd.client_window);
XDestroyWindow(DisplayHandle, hwnd.client_window);
}
internal override void DrawReversibleLine(Point start, Point end, Color backColor)
{
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
IntPtr gc = GetReversibleScreenGC (backColor);
XDrawLine (DisplayHandle, RootWindow, gc, start.X, start.Y, end.X, end.Y);
internal override void DrawReversibleFrame (Rectangle rectangle, Color backColor, FrameStyle style)
{
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
IntPtr gc = GetReversibleScreenGC (backColor);
if (rectangle.Width < 0) {
internal override void FillReversibleRectangle (Rectangle rectangle, Color backColor)
{
+ if (backColor.GetBrightness() < 0.5)
+ backColor = Color.FromArgb(255 - backColor.R, 255 - backColor.G, 255 - backColor.B);
+
IntPtr gc = GetReversibleScreenGC (backColor);
if (rectangle.Width < 0) {
XFreeGC(DisplayHandle, gc);
}
- internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width) {
+ internal override void DrawReversibleRectangle(IntPtr handle, Rectangle rect, int line_width)
+ {
IntPtr gc;
Control control = Control.FromHandle(handle);
}
return IntPtr.Zero;
}
+
+ // This is a nop on win32 and x11
+ internal override IntPtr GetPreviousWindow(IntPtr handle) {
+ return handle;
+ }
internal override void GetCursorPos(IntPtr handle, out int x, out int y) {
IntPtr use_handle;
internal override bool GetFontMetrics(Graphics g, Font font, out int ascent, out int descent) {
- return GetFontMetrics(g.GetHdc(), font.ToHfont(), out ascent, out descent);
+ FontFamily ff = font.FontFamily;
+ ascent = ff.GetCellAscent (font.Style);
+ descent = ff.GetCellDescent (font.Style);
+ return true;
}
internal override Point GetMenuOrigin(IntPtr handle) {
// 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) {
+ if (hwnd == null || hwnd.zombie && xevent.AnyEvent.type != XEventName.ClientMessage) {
#if DriverDebug || DriverDebugDestroy
Console.WriteLine("GetMessage(): Got message {0} for non-existent or already destroyed window {1:X}", xevent.type, xevent.AnyEvent.window.ToInt32());
#endif
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: {
- if (Dnd.InDrag ())
- Dnd.HandleKeyPress (ref xevent);
Keyboard.KeyEvent (FocusWindow, xevent, ref msg);
break;
}
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);
}
- // TODO: For WM_NCLBUTTONDOWN wParam specifies a hit-test value not the virtual keys down
- msg.wParam=GetMousewParam(0);
break;
}
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);
}
- msg.wParam=GetMousewParam(0);
break;
}
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);
}
- msg.wParam=GetMousewParam(0);
break;
}
}
case XEventName.ButtonRelease: {
- if (Dnd.InDrag()) {
- if (Dnd.HandleButtonRelease (ref xevent)) {
- break;
- }
- // Allow the LBUTTONUP message to get through
- }
-
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);
+ msg.wParam = GetMousewParam (0);
break;
}
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);
+ msg.wParam = GetMousewParam (0);
break;
}
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);
+ msg.wParam = GetMousewParam (0);
break;
}
Console.WriteLine("GetMessage(): Window {0:X} MotionNotify x={1} y={2}", client ? hwnd.client_window.ToInt32() : hwnd.whole_window.ToInt32(), xevent.MotionEvent.x, xevent.MotionEvent.y);
#endif
- if (Dnd.HandleMotionNotify (ref xevent))
- goto ProcessNextMessage;
if (Grab.Hwnd != IntPtr.Zero) {
msg.hwnd = Grab.Hwnd;
} else {
- NativeWindow.WndProc(msg.hwnd, Msg.WM_SETCURSOR, msg.hwnd, (IntPtr)HitTest.HTCLIENT);
+ 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.lParam = (IntPtr)(mouse_position.Y << 16 | mouse_position.X);
}
- // The hit test is sent in screen coordinates
- XTranslateCoordinates (DisplayHandle, xevent.AnyEvent.window, RootWindow,
- 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.client_window, Msg.WM_NCHITTEST,
- IntPtr.Zero, msg.lParam).ToInt32 ();
+ 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;
if (!hwnd.Enabled) {
goto ProcessNextMessage;
}
- if (xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) {
+ if (xevent.CrossingEvent.mode == NotifyMode.NotifyGrab || LastPointerWindow == xevent.CrossingEvent.window ||
+ hwnd.client_window == IntPtr.Zero) {
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)
+ if (child_control.Bounds.Contains (enter_loc))
+ goto ProcessNextMessage;
+ }
+
+ 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;
}
if ((xevent.CrossingEvent.mode != NotifyMode.NotifyNormal) || (xevent.CrossingEvent.window != hwnd.client_window)) {
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;
case XEventName.ReparentNotify: {
if (hwnd.parent == null) { // Toplevel
if ((xevent.ReparentEvent.parent != IntPtr.Zero) && (xevent.ReparentEvent.window == hwnd.whole_window)) {
- // 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;
- XGetGeometry(DisplayHandle, XGetParent(hwnd.whole_window), out dummy_ptr, out new_x, out new_y, out dummy_int, out dummy_int, out dummy_int, out dummy_int);
- FrameExtents(hwnd.whole_window, 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;
- }
+ // 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;
#if DriverDebugExtra
Console.WriteLine("GetMessage(): Window {0:X} ConfigureNotify x={1} y={2} width={3} height={4}", hwnd.client_window.ToInt32(), xevent.ConfigureEvent.x, xevent.ConfigureEvent.y, xevent.ConfigureEvent.width, xevent.ConfigureEvent.height);
#endif
-// if ((hwnd.x != xevent.ConfigureEvent.x) || (hwnd.y != xevent.ConfigureEvent.y) || (hwnd.width != xevent.ConfigureEvent.width) || (hwnd.height != xevent.ConfigureEvent.height)) {
- lock (hwnd.configure_lock) {
- SendMessage(msg.hwnd, Msg.WM_WINDOWPOSCHANGED, IntPtr.Zero, IntPtr.Zero);
- hwnd.configure_pending = false;
- }
+ 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;
}
}
goto ProcessNextMessage;
}
- Keyboard.FocusIn(FocusWindow);
SendMessage(FocusWindow, Msg.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
+ Keyboard.FocusIn (FocusWindow);
goto ProcessNextMessage;
}
if (xevent.FocusChangeEvent.detail != NotifyDetail.NotifyNonlinear) {
goto ProcessNextMessage;
}
- Keyboard.FocusOut(FocusWindow);
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;
}
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;
}
return true;
}
+ private HitTest NCHitTest (Hwnd hwnd, int x, int y)
+ {
+ // The hit test is sent in screen coordinates
+ IntPtr dummy;
+ int screen_x, screen_y;
+ XTranslateCoordinates (DisplayHandle, hwnd.WholeWindow, RootWindow, x, y, out screen_x, out screen_y, out dummy);
+ return (HitTest) NativeWindow.WndProc (hwnd.client_window, Msg.WM_NCHITTEST, IntPtr.Zero,
+ (IntPtr) (screen_y << 16 | screen_x & 0xFFFF));
+ }
+
internal override bool GetText(IntPtr handle, out string text) {
lock (XlibLock) {
XGrabPointer(DisplayHandle, hwnd.client_window, false,
EventMask.ButtonPressMask | EventMask.ButtonMotionMask |
EventMask.ButtonReleaseMask | EventMask.PointerMotionMask |
- EventMask.LeaveWindowMask,
+ EventMask.PointerMotionHintMask | EventMask.LeaveWindowMask,
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, confine_to_window, IntPtr.Zero, IntPtr.Zero);
}
}
hwnd = Hwnd.ObjectFromHandle(handle);
- AddExpose (hwnd, false, 0, 0, hwnd.Width, hwnd.Height);
+ AddExpose (hwnd, hwnd.WholeWindow == hwnd.ClientWindow, 0, 0, hwnd.Width, hwnd.Height);
}
internal override bool IsEnabled(IntPtr handle) {
if (queue == null) {
// This isn't really an error, MS doesn't start the timer if
- // it has no assosciated queue
+ // it has no assosciated queue. In this case, remove the timer
+ // from the list of unattached timers (if it was enabled).
+ lock (unattached_timer_list) {
+ if (unattached_timer_list.Contains (timer))
+ unattached_timer_list.Remove (timer);
+ }
return;
}
queue.timer_list.Remove (timer);
XChangeActivePointerGrab (DisplayHandle,
EventMask.ButtonMotionMask |
EventMask.PointerMotionMask |
+ EventMask.PointerMotionHintMask |
EventMask.ButtonPressMask |
EventMask.ButtonReleaseMask,
cursor, IntPtr.Zero);
OverrideCursorHandle = cursor;
}
- internal override PaintEventArgs PaintEventStart(IntPtr handle, bool client) {
+ internal override PaintEventArgs PaintEventStart(ref Message msg, IntPtr handle, bool client) {
PaintEventArgs paint_event;
Hwnd hwnd;
-
- hwnd = Hwnd.ObjectFromHandle(handle);
-
+ Hwnd paint_hwnd;
+
+ //
+ // handle (and paint_hwnd) refers to the window that is should be painted.
+ // msg.HWnd (and hwnd) refers to the window that got the paint message.
+ //
+
+ hwnd = Hwnd.ObjectFromHandle(msg.HWnd);
+ if (msg.HWnd == handle) {
+ paint_hwnd = hwnd;
+ } else {
+ paint_hwnd = Hwnd.ObjectFromHandle (handle);
+ }
+
if (Caret.Visible == true) {
Caret.Paused = true;
HideCaret();
Graphics dc;
if (client) {
- dc = Graphics.FromHwnd (hwnd.client_window);
+ dc = Graphics.FromHwnd (paint_hwnd.client_window);
Region clip_region = new Region ();
clip_region.MakeEmpty();
return paint_event;
} else {
- dc = Graphics.FromHwnd (hwnd.whole_window);
+ dc = Graphics.FromHwnd (paint_hwnd.whole_window);
if (!hwnd.nc_invalid.IsEmpty) {
dc.SetClip (hwnd.nc_invalid);
}
}
- internal override void PaintEventEnd(IntPtr handle, bool client) {
+ internal override void PaintEventEnd(ref Message msg, IntPtr handle, bool client) {
Hwnd hwnd;
- hwnd = Hwnd.ObjectFromHandle(handle);
+ hwnd = Hwnd.ObjectFromHandle (msg.HWnd);
Graphics dc = (Graphics)hwnd.drawing_stack.Pop ();
dc.Flush();
xevent.ClientMessageEvent.ptr3 = wparam;
xevent.ClientMessageEvent.ptr4 = lparam;
- hwnd.Queue.EnqueueLocked (xevent);
+ if (hwnd != null)
+ hwnd.Queue.EnqueueLocked (xevent);
+ else
+ ThreadQueue(Thread.CurrentThread).EnqueueLocked (xevent);
return true;
}
internal override void PostQuitMessage(int exitCode) {
- PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ ApplicationContext ctx = Application.MWFThread.Current.Context;
+ Form f = ctx != null ? ctx.MainForm : null;
+ if (f != null)
+ PostMessage (Application.MWFThread.Current.Context.MainForm.window.Handle, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ else
+ PostMessage (FosterParent, Msg.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
XFlush(DisplayHandle);
}
XTranslateCoordinates (DisplayHandle, RootWindow, hwnd.whole_window, x, y, out dest_x_return, out dest_y_return, out child);
}
+ Form form = Control.FromHandle (handle) as Form;
+ if (form != null && form.window_manager != null) {
+ dest_y_return -= form.window_manager.TitleBarHeight;
+ }
+
x = dest_x_return;
y = dest_y_return;
}
+ bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg)
+ {
+ return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) &&
+ arg == xevent.GraphicsExposeEvent.drawable;
+ }
+
+ delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg);
+
+ 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 override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) {
Hwnd hwnd;
IntPtr gc;
gc = XCreateGC(DisplayHandle, hwnd.client_window, IntPtr.Zero, ref gc_values);
- int src_x, src_y;
- int dest_x, dest_y;
- int width, height;
+ Rectangle visible_rect = GetTotalVisibleArea (hwnd.client_window);
+ visible_rect.Intersect (area);
- if (YAmount > 0) {
- src_y = area.Y;
- height = area.Height - YAmount;
- dest_y = area.Y + YAmount;
- }
- else {
- src_y = area.Y - YAmount;
- height = area.Height + YAmount;
- dest_y = area.Y;
- }
+ Rectangle dest_rect = visible_rect;
+ dest_rect.Y += YAmount;
+ dest_rect.X += XAmount;
+ dest_rect.Intersect (area);
- if (XAmount > 0) {
- src_x = area.X;
- width = area.Width - XAmount;
- dest_x = area.X + XAmount;
- }
- else {
- src_x = area.X - XAmount;
- width = area.Width + XAmount;
- dest_x = area.X;
- }
+ Point src = new Point (dest_rect.X - XAmount, dest_rect.Y - YAmount);
+ XCopyArea (DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src.X, src.Y,
+ dest_rect.Width, dest_rect.Height, dest_rect.X, dest_rect.Y);
- XCopyArea(DisplayHandle, hwnd.client_window, hwnd.client_window, gc, src_x, src_y, width, height, dest_x, dest_y);
+ Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount);
+ AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height);
- // Generate an expose for the area exposed by the horizontal scroll
- // We don't use AddExpose since we're
- if (XAmount > 0) {
- AddExpose(hwnd, true, area.X, area.Y, XAmount, area.Height);
- } else if (XAmount < 0) {
- AddExpose(hwnd, true, XAmount + area.X + area.Width, area.Y, -XAmount, area.Height);
- }
+ ProcessGraphicsExpose (hwnd);
- // Generate an expose for the area exposed by the vertical scroll
- if (YAmount > 0) {
- AddExpose(hwnd, true, area.X, area.Y, area.Width, YAmount);
- } else if (YAmount < 0) {
- AddExpose(hwnd, true, area.X, YAmount + area.Y + area.Height, area.Width, -YAmount);
- }
XFreeGC(DisplayHandle, gc);
}
ScrollWindow(handle, rect, XAmount, YAmount, with_children);
}
+ Rectangle GetDirtyArea (Rectangle total_area, Rectangle valid_area, int XAmount, int YAmount)
+ {
+ Rectangle dirty_area = total_area;
+
+ if (YAmount > 0)
+ dirty_area.Height -= valid_area.Height;
+ else if (YAmount < 0) {
+ dirty_area.Height -= valid_area.Height;
+ dirty_area.Y += valid_area.Height;
+ }
+
+ if (XAmount > 0)
+ dirty_area.Width -= valid_area.Width;
+ else if (XAmount < 0) {
+ dirty_area.Width -= valid_area.Width;
+ dirty_area.X += valid_area.Width;
+ }
+
+ return dirty_area;
+ }
+
+ Rectangle GetTotalVisibleArea (IntPtr handle)
+ {
+ Control c = Control.FromHandle (handle);
+
+ Rectangle visible_area = c.ClientRectangle;
+ visible_area.Location = c.PointToScreen (Point.Empty);
+
+ for (Control parent = c.Parent; parent != null; parent = parent.Parent) {
+ if (!parent.IsHandleCreated || !parent.Visible)
+ return visible_area; // Non visible, not need to finish computations
+
+ Rectangle r = parent.ClientRectangle;
+ r.Location = parent.PointToScreen (Point.Empty);
+
+ visible_area.Intersect (r);
+ }
+
+ visible_area.Location = c.PointToClient (visible_area.Location);
+ return visible_area;
+ }
+
internal override void SendAsyncMethod (AsyncMethodData method) {
Hwnd hwnd;
XEvent xevent = new XEvent ();
internal override void SetBorderStyle(IntPtr handle, FormBorderStyle border_style) {
Form form = Control.FromHandle (handle) as Form;
- if (form != null && form.window_manager == null && (border_style == FormBorderStyle.FixedToolWindow ||
- border_style == FormBorderStyle.SizableToolWindow)) {
- form.window_manager = new ToolWindowManager (form);
+ if (form != null && form.window_manager == null) {
+ CreateParams cp = form.GetCreateParams ();
+ if (border_style == FormBorderStyle.FixedToolWindow ||
+ border_style == FormBorderStyle.SizableToolWindow ||
+ cp.IsSet (WindowExStyles.WS_EX_TOOLWINDOW)) {
+ form.window_manager = new ToolWindowManager (form);
+ }
}
RequestNCRecalc(handle);
Caret.X = x;
Caret.Y = y;
+ Keyboard.SetCaretPos (Caret, handle, x, y);
+
if (Caret.Visible == true) {
ShowCaret();
Caret.Timer.Start();
}
hwnd.UserClip = region;
- Invalidate(handle, new Rectangle(0, 0, hwnd.Width, hwnd.Height), false);
}
internal override void SetCursor(IntPtr handle, IntPtr cursor) {
return;
}
+ // Win32 doesn't do anything if disabled
+ if (!hwnd.enabled)
+ return;
+
prev_focus_window = FocusWindow;
FocusWindow = hwnd.client_window;
SendMessage(prev_focus_window, Msg.WM_KILLFOCUS, FocusWindow, IntPtr.Zero);
}
SendMessage(FocusWindow, Msg.WM_SETFOCUS, prev_focus_window, IntPtr.Zero);
+ Keyboard.FocusIn (FocusWindow);
//XSetInputFocus(DisplayHandle, Hwnd.ObjectFromHandle(handle).client_window, RevertTo.None, IntPtr.Zero);
}
Activate((IntPtr)ModalWindows.Peek());
}
}
+
+ Hwnd hwnd = Hwnd.ObjectFromHandle (handle);
+ Control ctrl = Control.FromHandle (handle);
+ SetWMStyles (hwnd, ctrl.GetCreateParams ());
}
internal override IntPtr SetParent(IntPtr handle, IntPtr parent) {
if (queue == null) {
// This isn't really an error, MS doesn't start the timer if
- // it has no assosciated queue
+ // it has no assosciated queue at this stage (it will be
+ // enabled when a window is activated).
+ unattached_timer_list.Add (timer);
return;
}
queue.timer_list.Add (timer);
WakeupMain ();
}
- internal override bool SetTopmost(IntPtr handle, IntPtr handle_owner, bool enabled) {
- Hwnd hwnd;
- Hwnd hwnd_owner;
+ internal override bool SetTopmost(IntPtr handle, bool enabled) {
- hwnd = Hwnd.ObjectFromHandle(handle);
+ Hwnd hwnd = Hwnd.ObjectFromHandle(handle);
- if (handle_owner != IntPtr.Zero) {
- hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
+ if (enabled) {
+ lock (XlibLock) {
+ int[] atoms = new int[8];
+ atoms[0] = _NET_WM_STATE_ABOVE.ToInt32();
+ XChangeProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE, (IntPtr)Atom.XA_ATOM, 32, PropertyMode.Replace, atoms, 1);
+ }
} else {
- hwnd_owner = null;
+ lock (XlibLock) {
+ XDeleteProperty(DisplayHandle, hwnd.whole_window, _NET_WM_STATE);
+ }
}
+ return true;
+ }
- if (enabled) {
+ internal override bool SetOwner(IntPtr handle, IntPtr handle_owner) {
+ Hwnd hwnd;
+ Hwnd hwnd_owner;
+
+ hwnd = Hwnd.ObjectFromHandle(handle);
+
+ if (handle_owner != IntPtr.Zero) {
+ hwnd_owner = Hwnd.ObjectFromHandle(handle_owner);
lock (XlibLock) {
int[] atoms;
}
internal override void SetWindowMinMax(IntPtr handle, Rectangle maximized, Size min, Size max) {
+ Control ctrl = Control.FromHandle (handle);
+ SetWindowMinMax (handle, maximized, min, max, ctrl != null ? ctrl.GetCreateParams () : null);
+ }
+
+ internal void SetWindowMinMax (IntPtr handle, Rectangle maximized, Size min, Size max, CreateParams cp)
+ {
Hwnd hwnd;
XSizeHints hints;
IntPtr dummy;
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;
}
lock (XlibLock) {
- XMoveResizeWindow(DisplayHandle, hwnd.whole_window, x, y, width, height);
+ Control ctrl = Control.FromHandle (handle);
+ Size TranslatedSize = TranslateWindowSizeToXWindowSize (ctrl.GetCreateParams (), new Size (width, height));
+ MoveResizeWindow (DisplayHandle, hwnd.whole_window, x, y, TranslatedSize.Width, TranslatedSize.Height);
PerformNCCalc(hwnd);
}
}
// 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);
- }
+ /* 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);
}
size_hints = new XSizeHints();
// Need to pick some reasonable defaults
tt = new ToolTip();
- tt.AutomaticDelay = 100;
+ tt.AutomaticDelay = 350;
tt.InitialDelay = 250;
tt.ReshowDelay = 250;
tt.ShowAlways = true;
if (control != null && tt != null) {
tt.SetToolTip(control, tip);
tt.Active = true;
+ SendMessage(handle, Msg.WM_PAINT, IntPtr.Zero, IntPtr.Zero);
return true;
} else {
return false;
internal override void SystrayRemove(IntPtr handle, ref ToolTip tt) {
-#if GTKSOCKET_SUPPORTS_REPARENTING
- Hwnd hwnd;
-
- hwnd = Hwnd.ObjectFromHandle(handle);
-
- /* in the XEMBED spec, it mentions 3 ways for a client window to break the protocol with the embedder.
- * 1. The embedder can unmap the window and reparent to the root window (we should probably handle this...)
- * 2. The client can reparent its window out of the embedder window.
- * 3. The client can destroy its window.
- *
- * this call to SetParent is case 2, but in
- * the spec it also mentions that gtk doesn't
- * support this at present. Looking at HEAD
- * gtksocket-x11.c jives with this statement.
- *
- * so we can't reparent. we have to destroy.
- */
- SetParent(hwnd.whole_window, FosterParent);
-#else
- Control control = Control.FromHandle(handle);
- if (control is NotifyIcon.NotifyIconWindow)
- ((NotifyIcon.NotifyIconWindow)control).InternalRecreateHandle ();
-#endif
+ SetVisible (handle, false, false);
// The caller can now re-dock it later...
if (tt != null) {
}
}
+#if NET_2_0
+ internal override void SystrayBalloon(IntPtr handle, int timeout, string title, string text, ToolTipIcon icon)
+ {
+ ThemeEngine.Current.ShowBalloonWindow (handle, timeout, title, text, icon);
+ SendMessage(handle, Msg.WM_USER, IntPtr.Zero, (IntPtr) Msg.NIN_BALLOONSHOW);
+ }
+#endif
+
internal override bool Text(IntPtr handle, string text) {
Hwnd hwnd;
internal override event EventHandler Idle;
#endregion // Events
+#region Xcursor imports
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadCursor")]
+ internal extern static IntPtr XcursorLibraryLoadCursor (IntPtr display, [MarshalAs (UnmanagedType.LPStr)] string name);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorLibraryLoadImages")]
+ internal extern static IntPtr XcursorLibraryLoadImages ([MarshalAs (UnmanagedType.LPStr)] string file, IntPtr theme, int size);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImagesDestroy")]
+ internal extern static void XcursorImagesDestroy (IntPtr images);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetDefaultSize")]
+ internal extern static int XcursorGetDefaultSize (IntPtr display);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorImageLoadCursor")]
+ internal extern static IntPtr XcursorImageLoadCursor (IntPtr display, IntPtr image);
+
+ [DllImport ("libXcursor", EntryPoint = "XcursorGetTheme")]
+ internal extern static IntPtr XcursorGetTheme (IntPtr display);
+#endregion
#region X11 Imports
[DllImport ("libX11", EntryPoint="XOpenDisplay")]
internal extern static IntPtr XOpenDisplay(IntPtr display);
[DllImport ("libX11", EntryPoint="XReparentWindow")]
internal extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y);
[DllImport ("libX11", EntryPoint="XMoveResizeWindow")]
- internal extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+ private extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height);
+
+ internal static int MoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height)
+ {
+ int ret = XMoveResizeWindow (display, window, x, y, width, height);
+ Keyboard.MoveCurrentCaretPos ();
+ return ret;
+ }
[DllImport ("libX11", EntryPoint="XResizeWindow")]
internal extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height);
[DllImport ("libX11", EntryPoint="XDeleteProperty")]
internal extern static int XDeleteProperty(IntPtr display, IntPtr window, IntPtr property);
- [DllImport ("gdiplus", EntryPoint="GetFontMetrics")]
- internal extern static bool GetFontMetrics(IntPtr graphicsObject, IntPtr nativeObject, out int ascent, out int descent);
-
// Drawing
[DllImport ("libX11", EntryPoint="XCreateGC")]
internal extern static IntPtr XCreateGC(IntPtr display, IntPtr window, IntPtr valuemask, ref XGCValues values);
[DllImport ("libX11", EntryPoint="XQueryBestCursor")]
internal extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
+ [DllImport ("libX11", EntryPoint="XQueryExtension")]
+ internal extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
+
[DllImport ("libX11", EntryPoint="XWhitePixel")]
internal extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
[DllImport ("libX11")]
internal extern static void XPeekEvent (IntPtr display, ref XEvent xevent);
+
+ [DllImport ("libX11")]
+ internal extern static void XIfEvent (IntPtr display, ref XEvent xevent, Delegate event_predicate, IntPtr arg);
#endregion
}
}