Use SetErrorMode so Windows will not show all kinds of error dialogs
[mplayer/glamo.git] / libvo / vo_ggi.c
blob645bed25779a868b57a2ff3db252c0c43b2da3d0
1 /*
2 * General Graphics Interface (GGI) vo driver
4 * copyright (C) 2001 Alex Beregszaszi
6 * Uses libGGI - http://www.ggi-project.org/
8 * TODO:
9 * * implement gamma handling (VAA isn't obsoleted?)
11 * Thanks to Andreas Beck for his patches.
13 * Many thanks to Atmosfear, he hacked this driver to work with planar
14 * formats, and he fixed the RGB handling.
16 * This file is part of MPlayer.
18 * MPlayer is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * MPlayer is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License along
29 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
30 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
38 #include "mp_msg.h"
40 #include "config.h"
41 #include "video_out.h"
42 #include "video_out_internal.h"
44 #include "mp_fifo.h"
46 #include <ggi/ggi.h>
48 #ifdef CONFIG_GGIWMH
49 #include <ggi/wmh.h>
50 #endif
52 /* maximum buffers */
53 #undef GGI_FLIP
55 static const vo_info_t info =
57 "General Graphics Interface (GGI) output",
58 "ggi",
59 "Alex Beregszaszi",
60 "major"
63 const LIBVO_EXTERN(ggi)
66 static struct ggi_conf_s {
67 char *driver;
69 ggi_visual_t vis;
70 ggi_visual_t drawvis;
72 /* source image format */
73 int srcwidth;
74 int srcheight;
75 int srcformat;
76 int srcdepth;
77 int srcbpp;
79 /* dirty region */
80 struct {
81 int x1, y1;
82 int x2, y2;
83 } flushregion;
85 int voflags;
86 } ggi_conf;
89 #ifdef CONFIG_GGIWMH
90 static void window_ontop(void)
92 mp_msg(MSGT_VO, MSGL_V, "[ggi] debug: window_ontop() called\n");
93 ggiWmhZOrder(ggi_conf.vis, ZO_TOP);
94 return;
96 #endif
99 static void set_graphtype(uint32_t format, ggi_mode *mode)
101 switch (format) {
102 case IMGFMT_RGB4:
103 mode->graphtype = GT_4BIT;
104 break;
105 case IMGFMT_BGR4:
106 mode->graphtype = GT_4BIT;
107 GT_SETSUBSCHEME(mode->graphtype, GT_SUB_HIGHBIT_RIGHT);
108 break;
109 case IMGFMT_RGB8:
110 case IMGFMT_BGR8:
111 mode->graphtype = GT_8BIT;
112 break;
113 case IMGFMT_RGB15:
114 case IMGFMT_BGR15:
115 mode->graphtype = GT_15BIT;
116 break;
117 case IMGFMT_RGB16:
118 case IMGFMT_BGR16:
119 mode->graphtype = GT_16BIT;
120 break;
121 case IMGFMT_RGB24:
122 case IMGFMT_BGR24:
123 mode->graphtype = GT_24BIT;
124 break;
125 case IMGFMT_RGB32:
126 case IMGFMT_BGR32:
127 mode->graphtype = GT_32BIT;
128 break;
131 return;
134 static int config(uint32_t width, uint32_t height, uint32_t d_width,
135 uint32_t d_height, uint32_t flags, char *title,
136 uint32_t format)
138 ggi_mode mode = {
139 1, /* frames */
140 {width, height}, /* visible */
141 {GGI_AUTO, GGI_AUTO}, /* virt */
142 {GGI_AUTO, GGI_AUTO}, /* size */
143 GT_AUTO, /* graphtype */
144 {GGI_AUTO, GGI_AUTO} /* dots per pixel */
148 set_graphtype(format, &mode);
150 #if 0
151 printf("[ggi] mode: ");
152 ggiPrintMode(&mode);
153 printf("\n");
154 #endif
156 ggiCheckMode(ggi_conf.vis, &mode);
158 if (ggiSetMode(ggi_conf.vis, &mode) < 0) {
159 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to set display mode\n");
160 return -1;
162 if (ggiGetMode(ggi_conf.vis, &mode) < 0) {
163 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to get display mode\n");
164 return -1;
166 if ((mode.graphtype == GT_INVALID)
167 || (mode.graphtype == GT_AUTO))
169 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] not supported depth/bpp\n");
170 return -1;
173 #if 0
174 printf("[ggi] mode: ");
175 ggiPrintMode(&mode);
176 printf("\n");
177 #endif
180 #ifdef CONFIG_GGIWMH
181 ggiWmhSetTitle(ggi_conf.vis, title);
182 if (vo_ontop) window_ontop();
183 #endif
185 ggiSetFlags(ggi_conf.vis, GGIFLAG_ASYNC);
187 if (GT_SCHEME(mode.graphtype) == GT_PALETTE)
188 ggiSetColorfulPalette(ggi_conf.vis);
190 if (GT_SCHEME(mode.graphtype) != GT_TRUECOLOR) {
191 ggi_mode drawmode;
193 ggi_conf.drawvis = ggiOpen("display-memory", NULL);
194 if (ggi_conf.drawvis == NULL) {
195 mp_msg(MSGT_VO, MSGL_ERR,
196 "[ggi] unable to get backbuffer for conversion\n");
197 return -1;
199 memcpy(&drawmode, &mode, sizeof(ggi_mode));
200 drawmode.graphtype = GT_32BIT;
201 drawmode.size.x = GGI_AUTO;
202 drawmode.size.y = GGI_AUTO;
203 ggiCheckMode(ggi_conf.drawvis, &drawmode);
204 if (ggiSetMode(ggi_conf.drawvis, &drawmode) < 0) {
205 mp_msg(MSGT_VO, MSGL_ERR,
206 "[ggi] unable to set backbuffer mode\n");
207 return -1;
209 mode.graphtype = drawmode.graphtype;
211 ggiSetFlags(ggi_conf.drawvis, GGIFLAG_ASYNC);
213 vo_depthonscreen = GT_DEPTH(mode.graphtype);
214 vo_screenwidth = mode.virt.x;
215 vo_screenheight = mode.virt.y;
217 vo_dwidth = width;
218 vo_dheight = height;
219 vo_dbpp = GT_SIZE(mode.graphtype);
222 /* calculate top, left corner */
223 vo_dx = (vo_screenwidth - vo_dwidth) / 2;
224 vo_dy = (vo_screenheight - vo_dheight) / 2;
227 ggi_conf.srcwidth = width;
228 ggi_conf.srcheight = height;
229 ggi_conf.srcformat = format;
231 ggi_conf.voflags = flags;
233 if (IMGFMT_IS_RGB(ggi_conf.srcformat)) {
234 ggi_conf.srcdepth = IMGFMT_RGB_DEPTH(ggi_conf.srcformat);
235 } else if (IMGFMT_IS_BGR(ggi_conf.srcformat)) {
236 ggi_conf.srcdepth = IMGFMT_BGR_DEPTH(ggi_conf.srcformat);
237 } else {
238 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] Unknown image format: %s\n",
239 vo_format_name(ggi_conf.srcformat));
240 return -1;
243 mp_msg(MSGT_VO, MSGL_INFO, "[ggi] input: %dx%dx%d, output: %dx%dx%d\n",
244 ggi_conf.srcwidth, ggi_conf.srcheight, ggi_conf.srcdepth,
245 mode.virt.x, mode.virt.y, vo_dbpp);
247 ggi_conf.srcbpp = (ggi_conf.srcdepth + 7) / 8;
249 ggi_conf.flushregion.x1 = vo_dx;
250 ggi_conf.flushregion.y1 = vo_dy;
251 ggi_conf.flushregion.x2 = vo_dwidth;
252 ggi_conf.flushregion.y2 = vo_dheight;
254 return 0;
257 static uint32_t get_image(mp_image_t *mpi)
259 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
260 if (!((IMGFMT_IS_BGR(mpi->imgfmt)) &&
261 (IMGFMT_BGR_DEPTH(mpi->imgfmt) == vo_dbpp)))
263 return VO_FALSE;
266 if (!((IMGFMT_IS_RGB(mpi->imgfmt)) &&
267 (IMGFMT_RGB_DEPTH(mpi->imgfmt) == vo_dbpp)))
269 return VO_FALSE;
272 if (!((mpi->width == ggi_conf.srcwidth) &&
273 (mpi->height == ggi_conf.srcheight)))
275 return VO_FALSE;
278 mpi->planes[1] = mpi->planes[2] = NULL;
279 mpi->stride[1] = mpi->stride[2] = 0;
281 mpi->planes[0] = NULL;
282 mpi->stride[0] = ggi_conf.srcwidth * ggi_conf.srcbpp;
283 mpi->flags |= MP_IMGFLAG_DIRECT;
285 #ifdef GGI_FLIP
286 if (ggi_conf.voflags & VOFLAG_FLIPPING) {
287 mpi->stride[0] = -mpi->stride[0];
289 #endif
291 return VO_TRUE;
295 static int draw_frame(uint8_t *src[])
297 ggiPutBox(ggi_conf.drawvis, vo_dx, vo_dy,
298 vo_dwidth, vo_dheight, src[0]);
300 ggi_conf.flushregion.x1 = vo_dx;
301 ggi_conf.flushregion.y1 = vo_dy;
302 ggi_conf.flushregion.x2 = vo_dwidth;
303 ggi_conf.flushregion.y2 = vo_dheight;
305 return 0;
308 static void draw_osd(void)
310 return;
313 static void flip_page(void)
315 if (ggi_conf.drawvis != ggi_conf.vis) {
316 #if 0
317 ggiFlushRegion(ggi_conf.drawvis,
318 ggi_conf.flushregion.x1, ggi_conf.flushregion.y1,
319 ggi_conf.flushregion.x2 - ggi_conf.flushregion.x1,
320 ggi_conf.flushregion.y2 - ggi_conf.flushregion.y1);
321 #endif
322 ggiCrossBlit(ggi_conf.drawvis,
323 ggi_conf.flushregion.x1, ggi_conf.flushregion.y1,
324 ggi_conf.flushregion.x2 - ggi_conf.flushregion.x1,
325 ggi_conf.flushregion.y2 - ggi_conf.flushregion.y1,
326 ggi_conf.vis,
327 ggi_conf.flushregion.x1, ggi_conf.flushregion.y1);
330 ggiFlushRegion(ggi_conf.vis,
331 ggi_conf.flushregion.x1, ggi_conf.flushregion.y1,
332 ggi_conf.flushregion.x2 - ggi_conf.flushregion.x1,
333 ggi_conf.flushregion.y2 - ggi_conf.flushregion.y1);
335 ggi_conf.flushregion.x1 = ggi_conf.flushregion.x2 = -1;
336 ggi_conf.flushregion.y1 = ggi_conf.flushregion.y2 = -1;
339 static int draw_slice(uint8_t *src[], int stride[],
340 int w, int h, int x, int y)
342 ggiPutBox(ggi_conf.drawvis, vo_dx + x, vo_dy + y, w, h, src[0]);
344 if ((ggi_conf.flushregion.x1 == -1) ||
345 ((vo_dx + x) < ggi_conf.flushregion.x1))
347 ggi_conf.flushregion.x1 = vo_dx + x;
349 if ((ggi_conf.flushregion.y1 == -1) ||
350 ((vo_dy + y) < ggi_conf.flushregion.y1))
352 ggi_conf.flushregion.y1 = vo_dy + y;
354 if ((ggi_conf.flushregion.x2 == -1) ||
355 ((vo_dx + x + w) > ggi_conf.flushregion.x2))
357 ggi_conf.flushregion.x2 = vo_dx + x + w;
359 if ((ggi_conf.flushregion.y2 == -1) ||
360 ((vo_dy + y + h) > ggi_conf.flushregion.y2))
362 ggi_conf.flushregion.y2 = vo_dy + y + h;
365 return 1;
368 static int query_format(uint32_t format)
370 ggi_mode mode;
371 uint32_t vfcap;
373 vfcap = VFCAP_CSP_SUPPORTED
374 | VFCAP_CSP_SUPPORTED_BY_HW
375 | VFCAP_ACCEPT_STRIDE;
377 if ((!vo_depthonscreen || !vo_dbpp) && ggi_conf.vis) {
378 if (ggiGetMode(ggi_conf.vis, &mode) == 0) {
379 vo_depthonscreen = GT_DEPTH(mode.graphtype);
380 vo_dbpp = GT_SIZE(mode.graphtype);
382 if (GT_SCHEME(mode.graphtype) == GT_AUTO) {
383 ggiCheckMode(ggi_conf.vis, &mode);
385 if (GT_SCHEME(mode.graphtype) != GT_TRUECOLOR) {
386 mode.graphtype = GT_32BIT;
387 vo_depthonscreen = GT_DEPTH(mode.graphtype);
388 vo_dbpp = GT_SIZE(mode.graphtype);
391 if ((IMGFMT_IS_BGR(format) && (IMGFMT_BGR_DEPTH(format) == vo_dbpp)) ||
392 (IMGFMT_IS_RGB(format) && (IMGFMT_RGB_DEPTH(format) == vo_dbpp)))
394 return vfcap;
396 if (IMGFMT_IS_BGR(format) || IMGFMT_IS_RGB(format)) {
397 set_graphtype(format, &mode);
399 if (ggiCheckMode(ggi_conf.drawvis, &mode) < 0) {
400 return 0;
401 } else {
402 return vfcap;
405 return 0;
408 static int preinit(const char *arg)
410 if (ggiInit() != 0) {
411 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to initialize GGI\n");
412 return -1;
414 #ifdef CONFIG_GGIWMH
415 if (ggiWmhInit() < 0) {
416 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to initialize libggiwmh\n");
417 return -1;
419 #endif
421 if (arg) {
422 int i = 0;
423 ggi_conf.driver = strdup(arg);
424 while (ggi_conf.driver[i] != '\0') {
425 if (ggi_conf.driver[i] == '.')
426 ggi_conf.driver[i] = ',';
427 i++;
429 } else {
430 ggi_conf.driver = NULL;
433 ggi_conf.vis = ggiOpen(ggi_conf.driver);
434 if (ggi_conf.vis == NULL) {
435 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to open '%s' output\n",
436 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
437 ggiExit();
438 return -1;
440 ggi_conf.drawvis = ggi_conf.vis;
443 #ifdef CONFIG_GGIWMH
444 ggiWmhAttach(ggi_conf.vis);
445 #endif
448 mp_msg(MSGT_VO, MSGL_V, "[ggi] using '%s' output\n",
449 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
451 return 0;
454 static void uninit(void)
456 if (ggi_conf.driver)
457 free(ggi_conf.driver);
459 #ifdef CONFIG_GGIWMH
460 ggiWmhDetach(ggi_conf.vis);
461 ggiWmhExit();
462 #endif
464 if (ggi_conf.drawvis != NULL && ggi_conf.drawvis != ggi_conf.vis)
465 ggiClose(ggi_conf.drawvis);
467 ggiClose(ggi_conf.vis);
468 ggiExit();
471 static int control(uint32_t request, void *data, ...)
473 switch (request) {
474 case VOCTRL_QUERY_FORMAT:
475 return query_format(*((uint32_t *) data));
476 case VOCTRL_GET_IMAGE:
477 return get_image(data);
478 #ifdef CONFIG_GGIWMH
479 case VOCTRL_ONTOP:
480 vo_ontop = (!(vo_ontop));
481 window_ontop();
482 return VO_TRUE;
483 #endif
485 return VO_NOTIMPL;
488 /* EVENT handling */
489 #include "osdep/keycodes.h"
491 static void check_events(void)
493 struct timeval tv = {0, 0};
494 ggi_event event;
495 ggi_event_mask mask;
497 if ((mask = ggiEventPoll(ggi_conf.vis, emAll, &tv))) {
498 if (ggiEventRead(ggi_conf.vis, &event, emAll) != 0) {
499 mp_dbg(MSGT_VO, MSGL_DBG3,
500 "type: %4x, origin: %4x, "
501 "sym: %4x, label: %4x, button=%4x\n",
502 event.any.origin, event.any.type, event.key.sym,
503 event.key.label, event.key.button);
505 switch (event.any.type) {
506 case evKeyPress:
507 switch (event.key.sym) {
508 case GIIK_PAsterisk: /* PStar */
509 case GIIUC_Asterisk:
510 mplayer_put_key('*');
511 break;
512 case GIIK_PSlash:
513 case GIIUC_Slash:
514 mplayer_put_key('/');
515 break;
516 case GIIK_PPlus:
517 case GIIUC_Plus:
518 mplayer_put_key('+');
519 break;
520 case GIIK_PMinus:
521 case GIIUC_Minus:
522 mplayer_put_key('-');
523 break;
524 case GIIUC_o:
525 case GIIUC_O:
526 mplayer_put_key('o');
527 break;
528 case GIIUC_g:
529 case GIIUC_G:
530 mplayer_put_key('g');
531 break;
532 case GIIUC_z:
533 case GIIUC_Z:
534 mplayer_put_key('z');
535 break;
536 case GIIUC_x:
537 case GIIUC_X:
538 mplayer_put_key('x');
539 break;
540 case GIIUC_m:
541 case GIIUC_M:
542 mplayer_put_key('m');
543 break;
544 case GIIUC_d:
545 case GIIUC_D:
546 mplayer_put_key('d');
547 break;
548 case GIIUC_q:
549 case GIIUC_Q:
550 mplayer_put_key('q');
551 break;
552 case GIIUC_h:
553 case GIIUC_H:
554 mplayer_put_key('h');
555 break;
556 case GIIUC_l:
557 case GIIUC_L:
558 mplayer_put_key('l');
559 break;
560 case GIIUC_Space:
561 case GIIUC_p:
562 case GIIUC_P:
563 mplayer_put_key('p');
564 break;
565 case GIIK_Up:
566 mplayer_put_key(KEY_UP);
567 break;
568 case GIIK_Down:
569 mplayer_put_key(KEY_DOWN);
570 break;
571 case GIIK_Left:
572 mplayer_put_key(KEY_LEFT);
573 break;
574 case GIIK_Right:
575 mplayer_put_key(KEY_RIGHT);
576 break;
577 case GIIK_PageUp:
578 mplayer_put_key(KEY_PAGE_UP);
579 break;
580 case GIIK_PageDown:
581 mplayer_put_key(KEY_PAGE_DOWN);
582 break;
583 default:
584 break;
585 } /* switch */
587 break;
588 } /* switch */
589 } /* if */
590 } /* if */
591 return;