message_pump_glib_x.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/message_pump_glib_x.h"
6
7#include <gdk/gdkx.h>
8#include <X11/Xlib.h>
9
10#include "base/message_pump_glib_x_dispatch.h"
11
12namespace {
13
14gboolean PlaceholderDispatch(GSource* source,
15                             GSourceFunc cb,
16                             gpointer data) {
17  return TRUE;
18}
19
20}  // namespace
21
22namespace base {
23
24MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
25    gdksource_(NULL),
26    dispatching_event_(false),
27    capture_x_events_(0),
28    capture_gdk_events_(0) {
29  gdk_event_handler_set(&EventDispatcherX, this, NULL);
30
31  InitializeEventsToCapture();
32}
33
34MessagePumpGlibX::~MessagePumpGlibX() {
35}
36
37bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
38  GdkDisplay* gdisp = gdk_display_get_default();
39  Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
40  if (XPending(display)) {
41    XEvent xev;
42    XPeekEvent(display, &xev);
43    if (capture_x_events_[xev.type]) {
44      XNextEvent(display, &xev);
45
46      bool processed = static_cast<MessagePumpGlibXDispatcher*>
47          (GetDispatcher())->Dispatch(&xev);
48
49      if (!processed) {
50        DLOG(WARNING) << "Event (" << xev.type << ") not handled.";
51      }
52    } else {
53      // TODO(sad): A couple of extra events can still sneak in during this.
54      // Those should be sent back to the X queue from the dispatcher
55      // EventDispatcherX.
56      g_main_context_iteration(context, FALSE);
57    }
58  }
59
60  bool retvalue;
61  if (gdksource_) {
62    // Replace the dispatch callback of the GDK event source temporarily so that
63    // it doesn't read events from X.
64    gboolean (*cb)(GSource*, GSourceFunc, void*) =
65        gdksource_->source_funcs->dispatch;
66    gdksource_->source_funcs->dispatch = PlaceholderDispatch;
67
68    dispatching_event_ = true;
69    retvalue = g_main_context_iteration(context, block);
70    dispatching_event_ = false;
71
72    gdksource_->source_funcs->dispatch = cb;
73  } else {
74    retvalue = g_main_context_iteration(context, block);
75  }
76
77  return retvalue;
78}
79
80void MessagePumpGlibX::InitializeEventsToCapture(void) {
81  // TODO(sad): Decide which events we want to capture and update the tables
82  // accordingly.
83  capture_x_events_[KeyPress] = true;
84  capture_gdk_events_[GDK_KEY_PRESS] = true;
85
86  capture_x_events_[KeyRelease] = true;
87  capture_gdk_events_[GDK_KEY_RELEASE] = true;
88
89  capture_x_events_[ButtonPress] = true;
90  capture_gdk_events_[GDK_BUTTON_PRESS] = true;
91
92  capture_x_events_[ButtonRelease] = true;
93  capture_gdk_events_[GDK_BUTTON_RELEASE] = true;
94
95  capture_x_events_[MotionNotify] = true;
96  capture_gdk_events_[GDK_MOTION_NOTIFY] = true;
97}
98
99void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
100  MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data);
101
102  if (!pump_x->gdksource_) {
103    pump_x->gdksource_ = g_main_current_source();
104  } else if (!pump_x->IsDispatchingEvent()) {
105    if (event->type != GDK_NOTHING &&
106        pump_x->capture_gdk_events_[event->type]) {
107      // TODO(sad): An X event is caught by the GDK handler. Put it back in the
108      // X queue so that we catch it in the next iteration. When done, the
109      // following DLOG statement will be removed.
110      DLOG(WARNING) << "GDK received an event it shouldn't have";
111    }
112  }
113
114  pump_x->DispatchEvents(event);
115}
116
117}  // namespace base
118