int main(int argc, char** argv) { bool fallbackMode = false; 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; float brightness = std::nanf("0"); bool relativeBrightness = false; 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, "shlfqmb:", kLongOptions, NULL)) != -1) { switch (c) { case 0: break; case 'f': fallbackMode = true; setMode = true; confirm = false; break; case 's': shortOutput = true; break; case 'l': listModes = true; break; case 'm': modeLine = true; break; case 'q': confirm = false; break; case 'b': if (optarg[0] == '+' || optarg[0] == '-') relativeBrightness = true; brightness = atof(optarg); break; case 'h': usage(0); break; default: usage(1); break; } } if (argc - optind > 0) { int depthIndex = -1; // arguments to specify the mode are following 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.v_display = strtol(argv[optind + 5], NULL, 0); mode.timing.v_sync_start = strtol(argv[optind + 6], NULL, 0); mode.timing.v_sync_end = strtol(argv[optind + 7], NULL, 0); mode.timing.v_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; } BApplication application("application/x-vnd.Haiku-screenmode"); ScreenMode screenMode(NULL); screen_mode currentMode; screenMode.Get(currentMode); if (!isnan(brightness)) { BScreen screen; if (relativeBrightness) { float previousBrightness; screen.GetBrightness(&previousBrightness); brightness = previousBrightness + brightness; // Clamp to min/max values if (brightness < 0.f) brightness = 0.f; if (brightness > 1.f) brightness = 1.f; } if (brightness < 0.f || brightness > 1.f) printf("Brightness %f is out of range\n", brightness); screen.SetBrightness(brightness); } 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 (fallbackMode) { if (currentMode.width == 800 && currentMode.height == 600) { newMode.width = 640; newMode.height = 480; newMode.space = B_CMAP8; newMode.refresh = 60; } else { newMode.width = 800; newMode.height = 600; 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; if (depth != -1) newMode.space = color_space_for_depth(depth); else newMode.space = B_RGB32; if (refresh > 0) newMode.refresh = refresh; else newMode.refresh = 60; } 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; snooze(10000); } if (c != '\n' && tolower(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; } if (fallbackMode) { // display notification requester BAlert* alert = new BAlert("screenmode", "You have used the shortcut <Shift><Command><Ctrl><Escape> to " "reset the screen mode to a safe fallback.", "Keep", "Revert"); alert->SetShortcut(1, B_ESCAPE); if (alert->Go() == 1) screenMode.Revert(); } return 0; }