summaryrefslogtreecommitdiffstats
path: root/ui/aura/dispatcher_linux.cc
blob: e6e70d0d4f091bb26f13cb8ea7cd1aa892f211b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/aura/dispatcher_linux.h"

#include <X11/extensions/XInput2.h>

#include "ui/base/events.h"

namespace {

// Pro-processes an XEvent before it is handled. The pre-processings include:
// - Map Alt+Button1 to Button3
void PreprocessXEvent(XEvent* xevent) {
  if (!xevent || xevent->type != GenericEvent)
    return;

  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
  if ((xievent->evtype == XI_ButtonPress ||
      xievent->evtype == XI_ButtonRelease) &&
        (xievent->mods.effective & Mod1Mask) &&
        xievent->detail == 1) {
    xievent->mods.effective &= ~Mod1Mask;
    xievent->detail = 3;
    if (xievent->evtype == XI_ButtonRelease) {
      // On the release clear the left button from the existing state and the
      // mods, and set the right button.
      XISetMask(xievent->buttons.mask, 3);
      XIClearMask(xievent->buttons.mask, 1);
      xievent->mods.effective &= ~Button1Mask;
    }
  }
}

}  // namespace

namespace aura {

DispatcherLinux::DispatcherLinux() {
  base::MessagePumpX::SetDefaultDispatcher(this);
}

DispatcherLinux::~DispatcherLinux() {
  base::MessagePumpX::SetDefaultDispatcher(NULL);
}

void DispatcherLinux::WindowDispatcherCreated(
    ::Window window,
    MessageLoop::Dispatcher* dispatcher) {
  dispatchers_.insert(std::make_pair(window, dispatcher));
}

void DispatcherLinux::WindowDispatcherDestroying(::Window window) {
  dispatchers_.erase(window);
}

bool DispatcherLinux::Dispatch(const base::NativeEvent& xev) {
  PreprocessXEvent(xev);

  // XI_HierarchyChanged events are special. There is no window associated with
  // these events. So process them directly from here.
  if (xev->type == GenericEvent &&
      xev->xgeneric.evtype == XI_HierarchyChanged) {
    ui::UpdateDeviceList();
    return true;
  }

  // MappingNotify events (meaning that the keyboard or pointer buttons have
  // been remapped) aren't associated with a window; send them to all
  // dispatchers.
  if (xev->type == MappingNotify) {
    for (DispatchersMap::const_iterator it = dispatchers_.begin();
         it != dispatchers_.end(); ++it) {
      it->second->Dispatch(xev);
    }
    return true;
  }

  MessageLoop::Dispatcher* dispatcher = GetDispatcherForXEvent(xev);
  return dispatcher ? dispatcher->Dispatch(xev) : true;
}

MessageLoop::Dispatcher* DispatcherLinux::GetDispatcherForXEvent(
    XEvent* xev) const {
  ::Window window = xev->xany.window;
  if (xev->type == GenericEvent) {
    XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    window = xievent->event;
  }
  DispatchersMap::const_iterator it = dispatchers_.find(window);
  return it != dispatchers_.end() ? it->second : NULL;
}

MessageLoop::Dispatcher* CreateDispatcher() {
  return new DispatcherLinux;
}

}  // namespace aura