Thursday, May 30, 2013

content_shell with aura : XWindow and event loop

Let's look around how content_shell with aura creates XWindow and handle X input events.

Before reading this article, plz read http://luxtella.blogspot.de/2013/05/chromium-launching-process.html

Create MessagePump needed for TYPE_UI MessageLoops.

aura uses g_main_context for event source. why does aura depend on glib although creating pure X Window. It is just because of convenience. aura developers just did not want to reinvent timer and event source. let's look at how to integrate g_main_context and XDisplay events.

MessagePumpGlib plays a role to create g_main_context and event sources to receive tasks from another thread. MessagePumpGlib is reused by MessagePumpGtk.
MessagePumpGlib::MessagePumpGlib()
    : state_(NULL),
      context_(g_main_context_default()),
      wakeup_gpollfd_(new GPollFD) {
  ...
}

Before looking at MessagePumpAuraX11, let's look at MessagePumpGtk.
MessagePumpGtk plays a role to dispatch input events to main context.
MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() {
  gdk_event_handler_set(&EventDispatcher, this, NULL);
}

So we can expect MessagePumpAuraX11's role is to dispatching X Display events to main loop. how to cast magic?
InitXSource() is crucial. It creates g event source monitoring X Display. When g_main_context handles the event source, XSourceDispatch() will be called. how smart!
MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(),
    x_source_(NULL) {
  InitializeXInput2();
  InitializeXkb();
  InitXSource();

  // Can't put this in the initializer list because g_xdisplay may not exist
  // until after InitXSource().
  x_root_window_ = DefaultRootWindow(g_xdisplay);
}

void MessagePumpAuraX11::InitXSource() {
  Display* display = GetDefaultXDisplay();
  x_poll_.reset(new GPollFD());
  x_poll_->fd = ConnectionNumber(display);
  x_poll_->events = G_IO_IN;

  x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
  g_source_add_poll(x_source_, x_poll_.get());
  g_source_set_can_recurse(x_source_, TRUE);
  g_source_set_callback(x_source_, NULL, this, NULL);
  g_source_attach(x_source_, g_main_context_default());
}

GSourceFuncs XSourceFuncs = {
  XSourcePrepare,
  XSourceCheck,
  XSourceDispatch,
  NULL
};

gboolean XSourceDispatch(GSource* source,
                         GSourceFunc unused_func,
                         gpointer data) {
  base::MessagePumpAuraX11* pump = static_cast{base::MessagePumpAuraX11*}(data);
  return pump->DispatchXEvents();
}
base::MessagePumpGlib::MessagePumpGlib() at message_pump_glib.cc:142 0x4d5ec6 
base::MessagePumpAuraX11::MessagePumpAuraX11() at message_pump_aurax11.cc:132 0x4d8510 
base::MessageLoop::MessageLoop() at message_loop.cc:182 0x471fbb 
content::BrowserMainLoop::MainMessageLoopStart() at browser_main_loop.cc:370 0x81aa6e 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:94 0x6010f0 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Main loop

MessagePumpGlib::RunWithDispatcher() is main loop. Chromium does not use glib main loop because chromium want to run chromium's own tasks without starvation.
X Display input events are handled by g_main_context_iteration(context_, block), because the input events are bound to glib event source.
void MessagePumpGlib::RunWithDispatcher(Delegate* delegate,
                                        MessagePumpDispatcher* dispatcher) {
  ..
  for (;;) {
    ..
    more_work_is_plausible = g_main_context_iteration(context_, block);
    ..
    more_work_is_plausible |= state_->delegate->DoWork();
    ..
    more_work_is_plausible |= state_->delegate->DoDelayedWork(&delayed_work_time_);
    ..
    more_work_is_plausible = state_->delegate->DoIdleWork();
    ..
  }
  ..
}
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:199 0x4d6282 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x4d67be 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x47385a 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x473704 
base::RunLoop::Run() at run_loop.cc:45 0x497abc 
content::BrowserMainLoop::MainMessageLoopRun() at browser_main_loop.cc:873 0x81c6d7 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:571 0x81b85e 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:125 0x6012bc 
ShellBrowserMain() at shell_browser_main.cc:180 0x43cfe3 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Create WebContentesViewAura.

This callstack is almost same to it of content_shell gtk. aura::Window is not related to native window or widget. It is something like cc::Layer + window event handler.

aura::Window::Window() at window.cc:51 0x51cfaa 
content::WebContentsViewAura::CreateView() at web_contents_view_aura.cc:944 0x7dab1b 
content::WebContentsImpl::Init() at web_contents_impl.cc:1,193 0x7bdcae 
content::WebContentsImpl::CreateWithOpener() at web_contents_impl.cc:405 0x7b897a 
content::WebContents::Create() at web_contents_impl.cc:262 0x7b78ed 
content::Shell::CreateNewWindow() at shell.cc:165 0x44db67 
content::ShellBrowserMainParts::PreMainMessageLoopRun() at shell_browser_main_parts.cc:132 0x453289 
content::BrowserMainLoop::CreateThreads() at browser_main_loop.cc:554 0x81b792 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:112 0x601108 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

