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