Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!


Click here to return to the 'Modified source to manage two or more monitors' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Modified source to manage two or more monitors
Authored by: wallybear on Apr 17, '09 04:44:57AM
I modified the source code to manage two or more monitors, and added some bonus too:
- It shows current main display resolution
- It shows current secondary displays resolution
- It shows the list of displays found, with their resolution, depth and refresh rate
- It sets the resolution of any display connected

Help is available with setgetscreenres -?

Here is the code:



/*
 * setgetscreenres.m
 * 
 * juanfc 2009-04-13
 * jawsoftware 2009-04-17
 * Based on newscreen
 *    Created by Jeffrey Osterman on 10/30/07.
 *    Copyright 2007 Jeffrey Osterman. All rights reserved. 
 *    PROVIDED AS IS AND WITH NO WARRANTIES WHATSOEVER
 *    http://forums.macosxhints.com/showthread.php?t=59575
 *
 * COMPILE:
 *    c++ setgetscreenres.m -framework ApplicationServices -o setgetscreenres
 * USE:
 *    setgetscreenres [ -l | 1..9] [ 1440 900 ]
 */

#include <ApplicationServices/ApplicationServices.h>

bool MyDisplaySwitchToMode (CGDirectDisplayID display, CFDictionaryRef mode);
void ListDisplays( CGDisplayCount dispCount, CGDirectDisplayID *dispArray );
void usage(const char *argv[]);
void GetDisplayParms(CGDirectDisplayID *dispArray,  CGDisplayCount dispNum, int *width, int *height, int *depth, int *freq);

int main (int argc, const char * argv[])
{
	int	h; 							// horizontal resolution
	int v; 							// vertical resolution
	int depth, freq;

	CFDictionaryRef switchMode; 	// mode to switch to
	CGDirectDisplayID theDisplay;  // ID of  display, display to set
	int displayNum; //display number requested by user
	
	CGDisplayCount maxDisplays = 10;
	CGDirectDisplayID onlineDspys[maxDisplays];
	CGDisplayCount dspyCnt;
	
	CGGetOnlineDisplayList (maxDisplays, onlineDspys, &dspyCnt);

	
	if (argc == 1) {
	    CGRect screenFrame = CGDisplayBounds(kCGDirectMainDisplay);
		CGSize screenSize  = screenFrame.size;
		printf("%.0f %.0f\n", screenSize.width, screenSize.height);
		return 0;
	}
	
	if (argc == 2) {
		if (! strcmp(argv[1],"-l")) {
			ListDisplays( dspyCnt, onlineDspys );
			return 0;
		}
		else if (! strcmp(argv[1],"-?")) {
			usage(argv);
			return 0;
		}
		else if (displayNum = atoi(argv[1])) {
			if (displayNum <= dspyCnt) {
				GetDisplayParms(onlineDspys, displayNum-1, &h, &v, &depth, &freq);
				printf("%d %d\n", h, v);
				return 0;
			}
			else {
				fprintf(stderr, "ERROR: display number out of bounds; displays on this mac: %d.\n", dspyCnt);
				return -1;
			}
		}
	}
	
	
	if (argc == 4 && (displayNum = atoi(argv[1])) && (h = atoi(argv[2])) && (v = atoi(argv[3])) ) {
		if (displayNum <= dspyCnt) {
			theDisplay= onlineDspys[displayNum-1];
		}
		else return -1;
	}
	else {
		if (argc != 3 || !(h = atoi(argv[1])) || !(v = atoi(argv[2])) ) {
			fprintf(stderr, "ERROR: syntax error.\n", argv[0]);
			usage(argv);
			return -1;
		}
		theDisplay = CGMainDisplayID();
	}


	switchMode = CGDisplayBestModeForParameters(theDisplay, 32, h, v, NULL);
	
	if (! MyDisplaySwitchToMode(theDisplay, switchMode)) {
	    fprintf(stderr, "Error changing resolution to %d %d\n", h, v);
		return 1;
	}
	
	return 0;
}


void ListDisplays( CGDisplayCount dispCount, CGDirectDisplayID *dispArray )
{
	int	h, v, depth, freq;
	
		printf("Displays found: %d\n", dispCount);
		for	(int i = 0 ; i < dispCount ;  i++ ) {

			GetDisplayParms(dispArray, i, &h, &v, &depth, &freq);
			printf("Display %d (id %d):  %d x %d x %d @ %dHz\n", i+1, dispArray[i], h, v, depth, freq);
		}
}


