// Constructor. internal Screen(Display dpy, int number, IntPtr screen) { // Copy parameters in from the create process. this.dpy = dpy; this.number = number; this.screen = screen; // Create the root window instance for this screen. rootWindow = new Xsharp.RootWindow (dpy, this, Xlib.XRootWindowOfScreen(screen)); // Get the default root visual for this screen. visual = Xlib.XDefaultVisualOfScreen(screen); // Create a "Colormap" object for the default colormap. defaultColormap = new Colormap (dpy, this, Xlib.XDefaultColormapOfScreen(screen)); // Create the GC cache. defaultGCs = new IntPtr [GCCacheSize]; bitmapGCs = new IntPtr [GCCacheSize]; // Initialize the standard colors. InitStandardColors(); // Create the placeholder window for parent-less widgets. placeholder = new PlaceholderWindow(rootWindow); // Create the grab window for managing popup window events. grabWindow = new GrabWindow(rootWindow); }
// Constructor. Called from the "Screen" class. internal RootWindow(Display dpy, Screen screen, XWindow handle) : base(dpy, screen, DrawableKind.Widget, null) { // Set this window's handle and add it to the handle map. this.handle = (XDrawable)handle; if(dpy.handleMap == null) { dpy.handleMap = new HandleMap(); } dpy.handleMap[handle] = this; // Adjust the root window object to match the screen state. width = (int)(Xlib.XWidthOfScreen(screen.screen)); height = (int)(Xlib.XHeightOfScreen(screen.screen)); mapped = true; autoMapChildren = false; // Get the current state of the RESOURCE_MANAGER property. // We extract color theme information from it. resourceManager = Xlib.XInternAtom (dpy.dpy, "RESOURCE_MANAGER", XBool.False); IntPtr resptr = Xlib.XSharpGetResources(dpy.dpy, handle); if(resptr != IntPtr.Zero) { resources = Marshal.PtrToStringAnsi(resptr); Xlib.XSharpFreeResources(resptr); } // Select for property notifications so that we can // track changes to the RESOURCE_MANAGER property. SelectInput(EventMask.PropertyChangeMask); }
// Constructor that is called from the "Screen" class. internal Colormap(Display dpy, Screen screen, XColormap colormap) { this.dpy = dpy; this.screen = screen; this.colormap = colormap; this.cachedPixels = new Hashtable(1024); // create hash with big capacity to avoid expansions of hashtable }
// Constructor. internal Widget(Display dpy, Screen screen, DrawableKind kind, Widget parent) : base(dpy, screen, kind) { // Set the initial widget properties. cursor = null; autoMapChildren = true; sensitive = true; // Insert this widget into the widget tree under its parent. this.parent = parent; this.topChild = null; this.nextAbove = null; if(parent != null) { ancestorSensitive = (parent.sensitive && parent.ancestorSensitive); nextBelow = parent.topChild; if(parent.topChild != null) { parent.topChild.nextAbove = this; } parent.topChild = this; } else { ancestorSensitive = true; nextBelow = null; } this.eventMask = 0; }
internal IntPtr GetFontSet(Display dpy, out FontExtents extents) { lock(typeof(Font)) { // Map this object to the one that actually stores // the font set information. Font font = (Font)(dpy.fonts[this]); if(font == null) { font = this; dpy.fonts[this] = this; } // Search for existing font set information. FontInfo info = font.infoList; while(info != null) { if(info.dpy == dpy) { extents = info.extents; return info.fontSet; } info = info.next; } // Create a new font set. IntPtr fontSet; int ascent, descent, maxWidth; try { IntPtr display = dpy.Lock(); fontSet = CreateFontSet (display, out ascent, out descent, out maxWidth); if(fontSet == IntPtr.Zero) { extents = null; return IntPtr.Zero; } } finally { dpy.Unlock(); } // Associate the font set with the display. info = new FontInfo(); info.next = font.infoList; info.extents = new FontExtents(ascent, descent, maxWidth); info.dpy = dpy; info.fontSet = fontSet; font.infoList = info; // Return the font set to the caller. extents = info.extents; return fontSet; } }
// Get the XFontSet structure for this font on a particular display. internal IntPtr GetFontSet(Display dpy) { FontExtents extents; return GetFontSet(dpy, out extents); }
// Internal constructor that wraps a pixmap XID. internal Pixmap(Display dpy, Screen screen, XPixmap pixmap) : base(dpy, screen, DrawableKind.Bitmap) { SetPixmapHandle(pixmap); try { // Get the geometry of the pixmap from the X server. IntPtr display = dpy.Lock(); XWindow root_return; Xlib.Xint x_return, y_return; Xlib.Xuint width_return, height_return; Xlib.Xuint border_width_return, depth_return; Xlib.XGetGeometry (display, handle, out root_return, out x_return, out y_return, out width_return, out height_return, out border_width_return, out depth_return); this.width = (int)width_return; this.height = (int)height_return; } finally { dpy.Unlock(); } }
/// <summary> /// <para>Construct a new application object, process command-line /// options, and open the display.</para> /// </summary> /// /// <param name="name"> /// <para>The resource name and class for the application.</para> /// </param> /// /// <param name="args"> /// <para>The arguments that came from the application's "Main" /// method.</para> /// </param> /// /// <exception cref="T:Xsharp.XCannotConnectException"> /// <para>A connection to the X display server could not /// be established.</para> /// </exception> public Application(String name, String[] args) { String[] envCmdLine; int firstArg = 0; String fontName; bool synchronous = false; // Set this as the primary application object if necessary. lock(typeof(Application)) { if(primary == null) { primary = this; } } // Choose defaults for the parameters. try { envCmdLine = Environment.GetCommandLineArgs(); } catch(NotSupportedException) { envCmdLine = null; } if(envCmdLine != null && envCmdLine.Length > 0) { programName = envCmdLine[0]; } else { programName = "Xsharp-application"; } if(name == null) { // Strip the path from the program name to // get the default resource name to use. int index = programName.LastIndexOf('/'); if(index == -1) { index = programName.LastIndexOf('\\'); } if(index != -1) { name = programName.Substring(index + 1); } else { name = programName; } int len = name.Length; if(len > 4 && name[len - 4] == '.' && (name[len - 3] == 'e' || name[len - 3] == 'E') && (name[len - 2] == 'x' || name[len - 2] == 'X') && (name[len - 1] == 'e' || name[len - 1] == 'E')) { name = name.Substring(0, len - 4); } } if(args == null) { if(envCmdLine != null && envCmdLine.Length > 0) { args = envCmdLine; firstArg = 1; } else { args = new String [0]; } } // Initialize the application state. resourceName = name; resourceClass = name; displayName = null; startIconic = false; title = null; geometry = null; fontName = null; // Process the standard Xt command-line options. ArrayList newArgs = new ArrayList(); while(firstArg < args.Length) { switch(args[firstArg]) { case "-display": { ++firstArg; if(firstArg < args.Length) { displayName = args[firstArg]; } } break; case "-iconic": { startIconic = true; } break; case "-name": { ++firstArg; if(firstArg < args.Length) { resourceName = args[firstArg]; } } break; case "-title": { ++firstArg; if(firstArg < args.Length) { title = args[firstArg]; } } break; case "-fn": case "-font": { ++firstArg; if(firstArg < args.Length) { fontName = args[firstArg]; } } break; case "-geometry": { ++firstArg; if(firstArg < args.Length) { geometry = args[firstArg]; } } break; case "+synchronous": case "-synchronous": { // Turn on synchronous processing to the X server. synchronous = true; } break; // Ignore other Xt toolkit options that aren't // relevant to us. We may add some of these later. case "-reverse": case "-rv": case "+rv": break; case "-bg": case "-background": case "-bw": case "-borderwidth": case "-bd": case "-bordercolor": case "-fg": case "-foreground": case "-selectionTimeout": case "-xnllanguage": case "-xrm": case "-xtsessionID": ++firstArg; break; default: { // Unknown option - copy it to "newArgs". newArgs.Add(args[firstArg]); } break; } ++firstArg; } cmdLineArgs = (String[])(newArgs.ToArray(typeof(String))); // Connect to the display. if(displayName == null) { // Xlib will figure it by itself, but classes using displayName can get broken is it's null displayName = Environment.GetEnvironmentVariable("DISPLAY"); } display = Xsharp.Display.Open(displayName, this, synchronous); // Create the default font. defaultFont = Font.CreateFromXLFD(fontName); defaultFont.GetFontSet(display); }
/// <summary> /// <para>Close the application if it is currently active.</para> /// </summary> public void Close() { lock(typeof(Application)) { if(display != null) { display.Close(); display = null; } if(primary == this) { primary = null; } } }
// Load builtin bitmaps for a particular display. public BuiltinBitmaps(Display display) { IntPtr dpy = display.dpy; XDrawable drawable = display.DefaultRootWindow.handle; RadioBottom = Xlib.XCreateBitmapFromData (dpy, drawable, radio_b_bits, (uint)12, (uint)12); RadioBottomEnhanced = Xlib.XCreateBitmapFromData (dpy, drawable, radio_B_bits, (uint)12, (uint)12); RadioTop = Xlib.XCreateBitmapFromData (dpy, drawable, radio_t_bits, (uint)12, (uint)12); RadioTopEnhanced = Xlib.XCreateBitmapFromData (dpy, drawable, radio_T_bits, (uint)12, (uint)12); RadioBackground = Xlib.XCreateBitmapFromData (dpy, drawable, radio_w_bits, (uint)12, (uint)12); RadioForeground = Xlib.XCreateBitmapFromData (dpy, drawable, radio_f_bits, (uint)12, (uint)12); Close = Xlib.XCreateBitmapFromData (dpy, drawable, close_button_bits, (uint)9, (uint)9); Minimize = Xlib.XCreateBitmapFromData (dpy, drawable, minimize_button_bits, (uint)9, (uint)9); Maximize = Xlib.XCreateBitmapFromData (dpy, drawable, maximize_button_bits, (uint)9, (uint)9); Restore = Xlib.XCreateBitmapFromData (dpy, drawable, restore_button_bits, (uint)9, (uint)9); Help = Xlib.XCreateBitmapFromData (dpy, drawable, help_button_bits, (uint)9, (uint)9); }
/// <summary> /// <para>Constructs a new <see cref="T:Xsharp.Graphics"/> object and /// attaches it to a <see cref="T:Xsharp.Drawable"/> instance.</para> /// </summary> /// /// <param name="drawable"> /// <para>The drawable to attach this graphics context to. If the /// drawable is a widget, the foreground and background colors of the /// graphics object will be initially set to the widget's standard /// foreground and background colors.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>Raised if <paramref name="drawable"/> is <see langword="null"/>. /// </para> /// </exception> /// /// <exception cref="T:Xsharp.XInvalidOperationException"> /// <para>Raised if <paramref name="drawable"/> does not support /// output, is disposed, or is the root window.</para> /// </exception> public Graphics(Drawable drawable) { if(drawable == null) { throw new ArgumentNullException("drawable"); } else if(drawable.Kind == DrawableKind.InputOnlyWidget) { throw new XInvalidOperationException (S._("X_GraphicsIsOutputOnly")); } else if(drawable is RootWindow) { throw new XInvalidOperationException (S._("X_NonRootOperation")); } dpy = drawable.dpy; this.drawable = drawable; XGCValues gcValues = new XGCValues(); InputOutputWidget widget = (drawable as InputOutputWidget); DoubleBuffer buffer = (drawable as DoubleBuffer); Bitmap bitmap = (drawable as Bitmap); if(widget != null) { foreground = widget.Foreground; background = widget.Background; } else if(buffer != null) { foreground = buffer.Widget.Foreground; background = buffer.Widget.Background; } else if(bitmap != null) { foreground = new Color(0x00, 0x00, 0x00); background = new Color(0xFF, 0xFF, 0xFF); } else { foreground = new Color (StandardColor.Foreground); background = new Color (StandardColor.Background); } gcValues.foreground = drawable.ToPixel(foreground); gcValues.background = drawable.ToPixel(background); if(drawable is DoubleBuffer) { ((DoubleBuffer)drawable).Start(this); } try { IntPtr display = dpy.Lock(); drawableHandle = drawable.GetGCHandle(); gc = drawable.screen.GetGC(bitmap != null); if(gc == IntPtr.Zero) { // Create a new GC because the cache is empty. gc = Xlib.XCreateGC(display, drawableHandle, (uint)(GCValueMask.GCForeground | GCValueMask.GCBackground), ref gcValues); if(gc == IntPtr.Zero) { Display.OutOfMemory(); } } else { // Reset the cached GC back to the default settings. // Xlib will take care of stripping the list down // to just the changes that need to be applied. gcValues.function = Xsharp.GCFunction.GXcopy; gcValues.plane_mask = ~((XPixel)0); gcValues.line_width = 0; gcValues.line_style = Xsharp.LineStyle.LineSolid; gcValues.cap_style = Xsharp.CapStyle.CapButt; gcValues.join_style = Xsharp.JoinStyle.JoinMiter; gcValues.fill_style = Xsharp.FillStyle.FillSolid; gcValues.fill_rule = Xsharp.FillRule.EvenOddRule; gcValues.arc_mode = Xsharp.ArcMode.ArcPieSlice; gcValues.ts_x_origin = 0; gcValues.ts_y_origin = 0; gcValues.subwindow_mode = Xsharp.SubwindowMode.ClipByChildren; gcValues.graphics_exposures = true; gcValues.clip_x_origin = 0; gcValues.clip_y_origin = 0; gcValues.clip_mask = XPixmap.Zero; gcValues.dash_offset = 0; gcValues.dashes = (sbyte)4; Xlib.XChangeGC(display, gc, (uint)(GCValueMask.GCFunction | GCValueMask.GCPlaneMask | GCValueMask.GCForeground | GCValueMask.GCBackground | GCValueMask.GCLineWidth | GCValueMask.GCLineStyle | GCValueMask.GCCapStyle | GCValueMask.GCJoinStyle | GCValueMask.GCFillStyle | GCValueMask.GCFillRule | GCValueMask.GCTileStipXOrigin | GCValueMask.GCTileStipYOrigin | GCValueMask.GCSubwindowMode | GCValueMask.GCGraphicsExposures | GCValueMask.GCClipXOrigin | GCValueMask.GCClipYOrigin | GCValueMask.GCClipMask | GCValueMask.GCDashOffset | GCValueMask.GCDashList | GCValueMask.GCArcMode), ref gcValues); } int sn = drawable.screen.ScreenNumber; double px, mm; px = (double)Xlib.XDisplayWidth(display, sn); mm = (double)Xlib.XDisplayWidthMM(display, sn); dpiX = (float)((px * 25.4) / mm); px = (double)Xlib.XDisplayHeight(display, sn); mm = (double)Xlib.XDisplayHeightMM(display, sn); dpiY = (float)((px * 25.4) / mm); } finally { dpy.Unlock(); } if(drawable is DoubleBuffer) { ((DoubleBuffer)drawable).ClearAtStart(this); } isDisposed = false; }
// Get the number of milliseconds until the next timeout. // Returns -1 if there are no active timers. internal static int GetNextTimeout(Display dpy) { lock(dpy) { if(dpy.timerQueue != null) { DateTime fireAt = dpy.timerQueue.nextDue; long diff = fireAt.Ticks - DateTime.UtcNow.Ticks; if(diff <= 0) { // The timeout has already fired or is about to. return 0; } else if (diff > (dpy.timerQueue.period * TimeSpan.TicksPerMillisecond)) { // The next due time is farther away than the time period we're // supposed to wait. This propably means the system clock has // been turned back (either manually or by NTP). In this case // we must calculate a new due time and just return 0. FixTimers( dpy.timerQueue ); /* dpy.timerQueue.nextDue = DateTime.UtcNow + new TimeSpan (dpy.timerQueue.period * TimeSpan.TicksPerMillisecond); */ return 0; } else if (diff > (100 * TimeSpan.TicksPerSecond)) { // Don't wait more than 100 seconds at a time. return 100000; } else { // Return the number of milliseconds + 1. // The "+ 1" takes care of rounding errors // due to converting ticks to milliseconds. return ((int)(diff / TimeSpan.TicksPerMillisecond)) + 1; } } } return -1; }
/// <summary> /// <para>Determine if the X server can support embedding.</para> /// </summary> /// /// <param name="dpy"> /// <para>The display to check.</para> /// </param> /// /// <returns> /// <para>Returns <see langword="true"/> if he display supports /// embedding, or <see langword="false"/> otherwise.</para> /// </returns> /// /// <remarks> /// <para>If this method returns <see langword="false"/>, then /// calling <c>Launch</c> will cause the child application to be /// displayed in its own top-level window, rather than being /// embedded directly as a child widget.</para> /// </remarks> public static bool CanEmbed(Display dpy) { String displayName; if(dpy == null) { return false; } return CanEmbed(dpy, false, out displayName); }
// Activate timers that have fired on a particular display. // We assume that this is called with the display lock. internal static bool ActivateTimers(Display dpy) { // Bail out early if there are no timers, to avoid // calling "DateTime.UtcNow" if we don't need to. if(dpy.timerQueue == null) { return false; } DateTime now = DateTime.UtcNow; Timer timer; DateTime next; bool activated = false; for(;;) { // Remove the first timer from the queue if // it has expired. Bail out if it hasn't. timer = dpy.timerQueue; if(timer == null) { break; } else if(timer.nextDue <= now) { timer.RemoveTimer(); } else { break; } // Invoke the timer's callback delegate. activated = true; if(timer.callback is TimerCallback) { TimerCallback cb1 = timer.callback as TimerCallback; dpy.Unlock(); try { cb1(timer.state); } finally { dpy.Lock(); } } else { EventHandler cb2 = timer.callback as EventHandler; dpy.Unlock(); try { cb2(timer.state, EventArgs.Empty); } finally { dpy.Lock(); } } // Add the timer back onto the queue if necessary. if(!timer.stopped && !timer.onDisplayQueue) { if(timer.period < 0) { timer.stopped = true; } else { next = timer.nextDue + new TimeSpan(timer.period * TimeSpan.TicksPerMillisecond); // if the next due is less than now, the date/time may have changed. // since the timer expired right now the next due might be now + period if(next <= now) { next += new TimeSpan (((((Int64)(now - next).TotalMilliseconds) / timer.period) + 1) * timer.period * TimeSpan.TicksPerMillisecond); } /* do not increment here, since the time might have changed with years this would do a long loop here while(next <= now) { next += new TimeSpan (timer.period * TimeSpan.TicksPerMillisecond); } */ timer.nextDue = next; timer.AddTimer(); } } } return activated; }
/// <summary> /// <para>Create a new timer.</para> /// </summary> /// /// <param name="dpy"> /// <para>The display to create the timer for, or <see langword="null"/> /// to use the application's primary display.</para> /// </param> /// /// <param name="callback"> /// <para>The delegate to invoke when the timer expires.</para> /// </param> /// /// <param name="state"> /// <para>The state information to pass to the callback.</para> /// </param> /// /// <param name="dueTime"> /// <para>The number of milliseconds until the timer expires /// for the first time.</para> /// </param> /// /// <param name="period"> /// <para>The number of milliseconds between timer expiries, or /// -1 to only expire once at <paramref name="dueTime"/>.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="callback"/> parameter is /// <see langword="null"/>.</para> /// </exception> /// /// <exception cref="T:System.ArgumentOutOfRangeException"> /// <para>The <paramref name="dueTime"/> parameter is /// less than zero.</para> /// </exception> public Timer(Display dpy, EventHandler callback, Object state, int dueTime, int period) { if(callback == null) { throw new ArgumentNullException("callback"); } if(dpy == null) { this.dpy = Application.Primary.Display; } else { this.dpy = dpy; } if(dueTime < 0) { throw new ArgumentOutOfRangeException ("dueTime", S._("X_NonNegative")); } this.callback = callback; this.state = state; this.nextDue = DateTime.UtcNow + new TimeSpan (dueTime * TimeSpan.TicksPerMillisecond); this.period = period; this.stopped = false; AddTimer(); }
/// <summary> /// <para>Create a new timer.</para> /// </summary> /// /// <param name="dpy"> /// <para>The display to create the timer for, or <see langword="null"/> /// to use the application's primary display.</para> /// </param> /// /// <param name="callback"> /// <para>The delegate to invoke when the timer expires.</para> /// </param> /// /// <param name="state"> /// <para>The state information to pass to the callback.</para> /// </param> /// /// <param name="dueTime"> /// <para>The number of milliseconds until the timer expires /// for the first time.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>The <paramref name="callback"/> parameter is /// <see langword="null"/>.</para> /// </exception> /// /// <exception cref="T:System.ArgumentOutOfRangeException"> /// <para>The <paramref name="dueTime"/> parameter is /// less than zero.</para> /// </exception> public Timer(Display dpy, TimerCallback callback, Object state, int dueTime) : this(dpy, callback, state, dueTime, -1) {}
// Disassociate this font from a particular display. internal void Disassociate(Display dpy) { lock(typeof(Font)) { FontInfo info, prev; info = infoList; prev = null; while(info != null && info.dpy != dpy) { prev = info; info = info.next; } if(info != null) { if(prev != null) { prev.next = info.next; } else { infoList = info.next; } FreeFontSet(dpy.dpy, info.fontSet); } } }
// Constructor. public AppGroupWidget(Display dpy, Screen screen, XAppGroup group, EmbeddedApplication parent) : base(dpy, screen, DrawableKind.Widget, null) { embedParent = parent; handle = (XDrawable)group; dpy.handleMap[(XWindow)handle] = this; }
// Determine if the X server supports embedding - inner version. // "displayName" will be set to a non-null value if it is necessary // to redirect the DISPLAY environment variable elsewhere. private static bool CanEmbed(Display display, bool reportErrors, out String displayName) { IntPtr dpy; Xlib.Xint major, minor; String client; int index; displayName = null; try { dpy = display.Lock(); // See if the X server supports XC-APPGROUP and SECURITY. if(Xlib.XagQueryVersion(dpy, out major, out minor) == XBool.False) { if(reportErrors && !errorReported) { Console.Error.WriteLine ("The X server `{0}' does not support the " + "XC-APPGROUP extension,", display.displayName); Console.Error.WriteLine ("which is required for application " + "embedding."); errorReported = true; } return false; } if(Xlib.XSecurityQueryExtension(dpy, out major, out minor) == XBool.False) { if(reportErrors && !errorReported) { Console.Error.WriteLine ("The X server `{0}' does not support the " + "SECURITY extension,", display.displayName); Console.Error.WriteLine ("which is required for for application " + "embedding."); errorReported = true; } return false; } // If we are in an ssh shell account, then we cannot // connect via ssh's X11 forwarding mechanism as it // does not know how to proxy appgroup security tokens. // Try to discover where the ssh client actually lives. displayName = Environment.GetEnvironmentVariable ("XREALDISPLAY"); client = Environment.GetEnvironmentVariable("SSH_CLIENT"); if(displayName != null && displayName.Length > 0) { // The user specified a display override with // the XREALDISPLAY environment variable. if(!ProbeDisplay(displayName, reportErrors)) { displayName = null; return false; } } else if(client != null && client.Length > 0) { // Synthesize a display name from the ssh client name. index = client.IndexOf(' '); if(index == -1) { index = client.Length; } displayName = client.Substring(0, index) + ":0.0"; if(!ProbeDisplay(displayName, reportErrors)) { displayName = null; return false; } } else if(Environment.GetEnvironmentVariable("SSH_ASKPASS") != null || Environment.GetEnvironmentVariable("SSH_TTY") != null) { // Older versions of bash do not export SSH_CLIENT // within an ssh login session. if(reportErrors && !errorReported) { Console.Error.WriteLine ("The `SSH_CLIENT' environment variable " + "is not exported from the shell."); Console.Error.WriteLine ("Either export `SSH_CLIENT' or set the " + "`XREALDISPLAY' environment"); Console.Error.WriteLine ("variable to the name of the real " + "X display."); errorReported = true; } displayName = null; return false; } else { // No ssh, so use the original "DISPLAY" value as-is. displayName = null; } } catch(MissingMethodException) { displayName = null; return false; } catch(DllNotFoundException) { displayName = null; return false; } catch(EntryPointNotFoundException) { displayName = null; return false; } finally { display.Unlock(); } return true; }
// Constructor. internal Drawable(Display dpy, Screen screen, DrawableKind kind) { this.dpy = dpy; this.screen = screen; this.kind = kind; }