├── README.md ├── .gitignore ├── LICENSE └── sdl-srv.c /README.md: -------------------------------------------------------------------------------- 1 | # devdraw-sdl 2 | SDL 2.0-based implementation of Plan 9 from User Space devdraw 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Oskar Sveinsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sdl-srv.c: -------------------------------------------------------------------------------- 1 | /* devdraw-sdl - SDL 2.0-based implementation of Plan 9 from User Space devdraw 2 | * Copyright (c) 2018 Oskar Sveinsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include "devdraw.h" 34 | 35 | #define HANDLER(type) ((type >> 1) - 1) 36 | 37 | #define DEFAULT_WINW 640 38 | #define DEFAULT_WINH 480 39 | #define DEFAULT_WINFLAGS SDL_WINDOW_RESIZABLE 40 | 41 | #define BUFSZ_EVTQ 32 42 | #define BUFSZ_RDDRAW 0x10000 43 | 44 | typedef union Evt Evt; 45 | typedef struct Evtq Evtq; 46 | 47 | union Evt { 48 | Rune kbd; 49 | }; 50 | 51 | struct Evtq { 52 | uint ri, wi; 53 | int dir; /* content type: >0 tags, 0 empty, <0 evts */ 54 | union { 55 | uchar tag; 56 | Evt evt; 57 | } buf[BUFSZ_EVTQ]; 58 | }; 59 | 60 | static uint matchtag(Evtq, uchar, Evt *); 61 | static uint matchevt(Evtq, Evt, uchar *); 62 | 63 | static void reply(Wsysmsg *msg); 64 | static void replyerrstr(Wsysmsg *msg); 65 | static void replyerrsdl(Wsysmsg *msg); 66 | 67 | static void handle_rdmouse(Wsysmsg *); 68 | static void handle_moveto(Wsysmsg *); 69 | static void handle_cursor(Wsysmsg *); 70 | static void handle_bouncemouse(Wsysmsg *); 71 | static void handle_rdkbd(Wsysmsg *); 72 | static void handle_label(Wsysmsg *); 73 | static void handle_init(Wsysmsg *); 74 | static void handle_rdsnarf(Wsysmsg *); 75 | static void handle_wrsnarf(Wsysmsg *); 76 | static void handle_rddraw(Wsysmsg *); 77 | static void handle_wrdraw(Wsysmsg *); 78 | static void handle_top(Wsysmsg *); 79 | static void handle_resize(Wsysmsg *); 80 | 81 | void (*handlers[])(Wsysmsg *) = { 82 | [HANDLER(Trdmouse)] = &handle_rdmouse, 83 | [HANDLER(Tmoveto)] = &handle_moveto, 84 | [HANDLER(Tcursor)] = &handle_cursor, 85 | [HANDLER(Tbouncemouse)] = &handle_bouncemouse, 86 | [HANDLER(Trdkbd)] = &handle_rdkbd, 87 | [HANDLER(Tlabel)] = &handle_label, 88 | [HANDLER(Tinit)] = &handle_init, 89 | [HANDLER(Trdsnarf)] = &handle_rdsnarf, 90 | [HANDLER(Twrsnarf)] = &handle_wrsnarf, 91 | [HANDLER(Trddraw)] = &handle_rddraw, 92 | [HANDLER(Twrdraw)] = &handle_wrdraw, 93 | [HANDLER(Ttop)] = &handle_top, 94 | [HANDLER(Tresize)] = &handle_resize 95 | }; 96 | 97 | SDL_Window *win; 98 | 99 | Evtq kbdq; 100 | 101 | uint 102 | matchtag(Evtq q, uchar tag, Evt *evt) 103 | { 104 | if (q.dir < 0) { 105 | *evt = q.buf[q.ri].evt; 106 | if (++q.ri >= nelem(q.buf)) 107 | q.ri = 0; 108 | if (q.ri == q.wi) 109 | q.dir = 0; 110 | return 1; 111 | } else { 112 | if (q.wi == q.ri) { 113 | Wsysmsg err; 114 | 115 | err.tag = q.buf[q.wi].tag; 116 | err.type = Rerror; 117 | err.error = "tag queue overflow"; 118 | reply(&err); 119 | if (++q.ri >= nelem(q.buf)) 120 | q.ri = 0; 121 | } 122 | q.buf[q.wi].tag = tag; 123 | if (++q.wi >= nelem(q.buf)) 124 | q.wi = 0; 125 | q.dir = 1; 126 | return 0; 127 | } 128 | } 129 | 130 | uint 131 | matchevt(Evtq q, Evt evt, uchar *tag) 132 | { 133 | if (q.dir > 0) { 134 | *tag = q.buf[q.ri].tag; 135 | if (++q.ri >= nelem(q.buf)) 136 | q.ri = 0; 137 | if (q.ri == q.wi) 138 | q.dir = 0; 139 | return 1; 140 | } else { 141 | if (q.wi == q.ri && ++q.ri >= nelem(q.buf)) 142 | q.ri = 0; 143 | q.buf[q.wi].evt = evt; 144 | if (++q.wi >= nelem(q.buf)) 145 | q.wi = 0; 146 | q.dir = -1; 147 | return 0; 148 | } 149 | } 150 | 151 | void 152 | reply(Wsysmsg *msg) 153 | { 154 | static uchar *buf; 155 | static int nbuf; 156 | uint n; 157 | 158 | msg->type |= 1; 159 | if ((n = sizeW2M(msg)) > nbuf) { 160 | free(buf); 161 | if (!(buf = malloc(nbuf = n))) 162 | sysfatal("malloc: %r"); 163 | } 164 | convW2M(msg, buf, n); 165 | if (write(1, buf, n) != n) 166 | sysfatal("write: %r"); 167 | } 168 | 169 | void 170 | replyerrstr(Wsysmsg *msg) 171 | { 172 | char err[ERRMAX]; 173 | 174 | rerrstr(err, sizeof(err)); 175 | msg->type = Rerror; 176 | msg->error = err; 177 | reply(msg); 178 | } 179 | 180 | void 181 | replyerrsdl(Wsysmsg *msg) 182 | { 183 | msg->type = Rerror; 184 | msg->error = SDL_GetError(); 185 | reply(msg); 186 | SDL_ClearError(); 187 | } 188 | 189 | void 190 | handle_moveto(Wsysmsg *msg) 191 | { 192 | SDL_WarpMouseInWindow(win, msg->mouse.xy.x, msg->mouse.xy.y); 193 | reply(msg); 194 | } 195 | 196 | void 197 | handle_cursor(Wsysmsg *msg) 198 | { 199 | SDL_FreeCursor(SDL_GetCursor()); /* cursor will be reset to default as a side effect */ 200 | if (!msg->arrowcursor) { 201 | Cursor *cur; 202 | SDL_Cursor *sdlcur; 203 | 204 | cur = &msg->cursor; 205 | sdlcur = SDL_CreateCursor(cur->set, cur->clr, 16, 16, cur->offset.x, cur->offset.y); 206 | if (!sdlcur) { 207 | replyerrsdl(msg); 208 | return; 209 | } 210 | SDL_SetCursor(sdlcur); 211 | } 212 | reply(msg); 213 | } 214 | 215 | void 216 | handle_rdkbd(Wsysmsg *msg) 217 | { 218 | Evt evt; 219 | 220 | if (matchtag(kbdq, msg->tag, &evt)) { 221 | msg->rune = evt.kbd; 222 | reply(msg); 223 | } 224 | } 225 | 226 | void 227 | handle_label(Wsysmsg *msg) 228 | { 229 | SDL_SetWindowTitle(win, msg->label); 230 | reply(msg); 231 | } 232 | 233 | void 234 | handle_init(Wsysmsg *msg) 235 | { 236 | int x, y, w, h; 237 | 238 | x = y = SDL_WINDOWPOS_UNDEFINED; 239 | w = DEFAULT_WINW; 240 | h = DEFAULT_WINH; 241 | if (*msg->winsize) { 242 | Rectangle r; 243 | int havemin; 244 | 245 | if (parsewinsize(msg->winsize, &r, &havemin) < 0) { 246 | replyerrstr(msg); 247 | return; 248 | } 249 | if (havemin) { 250 | x = r.min.x; 251 | y = r.min.y; 252 | } 253 | w = Dx(r); 254 | h = Dy(r); 255 | } 256 | if (win = SDL_CreateWindow(msg->label, x, y, w, h, DEFAULT_WINFLAGS)) 257 | reply(msg); 258 | else 259 | replyerrsdl(msg); 260 | } 261 | 262 | void 263 | handle_rdsnarf(Wsysmsg *msg) 264 | { 265 | if (msg->snarf = SDL_GetClipboardText()) { 266 | reply(msg); 267 | SDL_free(msg->snarf); 268 | } else { 269 | replyerrsdl(msg); 270 | } 271 | } 272 | 273 | void 274 | handle_wrsnarf(Wsysmsg *msg) 275 | { 276 | if (SDL_SetClipboardText(msg->snarf)) 277 | replyerrsdl(msg); 278 | else 279 | reply(msg); 280 | } 281 | 282 | void 283 | handle_rddraw(Wsysmsg *msg) 284 | { 285 | uchar buf[BUFSZ_RDDRAW]; 286 | 287 | msg->data = buf; 288 | if (msg->count > sizeof(buf)) 289 | msg->count = sizeof(buf); 290 | if ((msg->count = _drawmsgread(buf, msg->count)) >= 0) 291 | reply(msg); 292 | else 293 | replyerrstr(msg); 294 | } 295 | 296 | void 297 | handle_wrdraw(Wsysmsg *msg) 298 | { 299 | if (_drawmsgwrite(msg->data, msg->count) >= 0) 300 | reply(msg); 301 | else 302 | replyerrstr(msg); 303 | } 304 | 305 | void 306 | handle_top(Wsysmsg *msg) 307 | { 308 | SDL_RaiseWindow(win); 309 | reply(msg); 310 | } 311 | 312 | void 313 | handle_resize(Wsysmsg *msg) 314 | { 315 | SDL_SetWindowSize(win, Dx(msg->rect), Dy(msg->rect)); 316 | reply(msg); 317 | } 318 | 319 | void 320 | main(int argc, char *argv[]) 321 | { 322 | uchar *buf; 323 | int nbuf; 324 | Wsysmsg msg; 325 | 326 | ARGBEGIN { 327 | defualt: 328 | } ARGEND 329 | 330 | if (SDL_Init(SDL_INIT_VIDEO) < 0) 331 | sysfatal("failed to initialize SDL: %s", SDL_GetError()); 332 | 333 | buf = malloc(nbuf = 4); 334 | while (read(1, buf, 4) == 4) { 335 | int n; 336 | 337 | GET(buf, n); 338 | if (n > nbuf) { 339 | free(buf); 340 | if (!(buf = malloc(4 + n))) 341 | sysfatal("malloc: %r"); 342 | PUT(buf, n); 343 | nbuf = n; 344 | } 345 | if (readn(3, buf + 4, n - 4) != 4) 346 | sysfatal("message too short"); 347 | if (!convM2W(buf, n, &msg)) 348 | sysfatal("invalid message"); 349 | handlers[HANDLER(msg.type)](&msg); 350 | } 351 | } 352 | --------------------------------------------------------------------------------