void GetDisplayParms(CGDirectDisplayID *dispArray,  CGDisplayCount dispNum, int *width, int *height, int *depth, int *freq)
{
	CFDictionaryRef currentMode = CGDisplayCurrentMode (dispArray[dispNum]);
	CFNumberRef number = CFDictionaryGetValue (currentMode, kCGDisplayRefreshRate);
	CFNumberGetValue (number, kCFNumberLongType, freq);
	number = CFDictionaryGetValue (currentMode, kCGDisplayWidth);
	CFNumberGetValue (number, kCFNumberLongType, width);
	number = CFDictionaryGetValue (currentMode, kCGDisplayHeight);
	CFNumberGetValue (number, kCFNumberLongType, height);
	number = CFDictionaryGetValue (currentMode, kCGDisplayBitsPerPixel);
	CFNumberGetValue (number, kCFNumberLongType, depth);
}

bool MyDisplaySwitchToMode (CGDirectDisplayID display, CFDictionaryRef mode)
{
	CGDisplayConfigRef config;
	if (CGBeginDisplayConfiguration(&config) == kCGErrorSuccess) {
		CGConfigureDisplayMode(config, display, mode);
		CGCompleteDisplayConfiguration(config, kCGConfigureForSession );
		return true;
	}
	return false;
}


void usage(const char *argv[])
{
	printf("\nUsage: %s [-l | 1..9 ] [ hor_res vert_res]\n\n", argv[0]);
	printf("      -l  list resolution, depth and refresh rate of all displays\n");
	printf("    1..9  display # (default: main display)\n");
	printf(" hor_res  horizontal resolution\n");
	printf("vert_res  vertical resolution\n\n");
	printf("Examples:\n");
	printf("%s 800 600      set resolution of main display to 800x600\n", argv[0]);
	printf("%s 2 800 600    set resolution of secondary display to 800x600\n", argv[0]);
	printf("%s 3            get resolution of third display\n", argv[0]);
	printf("%s -l           get resolution, bit depth and refresh rate of all displays\n\n", argv[0]);
}


[ Reply to This | # ]
Modified source to manage two or more monitors
Authored by: juanfal on Apr 17, '09 05:56:01AM
THANKS A LOT! I have found only an annoying C++ error:
$ c++ setgetscreenres.m -framework ApplicationServices -o setgetscreenres
setgetscreenres.m: In function ‘ListDisplays’:
setgetscreenres.m:104: error: ‘for’ loop initial declaration used outside C99 mode
But you can avoid it changing lines 101-104 by:
	int	h, v, depth, freq, i;
	
	printf("Displays found: %dn", dispCount);
	for	(i = 0 ; i < dispCount ;  i++ ) {


[ Reply to This | # ]
One more thing...
Authored by: wallybear on Apr 17, '09 02:49:37PM

Ouch, that's true; I didn't get that error because I compiled it under XCode, which accepts that syntax.
I used XCode to be sure it works also on 10.4 and to make it Universal. It even builds a smaller fat binary (38Kb vs. 46Kb).

The command line compiling instructions given will generate a binary only for the CPU (and System version) of the Mac used.

To compile it as Universal from command line just change the compile command to this:

c++ setgetscreenres.m -framework ApplicationServices -o setgetscreenres -arch i386 -arch ppc

...and to make it work from OS X Panther (10.3.9) or newer, just add this flag at the end of the compile command line:

-mmacosx-version-min=10.3.9

(obviously if you want to exclude OS X Panther then use: -mmacosx-version-min=10.4 )



[ Reply to This | # ]
...a small addition...
Authored by: wallybear on Apr 18, '09 07:55:34AM
Changing my ListDisplays() function with the following, we can see which display is the primary (i.e. the one with the menu bar):

void ListDisplays( CGDisplayCount dispCount, CGDirectDisplayID *dispArray )
{
	int	h, v, depth, freq, i;
	CGDirectDisplayID mainDisplay = CGMainDisplayID();
	
		printf("Displays found: %d\n", dispCount);
		for	(i = 0 ; i < dispCount ;  i++ ) {

			GetDisplayParms(dispArray, i, &h, &v, &depth, &freq);
			printf("Display %d (id %d):  %d x %d x %d @ %dHz", i+1, dispArray[i], h, v, depth, freq);
			if ( mainDisplay == dispArray[i] ) 
				printf(" (main)\n");
			else
				printf("\n");
		}
}
With this mod, the displays listing (using setgetscreenres -l) will look like this one:

Displays found: 3
Display 1 (id 180814742):  1024 x 768 x 32 @ 75Hz
Display 2 (id 188810672):  1920 x 1080 x 32 @ 60Hz (main)
Display 3 (id 160845621):  1440 x 900 x 32 @ 60Hz
stating that Display 2 is the main display.


[ Reply to This | # ]