1 #include <stdlib.h>
2 #include "xglk.h"
3 #include "xg_internal.h"
4
5 static stylehints_t null_hints;
6 static stylehints_t textbuf_hints;
7 static stylehints_t textgrid_hints;
8
9 static int gli_stylehints_init(stylehints_t *hints);
10 static int gli_stylehints_clone(stylehints_t *dest, stylehints_t *src);
11 static int gli_stylehint_get(stylehints_t *hints, glui32 styl, glui32 hint,
12 glsi32 *val);
13 static void gli_stylehint_set(stylehints_t *hints, glui32 styl, glui32 hint,
14 int set, glsi32 val);
15
16 static unsigned short MaxRGBDifference(XColor *col1, XColor *col2);
17
init_gli_styles()18 int init_gli_styles()
19 {
20 int ix, jx;
21
22 ix = gli_stylehints_init(&null_hints);
23 if (!ix)
24 return FALSE;
25 ix = gli_stylehints_init(&textbuf_hints);
26 if (!ix)
27 return FALSE;
28 ix = gli_stylehints_init(&textgrid_hints);
29 if (!ix)
30 return FALSE;
31
32 textbuf_hints.type = wintype_TextBuffer;
33 textgrid_hints.type = wintype_TextGrid;
34
35 return TRUE;
36 }
37
gli_stylehints_init(stylehints_t * hints)38 static int gli_stylehints_init(stylehints_t *hints)
39 {
40 int ix;
41
42 hints->type = wintype_AllTypes;
43
44 for (ix=0; ix<style_NUMSTYLES; ix++) {
45 hints->style[ix].setflags = 0;
46 hints->style[ix].vals = NULL;
47 hints->style[ix].length = 0;
48 hints->style[ix].size = 0;
49 }
50
51 return TRUE;
52 }
53
gli_stylehints_clone(stylehints_t * dest,stylehints_t * src)54 static int gli_stylehints_clone(stylehints_t *dest, stylehints_t *src)
55 {
56 int ix, jx, len;
57
58 dest->type = src->type;
59
60 for (ix=0; ix<style_NUMSTYLES; ix++) {
61 dest->style[ix].setflags = src->style[ix].setflags;
62 len = src->style[ix].length;
63 dest->style[ix].length = len;
64 dest->style[ix].size = len;
65 if (len) {
66 dest->style[ix].vals = (styleval_t *)malloc(len * sizeof(styleval_t));
67 for (jx=0; jx<len; jx++) {
68 dest->style[ix].vals[jx] = src->style[ix].vals[jx];
69 }
70 }
71 else {
72 dest->style[ix].vals = NULL;
73 }
74 }
75
76 return TRUE;
77 }
78
gli_styles_compute(fontset_t * font,stylehints_t * hints)79 void gli_styles_compute(fontset_t *font, stylehints_t *hints)
80 {
81 int ix;
82 int negindent;
83 glsi32 val;
84 winprefs_t *wprefs;
85
86 /* Here is the routine: For every (damn) attribute, look at the
87 prefs.fontprefs_t. That will specify a value, and also a check-hints
88 flag. If the latter is true, and there's a hint, let the hint
89 override. Otherwise, use the value. */
90
91 if (!hints)
92 hints = &null_hints;
93
94 if (hints->type == wintype_TextGrid)
95 wprefs = &prefs.textgrid;
96 else
97 wprefs = &prefs.textbuffer;
98
99 font->forecolor = wprefs->forecolor;
100 font->linkcolor = wprefs->linkcolor;
101 font->backcolor = wprefs->backcolor;
102
103 for (ix=0; ix<style_NUMSTYLES; ix++) {
104 fontref_t *fref = &(font->gc[ix]);
105 XGCValues gcvalues;
106 int size, weight, oblique, proportional;
107 char buf[256];
108
109 size = wprefs->style[ix].size;
110 if (wprefs->sizehint
111 && gli_stylehint_get(hints, ix, stylehint_Size, &val))
112 size += val;
113
114 if (wprefs->attribhint
115 && gli_stylehint_get(hints, ix, stylehint_Weight, &val))
116 weight = val;
117 else
118 weight = wprefs->style[ix].weight;
119
120 if (wprefs->attribhint
121 && gli_stylehint_get(hints, ix, stylehint_Oblique, &val))
122 oblique = val;
123 else
124 oblique = wprefs->style[ix].oblique;
125
126 if (wprefs->fixedhint
127 && gli_stylehint_get(hints, ix, stylehint_Proportional, &val))
128 proportional = val;
129 else
130 proportional = wprefs->style[ix].proportional;
131
132 xglk_build_fontname(wprefs->style[ix].spec, buf,
133 size, weight, oblique, proportional);
134 fref->fontstr = XLoadQueryFont(xiodpy, buf);
135 if (!fref->fontstr) {
136 fprintf(stderr, "### unable to snarf font %s.\n", buf);
137 }
138
139 fref->specname = (char *)malloc(sizeof(char) * (strlen(buf)+1));
140 /* ### bit of a core leak here, I'm afraid. */
141 strcpy(fref->specname, buf);
142
143 fref->forecolor = wprefs->style[ix].forecolor;
144 fref->linkcolor = wprefs->style[ix].linkcolor;
145 fref->backcolor = wprefs->style[ix].backcolor;
146 /*### or hint */
147
148 if (wprefs->justhint
149 && gli_stylehint_get(hints, ix, stylehint_Justification, &val))
150 font->gc[ix].justify = val;
151 else
152 font->gc[ix].justify = wprefs->style[ix].justify;
153
154 if (wprefs->indenthint
155 && gli_stylehint_get(hints, ix, stylehint_Indentation, &val))
156 font->gc[ix].indent = (font->gc[ix].fontstr->ascent * val) / 2;
157 else
158 font->gc[ix].indent = wprefs->style[ix].baseindent;
159
160 if (wprefs->indenthint
161 && gli_stylehint_get(hints, ix, stylehint_ParaIndentation, &val))
162 font->gc[ix].parindent = (font->gc[ix].fontstr->ascent * val) / 2;
163 else
164 font->gc[ix].parindent = wprefs->style[ix].parindent;
165 }
166
167 font->lineheight = 0;
168 font->lineoff = 0;
169 font->baseindent = 0;
170 negindent = 0;
171
172 for (ix=0; ix<style_NUMSTYLES; ix++) {
173 fontref_t *fref = &(font->gc[ix]);
174 int ascent, descent, dir;
175 int clineheight, clineheightoff, ival;
176 XCharStruct strdat;
177
178 XTextExtents(fref->fontstr, " ", 1, &dir, &ascent, &descent, &strdat);
179 font->gc[ix].ascent = ascent;
180 font->gc[ix].descent = descent;
181 if (descent < 2)
182 font->gc[ix].underliney = descent-1;
183 else
184 font->gc[ix].underliney = 1;
185
186 clineheight = ascent + descent + wprefs->leading;
187 clineheightoff = ascent;
188 if (clineheight > font->lineheight)
189 font->lineheight = clineheight;
190 if (clineheightoff > font->lineoff)
191 font->lineoff = clineheightoff;
192 font->gc[ix].spacewidth = strdat.width;
193
194 ival = font->gc[ix].indent + font->gc[ix].parindent;
195 if (ival < negindent)
196 negindent = ival;
197 if (font->gc[ix].indent < negindent)
198 negindent = font->gc[ix].indent;
199 }
200
201 font->baseindent = -negindent;
202 }
203
gli_stylehint_set(stylehints_t * hints,glui32 styl,glui32 hint,int set,glsi32 val)204 static void gli_stylehint_set(stylehints_t *hints, glui32 styl, glui32 hint,
205 int set, glsi32 val)
206 {
207 int ix, len;
208 glui32 hintbit;
209 styleonehint_t *hn;
210
211 if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
212 return;
213
214 hn = &(hints->style[styl]);
215 hintbit = (1 << hint);
216 len = hn->length;
217
218 if (set) {
219 if (hn->setflags & hintbit) {
220 for (ix=0; ix<len; ix++) {
221 if (hn->vals[ix].type == hint) {
222 hn->vals[ix].val = val;
223 break;
224 }
225 }
226 }
227 else {
228 if (!hn->size || !hn->vals) {
229 hn->size = 3;
230 hn->vals = (styleval_t *)malloc(hn->size * sizeof(styleval_t));
231 }
232 else if (len+1 > hn->size) {
233 hn->size = len+4;
234 hn->vals = (styleval_t *)realloc(hn->vals, hn->size * sizeof(styleval_t));
235 }
236 hn->vals[len].type = hint;
237 hn->vals[len].val = val;
238 hn->length++;
239 hn->setflags |= (hintbit);
240 }
241 }
242 else {
243 if (!(hn->setflags & hintbit))
244 return;
245 for (ix=0; ix<len; ix++) {
246 if (hn->vals[ix].type == hint)
247 break;
248 }
249 for (; ix+1<len; ix++) {
250 hn->vals[ix] = hn->vals[ix+1];
251 }
252 hn->length--;
253 hn->setflags &= (~hintbit);
254 }
255 }
256
gli_stylehint_get(stylehints_t * hints,glui32 styl,glui32 hint,glsi32 * val)257 static int gli_stylehint_get(stylehints_t *hints, glui32 styl, glui32 hint,
258 glsi32 *val)
259 {
260 int ix, len;
261 styleonehint_t *hn;
262
263 if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
264 return FALSE;
265
266 hn = &(hints->style[styl]);
267
268 if (!(hn->setflags & (1 << hint))) {
269 return FALSE;
270 }
271
272 len = hn->length;
273 for (ix=0; ix<len; ix++) {
274 if (hn->vals[ix].type == hint) {
275 *val = hn->vals[ix].val;
276 return TRUE;
277 }
278 }
279
280 return FALSE;
281 }
282
glk_stylehint_set(glui32 wintype,glui32 styl,glui32 hint,glsi32 val)283 void glk_stylehint_set(glui32 wintype, glui32 styl, glui32 hint, glsi32 val)
284 {
285 switch (wintype) {
286 case wintype_TextBuffer:
287 gli_stylehint_set(&textbuf_hints, styl, hint, TRUE, val);
288 break;
289 case wintype_TextGrid:
290 gli_stylehint_set(&textgrid_hints, styl, hint, TRUE, val);
291 break;
292 case wintype_AllTypes:
293 gli_stylehint_set(&textbuf_hints, styl, hint, TRUE, val);
294 gli_stylehint_set(&textgrid_hints, styl, hint, TRUE, val);
295 break;
296 }
297 }
298
glk_stylehint_clear(glui32 wintype,glui32 styl,glui32 hint)299 void glk_stylehint_clear(glui32 wintype, glui32 styl, glui32 hint)
300 {
301 switch (wintype) {
302 case wintype_TextBuffer:
303 gli_stylehint_set(&textbuf_hints, styl, hint, FALSE, 0);
304 break;
305 case wintype_TextGrid:
306 gli_stylehint_set(&textgrid_hints, styl, hint, FALSE, 0);
307 break;
308 case wintype_AllTypes:
309 gli_stylehint_set(&textbuf_hints, styl, hint, FALSE, 0);
310 gli_stylehint_set(&textgrid_hints, styl, hint, FALSE, 0);
311 break;
312 }
313 }
314
gli_stylehints_for_window(glui32 wintype,stylehints_t * hints)315 int gli_stylehints_for_window(glui32 wintype, stylehints_t *hints)
316 {
317 switch (wintype) {
318 case wintype_TextBuffer:
319 return gli_stylehints_clone(hints, &textbuf_hints);
320 case wintype_TextGrid:
321 return gli_stylehints_clone(hints, &textgrid_hints);
322 default:
323 return gli_stylehints_init(hints);
324 }
325 }
326
glk_style_distinguish(window_t * win,glui32 styl1,glui32 styl2)327 glui32 glk_style_distinguish(window_t *win, glui32 styl1, glui32 styl2)
328 {
329 fontset_t *fonts;
330 fontref_t *font1, *font2;
331
332 if (!win) {
333 gli_strict_warning("window_style_distinguish: invalid id");
334 return FALSE;
335 }
336
337 fonts = gli_window_get_fontset(win);
338 if (!fonts)
339 return FALSE;
340
341 if (styl1 >= style_NUMSTYLES || styl2 >= style_NUMSTYLES)
342 return FALSE;
343
344 if (styl1 == styl2)
345 return FALSE;
346
347 font1 = &(fonts->gc[styl1]);
348 font2 = &(fonts->gc[styl2]);
349
350 if (strcmp(font1->specname, font2->specname))
351 return TRUE;
352
353 if (font1->justify != font2->justify) {
354 if (!((font1->justify == stylehint_just_LeftFlush
355 || font1->justify == stylehint_just_LeftRight)
356 && (font2->justify == stylehint_just_LeftFlush
357 || font2->justify == stylehint_just_LeftRight)))
358 return TRUE;
359 }
360
361 if (font1->indent != font2->indent)
362 return TRUE;
363
364 if (MaxRGBDifference(&font1->forecolor, &font2->forecolor) >= 6500)
365 return TRUE;
366 if (MaxRGBDifference(&font1->backcolor, &font2->backcolor) >= 6500)
367 return TRUE;
368
369 return FALSE;
370 }
371
glk_style_measure(window_t * win,glui32 styl,glui32 hint,glui32 * result)372 glui32 glk_style_measure(window_t *win, glui32 styl, glui32 hint,
373 glui32 *result)
374 {
375 fontset_t *fonts;
376 fontref_t *font;
377 glui32 dummy, val;
378
379 if (!win) {
380 gli_strict_warning("window_style_measure: invalid id");
381 return FALSE;
382 }
383
384 if (!result)
385 result = &dummy;
386
387 fonts = gli_window_get_fontset(win);
388 if (!fonts)
389 return FALSE;
390
391 if (styl >= style_NUMSTYLES || hint >= stylehint_NUMHINTS)
392 return FALSE;
393
394 font = &(fonts->gc[styl]);
395
396 switch (hint) {
397 case stylehint_Weight:
398 /* Can't figure this out in X */
399 return FALSE;
400 case stylehint_Oblique:
401 /* Can't figure this out in X */
402 return FALSE;
403 case stylehint_TextColor:
404 *result = PackRGBColor(&font->forecolor);
405 return TRUE;
406 case stylehint_BackColor:
407 *result = PackRGBColor(&fonts->backcolor);
408 return TRUE;
409 case stylehint_Justification:
410 *result = font->justify;
411 return TRUE;
412 case stylehint_Size:
413 *result = font->fontstr->ascent + font->fontstr->descent;
414 return TRUE;
415 case stylehint_Indentation:
416 *result = font->indent;
417 return TRUE;
418 case stylehint_ParaIndentation:
419 *result = font->parindent;
420 return TRUE;
421 case stylehint_Proportional:
422 default:
423 return FALSE;
424 }
425 }
426
MaxRGBDifference(XColor * col1,XColor * col2)427 static unsigned short MaxRGBDifference(XColor *col1, XColor *col2)
428 {
429 unsigned short val, result;
430
431 result = 0;
432
433 if ((unsigned short)(col1->red) > (unsigned short)(col2->red))
434 val = (unsigned short)(col1->red) - (unsigned short)(col2->red);
435 else
436 val = (unsigned short)(col2->red) - (unsigned short)(col1->red);
437 if (val > result)
438 result = val;
439
440 if ((unsigned short)(col1->green) > (unsigned short)(col2->green))
441 val = (unsigned short)(col1->green) - (unsigned short)(col2->green);
442 else
443 val = (unsigned short)(col2->green) - (unsigned short)(col1->green);
444 if (val > result)
445 result = val;
446
447 if ((unsigned short)(col1->blue) > (unsigned short)(col2->blue))
448 val = (unsigned short)(col1->blue) - (unsigned short)(col2->blue);
449 else
450 val = (unsigned short)(col2->blue) - (unsigned short)(col1->blue);
451 if (val > result)
452 result = val;
453
454 return result;
455 }
456
457