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:
does not have any dependencies outside the
operating system and simpledisplay
.dcolor.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
and simpledisplay
.dcolor.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.
// 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:
// 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:
// 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:
// dmd example.d simpledisplay.d color.d
import arsd.simpledisplay;
void main() {
}
You can also load PNG images using [arsd.png].
// 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.
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.
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"?>
`
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.
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.
// 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.
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(
more reliably thanUsingSimpledisplayWindows
) ...version()
becauseversion
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(
more reliably thanUsingSimpledisplayX11
) ...version()
becauseversion
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(
more reliably thanUsingSimpledisplayCocoa
) ...version()
becauseversion
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
()(ubytehi
, ubytelo
);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
()(boolv
);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
()(boolv
);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 returntrue
. -
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 callnew
and get a suitable window to work with.SimpleWindow
(some_width, some_height, "some title")
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 aSimpleWindow
instance by callingnew
. Remember, though, if you do this, managing the window is still your own responsibility! Notably, you will need to destroy it yourself.SimpleWindow
(native_handle)-
Declaration
TrueColorImage
takeScreenshot
();Be warned: this can be a very slow operation FIXME NOT IMPLEMENTED
-
Declaration
this(int
width
= 640, intheight
= 480, stringtitle
= null, OpenGlOptionsopengl
= OpenGlOptions.no, Resizabilityresizable
= Resizability.automaticallyScaleIfPossible, WindowTypeswindowType
= WindowTypes.normal, intcustomizationFlags
= WindowFlags.normal, SimpleWindowparent
= 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 pixelsint
height
the
height
of the window's client area, in pixelsstring
title
the
title
of the window (seen in thetitle
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. ThewindowResized
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. ThewindowResized
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
argument, is a good match for what you need.windowType
SimpleWindow
parent
the
parent
window, if applicable -
Declaration
this(Size
size
, stringtitle
= null, OpenGlOptionsopengl
= OpenGlOptions.no, Resizabilityresizable
= Resizability.automaticallyScaleIfPossible);Same as above, except using the
Size
struct instead of separate width and height. -
Declaration
this(Image
image
, stringtitle
= 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 thetitle
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
(boolkeyboard
= true, boolmouse
= true, boolconfine
= 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
themouse
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:
uses the NET_WM_STATE_DEMANDS_ATTENTION atom on X11 and the FlashWindow function on Windows.requestAttention
-
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 beenclosed
. -
Declaration
final @property bool
focused
();Returns
true
if the window isfocused
. -
Declaration
final @property bool
visible
();Returns
true
if the window isvisible
(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
(intx
, inty
);"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
(intminwidth
, intminheight
);Set window minimal size.
-
Declaration
void
setMaxSize
(intmaxwidth
, intmaxheight
);Set window maximal size.
-
Declaration
void
setResizeGranularity
(intgranx
, intgrany
);Set window resize step (window size will be changed with the given granularity on supported platforms). Currently only supported on X11.
-
Declaration
void
move
(intx
, inty
);
voidmove
(Pointp
);Move window.
-
Declaration
void
resize
(intw
, inth
);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
(intx
, inty
, intw
, inth
);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 ishidden
. -
Declaration
final @property void
hidden
(boolb
);Shows or hides the window based on the bool argument.
-
Declaration
@property void
opacity
(doubleopacity
);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...)(TeventHandlers
);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...)(longpulseTimeout
, TeventHandlers
);The event loop automatically returns when the window is closed
pulseTimeout
is given in milliseconds. IfpulseTimeout
== 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 theSimpleWindow
. -
Declaration
final @property void
vsync
(boolwait
);This will allow you to change OpenGL
vsync
state. -
Declaration
bool
useGLFinish
;Set this to
false
if you don't need to doglFinish()
afterswapOpenGlBuffers()
. 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
(stringtitle
);Set the window
title
, which is visible on the window managertitle
bar, operating system taskbar, etc.Discussion
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
(MemoryImageicon
);Set the
icon
that is seen in the title bar or taskbar, etc., for the user. -
Declaration
@property void
image
(Imagei
);Draws an
image
on the window. This is meant to provide quick look of a staticimage
generated elsewhere. -
Declaration
@property void
cursor
(MouseCursorcursor
);Changes the
cursor
for the window. If thecursor
is hidden via [hideCursor], this has no effect.Discussion
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, ortrue
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
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
()(uintid
);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)(ETevt
, uinttimeoutmsecs
, boolreplace
= false);Post event to queue. It is safe to call this from non-UI threads. If
is greater than zero, the event will be delayed for at leasttimeoutmsecs
milliseconds. iftimeoutmsecs
isreplace
true
,replace
all existing events typedET
with the new one (if
is empty, remove 'em all) Returnsevt
true
if event was queued. Always returnsfalse
if
isevt
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)(ETevt
, boolreplace
= false);Post event to queue. It is safe to call this from non-UI threads. if
isreplace
true
,replace
all existing events typedET
with the new one (if
is empty, remove 'em all) Returnsevt
true
if event was queued. Always returnsfalse
if
isevt
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
. See [GenericCursorType] for a list of types.GenericCursor
.SomeTime-
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 intx
, out inty
, out intwidth
, out intheight
);X11 only. Get global window coordinates and size. This can be used to show various notifications.
-
Declaration
this(string
name
, MemoryImageicon
, void delegate(MouseButton button)onClick
);
this(stringname
, Imageicon
, 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
, MemoryImageicon
, void delegate(int x, int y, MouseButton button, ModifierState mods)onClickEx
);
this(stringname
, Imageicon
, 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 voidonClick
(void delegate(MouseButton)handler
); -
Declaration
@property void
icon
(MemoryImagei
);
@property voidicon
(Imagei
); -
Declaration
void
showBalloon
(stringtitle
, stringmessage
, MemoryImageicon
= null, void delegate()onclick
= null, inttimeout
= 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. Ifnull
, it uses your existingicon
.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
(MemoryImagei
, Windowwindow
);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 = newTimer
(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
, intfd
, boolcaptureReads
= true, boolcaptureWrites
= false); -
Declaration
this(void delegate(int)
onReady
, intfd
, boolcaptureReads
= true, boolcaptureWrites
= false); -
Declaration
this(void delegate(int
fd
, bool read, bool write)onReady
, intfd
, boolcaptureReads
= true, boolcaptureWrites
= false); -
Declaration
void
enable
(); -
Declaration
void
disable
(); -
Declaration
void
dispose
();
-
-
Declaration
void
getClipboardText
(SimpleWindowclipboardOwner
, 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
(SimpleWindowclipboardOwner
, stringtext
);copies some
text
to the clipboard -
Declaration
@property Atom
GetAtom
(string name, bool create = false)(Display*display
);Platform specific for X11
-
Declaration
string
getAtomName
(Atomatom
, Display*display
);Platform specific for X11 - gets
atom
names as a string -
Declaration
void
setPrimarySelection
(SimpleWindowwindow
, stringtext
);Asserts ownership of PRIMARY and copies the
text
into a buffer that clients can request later -
Declaration
void
setSecondarySelection
(SimpleWindowwindow
, stringtext
);Asserts ownership of SECONDARY and copies the
text
into a buffer that clients can request later -
Declaration
void
setX11Selection
(string atomName)(SimpleWindowwindow
, stringtext
); -
Declaration
void
getPrimarySelection
(SimpleWindowwindow
, void delegate(in char[])handler
); -
Declaration
void
getX11Selection
(string atomName)(SimpleWindowwindow
, void delegate(in char[])handler
); -
Declaration
void[]
getX11PropertyData
(Windowwindow
, Atomproperty
, Atomtype
= 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
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
meansalt
andH
means the Windows logo key.C
isctrl
.
-
Declaration
static void
register
(GlobalHotkeygh
);
static voidregister
(const(char)[]akey
, void delegate()ahandler
);Register new global hotkey with initialized
GlobalHotkey
object. This function will throw if it failed toregister
hotkey (i.e. hotkey is invalid or already taken). -
Declaration
static void
unregister
(GlobalHotkeygh
);Register new global hotkey with previously used
GlobalHotkey
object. It is safe tounregister
unknown or invalid hotkey. -
Declaration
static void
unregister
(const(char)[]key
);Ditto.
-
Declaration
enum
RasterOp
: int; -
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].
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); }
-
Declaration
no
No OpenGL context is created
-
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
Left
-
Declaration
Center
-
Declaration
Right
-
Declaration
VerticalTop
-
Declaration
VerticalCenter
-
Declaration
VerticalBottom
-
-
Declaration
struct
KeyEvent
;Keyboard press and release events
-
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 justpressed
,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
(stringname
);
@property stringApplicationName
();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.
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]
-
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.
-
Declaration
int
y
;Current Y position of the cursor when the event fired.
-
Declaration
int
dx
;Change in X position since last report
-
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 MouseEventevent
, 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"
-
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;
-
-
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
is also the first step in loading and displaying images loaded from files.Image
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 theopIndexAssign
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
, intheight
, boolforcexshm
= false); -
Declaration
this(Size
size
, boolforcexshm
= 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
(intx
, inty
);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
(intx
, inty
, Colorc
); -
Declaration
final Color
getPixel
(intx
, inty
); -
Declaration
final void
opIndexAssign
(Colorc
, intx
, inty
); -
Declaration
TrueColorImage
toTrueColorImage
(); -
Declaration
static Image
fromMemoryImage
(MemoryImagei
); -
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 passnull
, 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
(Imageimage
, SimpleWindowwin
= null);A convenience function to pop up a window displaying the
image
. If you pass awin
, it will draw theimage
in it. Otherwise, it will create a window with the size of theimage
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, anull
font will automatically fall back to the default font loaded for your system.-
Declaration
this(string
name
, intsize
= 0, FontWeightweight
= FontWeight.dontcare, boolitalic
= false); -
Declaration
bool
load
(stringname
, intsize
= 0, FontWeightweight
= FontWeight.dontcare, boolitalic
= 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
(Pointpt
, intwidth
, intheight
);
voidsetClipRectangle
(arsd.color.Rectanglerect
);Sets the clipping region for drawing. If
width
== 0 &&height
== 0, disabled clipping. -
Declaration
void
setFont
(OperatingSystemFontfont
); -
Declaration
int
fontHeight
(); -
Declaration
@property void
pen
(Penp
); -
Declaration
@property void
outlineColor
(Colorc
); -
Declaration
@property void
fillColor
(Colorc
); -
Declaration
@property void
rasterOp
(RasterOpop
); -
Declaration
void
scrollArea
(PointupperLeft
, intwidth
, intheight
, intdx
, intdy
);Scrolls the contents in the bounding rectangle by
dx
,dy
. Positivedx
means scroll left (make space available at the right), positivedy
means scroll up (make space available at the bottom) -
Declaration
void
clear
(); -
Declaration
void
drawPixmap
(Sprites
, PointupperLeft
); -
Declaration
void
drawImage
(PointupperLeft
, Imagei
, PointupperLeftOfImage
= Point(0, 0), intw
= 0, inth
= 0); -
Declaration
Size
textSize
(in char[]text
); -
Declaration
void
drawText
(PointupperLeft
, in char[]text
, PointlowerRight
= Point(0, 0), uintalignment
= 0); -
Declaration
void
drawText
(DrawableFontfont
, PointupperLeft
, in char[]text
);Draws
text
using a customfont
.Discussion
This is still MAJOR work in progress.
Creating a [DrawableFont] can be tricky and require additional dependencies. -
Declaration
void
drawPixel
(Pointwhere
);Drawing an individual pixel is slow. Avoid it if possible.
-
Declaration
void
drawLine
(Pointstarting
, Pointending
);Draws a pen using the current pen / outlineColor
-
Declaration
void
drawRectangle
(PointupperLeft
, intwidth
, intheight
);
voiddrawRectangle
(PointupperLeft
, Sizesize
);
voiddrawRectangle
(PointupperLeft
, PointlowerRightInclusive
);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
(PointupperLeft
, PointlowerRight
);Arguments are the points of the bounding rectangle
-
Declaration
void
drawArc
(PointupperLeft
, intwidth
, intheight
, intstart
, intfinish
);start
andfinish
are units of degrees * 64 -
Declaration
void
drawPolygon
(Point[]vertexes
);
voiddrawPolygon
(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 usesprite.drawAt(painter, point);
to draw it, which should be a fast operation - much faster than drawing the Image itself every time.
represents a scarce resource which should be freed when you are done with it. Use theSprite
dispose
method to do this. Do not use a
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.Sprite
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
to have const contents.Sprite
-
Declaration
ScreenPainter
draw
(); -
Declaration
TrueColorImage
takeScreenshot
();Be warned: this can be a very slow operation FIXME NOT IMPLEMENTED
-
Declaration
this(SimpleWindow
win
, Imagei
);Makes a sprite based on the image with the initial contents from the Image
-
Declaration
void
drawAt
(ScreenPainterpainter
, Pointwhere
);Draws the image on the specified
painter
at the specified point. The point is the upper-left pointwhere
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
-
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
-
-
Declaration
enum
Key
: int;Do not trust the numeric values as they are platform-specific. Always use the symbolic name.
-
Declaration
Escape
-
Declaration
F1
-
Declaration
F2
-
Declaration
F3
-
Declaration
F4
-
Declaration
F5
-
Declaration
F6
-
Declaration
F7
-
Declaration
F8
-
Declaration
F9
-
Declaration
F10
-
Declaration
F11
-
Declaration
F12
-
Declaration
PrintScreen
-
Declaration
ScrollLock
-
Declaration
Pause
-
Declaration
Grave
The ` ~ key
-
Declaration
N1
Number key atop the keyboard
-
Declaration
N2
-
Declaration
N3
-
Declaration
N4
-
Declaration
N5
-
Declaration
N6
-
Declaration
N7
-
Declaration
N8
-
Declaration
N9
-
Declaration
N0
-
Declaration
Dash
-
Declaration
Equals
-
Declaration
Backslash
The \ | key
-
Declaration
Backspace
-
Declaration
Insert
-
Declaration
Home
-
Declaration
PageUp
-
Declaration
Delete
-
Declaration
End
-
Declaration
PageDown
-
Declaration
Up
-
Declaration
Down
-
Declaration
Left
-
Declaration
Right
-
Declaration
Tab
-
Declaration
Q
-
Declaration
W
-
Declaration
E
-
Declaration
R
-
Declaration
T
-
Declaration
Y
-
Declaration
U
-
Declaration
I
-
Declaration
O
-
Declaration
P
-
Declaration
LeftBracket
the [ { key
-
Declaration
RightBracket
the ] } key
-
Declaration
CapsLock
-
Declaration
A
-
Declaration
S
-
Declaration
D
-
Declaration
F
-
Declaration
G
-
Declaration
H
-
Declaration
J
-
Declaration
K
-
Declaration
L
-
Declaration
Semicolon
-
Declaration
Apostrophe
-
Declaration
Enter
-
Declaration
Shift
-
Declaration
Z
-
Declaration
X
-
Declaration
C
-
Declaration
V
-
Declaration
B
-
Declaration
N
-
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
-
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
(stringnewDisplayString
= 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
(EventMaskmask
);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
(stringnewDisplayName
);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
-
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
(SimpleWindowwindow
, boolneeds
= true);X-specific. Use [SimpleWindow.requestAttention] instead for most casesl
-
Declaration
TrueColorImage
getWindowNetWmIcon
(Windowwindow
);X-specific
-
Declaration
interface
DrawableFont
;An interface representing a font.
Discussion
This is still MAJOR work in progress.
-
Declaration
DrawableFont
arsdTtfFont
()(in ubyte[]data
, intsize
);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.