Explorar el Código

std.requesters cleanups.

Mark Sibly hace 8 años
padre
commit
bf3052d00a

+ 7 - 6
bin/env_windows.txt

@@ -24,15 +24,16 @@ MX2_LD_OPTS_WINDOWS=-static -m32
 MX2_LD_OPTS_WINDOWS_DEBUG=
 MX2_LD_OPTS_WINDOWS_RELEASE=-s -O3 '-Wl,--gc-sections 
 
-'C Compiler options
+'C Compiler options. Note: -D_WIN32_WINNT=0x0601 means headers for Windows 7, ie: Windows 7 is min SDK!
+'
 MX2_CC_OPTS_WINDOWS=-std=gnu99 -m32
 MX2_CC_OPTS_WINDOWS_DEBUG=
-MX2_CC_OPTS_WINDOWS_RELEASE=-O3 -DNDEBUG '-fdata-sections -ffunction-sections
+MX2_CC_OPTS_WINDOWS_RELEASE=-O3 -DNDEBUG -D_WIN32_WINNT=0x0603 '-fdata-sections -ffunction-sections
 
 'C++ Compiler options
-MX2_CPP_OPTS_WINDOWS=-std=c++11 -m32
+MX2_CPP_OPTS_WINDOWS=-std=c++14 -m32
 MX2_CPP_OPTS_WINDOWS_DEBUG=
-MX2_CPP_OPTS_WINDOWS_RELEASE=-O3 -DNDEBUG '-fvtable-gc -fdata-sections -ffunction-sections
+MX2_CPP_OPTS_WINDOWS_RELEASE=-O3 -DNDEBUG -D_WIN32_WINNT=0x0603 '-fvtable-gc -fdata-sections -ffunction-sections
 
 
 '***** EMSCRIPTEN/WASM *****
@@ -54,7 +55,7 @@ MX2_CC_OPTS_EMSCRIPTEN_DEBUG=-O2
 MX2_CC_OPTS_EMSCRIPTEN_RELEASE=-O3
 
 'C++ Compiler options
-MX2_CPP_OPTS_EMSCRIPTEN=-std=c++11 -s USE_SDL=2 -s TOTAL_MEMORY=67108864 -s DISABLE_EXCEPTION_CATCHING=1
+MX2_CPP_OPTS_EMSCRIPTEN=-std=c++14 -s USE_SDL=2 -s TOTAL_MEMORY=67108864 -s DISABLE_EXCEPTION_CATCHING=1
 MX2_CPP_OPTS_EMSCRIPTEN_DEBUG=-O2
 MX2_CPP_OPTS_EMSCRIPTEN_RELEASE=-O3
 
@@ -94,6 +95,6 @@ MX2_CC_OPTS_RASPBIAN_DEBUG=
 MX2_CC_OPTS_RASPBIAN_RELEASE=-O3 -DNDEBUG ' -fdata-sections -ffunction-sections
 
 'C++ Compiler options
-MX2_CPP_OPTS_RASPBIAN=-std=c++11
+MX2_CPP_OPTS_RASPBIAN=-std=c++14
 MX2_CPP_OPTS_RASPBIAN_DEBUG=
 MX2_CPP_OPTS_RASPBIAN_RELEASE=-O3 -DNDEBUG ' -fvtable-gc -fdata-sections -ffunction-sections

BIN
bin/mx2cc_windows.exe


BIN
modules/gles20/angle/bin/libGLESv2.dll


+ 1 - 1
modules/gles20/gles20.monkey2

@@ -485,7 +485,7 @@ Function glGetShaderiv:Void(shader_:GLuint,pname_:GLenum,params_:GLint Ptr)
 Function glGetShaderInfoLog:Void(shader_:GLuint,bufsize_:GLsizei,length_:GLsizei Ptr,infolog_:GLchar Ptr )
 Function glGetShaderPrecisionFormat:Void(shadertype_:GLenum,precisiontype_:GLenum,range_:GLint Ptr,precision_:GLint Ptr)
 Function glGetShaderSource:Void(shader_:GLuint,bufsize_:GLsizei,length_:GLsizei Ptr,source_:CString)
