1 ////////////////////////////////////////////////////////////////////////////////
2 // x11 drawing and utils
4 static void xcreatebw (void) {
5 if ((dc.bcol = calloc(MAX_COLOR+1, sizeof(dc.bcol[0]))) == NULL) k8t_die("out of memory");
7 for (int f = 0; f <= MAX_COLOR; ++f) {
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
) {
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
);
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
);
36 dc
.gcol
[idx
] = color
->pixel
;
40 static void xallocnamedclr (int idx
, const char *cname
) {
43 if (!XAllocNamedColor(xw
.dpy
, xw
.cmap
, cname
, &color
, &color
)) {
44 fprintf(stderr
, "WARNING: could not allocate color #%d: '%s'\n", idx
, cname
);
47 dc
.ncol
[idx
] = color
.pixel
;
48 xallocbwclr(idx
, &color
);
52 static void xloadcols (void) {
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
];
73 if (K8T_ARRLEN(defextcolornames
) <= (unsigned)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
]);
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
);
92 dc
.ncol
[f
] = color
.pixel
;
93 xallocbwclr(f
, &color
);
100 for (r
= 0; r
< 24; ++r
, ++f
) {
101 if (opt_colornames
[f
] != NULL
) {
102 xallocnamedclr(f
, opt_colornames
[f
]);
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
);
108 dc
.ncol
[f
] = color
.pixel
;
109 xallocbwclr(f
, &color
);
114 for (size_t f
= 0; f
< K8T_ARRLEN(opt_colornames
); ++f
) {
115 if (opt_colornames
[f
]) free(opt_colornames
[f
]);
120 static void xhints (void) {
121 XClassHint
class = {opt_class
, opt_title
};
122 XWMHints wm
= {.flags
= InputHint
, .input
= 1};
124 .flags
= PSize
|PResizeInc
|PBaseSize
,
129 .base_height
= xw
.h
/*xw.tabheight*/,
132 //XSetWMNormalHints(xw.dpy, xw.win, &size);
133 XSetWMProperties(xw
.dpy
, xw
.win
, NULL
, NULL
, NULL
, 0, &size
, &wm
, &class);
134 XSetWMProtocols(xw
.dpy
, xw
.win
, &XA_WM_DELETE_WINDOW
, 1);
138 #ifdef X11_USE_FUCKED_FONTSETS
139 static XFontSet
xinitfont (const char *fontstr
) {
141 char *def
, **missing
;
145 set
= XCreateFontSet(xw
.dpy
, fontstr
, &missing
, &n
, &def
);
147 while (n
--) fprintf(stderr
, "sterm: missing fontset: %s\n", missing
[n
]);
148 XFreeStringList(missing
);
153 static XFontStruct
*xinitfont (const char *fontstr
) {
154 XFontStruct
*fst
= NULL
;
156 char **flist
= XListFonts(xw
.dpy
, (char *)fontstr
, 32700/*maxnames*/, &fcount
);
158 //for (int f = 0; f < fcount; ++f) fprintf(stderr, "F#%d: <%s>\n", f, flist[f]);
159 for (int f
= 0; f
< fcount
; ++f
) {
160 if (strstr(flist
[f
], "-iso10646-1")) {
161 fst
= XLoadQueryFont(xw
.dpy
, flist
[f
]);
163 int dir
, ascent
, descent
;
165 XQueryTextExtents(xw
.dpy
, fst
->fid
, "W", 1, &dir
, &ascent
, &descent
, &cs
);
166 if (ascent
+descent
> 0 && cs
.rbearing
-cs
.lbearing
> 0 && cs
.width
> 0) {
167 fprintf(stderr
, "X11: loaded font '%s' (hgt=%d; wdt=%d)\n", flist
[f
], (int)(ascent
+descent
), (int)cs
.width
);
170 fprintf(stderr
, "X11: rejected font '%s'\n", flist
[f
]);
171 XFreeFont(xw
.dpy
, fst
);
176 XFreeFontNames(flist
);
179 fst
= XLoadQueryFont(xw
.dpy
, (char *)fontstr
);
186 #ifdef X11_USE_FUCKED_FONTSETS
187 static void xgetfontinfo (XFontSet set
, int *ascent
, int *descent
, int *width
, Font
*fid
, int monocheck
) {
188 XFontStruct
**xfonts
;
192 *ascent
= *descent
= 0;
193 int lbearing
= 0, rbearing
= 0;
194 n
= XFontsOfFontSet(set
, &xfonts
, &font_names
);
195 for (int f
= 0; f
< n
; ++f
, ++xfonts
) {
196 //fprintf(stderr, "--%d-- [%s] a=%d; d=%d\n", f, font_names[f], (*xfonts)->ascent, (*xfonts)->descent);
197 if (f
== 0) *fid
= (*xfonts
)->fid
;
198 //if (*rbearing != 0 && (*xfonts)->max_bounds.rbearing > (*rbearing)*2-(*rbearing)/2) continue; /*HACK: skip too wide fonts*/
199 *ascent
= K8T_MAX(*ascent
, (*xfonts
)->ascent
);
200 *descent
= K8T_MAX(*descent
, (*xfonts
)->descent
);
203 fprintf(stderr, "--%d-- [%s]\n", f, font_names[f]);
204 fprintf(stderr, " ib: l=%d; r=%d\n", (*xfonts)->min_bounds.lbearing, (*xfonts)->min_bounds.rbearing);
205 fprintf(stderr, " ab: l=%d; r=%d\n", (*xfonts)->max_bounds.lbearing, (*xfonts)->max_bounds.rbearing);
207 lbearing
= K8T_MAX(lbearing
, (*xfonts
)->min_bounds
.lbearing
);
208 rbearing
= K8T_MAX(rbearing
, (*xfonts
)->max_bounds
.rbearing
);
211 memset(&r
, 0, sizeof(r
));
212 XmbTextExtents(set
, "W", 1, &r
, NULL
);
213 fprintf(stderr
, "x=%d; w=%d\n", r
.x
, r
.width
);
214 fprintf(stderr
, " ib: l=%d; r=%d\n", (*xfonts
)->min_bounds
.lbearing
, (*xfonts
)->min_bounds
.rbearing
);
215 fprintf(stderr
, " ab: l=%d; r=%d\n", (*xfonts
)->max_bounds
.lbearing
, (*xfonts
)->max_bounds
.rbearing
);
216 lbearing
= K8T_MAX(lbearing
, r
.x
);
217 rbearing
= K8T_MAX(rbearing
, r
.width
);
219 *width
= rbearing
-lbearing
;
220 break; /*HACK: use first font in set*/
224 static void xgetfontinfo (XFontStruct
*set
, int *ascent
, int *descent
, int *width
, Font
*fid
, int monocheck
) {
228 XQueryTextExtents(xw
.dpy
, set
->fid
, "W", 1, &dir
, ascent
, descent
, &cs
);
230 if (!(cs
.width
> 0 && *ascent
+*descent
> 0)) {
231 k8t_die("X11: specified X font has invalid dimensions");
234 //fprintf(stderr, "ASCENT: %d; DESCENT: %d; lb=%d; rb=%d\n", font->ascent, font->descent, font->lbearing, font->rbearing);
237 // rough check for monospaced font
238 const char *wcs
[9] = {"A", "W", "I", "i", "0", "1", "-", "g", "b"};
241 for (unsigned f
= 0; f
< 9; ++f
) {
242 wdt
[f
] = XTextWidth(set
, wcs
[f
], 1);
245 for (unsigned f
= 0; f
< 9; ++f
) {
246 for (unsigned c
= 0; c
< 9; ++c
) {
247 if (wdt
[f
] != wdt
[c
]) {
248 k8t_die("X11: specified X font is not monospaced");
259 static int isUTF8LocaleName (const char *lang) {
262 if ((lang[0]|0x20) == 'u' && (lang[1]|0x20) == 't' && (lang[2]|0x20) == 'f') return 1;
270 static void initfonts (const char *fontstr
, const char *bfontstr
, const char *tabfont
) {
271 #ifdef X11_USE_FUCKED_FONTSETS
273 /* X Core Fonts fix */
274 /* sorry, we HAVE to do this shit here!
275 * braindamaged X11 will not work with utf-8 in Xmb*() correctly if we have, for example,
276 * koi8 as system locale unless we first create font set in system locale. don't even ask
277 * me why X.Org is so fuckin' broken. */
281 olocale
= strdup(setlocale(LC_ALL
, NULL
)); /*FIXME: this can fail if we have no memory; fuck it*/
282 setlocale(LC_ALL
, "");
283 tmp_fs
= XCreateFontSet(xw
.dpy
, "-*-*-*-*-*-*-*-*-*-*-*-*-*", &missing
, &missing_count
, NULL
);
285 fprintf(stderr
, "FATAL: can't apply workarount for X Core FontSets!\n");
288 if (missing
) XFreeStringList(missing
);
289 /* throw out unused fontset */
290 XFreeFontSet(xw
.dpy
, tmp_fs
);
291 //setlocale(LC_ALL, "ru_RU.utf-8");
292 /*TODO: find suitable utf-8 encoding */
293 if (!isUTF8LocaleName(setlocale(LC_ALL
, NULL
)) {
294 //setlocale(LC_ALL, "en_US.UTF-8");
295 if (!setlocale(LC_ALL
, "en_US.UTF-8") && !setlocale(LC_ALL
, "en_US.UTF8") && !setlocale(LC_ALL
, "en_US.utf8")) {
296 fprintf(stderr
, "FATAL: can't set UTF locale!\n");
300 /* create fonts for utf-8 locale */
302 if ((dc
.font
[0].set
= xinitfont(fontstr
)) == NULL
) {
303 if ((dc
.font
[0].set
= xinitfont(FONT
)) == NULL
) k8t_die("can't load font '%s'", fontstr
);
305 xgetfontinfo(dc
.font
[0].set
, &dc
.font
[0].ascent
, &dc
.font
[0].descent
, &dc
.font
[0].width
, &dc
.font
[0].fid
, 1);
306 if ((dc
.font
[1].set
= xinitfont(bfontstr
)) == NULL
) {
307 if ((dc
.font
[1].set
= xinitfont(FONTBOLD
)) == NULL
) k8t_die("can't load font '%s'", bfontstr
);
309 xgetfontinfo(dc
.font
[1].set
, &dc
.font
[1].ascent
, &dc
.font
[1].descent
, &dc
.font
[1].width
, &dc
.font
[1].fid
, 1);
310 if ((dc
.font
[2].set
= xinitfont(tabfont
)) == NULL
) {
311 if ((dc
.font
[2].set
= xinitfont(FONTTAB
)) == NULL
) k8t_die("can't load font '%s'", tabfont
);
313 xgetfontinfo(dc
.font
[2].set
, &dc
.font
[2].ascent
, &dc
.font
[2].descent
, &dc
.font
[2].width
, &dc
.font
[2].fid
, 0);
315 #ifdef X11_USE_FUCKED_FONTSETS
316 setlocale(LC_ALL
, olocale
);
322 static void xinit (void) {
323 XSetWindowAttributes attrs
;
325 XColor blackcolor
= { 0, 0, 0, 0, 0, 0 };
328 if (!(xw
.dpy
= XOpenDisplay(NULL
))) k8t_die("can't open display");
330 XA_VT_SELECTION
= XInternAtom(xw
.dpy
, "_K8STERM_SELECTION_PROP_", 0);
331 XA_CLIPBOARD
= XInternAtom(xw
.dpy
, "CLIPBOARD", 0);
332 XA_UTF8
= XInternAtom(xw
.dpy
, "UTF8_STRING", 0);
333 XA_NETWM_NAME
= XInternAtom(xw
.dpy
, "_NET_WM_NAME", 0);
334 XA_TARGETS
= XInternAtom(xw
.dpy
, "TARGETS", 0);
335 XA_WM_DELETE_WINDOW
= XInternAtom(xw
.dpy
, "WM_DELETE_WINDOW", 0);
336 XA_INCR
= XInternAtom(xw
.dpy
, "INCR", 0);
337 XA_CSTRING
= XInternAtom(xw
.dpy
, "C_STRING", 0);
338 xw
.xembed
= XInternAtom(xw
.dpy
, "_XEMBED", False
);
340 xw
.paste_term
= NULL
;
342 xw
.scr
= XDefaultScreen(xw
.dpy
);
344 initfonts(opt_fontnorm
, opt_fontbold
, opt_fonttab
);
345 /* XXX: Assuming same size for bold font */
346 xw
.cw
= dc
.font
[0].width
;
347 xw
.ch
= dc
.font
[0].ascent
+dc
.font
[0].descent
;
348 xw
.tch
= dc
.font
[2].ascent
+dc
.font
[2].descent
;
349 xw
.tabheight
= opt_disabletabs
? 0 : xw
.tch
+2;
352 xw
.cmap
= XDefaultColormap(xw
.dpy
, xw
.scr
);
354 /* window - default size */
356 K8T_DATA(curterm)->picbufh = curterm->row*xw.ch;
357 K8T_DATA(curterm)->picbufw = curterm->col*xw.cw;
359 wwdt
= curterm
->col
*xw
.cw
;
360 whgt
= curterm
->row
*xw
.ch
;
362 xw
.h
= whgt
+xw
.tabheight
;
365 attrs
.background_pixel
= getColor(defaultBG
);
366 attrs
.border_pixel
= getColor(defaultBG
);
367 attrs
.bit_gravity
= NorthWestGravity
;
369 FocusChangeMask
|KeyPressMask
|
370 ExposureMask
|VisibilityChangeMask
|StructureNotifyMask
|
371 /*ButtonMotionMask|*/PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
|
372 EnterWindowMask
|LeaveWindowMask
|
373 PropertyChangeMask
; // for selection pasting
374 attrs
.colormap
= xw
.cmap
;
375 //fprintf(stderr, "oe: [%s]\n", opt_embed);
376 parent
= opt_embed
? (Window
)strtol(opt_embed
, NULL
, 0) : XRootWindow(xw
.dpy
, xw
.scr
);
377 xw
.win
= XCreateWindow(xw
.dpy
, parent
, 0, 0,
378 xw
.w
, xw
.h
, 0, XDefaultDepth(xw
.dpy
, xw
.scr
), InputOutput
,
379 XDefaultVisual(xw
.dpy
, xw
.scr
),
380 CWBackPixel
|CWBorderPixel
|CWBitGravity
|CWEventMask
|CWColormap
,
384 xw
.pictab
= XCreatePixmap(xw
.dpy
, xw
.win
, xw
.w
, xw
.tabheight
>0?xw
.tabheight
:1, XDefaultDepth(xw
.dpy
, xw
.scr
));
386 if ((xw
.xim
= XOpenIM(xw
.dpy
, NULL
, NULL
, NULL
)) == NULL
) k8t_die("XOpenIM() failed");
387 xw
.xic
= XCreateIC(xw
.xim
, XNInputStyle
, XIMPreeditNothing
|XIMStatusNothing
, XNClientWindow
, xw
.win
, XNFocusWindow
, xw
.win
, NULL
);
389 dc
.gc
= XCreateGC(xw
.dpy
, xw
.win
, 0, NULL
);
390 #ifdef X11_USE_FUCKED_FONTSETS
393 XSetFont(xw
.dpy
, dc
.gc
, dc
.font
[0].fid
);
394 dc
.gcfid
= dc
.font
[0].fid
;
397 xw
.lastcursor
= xw
.cursor
= XCreateFontCursor(xw
.dpy
, XC_xterm
);
398 //xw.cursor = XCreateFontCursor(xw.dpy, XC_arrow);
399 /* green cursor, black outline */
400 XRecolorCursor(xw
.dpy
, xw
.cursor
,
401 &(XColor
){.red
= 0x0000, .green
= 0xffff, .blue
= 0x0000},
402 &(XColor
){.red
= 0x0000, .green
= 0x0000, .blue
= 0x0000});
404 xw
.defcursor
= XCreateFontCursor(xw
.dpy
, /*XC_X_cursor*/XC_left_ptr
);
405 XRecolorCursor(xw
.dpy
, xw
.defcursor
,
406 &(XColor
){.red
= 0x0000, .green
= 0xffff, .blue
= 0x0000},
407 &(XColor
){.red
= 0x0000, .green
= 0x0000, .blue
= 0x0000});
409 XDefineCursor(xw
.dpy
, xw
.win
, xw
.lastcursor
);
410 fixWindowTitle(curterm
);
411 //XStoreName(xw.dpy, xw.win, opt_title);
413 XSetForeground(xw
.dpy
, dc
.gc
, 0);
414 if (xw
.tabheight
> 0) XFillRectangle(xw
.dpy
, xw
.pictab
, dc
.gc
, 0, 0, xw
.w
, xw
.tabheight
);
417 termCreateXPixmap(curterm
);
419 XMapWindow(xw
.dpy
, xw
.win
);
421 #if BLANKPTR_USE_GLYPH_CURSOR
422 xw
.blankPtr
= XCreateGlyphCursor(xw
.dpy
, dc
.font
[0].fid
, dc
.font
[0].fid
, ' ', ' ', &blackcolor
, &blackcolor
);
424 static const char cmbmp
[1] = {0};
427 pm
= XCreateBitmapFromData(xw
.dpy
, xw
.win
, cmbmp
, 1, 1);
428 xw
.blankPtr
= XCreatePixmapCursor(xw
.dpy
, pm
, pm
, &blackcolor
, &blackcolor
, 0, 0);
429 XFreePixmap(xw
.dpy
, pm
);
437 if (xw
.xim
) XCloseIM(xw
.xim
);
438 if (xw
.dpy
) XCloseDisplay(xw
.dpy
);