#include "cfg.h" #ifdef GRDRV_GRX #include "links.h" #include #include "arrow.inc" #define NUMBER_OF_DEVICES 12 static void grx_mouse_init(void); static void grx_mouse_terminate(void); void _GrCloseVideoDriver(void); extern struct graphics_driver grx_driver; static struct itrm *svgalib_kbd; static unsigned char *grx_driver_param = NULL; static struct graphics_device *grx_old_vd; static unsigned char in_graphics_mode = 0; #define TEST_INACTIVITY if (dev != current_virtual_device || !dev->clip.x2) return; #define TEST_INACTIVITY_0 if (dev != current_virtual_device || !dev->clip.x2) return 0; static void grx_set_palette(void) { unsigned i, colors; if (grx_driver.depth == 33) colors = 16; else if (grx_driver.depth == (65 | 0x300)) colors = 216; else if (grx_driver.depth == 65) colors = 256; else return; GrResetColors(); for (i = 0; i < colors; i++) { unsigned rgb[3]; q_palette(colors, i, 255, rgb); GrSetColor(i, rgb[0], rgb[1], rgb[2]); } return; } static void grx_update_palette(void) { int new_depth; if (!grx_driver.param->palette_mode) new_depth = grx_driver.depth | 0x300; else new_depth = grx_driver.depth & ~0x300; if (new_depth == grx_driver.depth) return; grx_driver.depth = new_depth; grx_driver.get_color = get_color_fn(new_depth); if (!grx_driver.get_color) internal_error("Unknown bit depth %x", new_depth); grx_mouse_terminate(); grx_set_palette(); grx_mouse_init(); } static void grx_set_text(void) { if (in_graphics_mode) { GrSetMode(GR_default_text); in_graphics_mode = 0; _GrCloseVideoDriver(); restore_terminal(); } } static void grx_restore(void) { if (grx_driver_param) mem_free(grx_driver_param), grx_driver_param = NULL; grx_set_text(); } static void grx_set_clip(void) { GrSetClipBox( current_virtual_device->clip.x1, current_virtual_device->clip.y1, current_virtual_device->clip.x2 - 1, current_virtual_device->clip.y2 - 1 ); } static void grx_key_in(struct itrm *p, unsigned char *ev_, int size) { int vd; struct links_event *ev = (struct links_event *)(void *)ev_; if (size != sizeof(struct links_event)) return; if (ev->ev == EV_ABORT) terminate_loop = 1; if (ev->ev != EV_KBD) return; if (ev->y & KBD_PASTING) goto skip; if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x >= '0' && ev->x <= '9') { vd = (ev->x - '1' + 10) % 10; goto switch_vd; } if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x == '-') { vd = 10; goto switch_vd; } if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x == '=') { vd = 11; goto switch_vd; } if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x <= KBD_F1 && ev->x >= KBD_F12) { vd = KBD_F1 - ev->x; goto switch_vd; } skip: if (g_kbd_codepage(&grx_driver) != utf8_table && ev->x >= 128 && ev->x <= 255) if ((ev->x = cp2u(ev->x, g_kbd_codepage(&grx_driver))) == -1) return; if (current_virtual_device && current_virtual_device->keyboard_handler) current_virtual_device->keyboard_handler(current_virtual_device, ev->x, ev->y); return; switch_vd: switch_virtual_device(vd); grx_set_clip(); } int grx_mouse_initialized = 0; static GrCursor *grx_mouse_cursor; static void grx_mouse_init(void) { int x, y; static unsigned char cursor[arrow_area]; static GrColor table[3]; if (!GrMouseDetect()) return; grx_mouse_initialized = 1; GrMouseInit(); GrMouseEventEnable(0, 1); memset(&table, 0, sizeof table); table[0] = 2; table[1] = grx_driver.get_color(0); table[2] = grx_driver.get_color(0xffffff); for (y = 0; y < arrow_height; y++) for (x = 0; x < arrow_width; x++) cursor[y * arrow_width + x] = (arrow[2 * y] >> (arrow_width - x - 1)) & 1 ? 1 : (arrow[2 * y + 1] >> (arrow_width - x - 1)) & 1 ? 2 : 0; grx_mouse_cursor = GrBuildCursor(cast_char cursor, arrow_width, arrow_width, arrow_height, 0, 0, table); if (!grx_mouse_cursor) GrMouseSetColors(grx_driver.get_color(0xffffff), grx_driver.get_color(0x000000)); else GrMouseSetCursor(grx_mouse_cursor); GrMouseDisplayCursor(); } static void grx_mouse_terminate(void) { if (!grx_mouse_initialized) return; GrMouseEraseCursor(); GrMouseUnInit(); if (grx_mouse_cursor) GrDestroyCursor(grx_mouse_cursor); grx_mouse_initialized = 0; } void grx_mouse_poll(void) { int x = GrMousePendingEvent(); x = x; } static void grx_do_event(GrMouseEvent *ev, int b) { if (!current_virtual_device) return; if (current_virtual_device->mouse_handler) current_virtual_device->mouse_handler(current_virtual_device, ev->x, ev->y, b); } int grx_mouse_event(void) { int e; GrMouseEvent ev; e = 0; get_another: GrMouseGetEvent(GR_M_MOTION | GR_M_BUTTON_CHANGE | GR_M_POLL, &ev); if (ev.flags & GR_M_LEFT_DOWN) grx_do_event(&ev, B_LEFT | B_DOWN), e = 1; if (ev.flags & GR_M_LEFT_UP) grx_do_event(&ev, B_LEFT | B_UP), e = 1; if (ev.flags & GR_M_RIGHT_DOWN) grx_do_event(&ev, B_RIGHT | B_DOWN), e = 1; if (ev.flags & GR_M_RIGHT_UP) grx_do_event(&ev, B_RIGHT | B_UP), e = 1; if (ev.flags & GR_M_MIDDLE_DOWN) grx_do_event(&ev, B_MIDDLE | B_DOWN), e = 1; if (ev.flags & GR_M_MIDDLE_UP) grx_do_event(&ev, B_MIDDLE | B_UP), e = 1; if (ev.flags & GR_M_P4_DOWN) grx_do_event(&ev, B_WHEELUP | B_MOVE), e = 1; if (ev.flags & GR_M_P5_DOWN) grx_do_event(&ev, B_WHEELDOWN | B_MOVE), e = 1; if (!e && ev.flags & GR_M_MOTION) { if (GrMousePendingEvent()) goto get_another; grx_do_event(&ev, ev.buttons & GR_M_LEFT ? B_LEFT | B_DRAG : ev.buttons & GR_M_RIGHT ? B_RIGHT | B_DRAG : ev.buttons & GR_M_MIDDLE ? B_DRAG | B_MIDDLE : B_MOVE), e = 1; } return e; } static unsigned char *set_mode_according_to_param(unsigned char *param) { unsigned char e[MAX_STR_LEN]; save_terminal(); if (!param || !*param) { return stracpy(cast_uchar "There is no default videomode.\nUse the switch \"-mode WIDTHxHEIGHTxCOLORS\" to select video mode.\nThe COLORS argument may be 16, 256, 32k, 64k, 16M.\n"); #if 0 if (!GrSetMode(GR_default_graphics)) return stracpy(cast_uchar "GrSetMode failed.\n"); in_graphics_mode = 1; #endif } else { unsigned long x, y; int pl; unsigned char *ptr = param; char *end; x = strtoul(cast_const_char ptr, &end, 10); if (cast_uchar end == ptr || *end != 'x' || x >= MAXINT) goto bad_param; ptr = cast_uchar end + 1; y = strtoul(cast_const_char ptr, &end, 10); if (cast_uchar end == ptr || *end != 'x' || y >= MAXINT) goto bad_param; ptr = cast_uchar end + 1; if (!strcmp(cast_const_char ptr, "16")) pl = 4; else if (!strcmp(cast_const_char ptr, "256")) pl = 8; else if (!casestrcmp(ptr, cast_uchar "32k") || !strcmp(cast_const_char ptr, "32768")) pl = 15; else if (!casestrcmp(ptr, cast_uchar "64k") || !strcmp(cast_const_char ptr, "65536")) pl = 16; else if (!casestrcmp(ptr, cast_uchar "16M") || !casestrcmp(ptr, cast_uchar "16M32") || !strcmp(cast_const_char ptr, "16777216")) pl = 24; else goto bad_param; if (x == 800 && y == 600 && pl == 4) y = 599; /* a bug in GRX */ if (!GrSetMode(GR_width_height_bpp_graphics, (int)x, (int)y, pl)) { snprintf(cast_char e, MAX_STR_LEN, "GrSetMode(%lu,%lu,%d) failed.\n", x, y, pl); return stracpy(e); } in_graphics_mode = 1; } return NULL; bad_param: return stracpy(cast_uchar "Bad -mode parameter.\n"); } static void grx_set_graphics(void) { if (!in_graphics_mode) { unsigned char *er; er = set_mode_according_to_param(grx_driver_param); if (er) fatal_exit("grx: Unable to restore video mode '%s': %s", grx_driver_param, er); } } static unsigned char *grx_init_driver(unsigned char *param, unsigned char *ignore) { unsigned char e[MAX_STR_LEN]; unsigned char *er; const GrVideoMode *mode; const GrFrameDriver *fd; kbd_set_raw = 1; grx_old_vd = NULL; er = set_mode_according_to_param(param); if (er) return er; mode = GrCurrentVideoMode(); fd = GrScreenFrameDriver(); if (GrNumPlanes() != (mode->bpp == 4 ? 4 : 1)) { unsupported_videomode: snprintf(cast_char e, MAX_STR_LEN, "Unsupported videomode: x %d, y %d, bpp (%d, %d), planes %d.\n", mode->width, mode->height, mode->bpp, fd->bits_per_pixel, (int)GrNumPlanes()); grx_restore(); return stracpy(e); } grx_driver.flags &= ~GD_SELECT_PALETTE; switch (mode->bpp) { case 4: grx_driver.depth = 33; break; case 8: grx_driver.depth = 65; if (!grx_driver.param->palette_mode) grx_driver.depth |= 0x300; grx_driver.flags |= GD_SELECT_PALETTE; break; case 15: grx_driver.depth = 122; break; case 16: grx_driver.depth = 130; break; case 24: case 32: if (fd->bits_per_pixel == 24) grx_driver.depth = 195; else if (fd->bits_per_pixel == 32) grx_driver.depth = 196; else goto unsupported_videomode; break; default: goto unsupported_videomode; } grx_driver.get_color = get_color_fn(grx_driver.depth); if (!grx_driver.get_color) internal_error("Unknown bit depth %x", grx_driver.depth); grx_driver.x = mode->width; grx_driver.y = mode->height; if (mode->bpp >= 8) grx_driver.flags |= GD_DONT_USE_SCROLL; else grx_driver.flags &= ~GD_DONT_USE_SCROLL; /*fatal_exit("current mode: %d,%d,%d planes %d bits %d %d", mode->width, mode->height, mode->bpp, GrNumPlanes(), GrScreenFrameDriver()->bits_per_pixel, mode->bpp);*/ grx_set_palette(); grx_driver_param = stracpy(param ? param : cast_uchar ""); init_virtual_devices(&grx_driver, NUMBER_OF_DEVICES); svgalib_kbd = handle_svgalib_keyboard(grx_key_in); grx_mouse_init(); return NULL; } static void grx_shutdown_driver(void) { shutdown_virtual_devices(); grx_mouse_terminate(); svgalib_free_trm(svgalib_kbd); grx_restore(); } static void grx_emergency_shutdown(void) { grx_restore(); } static unsigned char *grx_get_driver_param(void) { return grx_driver_param; } struct grx_bmp { GrContext c; }; static int grx_get_empty_bitmap(struct bitmap *bmp) { struct grx_bmp *b; if (!in_graphics_mode) internal_error("grx_get_empty_bitmap: not in graphics mode"); b = mem_alloc_mayfail(sizeof(struct grx_bmp)); if (!b) goto fail0; again1: if (!GrCreateContext(bmp->x, bmp->y, NULL, &b->c)) { if (out_of_memory(0, NULL, 0)) goto again1; goto fail1; } bmp->flags = b; if (GrNumPlanes() == 1) { bmp->data = b->c.gc_baseaddr[0]; bmp->skip = b->c.gc_lineoffset; } else { if (bmp->x && (unsigned)bmp->x * (unsigned)bmp->y / (unsigned)bmp->x != (unsigned)bmp->y) goto fail2; if ((unsigned)bmp->x * (unsigned)bmp->y > (unsigned)MAXINT) goto fail2; bmp->skip = bmp->x; bmp->data = mem_alloc_mayfail(bmp->skip * bmp->y); if (!bmp->data) goto fail2; } return 0; fail2: GrDestroyContext(&b->c); fail1: mem_free(b); fail0: bmp->data = NULL; bmp->flags = NULL; return -1; } static void grx_copy_planes(struct bitmap *bmp, int y, int n) { struct grx_bmp *b = bmp->flags; int j; if (!b) return; for (j = 0; j < n; y++, j++) { int i; for (i = 0; i < GrNumPlanes(); i++) { int x; unsigned char *src = (unsigned char *)bmp->data + bmp->skip * j; unsigned char *dst = (unsigned char *)b->c.gc_baseaddr[i] + y * b->c.gc_lineoffset; unsigned char byt = 0; for (x = 0; x < bmp->x; ) { unsigned char bit = (*src++ >> i) & 1; byt |= bit << ((x & 7) ^ 7); x++; if (!(x & 7)) *dst++ = byt, byt = 0; } if (x & 7) *dst = byt; } } } static void grx_register_bitmap(struct bitmap *bmp) { if (GrNumPlanes() != 1) { grx_copy_planes(bmp, 0, bmp->y); mem_free(bmp->data); } } static void *grx_prepare_strip(struct bitmap *bmp, int top, int lines) { struct grx_bmp *b = bmp->flags; if (!b) return NULL; if (GrNumPlanes() != 1) { bmp->data = mem_alloc_mayfail(bmp->skip * lines); return bmp->data; } return ((unsigned char *)bmp->data) + bmp->skip * top; } static void grx_commit_strip(struct bitmap *bmp, int top, int lines) { if (GrNumPlanes() != 1) { if (!bmp->data) return; grx_copy_planes(bmp, top, lines); mem_free(bmp->data); } } static void grx_unregister_bitmap(struct bitmap *bmp) { struct grx_bmp *b = bmp->flags; if (!b) return; GrDestroyContext(&b->c); mem_free(b); } static void grx_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y) { struct grx_bmp *b = bmp->flags; if (!b) return; TEST_INACTIVITY CLIP_DRAW_BITMAP /* note: GrImageDisplay has buggy clipping. It doesn't draw if the target x or y coordinate is one pixel before the end of clip area */ GrBitBlt(NULL, x, y, &b->c, 0, 0, bmp->x - 1, bmp->y - 1, GrWRITE); } static void grx_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color) { TEST_INACTIVITY CLIP_FILL_AREA if (x1 >= x2 || y1 >= y2) return; GrFilledBox(x1, y1, x2 - 1, y2 - 1, color); } static void grx_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color) { TEST_INACTIVITY CLIP_DRAW_HLINE GrHLine(x1, x2 - 1, y, color); } static void grx_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color) { TEST_INACTIVITY CLIP_DRAW_VLINE GrVLine(x, y1, y2 - 1, color); } static int grx_scroll(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy) { TEST_INACTIVITY_0 GrBitBlt(NULL, dev->clip.x1 + (scx >= 0 ? scx : 0), dev->clip.y1 + (scy >= 0 ? scy : 0), NULL, dev->clip.x1 - (scx < 0 ? scx : 0), dev->clip.y1 - (scy < 0 ? scy : 0), dev->clip.x2 - (scx >= 0 ? scx : 0) - 1, dev->clip.y2 - (scy >= 0 ? scy : 0) - 1, GrWRITE); return 1; } static void grx_set_clip_area(struct graphics_device *dev) { if (dev != current_virtual_device) return; grx_set_clip(); } static int grx_block(struct graphics_device *dev) { if (grx_old_vd) return 1; grx_old_vd = current_virtual_device; current_virtual_device = NULL; grx_mouse_terminate(); svgalib_block_itrm(svgalib_kbd); grx_set_text(); return 0; } static int grx_unblock(struct graphics_device *dev) { if (current_virtual_device) { internal_error("grx_unblock called without grx_block"); return 0; } grx_set_graphics(); svgalib_unblock_itrm(svgalib_kbd); current_virtual_device = grx_old_vd; grx_old_vd = NULL; grx_set_palette(); grx_set_clip(); grx_mouse_init(); if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device, ¤t_virtual_device->size); return 0; } struct graphics_driver grx_driver = { cast_uchar "grx", grx_init_driver, init_virtual_device, shutdown_virtual_device, grx_shutdown_driver, grx_emergency_shutdown, NULL, grx_get_driver_param, NULL, NULL, NULL, grx_get_empty_bitmap, grx_register_bitmap, grx_prepare_strip, grx_commit_strip, grx_unregister_bitmap, grx_draw_bitmap, NULL, grx_fill_area, grx_draw_hline, grx_draw_vline, grx_scroll, grx_set_clip_area, NULL, grx_block, grx_unblock, grx_update_palette, /* set_palette */ NULL, /* get_real_colors */ NULL, /* set_title */ NULL, /* exec */ NULL, /* set_clipboard_text */ NULL, /* get_clipboard_text */ 0, /* depth */ 0, 0, /* size */ GD_NEED_CODEPAGE, /* flags */ NULL, /* param */ }; #endif