-Function glGetString:GLubyte Ptr(name_:GLenum)
+Function glGetString:CString(name_:GLenum)
 Function glGetTexParameterfv:Void(target_:GLenum,pname_:GLenum,params_:GLfloat Ptr)
 Function glGetTexParameteriv:Void(target_:GLenum,pname_:GLenum,params_:GLint Ptr)
 Function glGetUniformfv:Void(program_:GLuint,location_:GLint,params_:GLfloat Ptr)

+ 6 - 2
modules/jni/jni.monkey2

@@ -64,20 +64,24 @@ Class JNIEnv Extends Void
 	Method CallVoidMethod:Void( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallVoidMethod"
 	
 	Method CallBooleanMethod:Bool( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallBooleanMethod"
+
+	Method CallObjectMethod:Bool( obj:jobject,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallObjectMethod"
 	
 	'static methods...
 	'
 	Method GetStaticMethodID:jmethodID( clazz:jclass,name:CString,sig:CString )
 	
 	Method CallStaticVoidMethod:Void( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticVoidMethod"
+
+	Method CallStaticBooleanMethod:Void( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticBooleanMethod"
 	
-	Method CallStaticBooleanMethod:Bool( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticBooleanMethod"
+	Method CallStaticObjectMethod:Bool( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::CallStaticObjectMethod"
 
 	'ctors...
 	'
 	Method AllocObject:jobject( clazz:jclass )
 		
-	Method NewObject:jobject( clazz:jclass,methodID:jmethodID )
+	Method NewObject:jobject( clazz:jclass,methodID:jmethodID,args:Variant[] ) Extension="bbJNI::NewObject"
 		
 	'refs...
 	'

+ 1 - 1
modules/jni/module.json

@@ -4,5 +4,5 @@
 	"author":"Mark Sibly",
 	"version":"1.0.0",
 	"support":"http://monkey2.monkey-x.com",
-	"depends":["mojo"]
+	"depends":["libc"]
 }

+ 33 - 0
modules/jni/native/jni_glue.cpp

@@ -98,6 +98,17 @@ namespace bbJNI{
 		return r;
 	}
 
+	jobject CallObjectMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args ){
+		
+		jvalue *jargs=makeArgs( env,args );
+		
+		jobject r=env->CallObjectMethodA( obj,methodID,jargs );
+		
+		delete[] jargs;
+		
+		return r;
+	}
+
 	void CallStaticVoidMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
 		
 		jvalue *jargs=makeArgs( env,args );
@@ -118,5 +129,27 @@ namespace bbJNI{
 		return r;
 	}
 
+	jobject CallStaticObjectMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
+		
+		jvalue *jargs=makeArgs( env,args );
+		
+		jobject r=env->CallStaticObjectMethodA( clazz,methodID,jargs );
+		
+		delete[] jargs;
+		
+		return r;
+	}
+	
+	jobject NewObject( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args ){
+
+		jvalue *jargs=makeArgs( env,args );
+		
+		jobject r=env->NewObjectA( clazz,methodID,jargs );
+		
+		delete[] jargs;
+		
+		return r;
+	}
+	
 }
 

+ 10 - 0
modules/jni/native/jni_glue.h

@@ -5,14 +5,24 @@
 
 namespace bbJNI{
 
+
 	void CallVoidMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 	
 	bbBool CallBooleanMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
 
+	jobject CallObjectMethod( JNIEnv *env,jobject obj,jmethodID methodID,bbArray<bbVariant> args );
+
+
 	void CallStaticVoidMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	
 	bbBool CallStaticBooleanMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
+
+	jobject CallStaticObjectMethod( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
 	
+
+	jobject NewObject( JNIEnv *env,jclass clazz,jmethodID methodID,bbArray<bbVariant> args );
+	
+
 	bbString JStringToString( JNIEnv *env,jstring jstr );
 	
 	jstring StringToJString( JNIEnv *env,bbString str );

+ 5 - 2
modules/sdl2/SDL/src/video/SDL_egl.c

@@ -287,8 +287,6 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
 		}
 	}
 	
-	#endif
-	
 	if( angleType ){
 	
 		PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT=
@@ -315,6 +313,11 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
 
 	    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
 	}
+	#else
+	
+    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
+    
+	#endif
     
     if (!_this->egl_data->egl_display) {
         return SDL_SetError("Could not get EGL display");

+ 1 - 1
modules/std/module.json

@@ -4,5 +4,5 @@
 	"author":"Mark Sibly",
 	"version":"1.0.0",
 	"support":"http://monkey2.monkey-x.com",
-	"depends":["libc","miniz","stb-image","stb-image-write","stb-vorbis"]
+	"depends":["libc","jni","sdl2","miniz","stb-image","stb-image-write","stb-vorbis"]
 }

+ 20 - 0
modules/std/requesters/native/Monkey2Requesters.java

@@ -0,0 +1,20 @@
+package com.monkey2.lib;
+
+import android.util.Log;
+import android.content.Intent;
+import android.net.Uri;
+
+public class Monkey2Requesters {
+
+    private static final String TAG = "Monkey2Requesters";
+    
+    static public void openUrl( String url ) {
+    
+		//Log.v( TAG,"openUrl, url="+url );
+    
+        Intent browserIntent=new Intent( Intent.ACTION_VIEW,Uri.parse( url ) );
+        
+		Monkey2Activity.instance().startActivity( browserIntent );
+    }
+    
+}

+ 12 - 0
modules/std/requesters/native/requesters_ios.mm

@@ -0,0 +1,12 @@
+
+#include "requesters_ios.h"
+
+#import <UIKit/UIKit.h>
+
+void bbRequesters::openUrl( bbString url ){
+
+	NSURL *nsurl=[NSURL URLWithString:url.ToNSString()];
+	
+	if( nsurl ) [[UIApplication sharedApplication] openURL:nsurl];
+}
+

+ 47 - 0
modules/std/requesters/native/requesters_linux.cpp

@@ -0,0 +1,47 @@
+
+#include "requesters.h"
+
+#include <limits.h>
+
+bbString bbRequesters::RequestFile( bbString title,bbString exts,bbBool save,bbString path ){
+
+	bbString cmd=BB_T("zenity --title=\"")+title+BB_T("\" --file-selection");
+	
+	if( save ) cmd+=" --save";
+	
+	FILE *f=popen( cmd.c_str(),"r" );
+	if( !f ) return "";
+	
+	char buf[PATH_MAX];
+	int n=fread( buf,1,PATH_MAX,f );
+	pclose( f );
+	
+	if( n<0 || n>PATH_MAX ) return "";
+	
+	while( n && buf[n-1]<=32 ) --n;
+	
+	return bbString::fromCString( buf,n );
+}
+
+bbString bbRequesters::RequestDir( bbString title,bbString dir ){
+
+	bbString cmd=BB_T("zenity --title=\"")+title+BB_T("\" --file-selection --directory");
+
+	FILE *f=popen( cmd.c_str(),"r" );
+	if( !f ) return "";
+	
+	char buf[PATH_MAX];
+	int n=fread( buf,1,PATH_MAX,f );
+	pclose( f );
+	
+	if( n<0 || n>PATH_MAX ) return "";
+	
+	while( n && buf[n-1]<=32 ) --n;
+	
+	return bbString::fromCString( buf,n );
+}
+
+void bbRequesters::OpenUrl( bbString url ){
+
+	system( ( bbString( "xdg-open \"" )+url+"\"" ).c_str() );
+}

+ 244 - 0
modules/std/requesters/native/requesters_macos.mm

@@ -0,0 +1,244 @@
+
+#include "requesters.h"
+
+#import <Cocoa/Cocoa.h>
+
+namespace{
+
+	typedef int (*AlertPanel)( 
+		NSString *title,
+		NSString *msg,
+		NSString *defaultButton,
+		NSString *alternateButton,
+		NSString *otherButton );
+	
+	NSWindow *keyWin;
+	NSOpenGLContext *glContext;
+	
+	void beginPanel(){
+	
+		glContext=[NSOpenGLContext currentContext];
+
+		keyWin=[NSApp keyWindow];
+	}
+	
+	void endPanel(){
+
+		if( glContext ) [glContext makeCurrentContext];
+
+		if( keyWin ) [keyWin makeKeyWindow];
+	}
+	
+	NSString *ConvString( bbString str ){
+		return [NSString stringWithCharacters:(const unichar*)str.data() length:str.length()];
+	}
+	
+	bbString ConvString( NSString *str ){
+		int n=[str length];
+		unichar *buf=new unichar[ n ];
+		[str getCharacters:buf range:NSMakeRange( 0,n )];
+		bbString t=bbString( buf,n );
+		delete[] buf;
+		return t;
+	}
+}
+
+void bbRequesters::Notify( bbString title,bbString text,bbBool serious ){
+
+	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
+	
+	beginPanel();
+	
+	panel( ConvString( title ),ConvString( text ),@"OK",0,0 );
+	
+	endPanel();
+}
+
+bbBool bbRequesters::Confirm( bbString title,bbString text,bbBool serious ){
+
+	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
+	
+	beginPanel();
+	
+	int n=panel( ConvString( title ),ConvString( text ),@"OK",@"Cancel",0 );
+
+	endPanel();
+	
+	switch( n ){
+	case NSAlertDefaultReturn:return 1;
+	}
+	return 0;
+}
+
+int bbRequesters::Proceed( bbString title,bbString text,bbBool serious ){
+
+	AlertPanel panel=(AlertPanel) ( serious ? (void*)NSRunCriticalAlertPanel : (void*)NSRunAlertPanel );
+	
+	beginPanel();
+	
+	int n=panel( ConvString( title ),ConvString( text ),@"Yes",@"No",@"Cancel" );
+	
+	endPanel();
+	
+	switch( n ){
+	case NSAlertDefaultReturn:return 1;
+	case NSAlertAlternateReturn:return 0;
+	}
+	return -1;
+}
+
+bbString bbRequesters::RequestFile( bbString title,bbString filter,bbBool save,bbString path ){
+
+	bbString file,dir;
+	int i=path.findLast( "\\" );
+	if( i!=-1 ){
+		dir=path.slice( 0,i );
+		file=path.slice( 1+1 );
+	}else{
+		file=path;
+	}
+	
+	NSMutableArray *nsfilter=0;
+	bool allowOthers=true;
+
+	if( filter.length() ){
+	
+		nsfilter=[NSMutableArray arrayWithCapacity:10];
+		
+		allowOthers=false;
+		
+		if( filter.find( ":" )!=-1 ){
+
+			int i0=0;
+			while( i0<filter.length() ){
+			
+				int i1=filter.find( ":",i0 );
+				if( i1==-1 ) break;
+				i1+=1;
+				
+				int i2=filter.find( ";",i1 );
+				if( i2==-1 ) i2=filter.length();
+				
+				while( i1<i2 ){
+				
+					int i3=filter.find( ",",i1 );
+					if( i3==-1 ) i3=i2;
+					
+					bbString ext=filter.slice( i1,i3 );
+					if( ext==BB_T("*") ){
+						allowOthers=true;
+					}else{
+						[nsfilter addObject:ConvString( ext )];
+					}
+					i1=i3+1;
+				}
+				i0=i2+1;
+			}
+			
+		}else{
+		
+			int i0=0;
+			while( i0<filter.length() ){
+			
+				int i1=filter.find( ",",i0 );
+				if( i1==-1 ) i1=filter.length();
+				
+				bbString ext=filter.slice( i0,i1 );
+				if( ext==BB_T("*") ){
+					allowOthers=true;
+				}else{
+					[nsfilter addObject:ConvString( ext )];
+				}
+				
+				i0=i1+1;
+			}
+		}
+	}
+
+	if( ![nsfilter count] ){
+		nsfilter=0;
+		allowOthers=true;
+	}
+	
+	NSString *nsdir=0;
+	NSString *nsfile=0;
+	NSString *nstitle=0;
+	NSMutableArray *nsexts=0;
+
+	if( dir.length() ) nsdir=ConvString( dir );
+	if( file.length() ) nsfile=ConvString( file );
+	if( title.length() ) nstitle=ConvString( title );
+
+	beginPanel();
+	
+	bbString str;
+
+	if( save ){
+		NSSavePanel *panel=[NSSavePanel savePanel];
+		
+		if( nstitle ) [panel setTitle:nstitle];
+		
+		if( nsfilter ){
+			[panel setAllowedFileTypes:nsfilter];
+			[panel setAllowsOtherFileTypes:allowOthers];
+		}
+		
+		if( [panel runModalForDirectory:nsdir file:nsfile]==NSFileHandlingPanelOKButton ){
+			str=ConvString( [panel filename] );
+		}
+
+	}else{
+		NSOpenPanel *panel=[NSOpenPanel openPanel];
+
+		if( nstitle ) [panel setTitle:nstitle];
+		
+		if( allowOthers ) nsfilter=0;
+		
+		if( [panel runModalForDirectory:nsdir file:nsfile types:nsfilter]==NSFileHandlingPanelOKButton ){
+			str=ConvString( [panel filename] );
+		}
+	}
+
+	endPanel();
+
+	return str;
+}
+
+bbString bbRequesters::RequestDir( bbString title,bbString dir ){
+
+	NSString *nsdir=0;
+	NSString *nstitle=0;
+	NSOpenPanel *panel;
+	
+	if( dir.length() ) nsdir=ConvString( dir );
+	if( title.length() ) nstitle=ConvString( title );
+
+	panel=[NSOpenPanel openPanel];
+	
+	[panel setCanChooseFiles:NO];
+	[panel setCanChooseDirectories:YES];
+	[panel setCanCreateDirectories:YES];
+	
+	if( nstitle ) [panel setTitle:nstitle];
+
+	beginPanel();
+	
+	bbString str;
+	
+	if( [panel runModalForDirectory:nsdir file:0 types:0]==NSFileHandlingPanelOKButton ){
+	
+		str=ConvString( [panel filename] );
+	}
+
+	endPanel();
+	
+	return str;
+}
+
+void bbRequesters::OpenUrl( bbString url ){
+
+	if( CFURLRef cfurl=CFURLCreateWithBytes( 0,(const UInt8*)url.c_str(),url.length(),kCFStringEncodingASCII,0 ) ){
+		LSOpenCFURLRef( cfurl,0 );
+		CFRelease( cfurl );
+	}
+}

+ 197 - 0
modules/std/requesters/native/requesters_windows.cpp

@@ -0,0 +1,197 @@
+
+#include "requesters.h"
+
+#include <windows.h>
+#include <shlobj.h>
+
+namespace{
+
+	HWND focHwnd;
+
+	void beginPanel(){
+		focHwnd=GetFocus();
+	}
+
+	void endPanel(){
+		SetFocus( focHwnd );
+	}
+
+	int panel( bbString title,bbString text,int flags ){
+		beginPanel();
+		int n=MessageBoxW( GetActiveWindow(),bbWString( text ),bbWString( title ),flags );
+		endPanel();
+		return n;
+	}
+	
+	WCHAR *tmpWString( bbString str ){
+		WCHAR *p=(WCHAR*)malloc( str.length()*2+2 );
+		memcpy( p,str.data(),str.length()*2 );
+		p[str.length()]=0;
+		return p;
+	}
+	
+	int CALLBACK BrowseForFolderCallbackW( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
+		wchar_t szPath[MAX_PATH];
+		switch( uMsg ){
+		case BFFM_INITIALIZED:
+			SendMessageW( hwnd,BFFM_SETSELECTIONW,TRUE,pData );
+			break;
+		case BFFM_SELCHANGED: 
+			if( SHGetPathFromIDListW( (LPITEMIDLIST)lp,szPath ) ){
+				SendMessageW( hwnd,BFFM_SETSTATUSTEXTW,0,(LPARAM)szPath );
+			}
+			break;
+		}
+		return 0;
+	}
+	
+	int CALLBACK BrowseForFolderCallbackA( HWND hwnd,UINT uMsg,LPARAM lp,LPARAM pData ){
+		char szPath[MAX_PATH];
+		switch( uMsg ){
+		case BFFM_INITIALIZED:
+			SendMessageA( hwnd,BFFM_SETSELECTIONA,TRUE,pData );
+			break;
+		case BFFM_SELCHANGED: 
+			if( SHGetPathFromIDListA( (LPITEMIDLIST)lp,szPath ) ){
+				SendMessageA( hwnd,BFFM_SETSTATUSTEXTA,0,(LPARAM)szPath );
+			}
+			break;
+		}
+		return 0;
+	}
+}
+	
+void bbRequesters::Notify( bbString title,bbString text,bbBool serious ){
+	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_OK|MB_APPLMODAL|MB_TOPMOST;
+	panel( title,text,flags );
+}
+
+bbBool bbRequesters::Confirm( bbString title,bbString text,bbBool serious ){
+	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_OKCANCEL|MB_APPLMODAL|MB_TOPMOST;
+	int n=panel( title,text,flags );
+	if( n==IDOK ) return 1;
+	return 0;
+}
+
+int bbRequesters::Proceed( bbString title,bbString text,bbBool serious ){
+	int flags=(serious ? MB_ICONWARNING : MB_ICONINFORMATION)|MB_YESNOCANCEL|MB_APPLMODAL|MB_TOPMOST;
+	int n=panel( title,text,flags );
+	if( n==IDYES ) return 1;
+	if( n==IDNO ) return 0;
+	return -1;
+}
+
+bbString bbRequesters::RequestFile( bbString title,bbString exts,bbBool save,bbString path ){
+
+	bbString file,dir;
+	path=path.replace( "/","\\" );
+		
+	int i=path.findLast( "\\" );
+	if( i!=-1 ){
+		dir=path.slice( 0,i );
+		file=path.slice( i+1 );
+	}else{
+		file=path;
+	}
+
+	if( file.length()>MAX_PATH ) return "";
+
+	if( exts.length() ){
+		if( exts.find( ":" )==-1 ){
+			exts=bbString( "Files\0*.",8 )+exts;
+		}else{
+			exts=exts.replace( ":",bbString( "\0*.",3 ) );
+		}
+		exts=exts.replace( ";",bbString( "\0",1 ) );
+		exts=exts.replace( ",",";*." )+bbString( "\0",1 );
+	}
+
+	WCHAR buf[MAX_PATH+1];
+	memcpy( buf,file.data(),file.length()*2 );
+	buf[file.length()]=0;
+
+	OPENFILENAMEW of={sizeof(of)};
+
+	of.hwndOwner=GetActiveWindow();
+	of.lpstrTitle=tmpWString( title );
+	of.lpstrFilter=tmpWString( exts );
+	of.lpstrFile=buf;
+	of.lpstrInitialDir=dir.length() ? tmpWString( dir ) : 0;
+	of.nMaxFile=MAX_PATH;
+	of.Flags=OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
+	
+	bbString str;
+	
+	beginPanel();
+	
+	if( save ){
+		of.lpstrDefExt=L"";
+		of.Flags|=OFN_OVERWRITEPROMPT;
+		if( GetSaveFileNameW( &of ) ){
+			str=bbString( buf );
+		}
+	}else{
+		of.Flags|=OFN_FILEMUSTEXIST;
+		if( GetOpenFileNameW( &of ) ){
+			str=bbString( buf );
+		}
+	}
+	
+	endPanel();
+	
+	free( (void*)of.lpstrTitle );
+	free( (void*)of.lpstrFilter );
+	free( (void*)of.lpstrInitialDir );
+	
+	str=str.replace( "\\","/" );
+	
+	return str;
+}
+
+bbString bbRequesters::RequestDir( bbString title,bbString dir ){
+
+	CoInitialize( 0 );
+	
+	dir=dir.replace( "/","\\" );
+
+	LPMALLOC shm;
+	BROWSEINFOW bi={0};
+	
+	WCHAR buf[MAX_PATH],*p;
+	GetFullPathNameW( bbWString( dir ),MAX_PATH,buf,&p );
+	
+	bi.hwndOwner=GetActiveWindow();
+	bi.lpszTitle=tmpWString( title );
+	bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE;
+	bi.lpfn=BrowseForFolderCallbackW;
+	bi.lParam=(LPARAM)buf;
+	
+	beginPanel();
+
+	bbString str;
+	
+	if( ITEMIDLIST *idlist=SHBrowseForFolderW( &bi ) ){
+	
+		SHGetPathFromIDListW( idlist,buf );
+		str=bbString( buf );
+		
+		//SHFree( idlist );	//?!?
+		
+		str=str.replace( "\\","/" );
+		if( !str.endsWith( "/" ) ) str+="/";
+	}
+	
+	endPanel();
+	
+	free( (void*)bi.lpszTitle );
+
+	return str;
+}
+
+void bbRequesters::OpenUrl( bbString url ){
+
+	CoInitializeEx( NULL,COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE );
+	
+	ShellExecute( HWND_DESKTOP,0,url.c_str(),0,0,SW_SHOWNORMAL );
+//	ShellExecute( HWND_DESKTOP,"open",url.c_str(),0,0,SW_SHOWNORMAL );
+}