1 /* $Id: ui.c,v 1.34 2008/12/11 12:18:17 ecd Exp $
2  */
3 
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <sys/times.h>
12 #include <math.h>
13 #include <errno.h>
14 
15 #include <gtk/gtk.h>
16 #include <glib.h>
17 #include <cairo.h>
18 
19 #include <x49gp.h>
20 #include <x49gp_ui.h>
21 #include <s3c2410.h>
22 #include <bitmaps.h>
23 #include <bitmap_font.h>
24 #include <symbol.h>
25 #include <glyphname.h>
26 
27 #include <gdk/gdkkeysyms.h>
28 
29 #if defined(__linux__)
30 #define X49GP_UI_NORMAL_FONT	"urw gothic l"
31 #else
32 #define X49GP_UI_NORMAL_FONT	"Century Gothic"
33 #endif
34 
35 
36 static const x49gp_ui_key_t x49gp_ui_keys[] =
37 {
38 	{
39 		"F1",	"A",	"Y=",	NULL,	NULL,
40 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
41 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
42 		  0,   0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
43 	},
44 	{
45 		"F2",	"B",	"WIN",	NULL,	NULL,
46 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
47 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
48 		 50,   0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
49 	},
50 	{
51 		"F3",	"C",	"GRAPH",	NULL,	NULL,
52 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
53 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
54 		 99,   0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
55 	},
56 	{
57 		"F4",	"D",	"2D/3D",	NULL,	NULL,
58 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
59 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
60 		149,   0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
61 	},
62 	{
63 		"F5",	"E",	"TBLSET",	NULL,	NULL,
64 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
65 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
66 		198,   0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
67 	},
68 	{
69 		"F6",	"F",	"TABLE",	NULL,	NULL,
70 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
71 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
72 		247,   0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
73 	},
74 	{
75 		"APPS",	"G",	"FILES",	"BEGIN",	NULL,
76 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
77 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
78 		  0,  44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
79 	},
80 	{
81 		"MODE",	"H",	"CUSTOM",	"END",	NULL,
82 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
83 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
84 		 50,  44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
85 	},
86 	{
87 		"TOOL",	"I",	"i",	"I",	NULL,
88 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
89 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
90 		 99,  44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
91 	},
92 	{
93 		"V\\kern-1 AR",	"J",	"UPDIR",	"COPY",	NULL,
94 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
95 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
96 		  0,  92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
97 	},
98 	{
99 		"STO \\triangleright",	"K",	"RCL",	"CUT",	NULL,
100 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
101 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
102 		 50,  92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
103 	},
104 	{
105 		"NXT",	"L",	"PREV",	"PASTE",	NULL,
106 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
107 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
108 		 99,  92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
109 	},
110 	{
111 		NULL,	NULL,	NULL,	NULL,	NULL,
112 		UI_COLOR_SILVER, 0.0, 0,
113 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
114 		200,  38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
115 	},
116 	{
117 		NULL,	NULL,	NULL,	NULL,	NULL,
118 		UI_COLOR_SILVER, 0.0, 0,
119 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
120 		164,  66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
121 	},
122 	{
123 		NULL,	NULL,	NULL,	NULL,	NULL,
124 		UI_COLOR_SILVER, 0.0, 0,
125 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
126 		200,  94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
127 	},
128 	{
129 		NULL,	NULL,	NULL,	NULL,	NULL,
130 		UI_COLOR_SILVER, 0.0, 0,
131 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
132 		236,  66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
133 	},
134 	{
135 		"HIST",	"M",	"CMD",	"UNDO",	NULL,
136 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
137 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
138 		  0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
139 	},
140 	{
141 		"EV\\kern-1 AL",	"N",	"PRG",	"CHARS",	NULL,
142 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
143 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
144 		 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
145 	},
146 	{
147 		"\\tick",	"O",	"MTRW",	"EQW",	NULL,
148 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
149 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
150 		119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
151 	},
152 	{
153 		"S\\kern-1 Y\\kern-1 M\\kern-1 B",	"P",	"MTH",	"CAT",	NULL,
154 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
155 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
156 		179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
157 	},
158 	{
159 		"\\arrowleftdblfull",	NULL,	"DEL", "CLEAR",	NULL,
160 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
161 		UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
162 		238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
163 	},
164 	{
165 		"Y\\super x\\/super",	"Q",	"\\math_e\\xsuperior",	"LN",	NULL,
166 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
167 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
168 		  0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
169 	},
170 	{
171 		"\\radical\\overscore\\kern-7 X",	"R",
172 		"\\math_x\\twosuperior",
173 		"\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
174 		NULL,
175 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
176 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
177 		 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
178 	},
179 	{
180 		"SIN",	"S",	"ASIN",	"\\math_summation",	NULL,
181 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
182 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
183 		119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
184 	},
185 	{
186 		"COS",	"T",	"ACOS",	"\\math_partialdiff",	NULL,
187 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
188 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
189 		179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
190 	},
191 	{
192 		"TAN",	"U",	"ATAN",	"\\math_integral",	NULL,
193 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
194 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
195 		238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
196 	},
197 	{
198 		"EEX",	"V",	"10\\xsuperior",	"LOG",	NULL,
199 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
200 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
201 		  0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
202 	},
203 	{
204 		"+\\divisionslash\\minus",	"W",
205 		"\\math_notequal",
206 		"\\math_equal",
207 		NULL,
208 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
209 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
210 		 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
211 	},
212 	{
213 		"X",	"X",
214 		"\\math_lessequal",
215 		"\\math_less",
216 		NULL,
217 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
218 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
219 		119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
220 	},
221 	{
222 		"1/X",	"Y",
223 		"\\math_greaterequal",
224 		"\\math_greater",
225 		NULL,
226 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
227 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
228 		179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
229 	},
230 	{
231 		"\\divide",	"Z",	"ABS",	"ARG",	NULL,
232 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
233 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
234 		238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
235 	},
236 	{
237 		"ALPHA",	NULL,	"USER",	"ENTRY",	NULL,
238 		UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
239 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
240 		  0, 267, 46, 32, 0, 0,        0,        0, 4
241 	},
242 	{
243 		"7",	NULL,	"S.SLV",	"NUM.SLV",	NULL,
244 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
245 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
246 		 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
247 	},
248 	{
249 		"8",	NULL,	"EXP&LN",	"TRIG",	NULL,
250 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
251 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
252 		119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
253 	},
254 	{
255 		"9",	NULL,	"FINANCE",	"TIME",	NULL,
256 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
257 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
258 		179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
259 	},
260 	{
261 		"\\multiply",	NULL,	"[ ]",	"\" \"",	NULL,
262 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
263 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
264 		238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
265 	},
266 	{
267 		"\\uparrowleft",	NULL,	NULL,	NULL,	NULL,
268 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
269 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
270 		  0, 313, 46, 32, 0, 0,        0,        0, 5
271 	},
272 	{
273 		"4",	NULL,	"CALC",	"ALG",	NULL,
274 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
275 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
276 		 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
277 	},
278 	{
279 		"5",	NULL,	"MATRICES",	"STAT",	NULL,
280 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
281 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
282 		119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
283 	},
284 	{
285 		"6",	NULL,	"CONVERT",	"UNITS",	NULL,
286 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
287 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
288 		179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
289 	},
290 	{
291 		"\\minus",	NULL,	"( )",	"_",	NULL,
292 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
293 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
294 		238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
295 	},
296 	{
297 		"\\uparrowright",	NULL,	NULL,	NULL,	NULL,
298 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
299 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
300 		  0, 359, 46, 32, 0, 0,        0,        0, 6
301 	},
302 	{
303 		"1",	NULL,	"ARITH",	"CMPLX",	NULL,
304 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
305 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
306 		 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
307 	},
308 	{
309 		"2",	NULL,	"DEF",	"LIB",	NULL,
310 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
311 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
312 		119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
313 	},
314 	{
315 		"3",	NULL,	"\\math_numbersign",	"BASE",	NULL,
316 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
317 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
318 		179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
319 	},
320 	{
321 		"+",	NULL,
322 		"{ }",
323 		"\\guillemotleft\\ \\guillemotright",
324 		NULL,
325 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
326 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
327 		238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
328 	},
329 	{
330 		"ON",	NULL,	"CONT",	"OFF",	"CANCEL",
331 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
332 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
333 		  0, 405, 46, 32, 0, 0,        0,        0, 0
334 	},
335 	{
336 		"0",	NULL,
337 		"\\math_infinity",
338 		"\\math_arrowright",
339 		NULL,
340 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
341 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
342 		 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
343 	},
344 	{
345 		"\\bullet",	NULL,
346 		": :",
347 		"\\math_downarrowleft",
348 		NULL,
349 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
350 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
351 		119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
352 	},
353 	{
354 		"SPC",	NULL,
355 		"\\math_pi",
356 		"\\large_comma",
357 		NULL,
358 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
359 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
360 		179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
361 	},
362 	{
363 		"ENTER",	NULL,	"ANS",	"\\arrowright NUM",	NULL,
364 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
365 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
366 		238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
367 	},
368 };
369 #define X49GP_UI_NR_KEYS (sizeof(x49gp_ui_keys) / sizeof(x49gp_ui_keys[0]))
370 
371 static const x49gp_ui_key_t x50g_ui_keys[] =
372 {
373 	{
374 		"F1",	"A",	"Y=",	NULL,	NULL,
375 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
376 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
377 		  0,   0, 36, 22, 5, 1, (1 << 5), (1 << 1), 1
378 	},
379 	{
380 		"F2",	"B",	"WIN",	NULL,	NULL,
381 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
382 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
383 		 50,   0, 36, 22, 5, 2, (1 << 5), (1 << 2), 2
384 	},
385 	{
386 		"F3",	"C",	"GRAPH",	NULL,	NULL,
387 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
388 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
389 		 99,   0, 36, 22, 5, 3, (1 << 5), (1 << 3), 3
390 	},
391 	{
392 		"F4",	"D",	"2D/3D",	NULL,	NULL,
393 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
394 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
395 		149,   0, 36, 22, 5, 4, (1 << 5), (1 << 4), 4
396 	},
397 	{
398 		"F5",	"E",	"TBLSET",	NULL,	NULL,
399 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
400 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
401 		198,   0, 36, 22, 5, 5, (1 << 5), (1 << 5), 5
402 	},
403 	{
404 		"F6",	"F",	"TABLE",	NULL,	NULL,
405 		UI_COLOR_BLACK,	12.0, CAIRO_FONT_WEIGHT_BOLD,
406 		UI_SHAPE_BUTTON_TINY, 12.0, UI_LAYOUT_LEFT,
407 		247,   0, 36, 22, 5, 6, (1 << 5), (1 << 6), 6
408 	},
409 	{
410 		"APPS",	"G",	"FILES",	"BEGIN",	NULL,
411 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
412 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
413 		  0,  44, 36, 28, 5, 7, (1 << 5), (1 << 7), 7
414 	},
415 	{
416 		"MODE",	"H",	"CUSTOM",	"END",	NULL,
417 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
418 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
419 		 50,  44, 36, 28, 6, 5, (1 << 6), (1 << 5), 5
420 	},
421 	{
422 		"TOOL",	"I",	"i",	"I",	NULL,
423 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
424 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
425 		 99,  44, 36, 28, 6, 6, (1 << 6), (1 << 6), 6
426 	},
427 	{
428 		"V\\kern-1 AR",	"J",	"UPDIR",	"COPY",	NULL,
429 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
430 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
431 		  0,  92, 36, 28, 6, 7, (1 << 6), (1 << 7), 7
432 	},
433 	{
434 		"STO \\triangleright",	"K",	"RCL",	"CUT",	NULL,
435 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
436 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
437 		 50,  92, 36, 28, 7, 1, (1 << 7), (1 << 1), 1
438 	},
439 	{
440 		"NXT",	"L",	"PREV",	"PASTE",	NULL,
441 		UI_COLOR_WHITE, 10.0, CAIRO_FONT_WEIGHT_BOLD,
442 		UI_SHAPE_BUTTON_SMALL, 10.0, UI_LAYOUT_BELOW,
443 		 99,  92, 36, 28, 7, 2, (1 << 7), (1 << 2), 2
444 	},
445 	{
446 		NULL,	NULL,	NULL,	NULL,	NULL,
447 		UI_COLOR_SILVER, 0.0, 0,
448 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
449 		200,  38, 33, 33, 6, 1, (1 << 6), (1 << 1), 1
450 	},
451 	{
452 		NULL,	NULL,	NULL,	NULL,	NULL,
453 		UI_COLOR_SILVER, 0.0, 0,
454 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
455 		164,  66, 33, 33, 6, 2, (1 << 6), (1 << 2), 2
456 	},
457 	{
458 		NULL,	NULL,	NULL,	NULL,	NULL,
459 		UI_COLOR_SILVER, 0.0, 0,
460 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
461 		200,  94, 33, 33, 6, 3, (1 << 6), (1 << 3), 3
462 	},
463 	{
464 		NULL,	NULL,	NULL,	NULL,	NULL,
465 		UI_COLOR_SILVER, 0.0, 0,
466 		UI_SHAPE_BUTTON_ROUND, 0.0, 0,
467 		236,  66, 33, 33, 6, 4, (1 << 6), (1 << 4), 4
468 	},
469 	{
470 		"HIST",	"M",	"CMD",	"UNDO",	NULL,
471 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
472 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
473 		  0, 141, 46, 28, 4, 1, (1 << 4), (1 << 1), 1
474 	},
475 	{
476 		"EV\\kern-1 AL",	"N",	"PRG",	"CHARS",	NULL,
477 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
478 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
479 		 59, 141, 46, 28, 3, 1, (1 << 3), (1 << 1), 1
480 	},
481 	{
482 		"\\tick",	"O",	"MTRW",	"EQW",	NULL,
483 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
484 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
485 		119, 141, 46, 28, 2, 1, (1 << 2), (1 << 1), 1
486 	},
487 	{
488 		"S\\kern-1 Y\\kern-1 M\\kern-1 B",	"P",	"MTH",	"CAT",	NULL,
489 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
490 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
491 		179, 141, 46, 28, 1, 1, (1 << 1), (1 << 1), 1
492 	},
493 	{
494 		"\\arrowleftdblfull",	NULL,	"DEL", "CLEAR",	NULL,
495 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
496 		UI_SHAPE_BUTTON_NORMAL, 0.0, 0,
497 		238, 141, 46, 28, 0, 1, (1 << 0), (1 << 1), 1
498 	},
499 	{
500 		"Y\\super x\\/super",	"Q",	"\\math_e\\xsuperior",	"LN",	NULL,
501 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
502 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
503 		  0, 183, 46, 28, 4, 2, (1 << 4), (1 << 2), 2
504 	},
505 	{
506 		"\\radical\\overscore\\kern-7 X",	"R",
507 		"\\math_x\\twosuperior",
508 		"\\xsuperior\\kern-4\\math_radical\\overscore\\kern-5\\math_y",
509 		NULL,
510 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
511 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
512 		 59, 183, 46, 28, 3, 2, (1 << 3), (1 << 2), 2
513 	},
514 	{
515 		"SIN",	"S",	"ASIN",	"\\math_summation",	NULL,
516 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
517 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
518 		119, 183, 46, 28, 2, 2, (1 << 2), (1 << 2), 2
519 	},
520 	{
521 		"COS",	"T",	"ACOS",	"\\math_partialdiff",	NULL,
522 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
523 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
524 		179, 183, 46, 28, 1, 2, (1 << 1), (1 << 2), 2
525 	},
526 	{
527 		"TAN",	"U",	"ATAN",	"\\math_integral",	NULL,
528 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
529 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
530 		238, 183, 46, 28, 0, 2, (1 << 0), (1 << 2), 2
531 	},
532 	{
533 		"EEX",	"V",	"10\\xsuperior",	"LOG",	NULL,
534 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
535 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
536 		  0, 225, 46, 28, 4, 3, (1 << 4), (1 << 3), 3
537 	},
538 	{
539 		"+\\divisionslash\\minus",	"W",
540 		"\\math_notequal",
541 		"\\math_equal",
542 		NULL,
543 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
544 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
545 		 59, 225, 46, 28, 3, 3, (1 << 3), (1 << 3), 3
546 	},
547 	{
548 		"X",	"X",
549 		"\\math_lessequal",
550 		"\\math_less",
551 		NULL,
552 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
553 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
554 		119, 225, 46, 28, 2, 3, (1 << 2), (1 << 3), 3
555 	},
556 	{
557 		"1/X",	"Y",
558 		"\\math_greaterequal",
559 		"\\math_greater",
560 		NULL,
561 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
562 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT,
563 		179, 225, 46, 28, 1, 3, (1 << 1), (1 << 3), 3
564 	},
565 	{
566 		"\\divide",	"Z",	"ABS",	"ARG",	NULL,
567 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
568 		UI_SHAPE_BUTTON_NORMAL, 12.0, UI_LAYOUT_LEFT_NO_SPACE,
569 		238, 225, 46, 28, 0, 3, (1 << 0), (1 << 3), 3
570 	},
571 	{
572 		"ALPHA",	NULL,	"USER",	"ENTRY",	NULL,
573 		UI_COLOR_BLACK, 12.0, CAIRO_FONT_WEIGHT_BOLD,
574 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
575 		  0, 267, 46, 32, 0, 0,        0,        0, 4
576 	},
577 	{
578 		"7",	NULL,	"S.SLV",	"NUM.SLV",	NULL,
579 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
580 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
581 		 59, 267, 46, 32, 3, 4, (1 << 3), (1 << 4), 4
582 	},
583 	{
584 		"8",	NULL,	"EXP&LN",	"TRIG",	NULL,
585 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
586 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
587 		119, 267, 46, 32, 2, 4, (1 << 2), (1 << 4), 4
588 	},
589 	{
590 		"9",	NULL,	"FINANCE",	"TIME",	NULL,
591 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
592 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
593 		179, 267, 46, 32, 1, 4, (1 << 1), (1 << 4), 4
594 	},
595 	{
596 		"\\multiply",	NULL,	"[ ]",	"\" \"",	NULL,
597 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
598 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
599 		238, 267, 46, 32, 0, 4, (1 << 0), (1 << 4), 4
600 	},
601 	{
602 		"\\uparrowleft",	NULL,	NULL,	NULL,	NULL,
603 		UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
604 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
605 		  0, 313, 46, 32, 0, 0,        0,        0, 5
606 	},
607 	{
608 		"4",	NULL,	"CALC",	"ALG",	NULL,
609 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
610 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
611 		 59, 313, 46, 32, 3, 5, (1 << 3), (1 << 5), 5
612 	},
613 	{
614 		"5",	NULL,	"MATRICES",	"STAT",	NULL,
615 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
616 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
617 		119, 313, 46, 32, 2, 5, (1 << 2), (1 << 5), 5
618 	},
619 	{
620 		"6",	NULL,	"CONVERT",	"UNITS",	NULL,
621 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
622 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
623 		179, 313, 46, 32, 1, 5, (1 << 1), (1 << 5), 5
624 	},
625 	{
626 		"\\minus",	NULL,	"( )",	"_",	NULL,
627 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
628 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
629 		238, 313, 46, 32, 0, 5, (1 << 0), (1 << 5), 5
630 	},
631 	{
632 		"\\uparrowright",	NULL,	NULL,	NULL,	NULL,
633 		UI_COLOR_BLACK, 19.0, CAIRO_FONT_WEIGHT_BOLD,
634 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
635 		  0, 359, 46, 32, 0, 0,        0,        0, 6
636 	},
637 	{
638 		"1",	NULL,	"ARITH",	"CMPLX",	NULL,
639 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
640 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
641 		 59, 359, 46, 32, 3, 6, (1 << 3), (1 << 6), 6
642 	},
643 	{
644 		"2",	NULL,	"DEF",	"LIB",	NULL,
645 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
646 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
647 		119, 359, 46, 32, 2, 6, (1 << 2), (1 << 6), 6
648 	},
649 	{
650 		"3",	NULL,	"\\math_numbersign",	"BASE",	NULL,
651 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
652 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
653 		179, 359, 46, 32, 1, 6, (1 << 1), (1 << 6), 6
654 	},
655 	{
656 		"+",	NULL,
657 		"{ }",
658 		"\\guillemotleft\\ \\guillemotright",
659 		NULL,
660 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
661 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
662 		238, 359, 46, 32, 0, 6, (1 << 0), (1 << 6), 6
663 	},
664 	{
665 		"ON",	NULL,	"CONT",	"OFF",	"CANCEL",
666 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
667 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
668 		  0, 405, 46, 32, 0, 0,        0,        0, 0
669 	},
670 	{
671 		"0",	NULL,
672 		"\\math_infinity",
673 		"\\math_arrowright",
674 		NULL,
675 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
676 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
677 		 59, 405, 46, 32, 3, 7, (1 << 3), (1 << 7), 7
678 	},
679 	{
680 		"\\bullet",	NULL,
681 		": :",
682 		"\\math_downarrowleft",
683 		NULL,
684 		UI_COLOR_WHITE, 19.0, CAIRO_FONT_WEIGHT_BOLD,
685 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
686 		119, 405, 46, 32, 2, 7, (1 << 2), (1 << 7), 7
687 	},
688 	{
689 		"SPC",	NULL,
690 		"\\math_pi",
691 		"\\large_comma",
692 		NULL,
693 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
694 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
695 		179, 405, 46, 32, 1, 7, (1 << 1), (1 << 7), 7
696 	},
697 	{
698 		"ENTER",	NULL,	"ANS",	"\\arrowright NUM",	NULL,
699 		UI_COLOR_WHITE, 12.0, CAIRO_FONT_WEIGHT_BOLD,
700 		UI_SHAPE_BUTTON_LARGE, 0.0, 0,
701 		238, 405, 46, 32, 0, 7, (1 << 0), (1 << 7), 7
702 	},
703 };
704 #define X50G_UI_NR_KEYS (sizeof(x50g_ui_keys) / sizeof(x50g_ui_keys[0]))
705 
706 static void
x49gp_ui_color_init(GdkColor * color,u8 red,u8 green,u8 blue)707 x49gp_ui_color_init(GdkColor *color, u8 red, u8 green, u8 blue)
708 {
709 	color->red = (red << 8) | red;
710 	color->green = (green << 8) | green;
711 	color->blue = (blue << 8) | blue;
712 }
713 
714 static void
x49gp_ui_style_init(GtkStyle * style,GtkWidget * widget,GdkColor * fg,GdkColor * bg)715 x49gp_ui_style_init(GtkStyle *style, GtkWidget *widget,
716 		    GdkColor *fg, GdkColor *bg)
717 {
718 	int i;
719 
720 	for (i = 0; i < 5; i++) {
721 		style->fg[i] = *fg;
722 		style->bg[i] = *bg;
723 
724 		style->text[i] = style->fg[i];
725 		style->base[i] = style->bg[i];
726 	}
727 
728 	style->xthickness = 0;
729 	style->ythickness = 0;
730 }
731 
732 static int
x49gp_ui_button_pixmaps_init(x49gp_t * x49gp,x49gp_ui_button_t * button,x49gp_ui_color_t color)733 x49gp_ui_button_pixmaps_init(x49gp_t *x49gp, x49gp_ui_button_t *button,
734 			     x49gp_ui_color_t color)
735 {
736 	x49gp_ui_t *ui = x49gp->ui;
737 	GdkPixbuf *src, *dst;
738 	GtkStyle *style;
739 	int i;
740 
741 	style = gtk_style_new();
742 	x49gp_ui_style_init(style, button->button,
743 			    &ui->colors[button->key->color],
744 			    &ui->colors[UI_COLOR_BLACK]);
745 
746 	for (i = 0; i < 5; i++) {
747 		style->bg_pixmap[i] = gdk_pixmap_new(ui->window->window,
748 						     button->key->width,
749 						     button->key->height, -1);
750 
751 		if (i == GTK_STATE_ACTIVE) {
752 			if (color == UI_COLOR_SILVER) {
753 				GError *gerror = NULL;
754 
755 				src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
756 					       ui->kb_x_offset + button->key->x,
757 					       ui->kb_y_offset + button->key->y,
758 					       button->key->width,
759 					       button->key->height);
760 				dst = gdk_pixbuf_copy(src);
761 				g_object_unref(src);
762 
763 				src = gdk_pixbuf_new_from_inline(sizeof(button_round),
764 						button_round, FALSE, &gerror);
765 
766 				gdk_pixbuf_composite(src, dst,
767 						0, 0,
768 						button->key->width,
769 						button->key->height,
770 						0.0, 0.0, 1.0, 1.0,
771 						GDK_INTERP_HYPER, 0xff);
772 
773 				g_object_unref(src);
774 				src = dst;
775 			} else {
776 				src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
777 					       ui->kb_x_offset + button->key->x,
778 					       ui->kb_y_offset + button->key->y + 1,
779 					       button->key->width,
780 					       button->key->height);
781 			}
782 		} else {
783 			src = gdk_pixbuf_new_subpixbuf(ui->bg_pixbuf,
784 					       ui->kb_x_offset + button->key->x,
785 					       ui->kb_y_offset + button->key->y,
786 					       button->key->width,
787 					       button->key->height);
788 		}
789 
790 		gdk_draw_pixbuf(style->bg_pixmap[i],
791 				ui->window->style->black_gc,
792 				src, 0, 0, 0, 0,
793 				button->key->width, button->key->height,
794 				GDK_RGB_DITHER_NORMAL, 0, 0);
795 
796 		g_object_unref(src);
797 	}
798 
799 	gtk_widget_set_style(button->button, style);
800 	return 0;
801 }
802 
803 static void
x49gp_ui_symbol_path(cairo_t * cr,double size,double xoffset,double yoffset,const x49gp_symbol_t * symbol)804 x49gp_ui_symbol_path(cairo_t *cr, double size,
805 		     double xoffset, double yoffset,
806 		     const x49gp_symbol_t *symbol)
807 {
808 	const symbol_path_t *path;
809 	const cairo_path_data_t *data;
810 	int i;
811 
812 	path = symbol->path;
813 	if (NULL == path) {
814 		return;
815 	}
816 
817 	cairo_move_to(cr, xoffset, yoffset);
818 
819 	for (i = 0; i < path->num_data; i += path->data[i].header.length) {
820 		data = &path->data[i];
821 
822 		switch (data->header.type) {
823 		case CAIRO_PATH_MOVE_TO:
824 			cairo_rel_move_to(cr, size * data[1].point.x,
825 					      -size * data[1].point.y);
826 			break;
827 		case CAIRO_PATH_LINE_TO:
828 			cairo_rel_line_to(cr, size * data[1].point.x,
829 					      -size * data[1].point.y);
830 			break;
831 		case CAIRO_PATH_CURVE_TO:
832 			cairo_rel_curve_to(cr, size * data[1].point.x,
833 					       -size * data[1].point.y,
834 					       size * data[2].point.x,
835 					       -size * data[2].point.y,
836 					       size * data[3].point.x,
837 					       -size * data[3].point.y);
838 			break;
839 		case CAIRO_PATH_CLOSE_PATH:
840 			cairo_close_path(cr);
841 			break;
842 		}
843 	}
844 }
845 
846 static void
x49gp_ui_draw_symbol(cairo_t * cr,GdkColor * color,double size,double line_width,gboolean fill,double xoffset,double yoffset,const x49gp_symbol_t * symbol)847 x49gp_ui_draw_symbol(cairo_t *cr, GdkColor *color, double size,
848 		     double line_width, gboolean fill,
849 		     double xoffset, double yoffset,
850 		     const x49gp_symbol_t *symbol)
851 {
852 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
853 	cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
854 	cairo_set_line_width(cr, line_width);
855 	cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
856 				 ((double) color->green) / 65535.0,
857 				 ((double) color->blue) / 65535.0);
858 
859 	x49gp_ui_symbol_path(cr, size, xoffset, yoffset, symbol);
860 
861 	if (fill) {
862 		cairo_fill(cr);
863 	} else {
864 		cairo_stroke(cr);
865 	}
866 }
867 
868 static int
x49gp_ui_lookup_glyph(const char * name,int namelen,gunichar * glyph)869 x49gp_ui_lookup_glyph(const char *name, int namelen, gunichar *glyph)
870 {
871 	int i;
872 
873 	for (i = 0; i < NR_GLYPHNAMES; i++) {
874 		if ((strlen(x49gp_glyphs[i].name) == namelen) &&
875 		    !strncmp(x49gp_glyphs[i].name, name, namelen)) {
876 			if (glyph)
877 				*glyph = x49gp_glyphs[i].unichar;
878 			return 1;
879 		}
880 	}
881 
882 	return 0;
883 }
884 
885 static int
x49gp_text_strlen(const char * text)886 x49gp_text_strlen(const char *text)
887 {
888 	const char *p, *q;
889 	char c;
890 	int namelen;
891 	int n = 0;
892 
893 	p = text;
894 	while ((c = *p++)) {
895 		if (c != '\\') {
896 			n++;
897 			continue;
898 		}
899 
900 		q = p;
901 		while (*q) {
902 			if ((*q == '\\') || (*q == ' '))
903 				break;
904 			q++;
905 		}
906 		if (q == p) {
907 			n++;
908 			p++;
909 			continue;
910 		}
911 		namelen = q - p;
912 		if (*q == ' ')
913 			q++;
914 
915 		if (symbol_lookup_glyph_by_name(p, namelen, NULL)) {
916 			p = q;
917 			n++;
918 			continue;
919 		}
920 
921 		if (x49gp_ui_lookup_glyph(p, namelen, NULL)) {
922 			p = q;
923 			n++;
924 			continue;
925 		}
926 
927 		/*
928 		 * Insert symbol .notdef here...
929 		 */
930 		p = q;
931 		n++;
932 	}
933 
934 	return n;
935 }
936 
937 static int
x49gp_text_to_ucs4(const char * text,gunichar ** ucs4p)938 x49gp_text_to_ucs4(const char *text, gunichar **ucs4p)
939 {
940 	const char *p, *q;
941 	gunichar glyph;
942 	gunichar *ucs4;
943 	char c;
944 	int namelen;
945 	int i, n;
946 
947 	n = x49gp_text_strlen(text);
948 	if (n <= 0)
949 		return n;
950 
951 	ucs4 = malloc(n * sizeof(gunichar));
952 
953 	i = 0;
954 
955 	p = text;
956 	while ((c = *p++)) {
957 		if (i == n) {
958 			free(ucs4);
959 			return -1;
960 		}
961 
962 		if (c != '\\') {
963 			ucs4[i++] = c;
964 			continue;
965 		}
966 
967 		q = p;
968 		while (*q) {
969 			if ((*q == '\\') || (*q == ' '))
970 				break;
971 			q++;
972 		}
973 		if (q == p) {
974 			ucs4[i++] = *p++;
975 			continue;
976 		}
977 		namelen = q - p;
978 		if (*q == ' ')
979 			q++;
980 
981 		if (symbol_lookup_glyph_by_name(p, namelen, &glyph)) {
982 			ucs4[i++] = glyph;
983 			p = q;
984 			continue;
985 		}
986 
987 		if (x49gp_ui_lookup_glyph(p, namelen, &glyph)) {
988 			ucs4[i++] = glyph;
989 			p = q;
990 			continue;
991 		}
992 
993 		/*
994 		 * Insert symbol .notdef here...
995 		 */
996 		ucs4[i++] = 0xe000;
997 		p = q;
998 	}
999 
1000 	*ucs4p = ucs4;
1001 	return n;
1002 }
1003 
1004 static void
x49gp_ui_vtext_path(cairo_t * cr,const char * family,double size,double x,double y,int n,va_list ap)1005 x49gp_ui_vtext_path(cairo_t *cr, const char *family, double size,
1006 		    double x, double y, int n, va_list ap)
1007 {
1008 	cairo_text_extents_t extents;
1009 	cairo_font_weight_t weight;
1010 	cairo_font_slant_t slant;
1011 	const x49gp_symbol_t *symbol;
1012 	const char *text;
1013 	gunichar *ucs4;
1014 	char out[8];
1015 	int bytes;
1016 	int i, j, len;
1017 
1018 	for (i = 0; i < n; i++) {
1019 		slant = va_arg(ap, cairo_font_slant_t);
1020 		weight = va_arg(ap, cairo_font_weight_t);
1021 		text = va_arg(ap, const char *);
1022 
1023 		cairo_select_font_face(cr, family, slant, weight);
1024 		cairo_set_font_size(cr, size);
1025 
1026 		ucs4 = NULL;
1027 		len = x49gp_text_to_ucs4(text, &ucs4);
1028 		if (len <= 0) {
1029 			continue;
1030 		}
1031 
1032 		for (j = 0; j < len; j++) {
1033 			if (g_unichar_type(ucs4[j]) == G_UNICODE_PRIVATE_USE) {
1034 				/*
1035 				 * Draw Symbol, Increment x...
1036 				 */
1037 				symbol = symbol_get_by_glyph(ucs4[j]);
1038 				if (NULL == symbol)
1039 					symbol = symbol_get_by_glyph(0xe000);
1040 
1041 				size *= symbol->prescale;
1042 
1043 				x49gp_ui_symbol_path(cr, size, x, y, symbol);
1044 
1045 				x += size * symbol->x_advance;
1046 				y -= size * symbol->y_advance;
1047 
1048 				size *= symbol->postscale;
1049 
1050 				if (symbol->prescale * symbol->postscale != 1.)
1051 					cairo_set_font_size(cr, size);
1052 
1053 				continue;
1054 			}
1055 
1056 			bytes = g_unichar_to_utf8(ucs4[j], out);
1057 			out[bytes] = '\0';
1058 
1059 			cairo_text_extents(cr, out, &extents);
1060 
1061 			cairo_move_to(cr, x, y);
1062 
1063 			cairo_text_path(cr, out);
1064 
1065 			x += extents.x_advance;
1066 			y += extents.y_advance;
1067 		}
1068 
1069 		free(ucs4);
1070 	}
1071 }
1072 
1073 static void
x49gp_ui_text_size(cairo_t * cr,const char * family,double size,double * x_bearing,double * y_bearing,double * width,double * height,double * ascent,double * descent,int n,...)1074 x49gp_ui_text_size(cairo_t *cr, const char *family, double size,
1075 		   double *x_bearing, double *y_bearing,
1076 		   double *width, double *height,
1077 		   double *ascent, double *descent,
1078 		   int n, ...)
1079 {
1080 	va_list ap;
1081 	cairo_font_extents_t font_extents;
1082 	cairo_font_weight_t weight;
1083 	cairo_font_slant_t slant;
1084 	double x1, y1, x2, y2, a, d;
1085 	const char *text;
1086 	int i;
1087 
1088 	if (n < 1)
1089 		return;
1090 
1091 	va_start(ap, n);
1092 
1093 	x49gp_ui_vtext_path(cr, family, size, 0.0, 0.0, n, ap);
1094 
1095 	cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
1096 
1097 	if (y2 < 0.0)
1098 		y2 = 0.0;
1099 
1100 	a = 0.0;
1101 	d = 0.0;
1102 
1103 	for (i = 0; i < n; i++) {
1104 		slant = va_arg(ap, cairo_font_slant_t);
1105 		weight = va_arg(ap, cairo_font_weight_t);
1106 		text = va_arg(ap, const char *);
1107 
1108 		cairo_select_font_face(cr, family, slant, weight);
1109 		cairo_set_font_size(cr, size);
1110 
1111 		cairo_font_extents(cr, &font_extents);
1112 
1113 		/*
1114 		 * Cairo seems to return overall height in ascent,
1115 		 * so fix this by calculating ascent = height - descent.
1116 		 */
1117 		if (font_extents.ascent - font_extents.descent > a)
1118 			a = font_extents.ascent - font_extents.descent;
1119 		if (font_extents.descent > -d)
1120 			d = -font_extents.descent;
1121 	}
1122 
1123 	*x_bearing = x1;
1124 	*y_bearing = y2;
1125 	*width = x2 - x1;
1126 	*height = y2 - y1;
1127 	*ascent = a;
1128 	*descent = d;
1129 
1130 	va_end(ap);
1131 }
1132 
1133 static void
x49gp_ui_draw_text(cairo_t * cr,GdkColor * color,const char * family,double size,double line_width,int xoffset,int yoffset,int n,...)1134 x49gp_ui_draw_text(cairo_t *cr, GdkColor *color,
1135 		   const char *family, double size, double line_width,
1136 		   int xoffset, int yoffset, int n, ...)
1137 {
1138 	va_list ap;
1139 
1140 	if (n < 1)
1141 		return;
1142 
1143 	va_start(ap, n);
1144 
1145 	cairo_set_line_width(cr, line_width);
1146 	cairo_set_source_rgb(cr, ((double) color->red) / 65535.0,
1147 				 ((double) color->green) / 65535.0,
1148 				 ((double) color->blue) / 65535.0);
1149 
1150 	x49gp_ui_vtext_path(cr, family, size, xoffset, yoffset, n, ap);
1151 
1152 	if (line_width == 0.0)
1153 		cairo_fill(cr);
1154 	else
1155 		cairo_stroke(cr);
1156 
1157 	va_end(ap);
1158 }
1159 
1160 #if 0
1161 static void
1162 x49gp_ui_dump_path(cairo_t *cr, const char *family, int n, ...)
1163 {
1164 	va_list ap;
1165 	const cairo_path_t *path;
1166 	const cairo_path_data_t *data;
1167 	int i;
1168 
1169 	if (n < 1)
1170 		return;
1171 
1172 	va_start(ap, n);
1173 
1174 	x49gp_ui_vtext_path(cr, family, 1000.0, 0.0, 0.0, n, ap);
1175 
1176 	path = cairo_copy_path(cr);
1177 	if (NULL == path) {
1178 		return;
1179 	}
1180 	cairo_new_path(cr);
1181 
1182 	for (i = 0; i < path->num_data; i += path->data[i].header.length) {
1183 		data = &path->data[i];
1184 
1185 		switch (data->header.type) {
1186 		case CAIRO_PATH_MOVE_TO:
1187 			printf("path: move to  %4.0f %4.0f\n",
1188 				data[1].point.x, -data[1].point.y);
1189 			break;
1190 		case CAIRO_PATH_LINE_TO:
1191 			printf("path: line to  %4.0f %4.0f\n",
1192 				data[1].point.x, -data[1].point.y);
1193 			break;
1194 		case CAIRO_PATH_CURVE_TO:
1195 			printf("path: curve to %4.0f %4.0f\n"
1196 			       "               %4.0f %4.0f\n"
1197 			       "               %4.0f %4.0f\n",
1198 				data[1].point.x, -data[1].point.y,
1199 				data[2].point.x, -data[2].point.y,
1200 				data[3].point.x, -data[3].point.y);
1201 			break;
1202 		case CAIRO_PATH_CLOSE_PATH:
1203 			printf("path: close path\n");
1204 			break;
1205 		}
1206 	}
1207 
1208 	va_end(ap);
1209 }
1210 #endif
1211 
1212 static unsigned char
bitmap_font_lookup_glyph(const bitmap_font_t * font,const char * name,int namelen)1213 bitmap_font_lookup_glyph(const bitmap_font_t *font,
1214 			 const char *name, int namelen)
1215 {
1216 	int i;
1217 
1218 	for (i = 0; font->glyphs[i].name; i++) {
1219 		if ((strlen(font->glyphs[i].name) == namelen) &&
1220 		    !strncmp(font->glyphs[i].name, name, namelen)) {
1221 			return i;
1222 		}
1223 	}
1224 
1225 	return 0;
1226 }
1227 
1228 static unsigned char
bitmap_font_lookup_ascii(const bitmap_font_t * font,char c)1229 bitmap_font_lookup_ascii(const bitmap_font_t *font, char c)
1230 {
1231 	int namelen = 0;
1232 	char *name;
1233 
1234 	switch (c) {
1235 	case ' ': name = "space"; break;
1236 	case '!': name = "exclam"; break;
1237 	case '"': name = "quotedbl"; break;
1238 	case '#': name = "numbersign"; break;
1239 	case '$': name = "dollar"; break;
1240 	case '%': name = "percent"; break;
1241 	case '&': name = "ampersand"; break;
1242 	case '(': name = "parenleft"; break;
1243 	case ')': name = "parenright"; break;
1244 	case '*': name = "asterisk"; break;
1245 	case '+': name = "plus"; break;
1246 	case ',': name = "comma"; break;
1247 	case '-': name = "hyphen"; break;
1248 	case '.': name = "period"; break;
1249 	case '/': name = "slash"; break;
1250 	case '0': name = "zero"; break;
1251 	case '1': name = "one"; break;
1252 	case '2': name = "two"; break;
1253 	case '3': name = "three"; break;
1254 	case '4': name = "four"; break;
1255 	case '5': name = "five"; break;
1256 	case '6': name = "six"; break;
1257 	case '7': name = "seven"; break;
1258 	case '8': name = "eight"; break;
1259 	case '9': name = "nine"; break;
1260 	case ':': name = "colon"; break;
1261 	case ';': name = "semicolon"; break;
1262 	case '<': name = "less"; break;
1263 	case '=': name = "equal"; break;
1264 	case '>': name = "greater"; break;
1265 	case '?': name = "question"; break;
1266 	case '@': name = "at"; break;
1267 	case '[': name = "bracketleft"; break;
1268 	case '\\': name = "backslash"; break;
1269 	case ']': name = "bracketright"; break;
1270 	case '^': name = "asciicircum"; break;
1271 	case '_': name = "underscore"; break;
1272 	case '`': name = "quoteleft"; break;
1273 	case '{': name = "braceleft"; break;
1274 	case '|': name = "bar"; break;
1275 	case '}': name = "braceright"; break;
1276 	case '~': name = "asciitilde"; break;
1277 	default:
1278 		  name = &c;
1279 		  namelen = 1;
1280 		  break;
1281 	}
1282 
1283 	if (0 == namelen)
1284 		namelen = strlen(name);
1285 
1286 	return bitmap_font_lookup_glyph(font, name, namelen);
1287 }
1288 
1289 static int
bitmap_font_strlen(const char * text)1290 bitmap_font_strlen(const char *text)
1291 {
1292 	const char *p, *q;
1293 	char c;
1294 	int n = 0;
1295 
1296 	p = text;
1297 	while ((c = *p++)) {
1298 		if (c != '\\') {
1299 			n++;
1300 			continue;
1301 		}
1302 
1303 		q = p;
1304 		while (*q) {
1305 			if ((*q == '\\') || (*q == ' '))
1306 				break;
1307 			q++;
1308 		}
1309 		if (q == p) {
1310 			n++;
1311 			p++;
1312 			continue;
1313 		}
1314 		if (*q == ' ')
1315 			q++;
1316 
1317 		n++;
1318 		p = q;
1319 	}
1320 
1321 	return n;
1322 }
1323 
1324 static int
bitmap_font_text_to_glyphs(const bitmap_font_t * font,const char * text,unsigned char ** glyphp)1325 bitmap_font_text_to_glyphs(const bitmap_font_t *font,
1326 			   const char *text, unsigned char **glyphp)
1327 {
1328 	unsigned char *glyphs;
1329 	const char *p, *q;
1330 	unsigned char c;
1331 	int namelen;
1332 	int i, n;
1333 
1334 	n = bitmap_font_strlen(text);
1335 	if (n <= 0)
1336 		return n;
1337 
1338 	glyphs = malloc(n);
1339 
1340 	i = 0;
1341 
1342 	p = text;
1343 	while ((c = *p++)) {
1344 		if (i == n) {
1345 			free(glyphs);
1346 			return -1;
1347 		}
1348 
1349 		if (c != '\\') {
1350 			glyphs[i++] = bitmap_font_lookup_ascii(font, c);
1351 			continue;
1352 		}
1353 
1354 		q = p;
1355 		while (*q) {
1356 			if ((*q == '\\') || (*q == ' '))
1357 				break;
1358 			q++;
1359 		}
1360 		if (q == p) {
1361 			glyphs[i++] = bitmap_font_lookup_ascii(font, *p++);
1362 			continue;
1363 		}
1364 		namelen = q - p;
1365 		if (*q == ' ')
1366 			q++;
1367 
1368 		glyphs[i++] = bitmap_font_lookup_glyph(font, p, namelen);
1369 		p = q;
1370 	}
1371 
1372 	*glyphp = glyphs;
1373 	return n;
1374 
1375 }
1376 
1377 static void
bitmap_font_text_size(const bitmap_font_t * font,const char * text,int * width,int * height,int * ascent,int * descent)1378 bitmap_font_text_size(const bitmap_font_t *font, const char *text,
1379 		      int *width, int *height, int *ascent, int *descent)
1380 {
1381 	const bitmap_glyph_t *glyph;
1382 	unsigned char *glyphs;
1383 	int i, n, w, a, d;
1384 
1385 	w = 0;
1386 	a = 0;
1387 	d = 0;
1388 
1389 	n = bitmap_font_text_to_glyphs(font, text, &glyphs);
1390 
1391 	for (i = 0; i < n; i++) {
1392 		glyph = &font->glyphs[glyphs[i]];
1393 
1394 		w += glyph->width;
1395 
1396 		if (glyph->ascent > a)
1397 			a = glyph->ascent;
1398 		if (glyph->descent < d)
1399 			d = glyph->descent;
1400 	}
1401 
1402 	*width = w - 1;
1403 	*height = font->ascent - font->descent;
1404 	*ascent = a;
1405 	*descent = d;
1406 
1407 	if (n > 0) {
1408 		free(glyphs);
1409 	}
1410 }
1411 
1412 static void
bitmap_font_draw_text(GdkDrawable * drawable,GdkColor * color,const bitmap_font_t * font,int x,int y,const char * text)1413 bitmap_font_draw_text(GdkDrawable *drawable, GdkColor *color,
1414 		      const bitmap_font_t *font,
1415 		      int x, int y, const char *text)
1416 {
1417 	const bitmap_glyph_t *glyph;
1418 	unsigned char *glyphs;
1419 	GdkBitmap *bitmap;
1420 	GdkGC *gc;
1421 	int i, n, w, h;
1422 
1423 	gc = gdk_gc_new(drawable);
1424 	gdk_gc_set_rgb_fg_color(gc, color);
1425 
1426 	n = bitmap_font_text_to_glyphs(font, text, &glyphs);
1427 
1428 	for (i = 0; i < n; i++) {
1429 		glyph = &font->glyphs[glyphs[i]];
1430 
1431 		w = glyph->width - glyph->kern;
1432 		h = glyph->ascent - glyph->descent;
1433 
1434 		if (w <= 0 || h <= 0) {
1435 			x += glyph->width;
1436 			continue;
1437 		}
1438 
1439 		bitmap = gdk_bitmap_create_from_data(NULL, (char *) glyph->bits, w, h);
1440 
1441 		gdk_gc_set_ts_origin(gc, x + glyph->kern,
1442 				     y + font->ascent - glyph->ascent);
1443 		gdk_gc_set_stipple(gc, bitmap);
1444 		gdk_gc_set_fill(gc, GDK_STIPPLED);
1445 
1446 		gdk_draw_rectangle(drawable, gc, TRUE, x + glyph->kern,
1447 				   y + font->ascent - glyph->ascent, w, h);
1448 
1449 		g_object_unref(bitmap);
1450 
1451 		x += glyph->width;
1452 	}
1453 
1454 	g_object_unref(gc);
1455 
1456 	if (n > 0) {
1457 		free(glyphs);
1458 	}
1459 }
1460 
1461 static gboolean
x49gp_ui_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1462 x49gp_ui_button_press(GtkWidget *widget, GdkEventButton *event,
1463 		      gpointer user_data)
1464 {
1465 	x49gp_ui_button_t *button = user_data;
1466 	const x49gp_ui_key_t *key = button->key;
1467 	x49gp_t *x49gp = button->x49gp;
1468 
1469 #ifdef DEBUG_X49GP_UI
1470 fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
1471 #endif
1472 
1473 	if (event->type != GDK_BUTTON_PRESS)
1474 		return FALSE;
1475 
1476 	switch (event->button) {
1477 	case 1:
1478 		button->down = TRUE;
1479 		break;
1480 	case 3:
1481 		if (!button->down) {
1482 			gtk_button_pressed(GTK_BUTTON(button->button));
1483 		}
1484 		button->down = TRUE;
1485 		button->hold = TRUE;
1486 		break;
1487 	default:
1488 		return TRUE;
1489 	}
1490 
1491 #ifdef DEBUG_X49GP_UI
1492 	printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
1493 		event->button,
1494 		button->key->column, button->key->row, button->key->eint);
1495 #endif
1496 
1497 	if (key->rowbit) {
1498 		s3c2410_io_port_g_set_bit(x49gp, key->eint, 1);
1499 		x49gp->keybycol[key->column] |= key->rowbit;
1500 		x49gp->keybyrow[key->row] |= key->columnbit;
1501 	} else {
1502 		s3c2410_io_port_f_set_bit(x49gp, key->eint, 1);
1503 	}
1504 
1505 	return FALSE;
1506 }
1507 
1508 static gboolean
x49gp_ui_button_release(GtkWidget * widget,GdkEventButton * event,gpointer user_data)1509 x49gp_ui_button_release(GtkWidget *widget, GdkEventButton *event,
1510 			gpointer user_data)
1511 {
1512 	x49gp_ui_button_t *button = user_data;
1513 	x49gp_t *x49gp = button->x49gp;
1514 	x49gp_ui_t *ui = x49gp->ui;
1515 	const x49gp_ui_key_t *key;
1516 	GtkButton *gtkbutton;
1517 	int i;
1518 
1519 	if (event->type != GDK_BUTTON_RELEASE)
1520 		return FALSE;
1521 
1522 	switch (event->button) {
1523 	case 1:
1524 		break;
1525 	default:
1526 		return TRUE;
1527 	}
1528 
1529 	for (i = 0; i < ui->nr_buttons; i++) {
1530 		button = &ui->buttons[i];
1531 
1532 		if (! button->down)
1533 			continue;
1534 
1535 #ifdef DEBUG_X49GP_UI
1536 		printf("%s: button %u: col %u, row %u, eint %u\n", __FUNCTION__,
1537 			event->button,
1538 			button->key->column, button->key->row, button->key->eint);
1539 #endif
1540 
1541 		button->down = FALSE;
1542 		button->hold = FALSE;
1543 
1544 		gtkbutton = GTK_BUTTON(button->button);
1545 
1546 		if (button != user_data)
1547 			gtkbutton->in_button = FALSE;
1548 		gtk_button_released(gtkbutton);
1549 
1550 		key = button->key;
1551 
1552 		if (key->rowbit) {
1553 			s3c2410_io_port_g_set_bit(x49gp, key->eint, 0);
1554 			x49gp->keybycol[key->column] &= ~(key->rowbit);
1555 			x49gp->keybyrow[key->row] &= ~(key->columnbit);
1556 		} else {
1557 			s3c2410_io_port_f_set_bit(x49gp, key->eint, 0);
1558 		}
1559 	}
1560 
1561 	return FALSE;
1562 }
1563 
1564 static gboolean
x49gp_ui_button_leave(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)1565 x49gp_ui_button_leave(GtkWidget *widget, GdkEventCrossing *event,
1566 		      gpointer user_data)
1567 {
1568 	x49gp_ui_button_t *button = user_data;
1569 
1570 	if (event->type != GDK_LEAVE_NOTIFY)
1571 		return FALSE;
1572 
1573 	if (!button->hold)
1574 		return FALSE;
1575 
1576 	return TRUE;
1577 }
1578 
1579 static gboolean
x49gp_ui_key_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1580 x49gp_ui_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
1581 {
1582 	x49gp_t *x49gp = user_data;
1583 	x49gp_ui_t *ui = x49gp->ui;
1584 	x49gp_ui_button_t *button;
1585 	GdkEventButton bev;
1586 	gboolean save_in;
1587 	int index;
1588 
1589 #ifdef DEBUG_X49GP_UI
1590 fprintf(stderr, "%s:%u: type %u, keyval %04x\n", __FUNCTION__, __LINE__, event->type, event->keyval);
1591 #endif
1592 
1593 	switch (event->keyval) {
1594 	case GDK_A: case GDK_a: case GDK_F1:	index = 0;	break;
1595 	case GDK_B: case GDK_b: case GDK_F2:	index = 1;	break;
1596 	case GDK_C: case GDK_c: case GDK_F3:	index = 2;	break;
1597 	case GDK_D: case GDK_d: case GDK_F4:	index = 3;	break;
1598 	case GDK_E: case GDK_e: case GDK_F5:	index = 4;	break;
1599 	case GDK_F: case GDK_f: case GDK_F6:	index = 5;	break;
1600 	case GDK_G: case GDK_g:			index = 6;	break;
1601 	case GDK_H: case GDK_h:			index = 7;	break;
1602 	case GDK_I: case GDK_i:			index = 8;	break;
1603 	case GDK_J: case GDK_j:			index = 9;	break;
1604 	case GDK_K: case GDK_k:			index = 10;	break;
1605 	case GDK_L: case GDK_l:			index = 11;	break;
1606 	case GDK_Up: case GDK_KP_Up:		index = 12;	break;
1607 	case GDK_Left: case GDK_KP_Left:	index = 13;	break;
1608 	case GDK_Down: case GDK_KP_Down:	index = 14;	break;
1609 	case GDK_Right: case GDK_KP_Right:	index = 15;	break;
1610 	case GDK_M: case GDK_m:			index = 16;	break;
1611 	case GDK_N: case GDK_n:			index = 17;	break;
1612 	case GDK_O: case GDK_o:
1613 	case GDK_apostrophe:			index = 18;	break;
1614 	case GDK_P: case GDK_p:			index = 19;	break;
1615 	case GDK_BackSpace: case GDK_Delete:
1616 	case GDK_KP_Delete:			index = 20;	break;
1617 	case GDK_Q: case GDK_q:			index = 21;	break;
1618 	case GDK_R: case GDK_r:			index = 22;	break;
1619 	case GDK_S: case GDK_s:			index = 23;	break;
1620 	case GDK_T: case GDK_t:			index = 24;	break;
1621 	case GDK_U: case GDK_u:			index = 25;	break;
1622 	case GDK_V: case GDK_v:			index = 26;	break;
1623 	case GDK_W: case GDK_w:			index = 27;	break;
1624 	case GDK_X: case GDK_x:			index = 28;	break;
1625 	case GDK_Y: case GDK_y:			index = 29;	break;
1626 	case GDK_Z: case GDK_z:
1627 	case GDK_slash: case GDK_KP_Divide:	index = 30;	break;
1628 #ifdef __APPLE__
1629 	case GDK_Tab:					index = 31;	break;
1630 #else
1631 	case GDK_Tab:					index = 31;	break;
1632 	case GDK_Alt_L: case GDK_Alt_R:
1633 	case GDK_Meta_L: case GDK_Meta_R:
1634 	case GDK_Mode_switch:			index = 31;	break;
1635 #endif
1636 	case GDK_7: case GDK_KP_7:		index = 32;	break;
1637 	case GDK_8: case GDK_KP_8:		index = 33;	break;
1638 	case GDK_9: case GDK_KP_9:		index = 34;	break;
1639 	case GDK_multiply: case GDK_backslash:
1640 	case GDK_KP_Multiply:			index = 35;	break;
1641 	case GDK_Shift_L:			index = 36;	break;
1642 	case GDK_4: case GDK_KP_4:		index = 37;	break;
1643 	case GDK_5: case GDK_KP_5:		index = 38;	break;
1644 	case GDK_6: case GDK_KP_6:		index = 39;	break;
1645 	case GDK_minus: case GDK_KP_Subtract:	index = 40;	break;
1646 	case GDK_Shift_R: case GDK_Control_L:	index = 41;	break;
1647 	case GDK_1: case GDK_KP_1:		index = 42;	break;
1648 	case GDK_2: case GDK_KP_2:		index = 43;	break;
1649 	case GDK_3: case GDK_KP_3:		index = 44;	break;
1650 	case GDK_plus: case GDK_equal:
1651 	case GDK_KP_Add:			index = 45;	break;
1652 	case GDK_Escape:			index = 46;	break;
1653 	case GDK_0: case GDK_KP_0:		index = 47;	break;
1654 	case GDK_period: case GDK_comma:
1655 	case GDK_KP_Decimal:			index = 48;	break;
1656 	case GDK_space: case GDK_KP_Space:	index = 49;	break;
1657 	case GDK_Return: case GDK_KP_Enter:	index = 50;	break;
1658 	default:
1659 		return FALSE;
1660 	}
1661 
1662 	button = &ui->buttons[index];
1663 
1664 	memset(&bev, 0, sizeof(GdkEventButton));
1665 
1666 	bev.time = event->time;
1667 	bev.button = 1;
1668 	bev.state = event->state;
1669 
1670 	save_in = GTK_BUTTON(button->button)->in_button;
1671 
1672 	switch (event->type) {
1673 	case GDK_KEY_PRESS:
1674 		bev.type = GDK_BUTTON_PRESS;
1675 		x49gp_ui_button_press(button->button, &bev, button);
1676 		GTK_BUTTON(button->button)->in_button = TRUE;
1677 		gtk_button_pressed(GTK_BUTTON(button->button));
1678 		GTK_BUTTON(button->button)->in_button = save_in;
1679 		break;
1680 	case GDK_KEY_RELEASE:
1681 		bev.type = GDK_BUTTON_RELEASE;
1682 		GTK_BUTTON(button->button)->in_button = TRUE;
1683 		gtk_button_released(GTK_BUTTON(button->button));
1684 		GTK_BUTTON(button->button)->in_button = save_in;
1685 		x49gp_ui_button_release(button->button, &bev, button);
1686 		break;
1687 	default:
1688 		return FALSE;
1689 	}
1690 
1691 	return TRUE;
1692 }
1693 
1694 static int
x49gp_button_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)1695 x49gp_button_expose_event(GtkWidget *widget, GdkEventExpose *event,
1696 			  gpointer user_data)
1697 {
1698 	x49gp_ui_button_t *button = user_data;
1699 	int x, y;
1700 
1701 	x = widget->allocation.x;
1702 	y = widget->allocation.y;
1703 
1704 	if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
1705 		y -= 1;
1706 
1707 	gdk_draw_drawable(widget->window, widget->style->black_gc,
1708 			  button->pixmap, 0, 0, x, y,
1709 			  widget->allocation.width, widget->allocation.height);
1710 
1711 	return FALSE;
1712 }
1713 
1714 static void
x49gp_button_realize(GtkWidget * widget,gpointer user_data)1715 x49gp_button_realize(GtkWidget *widget, gpointer user_data)
1716 {
1717 	x49gp_ui_button_t *button = user_data;
1718 	x49gp_ui_t *ui = button->x49gp->ui;
1719 	const x49gp_ui_key_t *key = button->key;
1720 	cairo_t *cr;
1721 	double xoff, yoff, width, height, ascent, descent;
1722 	unsigned int w, h;
1723 	int xoffset, yoffset, x, y;
1724 
1725 	xoffset = widget->allocation.x;
1726 	yoffset = widget->allocation.y;
1727 	w = widget->allocation.width;
1728 	h = widget->allocation.height;
1729 
1730 	button->pixmap = gdk_pixmap_new(widget->style->bg_pixmap[0], w, h, -1);
1731 
1732 	assert(button->pixmap);
1733 
1734 	gdk_draw_drawable(button->pixmap, widget->style->black_gc,
1735 			  widget->style->bg_pixmap[0],
1736 			  xoffset, yoffset,
1737 			  0, 0, button->key->width, button->key->height);
1738 
1739 	xoffset += 2;
1740 	yoffset += 2;
1741 	w -= 4;
1742 	h -= 4;
1743 
1744 	cr = gdk_cairo_create(button->pixmap);
1745 	assert(cr);
1746 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1747 	cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1748 
1749 #if 0	/* Layout Debug */
1750 	cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1751 	cairo_set_line_width(cr, 1.0);
1752 	cairo_move_to(cr, xoffset, yoffset);
1753 	cairo_line_to(cr, xoffset + w - 1, yoffset);
1754 	cairo_line_to(cr, xoffset + w - 1, yoffset + h - 1);
1755 	cairo_line_to(cr, xoffset, yoffset + h - 1);
1756 	cairo_close_path(cr);
1757 	cairo_stroke(cr);
1758 #endif
1759 
1760 	if (key->letter) {
1761 		x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->letter_size,
1762 				   &xoff, &yoff, &width, &height, &ascent, &descent,
1763 				   1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1764 				   key->letter);
1765 
1766 		switch (key->layout) {
1767 		case UI_LAYOUT_LEFT:
1768 		default:
1769 			x = (int) floor(w - 1.0 - width - xoff + 0.5);
1770 			y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1771 			w -= width;
1772 			break;
1773 		case UI_LAYOUT_LEFT_NO_SPACE:
1774 			x = (int) floor(w - 1.0 - width - xoff + 0.5);
1775 			y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1776 			break;
1777 		case UI_LAYOUT_BELOW:
1778 			x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
1779 			y = (int) h - 1.0;
1780 			h -= ascent;
1781 			break;
1782 		}
1783 
1784 		x49gp_ui_draw_text(cr, &ui->colors[UI_COLOR_YELLOW],
1785 				   X49GP_UI_NORMAL_FONT, key->letter_size, 0.0,
1786 				   x + xoffset, y + yoffset,
1787 				   1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1788 				   key->letter);
1789 	}
1790 
1791 	x49gp_ui_text_size(cr, X49GP_UI_NORMAL_FONT, key->font_size,
1792 			   &xoff, &yoff, &width, &height, &ascent, &descent,
1793 			   1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1794 			   key->label);
1795 
1796 	x = (int) floor((w - 1.0 - width) / 2.0 - xoff + 0.5);
1797 	y = (int) floor((h - 1.0 + ascent) / 2.0 + 0.5);
1798 
1799 	x49gp_ui_draw_text(cr, &widget->style->text[0],
1800 			   X49GP_UI_NORMAL_FONT, key->font_size, 0.0,
1801 			   x + xoffset, y + yoffset,
1802 			   1, CAIRO_FONT_SLANT_NORMAL, key->font_weight,
1803 			   key->label);
1804 
1805 	cairo_destroy(cr);
1806 }
1807 
1808 static int
x49gp_lcd_expose_event(GtkWidget * widget,GdkEventExpose * event,gpointer user_data)1809 x49gp_lcd_expose_event(GtkWidget *widget, GdkEventExpose *event,
1810 		       gpointer user_data)
1811 {
1812 	x49gp_t *x49gp = user_data;
1813 	x49gp_ui_t *ui = x49gp->ui;
1814 	GdkRectangle *rects;
1815 	int i, n;
1816 
1817 	gdk_region_get_rectangles(event->region, &rects, &n);
1818 	for (i = 0; i < n; i++) {
1819 		gdk_draw_drawable(widget->window, widget->style->black_gc,
1820 				  ui->lcd_pixmap,
1821 				  rects[i].x, rects[i].y,
1822 				  rects[i].x, rects[i].y,
1823 				  rects[i].width, rects[i].height);
1824 	}
1825 	g_free(rects);
1826 
1827 	return FALSE;
1828 }
1829 
1830 static int
x49gp_lcd_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)1831 x49gp_lcd_configure_event(GtkWidget *widget, GdkEventConfigure *event,
1832 			  gpointer user_data)
1833 {
1834 	x49gp_t *x49gp = user_data;
1835 	x49gp_ui_t *ui = x49gp->ui;
1836 
1837 	if (NULL != ui->lcd_pixmap) {
1838 		return FALSE;
1839 	}
1840 
1841 	ui->ann_left = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1842 						   (char *) ann_left_bits,
1843 						   ann_left_width,
1844 						   ann_left_height);
1845 	ui->ann_right = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1846 						    (char *) ann_right_bits,
1847 						    ann_right_width,
1848 						    ann_right_height);
1849 	ui->ann_alpha = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1850 						    (char *) ann_alpha_bits,
1851 						    ann_alpha_width,
1852 						    ann_alpha_height);
1853 	ui->ann_battery = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1854 						      (char *) ann_battery_bits,
1855 						      ann_battery_width,
1856 						      ann_battery_height);
1857 	ui->ann_busy = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1858 						   (char *) ann_busy_bits,
1859 						   ann_busy_width,
1860 						   ann_busy_height);
1861 	ui->ann_io = gdk_bitmap_create_from_data(ui->lcd_canvas->window,
1862 						 (char *) ann_io_bits,
1863 						 ann_io_width,
1864 						 ann_io_height);
1865 
1866 	ui->ann_left_gc = gdk_gc_new(ui->lcd_canvas->window);
1867 	gdk_gc_copy(ui->ann_left_gc, widget->style->black_gc);
1868 	gdk_gc_set_ts_origin(ui->ann_left_gc, 11, 0);
1869 	gdk_gc_set_stipple(ui->ann_left_gc, ui->ann_left);
1870 	gdk_gc_set_fill(ui->ann_left_gc, GDK_STIPPLED);
1871 
1872 	ui->ann_right_gc = gdk_gc_new(ui->lcd_canvas->window);
1873 	gdk_gc_copy(ui->ann_right_gc, widget->style->black_gc);
1874 	gdk_gc_set_ts_origin(ui->ann_right_gc, 56, 0);
1875 	gdk_gc_set_stipple(ui->ann_right_gc, ui->ann_right);
1876 	gdk_gc_set_fill(ui->ann_right_gc, GDK_STIPPLED);
1877 
1878 	ui->ann_alpha_gc = gdk_gc_new(ui->lcd_canvas->window);
1879 	gdk_gc_copy(ui->ann_alpha_gc, widget->style->black_gc);
1880 	gdk_gc_set_ts_origin(ui->ann_alpha_gc, 101, 0);
1881 	gdk_gc_set_stipple(ui->ann_alpha_gc, ui->ann_alpha);
1882 	gdk_gc_set_fill(ui->ann_alpha_gc, GDK_STIPPLED);
1883 
1884 	ui->ann_battery_gc = gdk_gc_new(ui->lcd_canvas->window);
1885 	gdk_gc_copy(ui->ann_battery_gc, widget->style->black_gc);
1886 	gdk_gc_set_ts_origin(ui->ann_battery_gc, 146, 0);
1887 	gdk_gc_set_stipple(ui->ann_battery_gc, ui->ann_battery);
1888 	gdk_gc_set_fill(ui->ann_battery_gc, GDK_STIPPLED);
1889 
1890 	ui->ann_busy_gc = gdk_gc_new(ui->lcd_canvas->window);
1891 	gdk_gc_copy(ui->ann_busy_gc, widget->style->black_gc);
1892 	gdk_gc_set_ts_origin(ui->ann_busy_gc, 191, 0);
1893 	gdk_gc_set_stipple(ui->ann_busy_gc, ui->ann_busy);
1894 	gdk_gc_set_fill(ui->ann_busy_gc, GDK_STIPPLED);
1895 
1896 	ui->ann_io_gc = gdk_gc_new(ui->lcd_canvas->window);
1897 	gdk_gc_copy(ui->ann_io_gc, widget->style->black_gc);
1898 	gdk_gc_set_ts_origin(ui->ann_io_gc, 236, 0);
1899 	gdk_gc_set_stipple(ui->ann_io_gc, ui->ann_io);
1900 	gdk_gc_set_fill(ui->ann_io_gc, GDK_STIPPLED);
1901 
1902 
1903 	ui->lcd_pixmap = gdk_pixmap_new(ui->lcd_canvas->window,
1904 					ui->lcd_width, ui->lcd_height, -1);
1905 
1906 #if 0 /* Debug Symbols on LCD screen ;) */
1907 {
1908 	cairo_t *cr;
1909 
1910 	cr = gdk_cairo_create(ui->bg_pixmap);
1911 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1912 	cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1913 
1914 #if 1
1915 	x49gp_ui_draw_text(cr, &widget->style->black,
1916 			   X49GP_UI_NORMAL_FONT, 100.0, 1.0,
1917 			   ui->lcd_x_offset + 10, ui->lcd_y_offset + 160,
1918 			   1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
1919 			   "\\arrowleftdblfull");
1920 #else
1921 	x49gp_ui_dump_path(cr, X49GP_UI_NORMAL_FONT,
1922 			   1, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD,
1923 			   "\\arrowleftdblfull");
1924 #endif
1925 
1926 	cairo_destroy(cr);
1927 }
1928 #endif
1929 
1930 	gdk_draw_drawable(ui->lcd_pixmap, widget->style->black_gc,
1931 			  ui->bg_pixmap, ui->lcd_x_offset, ui->lcd_y_offset,
1932 			  0, 0, ui->lcd_width, ui->lcd_height);
1933 
1934 	return FALSE;
1935 }
1936 
1937 static int
x49gp_window_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)1938 x49gp_window_configure_event(GtkWidget *widget, GdkEventConfigure *event,
1939 			     gpointer user_data)
1940 {
1941 	x49gp_t *x49gp = user_data;
1942 	x49gp_ui_t *ui = x49gp->ui;
1943 	const x49gp_ui_key_t *key;
1944 	cairo_t *cr;
1945 	int left_color;
1946 	int right_color;
1947 	int below_color;
1948 	int xl, xr, a;
1949 	int wl = 0, wr = 0;
1950 	int hl = 0, hr = 0;
1951 	int dl = 0, dr = 0;
1952 	int i;
1953 
1954 	if (NULL != ui->bg_pixmap) {
1955 		return FALSE;
1956 	}
1957 
1958 	ui->bg_pixmap = gdk_pixmap_new(widget->window,
1959 				       ui->width, ui->height, -1);
1960 
1961 	gdk_draw_pixbuf(ui->bg_pixmap, widget->style->black_gc,
1962 			ui->bg_pixbuf, 0, 0, 0, 0, ui->width, ui->height,
1963 			GDK_RGB_DITHER_NORMAL, 0, 0);
1964 
1965 	cr = gdk_cairo_create(ui->bg_pixmap);
1966 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
1967 	cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
1968 
1969 	switch (ui->calculator) {
1970 	default:
1971 		ui->calculator = UI_CALCULATOR_HP49GP;
1972 		/* fall through */
1973 
1974 	case UI_CALCULATOR_HP49GP:
1975 		x49gp_ui_draw_text(cr, &widget->style->black,
1976 				   X49GP_UI_NORMAL_FONT, 15.0, 0.0,
1977 				   38, 42, 2,
1978 				   CAIRO_FONT_SLANT_NORMAL,
1979 				   CAIRO_FONT_WEIGHT_BOLD,
1980 				   "hp",
1981 				   CAIRO_FONT_SLANT_NORMAL,
1982 				   CAIRO_FONT_WEIGHT_NORMAL,
1983 				   " 49g+");
1984 
1985 		x49gp_ui_draw_text(cr, &widget->style->black,
1986 				   X49GP_UI_NORMAL_FONT, 13.0, 0.0,
1987 				   38, 56, 1,
1988 				   CAIRO_FONT_SLANT_NORMAL,
1989 				   CAIRO_FONT_WEIGHT_NORMAL,
1990 				   "graphing calculator");
1991 
1992 		x49gp_ui_draw_symbol(cr, &widget->style->black, 10.0, 0.0, TRUE,
1993 				     138, 25, symbol_get_by_name("triangleup"));
1994 
1995 		left_color = UI_COLOR_GREEN;
1996 		right_color = UI_COLOR_RED;
1997 		below_color = UI_COLOR_BLACK;
1998 		break;
1999 
2000 	case UI_CALCULATOR_HP50G:
2001 		x49gp_ui_draw_text(cr, &widget->style->white,
2002 				   X49GP_UI_NORMAL_FONT, 15.0, 0.0,
2003 				   38, 42, 2,
2004 				   CAIRO_FONT_SLANT_NORMAL,
2005 				   CAIRO_FONT_WEIGHT_NORMAL,
2006 				   "HP",
2007 				   CAIRO_FONT_SLANT_NORMAL,
2008 				   CAIRO_FONT_WEIGHT_NORMAL,
2009 				   " 50g");
2010 
2011 		x49gp_ui_draw_text(cr, &widget->style->white,
2012 				   X49GP_UI_NORMAL_FONT, 13.0, 0.0,
2013 				   38, 56, 1,
2014 				   CAIRO_FONT_SLANT_NORMAL,
2015 				   CAIRO_FONT_WEIGHT_NORMAL,
2016 				   "Graphing Calculator");
2017 
2018 		x49gp_ui_draw_symbol(cr, &widget->style->white, 10.0, 0.0, TRUE,
2019 				     168, 25, symbol_get_by_name("triangleup"));
2020 
2021 		left_color = UI_COLOR_WHITE;
2022 		right_color = UI_COLOR_ORANGE;
2023 		below_color = UI_COLOR_BLUE;
2024 		break;
2025 	}
2026 
2027 	cairo_destroy(cr);
2028 
2029 	for (i = 0; i < ui->nr_buttons; i++) {
2030 		key = &x49gp_ui_keys[i];
2031 		key = &x50g_ui_keys[i];
2032 
2033 		if (key->left) {
2034 			bitmap_font_text_size(&tiny_font, key->left, &wl, &hl, &a, &dl);
2035 			if (!key->right) {
2036 				xl = key->x + (key->width - wl) / 2;
2037 				bitmap_font_draw_text(ui->bg_pixmap,
2038 						&ui->colors[left_color],
2039 						&tiny_font,
2040 						ui->kb_x_offset + xl,
2041 						ui->kb_y_offset + key->y - hl + dl + 1,
2042 						key->left);
2043 			}
2044 		}
2045 
2046 		if (key->right) {
2047 			bitmap_font_text_size(&tiny_font, key->right, &wr, &hr, &a, &dr);
2048 			if (!key->left) {
2049 				xr = key->x + (key->width - wr) / 2;
2050 				bitmap_font_draw_text(ui->bg_pixmap,
2051 						&ui->colors[right_color],
2052 						&tiny_font,
2053 						ui->kb_x_offset + xr,
2054 						ui->kb_y_offset + key->y - hr + dr + 1,
2055 						key->right);
2056 			}
2057 		}
2058 
2059 		if (key->left && key->right) {
2060 			xl = key->x;
2061 			xr = key->x + key->width - 1 - wr;
2062 
2063 			if (wl + wr > key->width - 4) {
2064 				xl += (key->width - 4 - (wl + wr)) / 2;
2065 				xr -= (key->width - 4 - (wl + wr)) / 2;
2066 			}
2067 
2068 			bitmap_font_draw_text(ui->bg_pixmap,
2069 					&ui->colors[left_color],
2070 					&tiny_font,
2071 					ui->kb_x_offset + xl,
2072 					ui->kb_y_offset + key->y - hl + dl + 1,
2073 					key->left);
2074 
2075 			bitmap_font_draw_text(ui->bg_pixmap,
2076 					&ui->colors[right_color],
2077 					&tiny_font,
2078 					ui->kb_x_offset + xr,
2079 					ui->kb_y_offset + key->y - hr + dr + 1,
2080 					key->right);
2081 		}
2082 
2083 		if (key->below) {
2084 			bitmap_font_text_size(&tiny_font, key->below, &wl, &hl, &a, &dl);
2085 			xl = key->x + (key->width - wl) / 2;
2086 
2087 			bitmap_font_draw_text(ui->bg_pixmap,
2088 					&ui->colors[below_color],
2089 					&tiny_font,
2090 					ui->kb_x_offset + xl,
2091 					ui->kb_y_offset + key->y + key->height + 2,
2092 					key->below);
2093 		}
2094 
2095 #if 0	/* Debug Button Layout */
2096 		gdk_draw_rectangle(ui->bg_pixmap, ui->window->style->white_gc,
2097 				   FALSE,
2098 				   ui->kb_x_offset + key->x,
2099 				   ui->kb_y_offset + key->y,
2100 				   key->width, key->height);
2101 #endif
2102 	}
2103 
2104 	gdk_window_set_back_pixmap(widget->window, ui->bg_pixmap, FALSE);
2105 
2106 	return FALSE;
2107 }
2108 
2109 static gboolean
x49gp_window_button_press(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2110 x49gp_window_button_press(GtkWidget *widget, GdkEventButton *event,
2111 			  gpointer user_data)
2112 {
2113 #ifdef DEBUG_X49GP_UI
2114 fprintf(stderr, "%s:%u: type %u, button %u\n", __FUNCTION__, __LINE__, event->type, event->button);
2115 #endif
2116 
2117 	gdk_window_focus(widget->window, event->time);
2118 	gdk_window_raise(widget->window);
2119 
2120 	if (event->type != GDK_BUTTON_PRESS)
2121 		return FALSE;
2122 
2123 	if (event->button != 1)
2124 		return FALSE;
2125 
2126 	gdk_window_begin_move_drag(widget->window, event->button,
2127 				   event->x_root, event->y_root,
2128 				   event->time);
2129 
2130 	return FALSE;
2131 }
2132 
2133 static void
x49gp_ui_quit(GtkWidget * widget,GdkEvent * event,gpointer user_data)2134 x49gp_ui_quit(GtkWidget *widget, GdkEvent *event, gpointer user_data)
2135 {
2136 	x49gp_t *x49gp = user_data;
2137 
2138 	x49gp->arm_exit++;
2139 }
2140 
2141 static void
x49gp_ui_place_at(x49gp_t * x49gp,GtkFixed * fixed,GtkWidget * widget,gint x,gint y,gint width,gint height)2142 x49gp_ui_place_at(x49gp_t *x49gp, GtkFixed *fixed, GtkWidget *widget,
2143 		  gint x, gint y, gint width, gint height)
2144 {
2145 	gtk_widget_set_size_request(widget, width, height);
2146 	gtk_fixed_put(fixed, widget, x, y);
2147 }
2148 
2149 static int
gui_init(x49gp_module_t * module)2150 gui_init(x49gp_module_t *module)
2151 {
2152 	x49gp_t *x49gp = module->x49gp;
2153 	x49gp_ui_t *ui;
2154 
2155 	ui = malloc(sizeof(x49gp_ui_t));
2156 	if (NULL == ui) {
2157 		fprintf(stderr, "%s: %s:%u: Out of memory\n",
2158 			x49gp->progname, __FUNCTION__, __LINE__);
2159 		return -ENOMEM;
2160 	}
2161 	memset(ui, 0, sizeof(x49gp_ui_t));
2162 
2163 	ui->nr_buttons = X49GP_UI_NR_KEYS;
2164 	ui->buttons = malloc(ui->nr_buttons * sizeof(x49gp_ui_button_t));
2165 	if (NULL == ui->buttons) {
2166 		fprintf(stderr, "%s: %s:%u: Out of memory\n",
2167 			x49gp->progname, __FUNCTION__, __LINE__);
2168 		free(ui);
2169 		return -ENOMEM;
2170 	}
2171 	memset(ui->buttons, 0, ui->nr_buttons * sizeof(x49gp_ui_button_t));
2172 
2173 	module->user_data = ui;
2174 	x49gp->ui = ui;
2175 
2176 	return 0;
2177 }
2178 
2179 static int
gui_exit(x49gp_module_t * module)2180 gui_exit(x49gp_module_t *module)
2181 {
2182 	return 0;
2183 }
2184 
2185 static int
gui_reset(x49gp_module_t * module,x49gp_reset_t reset)2186 gui_reset(x49gp_module_t *module, x49gp_reset_t reset)
2187 {
2188 	return 0;
2189 }
2190 
2191 static int
gui_load(x49gp_module_t * module,GKeyFile * keyfile)2192 gui_load(x49gp_module_t *module, GKeyFile *keyfile)
2193 {
2194 	x49gp_t *x49gp = module->x49gp;
2195 	x49gp_ui_t *ui = module->user_data;
2196 	x49gp_ui_button_t *button;
2197 	const x49gp_ui_key_t *key;
2198 	GError *gerror = NULL;
2199 	GdkBitmap *shape;
2200 	char *imagefile;
2201 	char *name;
2202 	int i;
2203 
2204 	imagefile = x49gp_module_get_filename(module, keyfile, "image");
2205 	x49gp_module_get_string(module, keyfile, "name", "hp49g+", &name);
2206 
2207 	if (access(imagefile, R_OK) == -1) {
2208 		fprintf(stderr, "Calculator skin file \"%s\" not accessible.\n", imagefile);
2209 		return 1;
2210 	}
2211 
2212 	if (!strcmp(name, "hp49g+")) {
2213 		ui->calculator = UI_CALCULATOR_HP49GP;
2214 	} else if (!strcmp(name, "hp50g")) {
2215 		ui->calculator = UI_CALCULATOR_HP50G;
2216 	} else {
2217 		ui->calculator = 0;
2218 	}
2219 
2220 	gdk_pixbuf_get_file_info(imagefile, &ui->width, &ui->height);
2221 
2222 	ui->lcd_width = 131 * 2;
2223 	ui->lcd_top_margin = 16;
2224 	ui->lcd_height = 80 * 2 + ui->lcd_top_margin;
2225 
2226 	ui->lcd_x_offset = (ui->width - ui->lcd_width) / 2;
2227 	ui->lcd_y_offset = 69;
2228 
2229 	ui->kb_x_offset = 36;
2230 	ui->kb_y_offset = 301;
2231 
2232 	ui->bg_pixbuf = gdk_pixbuf_new_from_file(imagefile, &gerror);
2233 
2234 
2235 	ui->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2236 	gtk_widget_set(ui->window, "can-focus", TRUE, NULL);
2237 	gtk_widget_set(ui->window, "accept-focus", TRUE, NULL);
2238 	gtk_widget_set(ui->window, "focus-on-map", TRUE, NULL);
2239 	gtk_widget_set(ui->window, "resizable", FALSE, NULL);
2240 	gtk_window_set_decorated(GTK_WINDOW(ui->window), FALSE);
2241 
2242 	gtk_widget_set_name(ui->window, name);
2243 	gtk_window_set_title(GTK_WINDOW(ui->window), name);
2244 
2245 //	gtk_window_set_icon(GTK_WINDOW(ui->window), ui->bg_pixbuf);
2246 
2247 	gdk_pixbuf_render_pixmap_and_mask(ui->bg_pixbuf, NULL, &shape, 255);
2248 
2249 	gtk_widget_set_size_request(ui->window, ui->width, ui->height);
2250 	gtk_widget_shape_combine_mask(ui->window, shape, 0, 0);
2251 
2252 	g_object_unref(shape);
2253 
2254 	gtk_widget_realize(ui->window);
2255 
2256 	ui->shapes[UI_SHAPE_BUTTON_TINY] = gdk_bitmap_create_from_data(NULL,
2257 						(char *) button_tiny_bits,
2258 						button_tiny_width,
2259 						button_tiny_height);
2260 	ui->shapes[UI_SHAPE_BUTTON_SMALL] = gdk_bitmap_create_from_data(NULL,
2261 						(char *) button_small_bits,
2262 						button_small_width,
2263 						button_small_height);
2264 	ui->shapes[UI_SHAPE_BUTTON_NORMAL] = gdk_bitmap_create_from_data(NULL,
2265 						(char *) button_normal_bits,
2266 						button_normal_width,
2267 						button_normal_height);
2268 	ui->shapes[UI_SHAPE_BUTTON_LARGE] = gdk_bitmap_create_from_data(NULL,
2269 						(char *) button_large_bits,
2270 						button_large_width,
2271 						button_large_height);
2272 	ui->shapes[UI_SHAPE_BUTTON_ROUND] = gdk_bitmap_create_from_data(NULL,
2273 						(char *) button_round_bits,
2274 						button_round_width,
2275 						button_round_height);
2276 
2277 
2278 	ui->fixed = gtk_fixed_new();
2279 	gtk_container_add(GTK_CONTAINER(ui->window), ui->fixed);
2280 
2281 	ui->background = gtk_drawing_area_new();
2282 	gtk_drawing_area_size(GTK_DRAWING_AREA(ui->background),
2283 			      ui->width, ui->height);
2284 	x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->background,
2285 			  0, 0, ui->width, ui->height);
2286 
2287 	x49gp_ui_color_init(&ui->colors[UI_COLOR_BLACK], 0x00, 0x00, 0x00);
2288 	x49gp_ui_color_init(&ui->colors[UI_COLOR_WHITE], 0xff, 0xff, 0xff);
2289 	x49gp_ui_color_init(&ui->colors[UI_COLOR_YELLOW], 0xfa, 0xe8, 0x2c);
2290 	x49gp_ui_color_init(&ui->colors[UI_COLOR_RED], 0x8e, 0x25, 0x18);
2291 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GREEN], 0x14, 0x4d, 0x49);
2292 	x49gp_ui_color_init(&ui->colors[UI_COLOR_SILVER], 0xe0, 0xe0, 0xe0);
2293 	x49gp_ui_color_init(&ui->colors[UI_COLOR_ORANGE], 0xc0, 0x6e, 0x60);
2294 	x49gp_ui_color_init(&ui->colors[UI_COLOR_BLUE], 0x40, 0x60, 0xa4);
2295 
2296 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_0], 0xab, 0xd2, 0xb4);
2297 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_1], 0xa0, 0xc4, 0xa8);
2298 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_2], 0x94, 0xb6, 0x9c);
2299 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_3], 0x89, 0xa8, 0x90);
2300 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_4], 0x7d, 0x9a, 0x84);
2301 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_5], 0x72, 0x8c, 0x78);
2302 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_6], 0x67, 0x7e, 0x6c);
2303 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_7], 0x5b, 0x70, 0x60);
2304 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_8], 0x50, 0x62, 0x54);
2305 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_9], 0x44, 0x54, 0x48);
2306 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_10], 0x39, 0x46, 0x3c);
2307 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_11], 0x2e, 0x38, 0x30);
2308 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_12], 0x22, 0x2a, 0x24);
2309 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_13], 0x17, 0x1c, 0x18);
2310 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_14], 0x0b, 0x03, 0x0c);
2311 	x49gp_ui_color_init(&ui->colors[UI_COLOR_GRAYSCALE_15], 0x00, 0x00, 0x00);
2312 
2313 
2314 	ui->lcd_canvas = gtk_drawing_area_new();
2315 	gtk_drawing_area_size(GTK_DRAWING_AREA(ui->lcd_canvas),
2316 			      ui->lcd_width, ui->lcd_height);
2317 	x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), ui->lcd_canvas,
2318 			  ui->lcd_x_offset, ui->lcd_y_offset,
2319 			  ui->lcd_width, ui->lcd_height);
2320 
2321 
2322 	for (i = 0; i < ui->nr_buttons; i++) {
2323 		key = &x49gp_ui_keys[i];
2324 		key = &x50g_ui_keys[i];
2325 		button = &ui->buttons[i];
2326 
2327 		button->x49gp = x49gp;
2328 		button->key = key;
2329 
2330 		button->button = gtk_button_new();
2331 		gtk_widget_set_size_request(button->button,
2332 					    key->width, key->height);
2333 		gtk_widget_set(button->button, "can-focus", FALSE, NULL);
2334 
2335 		x49gp_ui_button_pixmaps_init(x49gp, button, key->color);
2336 
2337 		if (key->label) {
2338 			button->label = gtk_label_new("");
2339 			gtk_widget_set_style(button->label,
2340 					     button->button->style);
2341 			gtk_container_add(GTK_CONTAINER(button->button),
2342 					  button->label);
2343 
2344 			g_signal_connect(G_OBJECT(button->label),
2345 					 "expose-event",
2346 			 		 G_CALLBACK(x49gp_button_expose_event),
2347 					 button);
2348 
2349 			g_signal_connect_after(G_OBJECT(button->label),
2350 					 "realize",
2351 					 G_CALLBACK(x49gp_button_realize),
2352 					 button);
2353 		}
2354 
2355 		button->box = gtk_event_box_new();
2356 		gtk_event_box_set_visible_window(GTK_EVENT_BOX(button->box),
2357 						 TRUE);
2358 		gtk_event_box_set_above_child(GTK_EVENT_BOX(button->box),
2359 					      FALSE);
2360 		gtk_widget_shape_combine_mask(button->box,
2361 					      ui->shapes[key->shape], 0, 0);
2362 		gtk_container_add(GTK_CONTAINER(button->box), button->button);
2363 
2364 
2365 		x49gp_ui_place_at(x49gp, GTK_FIXED(ui->fixed), button->box,
2366 				  ui->kb_x_offset + key->x,
2367 				  ui->kb_y_offset + key->y,
2368 				  key->width, key->height);
2369 
2370 		g_signal_connect(G_OBJECT(button->button),
2371 				 "button-press-event",
2372 				 G_CALLBACK(x49gp_ui_button_press), button);
2373 
2374 		g_signal_connect(G_OBJECT(button->button),
2375 				 "button-release-event",
2376 				 G_CALLBACK(x49gp_ui_button_release), button);
2377 
2378 		g_signal_connect(G_OBJECT(button->button),
2379 				 "leave-notify-event",
2380 				 G_CALLBACK(x49gp_ui_button_leave), button);
2381 
2382 		gtk_widget_add_events(button->button,
2383 				      GDK_BUTTON_PRESS_MASK |
2384 				      GDK_BUTTON_RELEASE_MASK |
2385 				      GDK_LEAVE_NOTIFY_MASK);
2386 	}
2387 
2388 	g_signal_connect(G_OBJECT(ui->background), "configure-event",
2389 			 G_CALLBACK(x49gp_window_configure_event), x49gp);
2390 
2391 	g_signal_connect(G_OBJECT(ui->lcd_canvas), "expose-event",
2392 			 G_CALLBACK(x49gp_lcd_expose_event), x49gp);
2393 	g_signal_connect(G_OBJECT(ui->lcd_canvas), "configure-event",
2394 			 G_CALLBACK(x49gp_lcd_configure_event), x49gp);
2395 
2396 	g_signal_connect(G_OBJECT(ui->window), "delete-event",
2397 			 G_CALLBACK(x49gp_ui_quit), x49gp);
2398 	g_signal_connect(G_OBJECT(ui->window), "destroy",
2399 			 G_CALLBACK(x49gp_ui_quit), x49gp);
2400 
2401 	g_signal_connect(G_OBJECT(ui->window), "key-press-event",
2402 			 G_CALLBACK(x49gp_ui_key_event), x49gp);
2403 	g_signal_connect(G_OBJECT(ui->window), "key-release-event",
2404 			 G_CALLBACK(x49gp_ui_key_event), x49gp);
2405 
2406 	g_signal_connect(G_OBJECT(ui->window), "button-press-event",
2407 			 G_CALLBACK(x49gp_window_button_press), x49gp);
2408 
2409 	gtk_widget_add_events(ui->window,
2410 			      GDK_BUTTON_PRESS_MASK |
2411 			      GDK_KEY_PRESS_MASK |
2412 			      GDK_KEY_RELEASE_MASK);
2413 
2414 	gtk_widget_show_all(ui->window);
2415 	return 0;
2416 }
2417 
2418 static int
gui_save(x49gp_module_t * module,GKeyFile * keyfile)2419 gui_save(x49gp_module_t *module, GKeyFile *keyfile)
2420 {
2421 	return 0;
2422 }
2423 
2424 int
x49gp_ui_init(x49gp_t * x49gp)2425 x49gp_ui_init(x49gp_t *x49gp)
2426 {
2427 	x49gp_module_t *module;
2428 
2429 	if (x49gp_module_init(x49gp, "gui", gui_init, gui_exit,
2430 			      gui_reset, gui_load, gui_save, NULL,
2431 			      &module)) {
2432 		return -1;
2433 	}
2434 
2435 	return x49gp_module_register(module);
2436 }
2437