<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[176785] trunk/Examples</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/176785">176785</a></dd>
<dt>Author</dt> <dd>adachan@apple.com</dd>
<dt>Date</dt> <dd>2014-12-03 22:42:38 -0800 (Wed, 03 Dec 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add a sample plugin to demonstrate the mute plugin API.
https://bugs.webkit.org/show_bug.cgi?id=139231

Reviewed by Anders Carlsson.

* NetscapeMuteAPIPlugin/AudioPlayer.h: Added.
* NetscapeMuteAPIPlugin/AudioPlayer.mm: Added.
(-[AudioPlayer initWithURL:]):
(-[AudioPlayer dealloc]):
(-[AudioPlayer isReadyToPlay]):
(-[AudioPlayer isPlaying]):
(-[AudioPlayer setPlaying:]):
(-[AudioPlayer isMuted]):
(-[AudioPlayer setMuted:]):
(-[AudioPlayer observeValueForKeyPath:ofObject:change:context:]):
* NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings: Added.
* NetscapeMuteAPIPlugin/Info.plist: Added.
* NetscapeMuteAPIPlugin/MenuHandler.h: Added.
* NetscapeMuteAPIPlugin/MenuHandler.m: Added.
(-[MenuHandler _play:]):
(-[MenuHandler _pause:]):
(-[MenuHandler validateUserInterfaceItem:]):
(-[MenuHandler initWithAudioPlayer:]):
(-[MenuHandler dealloc]):
(-[MenuHandler menu]):
* NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj: Added.
* NetscapeMuteAPIPlugin/main.m: Added.
(-[PluginObject initWithNPP:audioURL:]):
(-[PluginObject dealloc]):
(-[PluginObject menuHandler]):
(-[PluginObject isPlayingAudio]):
(-[PluginObject isMuted]):
(-[PluginObject setMuted:]):
(-[PluginObject readyStateDidChangeForAudioPlayer:]):
(-[PluginObject mutedStateDidChangeForAudioPlayer:]):
(-[PluginObject playStateDidChangeForAudioPlayer:]):
(-[PluginObject _invalidateDisplayString]):
(NP_Initialize):
(NP_GetEntryPoints):
(NP_Shutdown):
(NPP_New):
(NPP_Destroy):
(NPP_SetWindow):
(NPP_NewStream):
(NPP_DestroyStream):
(NPP_WriteReady):
(NPP_Write):
(NPP_StreamAsFile):
(NPP_Print):
(handleDraw):
(invalidatePlugin):
(handleMouseEvent):
(NPP_HandleEvent):
(NPP_URLNotify):
(NPP_GetValue):
(NPP_SetValue):
* NetscapeMuteAPIPlugin/test.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkExamplesChangeLog">trunk/Examples/ChangeLog</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/Examples/NetscapeMuteAPIPlugin/</li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginAudioPlayerh">trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.h</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginAudioPlayermm">trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.mm</a></li>
<li>trunk/Examples/NetscapeMuteAPIPlugin/English.lproj/</li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginEnglishlprojInfoPliststrings">trunk/Examples/NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginInfoplist">trunk/Examples/NetscapeMuteAPIPlugin/Info.plist</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginMenuHandlerh">trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.h</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginMenuHandlerm">trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.m</a></li>
<li>trunk/Examples/NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/</li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginNetscapeMuteAPIPluginxcodeprojprojectpbxproj">trunk/Examples/NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPluginmainm">trunk/Examples/NetscapeMuteAPIPlugin/main.m</a></li>
<li><a href="#trunkExamplesNetscapeMuteAPIPlugintesthtml">trunk/Examples/NetscapeMuteAPIPlugin/test.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkExamplesChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Examples/ChangeLog (176784 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/ChangeLog        2014-12-04 03:12:06 UTC (rev 176784)
+++ trunk/Examples/ChangeLog        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2014-12-03  Ada Chan  &lt;adachan@apple.com&gt;
+
+        Add a sample plugin to demonstrate the mute plugin API.
+        https://bugs.webkit.org/show_bug.cgi?id=139231
+
+        Reviewed by Anders Carlsson.
+
+        * NetscapeMuteAPIPlugin/AudioPlayer.h: Added.
+        * NetscapeMuteAPIPlugin/AudioPlayer.mm: Added.
+        (-[AudioPlayer initWithURL:]):
+        (-[AudioPlayer dealloc]):
+        (-[AudioPlayer isReadyToPlay]):
+        (-[AudioPlayer isPlaying]):
+        (-[AudioPlayer setPlaying:]):
+        (-[AudioPlayer isMuted]):
+        (-[AudioPlayer setMuted:]):
+        (-[AudioPlayer observeValueForKeyPath:ofObject:change:context:]):
+        * NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings: Added.
+        * NetscapeMuteAPIPlugin/Info.plist: Added.
+        * NetscapeMuteAPIPlugin/MenuHandler.h: Added.
+        * NetscapeMuteAPIPlugin/MenuHandler.m: Added.
+        (-[MenuHandler _play:]):
+        (-[MenuHandler _pause:]):
+        (-[MenuHandler validateUserInterfaceItem:]):
+        (-[MenuHandler initWithAudioPlayer:]):
+        (-[MenuHandler dealloc]):
+        (-[MenuHandler menu]):
+        * NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj: Added.
+        * NetscapeMuteAPIPlugin/main.m: Added.
+        (-[PluginObject initWithNPP:audioURL:]):
+        (-[PluginObject dealloc]):
+        (-[PluginObject menuHandler]):
+        (-[PluginObject isPlayingAudio]):
+        (-[PluginObject isMuted]):
+        (-[PluginObject setMuted:]):
+        (-[PluginObject readyStateDidChangeForAudioPlayer:]):
+        (-[PluginObject mutedStateDidChangeForAudioPlayer:]):
+        (-[PluginObject playStateDidChangeForAudioPlayer:]):
+        (-[PluginObject _invalidateDisplayString]):
+        (NP_Initialize):
+        (NP_GetEntryPoints):
+        (NP_Shutdown):
+        (NPP_New):
+        (NPP_Destroy):
+        (NPP_SetWindow):
+        (NPP_NewStream):
+        (NPP_DestroyStream):
+        (NPP_WriteReady):
+        (NPP_Write):
+        (NPP_StreamAsFile):
+        (NPP_Print):
+        (handleDraw):
+        (invalidatePlugin):
+        (handleMouseEvent):
+        (NPP_HandleEvent):
+        (NPP_URLNotify):
+        (NPP_GetValue):
+        (NPP_SetValue):
+        * NetscapeMuteAPIPlugin/test.html: Added.
+
</ins><span class="cx"> 2014-03-14  Maciej Stachowiak  &lt;mjs@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Replace &quot;Apple Computer, Inc.&quot; with &quot;Apple Inc.&quot; in copyright headers
</span></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginAudioPlayerh"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.h (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.h                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.h        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/*
+ IMPORTANT:  This Apple software is supplied to you by Apple Inc. (&quot;Apple&quot;) in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms.  If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in
+ this original Apple software (the &quot;Apple Software&quot;), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software.  Neither the name, trademarks, service marks
+ or logos of Apple Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an &quot;AS IS&quot; basis.  APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &lt;WebKit/npfunctions.h&gt;
+
+@class AVPlayer;
+@class AVPlayerItem;
+@class AudioPlayer;
+
+@protocol AudioPlayerDelegate &lt;NSObject&gt;
+
+- (void)readyStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer;
+- (void)mutedStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer;
+- (void)playStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer;
+
+@end
+
+@interface AudioPlayer : NSObject {
+    BOOL _playing;
+    AVPlayer *_audioPlayer;
+    AVPlayerItem *_playerItem;
+    id&lt;AudioPlayerDelegate&gt; _audioPlayerDelegate;
+}
+
+- (instancetype)initWithURL:(NSURL *)url;
+
+@property (nonatomic, weak) id&lt;AudioPlayerDelegate&gt; audioPlayerDelegate;
+@property (nonatomic, readonly, getter=isReadyToPlay) BOOL readyToPlay;
+@property (nonatomic, getter=isPlaying) BOOL playing;
+@property (nonatomic, getter=isMuted) BOOL muted;
+
+@end
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginAudioPlayermm"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.mm (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.mm                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/AudioPlayer.mm        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,118 @@
</span><ins>+/*
+ IMPORTANT:  This Apple software is supplied to you by Apple Inc. (&quot;Apple&quot;) in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms.  If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in
+ this original Apple software (the &quot;Apple Software&quot;), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software.  Neither the name, trademarks, service marks
+ or logos of Apple Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an &quot;AS IS&quot; basis.  APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &quot;AudioPlayer.h&quot;
+
+#import &lt;AVFoundation/AVFoundation.h&gt;
+
+static void *itemStatusKVOContext = &amp;itemStatusKVOContext;
+
+@implementation AudioPlayer
+
+@synthesize audioPlayerDelegate=_audioPlayerDelegate;
+
+- (instancetype)initWithURL:(NSURL *)url
+{
+    if (!url.absoluteString.length)
+        return nil;
+
+    if (!(self = [super init]))
+        return nil;
+
+    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
+    _playerItem = [[AVPlayerItem alloc] initWithAsset:avAsset];
+    [_playerItem addObserver:self forKeyPath:@&quot;status&quot; options:0 context:itemStatusKVOContext];
+    _audioPlayer = [[AVPlayer alloc] initWithPlayerItem:_playerItem];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [_playerItem removeObserver:self forKeyPath:@&quot;status&quot;];
+    [_audioPlayer release];
+    [_playerItem release];
+    [super dealloc];
+}
+
+- (BOOL)isReadyToPlay
+{
+    return _audioPlayer.currentItem.status == AVPlayerItemStatusReadyToPlay;
+}
+
+- (BOOL)isPlaying
+{
+    return _playing;
+}
+
+- (void)setPlaying:(BOOL)playing
+{
+    if (_playing == playing)
+        return;
+
+    if (playing &amp;&amp; !self.isReadyToPlay)
+        return;
+
+    _playing = playing;
+
+    if (_playing)
+        [_audioPlayer play];
+    else
+        [_audioPlayer pause];
+
+    [_audioPlayerDelegate playStateDidChangeForAudioPlayer:self];
+}
+
+- (BOOL)isMuted
+{
+    return _audioPlayer.isMuted;
+}
+
+- (void)setMuted:(BOOL)muted
+{
+    if (self.isMuted == muted)
+        return;
+
+    _audioPlayer.muted = muted;
+    [_audioPlayerDelegate mutedStateDidChangeForAudioPlayer:self];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+
+    if (context == &amp;itemStatusKVOContext) {
+        dispatch_async(dispatch_get_main_queue(), ^{ [_audioPlayerDelegate readyStateDidChangeForAudioPlayer:self]; });
+        return;
+    }
+    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+}
+@end
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginEnglishlprojInfoPliststrings"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/English.lproj/InfoPlist.strings        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+\xFF\xFE/* Localized versions of Info.plist keys */
+
+
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginInfoplist"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/Info.plist (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/Info.plist                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/Info.plist        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
+&lt;plist version=&quot;1.0&quot;&gt;
+&lt;dict&gt;
+        &lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
+        &lt;string&gt;English&lt;/string&gt;
+        &lt;key&gt;CFBundleExecutable&lt;/key&gt;
+        &lt;string&gt;NetscapeMuteAPIPlugin&lt;/string&gt;
+        &lt;key&gt;CFBundleIconFile&lt;/key&gt;
+        &lt;string&gt;&lt;/string&gt;
+        &lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+        &lt;string&gt;com.apple.netscapemuteapiplugin&lt;/string&gt;
+        &lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
+        &lt;string&gt;6.0&lt;/string&gt;
+        &lt;key&gt;CFBundlePackageType&lt;/key&gt;
+        &lt;string&gt;BRPL&lt;/string&gt;
+        &lt;key&gt;CFBundleShortVersionString&lt;/key&gt;
+        &lt;string&gt;1.0&lt;/string&gt;
+        &lt;key&gt;CFBundleSignature&lt;/key&gt;
+        &lt;string&gt;????&lt;/string&gt;
+        &lt;key&gt;CFBundleVersion&lt;/key&gt;
+        &lt;string&gt;1.0&lt;/string&gt;
+        &lt;key&gt;WebPluginDescription&lt;/key&gt;
+        &lt;string&gt;Simple Netscape plug-in that uses the Mute API&lt;/string&gt;
+        &lt;key&gt;WebPluginMIMETypes&lt;/key&gt;
+        &lt;dict&gt;
+                &lt;key&gt;test/x-netscape-mute-api-plugin&lt;/key&gt;
+                &lt;dict&gt;
+                        &lt;key&gt;WebPluginTypeDescription&lt;/key&gt;
+                        &lt;string&gt;Netscape Cocoa Plug-in&lt;/string&gt;
+                &lt;/dict&gt;
+        &lt;/dict&gt;
+        &lt;key&gt;WebPluginName&lt;/key&gt;
+        &lt;string&gt;Netscape Mute API Plug-in&lt;/string&gt;
+&lt;/dict&gt;
+&lt;/plist&gt;
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginMenuHandlerh"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.h (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.h                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.h        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+/*
+ IMPORTANT:  This Apple software is supplied to you by Apple Inc. (&quot;Apple&quot;) in
+ consideration of your agreement to the following terms, and your use, installation, 
+ modification or redistribution of this Apple software constitutes acceptance of these 
+ terms.  If you do not agree with these terms, please do not use, install, modify or 
+ redistribute this Apple software.

+ In consideration of your agreement to abide by the following terms, and subject to these 
+ terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 
+ this original Apple software (the &quot;Apple Software&quot;), to use, reproduce, modify and 
+ redistribute the Apple Software, with or without modifications, in source and/or binary 
+ forms; provided that if you redistribute the Apple Software in its entirety and without 
+ modifications, you must retain this notice and the following text and disclaimers in all 
+ such redistributions of the Apple Software.  Neither the name, trademarks, service marks 
+ or logos of Apple Inc. may be used to endorse or promote products derived from 
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your 
+ derivative works or by other works in which the Apple Software may be incorporated.

+ The Apple Software is provided by Apple on an &quot;AS IS&quot; basis.  APPLE MAKES NO WARRANTIES, 
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &lt;Cocoa/Cocoa.h&gt;
+
+@class AudioPlayer;
+
+@interface MenuHandler : NSObject {
+    NSMenu *_menu;
+    AudioPlayer *_audioPlayer;
+}
+
+- (id)initWithAudioPlayer:(AudioPlayer *)audioPlayer;
+- (NSMenu *)menu;
+
+@end
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginMenuHandlerm"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.m (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.m                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/MenuHandler.m        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+/*
+ IMPORTANT:  This Apple software is supplied to you by Apple Inc. (&quot;Apple&quot;) in
+ consideration of your agreement to the following terms, and your use, installation, 
+ modification or redistribution of this Apple software constitutes acceptance of these 
+ terms.  If you do not agree with these terms, please do not use, install, modify or 
+ redistribute this Apple software.

+ In consideration of your agreement to abide by the following terms, and subject to these 
+ terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 
+ this original Apple software (the &quot;Apple Software&quot;), to use, reproduce, modify and 
+ redistribute the Apple Software, with or without modifications, in source and/or binary 
+ forms; provided that if you redistribute the Apple Software in its entirety and without 
+ modifications, you must retain this notice and the following text and disclaimers in all 
+ such redistributions of the Apple Software.  Neither the name, trademarks, service marks 
+ or logos of Apple Inc. may be used to endorse or promote products derived from 
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your 
+ derivative works or by other works in which the Apple Software may be incorporated.

+ The Apple Software is provided by Apple on an &quot;AS IS&quot; basis.  APPLE MAKES NO WARRANTIES, 
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &quot;MenuHandler.h&quot;
+
+#import &quot;AudioPlayer.h&quot;
+
+@implementation MenuHandler
+
+- (void)_play:(id)sender
+{
+    _audioPlayer.playing = YES;
+}
+
+- (void)_pause:(id)sender
+{
+    _audioPlayer.playing = NO;
+}
+
+- (BOOL)validateUserInterfaceItem:(id &lt;NSValidatedUserInterfaceItem&gt;)anItem
+{
+    SEL sel = [anItem action];
+    
+    if (sel == @selector(_play:))
+        return _audioPlayer.isReadyToPlay &amp;&amp; !_audioPlayer.isPlaying;
+
+    if (sel == @selector(_pause:))
+        return _audioPlayer.isPlaying;
+
+    return NO;
+}
+
+- (id)initWithAudioPlayer:(AudioPlayer *)audioPlayer
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    _audioPlayer = [audioPlayer retain];
+
+    // Create the menu
+    _menu = [[NSMenu alloc] initWithTitle:@&quot;Menu&quot;];
+    
+    NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@&quot;Play&quot; action:@selector(_play:) keyEquivalent:@&quot;&quot;];
+    [item setTarget:self];
+    [_menu addItem:item];
+    [item release];
+
+    item = [[NSMenuItem alloc] initWithTitle:@&quot;Pause&quot; action:@selector(_pause:) keyEquivalent:@&quot;&quot;];
+    [item setTarget:self];
+    [_menu addItem:item];
+    [item release];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [_menu release];
+    [_audioPlayer release];
+    
+    [super dealloc];
+}
+
+- (NSMenu *)menu
+{
+    return _menu;
+}
+
+@end
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginNetscapeMuteAPIPluginxcodeprojprojectpbxproj"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/NetscapeMuteAPIPlugin.xcodeproj/project.pbxproj        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,263 @@
</span><ins>+// !$*UTF8*$!
+{
+        archiveVersion = 1;
+        classes = {
+        };
+        objectVersion = 46;
+        objects = {
+
+/* Begin PBXBuildFile section */
+                1A624E590DCBC7F6006898C8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A624E580DCBC7F6006898C8 /* main.m */; };
+                1A6250420DCBC81B006898C8 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A6250410DCBC81B006898C8 /* Cocoa.framework */; };
+                1AAD6A090DD0DC52003985DA /* MenuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAD6A080DD0DC52003985DA /* MenuHandler.m */; };
+                52E2CAF119F856E9001EEB4F /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52E2CAF019F856E9001EEB4F /* AVFoundation.framework */; };
+                52E2CAF419F85A47001EEB4F /* AudioPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 52E2CAF319F85A47001EEB4F /* AudioPlayer.mm */; };
+                8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+                089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = &quot;&lt;group&gt;&quot;; };
+                1A624E580DCBC7F6006898C8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+                1A6250410DCBC81B006898C8 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = &quot;&lt;absolute&gt;&quot;; };
+                1AAD6A070DD0DC52003985DA /* MenuHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuHandler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                1AAD6A080DD0DC52003985DA /* MenuHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuHandler.m; sourceTree = &quot;&lt;group&gt;&quot;; };
+                52E2CAF019F856E9001EEB4F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = ../../../../../../../../System/Library/Frameworks/AVFoundation.framework; sourceTree = &quot;&lt;group&gt;&quot;; };
+                52E2CAF219F85A47001EEB4F /* AudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioPlayer.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                52E2CAF319F85A47001EEB4F /* AudioPlayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioPlayer.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
+                8D576316048677EA00EA77CD /* NetscapeMuteAPIPlugin.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetscapeMuteAPIPlugin.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
+                8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = &quot;&lt;group&gt;&quot;; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+                8D576313048677EA00EA77CD /* Frameworks */ = {
+                        isa = PBXFrameworksBuildPhase;
+                        buildActionMask = 2147483647;
+                        files = (
+                                52E2CAF119F856E9001EEB4F /* AVFoundation.framework in Frameworks */,
+                                1A6250420DCBC81B006898C8 /* Cocoa.framework in Frameworks */,
+                        );
+                        runOnlyForDeploymentPostprocessing = 0;
+                };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+                089C166AFE841209C02AAC07 /* NetscapeMuteAPIPlugin */ = {
+                        isa = PBXGroup;
+                        children = (
+                                52E2CAF019F856E9001EEB4F /* AVFoundation.framework */,
+                                08FB77AFFE84173DC02AAC07 /* Source */,
+                                089C167CFE841241C02AAC07 /* Resources */,
+                                089C1671FE841209C02AAC07 /* External Frameworks and Libraries */,
+                                19C28FB6FE9D52B211CA2CBB /* Products */,
+                        );
+                        name = NetscapeMuteAPIPlugin;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = {
+                        isa = PBXGroup;
+                        children = (
+                                1A6250410DCBC81B006898C8 /* Cocoa.framework */,
+                        );
+                        name = &quot;External Frameworks and Libraries&quot;;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                089C167CFE841241C02AAC07 /* Resources */ = {
+                        isa = PBXGroup;
+                        children = (
+                                8D576317048677EA00EA77CD /* Info.plist */,
+                                8D5B49A704867FD3000E48DA /* InfoPlist.strings */,
+                        );
+                        name = Resources;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                08FB77AFFE84173DC02AAC07 /* Source */ = {
+                        isa = PBXGroup;
+                        children = (
+                                1A624E580DCBC7F6006898C8 /* main.m */,
+                                1AAD6A070DD0DC52003985DA /* MenuHandler.h */,
+                                1AAD6A080DD0DC52003985DA /* MenuHandler.m */,
+                                52E2CAF219F85A47001EEB4F /* AudioPlayer.h */,
+                                52E2CAF319F85A47001EEB4F /* AudioPlayer.mm */,
+                        );
+                        name = Source;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                19C28FB6FE9D52B211CA2CBB /* Products */ = {
+                        isa = PBXGroup;
+                        children = (
+                                8D576316048677EA00EA77CD /* NetscapeMuteAPIPlugin.plugin */,
+                        );
+                        name = Products;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+                8D57630D048677EA00EA77CD /* NetscapeMuteAPIPlugin */ = {
+                        isa = PBXNativeTarget;
+                        buildConfigurationList = 149C298308902C53008A9EFC /* Build configuration list for PBXNativeTarget &quot;NetscapeMuteAPIPlugin&quot; */;
+                        buildPhases = (
+                                8D576311048677EA00EA77CD /* Sources */,
+                                8D57630F048677EA00EA77CD /* Resources */,
+                                8D576313048677EA00EA77CD /* Frameworks */,
+                        );
+                        buildRules = (
+                        );
+                        dependencies = (
+                        );
+                        name = NetscapeMuteAPIPlugin;
+                        productInstallPath = &quot;$(HOME)/Library/Bundles&quot;;
+                        productName = NetscapeMuteAPIPlugin;
+                        productReference = 8D576316048677EA00EA77CD /* NetscapeMuteAPIPlugin.plugin */;
+                        productType = &quot;com.apple.product-type.bundle&quot;;
+                };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+                089C1669FE841209C02AAC07 /* Project object */ = {
+                        isa = PBXProject;
+                        attributes = {
+                                LastUpgradeCheck = 0600;
+                        };
+                        buildConfigurationList = 149C298708902C53008A9EFC /* Build configuration list for PBXProject &quot;NetscapeMuteAPIPlugin&quot; */;
+                        compatibilityVersion = &quot;Xcode 3.2&quot;;
+                        developmentRegion = English;
+                        hasScannedForEncodings = 1;
+                        knownRegions = (
+                                English,
+                                Japanese,
+                                French,
+                                German,
+                        );
+                        mainGroup = 089C166AFE841209C02AAC07 /* NetscapeMuteAPIPlugin */;
+                        projectDirPath = &quot;&quot;;
+                        projectRoot = &quot;&quot;;
+                        targets = (
+                                8D57630D048677EA00EA77CD /* NetscapeMuteAPIPlugin */,
+                        );
+                };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+                8D57630F048677EA00EA77CD /* Resources */ = {
+                        isa = PBXResourcesBuildPhase;
+                        buildActionMask = 2147483647;
+                        files = (
+                                8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */,
+                        );
+                        runOnlyForDeploymentPostprocessing = 0;
+                };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+                8D576311048677EA00EA77CD /* Sources */ = {
+                        isa = PBXSourcesBuildPhase;
+                        buildActionMask = 2147483647;
+                        files = (
+                                1A624E590DCBC7F6006898C8 /* main.m in Sources */,
+                                52E2CAF419F85A47001EEB4F /* AudioPlayer.mm in Sources */,
+                                1AAD6A090DD0DC52003985DA /* MenuHandler.m in Sources */,
+                        );
+                        runOnlyForDeploymentPostprocessing = 0;
+                };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+                8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = {
+                        isa = PBXVariantGroup;
+                        children = (
+                                089C167EFE841241C02AAC07 /* English */,
+                        );
+                        name = InfoPlist.strings;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+                149C298408902C53008A9EFC /* Debug */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                COMBINE_HIDPI_IMAGES = YES;
+                                COPY_PHASE_STRIP = NO;
+                                FRAMEWORK_SEARCH_PATHS = (
+                                        &quot;$(inherited)&quot;,
+                                        &quot;$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks&quot;,
+                                );
+                                GCC_DEBUGGING_SYMBOLS = full;
+                                GCC_DYNAMIC_NO_PIC = NO;
+                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                                GCC_MODEL_TUNING = G5;
+                                GCC_OPTIMIZATION_LEVEL = 0;
+                                INFOPLIST_FILE = Info.plist;
+                                INSTALL_PATH = &quot;$(HOME)/Library/Bundles&quot;;
+                                PRODUCT_NAME = NetscapeMuteAPIPlugin;
+                                WRAPPER_EXTENSION = plugin;
+                                ZERO_LINK = YES;
+                        };
+                        name = Debug;
+                };
+                149C298508902C53008A9EFC /* Release */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                COMBINE_HIDPI_IMAGES = YES;
+                                FRAMEWORK_SEARCH_PATHS = (
+                                        &quot;$(inherited)&quot;,
+                                        &quot;$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks&quot;,
+                                );
+                                GCC_DEBUGGING_SYMBOLS = full;
+                                GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                                GCC_MODEL_TUNING = G5;
+                                GCC_OPTIMIZATION_LEVEL = 0;
+                                INFOPLIST_FILE = Info.plist;
+                                INSTALL_PATH = &quot;$(HOME)/Library/Bundles&quot;;
+                                PRODUCT_NAME = NetscapeMuteAPIPlugin;
+                                WRAPPER_EXTENSION = plugin;
+                        };
+                        name = Release;
+                };
+                149C298808902C53008A9EFC /* Debug */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = &quot;ppc i386 ppc64 x86_64&quot;;
+                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                                GCC_WARN_UNUSED_VARIABLE = YES;
+                                ONLY_ACTIVE_ARCH = YES;
+                                PREBINDING = NO;
+                        };
+                        name = Debug;
+                };
+                149C298908902C53008A9EFC /* Release */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = &quot;ppc i386 ppc64 x86_64&quot;;
+                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                                GCC_WARN_UNUSED_VARIABLE = YES;
+                                PREBINDING = NO;
+                        };
+                        name = Release;
+                };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+                149C298308902C53008A9EFC /* Build configuration list for PBXNativeTarget &quot;NetscapeMuteAPIPlugin&quot; */ = {
+                        isa = XCConfigurationList;
+                        buildConfigurations = (
+                                149C298408902C53008A9EFC /* Debug */,
+                                149C298508902C53008A9EFC /* Release */,
+                        );
+                        defaultConfigurationIsVisible = 0;
+                        defaultConfigurationName = Release;
+                };
+                149C298708902C53008A9EFC /* Build configuration list for PBXProject &quot;NetscapeMuteAPIPlugin&quot; */ = {
+                        isa = XCConfigurationList;
+                        buildConfigurations = (
+                                149C298808902C53008A9EFC /* Debug */,
+                                149C298908902C53008A9EFC /* Release */,
+                        );
+                        defaultConfigurationIsVisible = 0;
+                        defaultConfigurationName = Release;
+                };
+/* End XCConfigurationList section */
+        };
+        rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPluginmainm"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/main.m (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/main.m                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/main.m        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,408 @@
</span><ins>+/*
+ IMPORTANT:  This Apple software is supplied to you by Apple Inc. (&quot;Apple&quot;) in
+ consideration of your agreement to the following terms, and your use, installation, 
+ modification or redistribution of this Apple software constitutes acceptance of these 
+ terms.  If you do not agree with these terms, please do not use, install, modify or 
+ redistribute this Apple software.

+ In consideration of your agreement to abide by the following terms, and subject to these 
+ terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 
+ this original Apple software (the &quot;Apple Software&quot;), to use, reproduce, modify and 
+ redistribute the Apple Software, with or without modifications, in source and/or binary 
+ forms; provided that if you redistribute the Apple Software in its entirety and without 
+ modifications, you must retain this notice and the following text and disclaimers in all 
+ such redistributions of the Apple Software.  Neither the name, trademarks, service marks 
+ or logos of Apple Inc. may be used to endorse or promote products derived from 
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your 
+ derivative works or by other works in which the Apple Software may be incorporated.

+ The Apple Software is provided by Apple on an &quot;AS IS&quot; basis.  APPLE MAKES NO WARRANTIES, 
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.

+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import &quot;AudioPlayer.h&quot;
+#import &quot;MenuHandler.h&quot;
+#import &lt;Cocoa/Cocoa.h&gt;
+#import &lt;WebKit/npapi.h&gt;
+#import &lt;WebKit/npfunctions.h&gt;
+#import &lt;WebKit/npruntime.h&gt;
+
+// Browser function table
+static NPNetscapeFuncs* browser;
+
+// Structure for per-instance storage
+@interface PluginObject : NSObject &lt;AudioPlayerDelegate&gt; {
+    AudioPlayer *_audioPlayer;
+    MenuHandler *_menuHandler;
+}
+
+@property (nonatomic, readonly) NPP npp;
+@property (nonatomic) NPWindow window;
+@property (nonatomic, strong, readonly) NSURL *audioURL;
+@property (nonatomic, copy, readonly) NSString *displayString;
+@property (nonatomic, strong, readonly) MenuHandler *menuHandler;
+@property (nonatomic) BOOL hasFocus;
+@property (nonatomic, readonly, getter=isPlayingAudio) BOOL playingAudio;
+@property (nonatomic, getter=isMuted) BOOL muted;
+
+- (instancetype)initWithNPP:(NPP)npp audioURL:(NSURL *)audioURL;
+
+@end
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData*);
+NPError NPP_Destroy(NPP instance, NPSavedData**);
+NPError NPP_SetWindow(NPP instance, NPWindow*);
+NPError NPP_NewStream(NPP instance, NPMIMEType, NPStream*, NPBool seekable, uint16_t* stype);
+NPError NPP_DestroyStream(NPP instance, NPStream*, NPReason);
+int32_t NPP_WriteReady(NPP instance, NPStream*);
+int32_t NPP_Write(NPP instance, NPStream*, int32_t offset, int32_t len, void* buffer);
+void NPP_StreamAsFile(NPP instance, NPStream*, const char* fname);
+void NPP_Print(NPP instance, NPPrint* platformPrint);
+int16_t NPP_HandleEvent(NPP instance, void* event);
+void NPP_URLNotify(NPP instance, const char* URL, NPReason, void* notifyData);
+NPError NPP_GetValue(NPP instance, NPPVariable, void *value);
+NPError NPP_SetValue(NPP instance, NPNVariable, void *value);
+
+#pragma export on
+// Mach-o entry points
+NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
+NPError NP_GetEntryPoints(NPPluginFuncs *);
+void NP_Shutdown(void);
+#pragma export off
+
+static void invalidatePlugin(PluginObject *);
+
+@implementation PluginObject
+
+- (instancetype)initWithNPP:(NPP)npp audioURL:(NSURL *)audioURL
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _npp = npp;
+    _audioURL = [audioURL retain];
+    _audioPlayer = [[AudioPlayer alloc] initWithURL:audioURL];
+    _audioPlayer.audioPlayerDelegate = self;
+
+    NPBool isMuted;
+    if (browser-&gt;getvalue(npp, NPNVmuteAudioBool, &amp;isMuted) != NPERR_NO_ERROR)
+        isMuted = FALSE;
+    self.muted = isMuted;
+
+    [self _invalidateDisplayString];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [_audioURL release];
+    [_menuHandler release];
+    [_audioPlayer release];
+    [_displayString release];
+
+    [super dealloc];
+}
+
+- (MenuHandler *)menuHandler
+{
+    if (!_menuHandler)
+        _menuHandler = [[MenuHandler alloc] initWithAudioPlayer:_audioPlayer];
+
+    return _menuHandler;
+}
+
+- (BOOL)isPlayingAudio
+{
+    return _audioPlayer.isPlaying;
+}
+
+- (BOOL)isMuted
+{
+    return _audioPlayer.isMuted;
+}
+
+- (void)setMuted:(BOOL)muted
+{
+    _audioPlayer.muted = muted;
+}
+
+- (void)readyStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
+{
+    [self _invalidateDisplayString];
+    invalidatePlugin(self);
+}
+
+- (void)mutedStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
+{
+}
+
+- (void)playStateDidChangeForAudioPlayer:(AudioPlayer *)audioPlayer
+{
+    [self _invalidateDisplayString];
+    invalidatePlugin(self);
+    browser-&gt;setvalue(_npp, NPPVpluginIsPlayingAudio, _audioPlayer.isPlaying);
+}
+
+- (void)_invalidateDisplayString
+{
+    [_displayString release];
+
+    NSString *prefix;
+    if (!_audioPlayer.isReadyToPlay)
+        prefix = @&quot;Loading: &quot;;
+    else if (_audioPlayer.isPlaying)
+        prefix = @&quot;Playing: &quot;;
+    else
+        prefix = @&quot;Ready to play: &quot;;
+
+    _displayString = [[NSString stringWithFormat:@&quot;%@ %@&quot;, prefix, _audioURL.absoluteString] retain];
+}
+
+@end
+
+
+NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
+{
+    browser = browserFuncs;
+    return NPERR_NO_ERROR;
+}
+
+NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
+{
+    pluginFuncs-&gt;version = 11;
+    pluginFuncs-&gt;size = sizeof(pluginFuncs);
+    pluginFuncs-&gt;newp = NPP_New;
+    pluginFuncs-&gt;destroy = NPP_Destroy;
+    pluginFuncs-&gt;setwindow = NPP_SetWindow;
+    pluginFuncs-&gt;newstream = NPP_NewStream;
+    pluginFuncs-&gt;destroystream = NPP_DestroyStream;
+    pluginFuncs-&gt;asfile = NPP_StreamAsFile;
+    pluginFuncs-&gt;writeready = NPP_WriteReady;
+    pluginFuncs-&gt;write = (NPP_WriteProcPtr)NPP_Write;
+    pluginFuncs-&gt;print = NPP_Print;
+    pluginFuncs-&gt;event = NPP_HandleEvent;
+    pluginFuncs-&gt;urlnotify = NPP_URLNotify;
+    pluginFuncs-&gt;getvalue = NPP_GetValue;
+    pluginFuncs-&gt;setvalue = NPP_SetValue;
+    
+    return NPERR_NO_ERROR;
+}
+
+void NP_Shutdown(void)
+{
+
+}
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
+{
+    // Create per-instance storage
+    // Ask the browser if it supports the CoreGraphics drawing model
+    NPBool supportsCoreGraphics;
+    if (browser-&gt;getvalue(instance, NPNVsupportsCoreGraphicsBool, &amp;supportsCoreGraphics) != NPERR_NO_ERROR)
+        supportsCoreGraphics = FALSE;
+    
+    if (!supportsCoreGraphics)
+        return NPERR_INCOMPATIBLE_VERSION_ERROR;
+    
+    // If the browser supports the CoreGraphics drawing model, enable it.
+    browser-&gt;setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreGraphics);
+
+    // If the browser supports the Cocoa event model, enable it.
+    NPBool supportsCocoa;
+    if (browser-&gt;getvalue(instance, NPNVsupportsCocoaBool, &amp;supportsCocoa) != NPERR_NO_ERROR)
+        supportsCocoa = FALSE;
+    
+    if (!supportsCocoa)
+        return NPERR_INCOMPATIBLE_VERSION_ERROR;
+    
+    browser-&gt;setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa);
+
+    NSURL *audioURL = nil;
+    for (int16_t i = 0; i &lt; argc; i++) {
+        if (!strcasecmp(argn[i], &quot;audiourl&quot;)) {
+            NSString *urlString = [NSString stringWithUTF8String:argv[i]];
+            if (urlString)
+                audioURL = [NSURL URLWithString:urlString];
+            break;
+        }
+    }
+
+    PluginObject *obj = [[PluginObject alloc] initWithNPP:instance audioURL:audioURL];
+    instance-&gt;pdata = obj;
+
+    return NPERR_NO_ERROR;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save)
+{
+    // Free per-instance storage
+    PluginObject *obj = instance-&gt;pdata;
+    [obj release];
+
+    return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window)
+{
+    PluginObject *obj = instance-&gt;pdata;
+    obj.window = *window;
+
+    return NPERR_NO_ERROR;
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
+{
+    *stype = NP_ASFILEONLY;
+    return NPERR_NO_ERROR;
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
+{
+    return NPERR_NO_ERROR;
+}
+
+int32_t NPP_WriteReady(NPP instance, NPStream* stream)
+{
+    return 0;
+}
+
+int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
+{
+    return 0;
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
+{
+}
+
+void NPP_Print(NPP instance, NPPrint* platformPrint)
+{
+}
+
+static void handleDraw(PluginObject *obj, NPCocoaEvent *event)
+{
+    NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
+    
+    NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:event-&gt;data.draw.context flipped:YES];
+
+    [NSGraphicsContext setCurrentContext:context];
+    
+    NSRect rect = NSMakeRect(0, 0, obj.window.width, obj.window.height);
+    
+    [[NSColor lightGrayColor] set];
+    [NSBezierPath fillRect:rect];
+
+    // If the plugin has focus, draw a focus indicator
+    if (obj.hasFocus) {
+        [[NSColor blackColor] set];
+        NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
+        [path setLineWidth:5];
+        [path stroke];
+    }
+    
+    [obj.displayString drawAtPoint:NSMakePoint(10, 10) withAttributes:nil];
+    
+    [NSGraphicsContext setCurrentContext:oldContext];
+    [oldContext release];
+}
+
+static void invalidatePlugin(PluginObject *obj)
+{
+    NPRect rect;
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = obj.window.width;
+    rect.bottom = obj.window.height;
+    
+    browser-&gt;invalidaterect(obj.npp, &amp;rect);
+}
+
+
+static void handleMouseEvent(PluginObject *obj, NPCocoaEvent *event)
+{
+    if (event-&gt;data.mouse.buttonNumber == 1)
+        browser-&gt;popupcontextmenu(obj.npp, (NPNSMenu *)[obj.menuHandler menu]);
+}
+
+int16_t NPP_HandleEvent(NPP instance, void* event)
+{
+    PluginObject *obj = instance-&gt;pdata;
+
+    NPCocoaEvent *cocoaEvent = event;
+    
+    switch (cocoaEvent-&gt;type) {
+    case NPCocoaEventFocusChanged:
+        obj.hasFocus = cocoaEvent-&gt;data.focus.hasFocus;
+        invalidatePlugin(obj);
+        return 1;
+        
+    case NPCocoaEventDrawRect:
+        handleDraw(obj, cocoaEvent);
+        return 1;
+    
+    case NPCocoaEventMouseDown:
+    case NPCocoaEventMouseUp:
+        
+    // FIXME: NPCocoaEventMouseMoved is currently disabled in order to see other events more clearly
+    // without &quot;drowning&quot; in mouse moved events.
+//        case NPCocoaEventMouseMoved:
+    case NPCocoaEventMouseEntered:
+    case NPCocoaEventMouseExited:
+    case NPCocoaEventMouseDragged:
+    case NPCocoaEventScrollWheel:
+        handleMouseEvent(obj, cocoaEvent);
+        return 1;
+
+    default:
+        break;
+    }
+    
+    return 0;
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+    PluginObject *obj = instance-&gt;pdata;
+
+    switch (variable) {
+    case NPPVpluginIsPlayingAudio:
+        if (value)
+            *((NPBool **)value) = obj.isPlayingAudio;
+        return NPERR_NO_ERROR;
+
+    default:
+        return NPERR_GENERIC_ERROR;
+    }
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+    PluginObject *obj = instance-&gt;pdata;
+
+    switch (variable) {
+    case NPNVmuteAudioBool:
+        if (value)
+            obj.muted = *((NPBool *)value);
+        return NPERR_NO_ERROR;
+
+    default:
+        return NPERR_GENERIC_ERROR;
+    }
+}
</ins></span></pre></div>
<a id="trunkExamplesNetscapeMuteAPIPlugintesthtml"></a>
<div class="addfile"><h4>Added: trunk/Examples/NetscapeMuteAPIPlugin/test.html (0 => 176785)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Examples/NetscapeMuteAPIPlugin/test.html                                (rev 0)
+++ trunk/Examples/NetscapeMuteAPIPlugin/test.html        2014-12-04 06:42:38 UTC (rev 176785)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;title&gt;Cocoa Mute API Plug-In&lt;/title&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;p&gt;To test, set audiourl to an absolute URL to an audio file (e.g. mp3).&lt;/p&gt;
+&lt;div&gt;
+    &lt;embed width=&quot;700&quot; height=&quot;50&quot; type=&quot;test/x-netscape-mute-api-plugin&quot; audiourl=&quot;&quot;&gt;&lt;/embed&gt;
+&lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre>
</div>
</div>

</body>
</html>