switched to `XDrawImageString16()` -- this should solve all rendering problems, once...
[k8sterm.git] / src / x11init.c
blob6dfd618114ebdd656d84efcc61c8b5a7601a4c84
1 ////////////////////////////////////////////////////////////////////////////////
2 // x11 drawing and utils
3 /*
4 static void xcreatebw (void) {
5 if ((dc.bcol = calloc(MAX_COLOR+1, sizeof(dc.bcol[0]))) == NULL) k8t_die("out of memory");
6 //
7 for (int f = 0; f <= MAX_COLOR; ++f) {
8 XColor nclr;
9 //
10 nclr = dc.ncol[f].pixel;
11 XQueryColor(xw.dpy, xw.cmap, &nclr);
12 fprintf(stderr, "%d: r=%u; g=%u; b=%u\n", f, nclr.red, nclr.green, nclr.blue);
18 static void xallocbwclr (int idx, XColor *color) {
19 double lumi;
21 XQueryColor(xw.dpy, xw.cmap, color);
22 //fprintf(stderr, "%d: r=%u; g=%u; b=%u\n", idx, color->red, color->green, color->blue);
24 lumi = 0.3*((double)color->red/65535.0)+0.59*((double)color->green/65535.0)+0.11*((double)color->blue/65535.0);
25 color->red = color->green = color->blue = (int)(lumi*65535.0);
26 if (!XAllocColor(xw.dpy, xw.cmap, color)) {
27 fprintf(stderr, "WARNING: could not allocate b/w color #%d\n", idx);
28 return;
30 dc.bcol[idx] = color->pixel;
31 color->red = color->blue = 0;
32 if (!XAllocColor(xw.dpy, xw.cmap, color)) {
33 fprintf(stderr, "WARNING: could not allocate b/w color #%d\n", idx);
34 return;
36 dc.gcol[idx] = color->pixel;
40 static void xallocnamedclr (int idx, const char *cname) {
41 XColor color;
43 if (!XAllocNamedColor(xw.dpy, xw.cmap, cname, &color, &color)) {
44 fprintf(stderr, "WARNING: could not allocate color #%d: '%s'\n", idx, cname);
45 return;
47 dc.ncol[idx] = color.pixel;
48 xallocbwclr(idx, &color);
52 static void xloadcols (void) {
53 int f, r, g, b;
54 XColor color;
55 uint32_t white = WhitePixel(xw.dpy, xw.scr);
57 if ((dc.clrs[0] = dc.ncol = calloc(MAX_COLOR+1, sizeof(dc.ncol[0]))) == NULL) k8t_die("out of memory");
58 if ((dc.clrs[1] = dc.bcol = calloc(MAX_COLOR+1, sizeof(dc.bcol[0]))) == NULL) k8t_die("out of memory");
59 if ((dc.clrs[2] = dc.gcol = calloc(MAX_COLOR+1, sizeof(dc.gcol[0]))) == NULL) k8t_die("out of memory");
61 for (f = 0; f <= MAX_COLOR; ++f) dc.ncol[f] = dc.bcol[f] = white;
62 /* load colors [0-15] */
63 for (f = 0; f <= 15; ++f) {
64 const char *cname = opt_colornames[f]!=NULL?opt_colornames[f]:defcolornames[f];
66 xallocnamedclr(f, cname);
68 /* load colors [256-...] */
69 for (f = 256; f <= MAX_COLOR; ++f) {
70 const char *cname = opt_colornames[f];
72 if (cname == NULL) {
73 if (K8T_ARRLEN(defextcolornames) <= f-256) continue;
74 cname = defextcolornames[f-256];
76 if (cname == NULL) continue;
77 xallocnamedclr(f, cname);
79 /* load colors [16-255] ; same colors as xterm */
80 for (f = 16, r = 0; r < 6; ++r) {
81 for (g = 0; g < 6; ++g) {
82 for (b = 0; b < 6; ++b) {
83 if (opt_colornames[f] != NULL) {
84 xallocnamedclr(f, opt_colornames[f]);
85 } else {
86 color.red = r == 0 ? 0 : 0x3737+0x2828*r;
87 color.green = g == 0 ? 0 : 0x3737+0x2828*g;
88 color.blue = b == 0 ? 0 : 0x3737+0x2828*b;
89 if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
90 fprintf(stderr, "WARNING: could not allocate color #%d\n", f);
91 } else {
92 dc.ncol[f] = color.pixel;
93 xallocbwclr(f, &color);
96 ++f;
100 for (r = 0; r < 24; ++r, ++f) {
101 if (opt_colornames[f] != NULL) {
102 xallocnamedclr(f, opt_colornames[f]);
103 } else {
104 color.red = color.green = color.blue = 0x0808+0x0a0a*r;
105 if (!XAllocColor(xw.dpy, xw.cmap, &color)) {
106 fprintf(stderr, "WARNING: could not allocate color #%d\n", f);
107 } else {
108 dc.ncol[f] = color.pixel;
109 xallocbwclr(f, &color);
114 for (int f = 0; f < K8T_ARRLEN(opt_colornames); ++f) if (opt_colornames[f]) free(opt_colornames[f]);
118 static void xhints (void) {
119 XClassHint class = {opt_class, opt_title};
120 XWMHints wm = {.flags = InputHint, .input = 1};
121 XSizeHints size = {
122 .flags = PSize|PResizeInc|PBaseSize,
123 .height = xw.h,
124 .width = xw.w,
125 .height_inc = xw.ch,
126 .width_inc = xw.cw,
127 .base_height = xw.h/*xw.tabheight*/,
128 .base_width = xw.w,
130 //XSetWMNormalHints(xw.dpy, xw.win, &size);
131 XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, &size, &wm, &class);
132 XSetWMProtocols(xw.dpy, xw.win, &XA_WM_DELETE_WINDOW, 1);
136 #ifdef X11_USE_FUCKED_FONTSETS
137 static XFontSet xinitfont (const char *fontstr) {
138 XFontSet set;
139 char *def, **missing;
140 int n;
142 missing = NULL;
143 set = XCreateFontSet(xw.dpy, fontstr, &missing, &n, &def);
144 if (missing) {
145 while (n--) fprintf(stderr, "sterm: missing fontset: %s\n", missing[n]);
146 XFreeStringList(missing);
148 return set;
150 #else
151 static XFontStruct *xinitfont (const char *fontstr) {
152 XFontStruct *fst = NULL;
153 int fcount = 0;
154 char **flist = XListFonts(xw.dpy, (char *)fontstr, 32700/*maxnames*/, &fcount);
155 if (flist) {
156 //for (int f = 0; f < fcount; ++f) fprintf(stderr, "F#%d: <%s>\n", f, flist[f]);
157 for (int f = 0; f < fcount; ++f) {
158 if (strstr(flist[f], "-iso10646-1")) {
159 fst = XLoadQueryFont(xw.dpy, flist[f]);
160 if (fst) {
161 int dir, ascent, descent;
162 XCharStruct cs;
163 XQueryTextExtents(xw.dpy, fst->fid, "W", 1, &dir, &ascent, &descent, &cs);
164 if (ascent+descent > 0 && cs.rbearing-cs.lbearing > 0 && cs.width > 0) {
165 fprintf(stderr, "X11: loaded font '%s' (hgt=%d; wdt=%d)\n", flist[f], (int)(ascent+descent), (int)cs.width);
166 break;
167 } else {
168 fprintf(stderr, "X11: rejected font '%s'\n", flist[f]);
169 XFreeFont(xw.dpy, fst);
174 XFreeFontNames(flist);
176 if (!fst) {
177 fst = XLoadQueryFont(xw.dpy, (char *)fontstr);
179 return fst;
181 #endif
184 #ifdef X11_USE_FUCKED_FONTSETS
185 static void xgetfontinfo (XFontSet set, int *ascent, int *descent, int *width, Font *fid, int monocheck) {
186 XFontStruct **xfonts;
187 char **font_names;
188 int n;
190 *ascent = *descent = 0;
191 int lbearing = 0, rbearing = 0;
192 n = XFontsOfFontSet(set, &xfonts, &font_names);
193 for (int f = 0; f < n; ++f, ++xfonts) {
194 //fprintf(stderr, "--%d-- [%s] a=%d; d=%d\n", f, font_names[f], (*xfonts)->ascent, (*xfonts)->descent);
195 if (f == 0) *fid = (*xfonts)->fid;
196 //if (*rbearing != 0 && (*xfonts)->max_bounds.rbearing > (*rbearing)*2-(*rbearing)/2) continue; /*HACK: skip too wide fonts*/
197 *ascent = K8T_MAX(*ascent, (*xfonts)->ascent);
198 *descent = K8T_MAX(*descent, (*xfonts)->descent);
199 #if 1
201 fprintf(stderr, "--%d-- [%s]\n", f, font_names[f]);
202 fprintf(stderr, " ib: l=%d; r=%d\n", (*xfonts)->min_bounds.lbearing, (*xfonts)->min_bounds.rbearing);
203 fprintf(stderr, " ab: l=%d; r=%d\n", (*xfonts)->max_bounds.lbearing, (*xfonts)->max_bounds.rbearing);
205 lbearing = K8T_MAX(lbearing, (*xfonts)->min_bounds.lbearing);
206 rbearing = K8T_MAX(rbearing, (*xfonts)->max_bounds.rbearing);
207 #else
208 XRectangle r;
209 memset(&r, 0, sizeof(r));
210 XmbTextExtents(set, "W", 1, &r, NULL);
211 fprintf(stderr, "x=%d; w=%d\n", r.x, r.width);
212 fprintf(stderr, " ib: l=%d; r=%d\n", (*xfonts)->min_bounds.lbearing, (*xfonts)->min_bounds.rbearing);
213 fprintf(stderr, " ab: l=%d; r=%d\n", (*xfonts)->max_bounds.lbearing, (*xfonts)->max_bounds.rbearing);
214 lbearing = K8T_MAX(lbearing, r.x);
215 rbearing = K8T_MAX(rbearing, r.width);
216 #endif
217 *width = rbearing-lbearing;
218 break; /*HACK: use first font in set*/
221 #else
222 static void xgetfontinfo (XFontStruct *set, int *ascent, int *descent, int *width, Font *fid, int monocheck) {
223 int dir;
224 XCharStruct cs;
225 *fid = set->fid;
226 XQueryTextExtents(xw.dpy, set->fid, "W", 1, &dir, ascent, descent, &cs);
227 *width = cs.width;
228 if (!(cs.width > 0 && *ascent+*descent > 0)) {
229 k8t_die("X11: specified X font has invalid dimensions");
230 return;
232 //fprintf(stderr, "ASCENT: %d; DESCENT: %d; lb=%d; rb=%d\n", font->ascent, font->descent, font->lbearing, font->rbearing);
234 if (monocheck) {
235 // rough check for monospaced font
236 const char *wcs[9] = {"A", "W", "I", "i", "0", "1", "-", "g", "b"};
237 int wdt[9] = {0};
239 for (unsigned f = 0; f < 9; ++f) {
240 wdt[f] = XTextWidth(set, wcs[f], 1);
243 for (unsigned f = 0; f < 9; ++f) {
244 for (unsigned c = 0; c < 9; ++c) {
245 if (wdt[f] != wdt[c]) {
246 k8t_die("X11: specified X font is not monospaced");
247 return;
253 #endif
257 static int isUTF8LocaleName (const char *lang) {
258 if (!lang) return 0;
259 while (*lang) {
260 if ((lang[0]|0x20) == 'u' && (lang[1]|0x20) == 't' && (lang[2]|0x20) == 'f') return 1;
261 ++lang;
263 return 0;
268 static void initfonts (const char *fontstr, const char *bfontstr, const char *tabfont) {
269 #ifdef X11_USE_FUCKED_FONTSETS
270 char *olocale;
271 /* X Core Fonts fix */
272 /* sorry, we HAVE to do this shit here!
273 * braindamaged X11 will not work with utf-8 in Xmb*() correctly if we have, for example,
274 * koi8 as system locale unless we first create font set in system locale. don't even ask
275 * me why X.Org is so fuckin' broken. */
276 XFontSet tmp_fs;
277 char **missing;
278 int missing_count;
279 olocale = strdup(setlocale(LC_ALL, NULL)); /*FIXME: this can fail if we have no memory; fuck it*/
280 setlocale(LC_ALL, "");
281 tmp_fs = XCreateFontSet(xw.dpy, "-*-*-*-*-*-*-*-*-*-*-*-*-*", &missing, &missing_count, NULL);
282 if (!tmp_fs) {
283 fprintf(stderr, "FATAL: can't apply workarount for X Core FontSets!\n");
284 exit(1);
286 if (missing) XFreeStringList(missing);
287 /* throw out unused fontset */
288 XFreeFontSet(xw.dpy, tmp_fs);
289 //setlocale(LC_ALL, "ru_RU.utf-8");
290 /*TODO: find suitable utf-8 encoding */
291 if (!isUTF8LocaleName(setlocale(LC_ALL, NULL)) {
292 //setlocale(LC_ALL, "en_US.UTF-8");
293 if (!setlocale(LC_ALL, "en_US.UTF-8") && !setlocale(LC_ALL, "en_US.UTF8") && !setlocale(LC_ALL, "en_US.utf8")) {
294 fprintf(stderr, "FATAL: can't set UTF locale!\n");
295 exit(1);
298 /* create fonts for utf-8 locale */
299 #endif
300 if ((dc.font[0].set = xinitfont(fontstr)) == NULL) {
301 if ((dc.font[0].set = xinitfont(FONT)) == NULL) k8t_die("can't load font '%s'", fontstr);
303 xgetfontinfo(dc.font[0].set, &dc.font[0].ascent, &dc.font[0].descent, &dc.font[0].width, &dc.font[0].fid, 1);
304 if ((dc.font[1].set = xinitfont(bfontstr)) == NULL) {
305 if ((dc.font[1].set = xinitfont(FONTBOLD)) == NULL) k8t_die("can't load font '%s'", bfontstr);
307 xgetfontinfo(dc.font[1].set, &dc.font[1].ascent, &dc.font[1].descent, &dc.font[1].width, &dc.font[1].fid, 1);
308 if ((dc.font[2].set = xinitfont(tabfont)) == NULL) {
309 if ((dc.font[2].set = xinitfont(FONTTAB)) == NULL) k8t_die("can't load font '%s'", tabfont);
311 xgetfontinfo(dc.font[2].set, &dc.font[2].ascent, &dc.font[2].descent, &dc.font[2].width, &dc.font[2].fid, 0);
312 /* restore locale */
313 #ifdef X11_USE_FUCKED_FONTSETS
314 setlocale(LC_ALL, olocale);
315 free(olocale);
316 #endif
320 static void xinit (void) {
321 XSetWindowAttributes attrs;
322 Window parent;
323 XColor blackcolor = { 0, 0, 0, 0, 0, 0 };
324 int wwdt, whgt;
326 if (!(xw.dpy = XOpenDisplay(NULL))) k8t_die("can't open display");
328 XA_VT_SELECTION = XInternAtom(xw.dpy, "_STERM_SELECTION_", 0);
329 XA_CLIPBOARD = XInternAtom(xw.dpy, "CLIPBOARD", 0);
330 XA_UTF8 = XInternAtom(xw.dpy, "UTF8_STRING", 0);
331 XA_NETWM_NAME = XInternAtom(xw.dpy, "_NET_WM_NAME", 0);
332 XA_TARGETS = XInternAtom(xw.dpy, "TARGETS", 0);
333 XA_WM_DELETE_WINDOW = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", 0);
334 xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
336 xw.scr = XDefaultScreen(xw.dpy);
337 /* font */
338 initfonts(opt_fontnorm, opt_fontbold, opt_fonttab);
339 /* XXX: Assuming same size for bold font */
340 xw.cw = dc.font[0].width;
341 xw.ch = dc.font[0].ascent+dc.font[0].descent;
342 xw.tch = dc.font[2].ascent+dc.font[2].descent;
343 xw.tabheight = opt_disabletabs ? 0 : xw.tch+2;
344 //xw.tabheight = 0;
345 /* colors */
346 xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
347 xloadcols();
348 /* window - default size */
350 K8T_DATA(curterm)->picbufh = curterm->row*xw.ch;
351 K8T_DATA(curterm)->picbufw = curterm->col*xw.cw;
353 wwdt = curterm->col*xw.cw;
354 whgt = curterm->row*xw.ch;
356 xw.h = whgt+xw.tabheight;
357 xw.w = wwdt;
359 attrs.background_pixel = getColor(defaultBG);
360 attrs.border_pixel = getColor(defaultBG);
361 attrs.bit_gravity = NorthWestGravity;
362 attrs.event_mask =
363 FocusChangeMask|KeyPressMask|
364 ExposureMask|VisibilityChangeMask|StructureNotifyMask|
365 /*ButtonMotionMask|*/PointerMotionMask|ButtonPressMask|ButtonReleaseMask|
366 EnterWindowMask|LeaveWindowMask;
367 attrs.colormap = xw.cmap;
368 //fprintf(stderr, "oe: [%s]\n", opt_embed);
369 parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
370 xw.win = XCreateWindow(xw.dpy, parent, 0, 0,
371 xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
372 XDefaultVisual(xw.dpy, xw.scr),
373 CWBackPixel|CWBorderPixel|CWBitGravity|CWEventMask|CWColormap,
374 &attrs);
375 xhints();
377 xw.pictab = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.tabheight>0?xw.tabheight:1, XDefaultDepth(xw.dpy, xw.scr));
378 /* input methods */
379 if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) k8t_die("XOpenIM() failed");
380 xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing|XIMStatusNothing, XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
381 /* gc */
382 dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
383 #ifdef X11_USE_FUCKED_FONTSETS
384 // nothing
385 #else
386 XSetFont(xw.dpy, dc.gc, dc.font[0].fid);
387 dc.gcfid = dc.font[0].fid;
388 #endif
390 xw.lastcursor = xw.cursor = XCreateFontCursor(xw.dpy, XC_xterm);
391 //xw.cursor = XCreateFontCursor(xw.dpy, XC_arrow);
392 /* green cursor, black outline */
393 XRecolorCursor(xw.dpy, xw.cursor,
394 &(XColor){.red = 0x0000, .green = 0xffff, .blue = 0x0000},
395 &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
397 xw.defcursor = XCreateFontCursor(xw.dpy, /*XC_X_cursor*/XC_left_ptr);
398 XRecolorCursor(xw.dpy, xw.defcursor,
399 &(XColor){.red = 0x0000, .green = 0xffff, .blue = 0x0000},
400 &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
402 XDefineCursor(xw.dpy, xw.win, xw.lastcursor);
403 fixWindowTitle(curterm);
404 //XStoreName(xw.dpy, xw.win, opt_title);
406 XSetForeground(xw.dpy, dc.gc, 0);
407 if (xw.tabheight > 0) XFillRectangle(xw.dpy, xw.pictab, dc.gc, 0, 0, xw.w, xw.tabheight);
409 xw.picscrhere = 0;
410 termCreateXPixmap(curterm);
412 XMapWindow(xw.dpy, xw.win);
414 #if BLANKPTR_USE_GLYPH_CURSOR
415 xw.blankPtr = XCreateGlyphCursor(xw.dpy, dc.font[0].fid, dc.font[0].fid, ' ', ' ', &blackcolor, &blackcolor);
416 #else
417 static const char cmbmp[1] = {0};
418 Pixmap pm;
420 pm = XCreateBitmapFromData(xw.dpy, xw.win, cmbmp, 1, 1);
421 xw.blankPtr = XCreatePixmapCursor(xw.dpy, pm, pm, &blackcolor, &blackcolor, 0, 0);
422 XFreePixmap(xw.dpy, pm);
423 #endif
425 XSync(xw.dpy, 0);
429 void xdone (void) {
430 if (xw.xim) XCloseIM(xw.xim);
431 if (xw.dpy) XCloseDisplay(xw.dpy);