1 /**
2 * X11 demo.
3 *
4 * License:
5 * This Source Code Form is subject to the terms of
6 * the Mozilla Public License, v. 2.0. If a copy of
7 * the MPL was not distributed with this file, You
8 * can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * Authors:
11 * Vladimir Panteleev <ae@cy.md>
12 */13 14 moduleae.demo.x11.demo;
15 16 importstd.algorithm.iteration;
17 importstd.array;
18 19 importae.net.asockets;
20 importae.net.x11;
21 importae.utils.array;
22 importae.utils.promise;
23 24 // Pro tip: Build with -debug=PRINTDATA to see the raw bytes sent and25 // received from the X server!26 27 voidmain()
28 {
29 autox11 = newX11Client();
30 31 // Maintain a dictionary of known interred atoms.32 Atom[string] atoms;
33 Promise!AtomgetAtom(stringname)
34 {
35 autop = newPromise!Atom;
36 if (autopatom = nameinatoms)
37 p.fulfill(*patom);
38 else39 x11.sendInternAtom(false, name)
40 .dmd21804workaround41 .then((result) {
42 atoms[name] = result.atom;
43 p.fulfill(result.atom);
44 });
45 returnp;
46 }
47 48 // Our window, and the context we use to draw on it.49 Windowwid;
50 GContextgc;
51 52 // All operations can only be done once the handshake completes.53 x11.handleConnect = {
54 wid = x11.newRID(); // ID generation happens completely locally.55 56 // Create our window.57 WindowAttributeswindowAttributes;
58 windowAttributes.eventMask = ExposureMask;
59 x11.sendCreateWindow(
60 0,
61 wid,
62 x11.roots[0].root.windowId,
63 0, 0,
64 256, 256,
65 10,
66 InputOutput,
67 x11.roots[0].root.rootVisualID,
68 windowAttributes,
69 );
70 x11.sendMapWindow(wid);
71 72 // Create a graphics context from the window.73 gc = x11.newRID();
74 GCAttributesgcAttributes;
75 gcAttributes.foreground = x11.roots[0].root.blackPixel;
76 gcAttributes.background = x11.roots[0].root.whitePixel;
77 x11.sendCreateGC(
78 gc, wid,
79 gcAttributes,
80 );
81 82 // Announce our support of the WM_DELETE_WINDOW window manager83 // protocol. To do that, we need to intern some atoms first.84 ["WM_PROTOCOLS", "WM_DELETE_WINDOW", "ATOM"]
85 .map!getAtom86 .array87 .all88 .then((result) {
89 x11.sendChangeProperty(
90 PropModeReplace,
91 wid,
92 atoms["WM_PROTOCOLS"], atoms["ATOM"],
93 32,
94 [atoms["WM_DELETE_WINDOW"]].bytes,
95 );
96 });
97 };
98 99 // The expose event informs us when it's time to repaint our window.100 // Register a handler here.101 x11.handleExpose = (event) {
102 if (event.window == wid)
103 {
104 x11.sendPolyFillRectangle(wid, gc, [xRectangle(0, 0, ushort.max, ushort.max)]);
105 // Query the current window geometry, so that we can draw the text in the center.106 x11.sendGetGeometry(wid)
107 .dmd21804workaround108 .then((result) {
109 x11.sendImageText8(wid, gc, result.width / 2, result.height / 2, "Hello X11!");
110 });
111 }
112 };
113 114 // Register a handler for the client message event, so that we can115 // be notified of when the window manager is asking our window to116 // please go away.117 x11.handleClientMessage = (event) {
118 if (event.type == atoms["WM_PROTOCOLS"])
119 {
120 automessageAtoms = event.bytes.fromBytes!(Atom[])();
121 if (messageAtoms[0] == atoms["WM_DELETE_WINDOW"])
122 {
123 // As the X11 connection is the only object in the124 // event loop, disconnecting from the X server will125 // gracefully stop our application.126 x11.conn.disconnect();
127 }
128 }
129 };
130 x11.handleDisconnect = (stringerror, DisconnectTypetype) {
131 importstd.stdio : writefln;
132 writefln("Disconnected (%s): %s", type, error);
133 };
134 135 // Run the event loop.136 socketManager.loop();
137 }