- add sources.
[platform/framework/web/crosswalk.git] / src / ozone / wayland / dispatcher.cc
1 // Copyright 2013 Intel Corporation. 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 "ozone/wayland/dispatcher.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/epoll.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <wayland-client.h>
13
14 #include "base/bind.h"
15 #include "ozone/wayland/dispatcher_delegate.h"
16 #include "ozone/wayland/display.h"
17
18 namespace ozonewayland {
19 WaylandDispatcher* WaylandDispatcher::instance_ = NULL;
20
21 // os-compatibility
22 extern "C" {
23 int osEpollCreateCloExec(void);
24
25 static int setCloExecOrClose(int fd) {
26   long flags;
27
28   if (fd == -1)
29     return -1;
30
31   flags = fcntl(fd, F_GETFD);
32   if (flags == -1)
33     goto err;
34
35   if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
36     goto err;
37
38   return fd;
39
40   err:
41     close(fd);
42     return -1;
43 }
44
45 int osEpollCreateCloExec(void) {
46   int fd;
47
48 #ifdef EPOLL_CLOEXEC
49   fd = epoll_create1(EPOLL_CLOEXEC);
50   if (fd >= 0)
51     return fd;
52   if (errno != EINVAL)
53     return -1;
54 #endif
55
56   fd = epoll_create(1);
57   return setCloExecOrClose(fd);
58 }
59 }  // os-compatibility
60
61 void WaylandDispatcher::MotionNotify(float x, float y) {
62   DCHECK(delegate_);
63   delegate_->MotionNotify(x, y);
64 }
65
66 void WaylandDispatcher::ButtonNotify(unsigned handle,
67                                      int state,
68                                      int flags,
69                                      float x,
70                                      float y) {
71   DCHECK(delegate_);
72   delegate_->ButtonNotify(handle, state, flags, x, y);
73 }
74
75 void WaylandDispatcher::AxisNotify(float x,
76                                    float y,
77                                    float xoffset,
78                                    float yoffset) {
79   DCHECK(delegate_);
80   delegate_->AxisNotify(x, y, xoffset, yoffset);
81 }
82
83 void WaylandDispatcher::PointerEnter(unsigned handle, float x, float y) {
84   DCHECK(delegate_);
85   delegate_->PointerEnter(handle, x, y);
86 }
87
88 void WaylandDispatcher::PointerLeave(unsigned handle, float x, float y) {
89   DCHECK(delegate_);
90   delegate_->PointerLeave(handle, x, y);
91 }
92
93 void WaylandDispatcher::KeyNotify(unsigned state,
94                                   unsigned code,
95                                   unsigned modifiers) {
96   DCHECK(delegate_);
97   delegate_->KeyNotify(state, code, modifiers);
98 }
99
100 void WaylandDispatcher::OutputSizeChanged(unsigned width, unsigned height) {
101   DCHECK(delegate_);
102   delegate_->OutputSizeChanged(width, height);
103 }
104
105 void WaylandDispatcher::PostTask(Task type) {
106   if (!IsRunning() || !active_)
107     return;
108
109   DCHECK(delegate_);
110
111   switch (type) {
112     case(Flush):
113       message_loop_proxy()->PostTask(
114           FROM_HERE, base::Bind(&WaylandDispatcher::HandleFlush));
115       break;
116     case(Poll):
117       DCHECK(epoll_fd_);
118       message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
119           &WaylandDispatcher::DisplayRun, this));
120   default:
121     break;
122   }
123 }
124
125 void WaylandDispatcher::SetWindowChangeObserver(
126     WindowChangeObserver* observer) {
127   DCHECK(delegate_);
128   delegate_->SetWindowChangeObserver(observer);
129 }
130
131 void WaylandDispatcher::SetDelegate(WaylandDispatcherDelegate* delegate) {
132   delegate_ = delegate;
133   SetActive(true);
134 }
135
136 void WaylandDispatcher::SetActive(bool active) {
137   DCHECK(delegate_);
138   active_ = active;
139   delegate_->SetActive(active);
140 }
141
142 WaylandDispatcher::WaylandDispatcher(int fd)
143     : Thread("WaylandDispatcher"),
144       active_(false),
145       epoll_fd_(0),
146       display_fd_(fd),
147       delegate_(NULL) {
148   instance_ = this;
149   if (display_fd_) {
150     epoll_fd_ = osEpollCreateCloExec();
151     struct epoll_event ep;
152     ep.events = EPOLLIN | EPOLLOUT;
153     ep.data.ptr = 0;
154     epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, display_fd_, &ep);
155   }
156
157   Options options;
158   options.message_loop_type = base::MessageLoop::TYPE_IO;
159   StartWithOptions(options);
160   SetPriority(base::kThreadPriority_Background);
161 }
162
163 WaylandDispatcher::~WaylandDispatcher() {
164   active_ = false;
165   if (delegate_)
166     delete delegate_;
167
168   Stop();
169
170   if (epoll_fd_) {
171     close(epoll_fd_);
172     epoll_fd_ = 0;
173   }
174
175   instance_ = NULL;
176 }
177
178 void WaylandDispatcher::HandleFlush() {
179   wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();
180
181   while (wl_display_prepare_read(waylandDisp) != 0)
182     wl_display_dispatch_pending(waylandDisp);
183
184   wl_display_flush(waylandDisp);
185   wl_display_read_events(waylandDisp);
186   wl_display_dispatch_pending(waylandDisp);
187 }
188
189 void  WaylandDispatcher::DisplayRun(WaylandDispatcher* data) {
190   struct epoll_event ep[16];
191   int i, count, ret;
192   // Adopted from:
193   // http://cgit.freedesktop.org/wayland/weston/tree/clients/window.c#n5531.
194   while (1) {
195     wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();
196     wl_display_dispatch_pending(waylandDisp);
197
198     if (!data->active_)
199       break;
200
201     ret = wl_display_flush(waylandDisp);
202     if (ret < 0 && errno == EAGAIN) {
203       ep[0].events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
204       epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &ep[0]);
205     } else if (ret < 0) {
206       break;
207     }
208
209     count = epoll_wait(data->epoll_fd_, ep, 16, -1);
210     if (!data->active_)
211       break;
212
213     for (i = 0; i < count; i++) {
214       int ret;
215       uint32_t event = ep[i].events;
216
217       if (event & EPOLLERR || event & EPOLLHUP)
218         return;
219
220       if (event & EPOLLIN) {
221         ret = wl_display_dispatch(waylandDisp);
222         if (ret == -1)
223           return;
224       }
225
226       if (event & EPOLLOUT) {
227         ret = wl_display_flush(waylandDisp);
228         if (ret == 0) {
229           struct epoll_event eps;
230           memset(&eps, 0, sizeof(eps));
231
232           eps.events = EPOLLIN | EPOLLERR | EPOLLHUP;
233           epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &eps);
234         } else if (ret == -1 && errno != EAGAIN) {
235           return;
236         }
237       }
238     }
239   }
240 }
241
242 }  // namespace ozonewayland