arsd.simpledisplay

simpledisplay.d provides basic cross-platform GUI-related functionality, including creating windows, drawing on them, working with the clipboard, timers, OpenGL, and more. However, it does NOT provide high level GUI widgets. See my minigui.d, an extension to this module, for that functionality.

Discussion

simpledisplay provides cross-platform wrapping for Windows and Linux (and perhaps other OSes that use X11), but also does not prevent you from using the underlying facilities if you need them. It has a goal of working efficiently over a remote X link (at least as far as Xlib reasonably allows.)

simpledisplay depends on [arsd.color|color.d], which should be available from the same place where you got this file. Other than that, however, it has very few dependencies and ones that don't come with the OS and/or the compiler are all opt-in.

simpledisplay.d's home base is on my arsd repo on Github. The file is: https://github.com/adamdruppe/arsd/blob/master/simpledisplay.d

simpledisplay is basically stable. I plan to refactor the internals, and may add new features and fix bugs, but It do not expect to significantly change the API. It has been stable a few years already now.

Installation instructions: simpledisplay.d does not have any dependencies outside the operating system and color.d, so it should just work most the time, but there are a few caveats on some systems:

Please note when compiling on Win64, you need to explicitly list -Lgdi32.lib -Luser32.lib on the build command. If you want the Windows subsystem too, use -L/subsystem:windows -L/entry:mainCRTStartup.

On Win32, you can pass -L/subsystem:windows if you don't want a console to be automatically allocated.

On Mac, when compiling with X11, you need XQuartz and -L-L/usr/X11R6/lib passed to dmd. If using the Cocoa implementation on Mac, you need to pass -L-framework -LCocoa to dmd.

On Ubuntu, you might need to install X11 development libraries to successfully link.



Jump list: Don't worry, you don't have to read this whole documentation file!

