diff --git a/doc/application.txt b/doc/application.txt index 2181c540c47..5a5e8bfe779 100644 --- a/doc/application.txt +++ b/doc/application.txt @@ -96,6 +96,27 @@ Method on_ui_created will be invoked after application's UI was created (usually super # To navigate to start_path from rhoconfig.txt end +Method on_ui_close_request will be invoked when application's UI is triggered to closed by user from the system UI + :::ruby + #in application.rb + def on_ui_close_request + Alert.show_popup( + :message=>"Do you realy whant to close?", + :title=>"Information", + :buttons => [{:id => 'ok', :title => 'Ok'},{:id => 'cancel', :title => 'Cancel'}], + :callback => "/app/Application/on_close_callback" + ) + end + + #in Appcliaction controller + def on_close_callback + if @params['button_id'] == "ok" + Rho::Application.quit() + end + end +**NOTE: if you redefine this function on your application class - the app would not be automatically closed after execution of the function - you should also close the application from code by yourself (just call Rho::Application.quit()). Works only on Win32** + + Method on_ui_destroyed will be invoked when application's UI was destroyed (usually on app exit) :::ruby def on_ui_destroyed diff --git a/lib/framework/autocomplete/Rho.rb b/lib/framework/autocomplete/Rho.rb index 7ce449177a5..b0d0a5f7d61 100644 --- a/lib/framework/autocomplete/Rho.rb +++ b/lib/framework/autocomplete/Rho.rb @@ -185,7 +185,9 @@ def on_activate_app def on_deactivate_app end def on_ui_created - end + end + def on_ui_close_request + end def on_ui_destroyed end def on_sync_user_changed @@ -261,7 +263,9 @@ def on_config_conflicts(conflicts) def activate_app end def deactivate_app - end + end + def ui_close_request + end def ui_created end def ui_destroyed diff --git a/lib/framework/rho/rho.rb b/lib/framework/rho/rho.rb index d645a02a642..81a1b5bb64a 100644 --- a/lib/framework/rho/rho.rb +++ b/lib/framework/rho/rho.rb @@ -180,6 +180,15 @@ def ui_created end end + def ui_close_request + begin + get_app(APPNAME).on_ui_close_request + rescue Exception => e + trace_msg = e.backtrace.join("\n") + puts '"UI created" callback failed: ' + e.inspect + ";Trace: #{trace_msg}" + end + end + def ui_destroyed begin get_app(APPNAME).on_ui_destroyed diff --git a/lib/framework/rho/rhoapplication.rb b/lib/framework/rho/rhoapplication.rb index db075fb4c7e..b64954dcedc 100644 --- a/lib/framework/rho/rhoapplication.rb +++ b/lib/framework/rho/rhoapplication.rb @@ -146,6 +146,10 @@ def on_ui_created Rho::Application.processApplicationEvent({'applicationEvent'=>'UICreated'}) end + def on_ui_close_request + Rho::Application.quit() + end + def on_ui_destroyed Rho::Application.processApplicationEvent({'applicationEvent'=>'UIDestroyed'}) end diff --git a/platform/shared/common/RhodesApp.cpp b/platform/shared/common/RhodesApp.cpp index 3507779858f..1ed24b8b775 100755 --- a/platform/shared/common/RhodesApp.cpp +++ b/platform/shared/common/RhodesApp.cpp @@ -742,6 +742,16 @@ static void callback_uicreated(void *arg, String const &strQuery) rho_http_sendresponse(arg, ""); } +static void callback_uicloserequest(void *arg, String const &strQuery) +{ +#ifndef RHO_NO_RUBY_API + if (!RHODESAPP().isJSApplication() && !RHODESAPP().isNodeJSApplication()) + rho_ruby_uiCloseRequest(); +#endif + + rho_http_sendresponse(arg, ""); +} + static void callback_uidestroyed(void *arg, String const &strQuery) { #ifndef RHO_NO_RUBY_API @@ -778,6 +788,23 @@ void CRhodesApp::callUiCreatedCallback() m_appCallbacksQueue->addQueueCommand(new CAppCallbacksQueue::Command(CAppCallbacksQueue::ui_created)); } +int CRhodesApp::callUiCloseRequestCallback() +{ + if ( m_bExit || !rho_ruby_is_started()) return 1; + + String strUrl = m_strHomeUrl + "/system/uicloserequest"; + NetResponse resp = getNetRequest().pullData( strUrl, NULL ); + if ( !resp.isOK() ) + { + LOG(ERROR) + "UI close request callback failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData(); + return 1; + }else{ + return 0; + } + return 1; + +} + void CRhodesApp::callUiDestroyedCallback() { if ( m_bExit/* || !rho_ruby_is_started()*/ ) @@ -1575,6 +1602,7 @@ void CRhodesApp::initHttpServer() m_httpServer->register_uri("/system/activateapp", callback_activateapp); m_httpServer->register_uri("/system/deactivateapp", callback_deactivateapp); m_httpServer->register_uri("/system/uicreated", callback_uicreated); + m_httpServer->register_uri("/system/uicloserequest", callback_uicloserequest); m_httpServer->register_uri("/system/uidestroyed", callback_uidestroyed); m_httpServer->register_uri("/system/loadserversources", callback_loadserversources); m_httpServer->register_uri("/system/resetDBOnSyncUserChanged", callback_resetDBOnSyncUserChanged); @@ -2927,6 +2955,16 @@ void rho_rhodesapp_callUiCreatedCallback() } } +int rho_rhodesapp_callUiCloseRequestCallback() //return zero if you whant to suppress closing +{ + if ( rho::common::CRhodesApp::getInstance() ){ + return RHODESAPP().callUiCloseRequestCallback(); + } + + return 1; +} + + void rho_rhodesapp_callUiDestroyedCallback() { if ( rho::common::CRhodesApp::getInstance() ) diff --git a/platform/shared/common/RhodesApp.h b/platform/shared/common/RhodesApp.h index 9d7981418d7..dd655c30a42 100644 --- a/platform/shared/common/RhodesApp.h +++ b/platform/shared/common/RhodesApp.h @@ -248,6 +248,7 @@ class CRhodesApp : public CRhodesAppBase void callBluetoothCallback(String strCallbackUrl, const char* body); void callAppActiveCallback(boolean bActive); void callUiCreatedCallback(); + int callUiCloseRequestCallback(); void callUiDestroyedCallback(); void callPopupCallback(String strCallbackUrl, const String &id, const String &title); boolean callTimerCallback(const String& strUrl, const String& strData); @@ -406,6 +407,7 @@ void rho_rhodesapp_callDateTimeCallback(const char* strCallbackUrl, long lDateTi void rho_rhodesapp_callBluetoothCallback(const char* strCallbackUrl, const char* body); void rho_rhodesapp_callAppActiveCallback(int nActive); void rho_rhodesapp_callUiCreatedCallback(); +int rho_rhodesapp_callUiCloseRequestCallback(); void rho_rhodesapp_callUiDestroyedCallback(); void rho_rhodesapp_callScreenOffCallback(); void rho_rhodesapp_callScreenOnCallback(); diff --git a/platform/shared/qt/rhodes/newVersion/QtMainWindow.cpp b/platform/shared/qt/rhodes/newVersion/QtMainWindow.cpp index ccf404e63e2..f6bbecc82bf 100644 --- a/platform/shared/qt/rhodes/newVersion/QtMainWindow.cpp +++ b/platform/shared/qt/rhodes/newVersion/QtMainWindow.cpp @@ -310,20 +310,28 @@ void QtMainWindow::showEvent(QShowEvent *) void QtMainWindow::closeEvent(QCloseEvent *ce) { - if ( rho_ruby_is_started() ) - rb_thread_wakeup(rb_thread_main()); - - if (mainWindowCallback) mainWindowCallback->onWindowClose(); - tabbarRemoveAllTabs(false); - if (m_logView) - m_logView->close(); + if (!acceptClosing){ + acceptClosing = rho_rhodesapp_callUiCloseRequestCallback() == 0 ? false : true; + } - QTimer::singleShot(1, this, [&]{rho_rhodesapp_callUiDestroyedCallback();}); - QTimer::singleShot(1000, this, [&]{rho::common::CRhodesApp::Destroy();}); - QTimer::singleShot(3000, this, [this, ce]{ - ce->accept(); - QMainWindow::closeEvent(ce); - }); + if (acceptClosing){ + if ( rho_ruby_is_started() ) + rb_thread_wakeup(rb_thread_main()); + + if (mainWindowCallback) mainWindowCallback->onWindowClose(); + tabbarRemoveAllTabs(false); + if (m_logView) + m_logView->close(); + + QTimer::singleShot(1, this, [&]{rho_rhodesapp_callUiDestroyedCallback();}); + QTimer::singleShot(1000, this, [&]{rho::common::CRhodesApp::Destroy();}); + QTimer::singleShot(3000, this, [this, ce]{ + ce->accept(); + QMainWindow::closeEvent(ce); + }); + }else{ + ce->setAccepted(false); + } } @@ -389,7 +397,7 @@ void QtMainWindow::on_actionRotate180_triggered() void QtMainWindow::on_actionExit_triggered() { - this->close(); + this->close(); } bool QtMainWindow::internalUrlProcessing(const QUrl& url) @@ -956,6 +964,7 @@ void QtMainWindow::on_actionAbout_triggered() void QtMainWindow::exitCommand() { + acceptClosing = true; this->close(); } diff --git a/platform/shared/qt/rhodes/newVersion/QtMainWindow.h b/platform/shared/qt/rhodes/newVersion/QtMainWindow.h index 6910a47bbf0..5f4e569e5fd 100644 --- a/platform/shared/qt/rhodes/newVersion/QtMainWindow.h +++ b/platform/shared/qt/rhodes/newVersion/QtMainWindow.h @@ -124,7 +124,7 @@ class QtMainWindow : public QMainWindow void doAlertCallback(CAlertParams* params, int btnNum, CAlertParams::CAlertButton &button); void internalSetProxy(); QMenuBar* createMenu(); - + bool acceptClosing = false; private: IMainWindowCallback* mainWindowCallback; diff --git a/platform/shared/ruby/ext/rho/rhoruby.c b/platform/shared/ruby/ext/rho/rhoruby.c index 7be3019924f..6e0e4de3afd 100644 --- a/platform/shared/ruby/ext/rho/rhoruby.c +++ b/platform/shared/ruby/ext/rho/rhoruby.c @@ -113,6 +113,7 @@ static ID onConfigConflicts_mid; static ID activateApp_mid; static ID deactivateApp_mid; static ID uiCreated_mid; +static ID uiCloseRequest_mid; static ID uiDestroyed_mid; static ID loadServerSources_mid; static ID loadAllSyncSources_mid; @@ -362,6 +363,7 @@ void RhoRubyStart() CONST_ID(activateApp_mid, "activate_app"); CONST_ID(deactivateApp_mid, "deactivate_app"); CONST_ID(uiCreated_mid, "ui_created"); + CONST_ID(uiCloseRequest_mid, "ui_close_request"); CONST_ID(uiDestroyed_mid, "ui_destroyed"); CONST_ID(loadServerSources_mid,"load_server_sources"); CONST_ID(loadAllSyncSources_mid,"load_all_sync_sources"); @@ -505,6 +507,11 @@ void rho_ruby_uiCreated() rb_funcall(framework, uiCreated_mid, 0); } +void rho_ruby_uiCloseRequest() +{ + rb_funcall(framework, uiCloseRequest_mid, 0); +} + void rho_ruby_uiDestroyed() { rb_funcall(framework, uiDestroyed_mid, 0); diff --git a/platform/shared/ruby/ext/rho/rhoruby.h b/platform/shared/ruby/ext/rho/rhoruby.h index e0e88e8c06f..0f314a1f731 100755 --- a/platform/shared/ruby/ext/rho/rhoruby.h +++ b/platform/shared/ruby/ext/rho/rhoruby.h @@ -62,6 +62,7 @@ void rho_ruby_call_config_conflicts(); void rho_ruby_activateApp(); void rho_ruby_deactivateApp(); void rho_ruby_uiCreated(); +void rho_ruby_uiCloseRequest(); void rho_ruby_uiDestroyed(); void rho_ruby_loadserversources(const char* szData); void rho_ruby_loadallsyncsources();