summaryrefslogtreecommitdiff
path: root/RealtimeSync/trayMenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'RealtimeSync/trayMenu.cpp')
-rw-r--r--RealtimeSync/trayMenu.cpp198
1 files changed, 98 insertions, 100 deletions
diff --git a/RealtimeSync/trayMenu.cpp b/RealtimeSync/trayMenu.cpp
index ff88a950..79076abd 100644
--- a/RealtimeSync/trayMenu.cpp
+++ b/RealtimeSync/trayMenu.cpp
@@ -9,24 +9,25 @@
#include <wx/taskbar.h>
#include <wx/app.h>
#include "resources.h"
-#include <memory>
+//#include <memory>
#include <wx/utils.h>
#include <wx/menu.h>
#include "watcher.h"
-#include <wx/timer.h>
#include <wx/utils.h>
#include <wx/log.h>
#include "../shared/staticAssert.h"
#include "../shared/buildInfo.h"
#include <wx/icon.h> //Linux needs this
+#include <wx/timer.h>
-class RtsTrayIcon;
+using namespace RealtimeSync;
-class WaitCallbackImpl : public RealtimeSync::WaitCallback
+class WaitCallbackImpl : private wxEvtHandler, public RealtimeSync::WaitCallback //keep this order: else VC++ generated wrong code
{
public:
WaitCallbackImpl();
+ ~WaitCallbackImpl();
virtual void requestUiRefresh();
@@ -35,156 +36,157 @@ public:
m_abortRequested = true;
}
- void requestResume()
+ void OnRequestResume(wxCommandEvent& event)
{
m_resumeRequested = true;
}
+ enum Selection
+ {
+ CONTEXT_ABORT,
+ CONTEXT_RESTORE,
+ CONTEXT_ABOUT
+ };
+
+ void OnContextMenuSelection(wxCommandEvent& event);
+
private:
- std::auto_ptr<RtsTrayIcon> trayMenu;
+ class RtsTrayIcon;
+ RtsTrayIcon* trayMenu;
+
bool m_abortRequested;
bool m_resumeRequested;
};
-class RtsTrayIcon : public wxTaskBarIcon
+//RtsTrayIcon shall be a dumb class whose sole purpose is to enable wxWidgets deferred deletion
+class WaitCallbackImpl::RtsTrayIcon : public wxTaskBarIcon
{
public:
- RtsTrayIcon(WaitCallbackImpl* callback) :
- m_callback(callback)
- {
-#ifdef FFS_WIN
- const wxIcon& realtimeIcon = *GlobalResources::getInstance().programIcon;
-#elif defined FFS_LINUX
- wxIcon realtimeIcon;
- realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit
-#endif
- wxTaskBarIcon::SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active..."));
+ RtsTrayIcon(WaitCallbackImpl* parent) : parent_(parent) {}
- //register double-click
- Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(RtsTrayIcon::resumeToMain), NULL, this);
- }
-
- void updateSysTray()
+ void parentHasDied() //call before tray icon is marked for deferred deletion
{
- wxTheApp->Yield();
+ parent_ = NULL;
}
private:
- enum Selection
- {
- CONTEXT_ABORT,
- CONTEXT_RESTORE,
- CONTEXT_ABOUT
- };
-
virtual wxMenu* CreatePopupMenu()
{
+ if (!parent_)
+ return NULL;
+
wxMenu* contextMenu = new wxMenu;
contextMenu->Append(CONTEXT_RESTORE, _("&Restore"));
contextMenu->Append(CONTEXT_ABOUT, _("&About..."));
contextMenu->AppendSeparator();
contextMenu->Append(CONTEXT_ABORT, _("&Exit"));
//event handling
- contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RtsTrayIcon::OnContextMenuSelection), NULL, this);
+ contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(WaitCallbackImpl::OnContextMenuSelection), NULL, parent_);
- return contextMenu; //ownership transferred to library
+ return contextMenu; //ownership transferred to caller
}
- void OnContextMenuSelection(wxCommandEvent& event)
- {
- const int eventId = event.GetId();
- switch (static_cast<Selection>(eventId))
- {
- case CONTEXT_ABORT:
- m_callback->requestAbort();
- break;
- case CONTEXT_ABOUT:
- {
- //build information
- wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__;
-#if wxUSE_UNICODE
- build += wxT(" - Unicode");
-#else
- build += wxT(" - ANSI");
-#endif //wxUSE_UNICODE
+ WaitCallbackImpl* parent_;
+};
+//##############################################################################################################
- //compile time info about 32/64-bit build
- if (Utility::is64BitBuild)
- build += wxT(" x64)");
- else
- build += wxT(" x86)");
- assert_static(Utility::is32BitBuild || Utility::is64BitBuild);
- wxMessageDialog* aboutDlg = new wxMessageDialog(NULL, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK);
- aboutDlg->ShowModal();
- aboutDlg->Destroy();
- }
- break;
- case CONTEXT_RESTORE:
- m_callback->requestResume();
- break;
- }
- }
+class AbortThisProcess //exception class
+{
+public:
+ AbortThisProcess(MonitorResponse command) : command_(command) {}
- void resumeToMain(wxCommandEvent& event)
+ MonitorResponse getCommand() const
{
- m_callback->requestResume();
+ return command_;
}
- WaitCallbackImpl* m_callback;
+private:
+ MonitorResponse command_;
};
+//##############################################################################################################
-bool updateUiIsAllowed()
+WaitCallbackImpl::WaitCallbackImpl() :
+ m_abortRequested(false),
+ m_resumeRequested(false)
{
- static wxLongLong lastExec = 0;
- const wxLongLong newExec = wxGetLocalTimeMillis();
+ trayMenu = new RtsTrayIcon(this); //not in initialization list: give it a valid parent object!
- if (newExec - lastExec >= RealtimeSync::UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary
- {
- lastExec = newExec;
- return true;
- }
- return false;
+#ifdef FFS_WIN
+ const wxIcon& realtimeIcon = *GlobalResources::getInstance().programIcon;
+#elif defined FFS_LINUX
+ wxIcon realtimeIcon;
+ realtimeIcon.CopyFromBitmap(GlobalResources::getInstance().getImageByName(wxT("RTS_tray_linux.png"))); //use a 22x22 bitmap for perfect fit
+#endif
+ trayMenu->SetIcon(realtimeIcon, wxString(wxT("RealtimeSync")) + wxT(" - ") + _("Monitoring active..."));
+
+ //register double-click
+ trayMenu->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this);
}
-class AbortThisProcess //exception class
+WaitCallbackImpl::~WaitCallbackImpl()
{
-public:
- AbortThisProcess(bool backToMain) : m_backToMain(backToMain) {}
+ trayMenu->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(WaitCallbackImpl::OnRequestResume), NULL, this);
+ trayMenu->RemoveIcon(); //(try to) hide icon until final deletion takes place
+ trayMenu->parentHasDied();
- bool backToMainMenu() const
- {
- return m_backToMain;
- }
+ //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
+ if (!wxPendingDelete.Member(trayMenu))
+ wxPendingDelete.Append(trayMenu);
+}
-private:
- bool m_backToMain;
-};
+void WaitCallbackImpl::OnContextMenuSelection(wxCommandEvent& event)
+{
+ const int eventId = event.GetId();
+ switch (static_cast<Selection>(eventId))
+ {
+ case CONTEXT_ABORT:
+ requestAbort();
+ break;
+ case CONTEXT_RESTORE:
+ OnRequestResume(event); //just remember: never throw exceptions through a C-Layer (GUI) ;)
+ break;
+ case CONTEXT_ABOUT:
+ {
+ //build information
+ wxString build = wxString(wxT("(")) + _("Build:") + wxT(" ") + __TDATE__;
+#if wxUSE_UNICODE
+ build += wxT(" - Unicode");
+#else
+ build += wxT(" - ANSI");
+#endif //wxUSE_UNICODE
+ //compile time info about 32/64-bit build
+ if (Utility::is64BitBuild)
+ build += wxT(" x64)");
+ else
+ build += wxT(" x86)");
+ assert_static(Utility::is32BitBuild || Utility::is64BitBuild);
-WaitCallbackImpl::WaitCallbackImpl() :
- m_abortRequested(false),
- m_resumeRequested(false)
-{
- trayMenu.reset(new RtsTrayIcon(this));
+ wxMessageDialog aboutDlg(NULL, wxString(wxT("RealtimeSync")) + wxT("\n\n") + build, _("About"), wxOK);
+ aboutDlg.ShowModal();
+ }
+ break;
+ }
}
void WaitCallbackImpl::requestUiRefresh()
{
if (updateUiIsAllowed())
- trayMenu->updateSysTray();
+ wxTheApp->Yield();
if (m_abortRequested)
- throw ::AbortThisProcess(false);
+ throw ::AbortThisProcess(QUIT);
if (m_resumeRequested)
- throw ::AbortThisProcess(true);
+ throw ::AbortThisProcess(RESUME);
}
+//##############################################################################################################
RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config)
@@ -216,10 +218,7 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces
}
catch (const ::AbortThisProcess& ab)
{
- if (ab.backToMainMenu())
- return RESUME;
- else
- return QUIT;
+ return ab.getCommand();
}
catch (const FreeFileSync::FileError& error)
{
@@ -229,4 +228,3 @@ RealtimeSync::MonitorResponse RealtimeSync::startDirectoryMonitor(const xmlAcces
return RESUME;
}
-
bgstack15