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

Delta Between Two Patch Sets: src/engine/Main.cpp

Issue 6505394822184960: Issue 1109 - Support notifications (Closed)
Left Patch Set: add border and shadow and remove title background Created July 3, 2015, 1:37 p.m.
Right Patch Set: fix obtaining of DPI value of content (NotificationWindow) of NotificationBorderWindow Created Aug. 18, 2015, 9:43 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #pragma comment(linker,"\"/manifestdependency:type='win32' \ 18 #pragma comment(linker,"\"/manifestdependency:type='win32' \
19 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ 19 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
20 processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 20 processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Eric 2015/08/19 17:43:37 I did not say it wasn't available, I said it wasn'
Oleksandr 2015/08/20 13:12:13 Common Controls 6 are essentially Windows XP UI up
21 21
22 #include <AdblockPlus.h> 22 #include <AdblockPlus.h>
23 #include <functional> 23 #include <functional>
24 #include <vector> 24 #include <vector>
25 #include <deque>
25 #include <thread> 26 #include <thread>
27 #include <mutex>
28 #include <condition_variable>
26 #include <Windows.h> 29 #include <Windows.h>
27 30
28 #include "../shared/AutoHandle.h" 31 #include "../shared/AutoHandle.h"
29 #include "../shared/Communication.h" 32 #include "../shared/Communication.h"
30 #include "../shared/Dictionary.h" 33 #include "../shared/Dictionary.h"
31 #include "../shared/Utils.h" 34 #include "../shared/Utils.h"
32 #include "../shared/Version.h" 35 #include "../shared/Version.h"
33 #include "../shared/CriticalSection.h" 36 #include "../shared/CriticalSection.h"
34 #include "IeVersion.h" 37 #include "IeVersion.h"
35 #include "AdblockPlus.h" 38 #include "AdblockPlus.h"
36 #include "Debug.h" 39 #include "Debug.h"
37 #include "Updater.h" 40 #include "Updater.h"
41 #include "Registry.h"
38 #include "NotificationWindow.h" 42 #include "NotificationWindow.h"
39 43
40 namespace 44 namespace
41 { 45 {
42 class MyModule : public ATL::CAtlExeModuleT<MyModule> { 46 struct ScopedAtlAxInitializer
47 {
48 ScopedAtlAxInitializer()
49 {
50 ATL::AtlAxWinInit();
51 }
52 ~ScopedAtlAxInitializer()
53 {
54 ATL::AtlAxWinTerm();
55 }
56 };
57
58 class ABPAtlModule : public ATL::CAtlExeModuleT<ABPAtlModule>
59 {
60 enum CustomMessages
61 {
62 TASK_POSTED = WM_USER + 1
63 };
64
43 public: 65 public:
66 ABPAtlModule() : m_msgHWnd(nullptr)
67 {
68 }
69 void Finalize();
70 HRESULT PreMessageLoop(int showCmd) throw();
71 void RunMessageLoop() throw();
Eric 2015/08/19 17:43:37 The only thing this message loop is doing is to pu
sergei 2015/08/20 14:45:42 What does the notification queue refers here? Righ
72 static HRESULT InitializeCom() throw()
73 {
74 // The default implementation initializes multithreaded version but
75 // in this case hosted ActiveX does not properly work.
76 return CoInitialize(nullptr);
77 }
78 private:
79 void onNewNotification(const AdblockPlus::NotificationPtr& notification);
80 void DispatchTask(std::function<void()>&& task);
81 void ProcessTasks();
82
83 ScopedAtlAxInitializer m_scopedAtlAxInit;
84 HWND m_msgHWnd;
85 std::recursive_mutex m_tasksMutex;
86 std::deque<std::function<void()>> m_tasks;
87 std::unique_ptr<NotificationBorderWindow> m_notificationWindow;
44 } _AtlModule; 88 } _AtlModule;
Eric 2015/08/19 17:43:37 '_AtlModule' is defined statically, yet its proper
Oleksandr 2015/08/20 13:12:13 It's not perfect right now, but good enough, IMHO.
sergei 2015/08/20 14:45:41 I faced with the troubles that it's static and yet
45 89
46 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; 90 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine;
47 std::auto_ptr<Updater> updater; 91 std::auto_ptr<Updater> updater;
48 int activeConnections = 0; 92 int activeConnections = 0;
49 CriticalSection activeConnectionsLock; 93 CriticalSection activeConnectionsLock;
50 HWND callbackWindow; 94 HWND callbackWindow;
51 95
52 void WriteSubscriptions(Communication::OutputBuffer& response, 96 void WriteSubscriptions(Communication::OutputBuffer& response,
53 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions) 97 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions)
54 { 98 {
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 457
414 Debug("Client disconnected " + threadString); 458 Debug("Client disconnected " + threadString);
415 459
416 { 460 {
417 CriticalSection::Lock lock(activeConnectionsLock); 461 CriticalSection::Lock lock(activeConnectionsLock);
418 activeConnections--; 462 activeConnections--;
419 if (activeConnections < 1) 463 if (activeConnections < 1)
420 { 464 {
421 Debug("No connections left, shutting down the engine"); 465 Debug("No connections left, shutting down the engine");
422 activeConnections = 0; 466 activeConnections = 0;
467
468 // The following exit(0) calls the destructor of _AtlModule from the
469 // current thread which results in the disaster because there is a
470 // running message loop as well as there can be alive notification
471 // window which holds v8::Value as well as m_tasks can hold v8::Value
472 // but JS Engine is destroyed before _AtlModule. BTW, various free
473 // running threads like Timeout also cause the crash because the engine
474 // is already destroyed.
Eric 2015/08/19 17:43:38 If it's possible for a dependency of a class to be
sergei 2015/08/20 14:45:41 Yes, this code needs attention. I would like to no
475 _AtlModule.Finalize();
423 exit(0); 476 exit(0);
424 } 477 }
425 } 478 }
426 479
427 } 480 }
428 481
429 void OnUpdateAvailable(AdblockPlus::JsValueList& params) 482 void OnUpdateAvailable(AdblockPlus::JsValueList& params)
430 { 483 {
431 if (params.size() < 1) 484 if (params.size() < 1)
432 { 485 {
433 Debug("updateAvailable event missing URL"); 486 Debug("updateAvailable event missing URL");
434 return; 487 return;
435 } 488 }
436 updateAvailable = true; 489 updateAvailable = true;
437 490
438 updater->Update(params[0]->AsString()); 491 updater->Update(params[0]->AsString());
492 }
493
494 std::wstring PreconfigurationValueFromRegistry(const std::wstring& preconfigNa me)
495 {
496 try
497 {
498 AdblockPlus::RegistryKey regKey(HKEY_CURRENT_USER, L"Software\\AdblockPlus ");
499 return regKey.value_wstring(preconfigName);
500 }
501 catch (const std::runtime_error&)
502 {
503 return L"";
504 }
439 } 505 }
440 506
441 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale) 507 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale)
442 { 508 {
443 AdblockPlus::AppInfo appInfo; 509 AdblockPlus::AppInfo appInfo;
444 appInfo.version = ToUtf8String(IEPLUGIN_VERSION); 510 appInfo.version = ToUtf8String(IEPLUGIN_VERSION);
445 appInfo.name = "adblockplusie"; 511 appInfo.name = "adblockplusie";
446 #ifdef _WIN64 512 #ifdef _WIN64
447 appInfo.application = "msie64"; 513 appInfo.application = "msie64";
448 #else 514 #else
449 appInfo.application = "msie32"; 515 appInfo.application = "msie32";
450 #endif 516 #endif
451 appInfo.applicationVersion = ToUtf8String(AdblockPlus::IE::InstalledVersionStr ing()); 517 appInfo.applicationVersion = ToUtf8String(AdblockPlus::IE::InstalledVersionStr ing());
452 appInfo.locale = ToUtf8String(locale); 518 appInfo.locale = ToUtf8String(locale);
453 #ifdef ADBLOCK_PLUS_TEST_MODE 519 #ifdef ADBLOCK_PLUS_TEST_MODE
454 appInfo.developmentBuild = true; 520 appInfo.developmentBuild = true;
455 #else 521 #else
456 appInfo.developmentBuild = false; 522 appInfo.developmentBuild = false;
457 #endif 523 #endif
458 524
459 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::New(appInfo); 525 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::New(appInfo);
460 jsEngine->SetEventCallback("updateAvailable", &OnUpdateAvailable); 526 jsEngine->SetEventCallback("updateAvailable", &OnUpdateAvailable);
461 527
462 std::string dataPath = ToUtf8String(GetAppDataPath()); 528 std::string dataPath = ToUtf8String(GetAppDataPath());
463 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); 529 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath);
464 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine)); 530 std::map<std::string, AdblockPlus::JsValuePtr> preconfig;
531 preconfig["disable_auto_updates"] = jsEngine->NewValue(
532 PreconfigurationValueFromRegistry(L"disable_auto_updates") == L"true");
533 preconfig["suppress_first_run_page"] = jsEngine->NewValue(
534 PreconfigurationValueFromRegistry(L"suppress_first_run_page") == L"true");
535 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine, preconfig));
465 return filterEngine; 536 return filterEngine;
466 } 537 }
467 538
468 class ScopedTimer 539 void ABPAtlModule::Finalize()
469 { 540 {
470 public: 541 std::condition_variable cv;
471 explicit ScopedTimer(HWND hwnd, UINT_PTR timerId, UINT elapse, TIMERPROC timer Proc) 542 std::mutex cvMutex;
472 : m_hwnd(hwnd), m_timerId(timerId) 543 std::unique_lock<std::mutex> lock(cvMutex);
473 { 544 DispatchTask([&cvMutex, &cv, this]
474 m_timerId = SetTimer(m_hwnd, m_timerId, elapse, timerProc); 545 {
475 } 546 if (m_notificationWindow)
476 ~ScopedTimer() 547 {
477 { 548 m_notificationWindow->SendMessage(WM_CLOSE);
478 Close(); 549 }
479 } 550 SendMessage(m_msgHWnd, WM_QUIT, 0, 0);
480 551 {
481 UINT_PTR GetID() 552 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
482 { 553 m_tasks.clear();
483 return m_timerId; 554 }
484 } 555 std::unique_lock<std::mutex> lock(cvMutex);
485 556 cv.notify_one();
486 operator bool() const 557 });
487 { 558 cv.wait(lock);
488 return m_timerId != 0; 559 }
489 } 560
490 561 HRESULT ABPAtlModule::PreMessageLoop(int showCmd) throw()
491 void Close()
492 {
493 if (m_timerId)
494 {
495 KillTimer(m_hwnd, m_timerId);
496 m_timerId = 0;
497 }
498 }
499 private:
500 ScopedTimer(const ScopedTimer&);
501 ScopedTimer& operator=(const ScopedTimer&);
502 private:
503 HWND m_hwnd;
504 UINT_PTR m_timerId;
505 };
506
507 struct ScopedAtlAxInitializer
508 {
509 ScopedAtlAxInitializer()
510 {
511 ATL::AtlAxWinInit();
512 }
513 ~ScopedAtlAxInitializer()
514 {
515 ATL::AtlAxWinTerm();
516 }
517 };
518
519 void ApplicationMessageLoop(HINSTANCE hInstance)
Oleksandr 2015/07/22 09:45:35 I still think using CreateTimerQueueTimer instead
sergei 2015/07/23 14:17:57 What is a window listener? Anyway the timer is rem
520 { 562 {
521 const std::wstring className = L"ABPEngineMessageWindow"; 563 const std::wstring className = L"ABPEngineMessageWindow";
522 WNDCLASS wc; 564 WNDCLASS wc;
523 wc.style = 0; 565 wc.style = 0;
524 wc.lpfnWndProc = DefWindowProcW; 566 wc.lpfnWndProc = DefWindowProcW;
525 wc.cbClsExtra = 0; 567 wc.cbClsExtra = 0;
526 wc.cbWndExtra = 0; 568 wc.cbWndExtra = 0;
527 wc.hInstance = hInstance; 569 wc.hInstance = ATL::_AtlBaseModule.GetModuleInstance();
528 wc.hIcon = nullptr; 570 wc.hIcon = nullptr;
529 wc.hCursor = nullptr; 571 wc.hCursor = nullptr;
530 wc.hbrBackground = nullptr; 572 wc.hbrBackground = nullptr;
531 wc.lpszMenuName = nullptr; 573 wc.lpszMenuName = nullptr;
532 wc.lpszClassName = className.c_str(); 574 wc.lpszClassName = className.c_str();
533 ATOM atom = RegisterClass(&wc); 575 ATOM atom = RegisterClass(&wc);
534 if (!atom) 576 if (!atom)
535 { 577 {
536 DebugLastError("Cannot register class for message only window"); 578 DebugLastError("Cannot register class for message only window");
537 return; 579 return E_FAIL;
538 } 580 }
539 HWND msgHWnd = CreateWindowW(className.c_str(), 581 m_msgHWnd = CreateWindowW(className.c_str(),
540 nullptr, // window name 582 nullptr, // window name
541 0, // style 583 0, // style
542 0, 0, 0, 0, // geometry (x, y, w, h) 584 0, 0, 0, 0, // geometry (x, y, w, h)
543 HWND_MESSAGE, // parent 585 HWND_MESSAGE, // parent
544 nullptr, // menu handle 586 nullptr, // menu handle
545 hInstance, 587 wc.hInstance,
546 0); // windows creation data. 588 0); // windows creation data.
547 if (!msgHWnd) 589 if (!m_msgHWnd)
548 { 590 {
549 DebugLastError("Cannot create message only window"); 591 DebugLastError("Cannot create message only window");
550 return; 592 return E_FAIL;
551 } 593 }
594
595 filterEngine->SetShowNotificationCallback([this](const AdblockPlus::Notificati onPtr& notification)
596 {
597 if (!notification)
598 {
599 return;
600 }
601 DispatchTask([notification, this]
602 {
603 onNewNotification(notification);
604 });
605 });
606
607 HRESULT retValue = __super::PreMessageLoop(showCmd);
608 // __super::PreMessageLoop returns S_FALSE because there is nothing to
609 // register but S_OK is required to run message loop.
610 return FAILED(retValue) ? retValue : S_OK;
611 }
612
613 void ABPAtlModule::RunMessageLoop() throw()
614 {
552 MSG msg = {}; 615 MSG msg = {};
553 ScopedTimer notificationTimer(msgHWnd, /*timer ID*/1, 3000/*msec*/, nullptr);
554 std::unique_ptr<NotificationBorderWindow> notificationWindow;
555 while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0) ) 616 while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0) )
556 { 617 {
557 if (msg.hwnd == msgHWnd) 618 if (msg.hwnd == m_msgHWnd && msg.message == CustomMessages::TASK_POSTED)
558 { 619 {
559 if (msg.message == WM_TIMER) 620 ProcessTasks();
560 {
561 if (msg.wParam == notificationTimer.GetID())
562 {
563 notificationTimer.Close();
564 auto notification = filterEngine->GetNextNotificationToShow();
565 if (notification)
566 {
567 notificationWindow.reset(new NotificationBorderWindow(*notification, GetExeDir() + L"html\\templates\\"));
568 notificationWindow->SetOnDestroyed([&notificationWindow]
569 {
570 notificationWindow.reset();
571 });
572 notificationWindow->SetOnLinkClicked([](const std::wstring& url)
573 {
574 ATL::CComPtr<IWebBrowser2> webBrowser;
575 if (SUCCEEDED(webBrowser.CoCreateInstance(__uuidof(InternetExplore r))) && webBrowser)
576 {
577 ATL::CComVariant emptyVariant;
578 webBrowser->Navigate(ATL::CComBSTR(url.c_str()), &emptyVariant, &emptyVariant, &emptyVariant, &emptyVariant);
579 webBrowser->put_Visible(VARIANT_TRUE);
580 }
581 });
582 notificationWindow->Create(/*parent window*/nullptr);
583 if (notificationWindow->operator HWND() != nullptr)
584 {
585 notificationWindow->ShowWindow(SW_SHOWNOACTIVATE);
586 notificationWindow->UpdateWindow();
587 }
588 }
589 }
590 }
591 } 621 }
592 TranslateMessage(&msg); 622 TranslateMessage(&msg);
593 DispatchMessage(&msg); 623 DispatchMessage(&msg);
594 } 624 }
595 } 625 }
596 626
627 void ABPAtlModule::onNewNotification(const AdblockPlus::NotificationPtr& notific ation)
628 {
629 m_notificationWindow.reset(new NotificationBorderWindow(*notification, GetExeD ir() + L"html\\templates\\"));
630 m_notificationWindow->SetOnDestroyed([notification, this]
631 {
632 notification->MarkAsShown();
633 m_notificationWindow.reset();
634 });
635 m_notificationWindow->SetOnLinkClicked([](const std::wstring& url)
636 {
637 ATL::CComPtr<IWebBrowser2> webBrowser;
638 if (SUCCEEDED(webBrowser.CoCreateInstance(__uuidof(InternetExplorer))) && we bBrowser)
639 {
640 ATL::CComVariant emptyVariant;
641 webBrowser->Navigate(ATL::CComBSTR(url.c_str()), &emptyVariant, &emptyVari ant, &emptyVariant, &emptyVariant);
642 webBrowser->put_Visible(VARIANT_TRUE);
643 }
644 });
645 m_notificationWindow->Create(/*parent window*/nullptr);
646 if (m_notificationWindow->operator HWND() != nullptr)
647 {
648 m_notificationWindow->ShowWindow(SW_SHOWNOACTIVATE);
649 m_notificationWindow->UpdateWindow();
650 }
651 }
652
653 void ABPAtlModule::DispatchTask(std::function<void()>&& task)
654 {
655 {
656 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
657 m_tasks.emplace_back(std::move(task));
658 }
659 PostMessageW(m_msgHWnd, CustomMessages::TASK_POSTED, 0, 0);
660 }
661
662 void ABPAtlModule::ProcessTasks()
663 {
664 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
665 while(!m_tasks.empty())
666 {
667 auto task = *m_tasks.begin();
668 m_tasks.pop_front();
669 if (task)
670 task();
671 }
672 }
673
597 } // namespace { 674 } // namespace {
598 675
599 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) 676 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int cmdShow)
600 { 677 {
601 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine")); 678 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine"));
602 if (!mutex) 679 if (!mutex)
603 { 680 {
604 DebugLastError("CreateMutex failed"); 681 DebugLastError("CreateMutex failed");
605 return 1; 682 return 1;
606 } 683 }
607 684
608 if (GetLastError() == ERROR_ALREADY_EXISTS) 685 if (GetLastError() == ERROR_ALREADY_EXISTS)
609 { 686 {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 return 1; 719 return 1;
643 } 720 }
644 catch (const std::runtime_error& e) 721 catch (const std::runtime_error& e)
645 { 722 {
646 DebugException(e); 723 DebugException(e);
647 return 1; 724 return 1;
648 } 725 }
649 } 726 }
650 }); 727 });
651 728
652 ScopedAtlAxInitializer atlAxInit; 729 int retValue = _AtlModule.WinMain(cmdShow);
653 ApplicationMessageLoop(hInstance);
654 if (communicationThread.joinable()) 730 if (communicationThread.joinable())
655 { 731 {
656 communicationThread.join(); 732 communicationThread.join();
657 } 733 }
658 734
659 735 return retValue;
Oleksandr 2015/07/22 09:45:35 NIT: Extra line here
sergei 2015/07/23 14:17:57 Fixed
660 return 0;
661 } 736 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld