// Constructor. public DrawingWindowBuffer(IToolkitWindow windowToBuffer) { toolkit = windowToBuffer.Toolkit; widget = windowToBuffer as InputOutputWidget; buffer = null; graphics = null; }
// Get the display and screen from a widget, after checking for null. private static Display GetDisplay(InputOutputWidget widget) { if (widget == null) { throw new ArgumentNullException("widget"); } return(widget.dpy); }
private static Screen GetScreen(InputOutputWidget widget) { if (widget == null) { throw new ArgumentNullException("widget"); } return(widget.screen); }
// Send a fake "LeaveNotify" event to a popup window. private static void FakeLeave(InputOutputWidget window) { if (window != null) { XEvent xevent = new XEvent(); xevent.xany.type__ = (Xlib.Xint)(int)(EventType.LeaveNotify); window.DispatchEvent(ref xevent); } }
/// <summary> /// <para>Constructs a new <see cref="T:Xsharp.DoubleBuffer"/> /// instance.</para> /// </summary> /// /// <param name="widget"> /// <para>The widget to attach the double buffer to.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>Raised if <paramref name="widget"/> is <see langword="null"/>. /// </para> /// </exception> public DoubleBuffer(InputOutputWidget widget) : base(GetDisplay(widget), GetScreen(widget), DrawableKind.DoubleBuffer) { this.widget = widget; this.width = widget.width; this.height = widget.height; try { IntPtr display = dpy.Lock(); // Determine if the X server supports double buffering. try { Xlib.Xint major, minor; if (Xlib.XdbeQueryExtension (display, out major, out minor) != XStatus.Zero) { usesXdbe = true; } else { usesXdbe = false; } } catch (Exception) { // Xdbe functions are not present in "Xext". usesXdbe = false; } // Create the back buffer or pixmap, as appropriate. if (usesXdbe) { handle = Xlib.XdbeAllocateBackBufferName (display, widget.GetWidgetHandle(), Xlib.XdbeSwapAction.Background); } else { handle = (XDrawable) Xlib.XCreatePixmap (display, (XDrawable) Xlib.XRootWindowOfScreen(screen.screen), (uint)width, (uint)height, (uint)Xlib.XDefaultDepthOfScreen (screen.screen)); } } finally { dpy.Unlock(); } }
/// <summary> /// <para>Constructs a new <see cref="T:Xsharp.DoubleBuffer"/> /// instance.</para> /// </summary> /// /// <param name="widget"> /// <para>The widget to attach the double buffer to.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>Raised if <paramref name="widget"/> is <see langword="null"/>. /// </para> /// </exception> public DoubleBuffer(InputOutputWidget widget) : base(GetDisplay(widget), GetScreen(widget), DrawableKind.DoubleBuffer) { this.widget = widget; this.width = widget.width; this.height = widget.height; try { IntPtr display = dpy.Lock(); // Determine if the X server supports double buffering. try { Xlib.Xint major, minor; if(Xlib.XdbeQueryExtension (display, out major, out minor) != XStatus.Zero) { usesXdbe = true; } else { usesXdbe = false; } } catch(Exception) { // Xdbe functions are not present in "Xext". usesXdbe = false; } // Create the back buffer or pixmap, as appropriate. if(usesXdbe) { handle = Xlib.XdbeAllocateBackBufferName (display, widget.GetWidgetHandle(), Xlib.XdbeSwapAction.Background); } else { handle = (XDrawable) Xlib.XCreatePixmap (display, (XDrawable) Xlib.XRootWindowOfScreen(screen.screen), (uint)width, (uint)height, (uint)Xlib.XDefaultDepthOfScreen (screen.screen)); } } finally { dpy.Unlock(); } }
// Process pending invalidates. private void ProcessPendingInvalidates() { InputOutputWidget current = invalidateList; InputOutputWidget next; invalidateList = null; while (current != null) { next = current.nextInvalidate; current.FlushInvalidates(); current = next; } }
// Find the child window that has the focus private InputOutputWidget FindFocusedChild(InputOutputWidget parent) { if (parent != null) { foreach (InputOutputWidget child in parent) { if (child.Focused) { return(child); } } } return(null); }
// Flush pending invalidates to the X server. internal void FlushInvalidates() { Region region = invalidateRegion; invalidateRegion = null; nextInvalidate = null; if (region != null) { // No point redrawing if we are unmapped. if (handle != XDrawable.Zero && mapped && AncestorsMapped) { Invalidate(region); } } }
// Remove a popup from the mapped list. public void RemovePopup(PopupWindow popup) { int index; lock (this) { for (index = list.Length - 1; index >= 0; --index) { if (list[index] == popup) { // Remove the item from the list. PopupWindow[] newList; newList = new PopupWindow [list.Length - 1]; Array.Copy(list, 0, newList, 0, index); Array.Copy(list, index + 1, newList, index, list.Length - index - 1); list = newList; // If this was the entered window, then // send it a fake "LeaveNotify" event. if (lastChildEntered != null && lastChildEntered.Parent == popup) { FakeLeave(lastChildEntered); lastChildEntered = null; } if (lastEntered == popup) { lastEntered = null; FakeLeave(popup); } // If this was the button window, then clear it. if (lastButton == popup) { lastButton = null; } // If the list is now empty, then ungrab. if (list.Length == 0) { Ungrab(); } return; } } } }
// Find the child window that contains a particular mouse position private InputOutputWidget FindChild(InputOutputWidget parent, int x, int y) { if (parent != null) { foreach (InputOutputWidget child in parent) { if (child.IsMapped && x - parent.X >= child.X && x - parent.X < (child.X + child.Width) && y - parent.Y >= child.y && y - parent.Y < (child.Y + child.Height)) { return(child); } } } return(null); }
// Change the "lastEntered" and "lastChildEntered" window. // The popup is entered before the child and left after. private void ChangeEntered(PopupWindow popup, InputOutputWidget child) { PopupWindow before = null; PopupWindow after = null; InputOutputWidget childBefore = null; InputOutputWidget childAfter = null; lock (this) { if (lastEntered != popup) { before = lastEntered; after = popup; lastEntered = popup; } if (lastChildEntered != child) { childBefore = lastChildEntered; childAfter = child; lastChildEntered = child; } } if (before != null) { if (childBefore != null) { FakeLeave(childBefore); } FakeLeave(before); } if (after != null) { FakeEnter(after); if (childAfter != null) { FakeEnter(childAfter); } } }
// Remove an input/output widget from the pending expose list. internal void RemovePendingExpose(InputOutputWidget widget) { InputOutputWidget current, prev; current = exposeList; prev = null; while (current != null && current != widget) { prev = current; current = current.nextExpose; } if (current != null) { if (prev != null) { prev.nextExpose = current.nextExpose; } else { exposeList = current.nextExpose; } } }
// Remove an input/output widget from the pending invalidate list. internal void RemovePendingInvalidate(InputOutputWidget widget) { InputOutputWidget current, prev; current = invalidateList; prev = null; while (current != null && current != widget) { prev = current; current = current.nextInvalidate; } if (current != null) { if (prev != null) { prev.nextInvalidate = current.nextInvalidate; } else { invalidateList = current.nextInvalidate; } } }
// Get the background information for use in graphics object clears. internal void GetBackgroundInfo(out Color bg, out Pixmap pixmap, out int tx, out int ty) { if (background.Index == StandardColor.Inherit) { InputOutputWidget parent = (Parent as InputOutputWidget); if (parent != null) { parent.GetBackgroundInfo (out bg, out pixmap, out tx, out ty); tx -= x; ty -= y; } else { bg = new Color(StandardColor.Background); pixmap = null; tx = 0; ty = 0; } } else if (background.Index == StandardColor.Pixmap) { bg = background; pixmap = backgroundPixmap; tx = 0; ty = 0; } else { bg = background; pixmap = null; tx = 0; ty = 0; } }
// Add an input/output widget to the pending expose list. internal void AddPendingExpose(InputOutputWidget widget) { widget.nextExpose = exposeList; exposeList = widget; pendingExposes = true; }
// Find the child window that has the focus private InputOutputWidget FindFocusedChild(InputOutputWidget parent) { if (parent != null) { foreach(InputOutputWidget child in parent) { if (child.Focused) return child; } } return null; }
// Add an input/output widget to the pending invalidate list. internal void AddPendingInvalidate(InputOutputWidget widget) { widget.nextInvalidate = invalidateList; invalidateList = widget; }
// Get the display and screen from a widget, after checking for null. private static Display GetDisplay(InputOutputWidget widget) { if(widget == null) { throw new ArgumentNullException("widget"); } return widget.dpy; }
// Dispatch an event to this widget. internal override void DispatchEvent(ref XEvent xevent) { XKeySym keysym; PopupWindow popup; InputOutputWidget child = null; switch ((EventType)(xevent.xany.type__)) { case EventType.ButtonPress: { // A mouse button was pressed during the grab. lock (this) { if (lastButton != null) { // We currently have a button window, so // all mouse events should go to it. popup = lastButton; } else { // Determine which popup contains the mouse. // If nothing contains, then use the top. popup = Find(xevent.xbutton.x_root, xevent.xbutton.y_root, true); } lastButton = popup; } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.ButtonRelease: { // A mouse button was released during the grab. lock (this) { popup = lastButton; if (popup != null) { // Reset "lastButton" if this is the last // button to be released. ModifierMask mask = ModifierMask.AllButtons; mask &= (ModifierMask) ~((int)ModifierMask.Button1Mask << ((int)(xevent.xbutton.button__) - 1)); if ((xevent.xbutton.state & mask) == 0) { lastButton = null; } } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xbutton.x__ = (Xlib.Xint)(xevent.xbutton.x_root - popup.x); xevent.xbutton.y__ = (Xlib.Xint)(xevent.xbutton.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.MotionNotify: { // The mouse pointer was moved during the grab. lock (this) { // If there is a last button window, then use // that, otherwise find the one under the mouse. popup = lastButton; if (popup == null) { popup = Find(xevent.xmotion.x_root, xevent.xmotion.y_root, false); } } // Find the child window. child = FindChild(popup, xevent.xbutton.x_root, xevent.xbutton.y_root); ChangeEntered(popup, child); if (popup != null) { // Adjust the co-ordinates and re-dispatch. xevent.xmotion.x__ = (Xlib.Xint)(xevent.xmotion.x_root - popup.x); xevent.xmotion.y__ = (Xlib.Xint)(xevent.xmotion.y_root - popup.y); popup.DispatchEvent(ref xevent); // Re-dispatch to the child window if necessary. if (child != null) { xevent.xbutton.x__ -= child.x; xevent.xbutton.y__ -= child.y; child.DispatchEvent(ref xevent); } } } break; case EventType.KeyPress: { // Convert the event into a symbol and a string. if (keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); String str; if (len > 0) { str = Marshal.PtrToStringAnsi(keyBuffer, len); } else { str = null; } // Dispatch the event to the top-most popup. lock (this) { if (list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if (popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) { popup.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); } else { child.DispatchKeyEvent ((KeyName)keysym, xevent.xkey.state, str); } } } break; case EventType.KeyRelease: { // Convert the event into a symbol and a string. if (keyBuffer == IntPtr.Zero) { keyBuffer = Marshal.AllocHGlobal(32); } keysym = 0; int len = Xlib.XLookupString (ref xevent.xkey, keyBuffer, 32, ref keysym, IntPtr.Zero); // Dispatch the event to the top-most popup. lock (this) { if (list.Length > 0) { popup = list[list.Length - 1]; } else { popup = null; } } if (popup != null) { // Find the child window. child = FindFocusedChild(popup); if (child == null) { popup.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); } else { child.DispatchKeyReleaseEvent ((KeyName)keysym, xevent.xkey.state); } } } break; default: { // Everything else is handled normally. base.DispatchEvent(ref xevent); } break; } }
// Remove a popup from the mapped list. public void RemovePopup(PopupWindow popup) { int index; lock(this) { for(index = list.Length - 1; index >= 0; --index) { if(list[index] == popup) { // Remove the item from the list. PopupWindow[] newList; newList = new PopupWindow [list.Length - 1]; Array.Copy(list, 0, newList, 0, index); Array.Copy(list, index + 1, newList, index, list.Length - index - 1); list = newList; // If this was the entered window, then // send it a fake "LeaveNotify" event. if(lastChildEntered != null && lastChildEntered.Parent == popup) { FakeLeave(lastChildEntered); lastChildEntered = null; } if(lastEntered == popup) { lastEntered = null; FakeLeave(popup); } // If this was the button window, then clear it. if(lastButton == popup) { lastButton = null; } // If the list is now empty, then ungrab. if(list.Length == 0) { Ungrab(); } return; } } } }
// Remove an input/output widget from the pending expose list. internal void RemovePendingExpose(InputOutputWidget widget) { InputOutputWidget current, prev; current = exposeList; prev = null; while(current != null && current != widget) { prev = current; current = current.nextExpose; } if(current != null) { if(prev != null) { prev.nextExpose = current.nextExpose; } else { exposeList = current.nextExpose; } } }
}; // enum AppEvent // Handle the next event and return what kind of event it was. private AppEvent HandleNextEvent(bool wait) { try { IntPtr dpy = Lock(); XEvent xevent; int timeout; // Processing any pending invalidates that we have. ProcessPendingInvalidates(); // Flush any requests that are in the outgoing queue. Xlib.XFlush(dpy); // Process "Quit". if(quit) { return AppEvent.Quit; } // Process events that are already in the queue. // It is important that this be done before processing // short period timeouts or the events may never get // processed at all. if(Xlib.XEventsQueued (dpy, 2 /* QueuedAfterFlush */) != 0) { // Read the next event and dispatch it. Xlib.XNextEvent(dpy, out xevent); Unlock(); try { DispatchEvent(ref xevent); return AppEvent.Regular; } finally { dpy = Lock(); } } // Do we have pending expose events to process? if(pendingExposes) { // Process the pending expose events. InputOutputWidget widget; while(exposeList != null) { widget = exposeList; exposeList = exposeList.nextExpose; Unlock(); try { widget.Expose(); } finally { dpy = Lock(); } } pendingExposes = false; return AppEvent.Regular; } else { // Wait for the next event. if(wait) { timeout = Timer.GetNextTimeout(this); } else { timeout = 0; } if(timeout < 0) { // Make sure that we release the display lock // before calling "XNextEvent", so that other // threads can issue X requests while we are // waiting for the next event to occur. Unlock(); try { Xlib.XNextEvent(dpy, out xevent); DispatchEvent(ref xevent); } finally { dpy = Lock(); } return AppEvent.Regular; } else { Unlock(); try { if(Xlib.XNextEventWithTimeout (dpy, out xevent, timeout) > 0) { DispatchEvent(ref xevent); return AppEvent.Regular; } } finally { dpy = Lock(); } } } // Process timers that need to be activated. if(Timer.ActivateTimers(this)) { return AppEvent.Timer; } } finally { Unlock(); } // If we get here, then there were no events processed. return AppEvent.NoEvent; }
}; // enum AppEvent // Handle the next event and return what kind of event it was. private AppEvent HandleNextEvent(bool wait) { try { IntPtr dpy = Lock(); XEvent xevent; int timeout; // Processing any pending invalidates that we have. ProcessPendingInvalidates(); // Flush any requests that are in the outgoing queue. Xlib.XFlush(dpy); // Process "Quit". if (quit) { return(AppEvent.Quit); } // Process events that are already in the queue. // It is important that this be done before processing // short period timeouts or the events may never get // processed at all. if (Xlib.XEventsQueued (dpy, 2 /* QueuedAfterFlush */) != 0) { // Read the next event and dispatch it. Xlib.XNextEvent(dpy, out xevent); Unlock(); try { DispatchEvent(ref xevent); return(AppEvent.Regular); } finally { dpy = Lock(); } } // Do we have pending expose events to process? if (pendingExposes) { // Process the pending expose events. InputOutputWidget widget; while (exposeList != null) { widget = exposeList; exposeList = exposeList.nextExpose; Unlock(); try { widget.Expose(); } finally { dpy = Lock(); } } pendingExposes = false; return(AppEvent.Regular); } else { // Wait for the next event. if (wait) { timeout = Timer.GetNextTimeout(this); } else { timeout = 0; } if (timeout < 0) { // Make sure that we release the display lock // before calling "XNextEvent", so that other // threads can issue X requests while we are // waiting for the next event to occur. Unlock(); try { timeout = 100; if (Xlib.XNextEventWithTimeout (dpy, out xevent, timeout) > 0) { DispatchEvent(ref xevent); } } finally { dpy = Lock(); } return(AppEvent.Regular); } else { Unlock(); try { if (Xlib.XNextEventWithTimeout (dpy, out xevent, timeout) > 0) { DispatchEvent(ref xevent); return(AppEvent.Regular); } } finally { dpy = Lock(); } } } // Process timers that need to be activated. if (Timer.ActivateTimers(this)) { return(AppEvent.Timer); } } finally { Unlock(); } // If we get here, then there were no events processed. return(AppEvent.NoEvent); }
// Send a fake "LeaveNotify" event to a popup window. private static void FakeLeave(InputOutputWidget window) { if(window != null) { XEvent xevent = new XEvent(); xevent.xany.type__ = (Xlib.Xint)(int)(EventType.LeaveNotify); window.DispatchEvent(ref xevent); } }
private static Screen GetScreen(InputOutputWidget widget) { if(widget == null) { throw new ArgumentNullException("widget"); } return widget.screen; }
// Change the "lastEntered" and "lastChildEntered" window. // The popup is entered before the child and left after. private void ChangeEntered(PopupWindow popup, InputOutputWidget child) { PopupWindow before = null; PopupWindow after = null; InputOutputWidget childBefore = null; InputOutputWidget childAfter = null; lock(this) { if(lastEntered != popup) { before = lastEntered; after = popup; lastEntered = popup; } if(lastChildEntered != child) { childBefore = lastChildEntered; childAfter = child; lastChildEntered = child; } } if(before != null) { if (childBefore != null) FakeLeave(childBefore); FakeLeave(before); } if(after != null) { FakeEnter(after); if (childAfter != null) FakeEnter(childAfter); } }
// Remove an input/output widget from the pending invalidate list. internal void RemovePendingInvalidate(InputOutputWidget widget) { InputOutputWidget current, prev; current = invalidateList; prev = null; while(current != null && current != widget) { prev = current; current = current.nextInvalidate; } if(current != null) { if(prev != null) { prev.nextInvalidate = current.nextInvalidate; } else { invalidateList = current.nextInvalidate; } } }
// Find the child window that contains a particular mouse position private InputOutputWidget FindChild(InputOutputWidget parent, int x, int y) { if (parent != null) { foreach(InputOutputWidget child in parent) { if (child.IsMapped && x - parent.X >= child.X && x - parent.X < (child.X + child.Width) && y - parent.Y >= child.y && y - parent.Y < (child.Y + child.Height)) return child; } } return null; }
// Flush pending invalidates to the X server. internal void FlushInvalidates() { Region region = invalidateRegion; invalidateRegion = null; nextInvalidate = null; if(region != null) { // No point redrawing if we are unmapped. if(handle != XDrawable.Zero && mapped && AncestorsMapped) { Invalidate(region); } } }
// Process pending invalidates. private void ProcessPendingInvalidates() { InputOutputWidget current = invalidateList; InputOutputWidget next; invalidateList = null; while(current != null) { next = current.nextInvalidate; current.FlushInvalidates(); current = next; } }