Last active
December 18, 2015 03:59
-
-
Save gregneagle/5722568 to your computer and use it in GitHub Desktop.
A Python/PyObjC port of Fabian Canas's command-line mirror tool from http://mirror-displays.googlecode.com/.
Demonstrates use of the Quartz Display Services to control display mirroring, and also shows how PyObjC handles "pass-by-reference" parameters. The LaunchAgent plist defines a job that runs at the loginwindow, running mirrortool.py to ena…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>Disabled</key> | |
<false/> | |
<key>Label</key> | |
<string>com.foo.displaymirroring</string> | |
<key>LimitLoadToSessionType</key> | |
<array> | |
<string>LoginWindow</string> | |
</array> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/Library/Tools/mirrortool.py</string> | |
<string>on</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true/> | |
</dict> | |
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# encoding: utf-8 | |
""" | |
mirrortool.py | |
Created by Greg Neagle on 2013-06-05. | |
A PyObjC port of Fabian Canas's command-line mirror tool from | |
http://mirror-displays.googlecode.com/ | |
See: | |
https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html | |
https://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/QuartzDisplayServicesConceptual/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004316 | |
""" | |
import sys | |
import os | |
import Quartz | |
def main(): | |
# default mode if none specified | |
mode = 'query' | |
# get our own name | |
toolname = os.path.basename(sys.argv[0]) | |
# get any mode that may have been passed at the command line | |
if len(sys.argv) > 1: | |
mode = sys.argv[1].lower() | |
# make sure the mode is one we know about | |
if not mode in ['toggle', 'on', 'off', 'query', 'help']: | |
mode = 'help' | |
if mode == 'help': | |
print """Usage: %s [toggle|on|off|query|help] | |
toggle: Toggle mirroring mode | |
on: Turn mirroring on | |
off: Turn mirroring off | |
query: Return mirroring state to stdout (default) | |
help: Print this message and exit.""" % toolname | |
exit(0) | |
# we currently know only how to handle two attached displays | |
max_displays = 2 | |
# get active display list | |
# CGGetActiveDisplayList: | |
# Provides a list of displays that are active (or drawable). | |
(err, active_displays, | |
number_of_active_displays) = Quartz.CGGetActiveDisplayList( | |
max_displays, None, None) | |
if err: | |
print >> sys.stderr, "Error in obtaining active display list: %s" % err | |
exit(-1) | |
# get online display list | |
# CGGetOnlineDisplayList: | |
# Provides a list of displays that are online | |
# (active, mirrored, or sleeping). | |
(err, online_displays, | |
number_of_online_displays) = Quartz.CGGetOnlineDisplayList( | |
max_displays, None, None) | |
if err: | |
print >> sys.stderr, "Error in obtaining online display list: %s" % err | |
exit(-1) | |
# make sure we have the right number of displays. | |
# currently that number is exactly 2. | |
if number_of_online_displays > 2: | |
print >> sys.stderr, (("Cannot handle more than two displays. " | |
"%s displays detected.") | |
% number_of_online_displays) | |
exit(-1) | |
if number_of_online_displays < 2: | |
print >> sys.stderr, (("Can't mirror fewer than two displays. " | |
"%s displays detected.") | |
% number_of_online_displays) | |
exit(-1) | |
if number_of_online_displays == 2: | |
if online_displays[0] == Quartz.CGMainDisplayID(): | |
secondary_display = online_displays[1] | |
else: | |
secondary_display = online_displays[0] | |
if mode == 'query': | |
if number_of_active_displays == 2: | |
print 'Display mirroring is off' | |
else: | |
print 'Display mirroring is on' | |
exit(0) | |
# begin display configuration | |
(err, config_ref) = Quartz.CGBeginDisplayConfiguration(None) | |
if err: | |
print >> sys.stderr, "Error with CGBeginDisplayConfiguration: %s" % err | |
exit(-1) | |
if mode == 'toggle': | |
if number_of_active_displays == 2: | |
# currently unmirrored | |
err = Quartz.CGConfigureDisplayMirrorOfDisplay( | |
config_ref, secondary_display, Quartz.CGMainDisplayID()) | |
else: | |
# currently mirrored | |
err = Quartz.CGConfigureDisplayMirrorOfDisplay( | |
config_ref, secondary_display, Quartz.kCGNullDirectDisplay) | |
if mode == 'on': | |
if number_of_active_displays == 2: | |
# currently unmirrored | |
err = Quartz.CGConfigureDisplayMirrorOfDisplay( | |
config_ref, secondary_display, Quartz.CGMainDisplayID()) | |
if mode == 'off': | |
if number_of_active_displays != 2: | |
# currently mirrored | |
err = Quartz.CGConfigureDisplayMirrorOfDisplay( | |
config_ref, secondary_display, Quartz.kCGNullDirectDisplay) | |
if err: | |
print >> sys.stderr, "Error configuring displays: %s" % err | |
exit(-1) | |
# apply the changes | |
err = Quartz.CGCompleteDisplayConfiguration( | |
config_ref, Quartz.kCGConfigurePermanently) | |
if err: | |
print >> sys.stderr, ("Error with CGCompleteDisplayConfiguration: %s" | |
% err) | |
exit(-1) | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment