Browse Source

macosx: Rework VLC Status bar icon for OS X

This overhauls the VLC Status Bar Icon for OS X
It completely changed the appearance, using a mini-player instead of
simple menu items.
Additionally the current playing track with metadata is shown, including
it's coverart, if any.

TODO:
  - Use more of the InputManager hooks to prevent unnecessary updates
  - Refactor the metadata update code, it's a  bit cluttered
  - Increase accessibility

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
pull/46/head
Marvin Scholz 10 years ago
committed by Jean-Baptiste Kempf
parent
commit
813c4b1200
  1. 196
      extras/package/macosx/Resources/English.lproj/VLCStatusBarIconMainMenu.xib
  2. BIN
      extras/package/macosx/Resources/vlcmenubaricon/VLCNextTemplate.pdf
  3. BIN
      extras/package/macosx/Resources/vlcmenubaricon/VLCPauseTemplate.pdf
  4. BIN
      extras/package/macosx/Resources/vlcmenubaricon/VLCPlayTemplate.pdf
  5. BIN
      extras/package/macosx/Resources/vlcmenubaricon/VLCPreviousTemplate.pdf
  6. BIN
      extras/package/macosx/Resources/vlcmenubaricon/VLCShuffleTemplate.pdf
  7. 0
      extras/package/macosx/Resources/vlcmenubaricon/VLCStatusBarIcon.pdf
  8. BIN
      extras/package/macosx/Resources/vlcmenubaricon/pauseIcon.png
  9. BIN
      extras/package/macosx/Resources/vlcmenubaricon/pauseIcon@2x.png
  10. BIN
      extras/package/macosx/Resources/vlcmenubaricon/playIcon.png
  11. BIN
      extras/package/macosx/Resources/vlcmenubaricon/playIcon@2x.png
  12. BIN
      extras/package/macosx/Resources/vlcmenubaricon/stopIcon.png
  13. BIN
      extras/package/macosx/Resources/vlcmenubaricon/stopIcon@2x.png
  14. 52
      extras/package/macosx/vlc.xcodeproj/project.pbxproj
  15. 1
      modules/gui/macosx/InputManager.m
  16. 7
      modules/gui/macosx/VLCStatusBarIcon.h
  17. 574
      modules/gui/macosx/VLCStatusBarIcon.m

196
extras/package/macosx/Resources/English.lproj/VLCStatusBarIconMainMenu.xib

