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 = ®Global; 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 }