Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

DialogManager abstraction for FireBreath

View DialogManager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#ifndef DialogManager_h__
#define DialogManager_h__
 
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include "BrowserHost.h"
 
typedef boost::function<void (const std::string&)> PathCallback;
 
namespace FB { class PluginWindow; }
 
class DialogManager
{
public:
static DialogManager* get();
virtual void OpenFolderDialog(const FB::BrowserHostPtr& host, FB::PluginWindow* win, const PathCallback& cb) = 0;
 
protected:
DialogManager() {}
virtual ~DialogManager() {}
};
 
#endif // DialogManager_h__
View DialogManager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#ifndef DialogManagerMac_h__
#define DialogManagerMac_h__
 
#include <boost/noncopyable.hpp>
#include <string>
 
#include "DialogManager.h"
 
class DialogManagerMac : public DialogManager
{
public:
void OpenFolderDialog(const FB::BrowserHostPtr& host, FB::PluginWindow* win, const PathCallback& cb);
void _showFolderDialog(FB::PluginWindow* win, const PathCallback& cb);
 
protected:
DialogManagerMac() {};
~DialogManagerMac() {};
friend class DialogManager;
};
#endif // DialogManagerMac_h__
View DialogManager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 
#include <string>
#include <boost/thread.hpp>
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include "logging.h"
 
#include "DialogManagerMac.h"
#include "BrowserHost.h"
 
DialogManager* DialogManager::get()
{
static DialogManagerMac inst;
return &inst;
}
 
 
void DialogManagerMac::OpenFolderDialog(const FB::BrowserHostPtr& host, FB::PluginWindow* win, const PathCallback& cb)
{
host->ScheduleOnMainThread(boost::shared_ptr<DialogManagerMac>(), boost::bind(&DialogManagerMac::_showFolderDialog, this, win, cb));
}
 
void DialogManagerMac::_showFolderDialog(FB::PluginWindow* win, const PathCallback& cb)
{
FBLOG_INFO("DialogManagerMac", "Showing folder dialog");
std::string out;
int result;
NSAutoreleasePool* pool = [NSAutoreleasePool new];
NSOpenPanel *oPanel = [NSOpenPanel openPanel];
[oPanel setAllowsMultipleSelection:NO];
[oPanel setCanChooseFiles:NO];
[oPanel setCanChooseDirectories:YES];
result = [oPanel runModalForDirectory:nil
file:nil types:nil];
if (result == NSOKButton) {
NSArray *filesToOpen = [oPanel filenames];
NSString *aFile = [filesToOpen objectAtIndex:0];
out = [aFile cStringUsingEncoding:[NSString defaultCStringEncoding]];
FBLOG_INFO("DialogManagerMac", "Folder selected: " << out);
}
[pool release];
cb(out);
}
View DialogManager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
 
#include "win_common.h"
#include <commdlg.h>
#include <string>
#include <boost/thread.hpp>
#include "utf8_tools.h"
#include "Win/PluginWindowlessWin.h"
#include "Win/PluginWindowWin.h"
 
#include "DialogManagerWin.h"
#include <shlobj.h>
#include "precompiled_headers.h" // Anything before this is PCH on windows
 
DialogManager* DialogManager::get()
{
static DialogManagerWin inst;
return &inst;
}
 
void DialogManagerWin::OpenFolderDialog(const FB::BrowserHostPtr& host, FB::PluginWindow* win, const PathCallback& cb) {
FB::PluginWindowWin* wndWin = dynamic_cast<FB::PluginWindowWin*>(win);
FB::PluginWindowlessWin* wndlessWin = dynamic_cast<FB::PluginWindowlessWin*>(win);
 
HWND browserWindow = wndWin ? wndWin->getBrowserHWND() : wndlessWin->getHWND();
boost::thread dlgThread(&DialogManagerWin::_showFolderDialog, this, browserWindow, cb);
}
 
