// Set the clipping region to a single rectangle. public override void SetClipRect(int x, int y, int width, int height) { using (Xsharp.Region region = new Xsharp.Region(x, y, width, height)) { graphics.SetClipRegion(region, 0, 0); } }
// Set the clipping region to a list of rectangles. public override void SetClipRects(System.Drawing.Rectangle[] rects) { using (Xsharp.Region region = rectsToRegion(rects)) { graphics.SetClipRegion(region); } }
// Set the clipping region to empty. public override void SetClipEmpty() { using (Xsharp.Region region = new Xsharp.Region()) { graphics.SetClipRegion(region, 0, 0); } }
// Set the clipping region to infinite (i.e. disable clipping). public override void SetClipInfinite() { using (Xsharp.Region region = new Xsharp.Region(short.MinValue, short.MinValue, ushort.MaxValue, ushort.MaxValue)) { graphics.SetClipRegion(region, 0, 0); } }
/// <summary> /// <para>Construct a new <see cref="T:Xsharp.Region"/> /// instance that is initially set to the same area as another /// region object.</para> /// </summary> /// /// <param name="r"> /// <para>The other region object to copy. If <paramref name="r"/> /// is <see langword="null"/> or has been disposed, the new region /// will be set to the empty region.</para> /// </param> public Region(Region r) { lock(typeof(Region)) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } Union(r); } }
// Convert an Xsharp.Region to System.Drawing.Region internal static System.Drawing.Region RegionToDrawingRegion (Xsharp.Region region) { Xsharp.Rectangle[] rectangles = region.GetRectangles(); System.Drawing.Region newRegion = new System.Drawing.Region(); newRegion.MakeEmpty(); for (int i = 0; i < rectangles.Length; i++) { Xsharp.Rectangle rect = rectangles[i]; newRegion.Union(new System.Drawing.Rectangle (rect.x, rect.y, rect.width, rect.height)); } return(newRegion); }
// Convert a System.Drawing.Region to Xsharp.Region private static Xsharp.Region rectsToRegion(System.Drawing.Rectangle[] rectangles) { Xsharp.Region newRegion = new Xsharp.Region(); for (int i = 0; i < rectangles.Length; i++) { System.Drawing.Rectangle rect = rectangles[i]; // This implementation has a region size restriction. int left = RestrictXY(rect.Left); int top = RestrictXY(rect.Top); int right = RestrictXY(rect.Right); int bottom = RestrictXY(rect.Bottom); newRegion.Union(left, top, right - left, bottom - top); } return(newRegion); }
// Set the clipping region to infinite (i.e. disable clipping). public override void SetClipInfinite() { using (Xsharp.Region region = new Xsharp.Region(short.MinValue, short.MinValue, ushort.MaxValue, ushort.MaxValue)) { graphics.SetClipRegion( region, 0, 0); } }
// Set the clipping region to empty. public override void SetClipEmpty() { using (Xsharp.Region region = new Xsharp.Region()) { graphics.SetClipRegion( region, 0, 0); } }
// Paint this widget in response to an "Expose" event. protected override void OnPaint(Graphics graphics) { // Draw the thick 3D border around the outside first. graphics.DrawEffect(0, 0, width, height, Effect.Raised); // Get the rectangle containing the caption area. Rectangle rect = new Rectangle (FrameBorderSize, FrameBorderSize, width - FrameBorderSize * 2, captionHeight - FrameBorderSize); // If the rectangle does not overlap the expose region, // then there is no point drawing the main caption area. if(!graphics.ExposeRegion.Overlaps(rect)) { return; } // Get the colors to use for the foreground and background. Color foreground, background, endBackground; if((flags & CaptionFlags.Active) != 0) { foreground = new Color(StandardColor.HighlightForeground); background = new Color(StandardColor.HighlightBackground); endBackground = new Color(StandardColor.HighlightEndBackground); } else { foreground = new Color(StandardColor.Background); background = new Color(StandardColor.BottomShadow); endBackground = new Color(StandardColor.EndBackground); } // Create a gradient for the title bar, if necessary. if(gradient != null && (gradient.Width != rect.width || gradient.Height != rect.height)) { // The size has changed and we need a new gradient. gradient.Dispose(); gradient = null; } if(gradient == null && screen.DefaultDepth >= 15) { DotGNU.Images.Image image = CreateGradient (rect.width, rect.height, background, endBackground); gradient = new Xsharp.Image(screen, image.GetFrame(0)); image.Dispose(); } // Clear the caption background. if(gradient == null) { graphics.Foreground = background; graphics.SetFillSolid(); graphics.FillRectangle(rect); } else { graphics.SetFillTiled(gradient.Pixmap, rect.x, rect.y); graphics.FillRectangle(rect); graphics.SetFillSolid(); } // Draw the caption buttons and then subtract that // region off the caption rectangle so we don't get // bleed through when we draw the caption text. rect.width -= DrawCaptionButtons (graphics, rect, flags, (CaptionFlags)(~0)); // Bail out if the rectangle is too small for the text. if(rect.width <= 2) { return; } // Position the caption text. Font font = GetCaptionFont(); FontExtents extents = font.GetFontExtents(graphics); int textY = (rect.height - extents.Ascent) / 2; textY += rect.y + extents.Ascent; // Draw the caption text, clipped to the caption area // so that it won't overwrite the buttons on the right. using(Region region = new Region(graphics.ExposeRegion)) { region.Intersect(rect); graphics.SetClipRegion(region); graphics.Foreground = foreground; graphics.DrawString(rect.x + 2, textY, child.Name, font); } }
/* * <summary><p>Invalidate the given region and flush the request</p></summary> */ private void Invalidate(Region region) { if (drawBackground) { ClearRegion(region, XBool.True); } else { /* Don't flush to the X server cause we don't want it to draw the background */ region.Intersect(0, 0, width, height); if (exposeRegion == null) { exposeRegion = region; dpy.AddPendingExpose(this); } else { exposeRegion.Union(region); region.Dispose(); } } }
/// <summary> /// <para>Clone an instance of <see cref="T:Xsharp.Region"/>.</para> /// </summary> /// /// <remarks> /// <para>This method implements the <see cref="T:System.ICloneable"/> /// interface.</para> /// </remarks> public Object Clone() { Region r = new Region(); lock(typeof(Region)) { if(region != IntPtr.Zero) { Xlib.XUnionRegion(region, r.region, r.region); } } return r; }
// Place a minimized window rectangle. internal void PlaceMinimizedRectangle(ref Rectangle rect, Widget placed) { // Create a region that consists of all minimized areas. Region region = new Region(); Widget current = TopChild; while(current != null) { if(current is CaptionWidget && current.IsMapped && ((CaptionWidget)current).Child.IsIconic) { if(current != placed) { region.Union (current.x, current.y, current.width, current.height); } } current = current.NextBelow; } // Place the minimized rectangle. int yplace = height - rect.height; int xplace = 0; for(;;) { // Move up to the next line if we've overflowed this one. if((xplace + rect.width) > width && width >= rect.width) { yplace -= rect.height; xplace = 0; } // Determine if the rectangle overlaps the region. // If it doesn't, then we have found the best location. rect.x = xplace; rect.y = yplace; if(!region.Overlaps(rect)) { region.Dispose(); return; } // Move on to the next candidate. xplace += rect.width; } }
/// <summary> /// <para>Xor another region with this one.</para> /// </summary> /// /// <param name="r"> /// <para>The other region to xor with this one. If /// <paramref name="r"/> is <see langword="null"/> or disposed, /// then it will be treated as the empty region.</para> /// </param> /// /// <remarks> /// <para>If this region has been disposed, then it will be treated /// as empty prior to the xor operation.</para> /// </remarks> public void Xor(Region r) { lock(typeof(Region)) { if(region == IntPtr.Zero) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } if(r == null || r.region == IntPtr.Zero) { // Xor of an empty and a non-empty region gives // the non-empty region as the result. } else if(r == this) { // Xor the region with itself: result is empty. Xlib.XDestroyRegion(region); region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } else { Xlib.XXorRegion(region, r.region, region); } } }
/// <summary> /// <para>Subtract another region from this one.</para> /// </summary> /// /// <param name="r"> /// <para>The other region to subtract from this one. If /// <paramref name="r"/> is <see langword="null"/> or disposed, /// the method does nothing.</para> /// </param> /// /// <remarks> /// <para>If this region has been disposed, then it will be re-created /// with its initial contents set to empty.</para> /// </remarks> public void Subtract(Region r) { lock(typeof(Region)) { if(region == IntPtr.Zero) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } else if(r == null || r.region == IntPtr.Zero) { // Nothing to do here: subtracting an empty region. } else if(r == this) { // Subtract the region from itself: result is empty. Xlib.XDestroyRegion(region); region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } else { Xlib.XSubtractRegion(region, r.region, region); } } }
/// <summary> /// <para>Intersect another region with this one.</para> /// </summary> /// /// <param name="r"> /// <para>The other region to intersect with this one. If /// <paramref name="r"/> is <see langword="null"/> or disposed, /// the method operates as an intersection with the empty region.</para> /// </param> /// /// <remarks> /// <para>If this region has been disposed, then it will be re-created /// with its initial contents set to empty.</para> /// </remarks> public void Intersect(Region r) { lock(typeof(Region)) { if(region == IntPtr.Zero) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } else if(r == null || r.region == IntPtr.Zero) { Xlib.XDestroyRegion(region); region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } else if(r != this) { Xlib.XIntersectRegion(r.region, region, region); } } }
/// <summary> /// <para>Union another region with this one.</para> /// </summary> /// /// <param name="r"> /// <para>The other region to union with this one. If <paramref name="r"/> /// is <see langword="null"/>, the same as <see langword="this"/>, or /// disposed, then this method will do nothing.</para> /// </param> /// /// <remarks> /// <para>If this region has been disposed, then it will be re-created /// with its initial contents set to a copy of <paramref name="r"/>.</para> /// </remarks> public void Union(Region r) { lock(typeof(Region)) { if(r != null && r != this && r.region != IntPtr.Zero) { if(region == IntPtr.Zero) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } Xlib.XUnionRegion(region, r.region, region); } } }
// Set the clipping region to a single rectangle. public override void SetClipRect(int x, int y, int width, int height) { using (Xsharp.Region region = new Xsharp.Region(x, y, width, height)) { graphics.SetClipRegion( region, 0, 0); } }
// Clear a region to the background and optionally queue expose events. private bool ClearRegion(Region region, XBool exposures) { // Intersect the region with the widget boundaries. region.Intersect(0, 0, width, height); // Remove areas that are occupied by mapped child widgets. Widget child = TopChild; while(child != null) { if(child.mapped) { region.Subtract(child.x, child.y, child.width, child.height); } child = child.NextBelow; } // Bail out if the region is now empty. if(region.IsEmpty()) { return false; } // Lock down the display and send the "XClearArea" requests. try { IntPtr display = dpy.Lock(); XWindow handle = GetWidgetHandle(); IntPtr xregion = region.GetRegion(); XRectangle xrect; int size, index; size = Xlib.XSharpGetRegionSize(xregion); for(index = 0; index < size; ++index) { Xlib.XSharpGetRegionRect(xregion, index, out xrect); Xlib.XClearArea(display, handle, xrect.x, xrect.y, xrect.width, xrect.height, exposures); } } finally { dpy.Unlock(); } return true; }
// Convert a System.Drawing.Region to Xsharp.Region private static Xsharp.Region rectsToRegion( System.Drawing.Rectangle[] rectangles) { Xsharp.Region newRegion = new Xsharp.Region(); for( int i = 0; i < rectangles.Length; i++) { System.Drawing.Rectangle rect = rectangles[i]; // This implementation has a region size restriction. int left = RestrictXY(rect.Left); int top = RestrictXY(rect.Top); int right = RestrictXY(rect.Right); int bottom = RestrictXY(rect.Bottom); newRegion.Union( left, top, right - left, bottom - top); } return newRegion; }
// 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); } } }
/// <summary> /// <para>Force a repaint on a section of this widget.</para> /// </summary> /// /// <param name="x"> /// <para>The X co-ordinate of the top-left corner of /// the section to repaint.</para> /// </param> /// /// <param name="y"> /// <para>The Y co-ordinate of the top-left corner of /// the section to repaint.</para> /// </param> /// /// <param name="width"> /// <para>The width of the section to repaint.</para> /// </param> /// /// <param name="height"> /// <para>The height of the section to repaint.</para> /// </param> /// /// <exception cref="T:Xsharp.XException"> /// <para>Raised if <paramref name="x"/>, <paramref name="y"/>, /// <paramref name="width"/>, or <paramref name="height"/> are /// out of range.</para> /// </exception> public void Repaint(int x, int y, int width, int height) { if(x < -32768 || x > 32767 || y < -32768 || y > 32767) { throw new XException(S._("X_InvalidPosition")); } if(width < 1 || width > 32767 || height < 1 || height > 32767) { throw new XException(S._("X_InvalidSize")); } try { IntPtr display = dpy.Lock(); if(mapped && AncestorsMapped) { if(invalidateRegion == null) { // Create a new invalidate region for this widget. invalidateRegion = new Region(x, y, width, height); dpy.AddPendingInvalidate(this); } else { // Add the rectangle to the invalidate region. invalidateRegion.Union(x, y, width, height); } } } finally { dpy.Unlock(); } }
/// <summary> /// <para>Determine if another region overlaps with this region.</para> /// </summary> /// /// <param name="r"> /// <para>The other region to test against this region.</para> /// </param> /// /// <returns> /// <para>Returns <see langword="true"/> if <paramref name="r"/> overlaps /// with this region; <see langword="false"/> otherwise.</para> /// </returns> public bool Overlaps(Region r) { lock(typeof(Region)) { if(region == IntPtr.Zero) { return false; } else if(r == null || r.region == IntPtr.Zero) { return false; } else if(r == this) { return true; } else { IntPtr reg = Xlib.XCreateRegion(); if(reg == IntPtr.Zero) { Display.OutOfMemory(); } Xlib.XIntersectRegion(region, r.region, reg); bool result = (Xlib.XEmptyRegion(reg) == 0); Xlib.XDestroyRegion(reg); return result; } } }
/// <summary> /// <para>Update this widget by immediately redrawing invalidated /// regions.</para> /// </summary> /// /// <param name="clear"> /// <para>Setting clear to true clears the region to the background. /// </para> /// </param> public void Update(bool clear) { Region region = invalidateRegion; invalidateRegion = null; if(region != null) { // Remove the region from the pending list. dpy.RemovePendingInvalidate(this); // No point redrawing if we are unmapped or the // region to be drawn is empty. if(mapped && AncestorsMapped && (!clear || ClearRegion(region, XBool.False))) { // Paint the region as if we got a regular expose. Graphics graphics = new Graphics(this); graphics.exposeRegion = region; graphics.SetClipRegion(region); try { OnPaint(graphics); } finally { graphics.Dispose(); } } // Dispose the region that we no longer require. region.Dispose(); } }
// Remove this widget from the pending expose list. internal void RemovePendingExpose() { dpy.RemovePendingExpose(this); if(exposeRegion != null) { exposeRegion.Dispose(); exposeRegion = null; } }
/* * <summary><p>Invalidate the given region and flush the request</p></summary> */ private void Invalidate(int x, int y, int width, int height) { Region region = new Region(); region.Union(x, y, width, height); Invalidate(region); }
/// <summary> /// <para>Set the clip area to a region object, with a /// specified origin.</para> /// </summary> /// /// <param name="r"> /// <para>The clipping region to set.</para> /// </param> /// /// <param name="xorigin"> /// <para>The X co-ordinate of the clipping origin.</para> /// </param> /// /// <param name="yorigin"> /// <para>The Y co-ordinate of the clipping origin.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="r"/> value is /// <see langword="null"/>.</para> /// </exception> /// /// <exception cref="T:Xsharp.XException"> /// <para>The <paramref name="xorigin"/> or <paramref name="yorigin"/> /// value is out of range.</para> /// </exception> public void SetClipRegion(Region r, int xorigin, int yorigin) { if(r == null) { throw new ArgumentNullException("r"); } if(xorigin < -32768 || xorigin > 32767 || yorigin < -32768 || yorigin > 32767) { throw new XException(S._("X_PointCoordRange")); } try { IntPtr display = Lock(); Xlib.XSetClipOrigin(display, gc, xorigin, yorigin); Xlib.XSetRegion(display, gc, r.GetRegion()); if(clipRegion != r) { if(clipRegion != null) clipRegion.Dispose(); clipRegion = new Region(r); } } finally { dpy.Unlock(); } }
// Dispatch an event to this widget. internal override void DispatchEvent(ref XEvent xevent) { switch((EventType)(xevent.xany.type__)) { case EventType.Expose: case EventType.GraphicsExpose: { // Add the area to the expose region. if(exposeRegion == null) { // This is the first rectangle in an expose. exposeRegion = new Region ((int)(xevent.xexpose.x__), (int)(xevent.xexpose.y__), (int)(xevent.xexpose.width__), (int)(xevent.xexpose.height__)); // Queue this widget for later repainting. // We don't do it now or the system will be // very slow during opaque window drags. dpy.AddPendingExpose(this); } else { // This is an extra rectangle in an expose. exposeRegion.Union ((int)(xevent.xexpose.x__), (int)(xevent.xexpose.y__), (int)(xevent.xexpose.width__), (int)(xevent.xexpose.height__)); } } break; case Xsharp.Events.EventType.ClientMessage: { if(xevent.xclient.message_type == dpy.internalBeginInvoke) { OnBeginInvokeMessage((IntPtr)xevent.xclient.l(0)); } } break; } base.DispatchEvent(ref xevent); }
/// <summary> /// <para>Dispose this graphics context object.</para> /// </summary> /// /// <remarks> /// <para>This method implements the <see cref="T:System.IDisposable"/> /// interface.</para> /// </remarks> public void Dispose() { try { IntPtr display = dpy.Lock(); if(gc != IntPtr.Zero) { // Flush the double buffer if necessary. if(drawable is DoubleBuffer) { ((DoubleBuffer)drawable).End(this); } // Release the GC back to the screen's cache so // that we can reuse it the next time we need a GC. drawable.screen.ReleaseGC(gc, (drawable is Bitmap)); gc = IntPtr.Zero; } } finally { dpy.Unlock(); } if(exposeRegion != null) { exposeRegion.Dispose(); exposeRegion = null; } if(clipRegion != null ) { clipRegion.Dispose(); clipRegion = null; } isDisposed = true; }
// Process pending exposures on this widget. internal void Expose() { Region region = exposeRegion; if(region != null) { exposeRegion = null; // sometimes it could be that Expose is called but the handle is destroyed. // so check here, if handle not null. if( handle != XDrawable.Zero ) { try { Graphics graphics = new Graphics(this); graphics.exposeRegion = region; graphics.SetClipRegion(region); OnPaint(graphics); graphics.Dispose(); region.Dispose(); } catch( XInvalidOperationException ) { // irgnore Widget disposed exception } } } }
/// <summary> /// <para>Set the clip area to a region object.</para> /// </summary> /// /// <param name="r"> /// <para>The clipping region to set.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="r"/> value is /// <see langword="null"/>.</para> /// </exception> public void SetClipRegion(Region r) { if(r == null) { throw new ArgumentNullException("r"); } try { IntPtr display = Lock(); Xlib.XSetClipOrigin(display, gc, 0, 0); Xlib.XSetRegion(display, gc, r.GetRegion()); if(clipRegion != r) { if(clipRegion != null) clipRegion.Dispose(); clipRegion = new Region(r); } } finally { dpy.Unlock(); } }