xref: /haiku/src/bin/screenmode/screenmode.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
1 /*
2  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <getopt.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <Alert.h>
13 #include <Application.h>
14 #include <Screen.h>
15 
16 #include "ScreenMode.h"
17 
18 
19 static struct option const kLongOptions[] = {
20 	{"fall-back", no_argument, 0, 'f'},
21 	{"short", no_argument, 0, 's'},
22 	{"help", no_argument, 0, 'h'},
23 	{NULL}
24 };
25 
26 extern const char *__progname;
27 static const char *kProgramName = __progname;
28 
29 
30 static color_space
31 color_space_for_depth(int32 depth)
32 {
33 	switch (depth) {
34 		case 8:
35 			return B_CMAP8;
36 		case 15:
37 			return B_RGB15;
38 		case 16:
39 			return B_RGB16;
40 		case 24:
41 			return B_RGB24;
42 		case 32:
43 		default:
44 			return B_RGB32;
45 	}
46 }
47 
48 
49 static void
50 usage(int status)
51 {
52 	fprintf(stderr,
53 		"Usage: %s [options] <mode>\n"
54 		"Sets the specified screen mode. When no screen mode has been chosen,\n"
55 		"the current one is printed. <mode> takes the form: <width> <height>\n"
56 		"<depth> <refresh-rate>, or <width>x<height>, etc.\n"
57 		"      --fall-back\tchanges to the standard fallback mode, and displays a\n"
58 		"\t\t\tnotification requester.\n"
59 		"  -s  --short\t\twhen no mode is given the current screen mode is\n"
60 		"\t\t\tprinted in short form.\n",
61 		kProgramName);
62 
63 	exit(status);
64 }
65 
66 
67 int
68 main(int argc, char** argv)
69 {
70 	bool fallbackMode = false;
71 	bool setMode = false;
72 	bool shortOutput = false;
73 	int width = -1;
74 	int height = -1;
75 	int depth = -1;
76 	float refresh = -1;
77 
78 	// TODO: add a possibility to set a virtual screen size in addition to
79 	// the display resolution!
80 
81 	int c;
82 	while ((c = getopt_long(argc, argv, "sh", kLongOptions, NULL)) != -1) {
83 		switch (c) {
84 			case 0:
85 				break;
86 			case 'f':
87 				fallbackMode = true;
88 				setMode = true;
89 				break;
90 			case 's':
91 				shortOutput = true;
92 				break;
93 			case 'h':
94 				usage(0);
95 				break;
96 			default:
97 				usage(1);
98 				break;
99 		}
100 	}
101 
102 	if (argc - optind > 0) {
103 		int depthIndex = -1;
104 
105 		// arguments to specify the mode are following
106 		int parsed = sscanf(argv[optind], "%dx%dx%d", &width, &height, &depth);
107 		if (parsed == 2)
108 			depthIndex = optind + 1;
109 		else if (parsed == 1) {
110 			if (argc - optind > 1) {
111 				height = strtol(argv[optind + 1], NULL, 0);
112 				depthIndex = optind + 2;
113 			} else
114 				usage(1);
115 		} else if (parsed != 3)
116 			usage(1);
117 
118 		if (depthIndex > 0 && depthIndex < argc)
119 			depth = strtol(argv[depthIndex], NULL, 0);
120 		if (depthIndex + 1 < argc)
121 			refresh = strtod(argv[depthIndex + 1], NULL);
122 
123 		setMode = true;
124 	}
125 
126 	BApplication application("application/x-vnd.Haiku-screenmode");
127 
128 	ScreenMode screenMode(NULL);
129 	screen_mode currentMode;
130 	screenMode.Get(currentMode);
131 
132 	if (!setMode) {
133 		const char* format = shortOutput
134 			? "%ld %ld %ld %g\n" : "Resolution: %ld %ld, %ld bits, %g Hz\n";
135 		printf(format, currentMode.width, currentMode.height,
136 			currentMode.BitsPerPixel(), currentMode.refresh);
137 		return 0;
138 	}
139 
140 	screen_mode newMode = currentMode;
141 
142 	if (fallbackMode) {
143 		if (currentMode.width == 800 && currentMode.height == 600) {
144 			newMode.width = 640;
145 			newMode.height = 480;
146 			newMode.space = B_CMAP8;
147 			newMode.refresh = 60;
148 		} else {
149 			newMode.width = 800;
150 			newMode.height = 600;
151 			newMode.space = B_RGB16;
152 			newMode.refresh = 60;
153 		}
154 	} else {
155 		newMode.width = width;
156 		newMode.height = height;
157 
158 		if (depth != -1)
159 			newMode.space = color_space_for_depth(depth);
160 		else
161 			newMode.space = B_RGB32;
162 
163 		if (refresh > 0)
164 			newMode.refresh = refresh;
165 		else
166 			newMode.refresh = 60;
167 	}
168 
169 	status_t status = screenMode.Set(newMode);
170 	if (status != B_OK) {
171 		fprintf(stderr, "%s: Could not set screen mode %ldx%ldx%ldx: %s\n",
172 			kProgramName, newMode.width, newMode.height, newMode.BitsPerPixel(),
173 			strerror(status));
174 		return 1;
175 	}
176 
177 	if (fallbackMode) {
178 		// display notification requester
179 		BAlert* alert = new BAlert("screenmode",
180 			"You have used the shortcut <Command><Ctrl><Escape> to reset the "
181 			"screen mode to a safe fallback.", "Keep", "Revert");
182 		if (alert->Go() == 1)
183 			screenMode.Revert();
184 	}
185 
186 	return 0;
187 }
188