void DialogManagerWin::_showFolderDialog(HWND wnd, const PathCallback& cb) {
BROWSEINFO bi = { 0 };
bi.lpszTitle = _T("Select a folder to import");
bi.hwndOwner = wnd;
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
std::wstring out;
// get the name of the folder
TCHAR path[MAX_PATH];
if ( SHGetPathFromIDList ( pidl, path ) )
{
out = path;
}
 
// free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
{
imalloc->Free ( pidl );
imalloc->Release ( );
}
cb(FB::wstring_to_utf8(path));
} else {
cb("");
}
}
void DialogManagerWin::_showFileDialog(HWND wnd, const std::string& path, const std::string& filter, const PathCallback& cb)
{
wchar_t Filestring[256];
std::string out;
 
std::wstring wFilter(FB::utf8_to_wstring(filter));
std::wstring wPath(FB::utf8_to_wstring(filter));
 
OPENFILENAME opf;
opf.hwndOwner = wnd;
opf.lpstrFilter = wFilter.c_str();
opf.lpstrCustomFilter = 0;
opf.nMaxCustFilter = 0L;
opf.nFilterIndex = 1L;
opf.lpstrFile = Filestring;
opf.lpstrFile[0] = '\0';
opf.nMaxFile = 256;
opf.lpstrFileTitle = 0;
opf.nMaxFileTitle=50;
opf.lpstrInitialDir = wPath.c_str();
opf.lpstrTitle = L"Choose directory to import";
opf.nFileOffset = 0;
opf.nFileExtension = 0;
opf.lpstrDefExt = L"*.*";
opf.lpfnHook = NULL;
opf.lCustData = 0;
opf.Flags = (OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT) & ~OFN_ALLOWMULTISELECT;
opf.lStructSize = sizeof(OPENFILENAME);
 
if(GetOpenFileName(&opf))
{
out = FB::wstring_to_utf8(std::wstring(opf.lpstrFile));
}
 
cb(out);
}
View DialogManager.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#ifndef DialogManagerWin_h__
#define DialogManagerWin_h__
 
#include <boost/noncopyable.hpp>
#include <string>
 
#include "DialogManager.h"
 
class DialogManagerWin : public DialogManager
{
public:
void OpenFolderDialog(const FB::BrowserHostPtr& host, FB::PluginWindow* win, const PathCallback& cb);
 
protected:
DialogManagerWin() {};
~DialogManagerWin() {};
void _showFileDialog(HWND wnd, const std::string& path, const std::string& filter, const PathCallback& cb);
void _showFolderDialog(HWND wnd, const PathCallback& cb);
friend class DialogManager;
};
#endif // DialogManagerWin_h__

Do your OSX dialogs work well? I'm doing something similar (fork a thread that shows a NSOpenPanel), but it crashes sometimes. Where the crash occurs seems inconsistent as well, and it crashes more often on some machines than others (maybe on 10.7? - not so much on mine).

Owner

These original ones did have that same crash, but I found a solution; I just barely posted it. Basically the trick, though, is instead of creating a new thread on OS X you use m_host->ScheduleOnMainThread . See the updated gist above for an example! These are working AFAIK.

Owner

Note that it has been suggested that a modal dialog should work fine on the main thread as long as it is started using ScheduleOnMainThread (and thus occurs on the main thread but not as part of one of the NPAPI methods). I haven't actually tried that, but the theory sounds promising.

Faham commented

Hi can you give an example how I should use your code? I'm trying to use it by the following code:

void LocalExecuteAPI::onReturn(const std::string& path) {
}

FB::variant LocalExecuteAPI::selectBracFile(const FB::variant& msg) {
DialogManager* dlg_mgr = DialogManager::get();
boost::shared_ptr loc_exe = m_plugin.lock();
FB::PluginWindow* wh = loc_exe->GetWindow();
dlg_mgr->OpenFolderDialog(m_host, wh, &LocalExecuteAPI::onReturn);
}

but it shows this error:

...src dir\3rdParty\boost\boost/function/function_template.hpp(225): error C2064: term does not evaluate to a function taking 1 arguments
class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.