1 /* drivers.c
2 * (c) 2002 Mikulas Patocka
3 * This file is a part of the Links program, released under GPL
4 */
5
6 #include "cfg.h"
7
8 #ifdef G
9
10 #include "links.h"
11
12 int F = 0;
13
14 struct graphics_driver *drv = NULL;
15
16 #ifdef GRDRV_X
17 extern struct graphics_driver x_driver;
18 #endif
19 #ifdef GRDRV_SVGALIB
20 extern struct graphics_driver svga_driver;
21 #endif
22 #ifdef GRDRV_FB
23 extern struct graphics_driver fb_driver;
24 #endif
25 #ifdef GRDRV_DIRECTFB
26 extern struct graphics_driver directfb_driver;
27 #endif
28 #ifdef GRDRV_PMSHELL
29 extern struct graphics_driver pmshell_driver;
30 #endif
31 #ifdef GRDRV_ATHEOS
32 extern struct graphics_driver atheos_driver;
33 #endif
34 #ifdef GRDRV_HAIKU
35 extern struct graphics_driver haiku_driver;
36 #endif
37 #ifdef GRDRV_GRX
38 extern struct graphics_driver grx_driver;
39 #endif
40 #ifdef GRDRV_SDL
41 extern struct graphics_driver sdl_driver;
42 #endif
43
44 /*
45 * On SPAD you must test first svgalib and then X (because X test is slow).
46 * On other systems you must test first X and then svgalib (because svgalib
47 * would work in X too and it's undesirable).
48 */
49
50 static struct graphics_driver *graphics_drivers[] = {
51 #ifdef GRDRV_PMSHELL
52 &pmshell_driver,
53 #endif
54 #ifdef GRDRV_ATHEOS
55 &atheos_driver,
56 #endif
57 #ifdef GRDRV_HAIKU
58 &haiku_driver,
59 #endif
60 #ifndef SPAD
61 #ifdef GRDRV_X
62 &x_driver,
63 #endif
64 #endif
65 #ifdef GRDRV_FB
66 /* use FB before DirectFB because DirectFB has bugs */
67 &fb_driver,
68 #endif
69 #ifdef GRDRV_DIRECTFB
70 &directfb_driver,
71 #endif
72 #ifdef GRDRV_SVGALIB
73 &svga_driver,
74 #endif
75 #ifdef SPAD
76 #ifdef GRDRV_X
77 &x_driver,
78 #endif
79 #endif
80 #ifdef GRDRV_GRX
81 &grx_driver,
82 #endif
83 #ifdef GRDRV_SDL
84 &sdl_driver,
85 #endif
86 NULL
87 };
88
89 #if 0
90 static unsigned char *list_graphics_drivers(void)
91 {
92 unsigned char *d = init_str();
93 int l = 0;
94 struct graphics_driver **gd;
95 for (gd = graphics_drivers; *gd; gd++) {
96 if (l) add_chr_to_str(&d, &l, ' ');
97 add_to_str(&d, &l, (*gd)->name);
98 }
99 return d;
100 }
101 #endif
102
103 /* Driver je jednorazovy argument, kterej se preda grafickymu driveru, nikde se dal
104 * neuklada. Param se skladuje v default_driver param a uklada se do konfiguraku. Pred
105 * ukoncenim grafickeho driveru se nastavi default_driver_param podle
106 * drv->get_driver_param.
107 */
init_graphics_driver(struct graphics_driver * gd,unsigned char * param,unsigned char * display)108 static unsigned char *init_graphics_driver(struct graphics_driver *gd, unsigned char *param, unsigned char *display)
109 {
110 unsigned char *r;
111 unsigned char *p = param;
112 struct driver_param *dp = get_driver_param(gd->name);
113 if (!param || !*param) p = dp->param;
114 gd->param = dp;
115 drv = gd;
116 r = gd->init_driver(p,display);
117 if (r) drv = NULL;
118 else F = 1;
119 return r;
120 }
121
122
add_graphics_drivers(unsigned char ** s,int * l)123 void add_graphics_drivers(unsigned char **s, int *l)
124 {
125 struct graphics_driver **gd;
126 for (gd = graphics_drivers; *gd; gd++) {
127 if (gd != graphics_drivers) add_to_str(s, l, cast_uchar ", ");
128 add_to_str(s, l, (*gd)->name);
129 }
130 }
131
init_graphics(unsigned char * driver,unsigned char * param,unsigned char * display)132 unsigned char *init_graphics(unsigned char *driver, unsigned char *param, unsigned char *display)
133 {
134 unsigned char *s = init_str();
135 int l = 0;
136 struct graphics_driver **gd;
137 #if defined(GRDRV_PMSHELL) && defined(GRDRV_X)
138 if (is_xterm()) {
139 static unsigned char swapped = 0;
140 if (!swapped) {
141 for (gd = graphics_drivers; *gd; gd++) {
142 if (*gd == &pmshell_driver) *gd = &x_driver;
143 else if (*gd == &x_driver) *gd = &pmshell_driver;
144 }
145 swapped = 1;
146 }
147 }
148 #endif
149 for (gd = graphics_drivers; *gd; gd++) {
150 if (!driver || !*driver || !casestrcmp((*gd)->name, driver)) {
151 unsigned char *r;
152 if ((!driver || !*driver) && (*gd)->flags & GD_NOAUTO) continue;
153 if (!(r = init_graphics_driver(*gd, param, display))) {
154 mem_free(s);
155 return NULL;
156 }
157 if (!l) {
158 if (!driver || !*driver) add_to_str(&s, &l, cast_uchar "Could not initialize any graphics driver. Tried the following drivers:\n");
159 else add_to_str(&s, &l, cast_uchar "Could not initialize graphics driver ");
160 }
161 add_to_str(&s, &l, (*gd)->name);
162 add_to_str(&s, &l, cast_uchar ":\n");
163 add_to_str(&s, &l, r);
164 mem_free(r);
165 }
166 }
167 if (!l) {
168 add_to_str(&s, &l, cast_uchar "Unknown graphics driver ");
169 if (driver) add_to_str(&s, &l, driver);
170 add_to_str(&s, &l, cast_uchar ".\nThe following graphics drivers are supported:\n");
171 add_graphics_drivers(&s, &l);
172 add_to_str(&s, &l, cast_uchar "\n");
173 }
174 return s;
175 }
176
shutdown_graphics(void)177 void shutdown_graphics(void)
178 {
179 if (drv) {
180 drv->shutdown_driver();
181 drv = NULL;
182 F = 0;
183 }
184 }
185
update_driver_param(void)186 void update_driver_param(void)
187 {
188 if (drv) {
189 struct driver_param *dp = drv->param;
190 if (dp->param) mem_free(dp->param), dp->param = NULL;
191 if (drv->get_driver_param)
192 dp->param = stracpy(drv->get_driver_param());
193 dp->nosave = 0;
194 }
195 }
196
g_kbd_codepage(struct graphics_driver * drv)197 int g_kbd_codepage(struct graphics_driver *drv)
198 {
199 if (drv->param->kbd_codepage >= 0)
200 return drv->param->kbd_codepage;
201 return get_default_charset();
202 }
203
do_rects_intersect(struct rect * r1,struct rect * r2)204 int do_rects_intersect(struct rect *r1, struct rect *r2)
205 {
206 return (r1->x1 > r2->x1 ? r1->x1 : r2->x1) < (r1->x2 > r2->x2 ? r2->x2 : r1->x2) && (r1->y1 > r2->y1 ? r1->y1 : r2->y1) < (r1->y2 > r2->y2 ? r2->y2 : r1->y2);
207 }
208
intersect_rect(struct rect * v,struct rect * r1,struct rect * r2)209 void intersect_rect(struct rect *v, struct rect *r1, struct rect *r2)
210 {
211 v->x1 = r1->x1 > r2->x1 ? r1->x1 : r2->x1;
212 v->x2 = r1->x2 > r2->x2 ? r2->x2 : r1->x2;
213 v->y1 = r1->y1 > r2->y1 ? r1->y1 : r2->y1;
214 v->y2 = r1->y2 > r2->y2 ? r2->y2 : r1->y2;
215 }
216
unite_rect(struct rect * v,struct rect * r1,struct rect * r2)217 void unite_rect(struct rect *v, struct rect *r1, struct rect *r2)
218 {
219 if (!is_rect_valid(r1)) {
220 if (v != r2) memcpy(v, r2, sizeof(struct rect));
221 return;
222 }
223 if (!is_rect_valid(r2)) {
224 if (v != r1) memcpy(v, r1, sizeof(struct rect));
225 return;
226 }
227 v->x1 = r1->x1 < r2->x1 ? r1->x1 : r2->x1;
228 v->x2 = r1->x2 < r2->x2 ? r2->x2 : r1->x2;
229 v->y1 = r1->y1 < r2->y1 ? r1->y1 : r2->y1;
230 v->y2 = r1->y2 < r2->y2 ? r2->y2 : r1->y2;
231 }
232
233 #define R_GR 8
234
init_rect_set(void)235 struct rect_set *init_rect_set(void)
236 {
237 struct rect_set *s;
238 s = mem_calloc(sizeof(struct rect_set) + sizeof(struct rect) * R_GR);
239 s->rl = R_GR;
240 s->m = 0;
241 return s;
242 }
243
add_to_rect_set(struct rect_set ** s,struct rect * r)244 void add_to_rect_set(struct rect_set **s, struct rect *r)
245 {
246 struct rect_set *ss = *s;
247 int i;
248 if (!is_rect_valid(r)) return;
249 for (i = 0; i < ss->rl; i++) if (!ss->r[i].x1 && !ss->r[i].x2 && !ss->r[i].y1 && !ss->r[i].y2) {
250 x:
251 memcpy(&ss->r[i], r, sizeof(struct rect));
252 if (i >= ss->m) ss->m = i + 1;
253 return;
254 }
255 if ((unsigned)ss->rl > (MAXINT - sizeof(struct rect_set)) / sizeof(struct rect) - R_GR) overalloc();
256 ss = mem_realloc(ss, sizeof(struct rect_set) + sizeof(struct rect) * (ss->rl + R_GR));
257 memset(&(*s = ss)->r[i = (ss->rl += R_GR) - R_GR], 0, sizeof(struct rect) * R_GR);
258 goto x;
259 }
260
exclude_rect_from_set(struct rect_set ** s,struct rect * r)261 void exclude_rect_from_set(struct rect_set **s, struct rect *r)
262 {
263 int i, a;
264 struct rect *rr;
265 do {
266 a = 0;
267 for (i = 0; i < (*s)->m; i++) if (do_rects_intersect(rr = &(*s)->r[i], r)) {
268 struct rect r1, r2, r3, r4;
269 r1.x1 = rr->x1;
270 r1.x2 = rr->x2;
271 r1.y1 = rr->y1;
272 r1.y2 = r->y1;
273
274 r2.x1 = rr->x1;
275 r2.x2 = r->x1;
276 r2.y1 = r->y1;
277 r2.y2 = r->y2;
278
279 r3.x1 = r->x2;
280 r3.x2 = rr->x2;
281 r3.y1 = r->y1;
282 r3.y2 = r->y2;
283
284 r4.x1 = rr->x1;
285 r4.x2 = rr->x2;
286 r4.y1 = r->y2;
287 r4.y2 = rr->y2;
288
289 intersect_rect(&r2, &r2, rr);
290 intersect_rect(&r3, &r3, rr);
291 rr->x1 = rr->x2 = rr->y1 = rr->y2 = 0;
292 #ifdef DEBUG
293 if (is_rect_valid(&r1) && do_rects_intersect(&r1, r)) internal_error("bad intersection 1");
294 if (is_rect_valid(&r2) && do_rects_intersect(&r2, r)) internal_error("bad intersection 2");
295 if (is_rect_valid(&r3) && do_rects_intersect(&r3, r)) internal_error("bad intersection 3");
296 if (is_rect_valid(&r4) && do_rects_intersect(&r4, r)) internal_error("bad intersection 4");
297 #endif
298 add_to_rect_set(s, &r1);
299 add_to_rect_set(s, &r2);
300 add_to_rect_set(s, &r3);
301 add_to_rect_set(s, &r4);
302 a = 1;
303 }
304 } while (a);
305 }
306
set_clip_area(struct graphics_device * dev,struct rect * r)307 void set_clip_area(struct graphics_device *dev, struct rect *r)
308 {
309 dev->clip = *r;
310 if (dev->clip.x1 < 0) dev->clip.x1 = 0;
311 if (dev->clip.x2 > dev->size.x2) dev->clip.x2 = dev->size.x2;
312 if (dev->clip.y1 < 0) dev->clip.y1 = 0;
313 if (dev->clip.y2 > dev->size.y2) dev->clip.y2 = dev->size.y2;
314 if (!is_rect_valid(&dev->clip)) {
315 /* Empty region */
316 dev->clip.x1 = dev->clip.x2 = dev->clip.y1 = dev->clip.y2 = 0;
317 }
318 if (drv->set_clip_area)
319 drv->set_clip_area(dev);
320 }
321
322 /* memory address r must contain one struct rect
323 * x1 is leftmost pixel that is still valid
324 * x2 is leftmost pixel that isn't valid any more
325 * y1, y2 analogically
326 */
restrict_clip_area(struct graphics_device * dev,struct rect * r,int x1,int y1,int x2,int y2)327 int restrict_clip_area(struct graphics_device *dev, struct rect *r, int x1, int y1, int x2, int y2)
328 {
329 struct rect v, rr;
330 rr.x1 = x1, rr.x2 = x2, rr.y1 = y1, rr.y2 = y2;
331 if (r) memcpy(r, &dev->clip, sizeof(struct rect));
332 intersect_rect(&v, &dev->clip, &rr);
333 set_clip_area(dev, &v);
334 return is_rect_valid(&v);
335 }
336
g_scroll(struct graphics_device * dev,int scx,int scy)337 struct rect_set *g_scroll(struct graphics_device *dev, int scx, int scy)
338 {
339 struct rect_set *rs = init_rect_set();
340
341 if (!scx && !scy)
342 return rs;
343 if (abs(scx) >= dev->clip.x2 - dev->clip.x1 ||
344 abs(scy) >= dev->clip.y2 - dev->clip.y1) {
345 add_to_rect_set(&rs, &dev->clip);
346 return rs;
347 }
348
349 if (drv->scroll(dev, &rs, scx, scy)) {
350 struct rect q = dev->clip;
351 if (scy >= 0)
352 q.y2 = q.y1 + scy;
353 else
354 q.y1 = q.y2 + scy;
355 add_to_rect_set(&rs, &q);
356
357 q = dev->clip;
358 if (scy >= 0)
359 q.y1 += scy;
360 else
361 q.y2 += scy;
362 if (scx >= 0)
363 q.x2 = q.x1 + scx;
364 else
365 q.x1 = q.x2 + scx;
366 add_to_rect_set(&rs, &q);
367 }
368
369 return rs;
370 }
371
372 #ifdef GRDRV_VIRTUAL_DEVICES
373
374 struct graphics_device **virtual_devices;
375 int n_virtual_devices = 0;
376 struct graphics_device *current_virtual_device;
377
378 static struct timer *virtual_device_timer;
379
init_virtual_devices(struct graphics_driver * drv,int n)380 void init_virtual_devices(struct graphics_driver *drv, int n)
381 {
382 if (n_virtual_devices) {
383 internal_error("init_virtual_devices: already initialized");
384 return;
385 }
386 if ((unsigned)n > MAXINT / sizeof(struct graphics_device *)) overalloc();
387 virtual_devices = mem_calloc(n * sizeof(struct graphics_device *));
388 n_virtual_devices = n;
389 virtual_device_timer = NULL;
390 current_virtual_device = NULL;
391 }
392
init_virtual_device(void)393 struct graphics_device *init_virtual_device(void)
394 {
395 int i;
396 for (i = 0; i < n_virtual_devices; i++) if (!virtual_devices[i]) {
397 struct graphics_device *dev;
398 dev = mem_calloc(sizeof(struct graphics_device));
399 dev->size.x2 = drv->x;
400 dev->size.y2 = drv->y;
401 current_virtual_device = virtual_devices[i] = dev;
402 set_clip_area(dev, &dev->size);
403 return dev;
404 }
405 return NULL;
406 }
407
virtual_device_timer_fn(void * p)408 static void virtual_device_timer_fn(void *p)
409 {
410 virtual_device_timer = NULL;
411 if (current_virtual_device && current_virtual_device->redraw_handler) {
412 set_clip_area(current_virtual_device, ¤t_virtual_device->size);
413 current_virtual_device->redraw_handler(current_virtual_device, ¤t_virtual_device->size);
414 }
415 }
416
switch_virtual_device(int i)417 void switch_virtual_device(int i)
418 {
419 if (i == VD_NEXT) {
420 int j;
421 int t = 0;
422 for (j = 0; j < n_virtual_devices * 2; j++)
423 if (virtual_devices[j % n_virtual_devices] == current_virtual_device) t = 1;
424 else if (virtual_devices[j % n_virtual_devices] && t) {
425 current_virtual_device = virtual_devices[j % n_virtual_devices];
426 goto ok_switch;
427 }
428 return;
429 }
430 if (i < 0 || i >= n_virtual_devices || !virtual_devices[i]) return;
431 current_virtual_device = virtual_devices[i];
432 ok_switch:
433 if (virtual_device_timer == NULL)
434 virtual_device_timer = install_timer(0, virtual_device_timer_fn, NULL);
435 }
436
shutdown_virtual_device(struct graphics_device * dev)437 void shutdown_virtual_device(struct graphics_device *dev)
438 {
439 int i;
440 for (i = 0; i < n_virtual_devices; i++) if (virtual_devices[i] == dev) {
441 virtual_devices[i] = NULL;
442 mem_free(dev);
443 if (current_virtual_device != dev) return;
444 for (; i < n_virtual_devices; i++) if (virtual_devices[i]) {
445 switch_virtual_device(i);
446 return;
447 }
448 for (i = 0; i < n_virtual_devices; i++) if (virtual_devices[i]) {
449 switch_virtual_device(i);
450 return;
451 }
452 current_virtual_device = NULL;
453 return;
454 }
455 mem_free(dev);
456 /*internal_error("shutdown_virtual_device: device not initialized");*/
457 }
458
resize_virtual_devices(int x,int y)459 void resize_virtual_devices(int x, int y)
460 {
461 int i;
462 drv->x = x;
463 drv->y = y;
464 for (i = 0; i < n_virtual_devices; i++) {
465 struct graphics_device *dev = virtual_devices[i];
466 if (dev) {
467 dev->size.x2 = x;
468 dev->size.y2 = y;
469 dev->resize_handler(dev);
470 }
471 }
472 }
473
shutdown_virtual_devices(void)474 void shutdown_virtual_devices(void)
475 {
476 int i;
477 if (!n_virtual_devices) {
478 internal_error("shutdown_virtual_devices: already shut down");
479 return;
480 }
481 for (i = 0; i < n_virtual_devices; i++) if (virtual_devices[i]) internal_error("shutdown_virtual_devices: virtual device %d is still active", i);
482 mem_free(virtual_devices);
483 n_virtual_devices = 0;
484 if (virtual_device_timer != NULL) kill_timer(virtual_device_timer), virtual_device_timer = NULL;
485 }
486
487 #endif
488
489 #if defined(GRDRV_X) || defined(GRDRV_HAIKU)
490
491 /* This is executed in a helper thread, so we must not use mem_alloc */
492
addchr(unsigned char ** str,size_t * l,unsigned char c)493 static void addchr(unsigned char **str, size_t *l, unsigned char c)
494 {
495 unsigned char *s;
496 if (!*str) return;
497 if ((*str)[*l]) *l = strlen(cast_const_char *str);
498 if (*l > MAXINT - 2) overalloc();
499 s = realloc(*str, *l + 2);
500 if (!s) {
501 free(*str);
502 *str = NULL;
503 return;
504 }
505 *str = s;
506 s[(*l)++] = c;
507 s[*l] = 0;
508 }
509
x_exec(unsigned char * command,int fg)510 int x_exec(unsigned char *command, int fg)
511 {
512 unsigned char *pattern, *final;
513 size_t i, j, l;
514 int retval;
515
516 if (!fg) {
517 retval = system(cast_const_char command);
518 return retval;
519 }
520
521 l = 0;
522 if (*drv->param->shell_term) {
523 pattern = cast_uchar strdup(cast_const_char drv->param->shell_term);
524 } else {
525 pattern = cast_uchar strdup(cast_const_char links_xterm());
526 if (*command) {
527 addchr(&pattern, &l, ' ');
528 addchr(&pattern, &l, '%');
529 }
530 }
531 if (!pattern) return -1;
532
533 final = cast_uchar strdup("");
534 l = 0;
535 for (i = 0; pattern[i]; i++) {
536 if (pattern[i] == '%') {
537 for (j = 0; j < strlen(cast_const_char command); j++)
538 addchr(&final, &l, command[j]);
539 } else {
540 addchr(&final, &l, pattern[i]);
541 }
542 }
543 free(pattern);
544 if (!final) return -1;
545
546 retval = system(cast_const_char final);
547 free(final);
548 return retval;
549 }
550
551 #endif
552
553 #endif
554