Check out the [#Event-example] and [#Pong-example] to get started quickly.

The main classes you may want to create are [SimpleWindow], [Timer], [Image], and [Sprite].

The main functions you'll want are [setClipboardText] and [getClipboardText].

There are also platform-specific functions available such as [XDisplayConnection] and [GetAtom] for X11, among others.

See the examples and topics list below to learn more.





The goal here is to give some complete programs as overview examples first, then a look at each major feature with working examples first, then, finally, the inline class and method list will follow.

Scan for headers for a topic - they will visually stand out - you're interested in to get started quickly and feel free to copy and paste any example as a starting point for your program. I encourage you to learn the library by experimenting with the examples!

All examples are provided with no copyright restrictions whatsoever. You do not need to credit me or carry any kind of notice with the source if you copy and paste from them.

To get started, download simpledisplay.d and color.d to a working directory. Copy an example info a file called example.d and compile using the command given at the top of each example.

If you need help, email me: destructionator@gmail.com or IRC us, #d on Freenode (I am destructionator or adam_d_ruppe there). If you learn something that isn't documented, I appreciate pull requests on github to this file.

At points, I will talk about implementation details in the documentation. These are sometimes subject to change, but nevertheless useful to understand what is really going on. You can learn more about some of the referenced things by searching the web for info about using them from C. You can always look at the source of simpledisplay.d too for the most authoritative source on its specific implementation. If you disagree with how I did something, please contact me so we can discuss it!

Examples

This program creates a window and draws events inside them as they happen, scrolling the text in the window as needed. Run this program and experiment to get a feel for where basic input events take place in the library.

  1. // dmd example.d simpledisplay.d color.d import arsd.simpledisplay; import std.conv; void main() { auto window = new SimpleWindow(Size(500, 500), "Event example - simpledisplay.d"); int y = 0; void addLine(string text) { auto painter = window.draw(); if(y + painter.fontHeight >= window.height) { painter.scrollArea(Point(0, 0), window.width, window.height, 0, painter.fontHeight); y -= painter.fontHeight; } painter.outlineColor = Color.red; painter.fillColor = Color.black; painter.drawRectangle(Point(0, y), window.width, painter.fontHeight); painter.outlineColor = Color.white; painter.drawText(Point(10, y), text); y += painter.fontHeight; } window.eventLoop(1000, () { addLine("Timer went off!"); }, (KeyEvent event) { addLine(to!string(event)); }, (MouseEvent event) { addLine(to!string(event)); }, (dchar ch) { addLine(to!string(ch)); } ); }


If you are interested in more game writing with D, check out my gamehelpers.d which builds upon simpledisplay, and its other stand-alone support modules, simpleaudio.d and joystick.d, too.

This program displays a pie chart. Clicking on a color will increase its share of the pie.





The [SimpleWindow] class is simpledisplay's flagship feature. It represents a single window on the user's screen.

You may create multiple windows, if the underlying platform supports it. You may check static if(multipleWindowsSupported) at compile time, or catch exceptions thrown by SimpleWindow's constructor at runtime to handle those cases.

A single running event loop will handle as many windows as needed.

setEventHandlers function eventLoop function draw function title property

The simpledisplay event loop is designed to handle common cases easily while being extensible for more advanced cases, or replaceable by other libraries.

The most common scenario is creating a window, then calling [SimpleWindow.eventLoop|window.eventLoop] when setup is complete. You can pass several handlers to the eventLoop method right there:

  1. // dmd example.d simpledisplay.d color.d import arsd.simpledisplay; void main() { auto window = new SimpleWindow(200, 200); window.eventLoop(0, delegate (dchar) { /* got a character key press */ } ); }




On Linux, the event loop is implemented with the epoll system call for efficiency an extensibility to other files. On Windows, it runs a traditional GetMessage + DispatchMessage loop, with a call to SleepEx in each iteration to allow the thread to enter an alertable wait state regularly, primarily so Overlapped I/O callbacks will get a chance to run.

On Linux, simpledisplay also supports my [arsd.eventloop] module. Compile your program, including the eventloop.d file, with the -version=with_eventloop switch.

It should be possible to integrate simpledisplay with vibe.d as well, though I haven't tried.

Notification area icons are currently implemented on X11 and Windows. On X11, it defaults to using libnotify to show bubbles, if available, and will do a custom bubble window if not. You can version=without_libnotify to avoid this run-time dependency, if you like.

There are event handlers for low-level keyboard and mouse events, and higher level handlers for character events.

To draw on your window, use the [SimpleWindow.draw] method. It returns a [ScreenPainter] structure with drawing methods.

Important: ScreenPainter double-buffers and will not actually update the window until its destructor is run. Always ensure the painter instance goes out-of-scope before proceeding. You can do this by calling it inside an event handler, a timer callback, or an small scope inside main. For example:

  1. // dmd example.d simpledisplay.d color.d import arsd.simpledisplay; void main() { auto window = new SimpleWindow(200, 200); { // introduce sub-scope auto painter = window.draw(); // begin drawing /* draw here */ painter.outlineColor = Color.red; painter.fillColor = Color.black; painter.drawRectangle(Point(0, 0), 200, 200); } // end scope, calling `painter`'s destructor, drawing to the screen. window.eventLoop(0); // handle events }


Painting is done based on two color properties, a pen and a brush.

At this time, the 2d drawing does not support alpha blending. If you need that, use a 2d OpenGL context instead. FIXME add example of 2d opengl drawing here simpledisplay can create OpenGL contexts on your window. It works quite differently than 2d drawing.

Note that it is still possible to draw 2d on top of an OpenGL window, using the draw method, though I don't recommend it.

To start, you create a [SimpleWindow] with OpenGL enabled by passing the argument [OpenGlOptions.yes] to the constructor.

Next, you set [SimpleWindow.redrawOpenGlScene|window.redrawOpenGlScene] to a delegate which draws your frame.

To force a redraw of the scene, call [SimpleWindow.redrawOpenGlScene|window.redrawOpenGlSceneNow()].

Please note that my experience with OpenGL is very out-of-date, and the bindings in simpledisplay reflect that. If you want to use more modern functions, you may have to define the bindings yourself, or import them from another module. However, the OpenGL context creation done in simpledisplay will work for any version.

This example program will draw a rectangle on your window:

  1. // dmd example.d simpledisplay.d color.d import arsd.simpledisplay; void main() { }


You can also load PNG images using [arsd.png].

  1. // dmd example.d simpledisplay.d color.d png.d import arsd.simpledisplay; import arsd.png; void main() { auto image = Image.fromMemoryImage(readPng("image.png")); displayImage(image); }


Compile with dmd example.d simpledisplay.d png.d.

If you find an image file which is a valid png that [arsd.png] fails to load, please let me know. In the mean time of fixing the bug, you can probably convert the file into an easier-to-load format. Be sure to turn OFF png interlacing, as that isn't supported. Other things to try would be making the image smaller, or trying 24 bit truecolor mode with an alpha channel.

The [Sprite] class is used to make images on the display server for fast blitting to screen. This is especially important to use to support fast drawing of repeated images on a remote X11 link.

The free functions [getClipboardText] and [setClipboardText] consist of simpledisplay's cross-platform clipboard support at this time.

It also has helpers for handling X-specific events.

There are two timers in simpledisplay: one is the pulse timeout you can set on the call to window.eventLoop, and the other is a customizable class, [Timer].

The pulse timeout is used by setting a non-zero interval as the first argument to eventLoop function and adding a zero-argument delegate to handle the pulse.

  1. import arsd.simpledisplay; void main() { auto window = new SimpleWindow(400, 400); // every 100 ms, it will draw a random line // on the window. window.eventLoop(100, { auto painter = window.draw(); import std.random; // random color painter.outlineColor = Color(uniform(0, 256), uniform(0, 256), uniform(0, 256)); // random line painter.drawLine( Point(uniform(0, window.width), uniform(0, window.height)), Point(uniform(0, window.width), uniform(0, window.height))); }); }


The Timer class works similarly, but is created separately from the event loop. (It still fires through the event loop, though.) You may make as many instances of Timer as you wish.

The pulse timer and instances of the [Timer] class may be combined at will.

  1. import arsd.simpledisplay; void main() { auto window = new SimpleWindow(400, 400); auto timer = new Timer(1000, delegate { auto painter = window.draw(); painter.clear(); }); window.eventLoop(0); }


Timers are currently only implemented on Windows, using SetTimer and Linux, using timerfd_create. These deliver timeout messages through your application event loop.

simpledisplay carries a lot of code to help implement itself without extra dependencies, and much of this code is available for you too, so you may extend the functionality yourself.

See also: xwindows.d from my github.

handleNativeEvent and handleNativeGlobalEvent.

Integration with a third-party event loop is possible.

On Linux, you might want to support both terminal input and GUI input. You can do this by using simpledisplay together with eventloop.d and terminal.d.

simpledisplay does not provide GUI widgets such as text areas, buttons, checkboxes, etc. It only gives basic windows, the ability to draw on it, receive input from it, and access native information for extension. You may write your own gui widgets with these, but you don't have to because I already did for you!

Download minigui.d from my github repository and add it to your project. minigui builds these things on top of simpledisplay and offers its own Window class (and subclasses) to use that wrap SimpleWindow, adding a new event and drawing model that is hookable by subwidgets, represented by their own classes.

Migrating to minigui from simpledisplay is often easy though, because they both use the same ScreenPainter API, and the same simpledisplay events are available, if you want them. (Though you may like using the minigui model, especially if you are familiar with writing web apps in the browser with Javascript.)

minigui still needs a lot of work to be finished at this time, but it already offers a number of useful classes.

Windows tips: You can add icons or manifest files to your exe using a resource file.

To create a Windows .ico file, use the gimp or something. I'll write a helper program later.

Create yourapp.rc:

`rc 1 ICON filename.ico CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "YourApp.exe.manifest" `

And yourapp.exe.manifest:

`xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> Your application description here. `





I don't have a Mac, so that code isn't maintained. I would like to have a Cocoa implementation though.

The NativeSimpleWindowImplementation and NativeScreenPainterImplementation both suck. If I was rewriting it, I wouldn't do it that way again.

This file must not have any more required dependencies. If you need bindings, add them right to this file. Once it gets into druntime and is there for a while, remove bindings from here to avoid conflicts (or put them in an appropriate version block so it continues to just work on old dmd), but wait a couple releases before making the transition so this module remains usable with older versions of dmd.

You may have optional dependencies if needed by putting them in version blocks or template functions. You may also extend the module with other modules with UFCS without actually editing this - that is nice to do if you can.

Try to make functions work the same way across operating systems. I typically make it thinly wrap Windows, then emulate that on Linux.

A goal of this is to keep a gui hello world to less than 250 KB. This means avoiding Phobos! So try to avoid it.

See more comments throughout the source.

I realize this file is fairly large, but over half that is just bindings at the bottom or documentation at the top. Some of the classes are a bit big too, but hopefully easy to understand. I suggest you jump around the source by looking for a particular declaration you're interested in, like class SimpleWindow using your editor's search function, then look at one piece at a time.

Authors

Adam D. Ruppe with the help of others. If you need help, please email me with destructionator@gmail.com or find me on IRC. Our channel is #d on Freenode. I go by Destructionator or adam_d_ruppe, depending on which computer I'm logged into.

I live in the eastern United States, so I will most likely not be around at night in that US east timezone.

License

Copyright Adam D. Ruppe, 2011-2017. Released under the Boost Software License.

Building documentation: You may wish to use the arsd.ddoc file from my github with building the documentation for simpledisplay yourself. It will give it a bit more style. Simply download the arsd.ddoc file and add it to your compile command when building docs. dmd -c simpledisplay.d color.d -D arsd.ddoc

Examples



This program creates a little Pong-like game. Player one is controlled with the keyboard. Player two is controlled with the mouse. It demos the pulse timer, event handling, and some basic drawing.

  1. // dmd example.d simpledisplay.d color.d import arsd.simpledisplay; enum paddleMovementSpeed = 8; enum paddleHeight = 48; void main() { auto window = new SimpleWindow(600, 400, "Pong game!"); int playerOnePosition, playerTwoPosition; int playerOneMovement, playerTwoMovement; int playerOneScore, playerTwoScore; int ballX, ballY; int ballDx, ballDy; void serve() { import std.random; ballX = window.width / 2; ballY = window.height / 2; ballDx = uniform(-4, 4) * 3; ballDy = uniform(-4, 4) * 3; if(ballDx == 0) ballDx = uniform(0, 2) == 0 ? 3 : -3; } serve(); window.eventLoop(50, // set a 50 ms timer pulls // This runs once per timer pulse delegate () { auto painter = window.draw(); painter.clear(); // Update everyone's motion playerOnePosition += playerOneMovement; playerTwoPosition += playerTwoMovement; ballX += ballDx; ballY += ballDy; // Bounce off the top and bottom edges of the window if(ballY + 7 >= window.height) ballDy = -ballDy; if(ballY - 8 <= 0) ballDy = -ballDy; // Bounce off the paddle, if it is in position if(ballX - 8 <= 16) { if(ballY + 7 > playerOnePosition && ballY - 8 < playerOnePosition + paddleHeight) { ballDx = -ballDx + 1; // add some speed to keep it interesting ballDy += playerOneMovement; // and y movement based on your controls too ballX = 24; // move it past the paddle so it doesn't wiggle inside } else { // Missed it playerTwoScore ++; serve(); } } if(ballX + 7 >= window.width - 16) { // do the same thing but for player 1 if(ballY + 7 > playerTwoPosition && ballY - 8 < playerTwoPosition + paddleHeight) { ballDx = -ballDx - 1; ballDy += playerTwoMovement; ballX = window.width - 24; } else { // Missed it playerOneScore ++; serve(); } } // Draw the paddles painter.outlineColor = Color.black; painter.drawLine(Point(16, playerOnePosition), Point(16, playerOnePosition + paddleHeight)); painter.drawLine(Point(window.width - 16, playerTwoPosition), Point(window.width - 16, playerTwoPosition + paddleHeight)); // Draw the ball painter.fillColor = Color.red; painter.outlineColor = Color.yellow; painter.drawEllipse(Point(ballX - 8, ballY - 8), Point(ballX + 7, ballY + 7)); // Draw the score painter.outlineColor = Color.blue; import std.conv; painter.drawText(Point(64, 4), to!string(playerOneScore)); painter.drawText(Point(window.width - 64, 4), to!string(playerTwoScore)); }, delegate (KeyEvent event) { // Player 1's controls are the arrow keys on the keyboard if(event.key == Key.Down) playerOneMovement = event.pressed ? paddleMovementSpeed : 0; if(event.key == Key.Up) playerOneMovement = event.pressed ? -paddleMovementSpeed : 0; }, delegate (MouseEvent event) { // Player 2's controls are mouse movement while the left button is held down if(event.type == MouseEventType.motion && (event.modifierState & ModifierState.leftButtonDown)) { if(event.dy > 0) playerTwoMovement = paddleMovementSpeed; else if(event.dy < 0) playerTwoMovement = -paddleMovementSpeed; } else { playerTwoMovement = 0; } } ); }

Examples



This minesweeper demo shows how we can implement another classic game with simpledisplay and shows some mouse input and basic output code.

  1. import arsd.simpledisplay; enum GameSquare { mine = 0, clear, m1, m2, m3, m4, m5, m6, m7, m8 } enum UserSquare { unknown, revealed, flagged, questioned } enum GameState { inProgress, lose, win } GameSquare[] board; UserSquare[] userState; GameState gameState; int boardWidth; int boardHeight; bool isMine(int x, int y) { if(x < 0 || y < 0 || x >= boardWidth || y >= boardHeight) return false; return board[y * boardWidth + x] == GameSquare.mine; } GameState reveal(int x, int y) { if(board[y * boardWidth + x] == GameSquare.clear) { floodFill(userState, boardWidth, boardHeight, UserSquare.unknown, UserSquare.revealed, x, y, (x, y) { if(board[y * boardWidth + x] == GameSquare.clear) return true; else { userState[y * boardWidth + x] = UserSquare.revealed; return false; } }); } else { userState[y * boardWidth + x] = UserSquare.revealed; if(isMine(x, y)) return GameState.lose; } foreach(state; userState) { if(state == UserSquare.unknown || state == UserSquare.questioned) return GameState.inProgress; } return GameState.win; } void initializeBoard(int width, int height, int numberOfMines) { boardWidth = width; boardHeight = height; board.length = width * height; userState.length = width * height; userState[] = UserSquare.unknown; import std.algorithm, std.random, std.range; board[] = GameSquare.clear; foreach(minePosition; randomSample(iota(0, board.length), numberOfMines)) board[minePosition] = GameSquare.mine; int x; int y; foreach(idx, ref square; board) { if(square == GameSquare.clear) { int danger = 0; danger += isMine(x-1, y-1)?1:0; danger += isMine(x-1, y)?1:0; danger += isMine(x-1, y+1)?1:0; danger += isMine(x, y-1)?1:0; danger += isMine(x, y+1)?1:0; danger += isMine(x+1, y-1)?1:0; danger += isMine(x+1, y)?1:0; danger += isMine(x+1, y+1)?1:0; square = cast(GameSquare) (danger + 1); } x++; if(x == width) { x = 0; y++; } } } void redraw(SimpleWindow window) { import std.conv; auto painter = window.draw(); painter.clear(); final switch(gameState) with(GameState) { case inProgress: break; case win: painter.fillColor = Color.green; painter.drawRectangle(Point(0, 0), window.width, window.height); return; case lose: painter.fillColor = Color.red; painter.drawRectangle(Point(0, 0), window.width, window.height); return; } int x = 0; int y = 0; foreach(idx, square; board) { auto state = userState[idx]; final switch(state) with(UserSquare) { case unknown: painter.outlineColor = Color.black; painter.fillColor = Color(128,128,128); painter.drawRectangle( Point(x * 20, y * 20), 20, 20 ); break; case revealed: if(square == GameSquare.clear) { painter.outlineColor = Color.white; painter.fillColor = Color.white; painter.drawRectangle( Point(x * 20, y * 20), 20, 20 ); } else { painter.outlineColor = Color.black; painter.fillColor = Color.white; painter.drawText( Point(x * 20, y * 20), to!string(square)[1..2], Point(x * 20 + 20, y * 20 + 20), TextAlignment.Center | TextAlignment.VerticalCenter); } break; case flagged: painter.outlineColor = Color.black; painter.fillColor = Color.red; painter.drawRectangle( Point(x * 20, y * 20), 20, 20 ); break; case questioned: painter.outlineColor = Color.black; painter.fillColor = Color.yellow; painter.drawRectangle( Point(x * 20, y * 20), 20, 20 ); break; } x++; if(x == boardWidth) { x = 0; y++; } } } void main() { auto window = new SimpleWindow(200, 200); initializeBoard(10, 10, 10); redraw(window); window.eventLoop(0, delegate (MouseEvent me) { if(me.type != MouseEventType.buttonPressed) return; auto x = me.x / 20; auto y = me.y / 20; if(x >= 0 && x < boardWidth && y >= 0 && y < boardHeight) { if(me.button == MouseButton.left) { gameState = reveal(x, y); } else { userState[y*boardWidth+x] = UserSquare.flagged; } redraw(window); } } ); }

  • Declaration

    enum bool UsingSimpledisplayWindows;

    If you have to get down and dirty with implementation details, this helps figure out if Windows is available you can static if(UsingSimpledisplayWindows) ... more reliably than version() because version is module-local.

  • Declaration

    enum bool UsingSimpledisplayX11;

    If you have to get down and dirty with implementation details, this helps figure out if X is available you can static if(UsingSimpledisplayX11) ... more reliably than version() because version is module-local.

  • Declaration

    enum bool UsingSimpledisplayCocoa;

    If you have to get down and dirty with implementation details, this helps figure out if Cocoa is available you can static if(UsingSimpledisplayCocoa) ... more reliably than version() because version is module-local.

  • Declaration

    enum bool multipleWindowsSupported;

    Does this platform support multiple windows? If not, trying to create another will cause it to throw an exception.

  • Declaration

    enum WindowFlags: int;

    After selecting a type from [WindowTypes], you may further customize its behavior by setting one or more of these flags.

    Discussion

    The different window types have different meanings of normal. If the window type already is a good match for what you want to do, you should just use [WindowFlags.normal], the default, which will do the right thing for your users.

    The window flags will not always be honored by the operating system and window managers; they are hints, not commands.

    • Declaration

      normal

    • Declaration

      skipTaskbar

    • Declaration

      alwaysOnTop

    • Declaration

      alwaysOnBottom

    • Declaration

      cannotBeActivated

    • Declaration

      alwaysRequestMouseMotionEvents

      By default, simpledisplay will attempt to optimize mouse motion event reporting when it detects a remote connection, causing them to only be issued if input is grabbed (see: [SimpleWindow.grabInput]). This means doing hover effects and mouse game control on a remote X connection may not work right. Include this flag to override this optimization and always request the motion events. However btw, if you are doing mouse game control, you probably want to grab input anyway, and hover events are usually expendable! So think before you use this flag.

    • Declaration

      extraComposite

      On windows this will make this a layered windows (not supported for child windows before windows 8) to support transparency and improve animation performance.

    • Declaration

      dontAutoShow

      Don't automatically show window after creation; you will have to call show() manually.

  • Declaration

    enum WindowTypes: int;

    When creating a window, you can pass a type to SimpleWindow's constructor, then further customize the window by changing WindowFlags.

    Discussion

    You should mostly only need [normal], [undecorated], and [eventOnly] for normal use. The others are there to build a foundation for a higher level GUI toolkit, but are themselves not as high level as you might think from their names.

    This list is based on the EMWH spec for X11. http://standards.freedesktop.org/wm-spec/1.4/ar01s05.html#idm139704063786896

    • Declaration

      normal

      An ordinary application window.

    • Declaration

      undecorated

      A generic window without a title bar or border. You can draw on the entire area of the screen it takes up and use it as you wish. Remember that users don't really expect these though, so don't use it where a window of any other type is appropriate.

    • Declaration

      eventOnly

      A window that doesn't actually display on screen. You can use it for cases where you need a dummy window handle to communicate with or something.

    • Declaration

      dropdownMenu

      A drop down menu, such as from a menu bar

    • Declaration

      popupMenu

      A popup menu, such as from a right click

    • Declaration

      notification

      A popup bubble notification

    • Declaration

      nestedChild

      a child nested inside the parent. You must pass a parent window to the ctor

  • Declaration

    void setOpenGLContextVersion()(ubyte hi, ubyte lo);

    Set OpenGL context version to use. This has no effect on non-OpenGL windows. You may want to change context version if you want to use advanced shaders or other modern OpenGL techinques. This setting doesn't affect already created windows. You may use version 2.1 as your default, which should be supported by any box since 2006, so seems to be a reasonable choice.

    Discussion

    Note that by default version is set to 0, which forces SimpleDisplay to use old context creation code without any version specified. This is the safest way to init OpenGL, but it may not give you access to advanced features.

    See available OpenGL versions here: https://en.wikipedia.org/wiki/OpenGL

  • Declaration

    @property void openGLContextCompatible()(bool v);

    Set OpenGL context mode. Modern (3.0+) OpenGL versions deprecated old fixed pipeline functions, and without "compatible" mode you won't be able to use your old non-shader-based code with such contexts. By default SimpleDisplay creates compatible context, so you can gradually upgrade your OpenGL code if you want to (or leave it as is, as it should "just work").

  • Declaration

    @property void openGLContextAllowFallback()(bool v);

    Set to true to allow creating OpenGL context with lower version than requested instead of throwing. If fallback was activated (or legacy OpenGL was requested), openGLContextFallbackActivated() will return true.

  • Declaration

    @property bool openGLContextFallbackActivated()();

    After creating OpenGL window, you can check this to see if you got only "legacy" OpenGL context.

  • Declaration

    void sdpyWindowClass(const(char)[] v);

    Set window class name for all following new SimpleWindow() calls.

    Discussion

    WARNING! For Windows, you should set your class name before creating any window, and NEVER change it after that!

  • Declaration

    string sdpyWindowClass();

    Get current window class name.

  • Declaration

    class SimpleWindow: arsd.simpledisplay.CapableOfHandlingNativeEvent, arsd.simpledisplay.CapableOfBeingDrawnUpon;

    The flagship window class.

    Discussion

    SimpleWindow tries to make ordinary windows very easy to create and use without locking you out of more advanced or complex features of the underlying windowing system.

    For many applications, you can simply call new SimpleWindow(some_width, some_height, "some title") and get a suitable window to work with.

    From there, you can opt into additional features, like custom resizability and OpenGL support with the next two constructor arguments. Or, if you need even more, you can set a window type and customization flags with the final two constructor arguments.

    If none of that works for you, you can also create a window using native function calls, then wrap the window in a SimpleWindow instance by calling new SimpleWindow(native_handle). Remember, though, if you do this, managing the window is still your own responsibility! Notably, you will need to destroy it yourself.

    • Declaration

      TrueColorImage takeScreenshot();

      Be warned: this can be a very slow operation FIXME NOT IMPLEMENTED

    • Declaration

      this(int width = 640, int height = 480, string title = null, OpenGlOptions opengl = OpenGlOptions.no, Resizability resizable = Resizability.automaticallyScaleIfPossible, WindowTypes windowType = WindowTypes.normal, int customizationFlags = WindowFlags.normal, SimpleWindow parent = null);

      This creates a window with the given options. The window will be visible and able to receive input as soon as you start your event loop. You may draw on it immediately after creating the window, without needing to wait for the event loop to start if you want.

      Discussion

      The constructor tries to have sane default arguments, so for many cases, you only need to provide a few of them.

      Parameters

      int width

      the width of the window's client area, in pixels

      int height

      the height of the window's client area, in pixels

      string title

      the title of the window (seen in the title bar, taskbar, etc.). You can change it after construction with the [SimpleWindow.title\ property.

      OpenGlOptions opengl

      [OpenGlOptions] are yes and no. If yes, it creates an OpenGL context on the window.

      Resizability resizable

      [Resizability] has three options:

      allowResizing, which allows the window to be resized by the user. The windowResized delegate will be called when the size is changed.

      fixedSize will not allow the user to resize the window.

      automaticallyScaleIfPossible will allow the user to resize, but will still present the original size to the API user. The contents you draw will be scaled to the size the user chose. If this scaling is not efficient, the window will be fixed size. The windowResized event handler will never be called. This is the default.

      WindowTypes windowType

      The type of window you want to make.

      int customizationFlags

      A way to make a window without a border, always on top, skip taskbar, and more. Do not use this if one of the pre-defined [WindowTypes], given in the windowType argument, is a good match for what you need.

      SimpleWindow parent

      the parent window, if applicable

    • Declaration

      this(Size size, string title = null, OpenGlOptions opengl = OpenGlOptions.no, Resizability resizable = Resizability.automaticallyScaleIfPossible);

      Same as above, except using the Size struct instead of separate width and height.

    • Declaration

      this(Image image, string title = null);

      Creates a window based on the given [Image]. It's client area width and height is equal to the image. (A window's client area is the drawable space inside; it excludes the title bar, etc.)

      Discussion

      Windows based on images will not be resizable and do not use OpenGL.

    • Declaration

      this(NativeWindowHandle nativeWindow);

      Wraps a native window handle with very little additional processing - notably no destruction this is incomplete so don't use it for much right now. The purpose of this is to make native windows created through the low level API (so you can use platform-specific options and other details SimpleWindow does not expose) available to the event loop wrappers.

    • Declaration

      void grabInput(bool keyboard = true, bool mouse = true, bool confine = false);

      Experimental, do not use yet Grabs exclusive input from the user until you release it with [releaseInputGrab].

      Note: it is extremely rude to do this without good reason. Reasons may include doing some kind of mouse drag operation or popping up a temporary menu that should get events and will be dismissed at ease by the user clicking away.

      Parameters

      bool keyboard

      do you want to grab keyboard input?

      bool mouse

      grab mouse input?

      bool confine

      confine the mouse cursor to inside this window?

    • Declaration

      void releaseInputGrab();

      Releases the grab acquired by [grabInput].

    • Declaration

      void focus();

      Sets the input focus to this window.

      Discussion

      You shouldn't call this very often - please let the user control the input focus.

    • Declaration

      void requestAttention();

      Requests attention from the user for this window.

      Discussion

      The typical result of this function is to change the color of the taskbar icon, though it may be tweaked on specific platforms.

      It is meant to unobtrusively tell the user that something relevant to them happened in the background and they should check the window when they get a chance. Upon receiving the keyboard focus, the window will automatically return to its natural state.

      If the window already has the keyboard focus, this function may do nothing, because the user is presumed to already be giving the window attention.

      Implementation note: requestAttention uses the NET_WM_STATE_DEMANDS_ATTENTION atom on X11 and the FlashWindow function on Windows.

    • Declaration

      void delegate() closeQuery;

      This will be called when WM wants to close your window (i.e. user clicked "close" icon, for example). You'll have to call close() manually if you set this delegate.

    • Declaration

      void delegate(bool becomesVisible) visibilityChanged;

      This will be called when window visibility was changed.

    • Declaration

      final @property bool closed();

      Returns true if the window has been closed.

    • Declaration

      final @property bool focused();

      Returns true if the window is focused.

    • Declaration

      final @property bool visible();

      Returns true if the window is visible (mapped).

    • Declaration

      void close();

      Closes the window. If there are no more open windows, the event loop will terminate.

    • Declaration

      void show();

      Alias for hidden = false

    • Declaration

      void hide();

      Alias for hidden = true

    • Declaration

      void hideCursor();

      Hide cursor when it enters the window.

    • Declaration

      void showCursor();

      Don't hide cursor when it enters the window.

    • Declaration

      bool warpMouse(int x, int y);

      "Warp" mouse pointer to coordinates relative to window top-left corner. Return "success" flag.

      Discussion

      Currently only supported on X11, so Windows implementation will return false.

      Note: "warping" pointer will not send any synthesised mouse events, so you probably doesn't want to use it to move mouse pointer to some active GUI area, for example, as your window won't receive "mouse moved here" event.

    • Declaration

      void sendDummyEvent();

      Send dummy window event to ping event loop. Required to process NotificationIcon on X11, for example.

    • Declaration

      void setMinSize(int minwidth, int minheight);

      Set window minimal size.

    • Declaration

      void setMaxSize(int maxwidth, int maxheight);

      Set window maximal size.

    • Declaration

      void setResizeGranularity(int granx, int grany);

      Set window resize step (window size will be changed with the given granularity on supported platforms). Currently only supported on X11.

    • Declaration

      void move(int x, int y);
      void move(Point p);

      Move window.

    • Declaration

      void resize(int w, int h);

      Resize window.

      Discussion

      Note that the width and height of the window are NOT instantly updated - it waits for the window manager to approve the resize request, which means you must return to the event loop before the width and height are actually changed.

    • Declaration

      void moveResize(int x, int y, int w, int h);

      Move and resize window (this can be faster and more visually pleasant than doing it separately).

    • Declaration

      final @property bool hidden();

      Returns true if the window is hidden.

    • Declaration

      final @property void hidden(bool b);

      Shows or hides the window based on the bool argument.

    • Declaration

      @property void opacity(double opacity);

      Sets the window opacity. On X11 this requires a compositor to be running. On windows the WindowFlags.extraComposite must be set at window creation.

    • Declaration

      void setEventHandlers(T...)(T eventHandlers);

      Sets your event handlers, without entering the event loop. Useful if you have multiple windows - set the handlers on each window, then only do eventLoop on your main window.

    • Declaration

      final int eventLoop(T...)(long pulseTimeout, T eventHandlers);

      The event loop automatically returns when the window is closed pulseTimeout is given in milliseconds. If pulseTimeout == 0, no pulse timer is created. The event loop will block until an event arrives or the pulse timer goes off.

    • Declaration

      ScreenPainter draw();

      This lets you draw on the window (or its backing buffer) using basic 2D primitives.

      Discussion

      Be sure to call this in a limited scope because your changes will not actually appear on the window until ScreenPainter's destructor runs.

      Return Value

      an instance of [ScreenPainter], which has the drawing methods on it to draw on this window.

    • Declaration

      final @property int width();

      Width of the window's drawable client area, in pixels.

    • Declaration

      final @property int height();

      Height of the window's drawable client area, in pixels.

    • Declaration

      const pure nothrow @nogc @property @safe bool isOpenGL();

      true if OpenGL was initialized for this window.

    • Declaration

      const pure nothrow @nogc @property @safe Resizability resizingMode();

      Original resizability.

    • Declaration

      const pure nothrow @nogc @property @safe WindowTypes type();

      Original window type.

    • Declaration

      const pure nothrow @nogc @property @safe int customFlags();

      Original customization flags.

    • Declaration

      void mtLock();

      "Lock" this window handle, to do multithreaded synchronization. You probably won't need to call this, as it's not recommended to share window between threads.

    • Declaration

      void mtUnlock();

      "Unlock" this window handle, to do multithreaded synchronization. You probably won't need to call this, as it's not recommended to share window between threads.

    • Declaration

      void beep();

      Emit a beep to get user's attention.

    • Declaration

      void delegate() redrawOpenGlScene;

      Put your code in here that you want to be drawn automatically when your window is uncovered. Set a handler here *before* entering your event loop any time you pass OpenGlOptions.yes to the constructor. Ideally, you will set this delegate immediately after constructing the SimpleWindow.

    • Declaration

      final @property void vsync(bool wait);

      This will allow you to change OpenGL vsync state.

    • Declaration

      bool useGLFinish;

      Set this to false if you don't need to do glFinish() after swapOpenGlBuffers(). Note that at least NVidia proprietary driver may segfault if you will modify texture fast enough without waiting 'em to finish their frame bussiness.

    • Declaration

      void redrawOpenGlSceneNow();

      call this to invoke your delegate. It automatically sets up the context and flips the buffer. If you need to redraw the scene in response to an event, call this.

    • Declaration

      void setAsCurrentOpenGlContext();

      Makes all gl* functions target this window until changed. This is only valid if you passed OpenGlOptions.yes to the constructor.

    • Declaration

      nothrow bool setAsCurrentOpenGlContextNT();

      Makes all gl* functions target this window until changed. This is only valid if you passed OpenGlOptions.yes to the constructor. This doesn't throw, returning success flag instead.

    • Declaration

      nothrow bool releaseCurrentOpenGlContext();

      Releases OpenGL context, so it can be reused in, for example, different thread. This is only valid if you passed OpenGlOptions.yes to the constructor. This doesn't throw, returning success flag instead.

    • Declaration

      void swapOpenGlBuffers();

      simpledisplay always uses double buffering, usually automatically. This manually swaps the OpenGL buffers.

      Discussion

      You should not need to call this yourself because simpledisplay will do it for you after calling your redrawOpenGlScene.

      Remember that this may throw an exception, which you can catch in a multithreaded application to keep your thread from dying from an unhandled exception.

    • Declaration

      @property void title(string title);

      Set the window title, which is visible on the window manager title bar, operating system taskbar, etc.

      Discussion

      1. auto window = new SimpleWindow(100, 100, "First title"); window.title = "A new title";


      You may call this function at any time.

    • Declaration

      @property string title();

      Gets the title

    • Declaration

      string getRealTitle();

      Get the title as set by the window manager. May not match what you attempted to set.

    • Declaration

      @property void icon(MemoryImage icon);

      Set the icon that is seen in the title bar or taskbar, etc., for the user.

    • Declaration

      @property void image(Image i);

      Draws an image on the window. This is meant to provide quick look of a static image generated elsewhere.

    • Declaration

      @property void cursor(MouseCursor cursor);

      Changes the cursor for the window. If the cursor is hidden via [hideCursor], this has no effect.

      Discussion

      1. window.cursor = GenericCursor.Help; // now the window mouse cursor is set to a generic help

    • Declaration

      void delegate(KeyEvent ke) handleKeyEvent;

      What follows are the event handlers. These are set automatically by the eventLoop function, but are still public so you can change them later. wasPressed == true means key down. false == key up.

      Discussion

      Handles a low-level keyboard event. Settable through setEventHandlers.

    • Declaration

      void delegate(dchar c) handleCharEvent;

      Handles a higher level keyboard event - c is the character just pressed. Settable through setEventHandlers.

    • Declaration

      void delegate() handlePulse;

      Handles a timer pulse. Settable through setEventHandlers.

    • Declaration

      void delegate(bool) onFocusChange;

      Called when the focus changes, param is if we have it (true) or are losing it (false).

    • Declaration

      void delegate() onClosing;

      Called inside close() method. Our window is still alive, and we can free various resources. Sometimes it is easier to setup the delegate instead of subclassing.

    • Declaration

      void delegate() onDestroyed;

      Called when we received destroy notification. At this stage we cannot do much with our window (as it is already dead, and it's native handle cannot be used), but we still can do some last minute cleanup.

    • Declaration

      bool delegate(int x, int y, int width, int height, int eventsLeft) handleExpose;

      Called when Expose event comes. See Xlib manual to understand the arguments. Return false if you want Simpledisplay to copy backbuffer, or true if you did it yourself. You will probably never need to setup this handler, it is for very low-level stuff.

      Discussion

      WARNING! Xlib is multithread-locked when this handles is called!

    • Declaration

      void delegate(MouseEvent) handleMouseEvent;

      Mouse event handler. Settable through setEventHandlers.

    • Declaration

      void delegate() paintingFinished;

      use to redraw child widgets if you use system apis to add stuff

    • Declaration

      void delegate(int width, int height) windowResized;

      handle a resize, after it happens. You must construct the window with Resizability.allowResizing for this to ever happen.

    • Declaration

      NativeEventHandler handleNativeEvent;

      Platform specific - handle any native messages this window gets.

      Note: this is called *in addition to* other event handlers, unless you return zero indicating that you handled it.

      On Windows, it takes the form of int delegate(HWND,UINT, WPARAM, LPARAM).

      On X11, it takes the form of int delegate(XEvent).

      IMPORTANT: it used to be static in old versions of simpledisplay.d, but I always used it as if it wasn't static... so now I just fixed it so it isn't anymore.

    • Declaration

      NativeEventHandler handleNativeGlobalEvent;

      This is the same as handleNativeEvent, but static so it can hook ALL events in the loop. If you used to use handleNativeEvent depending on it being static, just change it to use this instead and it will work the same way.

    • Declaration

      @property bool eventQueueEmpty()();

      Is our custom event queue empty? Can be used in simple cases to prevent "spamming" window with events it can't cope with. It is safe to call this from non-UI threads.

      Discussion

      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

    • Declaration

      @property bool eventQueued(ET : Object)();

      Does our custom event queue contains at least one with the given type? Can be used in simple cases to prevent "spamming" window with events it can't cope with. It is safe to call this from non-UI threads.

      Discussion

      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

    • Declaration

      uint addEventListener(ET : Object)(void delegate(ET) dg);

      Add listener for custom event. Can be used like this:

      Discussion

      1. auto eid = win.addEventListener((MyStruct evt) { ... }); ... win.removeEventListener(eid);

      Return Value

      0 on failure (should never happen, so ignore it)





      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

    • Declaration

      void removeEventListener()(uint id);

      Remove event listener. It is safe to pass invalid event id here.

      Discussion

      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

    • Declaration

      bool postTimeout(ET : Object)(ET evt, uint timeoutmsecs, bool replace = false);

      Post event to queue. It is safe to call this from non-UI threads. If timeoutmsecs is greater than zero, the event will be delayed for at least timeoutmsecs milliseconds. if replace is true, replace all existing events typed ET with the new one (if evt is empty, remove 'em all) Returns true if event was queued. Always returns false if evt is null.

      Discussion

      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

    • Declaration

      bool postEvent(ET : Object)(ET evt, bool replace = false);

      Post event to queue. It is safe to call this from non-UI threads. if replace is true, replace all existing events typed ET with the new one (if evt is empty, remove 'em all) Returns true if event was queued. Always returns false if evt is null.

      Discussion

      This is in-process one-way (from anything to window) event sending mechanics. It is thread-safe, so it can be used in multi-threaded applications to send, for example, "wake up and repaint" events when thread completed some operation. This will allow to avoid using timer pulse to check events with synchronization, 'cause event handler will be called in UI thread. You can stop guessing which pulse frequency will be enough for your app. Note that events handlers may be called in arbitrary order, i.e. last registered handler can be called first, and vice versa.

  • Declaration

    class MouseCursor;

    Represents a mouse cursor (aka the mouse pointer, the image seen on screen that indicates where the mouse is pointing). See [GenericCursor]

  • Declaration

    enum GenericCursorType: int;

    Note that there is no exact appearance guaranteed for any of these items; it may change appearance on different operating systems or future simpledisplay versions

    • Declaration

      Default

      The default arrow pointer.

    • Declaration

      Wait

      A cursor indicating something is loading and the user must wait.

    • Declaration

      Hand

      A pointing finger, like the one used hovering over hyperlinks in a web browser.

    • Declaration

      Help

      A cursor indicating the user can get help about the pointer location.

    • Declaration

      Cross

      A crosshair.

    • Declaration

      Text

      An i-beam shape, typically used to indicate text selection is possible.

    • Declaration

      Move

      Pointer indicating movement is possible. May also be used as SizeAll

    • Declaration

      UpArrow

      An arrow pointing straight up.

    • Declaration

      Progress

      The hourglass and arrow, indicating the computer is working but the user can still work. Not great results on X11.

    • Declaration

      NotAllowed

      Indicates the current operation is not allowed. Not great results on X11.

    • Declaration

      SizeNesw

      Arrow pointing northeast and southwest (lower-left corner resize indicator)

    • Declaration

      SizeNs

      Arrow pointing north and south (upper/lower edge resize indicator)

    • Declaration

      SizeNwse

      Arrow pointing northwest and southeast (upper-left corner resize indicator)

    • Declaration

      SizeWe

      Arrow pointing west and east (left/right edge resize indicator)

  • Declaration

    struct GenericCursor;

    You get one by GenericCursor.SomeTime. See [GenericCursorType] for a list of types.

    • Declaration

      MouseCursor opDispatch(string str)() if (__traits(hasMember, GenericCursorType, str));

  • Declaration

    struct EventLoop;

    If you want to get more control over the event loop, you can use this.

    Discussion

    Typically though, you can just call [SimpleWindow.eventLoop].

  • Declaration

    class NotificationAreaIcon: arsd.simpledisplay.CapableOfHandlingNativeEvent;

    Provides an icon on the system notification area (also known as the system tray).

    Discussion

    If a notification area is not available with the NotificationIcon object is created, it will silently succeed and simply attempt to create one when an area becomes available.



    NotificationAreaIcon on Windows assumes you are on Windows Vista or later. If this is wrong, pass -version=WindowsXP to dmd when compiling and it will use the older version.

    • Declaration

      void delegate(int x, int y, MouseButton button, ModifierState mods) onClickEx;

      x and y are globals (relative to root window). X11 only.

    • Declaration

      void delegate(int x, int y, ModifierState mods) onEnter;

      x and y are global window coordinates. X11 only.

    • Declaration

      void delegate() onLeave;

      X11 only.

    • Declaration

      const pure nothrow @nogc @property @safe bool closed();

    • Declaration

      void getWindowRect(out int x, out int y, out int width, out int height);

      X11 only. Get global window coordinates and size. This can be used to show various notifications.

    • Declaration

      this(string name, MemoryImage icon, void delegate(MouseButton button) onClick);
      this(string name, Image icon, void delegate(MouseButton button) onClick);

      Note that on Windows, only left, right, and middle buttons are sent. Mouse wheel buttons are NOT set, so don't rely on those events if your program is meant to be used on Windows too.

    • Declaration

      this(string name, MemoryImage icon, void delegate(int x, int y, MouseButton button, ModifierState mods) onClickEx);
      this(string name, Image icon, void delegate(int x, int y, MouseButton button, ModifierState mods) onClickEx);

      X-specific extension (for now at least)

    • Declaration

      final @property void delegate(MouseButton) onClick();
      final @property void onClick(void delegate(MouseButton) handler);

    • Declaration

      @property void icon(MemoryImage i);
      @property void icon(Image i);

    • Declaration

      void showBalloon(string title, string message, MemoryImage icon = null, void delegate() onclick = null, int timeout = 2500);

      Shows a balloon notification. You can only show one balloon at a time, if you call it twice while one is already up, the first balloon will be replaced.

      Discussion

      The user is free to block notifications and they will automatically disappear after a timeout period.

      Parameters

      string title

      Title of the notification. Must be 40 chars or less or the OS may truncate it.

      string message

      The message to pop up. Must be 220 chars or less or the OS may truncate it.

      MemoryImage icon

      the icon to display with the notification. If null, it uses your existing icon.

      void delegate() onclick

      delegate called if the user clicks the balloon. (not yet implemented)

      int timeout

      your suggested timeout period. The operating system is free to ignore your suggestion.

    • Declaration

      void show();

    • Declaration

      void hide();

    • Declaration

      void close();

  • Declaration

    Pixmap transparencyMaskFromMemoryImage(MemoryImage i, Window window);

    call XFreePixmap on the return value

  • Declaration

    class Timer;

    A timer that will trigger your function on a given interval.

    Discussion

    You create a timer with an interval and a callback. It will continue to fire on the interval until it is destroyed.

    There are currently no one-off timers (instead, just create one and destroy it when it is triggered) nor are there pause/resume functions - the timer must again be destroyed and recreated if you want to pause it.

    auto timer = new Timer(50, { it happened!; }); timer.destroy();

    Timers can only be expected to fire when the event loop is running.

    • Declaration

      this(int intervalInMilliseconds, void delegate() onPulse);

      Create a timer with a callback when it triggers.

    • Declaration

      void destroy();

      Stop and destroy the timer object.

  • Declaration

    class PosixFdReader;

    Lets you add files to the event loop for reading. Use at your own risk.

    • Declaration

      this(void delegate() onReady, int fd, bool captureReads = true, bool captureWrites = false);

    • Declaration

      this(void delegate(int) onReady, int fd, bool captureReads = true, bool captureWrites = false);

    • Declaration

      this(void delegate(int fd, bool read, bool write) onReady, int fd, bool captureReads = true, bool captureWrites = false);

    • Declaration

      void enable();

    • Declaration

      void disable();

    • Declaration

      void dispose();

  • Declaration

    void getClipboardText(SimpleWindow clipboardOwner, void delegate(in char[]) receiver);

    this does a delegate because it is actually an async call on X... the receiver may never be called if the clipboard is empty or unavailable gets plain text from the clipboard

  • Declaration

    void setClipboardText(SimpleWindow clipboardOwner, string text);

    copies some text to the clipboard

  • Declaration

    @property Atom GetAtom(string name, bool create = false)(Display* display);

    Platform specific for X11

  • Declaration

    string getAtomName(Atom atom, Display* display);

    Platform specific for X11 - gets atom names as a string

  • Declaration

    void setPrimarySelection(SimpleWindow window, string text);

    Asserts ownership of PRIMARY and copies the text into a buffer that clients can request later

  • Declaration

    void setSecondarySelection(SimpleWindow window, string text);

    Asserts ownership of SECONDARY and copies the text into a buffer that clients can request later

  • Declaration

    void setX11Selection(string atomName)(SimpleWindow window, string text);

  • Declaration

    void getPrimarySelection(SimpleWindow window, void delegate(in char[]) handler);

  • Declaration

    void getX11Selection(string atomName)(SimpleWindow window, void delegate(in char[]) handler);

  • Declaration

    void[] getX11PropertyData(Window window, Atom property, Atom type = AnyPropertyType);

  • Declaration

    class GlobalHotkey;

    Global hotkey handler. Simpledisplay will usually create one for you, but if you want to use subclassing instead of delegates, you can subclass this, and override doHandle() method.

    • Declaration

      void doHandle();

      this will be called by hotkey manager

    • Declaration

      this(KeyEvent akey, void delegate() ahandler = null);

      Create from initialzed KeyEvent object

    • Declaration

      this(const(char)[] akey, void delegate() ahandler = null);

      Create from emacs-like key name ("C-M-Y", etc.)

  • Declaration

    class GlobalHotkeyManager: arsd.simpledisplay.CapableOfHandlingNativeEvent;

    Global hotkey manager. It contains static methods to manage global hotkeys.

    Discussion

    1. try { GlobalHotkeyManager.register("M-H-A", delegate () { hideShowWindows(); }); } catch (Exception e) { conwriteln("ERROR registering hotkey!"); }


    The key strings are based on Emacs. In practical terms, M means alt and H means the Windows logo key. C is ctrl.

    • Declaration

      static void register(GlobalHotkey gh);
      static void register(const(char)[] akey, void delegate() ahandler);

      Register new global hotkey with initialized GlobalHotkey object. This function will throw if it failed to register hotkey (i.e. hotkey is invalid or already taken).

    • Declaration

      static void unregister(GlobalHotkey gh);

      Register new global hotkey with previously used GlobalHotkey object. It is safe to unregister unknown or invalid hotkey.

    • Declaration

      static void unregister(const(char)[] key);

      Ditto.

  • Declaration

    enum RasterOp: int;

    [ScreenPainter] operations can use different operations to combine the color with the color on screen.

    See Also

    • Declaration

      normal

      Replaces the pixel.

    • xor

      Declaration

      xor

      Uses bitwise xor to draw.

  • Declaration

    enum OpenGlOptions: int;

    Determines if you want an OpenGL context created on the new window.

    Discussion

    See more: [#topics-3d|in the 3d topic].

    1. import arsd.simpledisplay; void main() { auto window = new SimpleWindow(500, 500, "OpenGL Test", OpenGlOptions.yes); // Set up the matrix window.setAsCurrentOpenGlContext(); // make this window active // This is called on each frame, we will draw our scene window.redrawOpenGlScene = delegate() { }; window.eventLoop(0); }

    • no

      Declaration

      no

      No OpenGL context is created

    • yes

      Declaration

      yes

      Yes, create an OpenGL context

  • Declaration

    enum Resizability: int;

    When you create a SimpleWindow, you can see its resizability to be one of these via the constructor...

    • Declaration

      fixedSize

      the window cannot be resized

    • Declaration

      allowResizing

      the window can be resized. The buffer (if there is one) will automatically adjust size, but not stretch the contents. the windowResized delegate will be called so you can respond to the new size yourself.

    • Declaration

      automaticallyScaleIfPossible

      if possible, your drawing buffer will remain the same size and simply be automatically scaled to the new window size. If this is impossible, it will not allow the user to resize the window at all. Note: window.width and window.height WILL be adjusted, which might throw you off if you draw based on them, so keep track of your expected width and height separately. That way, when it is scaled, things won't be thrown off.

  • Declaration

    enum TextAlignment: uint;

    Alignment for . Left, Center, or Right may be combined with VerticalTop, VerticalCenter, or VerticalBottom via bitwise or.

  • Declaration

    struct KeyEvent;

    Keyboard press and release events

    • key

      Declaration

      Key key;

      see table below. Always use the symbolic names, even for ASCII characters, since the actual numbers vary across platforms. See [Key]

    • Declaration

      ubyte hardwareCode;

      A platform and hardware specific code for the key

    • Declaration

      bool pressed;

      true if the key was just pressed, false if it was just released. note: released events aren't always sent...

    • Declaration

      dchar character;

    • Declaration

      uint modifierState;

      see enum [ModifierState]. They are bitwise combined together.

    • Declaration

      SimpleWindow window;

      associated Window

    • Declaration

      static nothrow @nogc @trusted KeyEvent parse(const(char)[] name, bool* ignoreModsOut = null, int* updown = null);

      Parse string into key name with modifiers. It accepts things like:

      Discussion

      C-H-1 -- emacs style (ctrl, and windows, and 1)

      Ctrl+Win+1 -- windows style

      Ctrl-Win-1 -- '-' is a valid delimiter too

      Ctrl Win 1 -- and space

      and even "Win + 1 + Ctrl".

  • Declaration

    @property string ApplicationName(string name);
    @property string ApplicationName();

    sets the application name.

  • Declaration

    enum MouseEventType: int;

    Type of a [MouseEvent]

    • Declaration

      motion

      The mouse moved inside the window

    • Declaration

      buttonPressed

      A mouse button was pressed or the wheel was spun

    • Declaration

      buttonReleased

      A mouse button was released

  • Declaration

    struct MouseEvent;

    Listen for this on your event listeners if you are interested in mouse action.

    Discussion

    Note that [button] is used on mouse press and release events. If you are curious about which button is being held in during motion, use [modifierState] and check the bitmask for [ModifierState.leftButtonDown], etc.

    Examples

    This will draw boxes on the window with the mouse as you hold the left button.

    1. import arsd.simpledisplay; void main() { auto window = new SimpleWindow(); window.eventLoop(0, (MouseEvent ev) { if(ev.modifierState & ModifierState.leftButtonDown) { auto painter = window.draw(); painter.fillColor = Color.red; painter.outlineColor = Color.black; painter.drawRectangle(Point(ev.x / 16 * 16, ev.y / 16 * 16), 16, 16); } } ); }

    • Declaration

      MouseEventType type;

      movement, press, release, double click. See [MouseEventType]

    • x

      Declaration

      int x;

      Current X position of the cursor when the event fired, relative to the upper-left corner of the window, reported in pixels. (0, 0) is the upper left, (window.width - 1, window.height - 1) is the lower right corner of the window.

    • y

      Declaration

      int y;

      Current Y position of the cursor when the event fired.

    • dx

      Declaration

      int dx;

      Change in X position since last report

    • dy

      Declaration

      int dy;

      Change in Y position since last report

    • Declaration

      MouseButton button;

      See [MouseButton]

    • Declaration

      int modifierState;

      See [ModifierState]

    • Declaration

      const @property ubyte buttonLinear();

      Returns a linear representation of mouse button, for use with static arrays. Guaranteed to be >= 0 && <= 15

      Discussion

      Its implementation is based on range-limiting core.bitop.bsf(button) + 1.

    • Declaration

      bool doubleClick;

      was it a double click? Only set on type == [MouseEventType.buttonPressed]

    • Declaration

      SimpleWindow window;

      The window in which the event happened.

    • Declaration

      pure nothrow @nogc @trusted bool equStr()(auto ref MouseEvent event, const(char)[] str);

      can contain emacs-like modifier prefix case-insensitive names: lmbX/leftX rmbX/rightX mmbX/middleX wheelX motion (no prefix allowed) 'X' is either "up" or "down" (or "-up"/"-down"); if omited, means "down"

  • Pen

    Declaration

    struct Pen;

    This gives a few more options to drawing lines and such

    • Declaration

      Color color;

      the foreground color

    • Declaration

      int width;

      width of the line

    • Declaration

      Style style;

      See [Style]

    • Declaration

      enum Style: int;

      Style of lines drawn

      • Declaration

        Solid

        a solid line

      • Declaration

        Dashed

        a dashed line

      • Declaration

        Dotted

        a dotted line

  • Declaration

    class Image;

    Represents an in-memory image in the format that the GUI expects, but with its raw data available to your program.

    Discussion

    On Windows, this means a device-independent bitmap. On X11, it is an XImage.



    Drawing an image to screen is not necessarily fast, but applying algorithms to draw to the image itself should be fast. An Image is also the first step in loading and displaying images loaded from files.

    If you intend to draw an image to screen several times, you will want to convert it into a [Sprite].



    Drawing pixels on the image may be simple, using the opIndexAssign function, but you can also often get a fair amount of speedup by getting the raw data format and writing some custom code.

    FIXME INSERT EXAMPLES HERE

    • Declaration

      this(int width, int height, bool forcexshm = false);

    • Declaration

      this(Size size, bool forcexshm = false);

    • Declaration

      const pure nothrow @system int offsetForTopLeftPixel();

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      const pure nothrow @system int offsetForPixel(int x, int y);

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      const pure nothrow @system int adjustmentForNextLine();

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      const pure nothrow @system int redByteOffset();

      once you have the position of a pixel, use these to get to the proper color

      Discussion

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      const pure nothrow @system int greenByteOffset();

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      const pure nothrow @system int blueByteOffset();

      if you do the math yourself you might be able to optimize it. Call these functions only once and cache the value.

    • Declaration

      final void putPixel(int x, int y, Color c);

    • Declaration

      final Color getPixel(int x, int y);

    • Declaration

      final void opIndexAssign(Color c, int x, int y);

    • Declaration

      TrueColorImage toTrueColorImage();

    • Declaration

      static Image fromMemoryImage(MemoryImage i);

    • Declaration

      ubyte[] getRgbaBytes(ubyte[] where = null);

      this is here for interop with arsd.image. where can be a TrueColorImage's data member if you pass in a buffer, it will put it right there. length must be width*height*4 already if you pass null, it will allocate a new one.

    • Declaration

      void setRgbaBytes(in ubyte[] from);

      this is here for interop with arsd.image. from can be a TrueColorImage's data member

    • Declaration

      ubyte* getDataPointer();

      warning: this is not portable across platforms because the data format can change

    • Declaration

      final const pure nothrow @safe int bytesPerLine();

      for use with getDataPointer

    • Declaration

      final const pure nothrow @safe int bytesPerPixel();

      for use with getDataPointer

    • Declaration

      immutable int width;

    • Declaration

      immutable int height;

  • Declaration

    void displayImage(Image image, SimpleWindow win = null);

    A convenience function to pop up a window displaying the image. If you pass a win, it will draw the image in it. Otherwise, it will create a window with the size of the image and run its event loop, closing when a key is pressed.

  • Declaration

    class OperatingSystemFont;

    Represents a font loaded off the operating system or the X server.

    Discussion

    While the api here is unified cross platform, the fonts are not necessarily available, even across machines of the same platform, so be sure to always check for null (using [isNull]) and have a fallback plan.

    When you have a font you like, use [ScreenPainter.setFont] to load it for drawing.

    Worst case, a null font will automatically fall back to the default font loaded for your system.

    • Declaration

      this(string name, int size = 0, FontWeight weight = FontWeight.dontcare, bool italic = false);

    • Declaration

      bool load(string name, int size = 0, FontWeight weight = FontWeight.dontcare, bool italic = false);

    • Declaration

      void unload();

    • Declaration

      void loadDefault();

      FIXME not implemented

    • Declaration

      bool isNull();

  • Declaration

    struct ScreenPainter;

    The 2D drawing proxy. You acquire one of these with [SimpleWindow.draw] rather than constructing it directly. Then, it is reference counted so you can pass it at around and when the last ref goes out of scope, the buffered drawing activities are all carried out.

    Discussion

    Most functions use the outlineColor instead of taking a color themselves. ScreenPainter is reference counted and draws its buffer to the screen when its final reference goes out of scope.

    • Declaration

      void setClipRectangle(Point pt, int width, int height);
      void setClipRectangle(arsd.color.Rectangle rect);

      Sets the clipping region for drawing. If width == 0 && height == 0, disabled clipping.

    • Declaration

      void setFont(OperatingSystemFont font);

    • Declaration

      int fontHeight();

    • pen

      Declaration

      @property void pen(Pen p);

    • Declaration

      @property void outlineColor(Color c);

    • Declaration

      @property void fillColor(Color c);

    • Declaration

      @property void rasterOp(RasterOp op);

    • Declaration

      void scrollArea(Point upperLeft, int width, int height, int dx, int dy);

      Scrolls the contents in the bounding rectangle by dx, dy. Positive dx means scroll left (make space available at the right), positive dy means scroll up (make space available at the bottom)

    • Declaration

      void clear();

    • Declaration

      void drawPixmap(Sprite s, Point upperLeft);

    • Declaration

      void drawImage(Point upperLeft, Image i, Point upperLeftOfImage = Point(0, 0), int w = 0, int h = 0);

    • Declaration

      Size textSize(in char[] text);

    • Declaration

      void drawText(Point upperLeft, in char[] text, Point lowerRight = Point(0, 0), uint alignment = 0);

    • Declaration

      void drawText(DrawableFont font, Point upperLeft, in char[] text);

      Draws text using a custom font.

      Discussion

      This is still MAJOR work in progress.

      Creating a [DrawableFont] can be tricky and require additional dependencies.

    • Declaration

      void drawPixel(Point where);

      Drawing an individual pixel is slow. Avoid it if possible.

    • Declaration

      void drawLine(Point starting, Point ending);

      Draws a pen using the current pen / outlineColor

    • Declaration

      void drawRectangle(Point upperLeft, int width, int height);
      void drawRectangle(Point upperLeft, Size size);
      void drawRectangle(Point upperLeft, Point lowerRightInclusive);

      Draws a rectangle using the current pen/outline color for the border and brush/fill color for the insides The outer lines, inclusive of x = 0, y = 0, x = width - 1, and y = height - 1 are drawn with the outlineColor The rest of the pixels are drawn with the fillColor. If fillColor is transparent, those pixels are not drawn.

    • Declaration

      void drawEllipse(Point upperLeft, Point lowerRight);

      Arguments are the points of the bounding rectangle

    • Declaration

      void drawArc(Point upperLeft, int width, int height, int start, int finish);

      start and finish are units of degrees * 64

    • Declaration

      void drawPolygon(Point[] vertexes);
      void drawPolygon(Point[] vertexes...);

      .

  • Declaration

    class Sprite: arsd.simpledisplay.CapableOfBeingDrawnUpon;

    Sprites are optimized for fast drawing on the screen, but slow for direct pixel access. They are best for drawing a relatively unchanging image repeatedly on the screen.

    Discussion

    On X11, this corresponds to an XPixmap. On Windows, it still uses a bitmap, though I'm not sure that's ideal and the implementation might change.

    You create one by giving a window and an image. It optimizes for that window, and copies the image into it to use as the initial picture. Creating a sprite can be quite slow (especially over a network connection) so you should do it as little as possible and just hold on to your sprite handles after making them. simpledisplay does try to do its best though, using the XSHM extension if available, but you should still write your code as if it will always be slow.

    Then you can use sprite.drawAt(painter, point); to draw it, which should be a fast operation - much faster than drawing the Image itself every time.

    Sprite represents a scarce resource which should be freed when you are done with it. Use the dispose method to do this. Do not use a Sprite after it has been disposed. If you are unsure about this, don't take chances, just let the garbage collector do it for you. But ideally, you can manage its lifetime more efficiently.

    FIXME: you are supposed to be able to draw on these similarly to on windows. ScreenPainter needs to be refactored to allow that though. So until that is done, consider a Sprite to have const contents.

    • Declaration

      ScreenPainter draw();

    • Declaration

      TrueColorImage takeScreenshot();

      Be warned: this can be a very slow operation FIXME NOT IMPLEMENTED

    • Declaration

      this(SimpleWindow win, Image i);

      Makes a sprite based on the image with the initial contents from the Image

    • Declaration

      void drawAt(ScreenPainter painter, Point where);

      Draws the image on the specified painter at the specified point. The point is the upper-left point where the image will be drawn.

    • Declaration

      void dispose();

      Call this when you're ready to get rid of it

    • Declaration

      final @property int width();

    • Declaration

      final @property int height();

  • Declaration

    interface CapableOfBeingDrawnUpon;

    • Declaration

      abstract ScreenPainter draw();

    • Declaration

      abstract int width();

    • Declaration

      abstract int height();

    • Declaration

      abstract TrueColorImage takeScreenshot();

      Be warned: this can be a very slow operation

  • Declaration

    void flushGui();

    Flushes any pending gui buffers. Necessary if you are using with_eventloop with X - flush after you create your windows but before you call loop()

  • Declaration

    interface CapableOfHandlingNativeEvent;

    Used internal to dispatch events to various classes.

  • Declaration

    enum ModifierState: uint;

    State of keys on mouse events, especially motion.

    Discussion

    Do not trust the actual integer values in this, they are platform-specific. Always use the names.

    • Declaration

      shift

    • Declaration

      capsLock

    • Declaration

      ctrl

    • alt

      Declaration

      alt
      windows

      Not always available on Windows

    • Declaration

      numLock

    • Declaration

      leftButtonDown
      middleButtonDown
      rightButtonDown

      these aren't available on Windows for key events, so don't use them for that unless your app is X only.

  • Declaration

    enum MouseButton: int;

    The names assume a right-handed mouse. These are bitwise combined on the events that use them

    • Declaration

      left

    • Declaration

      right

    • Declaration

      middle

    • Declaration

      wheelUp

    • Declaration

      wheelDown

    • Declaration

      backButton

      often found on the thumb and used for back in browsers

    • Declaration

      forwardButton

      often found on the thumb and used for forward in browsers

  • Key

    Declaration

    enum Key: int;

    Do not trust the numeric values as they are platform-specific. Always use the symbolic name.

    • Declaration

      Escape

    • F1

      Declaration

      F1

    • F2

      Declaration

      F2

    • F3

      Declaration

      F3

    • F4

      Declaration

      F4

    • F5

      Declaration

      F5

    • F6

      Declaration

      F6

    • F7

      Declaration

      F7

    • F8

      Declaration

      F8

    • F9

      Declaration

      F9

    • F10

      Declaration

      F10

    • F11

      Declaration

      F11

    • F12

      Declaration

      F12

    • Declaration

      PrintScreen

    • Declaration

      ScrollLock

    • Declaration

      Pause

    • Declaration

      Grave

      The ` ~ key

    • N1

      Declaration

      N1

      Number key atop the keyboard

    • N2

      Declaration

      N2

    • N3

      Declaration

      N3

    • N4

      Declaration

      N4

    • N5

      Declaration

      N5

    • N6

      Declaration

      N6

    • N7

      Declaration

      N7

    • N8

      Declaration

      N8

    • N9

      Declaration

      N9

    • N0

      Declaration

      N0

    • Declaration

      Dash

    • Declaration

      Equals

    • Declaration

      Backslash

      The \ | key

    • Declaration

      Backspace

    • Declaration

      Insert

    • Declaration

      Home

    • Declaration

      PageUp

    • Declaration

      Delete

    • End

      Declaration

      End

    • Declaration

      PageDown

    • Up

      Declaration

      Up

    • Declaration

      Down

    • Declaration

      Left

    • Declaration

      Right

    • Tab

      Declaration

      Tab

    • Q

      Declaration

      Q

    • W

      Declaration

      W

    • E

      Declaration

      E

    • R

      Declaration

      R

    • T

      Declaration

      T

    • Y

      Declaration

      Y

    • U

      Declaration

      U

    • I

      Declaration

      I

    • O

      Declaration

      O

    • P

      Declaration

      P

    • Declaration

      LeftBracket

      the [ { key

    • Declaration

      RightBracket

      the ] } key

    • Declaration

      CapsLock

    • A

      Declaration

      A

    • S

      Declaration

      S

    • D

      Declaration

      D

    • F

      Declaration

      F

    • G

      Declaration

      G

    • H

      Declaration

      H

    • J

      Declaration

      J

    • K

      Declaration

      K

    • L

      Declaration

      L

    • Declaration

      Semicolon

    • Declaration

      Apostrophe

    • Declaration

      Enter

    • Declaration

      Shift

    • Z

      Declaration

      Z

    • X

      Declaration

      X

    • C

      Declaration

      C

    • V

      Declaration

      V

    • B

      Declaration

      B

    • N

      Declaration

      N

    • M

      Declaration

      M

    • Declaration

      Comma

    • Declaration

      Period

    • Declaration

      Slash

      the / ? key

    • Declaration

      Shift_r

      Note: this isn't sent on all computers, sometimes it just sends Shift, so don't rely on it. If it is supported though, it is the right Shift key, as opposed to the left Shift key

    • Declaration

      Ctrl

    • Declaration

      Windows

    • Alt

      Declaration

      Alt

    • Declaration

      Space

    • Declaration

      Alt_r

      ditto of shift_r

    • Declaration

      Windows_r

    • Declaration

      Menu

    • Declaration

      Ctrl_r

    • Declaration

      NumLock

    • Declaration

      Divide

      The / key on the number pad

    • Declaration

      Multiply

      The * key on the number pad

    • Declaration

      Minus

      The - key on the number pad

    • Declaration

      Plus

      The + key on the number pad

    • Declaration

      PadEnter

      Numberpad enter key

    • Declaration

      Pad1

      Numberpad keys

    • Declaration

      Pad2

    • Declaration

      Pad3

    • Declaration

      Pad4

    • Declaration

      Pad5

    • Declaration

      Pad6

    • Declaration

      Pad7

    • Declaration

      Pad8

    • Declaration

      Pad9

    • Declaration

      Pad0

    • Declaration

      PadDot

  • Declaration

    string xfontstr;

    This is the default font used. You might change this before doing anything else with the library if you want to try something else. Surround that in static if(UsingSimpledisplayX11) for cross-platform compatibility.

  • Declaration

    class XDisplayConnection;

    Platform-specific for X11. A singleton class (well, all its methods are actually static... so more like a namespace) wrapping a Display*

    • Declaration

      static int connectionSequenceNumber();

      use this for lazy caching when reconnection

    • Declaration

      static void discardAndRecreate(string newDisplayString = null);

      Attempts recreation of state, may require application assistance You MUST call this OUTSIDE the event loop. Let the exception kill the loop, then call this, and if successful, reenter the loop.

    • Declaration

      static void addRootInput(EventMask mask);

      Requests the specified input from the root window on the connection, in addition to any other request.

      Discussion

      Since plain XSelectInput will replace the existing mask, adding input from multiple locations is tricky. This central function will combine all the masks for you.

    • Declaration

      static auto setDisplayName(string newDisplayName);

      can be used to override normal handling of display name from environment and/or command line

    • Declaration

      static auto resetDisplayName();

      resets to the default display string

    • get

      Declaration

      static Display* get();

    • Declaration

      static void close();

  • Declaration

    int mouseDoubleClickTimeout;

    double click timeout. X only, you probably shouldn't change this.

  • Declaration

    bool doXNextEvent(Display* display);

    Platform-specific, you might use it when doing a custom event loop

  • Declaration

    void demandAttention(SimpleWindow window, bool needs = true);

    X-specific. Use [SimpleWindow.requestAttention] instead for most casesl

  • Declaration

    TrueColorImage getWindowNetWmIcon(Window window);

    X-specific

  • Declaration

    interface DrawableFont;

    An interface representing a font.

    Discussion

    This is still MAJOR work in progress.

  • Declaration

    DrawableFont arsdTtfFont()(in ubyte[] data, int size);

    Loads a true type font using [arsd.ttf]. That module must be compiled in if you choose to use this function.

    Discussion

    Be warned: this can be slow and memory hungry, especially on remote connections to the X server.

    This is still MAJOR work in progress.