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 {NULL} 29 }; 30 31 extern const char *__progname; 32 static const char *kProgramName = __progname; 33 34 35 static color_space 36 color_space_for_depth(int32 depth) 37 { 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; 50 } 51 } 52 53 54 static void 55 print_mode(const screen_mode& mode, bool shortOutput) 56 { 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); 60 } 61 62 63 static void 64 print_mode(const display_mode& displayMode, const screen_mode& mode) 65 { 66 const display_timing& timing = displayMode.timing; 67 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); 72 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()); 81 } 82 83 84 static void 85 usage(int status) 86 { 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); 105 106 exit(status); 107 } 108 109 110 int 111 main(int argc, char** argv) 112 { 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; 124 125 // TODO: add a possibility to set a virtual screen size in addition to 126 // the display resolution! 127 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; 156 } 157 } 158 159 if (argc - optind > 0) { 160 int depthIndex = -1; 161 162 // arguments to specify the mode are following 163 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); 177 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); 186 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; 198 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); 217 } 218 219 i++; 220 } 221 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; 226 } 227 228 setMode = true; 229 } 230 231 BApplication application("application/x-vnd.Haiku-screenmode"); 232 233 ScreenMode screenMode(NULL); 234 screen_mode currentMode; 235 screenMode.Get(currentMode); 236 237 if (listModes) { 238 // List all reported modes 239 if (!shortOutput) 240 printf("Available screen modes:\n"); 241 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); 248 } 249 250 return 0; 251 } 252 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); 263 } 264 return 0; 265 } 266 267 screen_mode newMode = currentMode; 268 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; 280 } 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; 288 289 if (depth != -1) 290 newMode.space = color_space_for_depth(depth); 291 else 292 newMode.space = B_RGB32; 293 294 if (refresh > 0) 295 newMode.refresh = refresh; 296 else 297 newMode.refresh = 60; 298 } 299 300 status_t status; 301 if (modeLine) 302 status = screenMode.Set(mode); 303 else 304 status = screenMode.Set(newMode); 305 306 if (status == B_OK) { 307 if (confirm) { 308 printf("Is this mode okay (Y/n - will revert after 10 seconds)? "); 309 fflush(stdout); 310 311 int flags = fcntl(STDIN_FILENO, F_GETFL, 0); 312 fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); 313 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; 320 321 snooze(10000); 322 } 323 324 if (c != '\n' && tolower(c) != 'y') 325 screenMode.Revert(); 326 } 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; 332 } 333 334 if (fallbackMode) { 335 // display notification requester 336 BAlert* alert = new BAlert("screenmode", 337 "You have used the shortcut <Command><Ctrl><Escape> to reset the " 338 "screen mode to a safe fallback.", "Keep", "Revert"); 339 alert->SetShortcut(1, B_ESCAPE); 340 if (alert->Go() == 1) 341 screenMode.Revert(); 342 } 343 344 return 0; 345 } 346