diff --git a/src/bin/screenmode/screenmode.cpp b/src/bin/screenmode/screenmode.cpp index 2967780e8b..0891dcfe49 100644 --- a/src/bin/screenmode/screenmode.cpp +++ b/src/bin/screenmode/screenmode.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2008-2011, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ +#include #include #include #include @@ -18,6 +19,8 @@ static struct option const kLongOptions[] = { {"fall-back", no_argument, 0, 'f'}, + {"dont-confirm", no_argument, 0, 'q'}, + {"modeline", no_argument, 0, 'm'}, {"short", no_argument, 0, 's'}, {"list", no_argument, 0, 'l'}, {"help", no_argument, 0, 'h'}, @@ -47,6 +50,36 @@ color_space_for_depth(int32 depth) } +static void +print_mode(const screen_mode& mode, bool shortOutput) +{ + const char* format + = shortOutput ? "%ld %ld %ld %g\n" : "%ld %ld, %ld bits, %g Hz\n"; + printf(format, mode.width, mode.height, mode.BitsPerPixel(), mode.refresh); +} + + +static void +print_mode(const display_mode& displayMode, const screen_mode& mode) +{ + const display_timing& timing = displayMode.timing; + + printf("%lu %u %u %u %u %u %u %u %u ", timing.pixel_clock / 1000, + timing.h_display, timing.h_sync_start, timing.h_sync_end, + timing.h_total, timing.v_display, timing.v_sync_start, + timing.v_sync_end, timing.v_total); + + // TODO: more flags? + if ((timing.flags & B_POSITIVE_HSYNC) != 0) + printf(" +HSync"); + if ((timing.flags & B_POSITIVE_VSYNC) != 0) + printf(" +VSync"); + if ((timing.flags & B_TIMING_INTERLACED) != 0) + printf(" Interlace"); + printf(" %lu\n", mode.BitsPerPixel()); +} + + static void usage(int status) { @@ -55,11 +88,18 @@ usage(int status) "Sets the specified screen mode. When no screen mode has been chosen,\n" "the current one is printed. takes the form: \n" " , or x, etc.\n" - " --fall-back\tchanges to the standard fallback mode, and displays a\n" + " --fall-back\tchanges to the standard fallback mode, and " + "displays a\n" "\t\t\tnotification requester.\n" " -s --short\t\twhen no mode is given the current screen mode is\n" - "\t\t\tprinted in short form.\n" - " -l --list\t\tdisplay a list of the available modes\n", + "\t\t\tprinted in short form.\n" + " -l --list\t\tdisplay a list of the available modes.\n" + " -q --dont-confirm\tdo not confirm the mode after setting it.\n" + " -m --modeline\taccept and print X-style modeline modes:\n" + "\t\t\t \n" + "\t\t\t [flags] " + "[depth]\n" + "\t\t\t(supported flags are: +/-HSync, +/-VSync, Interlace)\n", kProgramName); exit(status); @@ -73,16 +113,19 @@ main(int argc, char** argv) bool setMode = false; bool shortOutput = false; bool listModes = false; + bool modeLine = false; + bool confirm = true; int width = -1; int height = -1; int depth = -1; float refresh = -1; + display_mode mode; // TODO: add a possibility to set a virtual screen size in addition to // the display resolution! int c; - while ((c = getopt_long(argc, argv, "shlf", kLongOptions, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "shlfqm", kLongOptions, NULL)) != -1) { switch (c) { case 0: break; @@ -96,6 +139,12 @@ main(int argc, char** argv) case 'l': listModes = true; break; + case 'm': + modeLine = true; + break; + case 'q': + confirm = false; + break; case 'h': usage(0); break; @@ -109,22 +158,70 @@ main(int argc, char** argv) int depthIndex = -1; // arguments to specify the mode are following - int parsed = sscanf(argv[optind], "%dx%dx%d", &width, &height, &depth); - if (parsed == 2) - depthIndex = optind + 1; - else if (parsed == 1) { - if (argc - optind > 1) { - height = strtol(argv[optind + 1], NULL, 0); - depthIndex = optind + 2; - } else - usage(1); - } else if (parsed != 3) - usage(1); - if (depthIndex > 0 && depthIndex < argc) - depth = strtol(argv[depthIndex], NULL, 0); - if (depthIndex + 1 < argc) - refresh = strtod(argv[depthIndex + 1], NULL); + if (!modeLine) { + int parsed = sscanf(argv[optind], "%dx%dx%d", &width, &height, + &depth); + if (parsed == 2) + depthIndex = optind + 1; + else if (parsed == 1) { + if (argc - optind > 1) { + height = strtol(argv[optind + 1], NULL, 0); + depthIndex = optind + 2; + } else + usage(1); + } else if (parsed != 3) + usage(1); + + if (depthIndex > 0 && depthIndex < argc) + depth = strtol(argv[depthIndex], NULL, 0); + if (depthIndex + 1 < argc) + refresh = strtod(argv[depthIndex + 1], NULL); + } else { + // parse mode line + if (argc - optind < 9) + usage(1); + + mode.timing.pixel_clock = strtol(argv[optind], NULL, 0) * 1000; + mode.timing.h_display = strtol(argv[optind + 1], NULL, 0); + mode.timing.h_sync_start = strtol(argv[optind + 2], NULL, 0); + mode.timing.h_sync_end = strtol(argv[optind + 3], NULL, 0); + mode.timing.h_total = strtol(argv[optind + 4], NULL, 0); + mode.timing.h_display = strtol(argv[optind + 5], NULL, 0); + mode.timing.h_sync_start = strtol(argv[optind + 6], NULL, 0); + mode.timing.h_sync_end = strtol(argv[optind + 7], NULL, 0); + mode.timing.h_total = strtol(argv[optind + 8], NULL, 0); + mode.timing.flags = 0; + mode.space = B_RGB32; + + int i = optind + 9; + while (i < argc) { + if (!strcasecmp(argv[i], "+HSync")) + mode.timing.flags |= B_POSITIVE_HSYNC; + else if (!strcasecmp(argv[i], "+VSync")) + mode.timing.flags |= B_POSITIVE_VSYNC; + else if (!strcasecmp(argv[i], "Interlace")) + mode.timing.flags |= B_TIMING_INTERLACED; + else if (!strcasecmp(argv[i], "-VSync") + || !strcasecmp(argv[i], "-HSync")) { + // okay, but nothing to do + } else if (isdigit(argv[i][0]) && i + 1 == argc) { + // bits per pixel + mode.space + = color_space_for_depth(strtoul(argv[i], NULL, 0)); + } else { + fprintf(stderr, "Unknown flag: %s\n", argv[i]); + exit(1); + } + + i++; + } + + mode.virtual_width = mode.timing.h_display; + mode.virtual_height = mode.timing.v_display; + mode.h_display_start = 0; + mode.v_display_start = 0; + } setMode = true; } @@ -135,29 +232,39 @@ main(int argc, char** argv) screen_mode currentMode; screenMode.Get(currentMode); - if ((!setMode) && (!listModes)) { - const char* format = shortOutput - ? "%ld %ld %ld %g\n" : "Resolution: %ld %ld, %ld bits, %g Hz\n"; - printf(format, currentMode.width, currentMode.height, - currentMode.BitsPerPixel(), currentMode.refresh); + if (listModes) { + // List all reported modes + if (!shortOutput) + printf("Available screen modes:\n"); + + for (int index = 0; index < screenMode.CountModes(); index++) { + if (modeLine) { + print_mode(screenMode.DisplayModeAt(index), + screenMode.ModeAt(index)); + } else + print_mode(screenMode.ModeAt(index), shortOutput); + } + + return 0; + } + + if (!setMode) { + // Just print the current mode + if (modeLine) { + display_mode mode; + screenMode.Get(mode); + print_mode(mode, currentMode); + } else { + if (!shortOutput) + printf("Resolution: "); + print_mode(currentMode, shortOutput); + } return 0; } screen_mode newMode = currentMode; - if (listModes) { - const int modeCount = screenMode.CountModes(); - printf("Available screen modes :\n"); - - for (int modeNumber = 0; modeNumber < modeCount; modeNumber++) { - currentMode = screenMode.ModeAt(modeNumber); - const char* format = shortOutput - ? "%ld %ld %ld %g\n" : "%ld %ld, %ld bits, %g Hz\n"; - printf(format, currentMode.width, currentMode.height, - currentMode.BitsPerPixel(), currentMode.refresh); - } - return 0; - } else if (fallbackMode) { + if (fallbackMode) { if (currentMode.width == 800 && currentMode.height == 600) { newMode.width = 640; newMode.height = 480; @@ -169,6 +276,10 @@ main(int argc, char** argv) newMode.space = B_RGB16; newMode.refresh = 60; } + } else if (modeLine) { + display_mode currentDisplayMode; + if (screenMode.Get(currentDisplayMode) == B_OK) + mode.flags = currentDisplayMode.flags; } else { newMode.width = width; newMode.height = height; @@ -184,9 +295,33 @@ main(int argc, char** argv) newMode.refresh = 60; } - status_t status = screenMode.Set(newMode); - if (status != B_OK) { - fprintf(stderr, "%s: Could not set screen mode %ldx%ldx%ldx: %s\n", + status_t status; + if (modeLine) + status = screenMode.Set(mode); + else + status = screenMode.Set(newMode); + + if (status == B_OK) { + if (confirm) { + printf("Is this mode okay (Y/n - will revert after 10 seconds)? "); + fflush(stdout); + + int flags = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + + bigtime_t end = system_time() + 10000000LL; + int c = 'n'; + while (system_time() < end) { + c = getchar(); + if (c != -1) + break; + } + + if (c != '\n' && c != 'y') + screenMode.Revert(); + } + } else { + fprintf(stderr, "%s: Could not set screen mode %ldx%ldx%ld: %s\n", kProgramName, newMode.width, newMode.height, newMode.BitsPerPixel(), strerror(status)); return 1;