@ -1,71 +1,205 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<development version="7000" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="VLCStatusBarIcon">
<connections>
<outlet property="nextItem" destination="GhQ-VQ-jtu" id="45X-b4-mHv"/>
<outlet property="playPauseItem" destination="9kC-yJ-Gy5" id="laU-MV-Il1"/>
<outlet property="prevItem" destination="iHu-rd-8KL" id="IzO-1Q-rtv"/>
<outlet property="albumField" destination="SKt-XT-Vki" id="33Z-OU-f74"/>
<outlet property="artistField" destination="FnZ-Gr-BKf" id="wl6-Tg-uhc"/>
<outlet property="backwardsButton" destination="p8X-zU-PwN" id="y6F-9l-mm8"/>
<outlet property="coverImageView" destination="0kw-t4-DcN" id="QmE-0F-ud4"/>
<outlet property="forwardButton" destination="NHj-Vf-SPF" id="XOV-fo-CZn"/>
<outlet property="pathActionItem" destination="1QM-IB-vK4" id="gbD-sJ-WLP"/>
<outlet property="playPauseButton" destination="lvI-lN-t4O" id="kA7-4Q-q36"/>
<outlet property="progressField" destination="z3X-aG-Veg" id="wV9-n7-N7O"/>
<outlet property="quitItem" destination="539" id="xuy-Vl-Ami"/>
<outlet property="randItem" destination="lPi-EL-hoN" id="dOE-ib-n98"/>
<outlet property="randButton" destination="PaW-Fe-vxo" id="L3x-xm-50A"/>
<outlet property="separatorField" destination="za4-8d-tZy" id="Qcx-VE-sZY"/>
<outlet property="showMainWindowItem" destination="08C-TA-yqu" id="qQR-Ah-T0b"/>
<outlet property="stopItem" destination="4Sh-MJ-bSf" id="qBc-qg-d9R"/>
<outlet property="titleField" destination="Byt-pH-60l" id="JKP-xq-fIb"/>
<outlet property="totalField" destination="wXO-2p-mxK" id="XoY-cx-jzm"/>
<outlet property="vlcStatusBarIconMenu" destination="534" id="O0F-8Q-FgA"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="420" customClass="NSFontManager"/>
<menu id="534" userLabel="vlcStatusBarIconMenu">
<menu autoenablesItems="NO" id="534" userLabel="vlcStatusBarIconMenu">
<items>
<menuItem title="Show Main Window" toolTip="Restore main window" id="08C-TA-yqu">
<menuItem title="Loading Now playing view..." id="KRm-PC-DPQ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="restoreMainWindow:" target="-2" id="2Uq-Pa-toi"/>
<outlet property="view" destination="fDN-Tb-DeD" id="T0n-Z2-HeL"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="t2X-zn-Z4x"/>
<menuItem title="Play" tag="74747" toolTip="Start/Pause playback" id="9kC-yJ-Gy5">
<menuItem isSeparatorItem="YES" id="hOT-4N-jtU"/>
<menuItem title="Loading Player view..." id="w9T-bW-Qom">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="statusBarIconTogglePlayPause:" target="-2" id="py3-sd-ST2"/>
<outlet property="view" destination="v97-Ct-Yqs" id="mXc-iD-4sJ"/>
</connections>
</menuItem>
<menuItem title="Stop" tag="83838" toolTip="Stop playback" id="4Sh-MJ-bSf">
<menuItem isSeparatorItem="YES" id="dNe-Wu-c6x"/>
<menuItem title="URL/Path action" enabled="NO" id="1QM-IB-vK4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="statusBarIconStop:" target="-2" id="unT-d5-vlC"/>
<action selector="copyOrOpenCurrentPlaybackItem:" target="-2" id="I4p-PQ-kPp"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="b5S-aL-b79"/>
<menuItem title="Next" toolTip="Next track in playlist" id="GhQ-VQ-jtu">
<menuItem title="Show Main Window" id="08C-TA-yqu">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="statusBarIconNext:" target="-2" id="VZh-xB-5IC"/>
<action selector="restoreMainWindow:" target="-2" id="2Uq-Pa-toi"/>
</connections>
</menuItem>
<menuItem title="Previous" toolTip="Previous track in playlist" id="iHu-rd-8KL">
<menuItem title="Quit" id="539">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="statusBarIconPrevious:" target="-2" id="rNU-Dq-Sot"/>
<action selector="quitAction:" target="-2" id="OJL-0Y-e8i"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="Dn5-wA-WfF"/>
<menuItem title="Random" tag="63636" toolTip="Randomize play order" id="lPi-EL-hoN">
</items>
<point key="canvasLocation" x="354" y="328.5"/>
</menu>
<customView id="fDN-Tb-DeD">
<rect key="frame" x="0.0" y="0.0" width="247" height="70"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" id="0kw-t4-DcN">
<rect key="frame" x="6" y="4" width="48" height="62"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="vlc" id="7Ns-2s-EgU"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="Byt-pH-60l">
<rect key="frame" x="60" y="42" width="183" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="The Fox (What Does the Fox Say?) to this very very" usesSingleLineMode="YES" id="Fo7-qA-sCC">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="FnZ-Gr-BKf">
<rect key="frame" x="60" y="27" width="183" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="by Ylvis" usesSingleLineMode="YES" id="TWt-2V-iGT">
<font key="font" metaFont="system"/>
<color key="textColor" red="0.34105039267015702" green="0.34105039267015702" blue="0.34105039267015702" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" red="0.021842277486911033" green="0.021842277486911033" blue="0.021842277486911033" alpha="1" colorSpace="calibratedRGB"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="SKt-XT-Vki">
<rect key="frame" x="60" y="12" width="183" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="on “The Fox”" usesSingleLineMode="YES" id="IKI-Pl-Iji">
<font key="font" metaFont="system"/>
<color key="textColor" red="0.34105039269999998" green="0.34105039269999998" blue="0.34105039269999998" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" red="0.021842277489999999" green="0.021842277489999999" blue="0.021842277489999999" alpha="1" colorSpace="calibratedRGB"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="370.5" y="-52"/>
</customView>
<customView id="v97-Ct-Yqs">
<rect key="frame" x="0.0" y="0.0" width="247" height="45"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button verticalHuggingPriority="750" id="rih-mA-gAq">
<rect key="frame" x="32" y="1" width="184" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" alignment="center" transparent="YES" imageScaling="proportionallyDown" inset="2" id="RbD-Js-cLU">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="statusBarIconToggleRandom:" target="-2" id="DyP-Hd-KHG"/>
<action selector="toggelProgressTime:" target="-2" id="S3e-vr-guH"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="p96-c8-lBM"/>
<menuItem title="Quit" toolTip="Quit VLC" id="539">
</button>
<button id="p8X-zU-PwN">
<rect key="frame" x="76" y="20" width="28" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="VLCPreviousTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="PSI-Wi-u0R">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="quitAction:" target="-2" id="OJL-0Y-e8i"/>
<action selector="statusBarIconPrevious:" target="-2" id="kAL-hK-8qL"/>
</connections>
</menuItem>
</items>
<point key="canvasLocation" x="328.5" y="267.5"/>
</menu>
</button>
<button id="lvI-lN-t4O">
<rect key="frame" x="109" y="20" width="28" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="VLCPlayTemplate" imagePosition="only" alignment="center" alternateImage="VLCPauseTemplate" imageScaling="proportionallyUpOrDown" inset="2" id="nqu-wV-vI1">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="statusBarIconTogglePlayPause:" target="-2" id="K38-Dr-lNS"/>
</connections>
</button>
<button id="NHj-Vf-SPF">
<rect key="frame" x="141" y="20" width="28" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="VLCNextTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="BIa-Vy-yD2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="statusBarIconNext:" target="-2" id="4I4-wu-R5u"/>
</connections>
</button>
<button id="PaW-Fe-vxo">
<rect key="frame" x="179" y="12" width="18" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="VLCShuffleTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="VEm-qG-2cc">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="statusBarIconToggleRandom:" target="-2" id="IHE-JL-EfK"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="z3X-aG-Veg">
<rect key="frame" x="18" y="0.0" width="100" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="right" title="00:00" usesSingleLineMode="YES" id="CLT-p2-bxf">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="za4-8d-tZy">
<rect key="frame" x="115" y="1" width="17" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="center" title="/" usesSingleLineMode="YES" id="y3P-oA-eTa">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="wXO-2p-mxK">
<rect key="frame" x="127" y="0.0" width="102" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" title="00:00" usesSingleLineMode="YES" id="vF8-Z8-vhW">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<point key="canvasLocation" x="370.5" y="100.5"/>
</customView>
</objects>
<resources>
<image name="VLCNextTemplate" width="128" height="128"/>
<image name="VLCPauseTemplate" width="128" height="128"/>
<image name="VLCPlayTemplate" width="128" height="128"/>
<image name="VLCPreviousTemplate" width="128" height="128"/>
<image name="VLCShuffleTemplate" width="128" height="128"/>
<image name="vlc" width="512" height="512"/>
</resources>
</document>

BIN
extras/package/macosx/Resources/vlcmenubaricon/VLCNextTemplate.pdf

Binary file not shown.

BIN
extras/package/macosx/Resources/vlcmenubaricon/VLCPauseTemplate.pdf

Binary file not shown.

BIN
extras/package/macosx/Resources/vlcmenubaricon/VLCPlayTemplate.pdf

Binary file not shown.

BIN
extras/package/macosx/Resources/vlcmenubaricon/VLCPreviousTemplate.pdf

Binary file not shown.

BIN
extras/package/macosx/Resources/vlcmenubaricon/VLCShuffleTemplate.pdf

Binary file not shown.

0
extras/package/macosx/Resources/vlcmenubaricon/statusBarIcon.pdf → extras/package/macosx/Resources/vlcmenubaricon/VLCStatusBarIcon.pdf

BIN
extras/package/macosx/Resources/vlcmenubaricon/pauseIcon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

BIN
extras/package/macosx/Resources/vlcmenubaricon/pauseIcon@2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
extras/package/macosx/Resources/vlcmenubaricon/playIcon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

BIN
extras/package/macosx/Resources/vlcmenubaricon/playIcon@2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
extras/package/macosx/Resources/vlcmenubaricon/stopIcon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

BIN
extras/package/macosx/Resources/vlcmenubaricon/stopIcon@2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

52
extras/package/macosx/vlc.xcodeproj/project.pbxproj

