vfs: check userland buffers before reading them.
[haiku.git] / src / bin / screenmode / screenmode.cpp
bloba1585fc7e9148d4e9c6803f6718264ca65a3b8f5
1 /*
2 * Copyright 2008-2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <ctype.h>
8 #include <getopt.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <strings.h>
14 #include <Alert.h>
15 #include <Application.h>
16 #include <Screen.h>
18 #include "ScreenMode.h"
21 static struct option const kLongOptions[] = {
22 {"fall-back", no_argument, 0, 'f'},
23 {"dont-confirm", no_argument, 0, 'q'},
24 {"modeline", no_argument, 0, 'm'},
25 {"short", no_argument, 0, 's'},
26 {"list", no_argument, 0, 'l'},
27 {"help", no_argument, 0, 'h'},
28 {NULL}
31 extern const char *__progname;
32 static const char *kProgramName = __progname;
35 static color_space
36 color_space_for_depth(int32 depth)
38 switch (depth) {
39 case 8:
40 return B_CMAP8;
41 case 15:
42 return B_RGB15;
43 case 16:
44 return B_RGB16;
45 case 24:
46 return B_RGB24;
47 case 32:
48 default:
49 return B_RGB32;
54 static void
55 print_mode(const screen_mode& mode, bool shortOutput)
57 const char* format
58 = shortOutput ? "%ld %ld %ld %g\n" : "%ld %ld, %ld bits, %g Hz\n";
59 printf(format, mode.width, mode.height, mode.BitsPerPixel(), mode.refresh);
63 static void
64 print_mode(const display_mode& displayMode, const screen_mode& mode)
66 const display_timing& timing = displayMode.timing;
68 printf("%lu %u %u %u %u %u %u %u %u ", timing.pixel_clock / 1000,
69 timing.h_display, timing.h_sync_start, timing.h_sync_end,
70 timing.h_total, timing.v_display, timing.v_sync_start,
71 timing.v_sync_end, timing.v_total);
73 // TODO: more flags?
74 if ((timing.flags & B_POSITIVE_HSYNC) != 0)
75 printf(" +HSync");
76 if ((timing.flags & B_POSITIVE_VSYNC) != 0)
77 printf(" +VSync");
78 if ((timing.flags & B_TIMING_INTERLACED) != 0)
79 printf(" Interlace");
80 printf(" %lu\n", mode.BitsPerPixel());
84 static void
85 usage(int status)
87 fprintf(stderr,
88 "Usage: %s [options] <mode>\n"
89 "Sets the specified screen mode. When no screen mode has been chosen,\n"
90 "the current one is printed. <mode> takes the form: <width> <height>\n"
91 "<depth> <refresh-rate>, or <width>x<height>, etc.\n"
92 " --fall-back\tchanges to the standard fallback mode, and "
93 "displays a\n"
94 "\t\t\tnotification requester.\n"
95 " -s --short\t\twhen no mode is given the current screen mode is\n"
96 "\t\t\tprinted in short form.\n"
97 " -l --list\t\tdisplay a list of the available modes.\n"
98 " -q --dont-confirm\tdo not confirm the mode after setting it.\n"
99 " -m --modeline\taccept and print X-style modeline modes:\n"
100 "\t\t\t <pclk> <h-display> <h-sync-start> <h-sync-end> <h-total>\n"
101 "\t\t\t <v-disp> <v-sync-start> <v-sync-end> <v-total> [flags] "
102 "[depth]\n"
103 "\t\t\t(supported flags are: +/-HSync, +/-VSync, Interlace)\n",
104 kProgramName);
106 exit(status);
111 main(int argc, char** argv)
113 bool fallbackMode = false;
114 bool setMode = false;
115 bool shortOutput = false;
116 bool listModes = false;
117 bool modeLine = false;
118 bool confirm = true;
119 int width = -1;
120 int height = -1;
121 int depth = -1;
122 float refresh = -1;
123 display_mode mode;
125 // TODO: add a possibility to set a virtual screen size in addition to
126 // the display resolution!
128 int c;
129 while ((c = getopt_long(argc, argv, "shlfqm", kLongOptions, NULL)) != -1) {
130 switch (c) {
131 case 0:
132 break;
133 case 'f':
134 fallbackMode = true;
135 setMode = true;
136 confirm = false;
137 break;
138 case 's':
139 shortOutput = true;
140 break;
141 case 'l':
142 listModes = true;
143 break;
144 case 'm':
145 modeLine = true;
146 break;
147 case 'q':
148 confirm = false;
149 break;
150 case 'h':
151 usage(0);
152 break;
153 default:
154 usage(1);
155 break;
159 if (argc - optind > 0) {
160 int depthIndex = -1;
162 // arguments to specify the mode are following
164 if (!modeLine) {
165 int parsed = sscanf(argv[optind], "%dx%dx%d", &width, &height,
166 &depth);
167 if (parsed == 2)
168 depthIndex = optind + 1;
169 else if (parsed == 1) {
170 if (argc - optind > 1) {
171 height = strtol(argv[optind + 1], NULL, 0);
172 depthIndex = optind + 2;
173 } else
174 usage(1);
175 } else if (parsed != 3)
176 usage(1);
178 if (depthIndex > 0 && depthIndex < argc)
179 depth = strtol(argv[depthIndex], NULL, 0);
180 if (depthIndex + 1 < argc)
181 refresh = strtod(argv[depthIndex + 1], NULL);
182 } else {
183 // parse mode line
184 if (argc - optind < 9)
185 usage(1);
187 mode.timing.pixel_clock = strtol(argv[optind], NULL, 0) * 1000;
188 mode.timing.h_display = strtol(argv[optind + 1], NULL, 0);
189 mode.timing.h_sync_start = strtol(argv[optind + 2], NULL, 0);
190 mode.timing.h_sync_end = strtol(argv[optind + 3], NULL, 0);
191 mode.timing.h_total = strtol(argv[optind + 4], NULL, 0);
192 mode.timing.v_display = strtol(argv[optind + 5], NULL, 0);
193 mode.timing.v_sync_start = strtol(argv[optind + 6], NULL, 0);
194 mode.timing.v_sync_end = strtol(argv[optind + 7], NULL, 0);
195 mode.timing.v_total = strtol(argv[optind + 8], NULL, 0);
196 mode.timing.flags = 0;
197 mode.space = B_RGB32;
199 int i = optind + 9;
200 while (i < argc) {
201 if (!strcasecmp(argv[i], "+HSync"))
202 mode.timing.flags |= B_POSITIVE_HSYNC;
203 else if (!strcasecmp(argv[i], "+VSync"))
204 mode.timing.flags |= B_POSITIVE_VSYNC;
205 else if (!strcasecmp(argv[i], "Interlace"))
206 mode.timing.flags |= B_TIMING_INTERLACED;
207 else if (!strcasecmp(argv[i], "-VSync")
208 || !strcasecmp(argv[i], "-HSync")) {
209 // okay, but nothing to do
210 } else if (isdigit(argv[i][0]) && i + 1 == argc) {
211 // bits per pixel
212 mode.space
213 = color_space_for_depth(strtoul(argv[i], NULL, 0));
214 } else {
215 fprintf(stderr, "Unknown flag: %s\n", argv[i]);
216 exit(1);
219 i++;
222 mode.virtual_width = mode.timing.h_display;
223 mode.virtual_height = mode.timing.v_display;
224 mode.h_display_start = 0;
225 mode.v_display_start = 0;
228 setMode = true;
231 BApplication application("application/x-vnd.Haiku-screenmode");
233 ScreenMode screenMode(NULL);
234 screen_mode currentMode;
235 screenMode.Get(currentMode);
237 if (listModes) {
238 // List all reported modes
239 if (!shortOutput)
240 printf("Available screen modes:\n");
242 for (int index = 0; index < screenMode.CountModes(); index++) {
243 if (modeLine) {
244 print_mode(screenMode.DisplayModeAt(index),
245 screenMode.ModeAt(index));
246 } else
247 print_mode(screenMode.ModeAt(index), shortOutput);
250 return 0;
253 if (!setMode) {
254 // Just print the current mode
255 if (modeLine) {
256 display_mode mode;
257 screenMode.Get(mode);
258 print_mode(mode, currentMode);
259 } else {
260 if (!shortOutput)
261 printf("Resolution: ");
262 print_mode(currentMode, shortOutput);
264 return 0;
267 screen_mode newMode = currentMode;
269 if (fallbackMode) {
270 if (currentMode.width == 800 && currentMode.height == 600) {
271 newMode.width = 640;
272 newMode.height = 480;
273 newMode.space = B_CMAP8;
274 newMode.refresh = 60;
275 } else {
276 newMode.width = 800;
277 newMode.height = 600;
278 newMode.space = B_RGB16;
279 newMode.refresh = 60;
281 } else if (modeLine) {
282 display_mode currentDisplayMode;
283 if (screenMode.Get(currentDisplayMode) == B_OK)
284 mode.flags = currentDisplayMode.flags;
285 } else {
286 newMode.width = width;
287 newMode.height = height;
289 if (depth != -1)
290 newMode.space = color_space_for_depth(depth);
291 else
292 newMode.space = B_RGB32;
294 if (refresh > 0)
295 newMode.refresh = refresh;
296 else
297 newMode.refresh = 60;
300 status_t status;
301 if (modeLine)
302 status = screenMode.Set(mode);
303 else
304 status = screenMode.Set(newMode);
306 if (status == B_OK) {
307 if (confirm) {
308 printf("Is this mode okay (Y/n - will revert after 10 seconds)? ");
309 fflush(stdout);
311 int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
312 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
314 bigtime_t end = system_time() + 10000000LL;
315 int c = 'n';
316 while (system_time() < end) {
317 c = getchar();
318 if (c != -1)
319 break;
321 snooze(10000);
324 if (c != '\n' && tolower(c) != 'y')
325 screenMode.Revert();
327 } else {
328 fprintf(stderr, "%s: Could not set screen mode %ldx%ldx%ld: %s\n",
329 kProgramName, newMode.width, newMode.height, newMode.BitsPerPixel(),
330 strerror(status));
331 return 1;
334 if (fallbackMode) {
335 // display notification requester
336 BAlert* alert = new BAlert("screenmode",
337 "You have used the shortcut <Shift><Command><Ctrl><Escape> to "
338 "reset the screen mode to a safe fallback.", "Keep", "Revert");
339 alert->SetShortcut(1, B_ESCAPE);
340 if (alert->Go() == 1)
341 screenMode.Revert();
344 return 0;