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

Side by Side Diff: src/engine/Main.cpp

Issue 6505394822184960: Issue 1109 - Support notifications (Closed)
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:
View unified diff | Download patch
OLDNEW
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' \
19 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
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
18 #include <AdblockPlus.h> 22 #include <AdblockPlus.h>
19 #include <functional> 23 #include <functional>
20 #include <vector> 24 #include <vector>
25 #include <deque>
21 #include <thread> 26 #include <thread>
27 #include <mutex>
28 #include <condition_variable>
22 #include <Windows.h> 29 #include <Windows.h>
23 30
24 #include "../shared/AutoHandle.h" 31 #include "../shared/AutoHandle.h"
25 #include "../shared/Communication.h" 32 #include "../shared/Communication.h"
26 #include "../shared/Dictionary.h" 33 #include "../shared/Dictionary.h"
27 #include "../shared/Utils.h" 34 #include "../shared/Utils.h"
28 #include "../shared/Version.h" 35 #include "../shared/Version.h"
29 #include "../shared/CriticalSection.h" 36 #include "../shared/CriticalSection.h"
30 #include "IeVersion.h" 37 #include "IeVersion.h"
31 #include "AdblockPlus.h" 38 #include "AdblockPlus.h"
32 #include "Debug.h" 39 #include "Debug.h"
33 #include "Updater.h" 40 #include "Updater.h"
34 #include "Registry.h" 41 #include "Registry.h"
42 #include "NotificationWindow.h"
35 43
36 namespace 44 namespace
37 { 45 {
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
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;
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
89
38 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; 90 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine;
39 std::auto_ptr<Updater> updater; 91 std::auto_ptr<Updater> updater;
40 int activeConnections = 0; 92 int activeConnections = 0;
41 CriticalSection activeConnectionsLock; 93 CriticalSection activeConnectionsLock;
42 HWND callbackWindow; 94 HWND callbackWindow;
43 95
44 void WriteSubscriptions(Communication::OutputBuffer& response, 96 void WriteSubscriptions(Communication::OutputBuffer& response,
45 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions) 97 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions)
46 { 98 {
47 int32_t count = static_cast<int32_t>(subscriptions.size()); 99 int32_t count = static_cast<int32_t>(subscriptions.size());
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 457
406 Debug("Client disconnected " + threadString); 458 Debug("Client disconnected " + threadString);
407 459
408 { 460 {
409 CriticalSection::Lock lock(activeConnectionsLock); 461 CriticalSection::Lock lock(activeConnectionsLock);
410 activeConnections--; 462 activeConnections--;
411 if (activeConnections < 1) 463 if (activeConnections < 1)
412 { 464 {
413 Debug("No connections left, shutting down the engine"); 465 Debug("No connections left, shutting down the engine");
414 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();
415 exit(0); 476 exit(0);
416 } 477 }
417 } 478 }
418 479
419 } 480 }
420 481
421 void OnUpdateAvailable(AdblockPlus::JsValueList& params) 482 void OnUpdateAvailable(AdblockPlus::JsValueList& params)
422 { 483 {
423 if (params.size() < 1) 484 if (params.size() < 1)
424 { 485 {
(...skipping 10 matching lines...) Expand all
435 try 496 try
436 { 497 {
437 AdblockPlus::RegistryKey regKey(HKEY_CURRENT_USER, L"Software\\AdblockPlus "); 498 AdblockPlus::RegistryKey regKey(HKEY_CURRENT_USER, L"Software\\AdblockPlus ");
438 return regKey.value_wstring(preconfigName); 499 return regKey.value_wstring(preconfigName);
439 } 500 }
440 catch (const std::runtime_error&) 501 catch (const std::runtime_error&)
441 { 502 {
442 return L""; 503 return L"";
443 } 504 }
444 } 505 }
445 }
446 506
447 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale) 507 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale)
448 { 508 {
449 AdblockPlus::AppInfo appInfo; 509 AdblockPlus::AppInfo appInfo;
450 appInfo.version = ToUtf8String(IEPLUGIN_VERSION); 510 appInfo.version = ToUtf8String(IEPLUGIN_VERSION);
451 appInfo.name = "adblockplusie"; 511 appInfo.name = "adblockplusie";
452 #ifdef _WIN64 512 #ifdef _WIN64
453 appInfo.application = "msie64"; 513 appInfo.application = "msie64";
454 #else 514 #else
455 appInfo.application = "msie32"; 515 appInfo.application = "msie32";
(...skipping 13 matching lines...) Expand all
469 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); 529 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath);
470 std::map<std::string, AdblockPlus::JsValuePtr> preconfig; 530 std::map<std::string, AdblockPlus::JsValuePtr> preconfig;
471 preconfig["disable_auto_updates"] = jsEngine->NewValue( 531 preconfig["disable_auto_updates"] = jsEngine->NewValue(
472 PreconfigurationValueFromRegistry(L"disable_auto_updates") == L"true"); 532 PreconfigurationValueFromRegistry(L"disable_auto_updates") == L"true");
473 preconfig["suppress_first_run_page"] = jsEngine->NewValue( 533 preconfig["suppress_first_run_page"] = jsEngine->NewValue(
474 PreconfigurationValueFromRegistry(L"suppress_first_run_page") == L"true"); 534 PreconfigurationValueFromRegistry(L"suppress_first_run_page") == L"true");
475 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine, preconfig)); 535 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine, preconfig));
476 return filterEngine; 536 return filterEngine;
477 } 537 }
478 538
479 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 539 void ABPAtlModule::Finalize()
540 {
541 std::condition_variable cv;
542 std::mutex cvMutex;
543 std::unique_lock<std::mutex> lock(cvMutex);
544 DispatchTask([&cvMutex, &cv, this]
545 {
546 if (m_notificationWindow)
547 {
548 m_notificationWindow->SendMessage(WM_CLOSE);
549 }
550 SendMessage(m_msgHWnd, WM_QUIT, 0, 0);
551 {
552 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
553 m_tasks.clear();
554 }
555 std::unique_lock<std::mutex> lock(cvMutex);
556 cv.notify_one();
557 });
558 cv.wait(lock);
559 }
560
561 HRESULT ABPAtlModule::PreMessageLoop(int showCmd) throw()
562 {
563 const std::wstring className = L"ABPEngineMessageWindow";
564 WNDCLASS wc;
565 wc.style = 0;
566 wc.lpfnWndProc = DefWindowProcW;
567 wc.cbClsExtra = 0;
568 wc.cbWndExtra = 0;
569 wc.hInstance = ATL::_AtlBaseModule.GetModuleInstance();
570 wc.hIcon = nullptr;
571 wc.hCursor = nullptr;
572 wc.hbrBackground = nullptr;
573 wc.lpszMenuName = nullptr;
574 wc.lpszClassName = className.c_str();
575 ATOM atom = RegisterClass(&wc);
576 if (!atom)
577 {
578 DebugLastError("Cannot register class for message only window");
579 return E_FAIL;
580 }
581 m_msgHWnd = CreateWindowW(className.c_str(),
582 nullptr, // window name
583 0, // style
584 0, 0, 0, 0, // geometry (x, y, w, h)
585 HWND_MESSAGE, // parent
586 nullptr, // menu handle
587 wc.hInstance,
588 0); // windows creation data.
589 if (!m_msgHWnd)
590 {
591 DebugLastError("Cannot create message only window");
592 return E_FAIL;
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 {
615 MSG msg = {};
616 while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0) )
617 {
618 if (msg.hwnd == m_msgHWnd && msg.message == CustomMessages::TASK_POSTED)
619 {
620 ProcessTasks();
621 }
622 TranslateMessage(&msg);
623 DispatchMessage(&msg);
624 }
625 }
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
674 } // namespace {
675
676 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int cmdShow)
480 { 677 {
481 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine")); 678 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine"));
482 if (!mutex) 679 if (!mutex)
483 { 680 {
484 DebugLastError("CreateMutex failed"); 681 DebugLastError("CreateMutex failed");
485 return 1; 682 return 1;
486 } 683 }
487 684
488 if (GetLastError() == ERROR_ALREADY_EXISTS) 685 if (GetLastError() == ERROR_ALREADY_EXISTS)
489 { 686 {
490 DebugLastError("Named pipe exists, another engine instance appears to be run ning"); 687 DebugLastError("Named pipe exists, another engine instance appears to be run ning");
491 return 1; 688 return 1;
492 } 689 }
493 690
494 int argc; 691 int argc;
495 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 692 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
496 std::wstring locale(argc >= 2 ? argv[1] : L""); 693 std::wstring locale(argc >= 2 ? argv[1] : L"");
497 LocalFree(argv); 694 LocalFree(argv);
498 Dictionary::Create(locale); 695 Dictionary::Create(locale);
499 filterEngine = CreateFilterEngine(locale); 696 filterEngine = CreateFilterEngine(locale);
500 updater.reset(new Updater(filterEngine->GetJsEngine())); 697 updater.reset(new Updater(filterEngine->GetJsEngine()));
501 698
502 for (;;) 699 std::thread communicationThread([]
503 { 700 {
504 try 701 for (;;)
505 { 702 {
506 auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE); 703 try
704 {
705 auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeNam e, Communication::Pipe::MODE_CREATE);
706
707 // TODO: we should wait for the finishing of the thread before exiting f rom this function.
708 // It works now in most cases because the browser waits for the response in the pipe, and the
709 // thread has time to finish while this response is being processed and the browser is
710 // disposing all its stuff.
711 std::thread([pipe]()
712 {
713 ClientThread(pipe.get());
714 }).detach();
715 }
716 catch(const std::system_error& ex)
717 {
718 DebugException(ex);
719 return 1;
720 }
721 catch (const std::runtime_error& e)
722 {
723 DebugException(e);
724 return 1;
725 }
726 }
727 });
507 728
508 // TODO: we should wait for the finishing of the thread before exiting fro m this function. 729 int retValue = _AtlModule.WinMain(cmdShow);
509 // It works now in most cases because the browser waits for the response i n the pipe, and the 730 if (communicationThread.joinable())
510 // thread has time to finish while this response is being processed and th e browser is 731 {
511 // disposing all its stuff. 732 communicationThread.join();
512 std::thread([pipe]()
513 {
514 ClientThread(pipe.get());
515 }).detach();
516 }
517 catch(const std::system_error& ex)
518 {
519 DebugException(ex);
520 return 1;
521 }
522 catch (const std::runtime_error& e)
523 {
524 DebugException(e);
525 return 1;
526 }
527 } 733 }
528 734
529 return 0; 735 return retValue;
530 } 736 }
OLDNEW

Powered by Google App Engine
This is Rietveld