Example #1
0
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;
}