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
nk_timestamp(void)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
nk_color_from_byte(const nk_byte * c)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*
nk_xsurf_create(int screen,unsigned int w,unsigned int h)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
nk_xsurf_resize(XSurface * surf,unsigned int w,unsigned int h)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
nk_xsurf_scissor(XSurface * surf,float x,float y,float w,float h)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
nk_xsurf_stroke_line(XSurface * surf,short x0,short y0,short x1,short y1,unsigned int line_thickness,struct nk_color col)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
nk_xsurf_stroke_rect(XSurface * surf,short x,short y,unsigned short w,unsigned short h,unsigned short r,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_fill_rect(XSurface * surf,short x,short y,unsigned short w,unsigned short h,unsigned short r,struct nk_color col)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
nk_xsurf_fill_triangle(XSurface * surf,short x0,short y0,short x1,short y1,short x2,short y2,struct nk_color col)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
nk_xsurf_stroke_triangle(XSurface * surf,short x0,short y0,short x1,short y1,short x2,short y2,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_fill_polygon(XSurface * surf,const struct nk_vec2i * pnts,int count,struct nk_color col)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
nk_xsurf_stroke_polygon(XSurface * surf,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_stroke_polyline(XSurface * surf,const struct nk_vec2i * pnts,int count,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_fill_circle(XSurface * surf,short x,short y,unsigned short w,unsigned short h,struct nk_color col)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
nk_xsurf_stroke_circle(XSurface * surf,short x,short y,unsigned short w,unsigned short h,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_stroke_curve(XSurface * surf,struct nk_vec2i p1,struct nk_vec2i p2,struct nk_vec2i p3,struct nk_vec2i p4,unsigned int num_segments,unsigned short line_thickness,struct nk_color col)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
nk_xsurf_draw_text(XSurface * surf,short x,short y,unsigned short w,unsigned short h,const char * text,int len,XFont * font,struct nk_color cbg,struct nk_color cfg)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
nk_stbi_image_to_xsurf(unsigned char * data,int width,int height,int channels)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
nk_xsurf_load_image_from_memory(const void * membuf,nk_uint membufSize)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
nk_xsurf_load_image_from_file(char const * filename)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
nk_xsurf_draw_image(XSurface * surf,short x,short y,unsigned short w,unsigned short h,struct nk_image img,struct nk_color col)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
nk_xsurf_image_free(struct nk_image * image)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
nk_xsurf_clear(XSurface * surf,unsigned long color)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
nk_xsurf_blit(Drawable target,XSurface * surf,unsigned int w,unsigned int h)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
nk_xsurf_del(XSurface * surf)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*
nk_xfont_create(Display * dpy,const char * name)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
nk_xfont_get_text_width(nk_handle handle,float height,const char * text,int len)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
nk_xfont_del(Display * dpy,XFont * font)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*
nk_xlib_init(XFont * xfont,Display * dpy,int screen,Window root,unsigned int w,unsigned int h)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
nk_xlib_set_font(XFont * xfont)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
nk_xlib_push_font(XFont * xfont)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
nk_xlib_paste(nk_handle handle,struct nk_text_edit * edit)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
nk_xlib_copy(nk_handle handle,const char * str,int len)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
nk_xlib_handle_event(Display * dpy,int screen,Window win,XEvent * evt)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
nk_xlib_shutdown(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
nk_xlib_render(Drawable screen,struct nk_color clear)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