Dockeinstellungen ändern bei Multi-Monitor

schlagi1979

Aktives Mitglied
Thread Starter
Dabei seit
22.07.2013
Beiträge
443
Reaktionspunkte
23
Liebe MacUser,

vorab, ich kenne mich weder mit (Apple)Scripting noch mit dem Automator aus, arbeite mich aber ein, wenn ihr mir sagt, dass eines der Tool (oder etwas anderes) meine Idee umsetzen kann.

Ich habe ein MacBook Pro Mid-2010, auf dem zur Zeit Mavericks läuft, und hätte es gern, dass sich die Einstellungen des Docks in Abhängigkeit davon verändern, ob ein externes Display angeschlossen ist oder nicht. Und zwar soll das Dock, wenn kein externer Monitor angeschlossen ist, an der linken Seite dauerhaft eingeblendet sein; bei angeschlossenem externem Monitor soll das Dock unten stehen und automatisch aus- und eingeblendet werden.

Nach meinem rudimentären Verständnis müsste sich doch ein Script mit folgenden Elementen dafür eignen:

10 if "kein Monitor da" [gibt es hier ein Element, das diese Abfrage erlaubt und aktuell hält?]
20 tell "Systemeinstellungen"
30 set "Dock" auf "links" "kein Haken bei ein- und ausblenden" [man kann doch in AppleScript angeben, welche Schaltflächen wie bedient werden sollen, korrekt?]
40 else [ich schließe immer nur einen Monitor an, aber sollten es mal zwei sein, soll das Dock auch unten sein]
50 tell "Systemeinstellungen"
60 set "Dock" auf "unten" "Haken bei ein- und ausblenden"
70 end tell
80 end if

Stimmt das von der grundsätzlichen Logik her?

Und wie bekomme ich es hin, dass diese Aktion von allein ausgeführt wird, sowie ein Monitor an- bzw. abgeschlossen wird? Denn wenn ich das manuell starten müsste, bin ich mit dem Umstellen der Systemeinstellungen ja fast genau so kommod unterwegs...

Vielen Dank und Gruß,
Marc
 
OK, die Veränderung der Einstellungen des Docks müsste über System Events bzw. dort Dock Preferences gehen. Also

10 if "kein Monitor da" [gibt es hier ein Element, das diese Abfrage erlaubt und aktuell hält?]
20 tell application "System Events"
21 tell dock preferences
30 set autohide to false
31 set screen edge to left
40 else [ich schließe immer nur einen Monitor an, aber sollten es mal zwei sein, soll das Dock auch unten sein]
50 tell application "System Events"
51 tell Dock Preferences
60 set autohide to true
61 set screen edge to bottom
70 end tell
71 end tell
80 end if

richtig?

Bleibt mein Problem, wo greife ich die Information "es wird ein Monitor an- bzw. abgeschlossen" ab.
 
Hallo,

zu 10:
ja, da gäbe es eine Funktion in AppleScript (on idle), aber statt dessen würde ich launchd nehmen -> ein LaunchAgent, welcher periodisch überprüft (default alle 10 Sekunden-lässt sich aber ändern), ob ein zweites Display angeschlossen ist.
Ein LauchAgent kann auch so gestaltet werden, dass er nur startet, wenn sich eine bestimmte Datei ändert. Da ich hier gerade keinen zweiten Monitor zur Hand habe, weiß ich nicht, ob und welche Dateien sich ändern, wenn einer angeschlossen wird...
Das ließe sich wohl auch recht einfach ohne Skriptkenntnisse mit einer Finder-Suche rausfinden:
Letztes Änderungsdatum innerhalb letzten 1 Tag
Systemdateien einschließen

dann Monitor anschließen und Suchfenster beobachten



Ob ein zweites Display angeschlossen ist, lässt sich ermitteln: eventuell über einen Eintrag in einer Plist (siehe oben); mit einem ShellScript (z.B. ioreg) oder mit AppleScript:

tell app "Image Events" to set SecondDisplay to (count displays) > 1
oder
tell app "System Events" to set SecondDisplay to (count desktop) > 1

Gruß
 
Varuna,

vielen Dank für Deine Antwort. Ich muss jetzt erstmal eine Weile in google abtauchen, um das nachzuvollziehen, aber ein paar Verständnisfragen habe ich noch:

