1 /* 2 * Nuklear - v1.40.8 - public domain 3 * no warrenty implied; use at your own risk. 4 * authored from 2015-2017 by Micha Mettke 5 */ 6 /* 7 * ============================================================== 8 * 9 * API 10 * 11 * =============================================================== 12 */ 13 #ifndef NK_XLIB_H_ 14 #define NK_XLIB_H_ 15 16 #include <X11/Xlib.h> 17 18 typedef struct XFont XFont; 19 NK_API struct nk_context* nk_xlib_init(XFont*, Display*, int scrn, Window root, unsigned w, unsigned h); 20 NK_API int nk_xlib_handle_event(Display*, int scrn, Window, XEvent*); 21 NK_API void nk_xlib_render(Drawable screen, struct nk_color clear); 22 NK_API void nk_xlib_shutdown(void); 23 NK_API void nk_xlib_set_font(XFont*); 24 NK_API void nk_xlib_push_font(XFont*); 25 NK_API void nk_xlib_paste(nk_handle, struct nk_text_edit*); 26 NK_API void nk_xlib_copy(nk_handle, const char*, int len); 27 28 /* Image */ 29 #ifdef NK_XLIB_INCLUDE_STB_IMAGE 30 NK_API struct nk_image nk_xsurf_load_image_from_file(char const *filename); 31 NK_API struct nk_image nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize); 32 #endif 33 34 /* Font */ 35 NK_API XFont* nk_xfont_create(Display *dpy, const char *name); 36 NK_API void nk_xfont_del(Display *dpy, XFont *font); 37 38 #endif 39 /* 40 * ============================================================== 41 * 42 * IMPLEMENTATION 43 * 44 * =============================================================== 45 */ 46 #ifdef NK_XLIB_IMPLEMENTATION 47 #include <X11/Xlib.h> 48 #include <X11/Xutil.h> 49 #include <X11/Xresource.h> 50 #include <X11/Xlocale.h> 51 #include <X11/Xatom.h> 52 53 #include <sys/time.h> 54 #include <unistd.h> 55 #include <time.h> 56 57 58 #ifdef NK_XLIB_IMPLEMENT_STB_IMAGE 59 #define STB_IMAGE_IMPLEMENTATION 60 #endif 61 62 #ifdef NK_XLIB_INCLUDE_STB_IMAGE 63 #include "../../example/stb_image.h" 64 #endif 65 66 67 #ifndef NK_X11_DOUBLE_CLICK_LO 68 #define NK_X11_DOUBLE_CLICK_LO 20 69 #endif 70 #ifndef NK_X11_DOUBLE_CLICK_HI 71 #define NK_X11_DOUBLE_CLICK_HI 200 72 #endif 73 74 typedef struct XSurface XSurface; 75 typedef struct XImageWithAlpha XImageWithAlpha; 76 struct XFont { 77 int ascent; 78 int descent; 79 int height; 80 XFontSet set; 81 XFontStruct *xfont; 82 struct nk_user_font handle; 83 }; 84 struct XSurface { 85 GC gc; 86 Display *dpy; 87 int screen; 88 Window root; 89 Drawable drawable; 90 unsigned int w, h; 91 }; 92 struct XImageWithAlpha { 93 XImage* ximage; 94 GC clipMaskGC; 95 Pixmap clipMask; 96 }; 97 static struct { 98 char *clipboard_data; 99 int clipboard_len; 100 struct nk_text_edit* clipboard_target; 101 102 Atom xa_clipboard; 103 Atom xa_targets; 104 Atom xa_text; 105 Atom xa_utf8_string; 106 107 struct nk_context ctx; 108 struct XSurface *surf; 109 Cursor cursor; 110 Display *dpy; 111 Window root; 112 long last_button_click; 113 } xlib; 114 115 NK_INTERN long 116 nk_timestamp(void) 117 { 118 struct timeval tv; 119 if (gettimeofday(&tv, NULL) < 0) return 0; 120 return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); 121 } 122 123 NK_INTERN unsigned long 124 nk_color_from_byte(const nk_byte *c) 125 { 126 unsigned long res = 0; 127 res |= (unsigned long)c[0] << 16; 128 res |= (unsigned long)c[1] << 8; 129 res |= (unsigned long)c[2] << 0; 130 return (res); 131 } 132 133 NK_INTERN XSurface* 134 nk_xsurf_create(int screen, unsigned int w, unsigned int h) 135 { 136 XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface)); 137 surface->w = w; 138 surface->h = h; 139 surface->dpy = xlib.dpy; 140 surface->screen = screen; 141 surface->root = xlib.root; 142 surface->gc = XCreateGC(xlib.dpy, xlib.root, 0, NULL); 143 XSetLineAttributes(xlib.dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter); 144 surface->drawable = XCreatePixmap(xlib.dpy, xlib.root, w, h, 145 (unsigned int)DefaultDepth(xlib.dpy, screen)); 146 return surface; 147 } 148 149 NK_INTERN void 150 nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h) 151 { 152 if(!surf) return; 153 if (surf->w == w && surf->h == h) return; 154 surf->w = w; surf->h = h; 155 if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable); 156 surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h, 157 (unsigned int)DefaultDepth(surf->dpy, surf->screen)); 158 } 159 160 NK_INTERN void 161 nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h) 162 { 163 XRectangle clip_rect; 164 clip_rect.x = (short)(x-1); 165 clip_rect.y = (short)(y-1); 166 clip_rect.width = (unsigned short)(w+2); 167 clip_rect.height = (unsigned short)(h+2); 168 XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted); 169 } 170 171 NK_INTERN void 172 nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1, 173 short y1, unsigned int line_thickness, struct nk_color col) 174 { 175 unsigned long c = nk_color_from_byte(&col.r); 176 XSetForeground(surf->dpy, surf->gc, c); 177 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 178 XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1); 179 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 180 } 181 182 NK_INTERN void 183 nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w, 184 unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col) 185 { 186 unsigned long c = nk_color_from_byte(&col.r); 187 XSetForeground(surf->dpy, surf->gc, c); 188 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 189 if (r == 0) {XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);return;} 190 191 {short xc = x + r; 192 short yc = y + r; 193 short wc = (short)(w - 2 * r); 194 short hc = (short)(h - 2 * r); 195 196 XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y); 197 XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc); 198 XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h); 199 XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc); 200 201 XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y, 202 (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64); 203 XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y, 204 (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64); 205 XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r, 206 (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64); 207 XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r, 208 (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);} 209 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 210 } 211 212 NK_INTERN void 213 nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w, 214 unsigned short h, unsigned short r, struct nk_color col) 215 { 216 unsigned long c = nk_color_from_byte(&col.r); 217 XSetForeground(surf->dpy, surf->gc, c); 218 if (r == 0) {XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); return;} 219 220 {short xc = x + r; 221 short yc = y + r; 222 short wc = (short)(w - 2 * r); 223 short hc = (short)(h - 2 * r); 224 225 XPoint pnts[12]; 226 pnts[0].x = x; 227 pnts[0].y = yc; 228 pnts[1].x = xc; 229 pnts[1].y = yc; 230 pnts[2].x = xc; 231 pnts[2].y = y; 232 233 pnts[3].x = xc + wc; 234 pnts[3].y = y; 235 pnts[4].x = xc + wc; 236 pnts[4].y = yc; 237 pnts[5].x = x + w; 238 pnts[5].y = yc; 239 240 pnts[6].x = x + w; 241 pnts[6].y = yc + hc; 242 pnts[7].x = xc + wc; 243 pnts[7].y = yc + hc; 244 pnts[8].x = xc + wc; 245 pnts[8].y = y + h; 246 247 pnts[9].x = xc; 248 pnts[9].y = y + h; 249 pnts[10].x = xc; 250 pnts[10].y = yc + hc; 251 pnts[11].x = x; 252 pnts[11].y = yc + hc; 253 254 XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin); 255 XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y, 256 (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64); 257 XFillArc(surf->dpy, surf->drawable, surf->gc, x, y, 258 (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64); 259 XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r, 260 (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64); 261 XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r, 262 (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);} 263 } 264 265 NK_INTERN void 266 nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1, 267 short y1, short x2, short y2, struct nk_color col) 268 { 269 XPoint pnts[3]; 270 unsigned long c = nk_color_from_byte(&col.r); 271 pnts[0].x = (short)x0; 272 pnts[0].y = (short)y0; 273 pnts[1].x = (short)x1; 274 pnts[1].y = (short)y1; 275 pnts[2].x = (short)x2; 276 pnts[2].y = (short)y2; 277 XSetForeground(surf->dpy, surf->gc, c); 278 XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin); 279 } 280 281 NK_INTERN void 282 nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1, 283 short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col) 284 { 285 unsigned long c = nk_color_from_byte(&col.r); 286 XSetForeground(surf->dpy, surf->gc, c); 287 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 288 XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1); 289 XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2); 290 XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0); 291 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 292 } 293 294 NK_INTERN void 295 nk_xsurf_fill_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count, 296 struct nk_color col) 297 { 298 int i = 0; 299 #define MAX_POINTS 128 300 XPoint xpnts[MAX_POINTS]; 301 unsigned long c = nk_color_from_byte(&col.r); 302 XSetForeground(surf->dpy, surf->gc, c); 303 for (i = 0; i < count && i < MAX_POINTS; ++i) { 304 xpnts[i].x = pnts[i].x; 305 xpnts[i].y = pnts[i].y; 306 } 307 XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin); 308 #undef MAX_POINTS 309 } 310 311 NK_INTERN void 312 nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count, 313 unsigned short line_thickness, struct nk_color col) 314 { 315 int i = 0; 316 unsigned long c = nk_color_from_byte(&col.r); 317 XSetForeground(surf->dpy, surf->gc, c); 318 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 319 for (i = 1; i < count; ++i) 320 XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); 321 XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y); 322 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 323 } 324 325 NK_INTERN void 326 nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts, 327 int count, unsigned short line_thickness, struct nk_color col) 328 { 329 int i = 0; 330 unsigned long c = nk_color_from_byte(&col.r); 331 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 332 XSetForeground(surf->dpy, surf->gc, c); 333 for (i = 0; i < count-1; ++i) 334 XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y); 335 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 336 } 337 338 NK_INTERN void 339 nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w, 340 unsigned short h, struct nk_color col) 341 { 342 unsigned long c = nk_color_from_byte(&col.r); 343 XSetForeground(surf->dpy, surf->gc, c); 344 XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, 345 (unsigned)w, (unsigned)h, 0, 360 * 64); 346 } 347 348 NK_INTERN void 349 nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w, 350 unsigned short h, unsigned short line_thickness, struct nk_color col) 351 { 352 unsigned long c = nk_color_from_byte(&col.r); 353 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 354 XSetForeground(surf->dpy, surf->gc, c); 355 XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, 356 (unsigned)w, (unsigned)h, 0, 360 * 64); 357 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 358 } 359 360 NK_INTERN void 361 nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1, 362 struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4, 363 unsigned int num_segments, unsigned short line_thickness, struct nk_color col) 364 { 365 unsigned int i_step; 366 float t_step; 367 struct nk_vec2i last = p1; 368 369 XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter); 370 num_segments = NK_MAX(num_segments, 1); 371 t_step = 1.0f/(float)num_segments; 372 for (i_step = 1; i_step <= num_segments; ++i_step) { 373 float t = t_step * (float)i_step; 374 float u = 1.0f - t; 375 float w1 = u*u*u; 376 float w2 = 3*u*u*t; 377 float w3 = 3*u*t*t; 378 float w4 = t * t *t; 379 float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; 380 float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; 381 nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col); 382 last.x = (short)x; last.y = (short)y; 383 } 384 XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter); 385 } 386 387 NK_INTERN void 388 nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h, 389 const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg) 390 { 391 int tx, ty; 392 unsigned long bg = nk_color_from_byte(&cbg.r); 393 unsigned long fg = nk_color_from_byte(&cfg.r); 394 395 XSetForeground(surf->dpy, surf->gc, bg); 396 XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h); 397 if(!text || !font || !len) return; 398 399 tx = (int)x; 400 ty = (int)y + font->ascent; 401 XSetForeground(surf->dpy, surf->gc, fg); 402 if(font->set) 403 XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len); 404 else XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len); 405 } 406 407 408 #ifdef NK_XLIB_INCLUDE_STB_IMAGE 409 NK_INTERN struct nk_image 410 nk_stbi_image_to_xsurf(unsigned char *data, int width, int height, int channels) { 411 XSurface *surf = xlib.surf; 412 struct nk_image img; 413 int bpl = channels; 414 long i, isize = width*height*channels; 415 XImageWithAlpha *aimage = (XImageWithAlpha*)calloc( 1, sizeof(XImageWithAlpha) ); 416 int depth = DefaultDepth(surf->dpy, surf->screen); 417 if (data == NULL) return nk_image_id(0); 418 if (aimage == NULL) return nk_image_id(0); 419 420 switch (depth){ 421 case 24: 422 bpl = 4; 423 break; 424 case 16: 425 case 15: 426 bpl = 2; 427 break; 428 default: 429 bpl = 1; 430 break; 431 } 432 433 /* rgba to bgra */ 434 if (channels >= 3){ 435 for (i=0; i < isize; i += channels) { 436 unsigned char red = data[i+2]; 437 unsigned char blue = data[i]; 438 data[i] = red; 439 data[i+2] = blue; 440 } 441 } 442 443 if (channels == 4){ 444 const unsigned alpha_treshold = 127; 445 aimage->clipMask = XCreatePixmap(surf->dpy, surf->drawable, width, height, 1); 446 447 if( aimage->clipMask ){ 448 aimage->clipMaskGC = XCreateGC(surf->dpy, aimage->clipMask, 0, 0); 449 XSetForeground(surf->dpy, aimage->clipMaskGC, BlackPixel(surf->dpy, surf->screen)); 450 XFillRectangle(surf->dpy, aimage->clipMask, aimage->clipMaskGC, 0, 0, width, height); 451 452 XSetForeground(surf->dpy, aimage->clipMaskGC, WhitePixel(surf->dpy, surf->screen)); 453 for (i=0; i < isize; i += channels){ 454 unsigned char alpha = data[i+3]; 455 int div = i / channels; 456 int x = div % width; 457 int y = div / width; 458 if( alpha > alpha_treshold ) 459 XDrawPoint(surf->dpy, aimage->clipMask, aimage->clipMaskGC, x, y); 460 } 461 } 462 } 463 464 aimage->ximage = XCreateImage(surf->dpy, 465 CopyFromParent, depth, 466 ZPixmap, 0, 467 (char*)data, 468 width, height, 469 bpl*8, bpl * width); 470 img = nk_image_ptr( (void*)aimage); 471 img.h = height; 472 img.w = width; 473 return img; 474 } 475 476 NK_API struct nk_image 477 nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize) 478 { 479 int x,y,n; 480 unsigned char *data; 481 data = stbi_load_from_memory(membuf, membufSize, &x, &y, &n, 0); 482 return nk_stbi_image_to_xsurf(data, x, y, n); 483 } 484 485 NK_API struct nk_image 486 nk_xsurf_load_image_from_file(char const *filename) 487 { 488 int x,y,n; 489 unsigned char *data; 490 data = stbi_load(filename, &x, &y, &n, 0); 491 return nk_stbi_image_to_xsurf(data, x, y, n); 492 } 493 #endif /* NK_XLIB_INCLUDE_STB_IMAGE */ 494 495 NK_INTERN void 496 nk_xsurf_draw_image(XSurface *surf, short x, short y, unsigned short w, unsigned short h, 497 struct nk_image img, struct nk_color col) 498 { 499 XImageWithAlpha *aimage = img.handle.ptr; 500 if (aimage){ 501 if (aimage->clipMask){ 502 XSetClipMask(surf->dpy, surf->gc, aimage->clipMask); 503 XSetClipOrigin(surf->dpy, surf->gc, x, y); 504 } 505 XPutImage(surf->dpy, surf->drawable, surf->gc, aimage->ximage, 0, 0, x, y, w, h); 506 XSetClipMask(surf->dpy, surf->gc, None); 507 } 508 } 509 510 void 511 nk_xsurf_image_free(struct nk_image* image) 512 { 513 XSurface *surf = xlib.surf; 514 XImageWithAlpha *aimage = image->handle.ptr; 515 if (!aimage) return; 516 XDestroyImage(aimage->ximage); 517 XFreePixmap(surf->dpy, aimage->clipMask); 518 XFreeGC(surf->dpy, aimage->clipMaskGC); 519 free(aimage); 520 } 521 522 523 NK_INTERN void 524 nk_xsurf_clear(XSurface *surf, unsigned long color) 525 { 526 XSetForeground(surf->dpy, surf->gc, color); 527 XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h); 528 } 529 530 NK_INTERN void 531 nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h) 532 { 533 XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0); 534 } 535 536 NK_INTERN void 537 nk_xsurf_del(XSurface *surf) 538 { 539 XFreePixmap(surf->dpy, surf->drawable); 540 XFreeGC(surf->dpy, surf->gc); 541 free(surf); 542 } 543 544 NK_API XFont* 545 nk_xfont_create(Display *dpy, const char *name) 546 { 547 int n; 548 char *def, **missing; 549 XFont *font = (XFont*)calloc(1, sizeof(XFont)); 550 font->set = XCreateFontSet(dpy, name, &missing, &n, &def); 551 if(missing) { 552 while(n--) 553 fprintf(stderr, "missing fontset: %s\n", missing[n]); 554 XFreeStringList(missing); 555 } 556 if(font->set) { 557 XFontStruct **xfonts; 558 char **font_names; 559 XExtentsOfFontSet(font->set); 560 n = XFontsOfFontSet(font->set, &xfonts, &font_names); 561 while(n--) { 562 font->ascent = NK_MAX(font->ascent, (*xfonts)->ascent); 563 font->descent = NK_MAX(font->descent,(*xfonts)->descent); 564 xfonts++; 565 } 566 } else { 567 if(!(font->xfont = XLoadQueryFont(dpy, name)) 568 && !(font->xfont = XLoadQueryFont(dpy, "fixed"))) { 569 free(font); 570 return 0; 571 } 572 font->ascent = font->xfont->ascent; 573 font->descent = font->xfont->descent; 574 } 575 font->height = font->ascent + font->descent; 576 return font; 577 } 578 579 NK_INTERN float 580 nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len) 581 { 582 XFont *font = (XFont*)handle.ptr; 583 XRectangle r; 584 if(!font || !text) 585 return 0; 586 587 if(font->set) { 588 XmbTextExtents(font->set, (const char*)text, len, NULL, &r); 589 return (float)r.width; 590 } else{ 591 int w = XTextWidth(font->xfont, (const char*)text, len); 592 return (float)w; 593 } 594 } 595 596 NK_API void 597 nk_xfont_del(Display *dpy, XFont *font) 598 { 599 if(!font) return; 600 if(font->set) 601 XFreeFontSet(dpy, font->set); 602 else 603 XFreeFont(dpy, font->xfont); 604 free(font); 605 } 606 607 NK_API struct nk_context* 608 nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root, 609 unsigned int w, unsigned int h) 610 { 611 struct nk_user_font *font = &xfont->handle; 612 font->userdata = nk_handle_ptr(xfont); 613 font->height = (float)xfont->height; 614 font->width = nk_xfont_get_text_width; 615 xlib.dpy = dpy; 616 xlib.root = root; 617 618 if (!setlocale(LC_ALL,"")) return 0; 619 if (!XSupportsLocale()) return 0; 620 if (!XSetLocaleModifiers("@im=none")) return 0; 621 622 xlib.xa_clipboard = XInternAtom(dpy, "CLIPBOARD", False); 623 xlib.xa_targets = XInternAtom(dpy, "TARGETS", False); 624 xlib.xa_text = XInternAtom(dpy, "TEXT", False); 625 xlib.xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False); 626 627 /* create invisible cursor */ 628 {static XColor dummy; char data[1] = {0}; 629 Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1); 630 if (blank == None) return 0; 631 xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0); 632 XFreePixmap(dpy, blank);} 633 634 xlib.surf = nk_xsurf_create(screen, w, h); 635 nk_init_default(&xlib.ctx, font); 636 return &xlib.ctx; 637 } 638 639 NK_API void 640 nk_xlib_set_font(XFont *xfont) 641 { 642 struct nk_user_font *font = &xfont->handle; 643 font->userdata = nk_handle_ptr(xfont); 644 font->height = (float)xfont->height; 645 font->width = nk_xfont_get_text_width; 646 nk_style_set_font(&xlib.ctx, font); 647 } 648 649 NK_API void 650 nk_xlib_push_font(XFont *xfont) 651 { 652 struct nk_user_font *font = &xfont->handle; 653 font->userdata = nk_handle_ptr(xfont); 654 font->height = (float)xfont->height; 655 font->width = nk_xfont_get_text_width; 656 nk_style_push_font(&xlib.ctx, font); 657 } 658 659 NK_API void 660 nk_xlib_paste(nk_handle handle, struct nk_text_edit* edit) 661 { 662 NK_UNUSED(handle); 663 /* Paste in X is asynchronous, so can not use a temporary text edit */ 664 NK_ASSERT(edit != &xlib.ctx.text_edit && "Paste not supported for temporary editors"); 665 xlib.clipboard_target = edit; 666 /* Request the contents of the primary buffer */ 667 XConvertSelection(xlib.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xlib.root, CurrentTime); 668 } 669 670 NK_API void 671 nk_xlib_copy(nk_handle handle, const char* str, int len) 672 { 673 NK_UNUSED(handle); 674 free(xlib.clipboard_data); 675 xlib.clipboard_len = 0; 676 xlib.clipboard_data = malloc((size_t)len); 677 if (xlib.clipboard_data) { 678 memcpy(xlib.clipboard_data, str, (size_t)len); 679 xlib.clipboard_len = len; 680 XSetSelectionOwner(xlib.dpy, XA_PRIMARY, xlib.root, CurrentTime); 681 XSetSelectionOwner(xlib.dpy, xlib.xa_clipboard, xlib.root, CurrentTime); 682 } 683 } 684 685 NK_API int 686 nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt) 687 { 688 struct nk_context *ctx = &xlib.ctx; 689 690 /* optional grabbing behavior */ 691 if (ctx->input.mouse.grab) { 692 XDefineCursor(xlib.dpy, xlib.root, xlib.cursor); 693 ctx->input.mouse.grab = 0; 694 } else if (ctx->input.mouse.ungrab) { 695 XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0, 696 (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y); 697 XUndefineCursor(xlib.dpy, xlib.root); 698 ctx->input.mouse.ungrab = 0; 699 } 700 701 if (evt->type == KeyPress || evt->type == KeyRelease) 702 { 703 /* Key handler */ 704 int ret, down = (evt->type == KeyPress); 705 KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret); 706 if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down); 707 else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down); 708 else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down); 709 else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down); 710 else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down); 711 else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down); 712 else if (*code == XK_Up) nk_input_key(ctx, NK_KEY_UP, down); 713 else if (*code == XK_Down) nk_input_key(ctx, NK_KEY_DOWN, down); 714 else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down); 715 else if (*code == XK_Escape) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); 716 else if (*code == XK_Page_Up) nk_input_key(ctx, NK_KEY_SCROLL_UP, down); 717 else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); 718 else if (*code == XK_Home) { 719 nk_input_key(ctx, NK_KEY_TEXT_START, down); 720 nk_input_key(ctx, NK_KEY_SCROLL_START, down); 721 } else if (*code == XK_End) { 722 nk_input_key(ctx, NK_KEY_TEXT_END, down); 723 nk_input_key(ctx, NK_KEY_SCROLL_END, down); 724 } else { 725 if (*code == 'c' && (evt->xkey.state & ControlMask)) 726 nk_input_key(ctx, NK_KEY_COPY, down); 727 else if (*code == 'v' && (evt->xkey.state & ControlMask)) 728 nk_input_key(ctx, NK_KEY_PASTE, down); 729 else if (*code == 'x' && (evt->xkey.state & ControlMask)) 730 nk_input_key(ctx, NK_KEY_CUT, down); 731 else if (*code == 'z' && (evt->xkey.state & ControlMask)) 732 nk_input_key(ctx, NK_KEY_TEXT_UNDO, down); 733 else if (*code == 'r' && (evt->xkey.state & ControlMask)) 734 nk_input_key(ctx, NK_KEY_TEXT_REDO, down); 735 else if (*code == XK_Left && (evt->xkey.state & ControlMask)) 736 nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down); 737 else if (*code == XK_Right && (evt->xkey.state & ControlMask)) 738 nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down); 739 else if (*code == 'b' && (evt->xkey.state & ControlMask)) 740 nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down); 741 else if (*code == 'e' && (evt->xkey.state & ControlMask)) 742 nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down); 743 else { 744 if (*code == 'i') 745 nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down); 746 else if (*code == 'r') 747 nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down); 748 if (down) { 749 char buf[32]; 750 KeySym keysym = 0; 751 if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol) 752 nk_input_glyph(ctx, buf); 753 } 754 } 755 } 756 XFree(code); 757 return 1; 758 } else if (evt->type == ButtonPress || evt->type == ButtonRelease) { 759 /* Button handler */ 760 int down = (evt->type == ButtonPress); 761 const int x = evt->xbutton.x, y = evt->xbutton.y; 762 if (evt->xbutton.button == Button1) { 763 if (down) { /* Double-Click Button handler */ 764 long dt = nk_timestamp() - xlib.last_button_click; 765 if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI) 766 nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true); 767 xlib.last_button_click = nk_timestamp(); 768 } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false); 769 nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); 770 } else if (evt->xbutton.button == Button2) 771 nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); 772 else if (evt->xbutton.button == Button3) 773 nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); 774 else if (evt->xbutton.button == Button4) 775 nk_input_scroll(ctx, nk_vec2(0, 1.0f)); 776 else if (evt->xbutton.button == Button5) 777 nk_input_scroll(ctx, nk_vec2(0, -1.0f)); 778 else return 0; 779 return 1; 780 } else if (evt->type == MotionNotify) { 781 /* Mouse motion handler */ 782 const int x = evt->xmotion.x, y = evt->xmotion.y; 783 nk_input_motion(ctx, x, y); 784 if (ctx->input.mouse.grabbed) { 785 ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; 786 ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; 787 XWarpPointer(xlib.dpy, None, xlib.surf->root, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y); 788 } 789 return 1; 790 } else if (evt->type == Expose || evt->type == ConfigureNotify) { 791 /* Window resize handler */ 792 unsigned int width, height; 793 XWindowAttributes attr; 794 XGetWindowAttributes(dpy, win, &attr); 795 width = (unsigned int)attr.width; 796 height = (unsigned int)attr.height; 797 nk_xsurf_resize(xlib.surf, width, height); 798 return 1; 799 } else if (evt->type == KeymapNotify) { 800 XRefreshKeyboardMapping(&evt->xmapping); 801 return 1; 802 } else if (evt->type == SelectionClear) { 803 free(xlib.clipboard_data); 804 xlib.clipboard_data = NULL; 805 xlib.clipboard_len = 0; 806 return 1; 807 } else if (evt->type == SelectionRequest) { 808 XEvent reply; 809 reply.xselection.type = SelectionNotify; 810 reply.xselection.requestor = evt->xselectionrequest.requestor; 811 reply.xselection.selection = evt->xselectionrequest.selection; 812 reply.xselection.target = evt->xselectionrequest.target; 813 reply.xselection.property = None; /* Default refuse */ 814 reply.xselection.time = evt->xselectionrequest.time; 815 816 if (reply.xselection.target == xlib.xa_targets) { 817 Atom target_list[4]; 818 target_list[0] = xlib.xa_targets; 819 target_list[1] = xlib.xa_text; 820 target_list[2] = xlib.xa_utf8_string; 821 target_list[3] = XA_STRING; 822 823 reply.xselection.property = evt->xselectionrequest.property; 824 XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor, 825 reply.xselection.property, XA_ATOM, 32, PropModeReplace, 826 (unsigned char*)&target_list, 4); 827 } else if (xlib.clipboard_data && (reply.xselection.target == xlib.xa_text || 828 reply.xselection.target == xlib.xa_utf8_string || reply.xselection.target == XA_STRING)) { 829 reply.xselection.property = evt->xselectionrequest.property; 830 XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor, 831 reply.xselection.property, reply.xselection.target, 8, PropModeReplace, 832 (unsigned char*)xlib.clipboard_data, xlib.clipboard_len); 833 } 834 XSendEvent(evt->xselection.display, evt->xselectionrequest.requestor, True, 0, &reply); 835 XFlush(evt->xselection.display); 836 return 1; 837 } else if (evt->type == SelectionNotify && xlib.clipboard_target) { 838 if ((evt->xselection.target != XA_STRING) && 839 (evt->xselection.target != xlib.xa_utf8_string) && 840 (evt->xselection.target != xlib.xa_text)) 841 return 1; 842 843 {Atom actual_type; 844 int actual_format; 845 unsigned long pos = 0, len, remain; 846 unsigned char* data = 0; 847 do { 848 XGetWindowProperty(dpy, win, XA_PRIMARY, (int)pos, 1024, False, 849 AnyPropertyType, &actual_type, &actual_format, &len, &remain, &data); 850 if (len && data) 851 nk_textedit_text(xlib.clipboard_target, (char*)data, (int)len); 852 if (data != 0) XFree(data); 853 pos += (len * (unsigned long)actual_format) / 32; 854 } while (remain != 0);} 855 return 1; 856 } 857 return 0; 858 } 859 860 NK_API void 861 nk_xlib_shutdown(void) 862 { 863 nk_xsurf_del(xlib.surf); 864 nk_free(&xlib.ctx); 865 XFreeCursor(xlib.dpy, xlib.cursor); 866 nk_memset(&xlib, 0, sizeof(xlib)); 867 } 868 869 NK_API void 870 nk_xlib_render(Drawable screen, struct nk_color clear) 871 { 872 const struct nk_command *cmd; 873 struct nk_context *ctx = &xlib.ctx; 874 XSurface *surf = xlib.surf; 875 876 nk_xsurf_clear(xlib.surf, nk_color_from_byte(&clear.r)); 877 nk_foreach(cmd, &xlib.ctx) 878 { 879 switch (cmd->type) { 880 case NK_COMMAND_NOP: break; 881 case NK_COMMAND_SCISSOR: { 882 const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd; 883 nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h); 884 } break; 885 case NK_COMMAND_LINE: { 886 const struct nk_command_line *l = (const struct nk_command_line *)cmd; 887 nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x, 888 l->end.y, l->line_thickness, l->color); 889 } break; 890 case NK_COMMAND_RECT: { 891 const struct nk_command_rect *r = (const struct nk_command_rect *)cmd; 892 nk_xsurf_stroke_rect(surf, r->x, r->y, NK_MAX(r->w -r->line_thickness, 0), 893 NK_MAX(r->h - r->line_thickness, 0), (unsigned short)r->rounding, 894 r->line_thickness, r->color); 895 } break; 896 case NK_COMMAND_RECT_FILLED: { 897 const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd; 898 nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h, 899 (unsigned short)r->rounding, r->color); 900 } break; 901 case NK_COMMAND_CIRCLE: { 902 const struct nk_command_circle *c = (const struct nk_command_circle *)cmd; 903 nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color); 904 } break; 905 case NK_COMMAND_CIRCLE_FILLED: { 906 const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd; 907 nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color); 908 } break; 909 case NK_COMMAND_TRIANGLE: { 910 const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd; 911 nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y, 912 t->c.x, t->c.y, t->line_thickness, t->color); 913 } break; 914 case NK_COMMAND_TRIANGLE_FILLED: { 915 const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd; 916 nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y, 917 t->c.x, t->c.y, t->color); 918 } break; 919 case NK_COMMAND_POLYGON: { 920 const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd; 921 nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color); 922 } break; 923 case NK_COMMAND_POLYGON_FILLED: { 924 const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd; 925 nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color); 926 } break; 927 case NK_COMMAND_POLYLINE: { 928 const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd; 929 nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color); 930 } break; 931 case NK_COMMAND_TEXT: { 932 const struct nk_command_text *t = (const struct nk_command_text*)cmd; 933 nk_xsurf_draw_text(surf, t->x, t->y, t->w, t->h, 934 (const char*)t->string, t->length, 935 (XFont*)t->font->userdata.ptr, 936 t->background, t->foreground); 937 } break; 938 case NK_COMMAND_CURVE: { 939 const struct nk_command_curve *q = (const struct nk_command_curve *)cmd; 940 nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1], 941 q->end, 22, q->line_thickness, q->color); 942 } break; 943 case NK_COMMAND_IMAGE: { 944 const struct nk_command_image *i = (const struct nk_command_image *)cmd; 945 nk_xsurf_draw_image(surf, i->x, i->y, i->w, i->h, i->img, i->col); 946 } break; 947 case NK_COMMAND_RECT_MULTI_COLOR: 948 case NK_COMMAND_ARC: 949 case NK_COMMAND_ARC_FILLED: 950 case NK_COMMAND_CUSTOM: 951 default: break; 952 } 953 } 954 nk_clear(ctx); 955 nk_xsurf_blit(screen, surf, surf->w, surf->h); 956 } 957 #endif 958