/* $Id: monitest.c,v 1.10 2005/07/30 11:58:40 cegger Exp $ ****************************************************************************** Monitor test pattern generator Written in 1998 by Hartmut Niemann This software is placed in the public domain and can be used freely for any purpose. It comes without any kind of warranty, either expressed or implied, including, but not limited to the implied warranties of merchantability or fitness for a particular purpose. Use it at your own risk. the author is not responsible for any damage or consequences raised by use or inability to use this program. ****************************************************************************** This program creates a test pattern like ctmon3 and the Nokia montest program created or is/was broadcast on tv during program breaks, when there was no 24h program. The second part is a convergence test researched from the Nokia program, to check whether red, green and blue beams are adjusted properly. for a first glance: run monitest 640x480 or monitest Very much is copied from ./demo.c The text output would require about 400x300 dots, but it works with less too. ****************************************************************************** */ #include "config.h" #include #include #include #include #include "monitest.h" #include "ggitext.h" #include "menu.h" #include "drawlib.h" #ifdef HAVE_KGIMON_H #include "kgitune.h" #else #define is_kgicondev(x) (0) #define kgitune(x) do{}while(0) #endif static ggi_visual_t vis; static int kgidevice; ggi_pixel white, black, red, green, blue, yellow, magenta, cyan; static void usage(const char *prog) { fprintf(stderr, "Usage:\n\n" "%s \n\n" "Default: %s 8 320 200\n", prog, prog); exit(1); } int waitabit(ggi_visual_t _vis) { int key; key = ggiGetc(_vis); if (toupper((uint8_t)key) == 'Q') { /* Q pressed */ ggiClose(_vis); ggiExit(); exit(1); } else if (key == GIIUC_Escape || toupper((uint8_t)key) == 'B') { return 1; } return 0; } static void setcolors(void) { /* just set the needed colour names */ ggi_color col; col.r = 0xFFFF; col.g = 0xFFFF; col.b = 0xFFFF; white = ggiMapColor(vis, &col); col.r = 0xFFFF; col.g = 0xFFFF; col.b = 0x0000; yellow = ggiMapColor(vis, &col); col.r = 0xFFFF; col.g = 0x0000; col.b = 0xFFFF; magenta = ggiMapColor(vis, &col); col.r = 0xFFFF; col.g = 0x0000; col.b = 0x0000; red = ggiMapColor(vis, &col); col.r = 0x0000; col.g = 0xFFFF; col.b = 0xFFFF; cyan = ggiMapColor(vis, &col); col.r = 0x0000; col.g = 0xFFFF; col.b = 0x0000; green = ggiMapColor(vis, &col); col.r = 0x0000; col.g = 0x0000; col.b = 0xFFFF; blue = ggiMapColor(vis, &col); col.r = 0x0000; col.g = 0x0000; col.b = 0x0000; black = ggiMapColor(vis, &col); } static void convergence(ggi_visual_t _vis) { #define PARTSHOR 16 #define PARTSVERT 12 #define PARTX(x) (signed)((x)*(xmax-1)/PARTSHOR) #define PARTWIDTH (signed)(xmax/PARTSHOR) #define PARTY(y) (signed)((y)*(ymax-1)/PARTSVERT) #define PARTHEIGHT (signed)(ymax/PARTSVERT) unsigned int i, j, k, xmax, ymax; unsigned int f[3]; ggi_mode currmode; ggiGetMode(_vis, &currmode); xmax = currmode.visible.x; ymax = currmode.visible.y; f[0] = red; f[1] = green; f[2] = blue; for (k = 0; k < 4; k++) { ggiSetGCForeground(_vis, black); ggiFillscreen(_vis); for (i = 0; i <= PARTSHOR; i++) { for (j = 0; j <= PARTSVERT; j++) { ggiSetGCForeground(_vis, f[(i + j + k) % 3]); ggiDrawHLine(_vis, PARTX(i), PARTY(j), PARTWIDTH / 2); ggiDrawVLine(_vis, PARTX(i), PARTY(j), PARTHEIGHT / 2); ggiDrawHLine(_vis, PARTX(i) - PARTWIDTH / 2, PARTY(j), PARTWIDTH / 2); ggiDrawVLine(_vis, PARTX(i), PARTY(j) - PARTHEIGHT / 2, PARTHEIGHT / 2); } } ggiFlush(_vis); if (waitabit(_vis)) return; } } static void moiree(ggi_visual_t _vis) { int xmax, ymax; ggi_mode currmode; ggiGetMode(_vis, &currmode); xmax = currmode.visible.x; ymax = currmode.visible.y; stripevert(_vis, 0, 0, xmax - 1, ymax - 1, black, white, 1); ggiFlush(_vis); if (waitabit(_vis)) return; stripevert(_vis, 0, 0, xmax - 1, ymax - 1, red, white, 1); ggiFlush(_vis); if (waitabit(_vis)) return; stripevert(_vis, 0, 0, xmax - 1, ymax - 1, green, white, 1); ggiFlush(_vis); if (waitabit(_vis)) return; stripevert(_vis, 0, 0, xmax - 1, ymax - 1, blue, white, 1); ggiFlush(_vis); if (waitabit(_vis)) return; dotone(_vis, 0, 0, xmax - 1, ymax - 1, black, white); ggiFlush(_vis); if (waitabit(_vis)) return; dotone(_vis, 0, 0, xmax - 1, ymax - 1, red, white); ggiFlush(_vis); if (waitabit(_vis)) return; dotone(_vis, 0, 0, xmax - 1, ymax - 1, green, white); ggiFlush(_vis); if (waitabit(_vis)) return; dotone(_vis, 0, 0, xmax - 1, ymax - 1, blue, white); ggiFlush(_vis); if (waitabit(_vis)) return; chessboardone(_vis, 0, 0, xmax - 1, ymax - 1, black, white); ggiFlush(_vis); if (waitabit(_vis)) return; chessboardone(_vis, 0, 0, xmax - 1, ymax - 1, red, white); ggiFlush(_vis); if (waitabit(_vis)) return; chessboardone(_vis, 0, 0, xmax - 1, ymax - 1, green, white); ggiFlush(_vis); if (waitabit(_vis)) return; chessboardone(_vis, 0, 0, xmax - 1, ymax - 1, blue, white); ggiFlush(_vis); if (waitabit(_vis)) return; } #if 0 /* defined but not used */ char *helptext = { "GGI screntest program \n" "(c) H. Niemann, $Id: monitest.c,v 1.10 2005/07/30 11:58:40 cegger Exp $ \n" "h: this help screen \n" "q: quit this testscreen \n" "" }; static int help(void) { ggi_mode currmode; ggiGetMode(vis, &currmode); ggiGraphTextLongPuts(vis, currmode.visible.x / 2, currmode.visible.y / 2, 0, 0, GGI_TEXT_CENTER, helptext); waitabit(vis); return 0; } #endif static const ggi_coord resolutions[] = { {320, 200}, {320, 240}, {320, 350}, /* EGA text */ {360, 400}, /* VGA text */ {400, 300}, {480, 300}, {512, 384}, {640, 200}, /* EGA */ {640, 350}, /* EGA */ {640, 400}, {640, 480}, {720, 350}, /* MDA text */ {720, 400}, /* VGA text */ {800, 600}, {1024, 768}, {1152, 864}, {1280, 1024}, {1600, 1200}, {0, 0} /* End mark!! */ }; static const ggi_graphtype graphtypes[] = { /* can't handle textmode yet */ GT_1BIT, /* 1 bpp graphics */ GT_4BIT, /* 4 bpp graphics */ GT_8BIT, /* 8 bpp graphics */ GT_15BIT, /* 15 bpp graphics */ GT_16BIT, /* 16 bpp graphics */ GT_24BIT, /* 24 bpp graphics */ GT_32BIT, /* 24 bpp word aligned */ GT_INVALID }; static int resindex = -1; /* 'base' resolution of the mode set */ static int gtindex = -1; /* graphtype, i.e. bit depth */ static int xres = GGI_AUTO; /* visual resolution, might be different */ static int yres = GGI_AUTO; /* from the mode list */ static int guessmode(void) { /* try to guess the mode you're in and set resindex and gtindex */ /* done on startup. */ /* I could set up a certain mode at startup, but I don't want to */ ggi_mode currmode; int i; ggiGetMode(vis, &currmode); fprintf(stderr, "Current mode is %dx%d %u/%u.\n", currmode.visible.x, currmode.visible.y, GT_DEPTH(currmode.graphtype), GT_SIZE(currmode.graphtype)); xres = currmode.visible.x; yres = currmode.visible.y; /* find most possible resolution */ resindex = 0; /* if everything else fails: assume first mode:320x200 */ i = 0; while (resolutions[i].x != 0) { /* for now: only test exact match */ if ((xres == resolutions[i].x) && (yres == resolutions[i].y)) { resindex = i; fprintf(stderr, "Detected resolution %d: %dx%d.\n", resindex, resolutions[resindex].x, resolutions[resindex].y); } i++; } /* find mode you're in */ gtindex = -1; i = 0; while (graphtypes[i] != GT_INVALID) { if (graphtypes[i] == currmode.graphtype) { gtindex = i; fprintf(stderr, "Detected graphtype %u/%u\n", GT_DEPTH(graphtypes[gtindex]), GT_SIZE(graphtypes[gtindex])); break; } i++; } if (gtindex == -1) { return -1; } return 0; } static int changeresmenu(void) { struct menu cm; static int _select = 0; ggi_mode suggmode; char s[32]; char nextmodeline[100]; char prevmodeline[100]; char nextgtline[100]; char prevgtline[100]; char bottom[100]; int nextresindex, prevresindex; int nextgtindex, prevgtindex; nextresindex = prevresindex = 0; nextgtindex = prevgtindex = 0; default_menu(&cm, vis); cm.w.title = " Change Screen resolution "; cm.lastentry = 8; cm.entry[0].text = "1 Increase X"; cm.entry[1].text = "2 Decrease X"; cm.entry[2].text = "3 Increase Y"; cm.entry[3].text = "4 Decrease Y"; cm.entry[8].text = "9 Back"; sprintf(bottom, " "); for (;;) { nextresindex = resindex + 1; if (resolutions[nextresindex].x == 0) { nextresindex--; }; prevresindex = resindex - 1; if (prevresindex < 0) { prevresindex = 0; } nextgtindex = gtindex + 1; if (graphtypes[nextgtindex] == GT_INVALID) { nextgtindex--; } prevgtindex = gtindex - 1; if (prevgtindex < 0) { prevgtindex = 0; } sprintf(cm.entry[4].text = nextgtline, "5 Increase depth: %u/%u", GT_DEPTH(graphtypes[nextgtindex]), GT_SIZE(graphtypes[nextgtindex])); sprintf(cm.entry[5].text = prevgtline, "6 Decrease depth: %u/%u", GT_DEPTH(graphtypes[prevgtindex]), GT_SIZE(graphtypes[prevgtindex])); sprintf(cm.entry[6].text = nextmodeline, "7 next res.: %dx%d", resolutions[nextresindex].x, resolutions[nextresindex].y); sprintf(cm.entry[7].text = prevmodeline, "8 prev. res.: %dx%d", resolutions[prevresindex].x, resolutions[prevresindex].y); sprintf(s, "current: %4dx%3dx%u/%u", xres, yres, GT_DEPTH(graphtypes[gtindex]), GT_SIZE(graphtypes[gtindex])); cm.toptext = s; cm.bottomtext = bottom; calculate_menu(&cm); center_menu(&cm); /*sleep(1); */ testpattern(vis); ggiFlush(vis); switch (_select = do_menu(&cm, _select)) { case 0: xres += 1; break; case 1: xres -= 1; break; case 2: yres += 1; break; case 3: yres -= 1; break; case 4: gtindex = nextgtindex; break; case 5: gtindex = prevgtindex; break; case 6: resindex = nextresindex; xres = resolutions[resindex].x; yres = resolutions[resindex].y; break; case 7: resindex = prevresindex; xres = resolutions[resindex].x; yres = resolutions[resindex].y; break; case 8: case -1: testpattern(vis); /* clear menu */ return (0); default: ggiPanic("Internal error, wrong menu selection"); } /* try mode */ if (ggiCheckSimpleMode (vis, xres, yres, 1, graphtypes[gtindex], &suggmode) != 0) { /* failed */ sprintf(bottom, "mode set failed"); } else { if (ggiSetSimpleMode(vis, xres, yres, 1, graphtypes[gtindex]) != 0) { fprintf(stderr, "Set may not fail!!\n"); } else { sprintf(bottom, "mode set succeeded"); } /*sleep(1); */ /*ggiFlush(vis); */ if (GT_SCHEME(graphtypes[gtindex]) == GT_PALETTE) ggiSetColorfulPalette(vis); } setcolors(); /* necessary when depth changed */ } return 0; /* never get here */ } static int mainmenu(void) { struct menu mainm; static int _select = 0; default_menu(&mainm, vis); mainm.w.title = " * Main menu * "; mainm.entry[0].text = "1 Geometry and Colors"; mainm.entry[1].text = "2 Convergence"; mainm.entry[2].text = "3 Resolution"; mainm.entry[3].text = "4 Moiree"; mainm.entry[4].text = "5 Change Resolution"; mainm.entry[5].text = "6 Flat panel check"; if (kgidevice) { mainm.entry[6].text = "7 Tune KGIcon monitor timings"; mainm.entry[7].text = "8 Exit"; mainm.lastentry = 7; } else { mainm.entry[6].text = "7 Exit"; mainm.lastentry = 6; } mainm.toptext = "Please choose with arrows"; mainm.bottomtext = "and press "; calculate_menu(&mainm); for (;;) { center_menu(&mainm); /* if resolution changes, we must recenter */ switch (_select = do_menu(&mainm, _select)) { case 0: testpattern(vis); waitabit(vis); break; case 1: convergence(vis); break; case 2: resolution(vis); break; case 3: moiree(vis); break; case 4: changeresmenu(); break; case 5: flatpanel(vis); break; case 6: if (kgidevice) { testpattern(vis); kgitune(vis); } else { return 0; } break; case 7: case -1: return 0; break; /* never get here */ default: ggiPanic("Internal error, wrong menu selection"); } } return 0; /* never get here */ } int main(int argc, char **argv) { const char *prog = argv[0]; ggi_mode mo; if (argc == 1) { ggiParseMode("", &mo); } else if (argc == 2) { ggiParseMode(argv[1], &mo); } else { usage(prog); return 1; } if (ggiInit() < 0) { fprintf(stderr, "unable to initialize LibGGI, exiting.\n"); exit(1); } vis = ggiOpen(NULL); /* Null gives the default visual */ if (vis == NULL) { ggiPanic("unable to open default visual, exiting.\n"); } ggiSetFlags(vis, GGIFLAG_ASYNC); printf("Trying mode "); ggiPrintMode(&mo); printf("\n"); ggiCheckMode(vis, &mo); /*ggiCheckTextMode(vis,80,25,80,25,9,14,GT_TEXT16,&mo,NULL); */ printf("Suggested mode "); ggiPrintMode(&mo); printf("\n"); if (ggiSetMode(vis, &mo) != 0) { ggiPanic("unable to set any mode at all, exiting!\n"); return 2; } if (GT_SCHEME(mo.graphtype) == GT_PALETTE) ggiSetColorfulPalette(vis); kgidevice = is_kgicondev(vis); setcolors(); if (guessmode() != 0) { fprintf(stderr, "Warning: Could not guess mode, probably not a standard mode\n"); } testpattern(vis); mainmenu(); ggiClose(vis); ggiExit(); return 0; }