diff --git a/src/arch/ArchHooks/ArchHooks.h b/src/arch/ArchHooks/ArchHooks.h index 847149d7e6..b7e534c668 100644 --- a/src/arch/ArchHooks/ArchHooks.h +++ b/src/arch/ArchHooks/ArchHooks.h @@ -32,11 +32,9 @@ public: */ virtual RString GetMachineId() const { return RString(); } - /* - * If this is a second instance, return true. Optionally, give focus to the existing - * window. - */ - virtual bool CheckForMultipleInstances() { return false; } + /* If this is a second instance, return true. + * Optionally, give focus to the existing window. */ + virtual bool CheckForMultipleInstances(int argc, char* argv[]) { return false; } virtual void SetTime( tm newtime ) { } diff --git a/src/arch/ArchHooks/ArchHooks_Win32.cpp b/src/arch/ArchHooks/ArchHooks_Win32.cpp index 41d4a316fe..a036ef764d 100644 --- a/src/arch/ArchHooks/ArchHooks_Win32.cpp +++ b/src/arch/ArchHooks/ArchHooks_Win32.cpp @@ -92,7 +92,7 @@ RString ArchHooks_Win32::GetMachineId() const return RString(); } -bool ArchHooks_Win32::CheckForMultipleInstances() +bool ArchHooks_Win32::CheckForMultipleInstances(int argc, char* argv[]) { if( !g_bIsMultipleInstance ) return false; @@ -117,6 +117,21 @@ bool ArchHooks_Win32::CheckForMultipleInstances() SetForegroundWindow( data.hResult ); else SetForegroundWindow( hWnd ); + + // Send the command line to the existing window. + vector vsArgs; + for( int i=0; i g_sIgnoredDialogs( "IgnoredDialogs", "" ); #endif +#include "Selector_Dialog.h" +DialogDriver *MakeDialogDriver() +{ + RString sDrivers = "win32,cocoa,null"; + vector asDriversToTry; + split( sDrivers, ",", asDriversToTry, true ); + + ASSERT( asDriversToTry.size() != 0 ); + + RString sDriver; + DialogDriver *pRet = NULL; + + for( unsigned i = 0; pRet == NULL && i < asDriversToTry.size(); ++i ) + { + sDriver = asDriversToTry[i]; + +#ifdef USE_DIALOG_DRIVER_COCOA + if( !asDriversToTry[i].CompareNoCase("Cocoa") ) pRet = new DialogDriver_Cocoa; +#endif +#ifdef USE_DIALOG_DRIVER_WIN32 + if( !asDriversToTry[i].CompareNoCase("Win32") ) pRet = new DialogDriver_Win32; +#endif +#ifdef USE_DIALOG_DRIVER_NULL + if( !asDriversToTry[i].CompareNoCase("Null") ) pRet = new DialogDriver_Null; +#endif + + if( pRet == NULL ) + { + continue; + } + + RString sError = pRet->Init(); + if( sError != "" ) + { + if( LOG ) + LOG->Info( "Couldn't load driver %s: %s", asDriversToTry[i].c_str(), sError.c_str() ); + SAFE_DELETE( pRet ); + } + } + + return pRet; +} + static DialogDriver *g_pImpl = NULL; static DialogDriver_Null g_NullDriver; -static bool g_bWindowed = true; // Start out true so that we'll show errors before DISPLAY is init'd. +static bool g_bWindowed = true; // Start out true so that we'll show errors before DISPLAY is init'd. static bool DialogsEnabled() { @@ -28,7 +72,7 @@ void Dialog::Init() g_pImpl = DialogDriver::Create(); - /* DialogDriver_Null should have worked, at least. */ + // DialogDriver_Null should have worked, at least. ASSERT( g_pImpl != NULL ); } @@ -52,7 +96,7 @@ static bool MessageIsIgnored( RString sID ) void Dialog::IgnoreMessage( RString sID ) { - /* We can't ignore messages before PREFSMAN is around. */ + // We can't ignore messages before PREFSMAN is around. #if !defined(SMPACKAGE) if( PREFSMAN == NULL ) { @@ -118,6 +162,30 @@ void Dialog::OK( RString sMessage, RString sID ) RageThread::SetIsShowingDialog( false ); } +Dialog::Result Dialog::OKCancel( RString sMessage, RString sID ) +{ + Dialog::Init(); + + if( LOG ) + LOG->Trace( "Dialog: \"%s\" [%s]", sMessage.c_str(), sID.c_str() ); + + if( sID != "" && MessageIsIgnored(sID) ) + return g_NullDriver.OKCancel( sMessage, sID ); + + RageThread::SetIsShowingDialog( true ); + + // only show Dialog if windowed + Dialog::Result ret; + if( DialogsEnabled() ) + ret = g_pImpl->OKCancel( sMessage, sID ); // call derived version + else + ret = g_NullDriver.OKCancel( sMessage, sID ); + + RageThread::SetIsShowingDialog( false ); + + return ret; +} + Dialog::Result Dialog::AbortRetryIgnore( RString sMessage, RString sID ) { Dialog::Init(); diff --git a/src/arch/Dialog/Dialog.h b/src/arch/Dialog/Dialog.h index 92fbd4ca22..b5979ffcda 100644 --- a/src/arch/Dialog/Dialog.h +++ b/src/arch/Dialog/Dialog.h @@ -13,6 +13,7 @@ namespace Dialog enum Result { abort, retry, ignore }; void Error( RString sError, RString sID = "" ); void OK( RString sMessage, RString sID = "" ); + Result OKCancel( RString sMessage, RString sID = "" ); Result AbortRetryIgnore( RString sMessage, RString sID = "" ); Result AbortRetry( RString sMessage, RString sID = "" ); diff --git a/src/arch/Dialog/DialogDriver.cpp b/src/arch/Dialog/DialogDriver.cpp index 83cbd7963c..8f0aaeb398 100644 --- a/src/arch/Dialog/DialogDriver.cpp +++ b/src/arch/Dialog/DialogDriver.cpp @@ -8,7 +8,7 @@ RegisterDialogDriver::RegisterDialogDriver( const istring &sName, CreateDialogDr { if( g_pRegistrees == NULL ) g_pRegistrees = new map; - + ASSERT( g_pRegistrees->find(sName) == g_pRegistrees->end() ); (*g_pRegistrees)[sName] = pfn; } @@ -20,20 +20,20 @@ DialogDriver *DialogDriver::Create() RString sDrivers = "win32,macosx,null"; vector asDriversToTry; split( sDrivers, ",", asDriversToTry, true ); - + ASSERT( asDriversToTry.size() != 0 ); - + FOREACH_CONST( RString, asDriversToTry, Driver ) { map::const_iterator iter = RegisterDialogDriver::g_pRegistrees->find( istring(*Driver) ); - + if( iter == RegisterDialogDriver::g_pRegistrees->end() ) continue; - + DialogDriver *pRet = (iter->second)(); DEBUG_ASSERT( pRet ); const RString sError = pRet->Init(); - + if( sError.empty() ) return pRet; if( LOG ) diff --git a/src/arch/Dialog/DialogDriver.h b/src/arch/Dialog/DialogDriver.h index 727657e4ac..44f107887a 100644 --- a/src/arch/Dialog/DialogDriver.h +++ b/src/arch/Dialog/DialogDriver.h @@ -11,6 +11,7 @@ public: virtual void Error( RString sMessage, RString sID ) { printf("Error: %s\n", sMessage.c_str()); } virtual void OK( RString sMessage, RString sID ) {} + virtual Dialog::Result OKCancel( RString sMessage, RString sID ) { return Dialog::ok; } virtual Dialog::Result AbortRetryIgnore( RString sMessage, RString sID ) { return Dialog::ignore; } virtual Dialog::Result AbortRetry( RString sMessage, RString sID ) { return Dialog::abort; } @@ -18,6 +19,7 @@ public: virtual ~DialogDriver() { } }; class DialogDriver_Null : public DialogDriver { }; +#define USE_DIALOG_DRIVER_NULL typedef DialogDriver *(*CreateDialogDriverFn)(); struct RegisterDialogDriver @@ -28,7 +30,6 @@ struct RegisterDialogDriver #define REGISTER_DIALOG_DRIVER_CLASS( name ) \ static RegisterDialogDriver register_##name( #name, CreateClass ) - #endif /* diff --git a/src/arch/Dialog/DialogDriver_MacOSX.h b/src/arch/Dialog/DialogDriver_MacOSX.h index 0c61b0d820..ca045802fd 100644 --- a/src/arch/Dialog/DialogDriver_MacOSX.h +++ b/src/arch/Dialog/DialogDriver_MacOSX.h @@ -11,6 +11,7 @@ public: Dialog::Result AbortRetryIgnore( RString sMessage, RString sID ); Dialog::Result AbortRetry( RString sMessage, RString sID ); }; +#define USE_DIALOG_DRIVER_COCOA #endif diff --git a/src/arch/Dialog/DialogDriver_Win32.cpp b/src/arch/Dialog/DialogDriver_Win32.cpp index ee419f129c..62333fd2a3 100644 --- a/src/arch/Dialog/DialogDriver_Win32.cpp +++ b/src/arch/Dialog/DialogDriver_Win32.cpp @@ -57,7 +57,7 @@ static BOOL CALLBACK OKWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara SetWindowText( GetDlgItem(hWnd, IDC_MESSAGE), sMessage ); // Focus is on any of the controls in the dialog by default. - // I'm not sure why. Set focus to the button manually. -Chris + // I'm not sure why. Set focus to the button manually. -Chris SetFocus( GetDlgItem(hWnd, IDOK) ); } break; @@ -72,7 +72,7 @@ static BOOL CALLBACK OKWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara { case IDOK: g_bHush = !!IsDlgButtonChecked( hWnd, IDC_HUSH ); - /* fall through */ + // fall through case IDCANCEL: EndDialog( hWnd, 0 ); break; @@ -112,6 +112,30 @@ void DialogDriver_Win32::OK( RString sMessage, RString sID ) Dialog::IgnoreMessage( sID ); } +Dialog::Result DialogDriver_Win32::OKCancel( RString sMessage, RString sID ) +{ + g_bAllowHush = sID != ""; + g_sMessage = sMessage; + AppInstance handle; + +#if !defined(SMPACKAGE) + //DialogBox( handle.Get(), MAKEINTRESOURCE(IDD_OK), ::GetHwnd(), OKWndProc ); + int result = ::MessageBox( NULL, sMessage, GetWindowTitle(), MB_OKCANCEL ); +#else + int result = ::AfxMessageBox( ConvertUTF8ToACP(sMessage).c_str(), MB_OKCANCEL, 0 ); +#endif + if( g_bAllowHush && g_bHush ) + Dialog::IgnoreMessage( sID ); + + switch( result ) + { + case IDOK: + return Dialog::ok; + default: + return Dialog::cancel; + } +} + #if !defined(SMPACKAGE) static RString g_sErrorString; @@ -159,7 +183,7 @@ static BOOL CALLBACK ErrorWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP break; case IDC_BUTTON_RESTART: Win32RestartProgram(); - /* not reached */ + // not reached ASSERT( 0 ); EndDialog( hWnd, 0 ); break; diff --git a/src/arch/Dialog/DialogDriver_Win32.h b/src/arch/Dialog/DialogDriver_Win32.h index 28dc05504a..15654e646d 100644 --- a/src/arch/Dialog/DialogDriver_Win32.h +++ b/src/arch/Dialog/DialogDriver_Win32.h @@ -8,6 +8,7 @@ class DialogDriver_Win32: public DialogDriver public: void Error( RString sMessage, RString sID ); void OK( RString sMessage, RString sID ); + Dialog::Result OKCancel( RString sMessage, RString sID ); Dialog::Result AbortRetryIgnore( RString sMessage, RString sID ); Dialog::Result AbortRetry( RString sMessage, RString sID ); }; diff --git a/src/arch/LoadingWindow/LoadingWindow.cpp b/src/arch/LoadingWindow/LoadingWindow.cpp index 61de2cd1e3..5883d64942 100644 --- a/src/arch/LoadingWindow/LoadingWindow.cpp +++ b/src/arch/LoadingWindow/LoadingWindow.cpp @@ -11,7 +11,7 @@ LoadingWindow *LoadingWindow::Create() #if defined(UNIX) && !defined(HAVE_GTK) return new LoadingWindow_Null; #endif - /* Don't load NULL by default. */ + // Don't load NULL by default. const RString drivers = "xbox,win32,macosx,gtk"; vector DriversToTry; split( drivers, ",", DriversToTry, true ); @@ -39,7 +39,6 @@ LoadingWindow *LoadingWindow::Create() #endif if( !DriversToTry[i].CompareNoCase("Null") ) ret = new LoadingWindow_Null; - if( ret == NULL ) continue; @@ -50,10 +49,10 @@ LoadingWindow *LoadingWindow::Create() SAFE_DELETE( ret ); } } - + if( ret ) LOG->Info( "Loading window: %s", Driver.c_str() ); - + return ret; } diff --git a/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm b/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm index a62a67be8e..c34d8d4d85 100644 --- a/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm +++ b/src/arch/LowLevelWindow/LowLevelWindow_MacOSX.mm @@ -7,7 +7,7 @@ #import "arch/ArchHooks/ArchHooks.h" #import -#import +#import #import #import diff --git a/src/archutils/Darwin/SMMain.mm b/src/archutils/Darwin/SMMain.mm index 975c6b1587..6fd9df2f8a 100644 --- a/src/archutils/Darwin/SMMain.mm +++ b/src/archutils/Darwin/SMMain.mm @@ -1,6 +1,8 @@ #include "global.h" #include "RageUtil.h" #include "RageThreads.h" +#include "RageLog.h" +#include "CommandLineActions.h" #import #include "ProductInfo.h" @@ -69,11 +71,34 @@ exit( SM_main(m_iArgc, m_pArgv) ); } +/* From here: + * http://www.cocoadev.com/index.pl?HowToRegisterURLHandler */ +- (void) getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + const char *url = [[[event paramDescriptorForKeyword:keyDirectObject] stringValue] UTF8String]; + + LOG->Info("Parsing URL: %s", url); + + // I'm not sure this handles everything it needs to. - Colby + CommandLineActions::CommandLineArgs args; + args.argv.push_back(url); + + CommandLineActions::ToProcess.push_back(args); +} + // Called when the internal event loop has just started running. - (void) applicationDidFinishLaunching:(NSNotification *)note { m_bApplicationLaunched = YES; [NSThread detachNewThreadSelector:@selector(startGame:) toTarget:self withObject:nil]; + + // Register ourselves as a URL handler. + [ + [NSAppleEventManager sharedAppleEventManager] setEventHandler:self + andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL + ]; } - (BOOL) application:(NSApplication *)app openFile:(NSString *)file diff --git a/src/archutils/Win32/DialogUtil.cpp b/src/archutils/Win32/DialogUtil.cpp index c534da05de..5971d8a23d 100644 --- a/src/archutils/Win32/DialogUtil.cpp +++ b/src/archutils/Win32/DialogUtil.cpp @@ -81,7 +81,6 @@ void DialogUtil::LocalizeDialogAndContents( HWND hdlg ) } } - /* * (c) 2002-2004 Chris Danford * All rights reserved. diff --git a/src/archutils/Win32/GraphicsWindow.cpp b/src/archutils/Win32/GraphicsWindow.cpp index 0de1571f0b..bc7c906a7b 100644 --- a/src/archutils/Win32/GraphicsWindow.cpp +++ b/src/archutils/Win32/GraphicsWindow.cpp @@ -11,6 +11,7 @@ #include "archutils/Win32/ErrorStrings.h" #include "archutils/Win32/WindowIcon.h" #include "archutils/Win32/GetFileInformation.h" +#include "CommandLineActions.h" #include @@ -25,7 +26,7 @@ static HICON g_hIcon = NULL; static bool m_bWideWindowClass; static bool g_bD3D = false; -/* If we're fullscreen, this is the mode we set. */ +// If we're fullscreen, this is the mode we set. static DEVMODE g_FullScreenDevMode; static bool g_bRecreatingVideoMode = false; @@ -58,108 +59,117 @@ static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wPar switch( msg ) { - case WM_ACTIVATE: - { - const bool bInactive = (LOWORD(wParam) == WA_INACTIVE); - const bool bMinimized = (HIWORD(wParam) != 0); - const bool bHadFocus = g_bHasFocus; - g_bHasFocus = !bInactive && !bMinimized; - LOG->Trace( "WM_ACTIVATE (%i, %i): %s", bInactive, bMinimized, g_bHasFocus? "has focus":"doesn't have focus" ); - if( !g_bHasFocus ) + case WM_ACTIVATE: { - RString sName = GetNewWindow(); - static set sLostFocusTo; - sLostFocusTo.insert( sName ); - RString sStr; - for( set::const_iterator it = sLostFocusTo.begin(); it != sLostFocusTo.end(); ++it ) - sStr += (sStr.size()?", ":"") + *it; - - LOG->MapLog( "LOST_FOCUS", "Lost focus to: %s", sStr.c_str() ); - } - - if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode ) - { - /* In OpenGL (not D3D), it's our job to unset and reset the full-screen video mode - * when we focus changes, and to hide and show the window. Hiding is done in WM_KILLFOCUS, - * because that's where most other apps seem to do it. */ - if( g_bHasFocus && !bHadFocus ) + const bool bInactive = (LOWORD(wParam) == WA_INACTIVE); + const bool bMinimized = (HIWORD(wParam) != 0); + const bool bHadFocus = g_bHasFocus; + g_bHasFocus = !bInactive && !bMinimized; + LOG->Trace( "WM_ACTIVATE (%i, %i): %s", bInactive, bMinimized, g_bHasFocus? "has focus":"doesn't have focus" ); + if( !g_bHasFocus ) { - ChangeDisplaySettings( &g_FullScreenDevMode, CDS_FULLSCREEN ); - ShowWindow( g_hWndMain, SW_SHOWNORMAL ); + RString sName = GetNewWindow(); + static set sLostFocusTo; + sLostFocusTo.insert( sName ); + RString sStr; + for( set::const_iterator it = sLostFocusTo.begin(); it != sLostFocusTo.end(); ++it ) + sStr += (sStr.size()?", ":"") + *it; + + LOG->MapLog( "LOST_FOCUS", "Lost focus to: %s", sStr.c_str() ); } - else if( !g_bHasFocus && bHadFocus ) + + if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode ) { - ChangeDisplaySettings( NULL, 0 ); + /* In OpenGL (not D3D), it's our job to unset and reset the full-screen video mode + * when we focus changes, and to hide and show the window. Hiding is done in WM_KILLFOCUS, + * because that's where most other apps seem to do it. */ + if( g_bHasFocus && !bHadFocus ) + { + ChangeDisplaySettings( &g_FullScreenDevMode, CDS_FULLSCREEN ); + ShowWindow( g_hWndMain, SW_SHOWNORMAL ); + } + else if( !g_bHasFocus && bHadFocus ) + { + ChangeDisplaySettings( NULL, 0 ); + } } - } - return 0; - } - case WM_KILLFOCUS: - if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode ) - ShowWindow( g_hWndMain, SW_SHOWMINNOACTIVE ); - break; - - /* Is there any reason we should care what size the user resizes the window to? */ -// case WM_GETMINMAXINFO: - - case WM_SETCURSOR: - if( !g_CurrentParams.windowed ) - { - SetCursor( NULL ); - return 1; - } - break; - - case WM_SYSCOMMAND: - switch( wParam&0xFFF0 ) - { - case SC_MONITORPOWER: - case SC_SCREENSAVE: return 0; } - break; - - case WM_PAINT: - { - PAINTSTRUCT ps; - BeginPaint( hWnd, &ps ); - EndPaint( hWnd, &ps ); - break; - } - - case WM_KEYDOWN: - case WM_KEYUP: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - /* We handle all input ourself, via DirectInput. */ - return 0; - - case WM_CLOSE: - LOG->Trace("WM_CLOSE: shutting down"); - ArchHooks::SetUserQuit(); - return 0; - - case WM_WINDOWPOSCHANGED: - { - /* If we're fullscreen and don't have focus, our window is hidden, so GetClientRect - * isn't meaningful. */ - if( !g_CurrentParams.windowed && !g_bHasFocus ) + case WM_KILLFOCUS: + if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode ) + ShowWindow( g_hWndMain, SW_SHOWMINNOACTIVE ); break; - RECT rect; - GetClientRect( hWnd, &rect ); + /* Is there any reason we should care what size the user resizes the window to? */ + // case WM_GETMINMAXINFO: - int iWidth = rect.right - rect.left; - int iHeight = rect.bottom - rect.top; - if( g_CurrentParams.width != iWidth || g_CurrentParams.height != iHeight ) + case WM_SETCURSOR: + if( !g_CurrentParams.windowed ) + { + SetCursor( NULL ); + return 1; + } + break; + + case WM_SYSCOMMAND: + switch( wParam&0xFFF0 ) + { + case SC_MONITORPOWER: + case SC_SCREENSAVE: + return 0; + } + break; + + case WM_PAINT: { - g_CurrentParams.width = iWidth; - g_CurrentParams.height = iHeight; - g_bResolutionChanged = true; + PAINTSTRUCT ps; + BeginPaint( hWnd, &ps ); + EndPaint( hWnd, &ps ); + break; + } + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + /* We handle all input ourself, via DirectInput. */ + return 0; + + case WM_CLOSE: + LOG->Trace("WM_CLOSE: shutting down"); + ArchHooks::SetUserQuit(); + return 0; + + case WM_WINDOWPOSCHANGED: + { + /* If we're fullscreen and don't have focus, our window is hidden, so GetClientRect + * isn't meaningful. */ + if( !g_CurrentParams.windowed && !g_bHasFocus ) + break; + + RECT rect; + GetClientRect( hWnd, &rect ); + + int iWidth = rect.right - rect.left; + int iHeight = rect.bottom - rect.top; + if( g_CurrentParams.width != iWidth || g_CurrentParams.height != iHeight ) + { + g_CurrentParams.width = iWidth; + g_CurrentParams.height = iHeight; + g_bResolutionChanged = true; + } + break; + } + case WM_COPYDATA: + { + PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT) lParam; + RString sCommandLine( (char*)pMyCDS->lpData, pMyCDS->cbData ); + CommandLineActions::CommandLineArgs args; + split( sCommandLine, "|", args.argv, false ); + CommandLineActions::ToProcess.push_back( args ); + break; } - break; - } } CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );