1 /* 2 * Copyright 2008-2011, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <ctype.h> 8 #include <getopt.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <strings.h> 13 14 #include <Alert.h> 15 #include <Application.h> 16 #include <Screen.h> 17 18 #include "ScreenMode.h" 19 20 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 {"brightness", required_argument, 0, 'b'}, 29 {NULL} 30 }; 31 32 extern const char *__progname; 33 static const char *kProgramName = __progname; 34 35 36 static color_space 37 color_space_for_depth(int32 depth) 38 { 39 switch (depth) { 40 case 8: 41 return B_CMAP8; 42 case 15: 43 return B_RGB15; 44 case 16: 45 return B_RGB16; 46 case 24: 47 return B_RGB24; 48 case 32: 49 default: 50 return B_RGB32; 51 } 52 } 53 54 55 static void 56 print_mode(const screen_mode& mode, bool shortOutput) 57 { 58 const char* format 59 = shortOutput ? "%ld %ld %ld %g\n" : "%ld %ld, %ld bits, %g Hz\n"; 60 printf(format, mode.width, mode.height, mode.BitsPerPixel(), mode.refresh); 61 } 62 63 64 static void 65 print_mode(const display_mode& displayMode, const screen_mode& mode) 66 { 67 const display_timing& timing = displayMode.timing; 68 69 printf("%lu %u %u %u %u %u %u %u %u ", timing.pixel_clock / 1000, 70 timing.h_display, timing.h_sync_start, timing.h_sync_end, 71 timing.h_total, timing.v_display, timing.v_sync_start, 72 timing.v_sync_end, timing.v_total); 73 74 // TODO: more flags? 75 if ((timing.flags & B_POSITIVE_HSYNC) != 0) 76 printf(" +HSync"); 77 if ((timing.flags & B_POSITIVE_VSYNC) != 0) 78 printf(" +VSync"); 79 if ((timing.flags & B_TIMING_INTERLACED) != 0) 80 printf(" Interlace"); 81 printf(" %lu\n", mode.BitsPerPixel()); 82 } 83 84 85 static void 86 usage(int status) 87 { 88 fprintf(stderr, 89 "Usage: %s [options] <mode>\n" 90 "Sets the specified screen mode. When no screen mode has been chosen,\n" 91 "the current one is printed. <mode> takes the form: <width> <height>\n" 92 "<depth> <refresh-rate>, or <width>x<height>, etc.\n" 93 " --fall-back\tchanges to the standard fallback mode, and " 94 "displays a\n" 95 "\t\t\tnotification requester.\n" 96 " -s --short\t\twhen no mode is given the current screen mode is\n" 97 "\t\t\tprinted in short form.\n" 98 " -l --list\t\tdisplay a list of the available modes.\n" 99 " -q --dont-confirm\tdo not confirm the mode after setting it.\n" 100 " -b --brightness f\tset brightness (range 0 to 1).\n" 101 " -b --brightness +/-f\tchange brightness by given amount.\n" 102 " -m --modeline\taccept and print X-style modeline modes:\n" 103 "\t\t\t <pclk> <h-display> <h-sync-start> <h-sync-end> <h-total>\n" 104 "\t\t\t <v-disp> <v-sync-start> <v-sync-end> <v-total> [flags] " 105 "[depth]\n" 106 "\t\t\t(supported flags are: +/-HSync, +/-VSync, Interlace)\n", 107 kProgramName); 108 109 exit(status); 110 } 111 112 113 int 114 main(int argc, char** argv) 115 { 116 bool fallbackMode = false; 117 bool setMode = false; 118 bool shortOutput = false; 119 bool listModes = false; 120 bool modeLine = false; 121 bool confirm = true; 122 int width = -1; 123 int height = -1; 124 int depth = -1; 125 float refresh = -1; 126 float brightness = std::nanf("0"); 127 bool relativeBrightness = false; 128 display_mode mode; 129 130 // TODO: add a possibility to set a virtual screen size in addition to 131 // the display resolution! 132 133 int c; 134 while ((c = getopt_long(argc, argv, "shlfqmb:", kLongOptions, NULL)) != -1) { 135 switch (c) { 136 case 0: 137 break; 138 case 'f': 139 fallbackMode = true; 140 setMode = true; 141 confirm = false; 142 break; 143 case 's': 144 shortOutput = true; 145 break; 146 case 'l': 147 listModes = true; 148 break; 149 case 'm': 150 modeLine = true; 151 break; 152 case 'q': 153 confirm = false; 154 break; 155 case 'b': 156 if (optarg[0] == '+' || optarg[0] == '-') 157 relativeBrightness = true; 158 brightness = atof(optarg); 159 break; 160 case 'h': 161 usage(0); 162 break; 163 default: 164 usage(1); 165 break; 166 } 167 } 168 169 if (argc - optind > 0) { 170 int depthIndex = -1; 171 172 // arguments to specify the mode are following 173 174 if (!modeLine) { 175 int parsed = sscanf(argv[optind], "%dx%dx%d", &width, &height, 176 &depth); 177 if (parsed == 2) 178 depthIndex = optind + 1; 179 else if (parsed == 1) { 180 if (argc - optind > 1) { 181 height = strtol(argv[optind + 1], NULL, 0); 182 depthIndex = optind + 2; 183 } else 184 usage(1); 185 } else if (parsed != 3) 186 usage(1); 187 188 if (depthIndex > 0 && depthIndex < argc) 189 depth = strtol(argv[depthIndex], NULL, 0); 190 if (depthIndex + 1 < argc) 191 refresh = strtod(argv[depthIndex + 1], NULL); 192 } else { 193 // parse mode line 194 if (argc - optind < 9) 195 usage(1); 196 197 mode.timing.pixel_clock = strtol(argv[optind], NULL, 0) * 1000; 198 mode.timing.h_display = strtol(argv[optind + 1], NULL, 0); 199 mode.timing.h_sync_start = strtol(argv[optind + 2], NULL, 0); 200 mode.timing.h_sync_end = strtol(argv[optind + 3], NULL, 0); 201 mode.timing.h_total = strtol(argv[optind + 4], NULL, 0); 202 mode.timing.v_display = strtol(argv[optind + 5], NULL, 0); 203 mode.timing.v_sync_start = strtol(argv[optind + 6], NULL, 0); 204 mode.timing.v_sync_end = strtol(argv[optind + 7], NULL, 0); 205 mode.timing.v_total = strtol(argv[optind + 8], NULL, 0); 206 mode.timing.flags = 0; 207 mode.space = B_RGB32; 208 209 int i = optind + 9; 210 while (i < argc) { 211 if (!strcasecmp(argv[i], "+HSync")) 212 mode.timing.flags |= B_POSITIVE_HSYNC; 213 else if (!strcasecmp(argv[i], "+VSync")) 214 mode.timing.flags |= B_POSITIVE_VSYNC; 215 else if (!strcasecmp(argv[i], "Interlace")) 216 mode.timing.flags |= B_TIMING_INTERLACED; 217 else if (!strcasecmp(argv[i], "-VSync") 218 || !strcasecmp(argv[i], "-HSync")) { 219 // okay, but nothing to do 220 } else if (isdigit(argv[i][0]) && i + 1 == argc) { 221 // bits per pixel 222 mode.space 223 = color_space_for_depth(strtoul(argv[i], NULL, 0)); 224 } else { 225 fprintf(stderr, "Unknown flag: %s\n", argv[i]); 226 exit(1); 227 } 228 229 i++; 230 } 231 232 mode.virtual_width = mode.timing.h_display; 233 mode.virtual_height = mode.timing.v_display; 234 mode.h_display_start = 0; 235 mode.v_display_start = 0; 236 } 237 238 setMode = true; 239 } 240 241 BApplication application("application/x-vnd.Haiku-screenmode"); 242 243 ScreenMode screenMode(NULL); 244 screen_mode currentMode; 245 screenMode.Get(currentMode); 246 247 if (!isnan(brightness)) { 248 BScreen screen; 249 if (relativeBrightness) { 250 float previousBrightness; 251 screen.GetBrightness(&previousBrightness); 252 brightness = previousBrightness + brightness; 253 254 // Clamp to min/max values 255 if (brightness < 0.f) 256 brightness = 0.f; 257 258 if (brightness > 1.f) 259 brightness = 1.f; 260 } 261 262 if (brightness < 0.f || brightness > 1.f) 263 printf("Brightness %f is out of range\n", brightness); 264 screen.SetBrightness(brightness); 265 } 266 267 if (listModes) { 268 // List all reported modes 269 if (!shortOutput) 270 printf("Available screen modes:\n"); 271 272 for (int index = 0; index < screenMode.CountModes(); index++) { 273 if (modeLine) { 274 print_mode(screenMode.DisplayModeAt(index), 275 screenMode.ModeAt(index)); 276 } else 277 print_mode(screenMode.ModeAt(index), shortOutput); 278 } 279 280 return 0; 281 } 282 283 if (!setMode) { 284 // Just print the current mode 285 if (modeLine) { 286 display_mode mode; 287 screenMode.Get(mode); 288 print_mode(mode, currentMode); 289 } else { 290 if (!shortOutput) 291 printf("Resolution: "); 292 print_mode(currentMode, shortOutput); 293 } 294 return 0; 295 } 296 297 screen_mode newMode = currentMode; 298 299 if (fallbackMode) { 300 if (currentMode.width == 800 && currentMode.height == 600) { 301 newMode.width = 640; 302 newMode.height = 480; 303 newMode.space = B_CMAP8; 304 newMode.refresh = 60; 305 } else { 306 newMode.width = 800; 307 newMode.height = 600; 308 newMode.space = B_RGB16; 309 newMode.refresh = 60; 310 } 311 } else if (modeLine) { 312 display_mode currentDisplayMode; 313 if (screenMode.Get(currentDisplayMode) == B_OK) 314 mode.flags = currentDisplayMode.flags; 315 } else { 316 newMode.width = width; 317 newMode.height = height; 318 319 if (depth != -1) 320 newMode.space = color_space_for_depth(depth); 321 else 322 newMode.space = B_RGB32; 323 324 if (refresh > 0) 325 newMode.refresh = refresh; 326 else 327 newMode.refresh = 60; 328 } 329 330 status_t status; 331 if (modeLine) 332 status = screenMode.Set(mode); 333 else 334 status = screenMode.Set(newMode); 335 336 if (status == B_OK) { 337 if (confirm) { 338 printf("Is this mode okay (Y/n - will revert after 10 seconds)? "); 339 fflush(stdout); 340 341 int flags = fcntl(STDIN_FILENO, F_GETFL, 0); 342 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); 343 344 bigtime_t end = system_time() + 10000000LL; 345 int c = 'n'; 346 while (system_time() < end) { 347 c = getchar(); 348 if (c != -1) 349 break; 350 351 snooze(10000); 352 } 353 354 if (c != '\n' && tolower(c) != 'y') 355 screenMode.Revert(); 356 } 357 } else { 358 fprintf(stderr, "%s: Could not set screen mode %ldx%ldx%ld: %s\n", 359 kProgramName, newMode.width, newMode.height, newMode.BitsPerPixel(), 360 strerror(status)); 361 return 1; 362 } 363 364 if (fallbackMode) { 365 // display notification requester 366 BAlert* alert = new BAlert("screenmode", 367 "You have used the shortcut <Shift><Command><Ctrl><Escape> to " 368 "reset the screen mode to a safe fallback.", "Keep", "Revert"); 369 alert->SetShortcut(1, B_ESCAPE); 370 if (alert->Go() == 1) 371 screenMode.Revert(); 372 } 373 374 return 0; 375 } 376