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 WlKeyboard kbd; 43 WlSeat seat; 44 WlShell shell; 45 WlShm shm; 46 47 int poolFd; 48 ubyte* poolMem; 49 size_t poolSize; 50 WlShmPool pool; 51 WlSurface surf; 52 WlShellSurface shSurf; 53 WlBuffer winBuf; 54 WlBuffer cursorBuf; 55 WlSurface cursorSurf; 56 bool doneFlag; 57 58 this() 59 { 60 display = enforce(WlDisplay.connect()); 61 auto reg = display.getRegistry(); 62 63 reg.onGlobal = ®Global; 64 65 display.roundtrip(); 66 reg.destroy(); 67 } 68 69 void regGlobal(WlRegistry reg, uint name, string iface, uint ver) 70 { 71 if(iface == WlCompositor.iface.name) 72 { 73 compositor = cast(WlCompositor)reg.bind( 74 name, WlCompositor.iface, min(ver, 4) 75 ); 76 } 77 else if(iface == WlShm.iface.name) 78 { 79 shm = cast(WlShm)reg.bind( 80 name, WlShm.iface, min(ver, 1) 81 ); 82 } 83 else if(iface == WlShell.iface.name) 84 { 85 shell = cast(WlShell)reg.bind( 86 name, WlShell.iface, min(ver, 1) 87 ); 88 } 89 else if(iface == WlSeat.iface.name) 90 { 91 seat = cast(WlSeat)reg.bind( 92 name, WlSeat.iface, min(ver, 2) 93 ); 94 seat.onCapabilities = &seatCapChanged; 95 } 96 } 97 98 void seatCapChanged (WlSeat seat, WlSeat.Capability cap) 99 { 100 if ((cap & WlSeat.Capability.pointer) && !pointer) 101 { 102 writeln("setup"); 103 pointer = seat.getPointer(); 104 pointer.onEnter = &pointerEnter; 105 pointer.onButton = &pointerButton; 106 } 107 else if (!(cap & WlSeat.Capability.pointer) && pointer) 108 { 109 pointer.destroy(); 110 pointer = null; 111 } 112 113 if ((cap & WlSeat.Capability.keyboard) && !kbd) 114 { 115 kbd = seat.getKeyboard(); 116 kbd.onKey = &kbdKey; 117 } 118 else if (!(cap & WlSeat.Capability.keyboard) && kbd) 119 { 120 kbd.destroy(); 121 kbd = null; 122 } 123 } 124 125 126 void makeMemPool(immutable(ubyte)[] imgData) 127 { 128 poolFd = createMmapableFile(imgData.length); 129 poolMem = cast(ubyte*)mmap( 130 null, imgData.length, PROT_READ|PROT_WRITE, MAP_SHARED, poolFd, 0 131 ); 132 enforce(poolMem !is MAP_FAILED); 133 poolSize = imgData.length; 134 poolMem[0 .. poolSize] = imgData[]; 135 pool = enforce(shm.createPool(poolFd, cast(int)poolSize)); 136 } 137 138 void createSurface() 139 { 140 surf = enforce(compositor.createSurface()); 141 scope(failure) surf.destroy(); 142 143 shSurf = shell.getShellSurface(surf); 144 shSurf.onPing = (WlShellSurface wlShSurf, uint serial) 145 { 146 wlShSurf.pong(serial); 147 }; 148 149 shSurf.setToplevel(); 150 151 cursorSurf = enforce(compositor.createSurface()); 152 } 153 154 void setupBuffers() 155 { 156 winBuf = pool.createBuffer( 157 0, winWidth, winHeight, 4*winWidth, WlShm.Format.argb8888 158 ); 159 cursorBuf = pool.createBuffer( 160 winWidth*winHeight*4, cursorWidth, cursorHeight, 4*cursorWidth, 161 WlShm.Format.argb8888 162 ); 163 164 surf.attach(winBuf, 0, 0); 165 surf.commit(); 166 } 167 168 void pointerEnter(WlPointer pointer, uint serial, WlSurface surface, 169 WlFixed surfaceX, WlFixed surfaceY) 170 { 171 cursorSurf.attach(cursorBuf, 0, 0); 172 cursorSurf.commit(); 173 pointer.setCursor(serial, cursorSurf, cursorHotSpotX, cursorHotSpotY); 174 } 175 176 void pointerButton(WlPointer, uint serial, uint time, uint button, 177 WlPointer.ButtonState state) 178 { 179 doneFlag = true; 180 } 181 182 void kbdKey(WlKeyboard keyboard, uint serial, uint time, uint key, 183 WlKeyboard.KeyState state) 184 { 185 import linux.input : KEY_ESC; 186 187 if (key == KEY_ESC && state) doneFlag = true; 188 } 189 190 void loop() 191 { 192 while (!doneFlag) 193 { 194 if (display.dispatch() < 0) 195 { 196 stderr.writeln("Main loop error"); 197 doneFlag = true; 198 } 199 } 200 } 201 202 void cleanUp() 203 { 204 cursorBuf.destroy(); 205 cursorSurf.destroy(); 206 winBuf.destroy(); 207 shSurf.destroy(); 208 surf.destroy(); 209 pool.destroy(); 210 munmap(poolMem, poolSize); 211 close(poolFd); 212 pointer.destroy(); 213 kbd.destroy(); 214 seat.destroy(); 215 shell.destroy(); 216 shm.destroy(); 217 compositor.destroy(); 218 display.disconnect(); 219 } 220 }