Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / xinput_hierarchy_changed_event_listener.cc
1 // Copyright (c) 2012 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 "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
6
7 #include <X11/Xlib.h>
8 #include <X11/extensions/XInput2.h>
9
10 #include "chromeos/ime/input_method_manager.h"
11 #include "chromeos/ime/xkeyboard.h"
12 #include "ui/base/x/x11_util.h"
13
14 namespace chromeos {
15 namespace {
16
17 // Gets the major opcode for XInput2. Returns -1 on error.
18 int GetXInputOpCode() {
19   static const char kExtensionName[] = "XInputExtension";
20   int xi_opcode = -1;
21   int event;
22   int error;
23
24   if (!XQueryExtension(
25           gfx::GetXDisplay(), kExtensionName, &xi_opcode, &event, &error)) {
26     VLOG(1) << "X Input extension not available: error=" << error;
27     return -1;
28   }
29   return xi_opcode;
30 }
31
32 // Checks the |event| and asynchronously sets the XKB layout when necessary.
33 void HandleHierarchyChangedEvent(
34     XIHierarchyEvent* event,
35     ObserverList<DeviceHierarchyObserver>* observer_list) {
36   if (!(event->flags & (XISlaveAdded | XISlaveRemoved)))
37     return;
38
39   bool update_keyboard_status = false;
40   for (int i = 0; i < event->num_info; ++i) {
41     XIHierarchyInfo* info = &event->info[i];
42     if ((info->flags & XISlaveAdded) && (info->use == XIFloatingSlave)) {
43       FOR_EACH_OBSERVER(DeviceHierarchyObserver,
44                         *observer_list,
45                         DeviceAdded(info->deviceid));
46       update_keyboard_status = true;
47     } else if (info->flags & XISlaveRemoved) {
48       // Can't check info->use here; it appears to always be 0.
49       FOR_EACH_OBSERVER(DeviceHierarchyObserver,
50                         *observer_list,
51                         DeviceRemoved(info->deviceid));
52     }
53   }
54
55   if (update_keyboard_status) {
56     chromeos::input_method::InputMethodManager* input_method_manager =
57         chromeos::input_method::InputMethodManager::Get();
58     chromeos::input_method::XKeyboard* xkeyboard =
59         input_method_manager->GetXKeyboard();
60     xkeyboard->ReapplyCurrentModifierLockStatus();
61     xkeyboard->ReapplyCurrentKeyboardLayout();
62   }
63 }
64
65 }  // namespace
66
67 // static
68 XInputHierarchyChangedEventListener*
69 XInputHierarchyChangedEventListener::GetInstance() {
70   return Singleton<XInputHierarchyChangedEventListener>::get();
71 }
72
73 XInputHierarchyChangedEventListener::XInputHierarchyChangedEventListener()
74     : stopped_(false),
75       xiopcode_(GetXInputOpCode()) {
76   Init();
77 }
78
79 XInputHierarchyChangedEventListener::~XInputHierarchyChangedEventListener() {
80   Stop();
81 }
82
83 void XInputHierarchyChangedEventListener::Stop() {
84   if (stopped_)
85     return;
86
87   StopImpl();
88   stopped_ = true;
89   xiopcode_ = -1;
90 }
91
92 void XInputHierarchyChangedEventListener::AddObserver(
93     DeviceHierarchyObserver* observer) {
94   observer_list_.AddObserver(observer);
95 }
96
97 void XInputHierarchyChangedEventListener::RemoveObserver(
98     DeviceHierarchyObserver* observer) {
99   observer_list_.RemoveObserver(observer);
100 }
101
102 bool XInputHierarchyChangedEventListener::ProcessedXEvent(XEvent* xevent) {
103   if ((xevent->xcookie.type != GenericEvent) ||
104       (xevent->xcookie.extension != xiopcode_)) {
105     return false;
106   }
107
108   XGenericEventCookie* cookie = &(xevent->xcookie);
109   bool handled = false;
110
111   if (cookie->evtype == XI_HierarchyChanged) {
112     XIHierarchyEvent* event = static_cast<XIHierarchyEvent*>(cookie->data);
113     HandleHierarchyChangedEvent(event, &observer_list_);
114     if (event->flags & XIDeviceEnabled || event->flags & XIDeviceDisabled)
115       NotifyDeviceHierarchyChanged();
116     handled = true;
117   } else if (cookie->evtype == XI_KeyPress || cookie->evtype == XI_KeyRelease) {
118     XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(cookie->data);
119     if (xiev->deviceid == xiev->sourceid) {
120       FOR_EACH_OBSERVER(DeviceHierarchyObserver,
121                         observer_list_,
122                         DeviceKeyPressedOrReleased(xiev->deviceid));
123       handled = true;
124     }
125   }
126
127   return handled;
128 }
129
130 void XInputHierarchyChangedEventListener::NotifyDeviceHierarchyChanged() {
131   FOR_EACH_OBSERVER(DeviceHierarchyObserver,
132                     observer_list_,
133                     DeviceHierarchyChanged());
134 }
135
136 }  // namespace chromeos