zu 10:
ja, da gäbe es eine Funktion in AppleScript (on idle), aber statt dessen würde ich launchd nehmen -> ein LaunchAgent, welcher periodisch überprüft (default alle 10 Sekunden-lässt sich aber ändern), ob ein zweites Display angeschlossen ist.
Wenn ich die Apple-Hilfeseiten richtig verstanden habe, ist der Agent ein .plist-Datei, die definiert, ob bei bestimmten Voraussetzungen eine bestimmte Aktion durchgeführt wird. Heißt das, ich müsste einen Agenten schreiben, der 1) die Monitorabfrage und 2) abhängig von deren Ergebnis ein Script für Dock unten etc., oder ein Script für Dock links startet? Wie Du merkst, ist das für mich völliges Neuland. Insbesondere ist mir die gedankliche Verknüpfung bzw. das Verhältnis von AppleScript zu LaunchAgent nicht klar.

Ein LauchAgent kann auch so gestaltet werden, dass er nur startet, wenn sich eine bestimmte Datei ändert. Da ich hier gerade keinen zweiten Monitor zur Hand habe, weiß ich nicht, ob und welche Dateien sich ändern, wenn einer angeschlossen wird...
Das ließe sich wohl auch recht einfach ohne Skriptkenntnisse mit einer Finder-Suche rausfinden:
Letztes Änderungsdatum innerhalb letzten 1 Tag
Systemdateien einschließen

dann Monitor anschließen und Suchfenster beobachten
Ok, das verstehe ich.


Ob ein zweites Display angeschlossen ist, lässt sich ermitteln: eventuell über einen Eintrag in einer Plist (siehe oben); mit einem ShellScript (z.B. ioreg) oder mit AppleScript:

tell app "Image Events" to set SecondDisplay to (count displays) > 1
oder
tell app "System Events" to set SecondDisplay to (count desktop) > 1
Das verstehe ich jetzt nicht mehr so ganz.

1) Mit "lässt sich über einen Eintrag in einer Plist herausfinden" meinst Du, wenn ich im Finder nach Änderungen suche, werden diese in einer Plist auftauchen, oder lässt sich über einen launchagent herausfinden, der eine .plist ist?

2) ShellScript sieht mir zu kompliziert aus, da würde ich mich jetzt mal drum drücken, wenn es nicht zwingend ist :)

3) Feststellung mit AppleScript: Die von Dir genannten Befehle zeigen also auch, ob ein 2. Display angeschlossen ist. (bzw. ich bekomme es noch nicht hin, dass mir die Abfrage über Image Events -> Display die Zahl der Displays auswirft). Würde ich das als "Wenn-Dann-Bedingung" für mein Scriptfragment nehmen, das wiederum dadurch ausgelöst wurde, dass der LaunchAgent eine Änderung an einer .plist beobachtet hat?

Sorry, habe gerade fürchte ich einen Knoten im Hirn, danke nochmal für Deine Antwort.

Gruß,
Marc
 
Hallo,
Wenn ich die Apple-Hilfeseiten richtig verstanden habe, ist der Agent ein .plist-Datei, die definiert, ob bei bestimmten Voraussetzungen eine bestimmte Aktion durchgeführt wird.
Jein. Man kann einen Launch Agent auch ohne bestimmte Vorraussetzungen alle so-und-so-viele Sekunden starten lassen.
In der Plist stehen die nötigen Parameter (des Agents), welche von dem Unix Programm launchd ausgelesen werden.


Heißt das, ich müsste einen Agenten schreiben, der 1) die Monitorabfrage und 2) abhängig von deren Ergebnis ein Script für Dock unten etc., oder ein Script für Dock links startet? Wie Du merkst, ist das für mich völliges Neuland.
Ja:
Wenn Anzahl Monitor > 1, dann schiebe Dock nach unten
sonst
schiebe Dock nach links

