| @@ -411,6 +411,7 @@ OBJECTS := \ | |||
| $(OBJDIR)/juce_linux_Network.o \ | |||
| $(OBJDIR)/juce_linux_SystemStats.o \ | |||
| $(OBJDIR)/juce_linux_Threads.o \ | |||
| $(OBJDIR)/juce_linux_WebBrowserComponent.o \ | |||
| $(OBJDIR)/juce_linux_Windowing.o \ | |||
| MKDIR_TYPE := msdos | |||
| @@ -2327,6 +2328,11 @@ $(OBJDIR)/juce_linux_Threads.o: platform_specific_code/juce_linux_Threads.cpp | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_linux_WebBrowserComponent.o: platform_specific_code/juce_linux_WebBrowserComponent.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @$(CXX) $(CXXFLAGS) -o $@ -c $< | |||
| $(OBJDIR)/juce_linux_Windowing.o: platform_specific_code/juce_linux_Windowing.cpp | |||
| -@$(CMD_MKOBJDIR) | |||
| @echo $(notdir $<) | |||
| @@ -0,0 +1,135 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/gui/components/special/juce_WebBrowserComponent.h" | |||
| /* | |||
| Sorry.. This class isn't implemented on Linux! | |||
| */ | |||
| //============================================================================== | |||
| WebBrowserComponent::WebBrowserComponent() | |||
| : browser (0), | |||
| blankPageShown (false) | |||
| { | |||
| setOpaque (true); | |||
| } | |||
| WebBrowserComponent::~WebBrowserComponent() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::goToURL (const String& url, | |||
| const StringArray* headers, | |||
| const MemoryBlock* postData) | |||
| { | |||
| lastURL = url; | |||
| lastHeaders.clear(); | |||
| if (headers != 0) | |||
| lastHeaders = *headers; | |||
| lastPostData.setSize (0); | |||
| if (postData != 0) | |||
| lastPostData = *postData; | |||
| blankPageShown = false; | |||
| } | |||
| void WebBrowserComponent::stop() | |||
| { | |||
| } | |||
| void WebBrowserComponent::goBack() | |||
| { | |||
| lastURL = String::empty; | |||
| blankPageShown = false; | |||
| } | |||
| void WebBrowserComponent::goForward() | |||
| { | |||
| lastURL = String::empty; | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::paint (Graphics& g) | |||
| { | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void WebBrowserComponent::checkWindowAssociation() | |||
| { | |||
| } | |||
| void WebBrowserComponent::reloadLastURL() | |||
| { | |||
| if (lastURL.isNotEmpty()) | |||
| { | |||
| goToURL (lastURL, &lastHeaders, &lastPostData); | |||
| lastURL = String::empty; | |||
| } | |||
| } | |||
| void WebBrowserComponent::parentHierarchyChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| void WebBrowserComponent::moved() | |||
| { | |||
| } | |||
| void WebBrowserComponent::resized() | |||
| { | |||
| } | |||
| void WebBrowserComponent::visibilityChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| bool WebBrowserComponent::pageAboutToLoad (const String& url) | |||
| { | |||
| return true; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -208,6 +208,8 @@ | |||
| 847F72DC0C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 847F72D80C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h */; }; | |||
| 847F72DD0C2702A000CBECEC /* juce_FileTreeComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F72D90C2702A000CBECEC /* juce_FileTreeComponent.cpp */; }; | |||
| 847F72DE0C2702A000CBECEC /* juce_FileTreeComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 847F72DA0C2702A000CBECEC /* juce_FileTreeComponent.h */; }; | |||
| 848A560B0DDDD3E40041C706 /* juce_mac_WebBrowserComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 848A560A0DDDD3E40041C706 /* juce_mac_WebBrowserComponent.mm */; }; | |||
| 848A560E0DDDD3FB0041C706 /* juce_WebBrowserComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 848A560D0DDDD3FB0041C706 /* juce_WebBrowserComponent.h */; }; | |||
| 8495BB8C0D8067B2001D9C0B /* juce_AudioThumbnail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8495BB880D8067B2001D9C0B /* juce_AudioThumbnail.cpp */; }; | |||
| 8495BB8D0D8067B2001D9C0B /* juce_AudioThumbnail.h in Headers */ = {isa = PBXBuildFile; fileRef = 8495BB890D8067B2001D9C0B /* juce_AudioThumbnail.h */; }; | |||
| 8495BB8E0D8067B2001D9C0B /* juce_AudioThumbnailCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8495BB8A0D8067B2001D9C0B /* juce_AudioThumbnailCache.cpp */; }; | |||
| @@ -897,6 +899,8 @@ | |||
| 847F72D80C2702A000CBECEC /* juce_DirectoryContentsDisplayComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_DirectoryContentsDisplayComponent.h; path = filebrowser/juce_DirectoryContentsDisplayComponent.h; sourceTree = "<group>"; }; | |||
| 847F72D90C2702A000CBECEC /* juce_FileTreeComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = juce_FileTreeComponent.cpp; path = filebrowser/juce_FileTreeComponent.cpp; sourceTree = "<group>"; }; | |||
| 847F72DA0C2702A000CBECEC /* juce_FileTreeComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = juce_FileTreeComponent.h; path = filebrowser/juce_FileTreeComponent.h; sourceTree = "<group>"; }; | |||
| 848A560A0DDDD3E40041C706 /* juce_mac_WebBrowserComponent.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = juce_mac_WebBrowserComponent.mm; sourceTree = "<group>"; }; | |||
| 848A560D0DDDD3FB0041C706 /* juce_WebBrowserComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = juce_WebBrowserComponent.h; sourceTree = "<group>"; }; | |||
| 8495BB880D8067B2001D9C0B /* juce_AudioThumbnail.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioThumbnail.cpp; sourceTree = "<group>"; }; | |||
| 8495BB890D8067B2001D9C0B /* juce_AudioThumbnail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_AudioThumbnail.h; sourceTree = "<group>"; }; | |||
| 8495BB8A0D8067B2001D9C0B /* juce_AudioThumbnailCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_AudioThumbnailCache.cpp; sourceTree = "<group>"; }; | |||
| @@ -1554,6 +1558,7 @@ | |||
| 847D06460DD88D1100DF6A61 /* juce_mac_Network.mm */, | |||
| 84A4882508A22E2400752A2B /* juce_mac_SystemStats.cpp */, | |||
| 84A4882608A22E2400752A2B /* juce_mac_Threads.cpp */, | |||
| 848A560A0DDDD3E40041C706 /* juce_mac_WebBrowserComponent.mm */, | |||
| 84A4882708A22E2400752A2B /* juce_mac_Windowing.cpp */, | |||
| ); | |||
| name = "mac specific code"; | |||
| @@ -1937,6 +1942,7 @@ | |||
| 84A488EB08A22E4900752A2B /* juce_PreferencesPanel.h */, | |||
| 84A488EC08A22E4900752A2B /* juce_QuickTimeMovieComponent.cpp */, | |||
| 84A488ED08A22E4900752A2B /* juce_QuickTimeMovieComponent.h */, | |||
| 848A560D0DDDD3FB0041C706 /* juce_WebBrowserComponent.h */, | |||
| ); | |||
| name = special; | |||
| path = ../../src/juce_appframework/gui/components/special; | |||
| @@ -2904,6 +2910,7 @@ | |||
| 8495BB960D806BDA001D9C0B /* juce_InputSource.h in Headers */, | |||
| 84581EEB0D9148C500AE1A4C /* juce_QuickTimeAudioFormat.h in Headers */, | |||
| 84022DFD0DAE4CB9004CF59A /* juce_mac_HTTPStream.h in Headers */, | |||
| 848A560E0DDDD3FB0041C706 /* juce_WebBrowserComponent.h in Headers */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -3320,6 +3327,7 @@ | |||
| 84581EEA0D9148C500AE1A4C /* juce_QuickTimeAudioFormat.cpp in Sources */, | |||
| 84CE8A410DC5D7D600799A0E /* juce_mac_AudioCDBurner.mm in Sources */, | |||
| 847D06470DD88D1100DF6A61 /* juce_mac_Network.mm in Sources */, | |||
| 848A560B0DDDD3E40041C706 /* juce_mac_WebBrowserComponent.mm in Sources */, | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| }; | |||
| @@ -0,0 +1,442 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| #import <Cocoa/Cocoa.h> | |||
| #import <WebKit/HIWebView.h> | |||
| #import <WebKit/WebPolicyDelegate.h> | |||
| #import <WebKit/CarbonUtils.h> | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/events/juce_Timer.h" | |||
| #include "../../../src/juce_appframework/gui/components/special/juce_WebBrowserComponent.h" | |||
| END_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| @interface DownloadClickDetector : NSObject | |||
| { | |||
| juce::WebBrowserComponent* ownerComponent; | |||
| } | |||
| - (DownloadClickDetector*) init: (juce::WebBrowserComponent*) ownerComponent; | |||
| - (void) webView: (WebView*) webView decidePolicyForNavigationAction: (NSDictionary*) actionInformation | |||
| request: (NSURLRequest*) request | |||
| frame: (WebFrame*) frame | |||
| decisionListener: (id<WebPolicyDecisionListener>) listener; | |||
| @end | |||
| //============================================================================== | |||
| @implementation DownloadClickDetector | |||
| - (DownloadClickDetector*) init: (juce::WebBrowserComponent*) ownerComponent_ | |||
| { | |||
| [super init]; | |||
| ownerComponent = ownerComponent_; | |||
| return self; | |||
| } | |||
| - (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener >)listener | |||
| { | |||
| NSURL* url = [actionInformation valueForKey: @"WebActionOriginalURLKey"]; | |||
| if (ownerComponent->pageAboutToLoad (juce::String::fromUTF8 ((const juce::uint8*) [[url absoluteString] UTF8String]))) | |||
| [listener use]; | |||
| else | |||
| [listener ignore]; | |||
| } | |||
| @end | |||
| BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| class WebBrowserComponentInternal : public Timer | |||
| { | |||
| public: | |||
| WebBrowserComponentInternal (WebBrowserComponent* const owner_) | |||
| : owner (owner_), | |||
| view (0), | |||
| webView (0) | |||
| { | |||
| HIWebViewCreate (&view); | |||
| ComponentPeer* const peer = owner_->getPeer(); | |||
| jassert (peer != 0); | |||
| if (view != 0 && peer != 0) | |||
| { | |||
| WindowRef parentWindow = (WindowRef) peer->getNativeHandle(); | |||
| WindowAttributes attributes; | |||
| GetWindowAttributes (parentWindow, &attributes); | |||
| HIViewRef parentView = 0; | |||
| if ((attributes & kWindowCompositingAttribute) != 0) | |||
| { | |||
| HIViewRef root = HIViewGetRoot (parentWindow); | |||
| HIViewFindByID (root, kHIViewWindowContentID, &parentView); | |||
| if (parentView == 0) | |||
| parentView = root; | |||
| } | |||
| else | |||
| { | |||
| GetRootControl (parentWindow, (ControlRef*) &parentView); | |||
| if (parentView == 0) | |||
| CreateRootControl (parentWindow, (ControlRef*) &parentView); | |||
| } | |||
| HIViewAddSubview (parentView, view); | |||
| updateBounds(); | |||
| show(); | |||
| webView = HIWebViewGetWebView (view); | |||
| clickListener = [[DownloadClickDetector alloc] init: owner_]; | |||
| [webView setPolicyDelegate: clickListener]; | |||
| } | |||
| startTimer (500); | |||
| } | |||
| ~WebBrowserComponentInternal() | |||
| { | |||
| [webView setPolicyDelegate: nil]; | |||
| [clickListener release]; | |||
| if (view != 0) | |||
| CFRelease (view); | |||
| } | |||
| // Horrific bodge-workaround for the fact that the webview somehow hangs onto key | |||
| // focus when you pop up a new window, no matter what that window does to | |||
| // try to grab focus for itself. This catches such a situation and forces | |||
| // focus away from the webview, then back to the place it should be.. | |||
| void timerCallback() | |||
| { | |||
| WindowRef viewWindow = HIViewGetWindow (view); | |||
| WindowRef focusedWindow = GetUserFocusWindow(); | |||
| if (focusedWindow != viewWindow) | |||
| { | |||
| if (HIViewSubtreeContainsFocus (view)) | |||
| { | |||
| HIViewAdvanceFocus (HIViewGetRoot (viewWindow), 0); | |||
| HIViewAdvanceFocus (HIViewGetRoot (focusedWindow), 0); | |||
| } | |||
| } | |||
| } | |||
| void show() | |||
| { | |||
| HIViewSetVisible (view, true); | |||
| } | |||
| void hide() | |||
| { | |||
| HIViewSetVisible (view, false); | |||
| } | |||
| void goToURL (const String& url, | |||
| const StringArray* headers, | |||
| const MemoryBlock* postData) | |||
| { | |||
| char** headerNamesAsChars = 0; | |||
| char** headerValuesAsChars = 0; | |||
| int numHeaders = 0; | |||
| if (headers != 0) | |||
| { | |||
| numHeaders = headers->size(); | |||
| headerNamesAsChars = (char**) juce_malloc (sizeof (char*) * numHeaders); | |||
| headerValuesAsChars = (char**) juce_malloc (sizeof (char*) * numHeaders); | |||
| int i; | |||
| for (i = 0; i < numHeaders; ++i) | |||
| { | |||
| const String headerName ((*headers)[i].upToFirstOccurrenceOf (T(":"), false, false).trim()); | |||
| headerNamesAsChars[i] = (char*) juce_calloc (headerName.copyToUTF8 (0)); | |||
| headerName.copyToUTF8 ((juce::uint8*) headerNamesAsChars[i]); | |||
| const String headerValue ((*headers)[i].fromFirstOccurrenceOf (T(":"), false, false).trim()); | |||
| headerValuesAsChars[i] = (char*) juce_calloc (headerValue.copyToUTF8 (0)); | |||
| headerValue.copyToUTF8 ((juce::uint8*) headerValuesAsChars[i]); | |||
| } | |||
| } | |||
| sendWebViewToURL ((const char*) url.toUTF8(), | |||
| (const char**) headerNamesAsChars, | |||
| (const char**) headerValuesAsChars, | |||
| numHeaders, | |||
| postData != 0 ? (const char*) postData->getData() : 0, | |||
| postData != 0 ? postData->getSize() : 0); | |||
| for (int i = 0; i < numHeaders; ++i) | |||
| { | |||
| juce_free (headerNamesAsChars[i]); | |||
| juce_free (headerValuesAsChars[i]); | |||
| } | |||
| juce_free (headerNamesAsChars); | |||
| juce_free (headerValuesAsChars); | |||
| } | |||
| void goBack() | |||
| { | |||
| [webView goBack]; | |||
| } | |||
| void goForward() | |||
| { | |||
| [webView goForward]; | |||
| } | |||
| void stop() | |||
| { | |||
| [webView stopLoading]; | |||
| } | |||
| void updateBounds() | |||
| { | |||
| HIRect r; | |||
| r.origin.x = (float) owner->getScreenX() - owner->getTopLevelComponent()->getScreenX(); | |||
| r.origin.y = (float) owner->getScreenY() - owner->getTopLevelComponent()->getScreenY(); | |||
| r.size.width = (float) owner->getWidth(); | |||
| r.size.height = (float) owner->getHeight(); | |||
| HIViewSetFrame (view, &r); | |||
| } | |||
| private: | |||
| WebBrowserComponent* const owner; | |||
| HIViewRef view; | |||
| WebView* webView; | |||
| DownloadClickDetector* clickListener; | |||
| void sendWebViewToURL (const char* utf8URL, | |||
| const char** headerNames, | |||
| const char** headerValues, | |||
| int numHeaders, | |||
| const char* postData, | |||
| int postDataSize) | |||
| { | |||
| NSMutableURLRequest* r = [NSMutableURLRequest | |||
| requestWithURL: [NSURL URLWithString: [NSString stringWithUTF8String: utf8URL]] | |||
| cachePolicy: NSURLRequestUseProtocolCachePolicy | |||
| timeoutInterval: 30.0]; | |||
| if (postDataSize > 0) | |||
| { | |||
| [ r setHTTPMethod: @"POST"]; | |||
| [ r setHTTPBody: [NSData dataWithBytes: postData length: postDataSize]]; | |||
| } | |||
| int i; | |||
| for (i = 0; i < numHeaders; ++i) | |||
| { | |||
| [ r setValue: [NSString stringWithUTF8String: headerValues[i]] | |||
| forHTTPHeaderField: [NSString stringWithUTF8String: headerNames[i]]]; | |||
| } | |||
| [[webView mainFrame] stopLoading ]; | |||
| [[webView mainFrame] loadRequest: r]; | |||
| } | |||
| WebBrowserComponentInternal (const WebBrowserComponentInternal&); | |||
| const WebBrowserComponentInternal& operator= (const WebBrowserComponentInternal&); | |||
| }; | |||
| //============================================================================== | |||
| WebBrowserComponent::WebBrowserComponent() | |||
| : browser (0), | |||
| associatedWindow (0), | |||
| blankPageShown (false) | |||
| { | |||
| setOpaque (true); | |||
| } | |||
| WebBrowserComponent::~WebBrowserComponent() | |||
| { | |||
| deleteBrowser(); | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::goToURL (const String& url, | |||
| const StringArray* headers, | |||
| const MemoryBlock* postData) | |||
| { | |||
| lastURL = url; | |||
| lastHeaders.clear(); | |||
| if (headers != 0) | |||
| lastHeaders = *headers; | |||
| lastPostData.setSize (0); | |||
| if (postData != 0) | |||
| lastPostData = *postData; | |||
| blankPageShown = false; | |||
| if (browser != 0) | |||
| browser->goToURL (url, headers, postData); | |||
| } | |||
| void WebBrowserComponent::stop() | |||
| { | |||
| if (browser != 0) | |||
| browser->stop(); | |||
| } | |||
| void WebBrowserComponent::goBack() | |||
| { | |||
| lastURL = String::empty; | |||
| blankPageShown = false; | |||
| if (browser != 0) | |||
| browser->goBack(); | |||
| } | |||
| void WebBrowserComponent::goForward() | |||
| { | |||
| lastURL = String::empty; | |||
| if (browser != 0) | |||
| browser->goForward(); | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::paint (Graphics& g) | |||
| { | |||
| if (browser == 0) | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void WebBrowserComponent::checkWindowAssociation() | |||
| { | |||
| void* const window = getWindowHandle(); | |||
| if (window != associatedWindow | |||
| || (browser == 0 && window != 0)) | |||
| { | |||
| associatedWindow = window; | |||
| deleteBrowser(); | |||
| createBrowser(); | |||
| } | |||
| if (browser != 0) | |||
| { | |||
| if (associatedWindow != 0 && isShowing()) | |||
| { | |||
| browser->show(); | |||
| if (blankPageShown) | |||
| goBack(); | |||
| } | |||
| else | |||
| { | |||
| if (! blankPageShown) | |||
| { | |||
| // when the component becomes invisible, some stuff like flash | |||
| // carries on playing audio, so we need to force it onto a blank | |||
| // page to avoid this.. | |||
| blankPageShown = true; | |||
| browser->goToURL ("about:blank", 0, 0); | |||
| } | |||
| browser->hide(); | |||
| } | |||
| } | |||
| } | |||
| void WebBrowserComponent::createBrowser() | |||
| { | |||
| deleteBrowser(); | |||
| if (isShowing()) | |||
| { | |||
| WebInitForCarbon(); | |||
| browser = new WebBrowserComponentInternal (this); | |||
| reloadLastURL(); | |||
| } | |||
| } | |||
| void WebBrowserComponent::deleteBrowser() | |||
| { | |||
| deleteAndZero (browser); | |||
| } | |||
| void WebBrowserComponent::reloadLastURL() | |||
| { | |||
| if (lastURL.isNotEmpty()) | |||
| { | |||
| goToURL (lastURL, &lastHeaders, &lastPostData); | |||
| lastURL = String::empty; | |||
| } | |||
| } | |||
| void WebBrowserComponent::updateBrowserPosition() | |||
| { | |||
| if (getPeer() != 0 && browser != 0) | |||
| browser->updateBounds(); | |||
| } | |||
| void WebBrowserComponent::parentHierarchyChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| void WebBrowserComponent::moved() | |||
| { | |||
| updateBrowserPosition(); | |||
| } | |||
| void WebBrowserComponent::resized() | |||
| { | |||
| updateBrowserPosition(); | |||
| } | |||
| void WebBrowserComponent::visibilityChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| bool WebBrowserComponent::pageAboutToLoad (const String& url) | |||
| { | |||
| return true; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -0,0 +1,362 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| //============================================================================== | |||
| #ifdef _MSC_VER | |||
| #pragma warning (disable: 4514) | |||
| #pragma warning (push) | |||
| #endif | |||
| #include "win32_headers.h" | |||
| #include <comutil.h> | |||
| #include <Exdisp.h> | |||
| #include <exdispid.h> | |||
| #ifdef _MSC_VER | |||
| #pragma warning (pop) | |||
| #pragma warning (disable: 4312 4244) | |||
| #endif | |||
| #include "../../../src/juce_core/basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "../../../src/juce_appframework/gui/components/special/juce_WebBrowserComponent.h" | |||
| #include "../../../src/juce_appframework/gui/components/special/juce_ActiveXControlComponent.h" | |||
| //============================================================================== | |||
| class WebBrowserComponentInternal : public ActiveXControlComponent | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| WebBrowserComponentInternal() | |||
| : browser (0), | |||
| connectionPoint (0), | |||
| adviseCookie (0) | |||
| { | |||
| } | |||
| ~WebBrowserComponentInternal() | |||
| { | |||
| if (connectionPoint != 0) | |||
| connectionPoint->Unadvise (adviseCookie); | |||
| if (browser != 0) | |||
| browser->Release(); | |||
| } | |||
| void createBrowser() | |||
| { | |||
| createControl (&CLSID_WebBrowser); | |||
| browser = (IWebBrowser2*) queryInterface (&IID_IWebBrowser2); | |||
| IConnectionPointContainer* connectionPointContainer = (IConnectionPointContainer*) queryInterface (&IID_IConnectionPointContainer); | |||
| if (connectionPointContainer != 0) | |||
| { | |||
| connectionPointContainer->FindConnectionPoint (DIID_DWebBrowserEvents2, | |||
| &connectionPoint); | |||
| if (connectionPoint != 0) | |||
| { | |||
| WebBrowserComponent* const owner = dynamic_cast <WebBrowserComponent*> (getParentComponent()); | |||
| jassert (owner != 0); | |||
| EventHandler* handler = new EventHandler (owner); | |||
| connectionPoint->Advise (handler, &adviseCookie); | |||
| } | |||
| } | |||
| } | |||
| void goToURL (const String& url, | |||
| const StringArray* headers, | |||
| const MemoryBlock* postData) | |||
| { | |||
| if (browser != 0) | |||
| { | |||
| LPSAFEARRAY sa = 0; | |||
| _variant_t flags, frame, postDataVar, headersVar; | |||
| if (headers != 0) | |||
| headersVar = (const tchar*) headers->joinIntoString ("\r\n"); | |||
| if (postData != 0 && postData->getSize() > 0) | |||
| { | |||
| LPSAFEARRAY sa = SafeArrayCreateVector (VT_UI1, 0, postData->getSize()); | |||
| if (sa != 0) | |||
| { | |||
| void* data = 0; | |||
| SafeArrayAccessData (sa, &data); | |||
| jassert (data != 0); | |||
| if (data != 0) | |||
| { | |||
| postData->copyTo (data, 0, postData->getSize()); | |||
| SafeArrayUnaccessData (sa); | |||
| VARIANT postDataVar2; | |||
| VariantInit (&postDataVar2); | |||
| V_VT (&postDataVar2) = VT_ARRAY | VT_UI1; | |||
| V_ARRAY (&postDataVar2) = sa; | |||
| postDataVar = postDataVar2; | |||
| } | |||
| } | |||
| } | |||
| browser->Navigate ((BSTR) (const OLECHAR*) url, | |||
| &flags, &frame, | |||
| &postDataVar, &headersVar); | |||
| if (sa != 0) | |||
| SafeArrayDestroy (sa); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| IWebBrowser2* browser; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| IConnectionPoint* connectionPoint; | |||
| DWORD adviseCookie; | |||
| //============================================================================== | |||
| class EventHandler : public IDispatch | |||
| { | |||
| public: | |||
| EventHandler (WebBrowserComponent* owner_) | |||
| : owner (owner_), | |||
| refCount (0) | |||
| { | |||
| } | |||
| ~EventHandler() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) | |||
| { | |||
| if (id == IID_IUnknown || id == IID_IDispatch || id == DIID_DWebBrowserEvents2) | |||
| { | |||
| AddRef(); | |||
| *result = this; | |||
| return S_OK; | |||
| } | |||
| *result = 0; | |||
| return E_NOINTERFACE; | |||
| } | |||
| ULONG __stdcall AddRef() { return ++refCount; } | |||
| ULONG __stdcall Release() { jassert (refCount > 0); const int r = --refCount; if (r == 0) delete this; return r; } | |||
| HRESULT __stdcall GetTypeInfoCount (UINT __RPC_FAR*) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetTypeInfo (UINT, LCID, ITypeInfo __RPC_FAR *__RPC_FAR*) { return E_NOTIMPL; } | |||
| HRESULT __stdcall GetIDsOfNames (REFIID, LPOLESTR __RPC_FAR*, UINT, LCID, DISPID __RPC_FAR*) { return E_NOTIMPL; } | |||
| HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID /*riid*/, LCID /*lcid*/, | |||
| WORD /*wFlags*/, DISPPARAMS __RPC_FAR* pDispParams, | |||
| VARIANT __RPC_FAR* /*pVarResult*/, EXCEPINFO __RPC_FAR* /*pExcepInfo*/, | |||
| UINT __RPC_FAR* /*puArgErr*/) | |||
| { | |||
| switch (dispIdMember) | |||
| { | |||
| case DISPID_BEFORENAVIGATE2: | |||
| { | |||
| VARIANT* const vurl = pDispParams->rgvarg[5].pvarVal; | |||
| String url; | |||
| if ((vurl->vt & VT_BYREF) != 0) | |||
| url = *vurl->pbstrVal; | |||
| else | |||
| url = vurl->bstrVal; | |||
| *pDispParams->rgvarg->pboolVal | |||
| = owner->pageAboutToLoad (url) ? VARIANT_FALSE | |||
| : VARIANT_TRUE; | |||
| return S_OK; | |||
| } | |||
| default: | |||
| break; | |||
| } | |||
| return E_NOTIMPL; | |||
| } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| WebBrowserComponent* const owner; | |||
| int refCount; | |||
| EventHandler (const EventHandler&); | |||
| const EventHandler& operator= (const EventHandler&); | |||
| }; | |||
| }; | |||
| //============================================================================== | |||
| WebBrowserComponent::WebBrowserComponent() | |||
| : browser (0), | |||
| blankPageShown (false) | |||
| { | |||
| setOpaque (true); | |||
| addAndMakeVisible (browser = new WebBrowserComponentInternal()); | |||
| } | |||
| WebBrowserComponent::~WebBrowserComponent() | |||
| { | |||
| delete browser; | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::goToURL (const String& url, | |||
| const StringArray* headers, | |||
| const MemoryBlock* postData) | |||
| { | |||
| lastURL = url; | |||
| lastHeaders.clear(); | |||
| if (headers != 0) | |||
| lastHeaders = *headers; | |||
| lastPostData.setSize (0); | |||
| if (postData != 0) | |||
| lastPostData = *postData; | |||
| blankPageShown = false; | |||
| browser->goToURL (url, headers, postData); | |||
| } | |||
| void WebBrowserComponent::stop() | |||
| { | |||
| if (browser->browser != 0) | |||
| browser->browser->Stop(); | |||
| } | |||
| void WebBrowserComponent::goBack() | |||
| { | |||
| lastURL = String::empty; | |||
| blankPageShown = false; | |||
| if (browser->browser != 0) | |||
| browser->browser->GoBack(); | |||
| } | |||
| void WebBrowserComponent::goForward() | |||
| { | |||
| lastURL = String::empty; | |||
| if (browser->browser != 0) | |||
| browser->browser->GoForward(); | |||
| } | |||
| //============================================================================== | |||
| void WebBrowserComponent::paint (Graphics& g) | |||
| { | |||
| if (browser->browser == 0) | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void WebBrowserComponent::checkWindowAssociation() | |||
| { | |||
| if (isShowing()) | |||
| { | |||
| if (blankPageShown) | |||
| goBack(); | |||
| if (browser->browser == 0 && getPeer() != 0) | |||
| { | |||
| browser->createBrowser(); | |||
| reloadLastURL(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (browser != 0 && ! blankPageShown) | |||
| { | |||
| // when the component becomes invisible, some stuff like flash | |||
| // carries on playing audio, so we need to force it onto a blank | |||
| // page to avoid this.. | |||
| blankPageShown = true; | |||
| browser->goToURL ("about:blank", 0, 0); | |||
| } | |||
| } | |||
| } | |||
| void WebBrowserComponent::reloadLastURL() | |||
| { | |||
| if (lastURL.isNotEmpty()) | |||
| { | |||
| goToURL (lastURL, &lastHeaders, &lastPostData); | |||
| lastURL = String::empty; | |||
| } | |||
| } | |||
| void WebBrowserComponent::parentHierarchyChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| void WebBrowserComponent::moved() | |||
| { | |||
| } | |||
| void WebBrowserComponent::resized() | |||
| { | |||
| browser->setSize (getWidth(), getHeight()); | |||
| } | |||
| void WebBrowserComponent::visibilityChanged() | |||
| { | |||
| checkWindowAssociation(); | |||
| } | |||
| bool WebBrowserComponent::pageAboutToLoad (const String&) | |||
| { | |||
| return true; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -4157,6 +4157,10 @@ | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\special\juce_SystemTrayIconComponent.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\juce_appframework\gui\components\special\juce_WebBrowserComponent.h" | |||
| > | |||
| </File> | |||
| </Filter> | |||
| <Filter | |||
| Name="windows" | |||
| @@ -6280,6 +6284,10 @@ | |||
| RelativePath="..\platform_specific_code\juce_win32_Threads.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\platform_specific_code\juce_win32_WebBrowserComponent.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\platform_specific_code\juce_win32_Windowing.cpp" | |||
| > | |||
| @@ -9,6 +9,7 @@ Changelist for version 1.46 | |||
| - new class: AudioProcessorGraph: This allows AudioProcessors to be efficiently wired together and run as a graph. I've converted the plugin host demo to now use this instead of its own graph rendering code. | |||
| - new class: AudioProcessorPlayer: This allows an audio i/o device to stream through an AudioProcessor (or an AudioProcessorGraph). | |||
| - new class QuickTimeAudioFormat, which uses QuickTime to implement an AudioFormat that can read .mov files and other formats that QT supports (e.g. mp3, aac, etc) | |||
| - new class: WebBrowserComponent, for embedding a web browser in your app | |||
| - AudioProcessor now has a few more pure virtual methods that you'll need to implement: acceptsMidi(), producesMidi() and getName() | |||
| - moved all the audio plugin hosting classes into the main juce tree | |||
| - Mac: the project now requires at least XCode V2.5 | |||
| @@ -713,6 +713,9 @@ | |||
| #ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/special/juce_SystemTrayIconComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/special/juce_WebBrowserComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ | |||
| #include "juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h" | |||
| #endif | |||
| @@ -0,0 +1,135 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ | |||
| #define __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ | |||
| #include "../juce_Component.h" | |||
| class WebBrowserComponentInternal; | |||
| //============================================================================== | |||
| /** | |||
| A component that displays an embedded web browser. | |||
| The browser itself will be platform-dependent. On the Mac, probably Safari, on | |||
| Windows, probably IE. | |||
| */ | |||
| class WebBrowserComponent : public Component | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a WebBrowserComponent. | |||
| Once it's created and visible, send the browser to a URL using goToURL(). | |||
| */ | |||
| WebBrowserComponent(); | |||
| /** Destructor. */ | |||
| ~WebBrowserComponent(); | |||
| //============================================================================== | |||
| /** Sends the browser to a particular URL. | |||
| @param url the URL to go to. | |||
| @param headers an optional set of parameters to put in the HTTP header. If | |||
| you supply this, it should be a set of string in the form | |||
| "HeaderKey: HeaderValue" | |||
| @param postData an optional block of data that will be attached to the HTTP | |||
| POST request | |||
| */ | |||
| void goToURL (const String& url, | |||
| const StringArray* headers = 0, | |||
| const MemoryBlock* postData = 0); | |||
| /** Stops the current page loading. | |||
| */ | |||
| void stop(); | |||
| /** Sends the browser back one page. | |||
| */ | |||
| void goBack(); | |||
| /** Sends the browser forward one page. | |||
| */ | |||
| void goForward(); | |||
| //============================================================================== | |||
| /** This callback is called when the browser is about to navigate | |||
| to a new location. | |||
| You can override this method to perform some action when the user | |||
| tries to go to a particular URL. To allow the operation to carry on, | |||
| return true, or return false to stop the navigation happening. | |||
| */ | |||
| virtual bool pageAboutToLoad (const String& newURL); | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void paint (Graphics& g); | |||
| /** @internal */ | |||
| void moved(); | |||
| /** @internal */ | |||
| void resized(); | |||
| /** @internal */ | |||
| void parentHierarchyChanged(); | |||
| /** @internal */ | |||
| void visibilityChanged(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| WebBrowserComponentInternal* browser; | |||
| bool blankPageShown; | |||
| String lastURL; | |||
| StringArray lastHeaders; | |||
| MemoryBlock lastPostData; | |||
| #if JUCE_MAC | |||
| void* associatedWindow; | |||
| void updateBrowserPosition(); | |||
| void createBrowser(); | |||
| void deleteBrowser(); | |||
| #endif | |||
| void reloadLastURL(); | |||
| void checkWindowAssociation(); | |||
| WebBrowserComponent (const WebBrowserComponent&); | |||
| const WebBrowserComponent& operator= (const WebBrowserComponent&); | |||
| }; | |||
| #endif // __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ | |||