Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/engine/Main.cpp

Issue 6505394822184960: Issue 1109 - Support notifications (Closed)
Patch Set: rebase, fix nullptrs, use COM InternetExplorer and close NotificationWindow when link is clicked Created June 25, 2015, 1:14 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/engine/Main.cpp
diff --git a/src/engine/Main.cpp b/src/engine/Main.cpp
index e4f653bdf26376534bbebd0158897072b826cf75..9108f1b668a46843b20bb97676119368bcb84d7f 100644
--- a/src/engine/Main.cpp
+++ b/src/engine/Main.cpp
@@ -15,6 +15,10 @@
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
+#pragma comment(linker,"\"/manifestdependency:type='win32' \
+ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
+ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+
#include <AdblockPlus.h>
#include <functional>
#include <vector>
@@ -31,9 +35,14 @@
#include "AdblockPlus.h"
#include "Debug.h"
#include "Updater.h"
+#include "NotificationWindow.h"
namespace
{
+ class MyModule : public ATL::CAtlExeModuleT<MyModule> {
+ public:
+ } _AtlModule;
+
std::auto_ptr<AdblockPlus::FilterEngine> filterEngine;
std::auto_ptr<Updater> updater;
int activeConnections = 0;
@@ -428,7 +437,6 @@ namespace
updater->Update(params[0]->AsString());
}
-}
std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale)
{
@@ -457,7 +465,138 @@ std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring&
return filterEngine;
}
-int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+class ScopedTimer
+{
+public:
+ explicit ScopedTimer(HWND hwnd, UINT_PTR timerId, UINT elapse, TIMERPROC timerProc)
+ : m_hwnd(hwnd), m_timerId(timerId)
+ {
+ m_timerId = SetTimer(m_hwnd, m_timerId, elapse, timerProc);
+ }
+ ~ScopedTimer()
+ {
+ Close();
+ }
+
+ UINT_PTR GetID()
+ {
+ return m_timerId;
+ }
+
+ operator bool() const
+ {
+ return m_timerId != 0;
+ }
+
+ void Close()
+ {
+ if (m_timerId)
+ {
+ KillTimer(m_hwnd, m_timerId);
+ m_timerId = 0;
+ }
+ }
+private:
+ ScopedTimer(const ScopedTimer&);
+ ScopedTimer& operator=(const ScopedTimer&);
+private:
+ HWND m_hwnd;
+ UINT_PTR m_timerId;
+};
+
+struct ScopedAtlAxInitializer
+{
+ ScopedAtlAxInitializer()
+ {
+ ATL::AtlAxWinInit();
+ }
+ ~ScopedAtlAxInitializer()
+ {
+ ATL::AtlAxWinTerm();
+ }
+};
+
+void ApplicationMessageLoop(HINSTANCE hInstance)
Oleksandr 2015/06/26 23:05:18 The whole idea behind this message loop is just to
sergei 2015/06/29 11:10:50 No, without message loop the notification window w
+{
+ const std::wstring className = L"ABPEngineMessageWindow";
+ WNDCLASS wc;
+ wc.style = 0;
+ wc.lpfnWndProc = DefWindowProcW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = nullptr;
+ wc.hCursor = nullptr;
+ wc.hbrBackground = nullptr;
+ wc.lpszMenuName = nullptr;
+ wc.lpszClassName = className.c_str();
+ ATOM atom = RegisterClass(&wc);
+ if (!atom)
+ {
+ DebugLastError("Cannot register class for message only window");
+ return;
+ }
+ HWND msgHWnd = CreateWindowW(className.c_str(),
+ nullptr, // window name
+ 0, // style
+ 0, 0, 0, 0, // geometry (x, y, w, h)
+ HWND_MESSAGE, // parent
+ nullptr, // menu handle
+ hInstance,
+ 0); // windows creation data.
+ if (!msgHWnd)
+ {
+ DebugLastError("Cannot create message only window");
+ return;
+ }
+ MSG msg = {};
+ ScopedTimer notificationTimer(msgHWnd, /*timer ID*/1, 3000/*msec*/, nullptr);
+ std::unique_ptr<NotificationWindow> notificationWindow;
+ while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0))
+ {
+ if (msg.hwnd == msgHWnd)
+ {
+ if (msg.message == WM_TIMER)
+ {
+ if (msg.wParam == notificationTimer.GetID())
+ {
+ notificationTimer.Close();
+ auto notification = filterEngine->GetNextNotificationToShow();
+ if (notification)
+ {
+ notificationWindow.reset(new NotificationWindow(*notification, GetExeDir() + L"html\\templates\\"));
+ notificationWindow->destroyed = [&notificationWindow]
+ {
+ notificationWindow.reset();
+ };
+ notificationWindow->linkClicked = [](const std::wstring& url)
+ {
+ ATL::CComPtr<IWebBrowser2> webBrowser;
+ if (SUCCEEDED(webBrowser.CoCreateInstance(__uuidof(InternetExplorer))) && webBrowser)
+ {
+ ATL::CComVariant emptyVariant;
+ webBrowser->Navigate(ATL::CComBSTR(url.c_str()), &emptyVariant, &emptyVariant, &emptyVariant, &emptyVariant);
+ webBrowser->put_Visible(VARIANT_TRUE);
+ }
+ };
+ notificationWindow->Create(/*parent window*/nullptr);
Oleksandr 2015/06/26 23:05:18 How about: notificationWindow->Create(/*parent win
sergei 2015/06/29 11:10:50 Of course we can. The difference is that it looks
+ if (notificationWindow->operator HWND() != nullptr)
+ {
+ notificationWindow->ShowWindow(SW_SHOWNOACTIVATE);
+ notificationWindow->UpdateWindow();
+ }
+ }
+ }
+ }
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+} // namespace {
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine"));
if (!mutex)
@@ -480,32 +619,43 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
filterEngine = CreateFilterEngine(locale);
updater.reset(new Updater(filterEngine->GetJsEngine()));
- for (;;)
+ std::thread communicationThread([]
{
- try
+ for (;;)
{
- auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE);
-
- // TODO: we should wait for the finishing of the thread before exiting from this function.
- // It works now in most cases because the browser waits for the response in the pipe, and the
- // thread has time to finish while this response is being processed and the browser is
- // disposing all its stuff.
- std::thread([pipe]()
+ try
{
- ClientThread(pipe.get());
- }).detach();
- }
- catch(const std::system_error& ex)
- {
- DebugException(ex);
- return 1;
- }
- catch (const std::runtime_error& e)
- {
- DebugException(e);
- return 1;
+ auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE);
+
+ // TODO: we should wait for the finishing of the thread before exiting from this function.
+ // It works now in most cases because the browser waits for the response in the pipe, and the
+ // thread has time to finish while this response is being processed and the browser is
+ // disposing all its stuff.
+ std::thread([pipe]()
+ {
+ ClientThread(pipe.get());
+ }).detach();
+ }
+ catch(const std::system_error& ex)
+ {
+ DebugException(ex);
+ return 1;
+ }
+ catch (const std::runtime_error& e)
+ {
+ DebugException(e);
+ return 1;
+ }
}
+ });
+
+ ScopedAtlAxInitializer atlAxInit;
+ ApplicationMessageLoop(hInstance);
+ if (communicationThread.joinable())
+ {
+ communicationThread.join();
}
+
return 0;
}

Powered by Google App Engine
This is Rietveld