On the other hands, when loading another page, new RenderWidgetHostViewAura is created and new aura::Window is also created.
aura::Window::Window() at window.cc:51 0x51cfaa 
content::RenderWidgetHostViewAura::RenderWidgetHostViewAura() at render_widget_host_view_aura.cc:626 0x75f75d 
content::RenderWidgetHostView::CreateViewForWidget() at render_widget_host_view_aura.cc:2,992 0x769eb5 
content::WebContentsViewAura::CreateViewForWidget() at web_contents_view_aura.cc:992 0x7dae49 
content::WebContentsImpl::CreateRenderViewForRenderManager() at web_contents_impl.cc:3,481 0x7c7895 
content::RenderViewHostManager::InitRenderView() at render_view_host_manager.cc:663 0x9c7720 
content::RenderViewHostManager::Navigate() at render_view_host_manager.cc:140 0x9c5a6d 
...

Create XWindow and RootWindow

Create XWindow

DesktopRootWindowHostX11 creates XWindow, installs dispatcher for XWindow (XDisplay receives all input events for all XWindows), and requests Input events to XServer.
void DesktopRootWindowHostX11::InitX11Window(
    const Widget::InitParams& params) {
  ..
  xwindow_ = XCreateWindow(
      xdisplay_, x_root_window_,
      ..
      &swa);
  base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);

  // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().

  long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
                    KeyPressMask | KeyReleaseMask |
                    EnterWindowMask | LeaveWindowMask |
                    ExposureMask | VisibilityChangeMask |
                    StructureNotifyMask | PropertyChangeMask |
                    PointerMotionMask;
  XSelectInput(xdisplay_, xwindow_, event_mask);
  ..
}
views::DesktopRootWindowHostX11::InitX11Window() at desktop_root_window_host_x11.cc:157 0xce36cb 
views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:357 0xce45c1 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:239 0xcdf031 
views::Widget::Init() at widget.cc:374 0xcf5219 
views::Widget::CreateWindowWithBounds() at widget.cc:239 0xcf4b5d 
content::Shell::PlatformCreateWindow() at shell_aura.cc:348 0x450379 
content::Shell::CreateShell() at shell.cc:105 0x44d753 
content::Shell::CreateNewWindow() at shell.cc:166 0x44db82 
content::ShellBrowserMainParts::PreMainMessageLoopRun() at shell_browser_main_parts.cc:132 0x453289 
content::BrowserMainLoop::CreateThreads() at browser_main_loop.cc:554 0x81b792 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:112 0x601108 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Create RootWindow

DesktopRootWindowHostX11 creates aura::RootWindow. RootWindow owns Compositor. FYI, chrome can create multi RootWindows. For example, context menu requires a XWindow and RootWindow.
RootWindow::RootWindow(const CreateParams& params)
    : Window(NULL),
      ..
      repostable_event_factory_(this) {
  ..
  compositor_.reset(new ui::Compositor(this, host_->GetAcceleratedWidget()));
  ..
}
aura::RootWindow::RootWindow() at root_window.cc:162 0x512ef4 
views::DesktopRootWindowHostX11::InitRootWindow() at desktop_root_window_host_x11.cc:230 0xce3add 
views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:358 0xce45d4 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:239 0xcdf031 
....

Handle mouse event

XDisplay input event is dispatched to MessagePumpAuraX11::DispatchXEvents(), because XDisplay events are bound with glib event source. Refer to "Create MessagePump needed for TYPE_UI MessageLoops."
DispatchXEvents() consumes all pending X events.
bool MessagePumpAuraX11::DispatchXEvents() {
  ...
  while (XPending(display)) {
    XEvent xev;
    XNextEvent(display, &xev);
    if (dispatcher && ProcessXEvent(dispatcher, &xev))
      return TRUE;
  }
  return TRUE;
}

DesktopRootWindowHostX11 installed dispatcher into MessagePumpAuraX11, so X event is dispatched to DesktopRootWindowHostX11 that owns specific X Window.

DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) converts X Event to ui::Event.

And then finally aura::RootWindow::OnHostMouseEvent() handles ui::MouseEvent.
aura::RootWindow::OnHostMouseEvent() at root_window.cc:902 0x516c2d 
views::DesktopRootWindowHostX11::DispatchMouseEvent() at desktop_root_window_host_x11.cc:560 0xce540b 
views::DesktopRootWindowHostX11::Dispatch() at desktop_root_window_host_x11.cc:1,075 0xce7632 
base::MessagePumpAuraX11::Dispatch() at message_pump_aurax11.cc:304 0x4d92cb 
base::MessagePumpAuraX11::ProcessXEvent() at message_pump_aurax11.cc:249 0x4d8f09 
base::MessagePumpAuraX11::DispatchXEvents() at message_pump_aurax11.cc:191 0x4d8876 
() at message_pump_aurax11.cc:33 0x4d8002 
g_main_dispatch() at gmain.c:2,715 0x7ffff6973ab5 
g_main_context_dispatch() at gmain.c:3,219 0x7ffff6973ab5 
g_main_context_iterate() at gmain.c:3,290 0x7ffff6973de8 
g_main_context_iteration() at gmain.c:3,351 0x7ffff6973ea4 
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:199 0x4d6282 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x4d67be 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x47385a 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x473704 
base::RunLoop::Run() at run_loop.cc:45 0x497abc 
content::BrowserMainLoop::MainMessageLoopRun() at browser_main_loop.cc:873 0x81c6d7 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:571 0x81b85e 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:125 0x6012bc 
ShellBrowserMain() at shell_browser_main.cc:180 0x43cfe3 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

No comments:

Post a Comment