2 * Copyright Neil Brown ©2021 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * X11 display driver for edlib, using xcb, cairopango, libxkbcommon etc.
7 * A different connection to the server will be created for each
8 * display. Maybe that can be optimised one day.
16 #include <xcb/xcbext.h>
21 #include <cairo-xcb.h>
24 #include <pango/pango.h>
25 #include <pango/pangocairo.h>
27 typedef struct PangoFontDescription {} PangoFontDescription;
28 typedef struct PangoLayout {} PangoLayout;
29 typedef struct PangoContext {} PangoContext;
30 typedef struct PangoFontMetrics {} PangoFontMetrics;
31 typedef struct PangoRectangle { int x,y,width,height;} PangoRectangle;
32 typedef enum { PANGO_STYLE_NORMAL, PANGO_STYLE_OBLIQUE, PANGO_STYLE_ITALIC
34 typedef enum { PANGO_VARIANT_NORMAL, PANGO_VARIANT_SMALL_CAPS } PangoVariant;
35 typedef enum { PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_BOLD } PangoWeight;
36 PangoFontDescription *pango_font_description_new(void);
37 void pango_font_description_set_family_static(PangoFontDescription*, char*);
38 void pango_font_description_set_family(PangoFontDescription*, char*);
39 void pango_font_description_set_size(PangoFontDescription*, int);
40 void pango_font_description_set_style(PangoFontDescription*, PangoStyle);
41 void pango_font_description_set_variant(PangoFontDescription*, PangoVariant);
42 void pango_font_description_set_weight(PangoFontDescription*, PangoWeight);
43 #define PANGO_SCALE (1024)
45 PangoLayout *pango_cairo_create_layout(cairo_t*);
46 void g_object_unref(PangoLayout*);
47 PangoContext *pango_cairo_create_context(cairo_t *);
48 void pango_cairo_show_layout(cairo_t *, PangoLayout *);
49 PangoFontMetrics *pango_context_get_metrics(PangoContext*, PangoFontDescription*, void*);
50 void pango_font_description_free(PangoFontDescription*);
51 int pango_font_metrics_get_approximate_char_width(PangoFontMetrics *);
52 int pango_font_metrics_get_ascent(PangoFontMetrics *);
53 int pango_font_metrics_get_descent(PangoFontMetrics *);
54 void pango_font_metrics_unref(PangoFontMetrics *);
55 PangoContext* pango_layout_get_context(PangoLayout *);
56 int pango_layout_get_baseline(PangoLayout *);
57 void pango_layout_get_extents(PangoLayout *, PangoRectangle *, PangoRectangle *);
58 void pango_layout_get_pixel_extents(PangoLayout *, PangoRectangle *, PangoRectangle *);
59 void pango_layout_set_font_description(PangoLayout *, PangoFontDescription *);
60 void pango_layout_set_text(PangoLayout*, const char *, int);
61 void pango_layout_xy_to_index(PangoLayout*, int, int, int*, int*);
62 void pango_layout_index_to_pos(PangoLayout*, int, PangoRectangle*);
65 //#include <xkbcommon/xkbcommon.h>
66 //#include <xkbcommon/xkbcommon-x11.h>
73 a_WM_STATE, a_STATE_ADD, a_STATE_REMOVE, a_STATE_FULLSCREEN,
76 static char *atom_names[NR_ATOMS] = {
77 [a_WM_STATE] = "_NET_WM_STATE",
78 [a_STATE_ADD] = "_NET_WM_STATE_ADD",
79 [a_STATE_REMOVE] = "_NET_WM_STATE_REMOVE",
80 [a_STATE_FULLSCREEN] = "_NET_WM_STATE_FULLSCREEN",
84 xcb_connection_t *conn safe;
87 const xcb_setup_t *setup safe;
88 const xcb_screen_t *screen safe;
89 xcb_atom_t atoms[NR_ATOMS];
93 xcb_visualtype_t *visual;
95 cairo_surface_t *surface safe;
96 PangoFontDescription *fd safe;
98 int charwidth, lineheight;
104 struct xkb_context *xkb;
105 int32_t xkb_device_id;
106 struct xkb_state *xkb_state;
109 /* FIXME use hash?? */
116 cairo_surface_t *surface safe;
120 static struct map *xcb_map;
121 DEF_LOOKUP_CMD(xcb_handle, xcb_map);
123 static cairo_t *get_pixmap(struct pane *home safe,
126 struct xcb_data *xd = home->data;
127 struct panes **pp, *ps;
128 cairo_surface_t *surface;
131 for (pp = &xd->panes; (ps = *pp) != NULL; pp = &(*pp)->next) {
134 if (ps->w == p->w && ps->h == p->h)
137 cairo_destroy(ps->ctx);
138 cairo_surface_destroy(ps->surface);
139 xcb_free_pixmap(xd->conn, ps->draw);
147 ps->draw = xcb_generate_id(xd->conn);
148 xcb_create_pixmap(xd->conn, xd->screen->root_depth, ps->draw,
149 xd->win, p->w, p->h);
150 surface = cairo_xcb_surface_create(
151 xd->conn, ps->draw, xd->visual, p->w, p->h);
154 ctx = cairo_create(surface);
158 ps->surface = surface;
160 pane_add_notify(home, p, "Notify:Close");
165 cairo_surface_destroy(surface);
167 xcb_free_pixmap(xd->conn, ps->draw);
172 static struct panes *find_pixmap(struct xcb_data *xd safe, struct pane *p safe,
173 int *xp safe, int *yp safe)
176 struct panes *ret = NULL;
178 while (!ret && p->parent != p) {
180 for (ps = xd->panes; ps ; ps = ps->next)
200 static inline double cvt(int i)
202 return (float)i / 1000.0;
205 static void parse_attrs(
206 struct pane *home safe, const char *cattrs, int scale,
207 struct rgb *fgp, struct rgb *bgp, bool *underline,
208 PangoFontDescription **fdp)
210 char *attrs = strdup(cattrs ?: "");
213 char *fg = NULL, *bg = NULL;
217 PangoFontDescription *fd = NULL;
218 PangoStyle style = PANGO_STYLE_NORMAL;
219 PangoVariant variant = PANGO_VARIANT_NORMAL;
220 PangoWeight weight = PANGO_WEIGHT_NORMAL;
223 fd = pango_font_description_new();
225 pango_font_description_set_family_static(fd, "mono");
228 while ((word = strsep(&ap, ",")) != NULL) {
229 if (fd && strncmp(word, "family:", 7) == 0)
230 pango_font_description_set_family(fd, word+7);
231 if (strcmp(word, "large") == 0)
233 if (strcmp(word, "small") == 0)
235 if (isdigit(word[0])) {
237 double s = strtod(word, &end);
238 if (end && end != word && !*end)
239 size = trunc(s * 1000.0);
243 if (strcmp(word, "oblique") == 0)
244 style = PANGO_STYLE_OBLIQUE;
245 if (strcmp(word, "italic") == 0)
246 style = PANGO_STYLE_ITALIC;
247 if (strcmp(word, "normal") == 0)
248 style = PANGO_STYLE_NORMAL;
249 if (strcmp(word, "small-caps") == 0)
250 variant = PANGO_VARIANT_SMALL_CAPS;
252 if (strcmp(word, "bold") == 0)
253 weight = PANGO_WEIGHT_BOLD;
254 if (strcmp(word, "nobold") == 0)
255 weight = PANGO_WEIGHT_NORMAL;
257 if (strncmp(word, "fg:", 3) == 0)
259 if (strncmp(word, "bg:", 3) == 0)
261 if (strcmp(word, "inverse") == 0)
263 if (strcmp(word, "underline") == 0)
279 struct call_return ret = call_ret(all, "colour:map", home,
282 fgp->g = cvt(ret.i2);
287 struct call_return ret = call_ret(all, "colour:map", home,
290 bgp->g = cvt(ret.i2);
295 pango_font_description_set_size(fd, size * scale / PANGO_SCALE);
296 if (style != PANGO_STYLE_NORMAL)
297 pango_font_description_set_style(fd, style);
298 if (variant != PANGO_VARIANT_NORMAL)
299 pango_font_description_set_variant(fd, variant);
300 if (weight != PANGO_WEIGHT_NORMAL)
301 pango_font_description_set_weight(fd, weight);
310 struct call_return *cr = container_of(ci->comm, struct call_return, c);
316 DEF_CMD(xcb_close_display)
318 /* If this is only display, then refuse to close this one */
319 struct call_return cr;
320 struct xcb_data *xd = ci->home->data;
322 call("Message", ci->focus, 0, NULL, xd->noclose);
327 call_comm("editor:notify:all-displays", ci->focus, &cr.c);
329 pane_close(ci->home);
331 call("Message", ci->focus, 0, NULL,
332 "Cannot close only window.");
336 DEF_CMD(xcb_set_noclose)
338 struct xcb_data *xd = ci->home->data;
343 xd->noclose = strdup(ci->str);
347 DEF_CMD(xcb_external_viewer)
349 //struct xcb_data *xd = ci->home->data;
354 DEF_CMD(xcb_fullscreen)
356 struct xcb_data *xd = ci->home->data;
357 xcb_client_message_event_t msg = {};
359 msg.response_type = XCB_CLIENT_MESSAGE;
361 msg.window = xd->win;
362 msg.type = xd->atoms[a_WM_STATE];
364 msg.data.data32[0] = xd->atoms[a_STATE_ADD];
366 msg.data.data32[0] = xd->atoms[a_STATE_REMOVE];
367 msg.data.data32[1] = xd->atoms[a_STATE_FULLSCREEN];
368 msg.data.data32[2] = 0;
369 msg.data.data32[3] = 1; /* source indicator */
371 xcb_send_event(xd->conn, 0, xd->screen->root,
372 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
373 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
374 (void*)msg.data.data8);
381 struct xcb_data *xd = ci->home->data;
382 xcb_destroy_window(xd->conn, xd->win);
383 xcb_disconnect(xd->conn);
390 struct xcb_data *xd = ci->home->data;
391 const char *attr = ci->str;
392 struct panes *src = NULL;
398 parse_attrs(ci->home, attr, PANGO_SCALE, NULL, &bg, NULL, NULL);
400 src = find_pixmap(xd, ci->focus->parent, &x, &y);
401 bg.r = bg.g = bg.b = 1.0;
404 pm = get_pixmap(ci->home, ci->focus);
408 cairo_set_source_surface(pm, src->surface, -x - ci->focus->x,
412 cairo_set_source_rgb(pm, bg.r, bg.g, bg.b);
413 cairo_rectangle(pm, 0.0, 0.0,
414 (double)ci->focus->w, (double)ci->focus->h);
417 pane_damaged(ci->home, DAMAGED_POSTORDER);
421 DEF_CMD(xcb_text_size)
423 struct xcb_data *xd = ci->home->data;
424 const char *attr = ci->str2 ?: "";
425 const char *str = ci->str ?: "";
426 int scale = ci->num2;
428 PangoFontDescription *fd;
435 parse_attrs(ci->home, attr, scale, NULL, NULL, NULL, &fd);
436 /* If we use an empty string, line-height it wrong */
437 layout = pango_cairo_create_layout(xd->cairo);
438 pango_layout_set_text(layout, *str ? str : "M", -1);
439 pango_layout_set_font_description(layout, fd);
440 pango_layout_get_pixel_extents(layout, NULL, &log);
441 baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
445 else if (log.width <= ci->num)
446 max_bytes = strlen(str);
448 pango_layout_xy_to_index(layout, 1000*ci->num,
449 baseline, &max_bytes, NULL);
451 comm_call(ci->comm2, "cb", ci->focus, max_bytes, NULL, NULL,
452 baseline, NULL, NULL,
453 str && *str ? log.width : 0,
456 pango_font_description_free(fd);
457 g_object_unref(layout);
461 DEF_CMD(xcb_draw_text)
463 struct xcb_data *xd = ci->home->data;
464 const char *str = ci->str;
465 const char *attr = ci->str2;
470 PangoFontDescription *fd;
480 ps = find_pixmap(xd, ci->focus, &xo, &yo);
485 pane_damaged(ci->home, DAMAGED_POSTORDER);
488 scale = ci->num2 * 10 / xd->charwidth;
490 parse_attrs(ci->home, attr, scale, &fg, &bg, &ul, &fd);
494 layout = pango_cairo_create_layout(ctx);
495 pango_layout_set_text(layout, str, -1);
496 pango_layout_set_font_description(layout, fd);
497 pango_layout_get_pixel_extents(layout, NULL, &log);
498 baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
500 cairo_set_source_rgb(ctx, bg.r, bg.g, bg.b);
501 cairo_rectangle(ctx, x+log.x, y - baseline + log.y,
502 log.width, log.height);
505 cairo_set_source_rgb(ctx, fg.r, fg.g, fg.b);
507 /* Draw an underline */
508 cairo_rectangle(ctx, x+log.x, y+2+log.y,
513 cairo_move_to(ctx, x, y - baseline);
514 pango_cairo_show_layout(ctx, layout);
518 /* draw a cursor - outline box if not in-focus,
519 * inverse-video if it is.
522 bool in_focus = xd->in_focus;
523 struct pane *f = ci->focus;
525 pango_layout_index_to_pos(layout, ci->num, &curs);
526 if (curs.width <= 0) {
528 pango_layout_set_text(layout, "M", 1);
529 pango_layout_get_extents(layout, NULL, &log);
530 curs.width = log.width;
532 cairo_rectangle(ctx, x+curs.x/PANGO_SCALE, y-baseline+curs.y/PANGO_SCALE,
533 (curs.width - PANGO_SCALE/2) / PANGO_SCALE,
534 (curs.height - PANGO_SCALE/2) / PANGO_SCALE);
535 cairo_set_line_width(ctx, 1.0);
538 while (in_focus && f->parent->parent != f &&
539 f->parent != ci->home) {
540 if (f->parent->focus != f && f->z >= 0)
546 cairo_set_source_rgb(ctx, fg.r, fg.g, fg.b);
547 cairo_rectangle(ctx, x+curs.x/PANGO_SCALE,
548 y-baseline+curs.y/PANGO_SCALE,
549 curs.width / PANGO_SCALE,
550 curs.height / PANGO_SCALE);
552 if (ci->num < (int)strlen(str)) {
553 const char *cp = str + ci->num;
555 pango_layout_set_text(layout, str + ci->num,
556 cp - (str + ci->num));
558 cairo_set_source_rgb(ctx, bg.r, bg.g, bg.b);
560 cairo_set_source_rgb(ctx, 1.0, 1.0, 1.0);
562 x + curs.x / PANGO_SCALE,
563 y - baseline + curs.y / PANGO_SCALE);
564 pango_cairo_show_layout(ctx, layout);
568 pango_font_description_free(fd);
569 g_object_unref(layout);
573 DEF_CMD(xcb_draw_image)
575 //struct xcb_data *xd = ci->home->data;
580 static struct panes *sort_split(struct panes *p)
582 /* consider 'p' to be a list of panes with
583 * ordered subsets (ordered by p->abs_z).
584 * Remove every other such subset and return them
586 * If p is ordered, this means we return NULL.
588 struct panes *ret, **end = &ret;
591 for (; p && p->next; p = next) {
592 /* If these are not ordered, attach p->next at
593 * 'end', and make 'end' point to &p->next.
596 if (p->p->abs_z <= next->p->abs_z)
605 static struct panes *sort_merge(struct panes *p1, struct panes *p2)
607 /* merge p1 and p2 and return result */
608 struct panes *ret, **end = &ret;
612 /* if both arg large or smaller than lastz, choose
613 * least, else choose largest
615 struct panes *lo, *hi, *choice;
616 if (p1->p->abs_z <= p2->p->abs_z) {
621 if (lo->p->abs_z >= lastz || hi->p->abs_z <= lastz)
639 DEF_CMD(xcb_refresh_post)
641 struct xcb_data *xd = ci->home->data;
644 time_start(TIME_WINDOW);
645 /* First: ensure panes are sorted */
646 while ((ps = sort_split(xd->panes)) != NULL)
647 xd->panes = sort_merge(xd->panes, ps);
649 /* Now copy all panes onto the window */
650 for (ps = xd->panes; ps; ps = ps->next) {
651 double lox, hix, loy, hiy;
652 struct xy rel, lo, hi;
654 rel = pane_mapxy(ps->p, ci->home, 0, 0, False);
655 lo = pane_mapxy(ps->p, ci->home, 0, 0, True);
656 hi = pane_mapxy(ps->p, ci->home, ps->p->w, ps->p->h, True);
657 lox = lo.x; loy = lo.y;
658 hix = hi.x; hiy = hi.y;
659 cairo_save(xd->cairo);
660 cairo_set_source_surface(xd->cairo, ps->surface,
662 cairo_rectangle(xd->cairo, lox, loy, hix, hiy);
663 cairo_fill(xd->cairo);
664 cairo_restore(xd->cairo);
666 time_stop(TIME_WINDOW);
671 DEF_CMD(xcb_pane_close)
673 struct xcb_data *xd = ci->home->data;
674 struct panes **pp, *ps;
676 for (pp = &xd->panes; (ps = *pp) != NULL; pp = &(*pp)->next) {
677 if (ps->p != ci->focus)
681 cairo_destroy(ps->ctx);
682 cairo_surface_destroy(ps->surface);
683 xcb_free_pixmap(xd->conn, ps->draw);
685 pane_damaged(ci->home, DAMAGED_POSTORDER);
691 DEF_CMD(xcb_notify_display)
693 struct xcb_data *xd = ci->home->data;
694 comm_call(ci->comm2, "callback:display", ci->home, xd->last_event);
698 static void handle_button(struct pane *home safe,
699 xcb_button_press_event_t *be safe)
701 struct xcb_data *xd = home->data;
702 bool press = (be->response_type & 0x7f) == XCB_BUTTON_PRESS;
704 char key[2+2+2+9+1+1];
708 xd->motion_blocked = False;
709 if (be->state & XCB_KEY_BUT_MASK_MOD_1)
711 if (be->state & XCB_KEY_BUT_MASK_CONTROL)
713 if (be->state & XCB_KEY_BUT_MASK_SHIFT)
716 strcat(key, ":Press-X");
718 strcpy(key, ":Release-X");
719 key[strlen(key) - 1] = '0' + be->detail;
720 xd->last_event = time(NULL);
721 call("Mouse-event", home, be->detail, NULL, key,
722 press?1:2, NULL, mod,
723 be->event_x, be->event_y);
726 static void handle_motion(struct pane *home safe,
727 xcb_motion_notify_event_t *mne safe)
729 struct xcb_data *xd = home->data;
730 xcb_query_pointer_cookie_t c;
731 xcb_query_pointer_reply_t *qpr;
733 int x = mne->event_x, y = mne->event_y;
735 if (xd->motion_blocked)
737 ret = call("Mouse-event", home, 0, NULL, ":Motion",
738 3, NULL, NULL, x, y);
740 xd->motion_blocked = True;
741 c = xcb_query_pointer(xd->conn, xd->win);
742 qpr = xcb_query_pointer_reply(xd->conn, c, NULL);
746 static void handle_focus(struct pane *home safe, xcb_focus_in_event_t *fie safe)
748 struct xcb_data *xd = home->data;
749 bool in = (fie->response_type & 0x7f) == XCB_FOCUS_IN;
755 pt = call_ret(mark, "doc:point", p);
757 call("view:changed", p, 0, pt);
759 call("pane:refocus", home);
762 static void handle_key(struct pane *home safe, xcb_key_press_event_t *kpe safe)
764 //struct xcb_data *xd = home->data;
765 bool press = (kpe->response_type & 0x7f) == XCB_KEY_PRESS;
767 xcb_key_press_event_t *kpe;
770 xkb_state_update_key(xd->xkb_state, kpe->keycode,
772 keysym = xkb_state_key_get_one_sym(xd->xkb_state,
774 xkb_keysym_get_name(keysym, name, sizeof(name));
775 xkb_state_key_get_utf8(xd->xkb_state, kpe->keycode,
778 if (kpe->detail == 24)
779 call("event:deactivate", home);
780 else if (kpe->detail == 65 && press)
781 call("Keystroke", home, 0, NULL, "- ");
782 else LOG("key %d", kpe->detail);
786 //XLookupString(&xke, &buf, sizeof(buf), &keysym, NULL);
789 static void handle_configure(struct pane *home safe,
790 xcb_configure_notify_event_t *cne safe)
792 struct xcb_data *xd = home->data;
794 pane_resize(home, 0, 0, cne->width, cne->height);
795 cairo_xcb_surface_set_size(xd->surface, cne->width, cne->height);
800 struct xcb_data *xd = ci->home->data;
801 xcb_generic_event_t *ev;
803 while ((ev = xcb_poll_for_event(xd->conn)) != NULL) {
804 switch (ev->response_type & 0x7f) {
806 case XCB_KEY_RELEASE:
807 time_start(TIME_KEY);
808 handle_key(ci->home, safe_cast (void*)ev);
811 case XCB_BUTTON_PRESS:
812 case XCB_BUTTON_RELEASE:
813 time_start(TIME_KEY);
814 handle_button(ci->home, (void*)ev);
817 case XCB_MOTION_NOTIFY:
818 time_start(TIME_KEY);
819 handle_motion(ci->home, (void*)ev);
824 time_start(TIME_WINDOW);
825 handle_focus(ci->home, (void*)ev);
826 time_stop(TIME_WINDOW);
829 pane_damaged(ci->home, DAMAGED_POSTORDER);
831 case XCB_CONFIGURE_NOTIFY:
832 time_start(TIME_WINDOW);
833 handle_configure(ci->home, (void*)ev);
834 time_stop(TIME_WINDOW);
837 LOG("ignored %x", ev->response_type);
844 static struct pane *xcb_display_init(const char *d safe, struct pane *focus safe)
848 xcb_connection_t *conn;
849 xcb_intern_atom_cookie_t cookies[NR_ATOMS];
850 xcb_screen_iterator_t iter;
851 xcb_depth_iterator_t di;
859 cairo_surface_t *surface;
860 PangoFontDescription *fd;
861 // FIXME SCALE from environ?? or pango_cairo_context_set_resolution dpi
862 // 254 * width_in_pixels / width_in_millimeters / 10
864 conn = xcb_connect(d, &screen);
870 xd->motion_blocked = True;
874 xd->display = strdup(d);
875 xd->setup = safe_cast xcb_get_setup(conn);
876 iter = xcb_setup_roots_iterator(xd->setup);
877 for (i = 0; i < screen; i++)
878 xcb_screen_next(&iter);
879 xd->screen = safe_cast iter.data;
881 di = xcb_screen_allowed_depths_iterator(xd->screen);
882 while (di.data && di.data->depth < 24)
884 //?? look for class = TrueColor??
885 xd->visual = xcb_depth_visuals(di.data);
887 for (i = 0; i < NR_ATOMS; i++) {
888 char *n = atom_names[i];
891 cookies[i] = xcb_intern_atom(conn, 0, strlen(n), n);
894 xd->win = xcb_generate_id(conn);
895 valwin[0] = xd->screen->white_pixel;
896 valwin[1] = (XCB_EVENT_MASK_KEY_PRESS |
897 XCB_EVENT_MASK_KEY_RELEASE |
898 XCB_EVENT_MASK_BUTTON_PRESS |
899 XCB_EVENT_MASK_BUTTON_RELEASE |
900 // XCB_EVENT_MASK_ENTER_WINDOW |
901 // XCB_EVENT_MASK_LEAVE_WINDOW |
902 XCB_EVENT_MASK_FOCUS_CHANGE |
903 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
904 XCB_EVENT_MASK_EXPOSURE |
905 XCB_EVENT_MASK_POINTER_MOTION |
906 // FIXME XCB_EVENT_MASK_POINTER_MOTION_HINT |
909 xcb_create_window(conn, XCB_COPY_FROM_PARENT, xd->win,
913 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
914 xd->screen->root_visual,
915 XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
919 surface = cairo_xcb_surface_create(
920 conn, xd->win, xd->visual, 100, 100);
923 xd->surface = surface;
924 cairo = cairo_create(xd->surface);
928 fd = pango_font_description_new();
932 pango_font_description_set_family(xd->fd, "mono");
933 pango_font_description_set_size(xd->fd, 12 * PANGO_SCALE);
935 layout = pango_cairo_create_layout(xd->cairo);
936 pango_layout_set_font_description(layout, fd);
937 pango_layout_set_text(layout, "M", 1);
938 pango_layout_get_pixel_extents(layout, NULL, &log);
939 g_object_unref(layout);
940 xd->lineheight = log.height;
941 xd->charwidth = log.width;
943 valwin[0] = xd->charwidth * 80;
944 valwin[1] = xd->lineheight * 26;
945 xcb_configure_window(conn, xd->win,
946 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
948 cairo_xcb_surface_set_size(xd->surface, valwin[0], valwin[1]);
950 /* Now resolve all those cookies */
951 for (i = 0; i < NR_ATOMS; i++) {
952 xcb_intern_atom_reply_t *r;
953 r = xcb_intern_atom_reply(conn, cookies[i], NULL);
956 xd->atoms[i] = r->atom;
961 xd->xkb = safe_cast xkb_context_new(XCB_CONTEXT_NO_FLAGS);
962 xd->xkb_device_id = xkb_x11_get_core_keyboard_device_id(conn);
963 xd->xkb_state = xkb_x11_state_new_from_device(xd->xkb_keymap, conn,
968 * WM_PROTOCOLS WM_DELETE_WINDOW WM_TAKE_FOCUS _NET_WM_PING _NET_WM_SYN_REQUEST??
969 * WM_NORMAL_HINTS WM_HINTS
972 xcb_map_window(conn, xd->win);
974 p = pane_register(pane_root(focus), 1, &xcb_handle.c, xd);
977 pane_resize(p, 0, 0, xd->charwidth*80, xd->lineheight*26);
978 call_comm("event:read", p, &xcb_input, xcb_get_file_descriptor(conn));
979 attr_set_str(&p->attrs, "DISPLAY", d);
980 snprintf(scale, sizeof(scale), "%dx%d", xd->charwidth, xd->lineheight);
981 attr_set_str(&p->attrs, "scale:M", scale);
982 //attr_set_int(&p->attrs, "scale", 2000);
985 cairo_destroy(xd->cairo);
986 cairo_surface_destroy(xd->surface);
987 xcb_disconnect(conn);
996 const char *d = ci->str;
1000 p = xcb_display_init(d, ci->focus);
1002 return comm_call(ci->comm2, "cb", p);
1006 DEF_CMD(xcb_new_display)
1009 char *d = pane_attr_get(ci->focus, "DISPLAY");
1013 p = xcb_display_init(d, ci->focus);
1015 p = call_ret(pane, "editor:activate-display", p);
1017 home_call(ci->focus, "doc:attach-view", p, 1);
1021 void edlib_init(struct pane *ed safe)
1023 call_comm("global-set-command", ed, &display_xcb, 0, NULL,
1024 "attach-display-x11");
1025 call_comm("global-set-command", ed, &xcb_new_display, 0, NULL,
1026 "interactive-cmd-x11window");
1028 xcb_map = key_alloc();
1030 key_add(xcb_map, "Display:close", &xcb_close_display);
1031 key_add(xcb_map, "Display:set-noclose", &xcb_set_noclose);
1032 key_add(xcb_map, "Display:external-viewer", &xcb_external_viewer);
1033 key_add(xcb_map, "Display:fullscreen", &xcb_fullscreen);
1034 key_add(xcb_map, "Display:new", &xcb_new_display);
1036 key_add(xcb_map, "Close", &xcb_close);
1037 key_add(xcb_map, "Free", &edlib_do_free);
1038 key_add(xcb_map, "Draw:clear", &xcb_clear);
1039 key_add(xcb_map, "Draw:text-size", &xcb_text_size);
1040 key_add(xcb_map, "Draw:text", &xcb_draw_text);
1041 key_add(xcb_map, "Draw:image", &xcb_draw_image);
1042 key_add(xcb_map, "Refresh:postorder", &xcb_refresh_post);
1043 key_add(xcb_map, "all-displays", &xcb_notify_display);
1044 key_add(xcb_map, "Notify:Close", &xcb_pane_close);