@ -461,19 +461,18 @@
1CE5ED2619DD6AB700FCEFD3 /* lion-window-fullscreen@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1CE5ED2019DD6AB700FCEFD3 /* lion-window-fullscreen@2x.png */; };
633121D01B5112C300E636DA /* ResumeDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 633121CE1B5112C300E636DA /* ResumeDialog.xib */; };
6B13E2A81BC67678001AD24A /* VLCScrollingClipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B13E2A71BC67678001AD24A /* VLCScrollingClipView.m */; };
6B242D4F1CBD18DA00016E2A /* statusBarIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B242D4E1CBD18DA00016E2A /* statusBarIcon.pdf */; };
6B3F8D2C1CE58E0E002A4998 /* VLCNextTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D281CE58E0E002A4998 /* VLCNextTemplate.pdf */; };
6B3F8D2D1CE58E0E002A4998 /* VLCPauseTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D291CE58E0E002A4998 /* VLCPauseTemplate.pdf */; };
6B3F8D2E1CE58E0E002A4998 /* VLCPlayTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D2A1CE58E0E002A4998 /* VLCPlayTemplate.pdf */; };
6B3F8D2F1CE58E0E002A4998 /* VLCPreviousTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D2B1CE58E0E002A4998 /* VLCPreviousTemplate.pdf */; };
6B3F8D311CE5CC21002A4998 /* VLCStatusBarIcon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D301CE5CC21002A4998 /* VLCStatusBarIcon.pdf */; };
6B3F8D331CE5CD57002A4998 /* VLCShuffleTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 6B3F8D321CE5CD57002A4998 /* VLCShuffleTemplate.pdf */; };
7D3F6525188051F2005776C4 /* BWQuincyMain.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D3F6523188051F2005776C4 /* BWQuincyMain.xib */; };
7D8BB0B71830311300FAE9B7 /* DebugMessageVisualizer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D8BB0B51830311300FAE9B7 /* DebugMessageVisualizer.xib */; };
7D8BB0BA1830367200FAE9B7 /* PlaylistMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D8BB0B81830367200FAE9B7 /* PlaylistMenu.xib */; };
7D8BB0C01830393300FAE9B7 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D8BB0BE1830393300FAE9B7 /* MainWindow.xib */; };
7D9516B71C60B69200D14E1A /* VLCStatusBarIconMainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516B51C60B69200D14E1A /* VLCStatusBarIconMainMenu.xib */; };
7D9516BA1C60B6AB00D14E1A /* VLCStatusBarIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D9516B91C60B6AB00D14E1A /* VLCStatusBarIcon.m */; };
7D9516C41C60B6DB00D14E1A /* pauseIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516BC1C60B6DB00D14E1A /* pauseIcon.png */; };
7D9516C51C60B6DB00D14E1A /* pauseIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516BD1C60B6DB00D14E1A /* pauseIcon@2x.png */; };
7D9516C61C60B6DB00D14E1A /* playIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516BE1C60B6DB00D14E1A /* playIcon.png */; };
7D9516C71C60B6DB00D14E1A /* playIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516BF1C60B6DB00D14E1A /* playIcon@2x.png */; };
7D9516CA1C60B6DB00D14E1A /* stopIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516C21C60B6DB00D14E1A /* stopIcon.png */; };
7D9516CB1C60B6DB00D14E1A /* stopIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D9516C31C60B6DB00D14E1A /* stopIcon@2x.png */; };
7DB65D5618ABD6490053B874 /* AddonManager.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DB65D5418ABD6490053B874 /* AddonManager.xib */; };
7DBB06641CC2314D004C74D2 /* caopengllayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DBB06631CC2314D004C74D2 /* caopengllayer.m */; };
7DD6EC101B58136D0047CF5C /* SimplePreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DD6EC0E1B58136D0047CF5C /* SimplePreferences.xib */; };
@ -1253,7 +1252,12 @@
633121CF1B5112C300E636DA /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Resources/English.lproj/ResumeDialog.xib; sourceTree = "<group>"; };
6B13E2A61BC67678001AD24A /* VLCScrollingClipView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCScrollingClipView.h; path = ../../../modules/gui/macosx/VLCScrollingClipView.h; sourceTree = "<group>"; };
6B13E2A71BC67678001AD24A /* VLCScrollingClipView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCScrollingClipView.m; path = ../../../modules/gui/macosx/VLCScrollingClipView.m; sourceTree = "<group>"; };
6B242D4E1CBD18DA00016E2A /* statusBarIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = statusBarIcon.pdf; path = Resources/vlcmenubaricon/statusBarIcon.pdf; sourceTree = "<group>"; };
6B3F8D281CE58E0E002A4998 /* VLCNextTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCNextTemplate.pdf; path = Resources/vlcmenubaricon/VLCNextTemplate.pdf; sourceTree = "<group>"; };
6B3F8D291CE58E0E002A4998 /* VLCPauseTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCPauseTemplate.pdf; path = Resources/vlcmenubaricon/VLCPauseTemplate.pdf; sourceTree = "<group>"; };
6B3F8D2A1CE58E0E002A4998 /* VLCPlayTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCPlayTemplate.pdf; path = Resources/vlcmenubaricon/VLCPlayTemplate.pdf; sourceTree = "<group>"; };
6B3F8D2B1CE58E0E002A4998 /* VLCPreviousTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCPreviousTemplate.pdf; path = Resources/vlcmenubaricon/VLCPreviousTemplate.pdf; sourceTree = "<group>"; };
6B3F8D301CE5CC21002A4998 /* VLCStatusBarIcon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCStatusBarIcon.pdf; path = Resources/vlcmenubaricon/VLCStatusBarIcon.pdf; sourceTree = "<group>"; };
6B3F8D321CE5CD57002A4998 /* VLCShuffleTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = VLCShuffleTemplate.pdf; path = Resources/vlcmenubaricon/VLCShuffleTemplate.pdf; sourceTree = "<group>"; };
7D3F6524188051F2005776C4 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Resources/English.lproj/BWQuincyMain.xib; sourceTree = "<group>"; };
7D3F652618805297005776C4 /* BWQuincyManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BWQuincyManager.h; path = ../../../modules/gui/macosx/BWQuincyManager.h; sourceTree = SOURCE_ROOT; };
7D3F652718805297005776C4 /* BWQuincyManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BWQuincyManager.m; path = ../../../modules/gui/macosx/BWQuincyManager.m; sourceTree = SOURCE_ROOT; };
@ -1270,12 +1274,6 @@
7D9516B61C60B69200D14E1A /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Resources/English.lproj/VLCStatusBarIconMainMenu.xib; sourceTree = "<group>"; };
7D9516B81C60B6AB00D14E1A /* VLCStatusBarIcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCStatusBarIcon.h; path = ../../../modules/gui/macosx/VLCStatusBarIcon.h; sourceTree = "<group>"; };
7D9516B91C60B6AB00D14E1A /* VLCStatusBarIcon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCStatusBarIcon.m; path = ../../../modules/gui/macosx/VLCStatusBarIcon.m; sourceTree = "<group>"; };
7D9516BC1C60B6DB00D14E1A /* pauseIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pauseIcon.png; path = Resources/vlcmenubaricon/pauseIcon.png; sourceTree = "<group>"; };
7D9516BD1C60B6DB00D14E1A /* pauseIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "pauseIcon@2x.png"; path = "Resources/vlcmenubaricon/pauseIcon@2x.png"; sourceTree = "<group>"; };
7D9516BE1C60B6DB00D14E1A /* playIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = playIcon.png; path = Resources/vlcmenubaricon/playIcon.png; sourceTree = "<group>"; };
7D9516BF1C60B6DB00D14E1A /* playIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "playIcon@2x.png"; path = "Resources/vlcmenubaricon/playIcon@2x.png"; sourceTree = "<group>"; };
7D9516C21C60B6DB00D14E1A /* stopIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = stopIcon.png; path = Resources/vlcmenubaricon/stopIcon.png; sourceTree = "<group>"; };
7D9516C31C60B6DB00D14E1A /* stopIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "stopIcon@2x.png"; path = "Resources/vlcmenubaricon/stopIcon@2x.png"; sourceTree = "<group>"; };
7DA481221B5FC13700917FD7 /* VLCPlaylistView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VLCPlaylistView.h; path = ../../../modules/gui/macosx/VLCPlaylistView.h; sourceTree = "<group>"; };
7DA481231B5FC13700917FD7 /* VLCPlaylistView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = VLCPlaylistView.m; path = ../../../modules/gui/macosx/VLCPlaylistView.m; sourceTree = "<group>"; };
7DB65D5218ABD6380053B874 /* AddonsWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AddonsWindowController.h; path = ../../../modules/gui/macosx/AddonsWindowController.h; sourceTree = SOURCE_ROOT; };
@ -2367,13 +2365,12 @@
7D9516BB1C60B6C700D14E1A /* status bar item */ = {
isa = PBXGroup;
children = (
7D9516BC1C60B6DB00D14E1A /* pauseIcon.png */,
7D9516BD1C60B6DB00D14E1A /* pauseIcon@2x.png */,
7D9516BE1C60B6DB00D14E1A /* playIcon.png */,
7D9516BF1C60B6DB00D14E1A /* playIcon@2x.png */,
6B242D4E1CBD18DA00016E2A /* statusBarIcon.pdf */,
7D9516C21C60B6DB00D14E1A /* stopIcon.png */,
7D9516C31C60B6DB00D14E1A /* stopIcon@2x.png */,
6B3F8D301CE5CC21002A4998 /* VLCStatusBarIcon.pdf */,
6B3F8D281CE58E0E002A4998 /* VLCNextTemplate.pdf */,
6B3F8D291CE58E0E002A4998 /* VLCPauseTemplate.pdf */,
6B3F8D2A1CE58E0E002A4998 /* VLCPlayTemplate.pdf */,
6B3F8D2B1CE58E0E002A4998 /* VLCPreviousTemplate.pdf */,
6B3F8D321CE5CD57002A4998 /* VLCShuffleTemplate.pdf */,
);
name = "status bar item";
sourceTree = "<group>";
@ -3237,6 +3234,7 @@
CC04336613B28B8200D7D52E /* effects-one-button.png in Resources */,
1C88BA7E19DC7B2200645190 /* yosemite-window-zoom-over-graphite.png in Resources */,
1C88BC2719DC7C8100645190 /* ys-progressbar-fill-right_dark.png in Resources */,
6B3F8D2E1CE58E0E002A4998 /* VLCPlayTemplate.pdf in Resources */,
1C88BB1A19DC7C7800645190 /* ys-effects-one-button.png in Resources */,
1C88BA9A19DC7C5D00645190 /* ys-sidebar-playlist@2x.png in Resources */,
1C88BB5D19DC7C7800645190 /* ys-repeat@2x.png in Resources */,
@ -3296,8 +3294,8 @@
1C88BB0A19DC7C7800645190 /* ys-backward-3btns.png in Resources */,
1C88BB0819DC7C7800645190 /* ys-backward-3btns-pressed.png in Resources */,
CC04338C13B28B8200D7D52E /* stop-pressed.png in Resources */,
6B3F8D2F1CE58E0E002A4998 /* VLCPreviousTemplate.pdf in Resources */,
CC04338D13B28B8200D7D52E /* stop.png in Resources */,
6B242D4F1CBD18DA00016E2A /* statusBarIcon.pdf in Resources */,
CC04338E13B28B8200D7D52E /* volume-high.png in Resources */,
CC04338F13B28B8200D7D52E /* volume-low.png in Resources */,
1C88BB3219DC7C7800645190 /* ys-pause.png in Resources */,
@ -3321,6 +3319,7 @@
1C88BCAC19DC7CB300645190 /* ys-fs_stop.png in Resources */,
CC0433AD13B28B9C00D7D52E /* m4a.icns in Resources */,
CC0433AE13B28B9C00D7D52E /* m4v.icns in Resources */,
6B3F8D331CE5CD57002A4998 /* VLCShuffleTemplate.pdf in Resources */,
1C88BA6419DC7B2200645190 /* yosemite-window-fullscreen-on.png in Resources */,
1C88BCB419DC7CB300645190 /* ys-fs_time_slider_knob_highlight.png in Resources */,
1C88BB5A19DC7C7800645190 /* ys-repeat-pressed.png in Resources */,
@ -3495,6 +3494,7 @@
CC9E5D7015975E2600D14E83 /* sidebar-local@2x.png in Resources */,
1C88BB2D19DC7C7800645190 /* ys-next-6btns-pressed@2x.png in Resources */,
CC9E5D7115975E2600D14E83 /* sidebar-movie@2x.png in Resources */,
6B3F8D2C1CE58E0E002A4998 /* VLCNextTemplate.pdf in Resources */,
1C88BBE619DC7C8100645190 /* ys-backward-3btns-dark-pressed@2x.png in Resources */,
1C88BB0C19DC7C7800645190 /* ys-backward-6btns-pressed.png in Resources */,
1C88BC2619DC7C8100645190 /* ys-progressbar-fill-middle_dark@2x.png in Resources */,
@ -3510,7 +3510,6 @@
1C88BB6319DC7C7800645190 /* ys-shuffle-pressed@2x.png in Resources */,
CC9E5D9B15975F5B00D14E83 /* fs_background@2x.png in Resources */,
1C88BC3E19DC7C8100645190 /* ys-shuffle-blue-pressed_dark@2x.png in Resources */,
7D9516C51C60B6DB00D14E1A /* pauseIcon@2x.png in Resources */,
1C88BC2119DC7C8100645190 /* ys-previous-6btns-dark.png in Resources */,
CC9E5D9C15975F5B00D14E83 /* fs_exit_fullscreen@2x.png in Resources */,
CC9E5D9D15975F5B00D14E83 /* fs_forward_highlight@2x.png in Resources */,
@ -3533,16 +3532,15 @@
1C88BA7519DC7B2200645190 /* yosemite-window-minimize-over@2x.png in Resources */,
CC9E5DA815975F5B00D14E83 /* fs_skip_previous@2x.png in Resources */,
1C88BC4319DC7C8100645190 /* ys-shuffle_dark.png in Resources */,
7D9516C71C60B6DB00D14E1A /* playIcon@2x.png in Resources */,
CC9E5DA915975F5B00D14E83 /* fs_stop_highlight@2x.png in Resources */,
CC9E5DAA15975F5B00D14E83 /* fs_stop@2x.png in Resources */,
CC9E5DAB15975F5B00D14E83 /* fs_time_slider_knob_highlight@2x.png in Resources */,
7D9516C41C60B6DB00D14E1A /* pauseIcon.png in Resources */,
1CE5ED2619DD6AB700FCEFD3 /* lion-window-fullscreen@2x.png in Resources */,
1C88BB3E19DC7C7800645190 /* ys-playlist-btn.png in Resources */,
1C88BBEB19DC7C8100645190 /* ys-backward-6btns-dark.png in Resources */,
CC9E5DAC15975F5B00D14E83 /* fs_time_slider_knob@2x.png in Resources */,
1C88BB3919DC7C7800645190 /* ys-playlist-1btn-pressed@2x.png in Resources */,
6B3F8D2D1CE58E0E002A4998 /* VLCPauseTemplate.pdf in Resources */,
1C88BC5519DC7C8100645190 /* ys-volume-slider-track_dark.png in Resources */,
1C88BB5419DC7C7800645190 /* ys-repeat-all.png in Resources */,
CC9E5DAD15975F5B00D14E83 /* fs_time_slider@2x.png in Resources */,
@ -3629,7 +3627,6 @@
CC9E5E08159760B100D14E83 /* stop@2x.png in Resources */,
CC9E5E09159760B100D14E83 /* volume-high@2x.png in Resources */,
1C88BCB719DC7CB300645190 /* ys-fs_volume_max@2x.png in Resources */,
7D9516CB1C60B6DB00D14E1A /* stopIcon@2x.png in Resources */,
1C88BB3019DC7C7800645190 /* ys-pause-pressed.png in Resources */,
CC9E5E0A159760B100D14E83 /* volume-low@2x.png in Resources */,
1C88BCBD19DC7CB300645190 /* ys-fs_volume_mute_highlight@2x.png in Resources */,
@ -3762,7 +3759,6 @@
1C88BA6019DC7B2200645190 /* yosemite-window-fullscreen-graphite.png in Resources */,
CC166FB415F511CC0088201B /* backward-3btns-dark.png in Resources */,
CC166FB515F511CC0088201B /* backward-3btns-dark@2x.png in Resources */,
7D9516CA1C60B6DB00D14E1A /* stopIcon.png in Resources */,
CC166FBA15F511DB0088201B /* backward-3btns-pressed.png in Resources */,
1C88BB3C19DC7C7800645190 /* ys-playlist-btn-pressed.png in Resources */,
CC166FBB15F511DB0088201B /* backward-3btns-pressed@2x.png in Resources */,
@ -3799,7 +3795,6 @@
CC166FE415F5136B0088201B /* previous-6btns-dark@2x.png in Resources */,
1C88BB1E19DC7C7800645190 /* ys-forward-3btns.png in Resources */,
CC166FE915F517660088201B /* backward-6btns-pressed.png in Resources */,
7D9516C61C60B6DB00D14E1A /* playIcon.png in Resources */,
1C88BB6819DC7C7800645190 /* ys-stop.png in Resources */,
CC166FEA15F517660088201B /* backward-6btns-pressed@2x.png in Resources */,
1C88BBF719DC7C8100645190 /* ys-effects-one-button-pressed-dark.png in Resources */,
@ -3840,6 +3835,7 @@
1C88BB1619DC7C7800645190 /* ys-effects-double-buttons.png in Resources */,
1C88BB0D19DC7C7800645190 /* ys-backward-6btns-pressed@2x.png in Resources */,
1C88BC9519DC7CB300645190 /* ys-fs_forward@2x.png in Resources */,
6B3F8D311CE5CC21002A4998 /* VLCStatusBarIcon.pdf in Resources */,
1C88BCA119DC7CB300645190 /* ys-fs_rewind@2x.png in Resources */,
1C88BB6519DC7C7800645190 /* ys-shuffle@2x.png in Resources */,
1CE5ED2119DD6AB700FCEFD3 /* lion-window-fullscreen-on.png in Resources */,

1
modules/gui/macosx/InputManager.m

@ -64,6 +64,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
break;
case INPUT_EVENT_POSITION:
[[[VLCMain sharedInstance] mainWindow] performSelectorOnMainThread:@selector(updateTimeSlider) withObject: nil waitUntilDone:NO];
[[[VLCMain sharedInstance] statusBarIcon] performSelectorOnMainThread:@selector(updateProgress) withObject:nil waitUntilDone:NO];
break;
case INPUT_EVENT_TITLE:
case INPUT_EVENT_CHAPTER:

7
modules/gui/macosx/VLCStatusBarIcon.h

@ -26,15 +26,12 @@
@interface VLCStatusBarIcon : NSObject <NSMenuDelegate>
@property NSStatusItem *statusItem;
@property NSTimer *dataRefreshUpdateTimer;
@property (readwrite, strong) IBOutlet NSMenu *vlcStatusBarIconMenu;
// get data from VLC and update the little status menu
// Get data from VLC and update the little status menu
- (void)updateMenuItemRandom;
- (void)updateMenuItemPlayPause;
- (void)setDataUpdateTimer:(float)interval;
- (void)updateProgress;
- (IBAction)updateMenuItemContent:(id)sender;
- (IBAction)restoreMainWindow:(id)sender;
- (IBAction)statusBarIconTogglePlayPause:(id)sender;
- (IBAction)statusBarIconStop:(id)sender;

574
modules/gui/macosx/VLCStatusBarIcon.m

@ -32,32 +32,33 @@
#import <CoreInteraction.h>
#import <StringUtility.h>
#pragma mark -
#pragma mark Defines
#define dataUpdateTimerInterval 1.0
#define NSInitialToolTipDelayIn_ms 20
// #define showURLInToolTip 1
@interface VLCStatusBarIcon ()
{
NSMenuItem *_vlcStatusBarMenuItem;
/* Outlets for Now Playing labels */
IBOutlet NSTextField *titleField;
IBOutlet NSTextField *artistField;
IBOutlet NSTextField *albumField;
IBOutlet NSTextField *progressField;
IBOutlet NSTextField *separatorField;
IBOutlet NSTextField *totalField;
IBOutlet NSImageView *coverImageView;
/* Outlets for player controls */
IBOutlet NSButton *backwardsButton;
IBOutlet NSButton *playPauseButton;
IBOutlet NSButton *forwardButton;
IBOutlet NSButton *randButton;
/* Outlets for menu items */
IBOutlet NSMenuItem *pathActionItem;
IBOutlet NSMenuItem *showMainWindowItem;
IBOutlet NSMenuItem *playPauseItem;
IBOutlet NSMenuItem *stopItem;
IBOutlet NSMenuItem *nextItem;
IBOutlet NSMenuItem *prevItem;
IBOutlet NSMenuItem *randItem;
IBOutlet NSMenuItem *quitItem;
NSString *_nameToDisplay;
NSString *_timeToDisplay;
NSString *_durationToDisplay;
NSString *_urlToDisplay;
NSImage *_menuImagePlay;
NSImage *_menuImagePause;
NSImage *_menuImageStop;
BOOL isStopped;
BOOL showTimeElapsed;
NSString *_currentPlaybackUrl;
}
@end
@ -69,280 +70,325 @@
#pragma mark -
#pragma mark Init
- (void)dealloc
{
// cleanup
[self.dataRefreshUpdateTimer invalidate];
self.dataRefreshUpdateTimer = nil;
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self enableMenuIcon];
// Set Accessibility Attributes for Image Buttons
[backwardsButton.cell accessibilitySetOverrideValue:_NS("Go to previous track")
forAttribute:NSAccessibilityDescriptionAttribute];
[playPauseButton.cell accessibilitySetOverrideValue:_NS("Play or pause current media")
forAttribute:NSAccessibilityDescriptionAttribute];
[forwardButton.cell accessibilitySetOverrideValue:_NS("Go to next track")
forAttribute:NSAccessibilityDescriptionAttribute];
[randButton.cell accessibilitySetOverrideValue:_NS("Toggle random order playback")
forAttribute:NSAccessibilityDescriptionAttribute];
// Populate menu items with localized strings
[showMainWindowItem setTitle:_NS("Show Main Window")];
[playPauseItem setTitle:_NS("Play")];
[stopItem setTitle:_NS("Stop")];
[nextItem setTitle:_NS("Next")];
[prevItem setTitle:_NS("Previous")];
[randItem setTitle:_NS("Random")];
[pathActionItem setTitle:_NS("Path/URL Action")];
[quitItem setTitle:_NS("Quit")];
// add the top menu item for dynamic data
_vlcStatusBarMenuItem = [[NSMenuItem alloc] initWithTitle:_NS("URL/Path Options") action:@selector(updateMenuItemContent:) keyEquivalent:@""];
[_vlcStatusBarMenuItem setToolTip:_NS("Misc functions with media URL or Path")];
[_vlcStatusBarMenuItem setTarget:self];
[_vlcStatusBarIconMenu insertItem:_vlcStatusBarMenuItem atIndex:0];
showTimeElapsed = YES;
// Set our selves up as delegate, to receive menuNeedsUpdate messages, so
// we can update our menu as needed/before it's drawn
[_vlcStatusBarIconMenu setDelegate:self];
// Register notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateNowPlayingInfo)
name:VLCInputChangedNotification
object:nil];
}
// Disable custom menu item initially
// needs to be done with validateMenuItem (see below)
[_vlcStatusBarMenuItem setEnabled:NO];
// Increase toolTip speed, improves status usability
// Tweak delay above, with '#define NSInitialToolTipDelayIn_ms x'
[[NSUserDefaults standardUserDefaults] setObject: [NSNumber numberWithInt: NSInitialToolTipDelayIn_ms] forKey: @"NSInitialToolTipDelay"];
// init _urlToDisplay
_urlToDisplay = nil;
// Load the menu icons
_menuImagePlay = [NSImage imageNamed:@"playIcon"];
_menuImagePause = [NSImage imageNamed:@"pauseIcon"];
_menuImageStop = [NSImage imageNamed:@"stopIcon"];
[stopItem setImage:_menuImageStop];
/* Enables the Status Bar Item and initializes it's image
* and context menu
*/
- (void)enableMenuIcon
{
// Init the status item
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[_statusItem setHighlightMode:YES];
[_statusItem setEnabled:YES];
[_statusItem setTarget:self];
// I'd rather not use a timer and only update when mouse comes near
// status icon in bar. But one can't tell without evil sourcery :(
// Tweak update frequency above (#define)
// Set the status item image
NSImage *menuIcon = [NSImage imageNamed:@"VLCStatusBarIcon"];
[menuIcon setTemplate:YES];
[_statusItem setImage:menuIcon];
[self setDataUpdateTimer:dataUpdateTimerInterval];
// Attach pull-down menu
[_statusItem setMenu:_vlcStatusBarIconMenu];
}
- (void)dealloc
{
// Cleanup
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark -
#pragma mark Various callback functions
#pragma mark Event callback functions
//---
// Menu delegate/callback for cocoa - called before menu is opened/displayed
// fire off menu item updates (dynamic item 0, play/pause, random)
/* Menu update delegate
* Called before menu is opened/displayed
*/
- (void)menuNeedsUpdate:(NSMenu *)menu
{
// update dynamic menu 'item 0' (follows data gathered by timer handler)
[self updateDynamicMenuItemText];
// update play/pause status in status bar menu
[self updateMenuItemPlayPause];
// update random status in status bar menu
[self updateMetadata];
[self updateMenuItemRandom];
[self updateDynamicMenuItemText];
}
//---
// Make sure we can enable/disable menu items (in our case index 0)
// override class method. Called every time before menu is drawn.
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
/* This is called whenever the playback status for VLC changes and here
* we can update our information in the menu/view
*/
- (void) updateNowPlayingInfo
{
// disable the URL/Path options menu if there is no meaningful data
if ((menuItem.action == @selector(updateMenuItemContent:)) && (!_urlToDisplay)) {
return NO;
}
return YES;
[self updateMetadata];
[self updateProgress];
[self updateDynamicMenuItemText];
}
//---
// callback for tooltip update timer
//
- (void)dataRefreshTimeHandler:(NSTimer *)timer
/* Callback to update current playback time
* Called by InputManager
*/
- (void)updateProgress
{
[self gatherDataToDisplay];
[self updateToolTipText];
input_thread_t *input = pl_CurrentInput(getIntf());
if (input) {
NSString *elapsedTime;
NSString *remainingTime;
NSString *totalTime;
/* Get elapsed and remaining time */
elapsedTime = [[VLCStringUtility sharedInstance] getCurrentTimeAsString:input negative:NO];
remainingTime = [[VLCStringUtility sharedInstance] getCurrentTimeAsString:input negative:YES];
/* Check item duration */
mtime_t dur = input_item_GetDuration(input_GetItem(input));
if (dur == -1) {
/* Unknown duration, possibly due to buffering */
[progressField setStringValue:@"--:--"];
[totalField setStringValue:@"--:--"];
} else if (dur == 0) {
/* Infinite duration */
[progressField setStringValue:elapsedTime];
[totalField setStringValue:@"∞"];
} else {
/* Not unknown, update displayed duration */
totalTime = [[VLCStringUtility sharedInstance] stringForTime:(dur/1000000)];
[progressField setStringValue:(showTimeElapsed) ? elapsedTime : remainingTime];
[totalField setStringValue:totalTime];
}
[self setStoppedStatus:NO];
vlc_object_release(input);
} else {
/* Nothing playing */
[self setStoppedStatus:YES];
}
}
#pragma mark -
#pragma mark Various functions
//---
// enables menu icon/status item, sets proporties like image, attach menu
//
- (void)enableMenuIcon
{
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[_statusItem setHighlightMode:YES];
[_statusItem setEnabled:YES];
[_statusItem setTarget:self];
NSImage *menuIcon;
// set black/white icon (or color, like originally)
menuIcon = [NSImage imageNamed:@"statusBarIcon"];
// Make sure the b/w statusItem icon is inverted on dark/light mode
menuIcon.template = YES;
[_statusItem setImage:menuIcon];
[_statusItem setLength:24];
// Attach pull-down menu
[_statusItem setMenu:_vlcStatusBarIconMenu];
}
#pragma mark Update functions
//---
// Make sure data is fresh, before displaying
//
- (void)gatherDataToDisplay
/* Updates the Metadata for the currently
* playing item or resets it if nothing is playing
*/
- (void)updateMetadata
{
mtime_t pos;
NSImage *coverArtImage;
NSString *title;
NSString *nowPlaying;
NSString *artist;
NSString *album;
input_thread_t *input = pl_CurrentInput(getIntf());
input_item_t *item = NULL;
// Update play/pause status
switch ([self getPlaylistPlayStatus]) {
case PLAYLIST_RUNNING:
[self setStoppedStatus:NO];
[self setProgressTimeEnabled:YES];
[pathActionItem setEnabled:YES];
_currentPlaybackUrl = [[[VLCCoreInteraction sharedInstance]
URLOfCurrentPlaylistItem] absoluteString];
break;
case PLAYLIST_STOPPED:
[self setStoppedStatus:YES];
[self setProgressTimeEnabled:NO];
[pathActionItem setEnabled:NO];
_currentPlaybackUrl = nil;
break;
case PLAYLIST_PAUSED:
[self setStoppedStatus:NO];
[self setProgressTimeEnabled:YES];
[pathActionItem setEnabled:YES];
_currentPlaybackUrl = [[[VLCCoreInteraction sharedInstance]
URLOfCurrentPlaylistItem] absoluteString];
[playPauseButton setState:NSOffState];
default:
break;
}
// get name of current item - clear first!
_nameToDisplay = nil;
_nameToDisplay = [[VLCCoreInteraction sharedInstance] nameOfCurrentPlaylistItem];
if (input) {
item = input_GetItem(input);
}
// If status is 'stopped' there is no useful data
// Otherwise could have used 'if (_nameToDisplay == nil)'
if (item) {
/* Something is playing */
static char *tmp_cstr = NULL;
// Get Coverart
tmp_cstr = input_item_GetArtworkURL(item);
if (tmp_cstr) {
NSString *tempStr = toNSStr(tmp_cstr);
if (![tempStr hasPrefix:@"attachment://"]) {
coverArtImage = [[NSImage alloc]
initWithContentsOfURL:[NSURL URLWithString:tempStr]];
}
FREENULL(tmp_cstr);
}
if ([self vlcPlayingStatus] == PLAYLIST_STOPPED) {
_urlToDisplay = nil;
} else {
input_thread_t * p_input;
p_input = pl_CurrentInput(getIntf());
if (p_input) {
pos = var_GetInteger(p_input, "time") / CLOCK_FREQ;
vlc_object_release(p_input); // must release or get segfault on quit
// Get Titel
tmp_cstr = input_item_GetTitle(item);
if (tmp_cstr) {
title = toNSStr(tmp_cstr);
FREENULL(tmp_cstr);
}
// update our time counter
_timeToDisplay = [[VLCStringUtility sharedInstance] stringForTime:(long long) pos];
// Get Now Playing
tmp_cstr = input_item_GetNowPlaying(item);
if (tmp_cstr) {
nowPlaying = toNSStr(tmp_cstr);
FREENULL(tmp_cstr);
}
// get the duration (if it's there)
int duration = [[VLCCoreInteraction sharedInstance] durationOfCurrentPlaylistItem];
_durationToDisplay = [[VLCStringUtility sharedInstance] stringForTime:(long long) duration];
// Get author
tmp_cstr = input_item_GetArtist(item);
if (tmp_cstr) {
artist = toNSStr(tmp_cstr);
FREENULL(tmp_cstr);
}
// update the playing item's URL/Path
_urlToDisplay = [[[VLCCoreInteraction sharedInstance] URLOfCurrentPlaylistItem] absoluteString];
// Get album
tmp_cstr = input_item_GetAlbum(item);
if (tmp_cstr) {
album = toNSStr(tmp_cstr);
FREENULL(tmp_cstr);
}
} else {
/* Nothing playing */
title = _NS("VLC media player");
artist = _NS("Nothing playing");
}
}
// Set fallback coverart
if (!coverArtImage) {
coverArtImage = [NSImage imageNamed:@"noart.png"];
}
//---
// Call for periodic updates of tooltip text
//
- (void)updateToolTipText
{
NSString *toolTipText = nil;
// craft the multiline string, for the tooltip, depending on play status
if ([self vlcPlayingStatus] == PLAYLIST_STOPPED) {
// nothing playing
toolTipText = _NS("VLC media player\nNothing playing");
} else {
#ifdef showURLInToolTip
toolTipText = [NSString stringWithFormat:_NS("VLC media player\nName: %@\nDuration: %@\nTime: %@\nURL/Path: %@"), _nameToDisplay, _durationToDisplay, _timeToDisplay, _urlToDisplay];
#else
toolTipText = [NSString stringWithFormat:_NS("VLC media player\nName: %@\nDuration: %@\nTime: %@"), _nameToDisplay, _durationToDisplay, _timeToDisplay];
// Causes warning, we need NS_FORMAT_ARGUMENT(1) for the localize function
#endif
// Hack to show now playing for streams (ICY)
if (nowPlaying && !artist) {
artist = nowPlaying;
}
[_statusItem setToolTip:toolTipText];
// Set the metadata in the UI
[self setMetadataTitle:title artist:artist album:album andCover:coverArtImage];
// Cleanup
if (input)
vlc_object_release(input);
}
//---
// Call for updating of dynamic menu item
//
// Update dynamic copy/open menu item status
- (void)updateDynamicMenuItemText
{
NSString *menuString = nil;
if (!_currentPlaybackUrl) {
[pathActionItem setTitle:_NS("Path/URL Action")];
return;
}
NSURL *itemURI = [NSURL URLWithString:_currentPlaybackUrl];
// create string for dynamic menu bit (sync?)
if ([self vlcPlayingStatus] == PLAYLIST_STOPPED) {
// put back our disabled menu item text.
menuString = _NS("URL/Path Options");
if ([itemURI.scheme isEqualToString:@"file"]) {
[pathActionItem setTitle:_NS("Select File In Finder")];
} else {
if ([_urlToDisplay hasPrefix:@"file://"]) {
// offer to show 'file://' in finder
menuString = _NS("Select File In Finder");
} else {
// offer to copy URL to clipboard
menuString = _NS("Copy URL to clipboard");
}
[pathActionItem setTitle:_NS("Copy URL to clipboard")];
}
[_vlcStatusBarMenuItem setTitle:menuString];
}
//---
// set timer for tooltips updates and flee
//
- (void)setDataUpdateTimer:(float)interval
// Update the random menu item status
- (void)updateMenuItemRandom
{
self.dataRefreshUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:@selector(dataRefreshTimeHandler:)
userInfo:nil
repeats:YES];
// Get current random status
bool random;
playlist_t *playlist = pl_Get(getIntf());
random = var_GetBool(playlist, "random");
[randButton setState:(random) ? NSOnState : NSOffState];
}
//---
//
//
- (void)updateMenuItemRandom
{
// get current random status
bool b_value;
playlist_t *p_playlist = pl_Get(getIntf());
b_value = var_GetBool(p_playlist, "random");
if (b_value) {
[randItem setState:NSOnState];
} else {
[randItem setState:NSOffState];
}
}
#pragma mark -
#pragma mark Utility functions
/* Update the UI to the specified metadata
* Any of the values can be nil and will be replaced with empty strings
* or no cover Image at all
*/
- (void)setMetadataTitle:(NSString *)title
artist:(NSString *)artist
album:(NSString *)album
andCover:(NSImage *)cover
{
[titleField setStringValue:(title) ? title : @""];
[artistField setStringValue:(artist) ? artist : @""];
[albumField setStringValue:(album) ? album : @""];
[coverImageView setImage:cover];
}
//---
//
//
- (void)updateMenuItemPlayPause
// Set the play/pause menu item status
- (void)setStoppedStatus:(BOOL)stopped
{
if ([self vlcPlayingStatus] == PLAYLIST_RUNNING) {
[playPauseItem setTitle:_NS("Pause")];
[playPauseItem setImage:_menuImagePause];
isStopped = stopped;
if (stopped) {
[playPauseButton setState:NSOffState];
} else {
[playPauseItem setTitle:_NS("Play")];
[playPauseItem setImage:_menuImagePlay];
[playPauseButton setState:NSOnState];
}
}
- (void)setProgressTimeEnabled:(BOOL)enabled
{
NSColor *color;
color = (!enabled) ? [NSColor secondaryLabelColor] : [NSColor blackColor];
// Set color to the labels
[progressField setTextColor:color];
[separatorField setTextColor:color];
[totalField setTextColor:color];
}
#pragma mark -
#pragma mark Utility functions
//---
// Returns VLC playlist status
// Check for: constants PLAYLIST_RUNNING, PLAYLIST_STOPPED, PLAYLIST_PAUSED.
- (int)vlcPlayingStatus
/* Returns VLC playlist status
* Check for constants:
* PLAYLIST_RUNNING, PLAYLIST_STOPPED, PLAYLIST_PAUSED
*/
- (int)getPlaylistPlayStatus
{
int res;
// get the playlist 'playing' status
playlist_t *p_playlist = pl_Get(getIntf());
PL_LOCK;
@ -353,108 +399,80 @@
}
//---
// Returns true if playing, false in all other cases.
//
- (BOOL)isVLCPlaying
{
bool vlcPlaying = false;
// get the playlist 'playing' status
playlist_t *p_playlist = pl_Get(getIntf());
PL_LOCK;
if (playlist_Status( p_playlist ) == PLAYLIST_RUNNING) {
vlcPlaying = true;
}
PL_UNLOCK;
return vlcPlaying;
}
#pragma mark -
#pragma mark Menu item Actions
//-- action for dynamic menu index 0
- (IBAction) updateMenuItemContent:(id)sender
/* Action: Select the currently playing file in Finder
* or in case of a network stream, copy the URL
*/
- (IBAction)copyOrOpenCurrentPlaybackItem:(id)sender
{
// Here we offer to copy the url to the clipboard or
// select/show a local file in the finder..(useful imo ;-)
if ([self vlcPlayingStatus] != PLAYLIST_STOPPED) {
if ([_urlToDisplay hasPrefix:@"file://"]) {
// show local file in finder
NSString *path=[_urlToDisplay substringFromIndex:7];
[[NSWorkspace sharedWorkspace] selectFile:path inFileViewerRootedAtPath:path];
} else {
// copy remote URL to clipboard
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard setString:_urlToDisplay forType:NSStringPboardType];
}
// If nothing playing, there is nothing to do
if (!_currentPlaybackUrl) {
return;
}
}
// Check if path or URL
NSURL *itemURI = [NSURL URLWithString:_currentPlaybackUrl];
//-- action for 'main window'
if ([itemURI.scheme isEqualToString:@"file"]) {
// Local file, open in Finder
[[NSWorkspace sharedWorkspace] selectFile:itemURI.path
inFileViewerRootedAtPath:itemURI.path];
} else {
// URL, copy to pasteboard
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard setString:_currentPlaybackUrl forType:NSPasteboardTypeString];
}
}
// Action: Show VLC main window
- (IBAction)restoreMainWindow:(id)sender
{
// force our window to go to front (huzzah) and restore window
[[VLCApplication sharedApplication] activateIgnoringOtherApps:YES];
[[[VLCMain sharedInstance] mainWindow] makeKeyAndOrderFront:sender];
}
//-- action for 'toggle play/pause'
// Action: Toggle Play / Pause
- (IBAction)statusBarIconTogglePlayPause:(id)sender
{
[[VLCCoreInteraction sharedInstance] playOrPause];
}
//-- action for 'stop'
// Action: Stop playback
- (IBAction)statusBarIconStop:(id)sender
{
[[VLCCoreInteraction sharedInstance] stop];
}
//-- action for 'Next track'
// Action: Go to next track
- (IBAction)statusBarIconNext:(id)sender
{
[[VLCCoreInteraction sharedInstance] next];
}
//-- action for 'previous track'
// Action: Go to previous track
- (IBAction)statusBarIconPrevious:(id)sender
{
[[VLCCoreInteraction sharedInstance] previous];
}
//-- action to actually 'toggle VLC randomize playorder status'
// Action: Toggle random playback (shuffle)
- (IBAction)statusBarIconToggleRandom:(id)sender
{
[[VLCCoreInteraction sharedInstance] shuffle];
}
// Action: Toggle between elapsed and remaining time
- (IBAction)toggelProgressTime:(id)sender
{
showTimeElapsed = (!showTimeElapsed);
}
//-- action voor 'quit'
// Action: Quit VLC
- (IBAction)quitAction:(id)sender
{
// clean timer, quit
[self.dataRefreshUpdateTimer invalidate];
[[NSApplication sharedApplication] terminate:nil];
}

Loading…
Cancel
Save