1 // Copyright © 2017 Rémi Thebault
2 module hello;
3 
4 // this is a port of https://github.com/hdante/hello_wayland
5 
6 import wayland.client;
7 import wayland.native.client;
8 import wayland.util;
9 import wayland.util.shm_helper;
10 
11 import core.sys.posix.sys.mman;
12 import core.sys.posix.unistd;
13 import std.algorithm;
14 import std.exception;
15 import std.stdio;
16 
17 enum winWidth = 320;
18 enum winHeight = 200;
19 enum cursorWidth = 100;
20 enum cursorHeight = 59;
21 enum cursorHotSpotX = 10;
22 enum cursorHotSpotY = 35;
23 
24 int main()
25 {
26 	version(WlDynamic) { wlClientDynLib.load(); }
27 
28 	auto hello = new Hello;
29 	hello.makeMemPool(cast(immutable(ubyte)[])import("images.bin"));
30 	hello.createSurface();
31 	hello.setupBuffers();
32 	hello.loop();
33 	hello.cleanUp();
34 	return 0;
35 }
36 
37 class Hello
38 {
39 	WlDisplay display;
40 	WlCompositor compositor;
41 	WlPointer pointer;
42 	WlSeat seat;
43 	WlShell shell;
44 	WlShm shm;
45 
46 	int poolFd;
47 	ubyte* poolMem;
48 	size_t poolSize;
49 	WlShmPool pool;
50 	WlSurface surf;
51 	WlShellSurface shSurf;
52 	WlBuffer winBuf;
53 	WlBuffer cursorBuf;
54 	WlSurface cursorSurf;
55 	bool doneFlag;
56 
57 	this()
58 	{
59 		display = enforce(WlDisplay.connect());
60 		auto reg = display.getRegistry();
61 
62 		reg.onGlobal = &regGlobal;
63 
64 		display.roundtrip();
65 		reg.destroy();
66 	}
67 
68 	void regGlobal(WlRegistry reg, uint name, string iface, uint ver)
69 	{
70 		if(iface == WlCompositor.iface.name)
71 		{
72 			compositor = cast(WlCompositor)reg.bind(
73 				name, WlCompositor.iface, min(ver, 4)
74 			);
75 		}
76 		else if(iface == WlShm.iface.name)
77 		{
78 			shm = cast(WlShm)reg.bind(
79 				name, WlShm.iface, min(ver, 1)
80 			);
81 		}
82 		else if(iface == WlShell.iface.name)
83 		{
84 			shell = cast(WlShell)reg.bind(
85 				name, WlShell.iface, min(ver, 1)
86 			);
87 		}
88 		else if(iface == WlSeat.iface.name)
89 		{
90 			seat = cast(WlSeat)reg.bind(
91 				name, WlSeat.iface, min(ver, 2)
92 			);
93 			pointer = seat.getPointer();
94 			pointer.onEnter = &pointerEnter;
95 			pointer.onButton = &pointerButton;
96 		}
97 	}
98 
99 	void makeMemPool(immutable(ubyte)[] imgData)
100 	{
101 		poolFd = createMmapableFile(imgData.length);
102 		poolMem = cast(ubyte*)mmap(
103 			null, imgData.length, PROT_READ|PROT_WRITE, MAP_SHARED, poolFd, 0
104 		);
105 		enforce(poolMem !is MAP_FAILED);
106 		poolSize = imgData.length;
107 		poolMem[0 .. poolSize] = imgData[];
108 		pool = enforce(shm.createPool(poolFd, cast(int)poolSize));
109 	}
110 
111 	void createSurface()
112 	{
113 		surf = enforce(compositor.createSurface());
114 		scope(failure) surf.destroy();
115 
116 		shSurf = shell.getShellSurface(surf);
117 		shSurf.onPing = (WlShellSurface wlShSurf, uint serial)
118 		{
119 			wlShSurf.pong(serial);
120 		};
121 
122 		shSurf.setToplevel();
123 
124 		cursorSurf = enforce(compositor.createSurface());
125 	}
126 
127 	void setupBuffers()
128 	{
129 		winBuf = pool.createBuffer(
130 			0, winWidth, winHeight, 4*winWidth, WlShm.Format.argb8888
131 		);
132 		cursorBuf = pool.createBuffer(
133 			winWidth*winHeight*4, cursorWidth, cursorHeight, 4*cursorWidth,
134 			WlShm.Format.argb8888
135 		);
136 
137 		surf.attach(winBuf, 0, 0);
138 		surf.commit();
139 	}
140 
141 	void pointerEnter(WlPointer pointer, uint serial, WlSurface surface,
142 						WlFixed surfaceX, WlFixed surfaceY)
143 	{
144 		cursorSurf.attach(cursorBuf, 0, 0);
145 		cursorSurf.commit();
146 		pointer.setCursor(serial, cursorSurf, cursorHotSpotX, cursorHotSpotY);
147 	}
148 
149 	void pointerButton(WlPointer, uint serial, uint time, uint button,
150 						WlPointer.ButtonState state)
151 	{
152 		doneFlag = true;
153 	}
154 
155 	void loop()
156 	{
157 		while (!doneFlag)
158 		{
159 			if (display.dispatch() < 0)
160 			{
161 				stderr.writeln("Main loop error");
162 				doneFlag = true;
163 			}
164 		}
165 	}
166 
167 	void cleanUp()
168 	{
169 		cursorBuf.destroy();
170 		cursorSurf.destroy();
171 		winBuf.destroy();
172 		shSurf.destroy();
173 		surf.destroy();
174 		pool.destroy();
175 		munmap(poolMem, poolSize);
176 		close(poolFd);
177 		pointer.destroy();
178 		seat.destroy();
179 		shell.destroy();
180 		shm.destroy();
181 		compositor.destroy();
182 		display.disconnect();
183 	}
184 }