Code:
[B]tell [/B][COLOR=#0433FF][FONT=Verdana][I]application[/I][/FONT][/COLOR][FONT=Verdana] "System Events"[/FONT]
[COLOR=#5E6161][FONT=Verdana]-- "SecondDisplay" ist wahr, wenn Anzahl Monitore größer 1 (jeder Monitor hat EINEN Schreibtisch!) - "Second Display" ist falsch, wenn Anzahl Monitore 1 (oder geringer :p):[/FONT][/COLOR]
[FONT=Verdana]    [B]set[/B] [COLOR=#4f8f00]SecondDisplay[/COLOR] [B]to[/B] ([COLOR=#0433ff][B]count[/B][/COLOR] [COLOR=#0433ff][I]desktop[/I][/COLOR]) > 1[/FONT]

[COLOR=#812FDC][FONT=Verdana][COLOR=#000000]    [B]tell[/B] [/COLOR]dock preferences[/FONT][/COLOR]
[COLOR=#5E6161][FONT=Verdana]-- wenn "SecondDisplay" wahr ist, dann ...[/FONT][/COLOR]
[COLOR=#5E6161][FONT=Verdana]-- if SecondDisplay is true then[/FONT][/COLOR]
[COLOR=#5E6161][FONT=Verdana]-- oder kürzer:[/FONT][/COLOR]
[COLOR=#4F8F00][FONT=Verdana][COLOR=#000000]        [B]if[/B] [/COLOR]SecondDisplay[COLOR=#000000] [B]then[/B][/COLOR][/FONT][/COLOR]
[COLOR=#812FDC][FONT=Verdana][COLOR=#000000]            [B]set[/B] [/COLOR]screen edge[COLOR=#000000] [B]to[/B] [/COLOR][I]bottom[/I][/FONT][/COLOR]
[COLOR=#812FDC][FONT=Verdana][COLOR=#000000]            [B]set[/B] [/COLOR]autohide[COLOR=#000000] [B]to[/B] [/COLOR][I]true[/I][/FONT][/COLOR]
[COLOR=#5E6161][FONT=Verdana]-- sonst[/FONT][/COLOR]
[FONT=Verdana]        [B]else[/B][/FONT]
[COLOR=#812FDC][FONT=Verdana][COLOR=#000000]            [B]set[/B] [/COLOR]screen edge[COLOR=#000000] [B]to[/B] [/COLOR][I]left[/I][/FONT][/COLOR]
[COLOR=#812FDC][FONT=Verdana][COLOR=#000000]            [B]set[/B] [/COLOR]autohide[COLOR=#000000] [B]to[/B] [/COLOR][I]false[/I][/FONT][/COLOR]
[FONT=Verdana]        [B]end[/B] [B]if[/B][/FONT]
[FONT=Verdana]    [B]end[/B] [B]tell[/B][/FONT]

[FONT=Verdana][B]end[/B] [B]tell[/B][/FONT]
1) Mit "lässt sich über einen Eintrag in einer Plist herausfinden" meinst Du, wenn ich im Finder nach Änderungen suche, werden diese in einer Plist auftauchen, oder lässt sich über einen launchagent herausfinden, der eine .plist ist?
Upps, das war wohl etwas missverständlich.
Eine Bedingung für einen Start eines Lauch Agent könnte (u.a.) die Veränderung an einer Datei sein. Z.B. an einer Preferences Datei.
Nun weiß ich aber nicht, ob überhaupt Änderungen in solch eine Datei geschrieben werden, wenn ein zweiter Monitor angeschlossen wird. Und falls ja, welche.
Das ließe sich mit der beschriebenen Methode herausfinden.


Der Launch Agent würde dann so aussehen:
• was: Skript ausführen (ProgrammArguments)
• starten, wenn Datei modifiziert wird (WatchPaths)


oder halt ohne Überwachung einer Datei:
• immer am Leben erhalten (KeepAlive)
• was: Skript ausführen (ProgrammArguments)
•ggfs: in kürzeren Abständen starten: (StartIntervall)

[…] ich bekomme es noch nicht hin, dass mir die Abfrage über Image Events -> Display die Zahl der Displays auswirft
tell app "System Events" to count desktop
oder
tell app"Image Events" to count displays


PS: Es gibt übrigens Programme mit einem GUI zur Erstellung von Launch Agents (mir fällt gerade nur "Lingon" ein)

Gruß
 
ja, da gäbe es eine Funktion in AppleScript (on idle), aber statt dessen würde ich launchd nehmen

Da wäre ich jetzt nicht sicher ob der To damit wirklich Glücklich sein kann.
Nach meiner Erfahrung und allem was ich bis jetzt über launchd gelesen habe ist es nicht soooo flexibel.

Beispiel:
Man kann ihn sagen, dass er nach dem Start etwas tun soll und dann alle X Zeit

Man kann ihn aber nicht sagen, dass er auch direkt nach dem aufwecken aus dem Sleep auch das tun soll. Das bedeutet in diesem konkreten Beispiel, der To kann bei starten prüfen ob der externe Schirm angeschlossen ist. Dann kann es auch gerne alle 10 Sekunden machen. Geht der MBP ins Sleep, ist nicht vorhersehbar wann sein Skript wieder gestartet wird.

(Ich hoffe meine Erklärung ist doch verständlich)

Ich habe keine wirklich praktikable Lösung für so etwas wie "ist ExtScreen vorhanden oder nicht" gefunden. Aus dem Grund hatte ich mir damals einfach 2 AppleScripts auf dem Desktop gepackt und die hatte ich abhängig davon gestartet ob eben nur MBP Display oder MBP mit ExtScreen vorhanden waren.

Tobi
 
Varuna,

vielen Dank für die ausführlich Erklärung und die Mühe, die Du Dir gibst. Das ist wirklich sehr hilfreich für mich, da ich mich erstmals vertieft mit diesen Themen befasse. Ich bastele dann mal weiter...

Tobi, vielen Dank, das mit den zwei Apps hatte ich auch schon überlegt, aber noch reicht der Spieltrieb zum Suchen von Lösungen; es gibt doch solche Tools wie DoSomethingWhen oder so ähnlich, die bei bestimmten Ereignissen Aktionen auslösen; von daher denke ich, es muss einen anzapfbaren Mechanismus für sowas geben...
 
Apropos Tools: Gerade neulich wurde hier wieder mal das Programm Control Plane erwähnt.

Dort kannst du eine neue Umgebung einstellen, nennen wir sie "2_Monitore".
Regel: Monitor "Xyz" (Monitor 2) -> Umgebung "2_Monitore" -> sehr hohe Wahrscheinlichkeit
Aktionen: Bei Ankunft in Umgebung "2_Monitore" öffne File "dein_Skript"

Gruß
 
Danke schön. Übrigens, das Script von oben funktioniert ganz prima, wenn ich es händisch nach an- und abstöpseln laufen lasse; über die erste Hürde hast Du mir also schon weggeholfen!

Ich hätte es halt gern, einen Mechanismus, wie ihn ControlPlane ja auch haben muss, selbst zu basteln, und damit das Script zu befeuern...

Wenn ich die Methode nehmen würde, das Script einfach alle 3 Sekunden laufen zu lassen, würde das denn das System insgesamt stark bremsen, (MBP 15" Mid 2010, 2,53 GHz Core i5, 8 GB RAM) oder wird das einfach als Minimalgedöns "weggemacht"?

Edit: Konnte noch nicht sicher eine Datei identifizieren, die geändert wird. Es scheint Änderungen in /.fseventsd zu geben, aber nicht immer, wenn an- oder abgestöpselt wird.
 
Ich denke, ein 3 Sek Intervall ist zu kurz ... nimm als Minimum alle 5 Sekunden.
Und nein, das wird dein MB mit < 0,1 % Prozessorauslastung und einem Hauch RAM wegstecken...
 
varuna,

ich muss Dich noch weiter belästigen. Habe nun das Script als "Dockwechsel_2ndScreen.app" im Programme-Ordner gespeichert. Wenn ich jetzt einen LaunchAgent namens com.Dockwechsel.marc schreiben will, der bei Änderungen am Ordner "fseventsd" genannte app laufen lässt, dann sähe der doch so aus, richtig?

Code:
<?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>Label</key>
	<string>com.Dockwechsel.marc</string>
	<key>ProgramArguments</key>
	<array>
		<string>/Applications/Dockwechsel_2ndScreen.app</string>
	</array>
	<key>WatchPaths</key>
	<array>
		<string>/.fseventsd</string>
	</array>
</dict>
</plist>

Der Ordner fseventsd ist so eingestellt, dass nur System darauf lesen und schreiben kann, alle anderen dürfen nix (darum habe ich etwas "Manschetten" vor diesem Ordner, aber die bloße Überwachung tut dem ja nix, oder?
 
Hallo,

der Ordner ist für deine Überwachung nicht geeignet.
File System Events API loggt dort Änderungen am Dateisystem.

Wird eventuell folgende Datei modifiziert?
/Library/Preferences/com.apple.windowserver.plist

Ach ja:
Die Plist sieht ansonsten soweit gut aus :)
Noch schöner ist es, wenn kein App, sondern das Skript im Hintergrund gestartet wird.
Speichere dein Dockwechsel_2ndScreen als Skript (.scpt)

Code:
<?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>Label</key>
	<string>com.Dockwechsel.marc</string>
        <key>Program</key>
	<string>/usr/bin/osascript</string>
	<key>ProgramArguments</key>
	<array>
		<string>osascript</string>
		<string>/Pfad/zu/deinem/Script/Dockwechsel_2ndScreen.scpt</string>
	</array>
	<key>WatchPaths</key>
	<array>
		<string>??????</string>
	</array>
</dict>
</plist>

Bedenke, dass ein LaunchAgent erst nach einem erneuten LogIn bzw. Neustart geladen wird ... oder aber manuell mit diesem Kommando (im Terminal):

Code:
launchctl load Pfad/zu/LaunchAgent

Und vor einem eventuellen Löschen immer schön erst
Code:
launchctl unload -w Pfad/zu/LaunchAgent

Gruß
 
Zuletzt bearbeitet:
Wow varuna,

vielen Dank, dass Du mich hier so Schritt für Schritt durchführst. Die Windowserver-plist zeigt leider keine Änderungen. Ich würde es daher mit dem "zeitabhängigen" Verfahren probieren, und Deinen Hinweis mit dem Verweis auf ein Script statt einer App setze ich auch gerade um. (Worin liegt denn der Vorteil dieser Herangehensweise?).

Gruß,
Marc
 
Na, dass keine App startet, um das Dock zu verschieben, sondern dass das Skript direkt ausgeführt wird ....
osascript ist ein Kommandozeilen-Programm, welches ein kompiliertes AppleScript starten oder sogar auch AppleScript Text ausführen kann.

Gruß
 
So, nachdem ich mir Xcode geladen habe, konnte ich die plist auch erstellen, bzw. eine Kopie einer existierenden plist wunschgemäß ändern. Die sieht jetzt so aus:

Code:
<?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>Label</key>
	<string>com.timed.Dockwechsel</string>
	<key>Program</key>
	<string>/usr/bin/osascript</string>
	<key>ProgramArguments</key>
	<array>
		<string>osascript</string>
		<string>/Users/marcschlagenhoff/Library/Scripts/Dockwechsel_2ndScreen.scpt</string>
	</array>
	<key>KeepAlive</key>
	<integer>5</integer>
</dict>
</plist>

und liegt in den LaunchAgents meines Benutzers. Allerdings funktioniert das ganze nicht, wenn ich den Monitor an- bzw. abstecke, wird auch nach 10 sec. kein selbsttätiger Wechsel durchgeführt. Das Script als solches habe ich als App im Dock liegen, und bei Klick darauf funktioniert es wunderbar, nur der "Selbstauslöser" tut nicht. Würde es etwas bringen, die plist in /Library/LaunchAgents zu legen?
 
Hallo,
dafür braucht man kein Xcode ...

TextEdit ->Format -> reiner Text
Speichern als com.timed.Dockwechsel.plist

Code:
<?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>KeepAlive</key>
	<true/>
	<key>Label</key>
	<string>com.timed.Dockwechsel</string>
	<key>Program</key>
	<string>/usr/bin/osascript</string>
	<key>ProgramArguments</key>
	<array>
		<string>osascript</string>
		<string>/Users/marcschlagenhoff/Library/Scripts/Dockwechsel_2ndScreen.scpt</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>StartInterval</key>
	<integer>5</integer>
</dict>
</plist>
Wobei ich das mit den 5 Sekunden Takt weglassen würde ... könnte zu kurz sein für ein AppleScript.

Zuerst aber im Terminal
Code:
launchctl unload ~/Library/LaunchAgents/com.timed.Dockwechsel.plist

dann Plist-Inhalt ändern und
Code:
launchctl load ~/Library/LaunchAgents/com.timed.Dockwechsel.plist

Ansonsten würde ich keine Großbuchstaben im Namen nehmen (was aber an sich gehen sollte)

Gruß
 
Also ich habe es gleich gemacht wie beschrieben... habe das Script, welches händisch auch wunderbar funktioniert unter scripts im Library Ordner abgelegt.
Die plist datei unter launchagent geschoben, den Intervall auf 10 und natürlich auch den Pfad verändert in der Vorlage.
Nun funktioniert es aber nicht... woran kann das liegen?
 
Zuletzt bearbeitet:
Ich würde das so machen:
Das Script...

Code:
tell application "System Events"
	repeat
		set SecondDisplay to (count desktop) > 1
		
		tell dock preferences
			if SecondDisplay then
				set screen edge to left
				set autohide to false
			else
				set screen edge to right
				set autohide to true
			end if
		end tell
		delay 5
	end repeat
end tell

... mit dem LaunchAgent...

Code:
<?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>
	<true/>
	<key>EnableGlobbing</key>
	<true/>
	<key>Label</key>
	<string>DockOnDisplaySetting.scpt</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/bin/osascript</string>
		<string>~/Library/Scripts/DockOnDisplaySetting.scpt</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
</dict>
</plist>

... laufen lassen.
Du kannst auch "Keep Alive no matter what" im LaunchAgent" verwenden. Der beste LaunchAgent Manager ist "LaunchControl"
PS: Habe das Script nach meinen Bedürfnissen geändert.
 
Zurück
Oben Unten