summaryrefslogtreecommitdiff
path: root/ui/tray_icon.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
commitfbe76102e941b9f1edaf236788e42678f05fdf9a (patch)
treef5f538316019fa89be8dc478103490c3a826f3ac /ui/tray_icon.cpp
parent3.8 (diff)
downloadFreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.gz
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.bz2
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.zip
3.9
Diffstat (limited to 'ui/tray_icon.cpp')
-rw-r--r--ui/tray_icon.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/ui/tray_icon.cpp b/ui/tray_icon.cpp
new file mode 100644
index 00000000..464bf7ef
--- /dev/null
+++ b/ui/tray_icon.cpp
@@ -0,0 +1,213 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+//
+#include "tray_icon.h"
+#include "../library/resources.h"
+#include "small_dlgs.h"
+#include <wx/taskbar.h>
+#include <cmath>
+#include <wx/image.h>
+#include <wx/menu.h>
+#include <wx/icon.h> //req. by Linux
+
+namespace
+{
+inline
+int roundNum(double d) //little rounding function
+{
+ return static_cast<int>(d < 0 ? d - .5 : d + .5);
+}
+
+
+wxIcon generateIcon(size_t percent) //generate icon with progress indicator
+{
+ percent = std::min(percent, static_cast<size_t>(100u)); //handle invalid input
+
+#ifdef FFS_WIN
+ static const wxBitmap trayIcon = GlobalResources::getInstance().getImageByName(wxT("FFS_tray_win.png"));
+#elif defined FFS_LINUX
+ static const wxBitmap trayIcon = GlobalResources::getInstance().getImageByName(wxT("FFS_tray_linux.png"));
+#endif
+
+ const int indicatorHeight = roundNum((trayIcon.GetHeight() * percent) / 100.0);
+
+ //minor optimization
+ static std::pair<int, wxIcon> buffer = std::make_pair(-1, wxNullIcon);
+ if (buffer.first == indicatorHeight)
+ return buffer.second;
+
+ if ( trayIcon.GetWidth() > 0 &&
+ trayIcon.GetHeight() > 0)
+ {
+ static const int indicatorWidth = trayIcon.GetWidth() * .25;
+ const int indicatorXBegin = ceil((trayIcon.GetWidth() - indicatorWidth) / 2.0);
+ const int indicatorYBegin = trayIcon.GetHeight() - indicatorHeight;
+
+ wxImage genImage(trayIcon.ConvertToImage());
+
+ //draw progress indicator: do NOT use wxDC::DrawRectangle! Doesn't respect alpha in Windows, but does in Linux!
+ //We need a simple, working solution:
+ unsigned char* const data = genImage.GetData();
+ for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row)
+ {
+ for (int col = indicatorXBegin; col < indicatorXBegin + indicatorWidth; ++col)
+ {
+ unsigned char* const pixelBegin = data + (row * genImage.GetWidth() + col) * 3;
+ pixelBegin[0] = 255; //red
+ pixelBegin[1] = 255; //green
+ pixelBegin[2] = 0; //blue
+ }
+ }
+
+ if (genImage.HasAlpha())
+ {
+ unsigned char* const alpha = genImage.GetAlpha();
+ //make progress indicator fully opaque:
+ for (int row = indicatorYBegin; row < genImage.GetHeight(); ++row)
+ ::memset(alpha + row * genImage.GetWidth() + indicatorXBegin, wxIMAGE_ALPHA_OPAQUE, indicatorWidth);
+ }
+
+ wxIcon genIcon;
+ genIcon.CopyFromBitmap(wxBitmap(genImage));
+
+ //fill buffer
+ buffer.first = indicatorHeight;
+ buffer.second = genIcon;
+
+ return genIcon;
+ }
+
+ //fallback
+ wxIcon defaultIcon;
+ defaultIcon.CopyFromBitmap(trayIcon);
+
+ //fill buffer
+ buffer.first = indicatorHeight;
+ buffer.second = defaultIcon;
+
+ return defaultIcon;
+}
+}
+
+
+//------------------------------------------------------------------------------------------------
+enum Selection
+{
+ CONTEXT_RESTORE,
+ CONTEXT_ABOUT
+};
+
+
+class MinimizeToTray::TaskBarImpl : public wxTaskBarIcon
+{
+public:
+ TaskBarImpl(MinimizeToTray* parent) : parent_(parent) {}
+
+ void parentHasDied()
+ {
+ parent_ = NULL;
+ }
+private:
+ virtual wxMenu* CreatePopupMenu()
+ {
+ if (!parent_)
+ return NULL;
+
+ wxMenu* contextMenu = new wxMenu;
+ contextMenu->Append(CONTEXT_ABOUT, _("&About..."));
+ contextMenu->AppendSeparator();
+ contextMenu->Append(CONTEXT_RESTORE, _("&Restore"));
+ //event handling
+ contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MinimizeToTray::OnContextMenuSelection), NULL, parent_);
+
+ return contextMenu; //ownership transferred to caller
+ }
+
+ MinimizeToTray* parent_;
+};
+
+
+MinimizeToTray::MinimizeToTray(wxTopLevelWindow* callerWnd, wxWindow* secondWnd) :
+ callerWnd_(callerWnd),
+ secondWnd_(secondWnd),
+ trayIcon(new TaskBarImpl(this))
+{
+ trayIcon->SetIcon(generateIcon(0), wxT("FreeFileSync"));
+ trayIcon->Connect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(MinimizeToTray::OnDoubleClick), NULL, this); //register double-click
+
+ if (callerWnd_)
+ callerWnd_->Hide();
+ if (secondWnd_)
+ secondWnd_->Hide();
+}
+
+
+MinimizeToTray::~MinimizeToTray()
+{
+ resumeFromTray();
+}
+
+
+void MinimizeToTray::resumeFromTray() //remove trayIcon and restore windows: MinimizeToTray is now a zombie object...
+{
+ if (trayIcon)
+ {
+ if (secondWnd_)
+ secondWnd_->Show();
+
+ if (callerWnd_) //usecase: avoid dialog flashing in batch silent mode
+ {
+ callerWnd_->Iconize(false);
+ callerWnd_->Show();
+ callerWnd_->Raise();
+ callerWnd_->SetFocus();
+ }
+ trayIcon->RemoveIcon(); //hide icon until final deletion takes place
+ trayIcon->Disconnect(wxEVT_TASKBAR_LEFT_DCLICK, wxCommandEventHandler(MinimizeToTray::OnDoubleClick), NULL, this);
+ trayIcon->parentHasDied(); //TaskBarImpl (potentially) has longer lifetime than MinimizeToTray: avoid callback!
+
+ //use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
+ if (!wxPendingDelete.Member(trayIcon))
+ wxPendingDelete.Append(trayIcon);
+
+ trayIcon = NULL; //avoid reentrance
+ }
+}
+
+
+void MinimizeToTray::setToolTip(const wxString& toolTipText, size_t percent)
+{
+ if (trayIcon)
+ trayIcon->SetIcon(generateIcon(percent), toolTipText);
+}
+
+
+void MinimizeToTray::keepHidden()
+{
+ callerWnd_ = NULL;
+ secondWnd_ = NULL;
+}
+
+
+void MinimizeToTray::OnContextMenuSelection(wxCommandEvent& event)
+{
+ const Selection eventId = static_cast<Selection>(event.GetId());
+ switch (eventId)
+ {
+ case CONTEXT_ABOUT:
+ ffs3::showAboutDialog();
+ break;
+ case CONTEXT_RESTORE:
+ resumeFromTray();
+ }
+}
+
+
+void MinimizeToTray::OnDoubleClick(wxCommandEvent& event)
+{
+ resumeFromTray();
+}
+
bgstack15