Merge "Added cumulative statistics option and actual call count to GLES call debug...
[platform/core/uifw/dali-adaptor.git] / adaptors / wayland / wayland-manager.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 // CLASS HEADER
18 #include "wayland-manager.h"
19
20 // EXTERNAL INCLUDES
21 #include <cstring>
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <base/interfaces/window-event-interface.h>
26 #include <base/interfaces/performance-interface.h>
27
28
29 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace Adaptor
34 {
35
36 namespace
37 {
38
39 const int NO_EVENTS_ALREADY_IN_QUEUE = 0;
40
41
42 void ShellSurfacePing( void* data, struct wl_shell_surface* shell_surface, uint32_t serial)
43 {
44   // The ping event comes from the compositor to checks if we're still alive.
45   wl_shell_surface_pong(shell_surface, serial);
46 }
47
48 void ShellSurfaceConfigure( void* data, struct wl_shell_surface* shell_surface, uint32_t edges, int32_t width, int32_t height)
49 {
50 }
51
52 const struct wl_shell_surface_listener ShellSurfaceListener =
53 {
54   ShellSurfacePing,
55   ShellSurfaceConfigure,
56 };
57
58
59 void XdgShellPing( void* data, Dali::WlXdgShell* shell, uint32_t serial)
60 {
61   // The ping event comes from the compositor to checks if we're still alive.
62   xdg_shell_pong( shell, serial);
63 }
64
65 struct xdg_shell_listener XdgShellListener=
66 {
67   XdgShellPing,
68 };
69
70
71 void RegistryGlobalCallback( void *data,
72            struct wl_registry *wlRegistry,
73            uint32_t name,
74            const char *interface,
75            uint32_t version)
76 {
77
78   WaylandManager* client = static_cast<   WaylandManager* >( data );
79
80   if (strcmp( interface, wl_compositor_interface.name) == 0)
81   {
82     client->mCompositor = static_cast<Dali::WlCompositor*>(wl_registry_bind( wlRegistry, name , &wl_compositor_interface, version ));
83   }
84   else if( strcmp( interface, wl_seat_interface.name) == 0  )
85   {
86     // register for seat callbacks and add a new seat to the input manager
87     Dali::WlSeat* seatInterface = static_cast<Dali::WlSeat*>( wl_registry_bind( wlRegistry, name,  &wl_seat_interface, version ));
88
89     client->mInputManager.AddSeatListener( seatInterface );
90   }
91   else if ( strcmp( interface, wl_output_interface.name ) == 0)
92   {
93     // get the interface and add the listener
94     Dali::WlOutput* output =  static_cast< Dali::WlOutput* >(wl_registry_bind(wlRegistry, name, &wl_output_interface, version));
95     client->mCompositorOutput.AddListener( output );
96   }
97   else if (strcmp(interface, wl_shell_interface.name) == 0)
98   {
99     client->mShell = static_cast<Dali::WlShell*>(wl_registry_bind( wlRegistry, name , &wl_shell_interface, version));
100   }
101   else if ( strcmp( interface, xdg_shell_interface.name ) == 0)
102   {
103     client->mXdgShell  =  static_cast< struct xdg_shell* >(wl_registry_bind(wlRegistry, name, &xdg_shell_interface, version));
104     // without this line Tizen 3 reports...
105     // xdg_shell@7: error 0: Must call use_unstable_version first
106     xdg_shell_use_unstable_version(client->mXdgShell, 5);
107   }
108
109
110 }
111
112
113 void RegistryGlobalCallbackRemove(void *data, struct wl_registry *registry, uint32_t id)
114 {
115   // occurs when a device is unplugged
116 }
117
118 const struct wl_registry_listener RegistryListener =
119 {
120    RegistryGlobalCallback,
121    RegistryGlobalCallbackRemove,
122 };
123
124 } //unnamed namespace
125
126 WaylandManager::WaylandManager()
127 :mDisplay( NULL ),
128  mShell( NULL ),
129  mCompositor( NULL ),
130  mDisplayFileDescriptor( 0 ),
131  mFileDescriptorMonitor( NULL ),
132  mXdgShell( NULL ),
133  mSurface( NULL ),
134  mShellSurface( NULL ),
135  mXdgSurface( NULL )
136 {
137 }
138 WaylandManager::~WaylandManager()
139 {
140   if( mXdgShell)
141   {
142     xdg_shell_destroy( mXdgShell );
143   }
144   if( mShell )
145   {
146     wl_shell_destroy( mShell );
147   }
148   if( mCompositor )
149   {
150     wl_compositor_destroy( mCompositor );
151   }
152   if( mDisplay )
153   {
154     wl_display_disconnect( mDisplay );
155   }
156
157   delete mFileDescriptorMonitor;
158 }
159
160 void WaylandManager::Initialise()
161 {
162   if( mDisplay )
163   {
164     return;
165   }
166   // Connect to a Wayland socket on the Wayland server/
167   // NULL = use default display aka "wayland-0"
168   // returns a new display context object
169
170   mDisplay =  wl_display_connect( NULL );
171
172   DALI_ASSERT_ALWAYS( mDisplay && "wl_display_connect failed");
173
174   // Monitor the display file descriptor used to communicate with Wayland server
175   InstallFileDescriptorMonitor();
176
177   // Get the interfaces to compositor / shell etc
178   GetWaylandInterfaces();
179
180 }
181 void WaylandManager::ReadAndDispatchEvents()
182 {
183   // Wayland client uses a single file descriptor to communicate with the compositor.
184   // Because DALi can have multiple client threads ( event thread for input, render thread for Tizen buffer management / TPL )
185   // it has to use the Wayland client thread safe API to prevent a dead lock
186
187   // prepare_read announces the calling thread's intention to read from the file descriptor
188   // If there is already events queued up in the default queue, then dispatch those first
189   while( wl_display_prepare_read( mDisplay ) != NO_EVENTS_ALREADY_IN_QUEUE )
190   {
191     // dispatch the event, e.g. a touch event or a clipboard event
192     wl_display_dispatch_pending( mDisplay );
193   }
194
195   // At this point the default queue is empty.
196   // We read data from the file descriptor in their respective queues
197   // This is thread safe. No other threads will read from the fd and queue events during this operation.
198   int ret = wl_display_read_events( mDisplay );
199
200   if( ret == 0 )
201   {
202     // dispatch the events from the default queue
203     wl_display_dispatch_pending( mDisplay );
204   }
205   else
206   {
207     DALI_LOG_ERROR("wl_display_read_events error");
208   }
209
210 }
211 void WaylandManager::AssignWindowEventInterface( WindowEventInterface* eventInterface)
212 {
213   mInputManager.AssignWindowEventInterface( eventInterface );
214 }
215 void WaylandManager::GetWaylandInterfaces()
216 {
217   // get and listen to the registry
218   WlRegistry* registry = wl_display_get_registry( mDisplay );
219
220   wl_registry_add_listener( registry, &RegistryListener, this);
221
222   // adaptor wants the DPI instantly, so we have wait for the data
223   while( !mCompositorOutput.DataReady() )
224   {
225     // This is the first and last time we use wl_display_roundtrip as its not thread safe
226     // however at this point we haven't started rendering it is safe.
227     wl_display_flush( mDisplay );
228     wl_display_roundtrip( mDisplay );
229   }
230   wl_registry_destroy( registry );
231
232 }
233
234 void WaylandManager::InstallFileDescriptorMonitor()
235 {
236   // get the file descriptor
237   mDisplayFileDescriptor = wl_display_get_fd( mDisplay );
238
239   // create the callback that gets triggered when a read / write event occurs
240   CallbackBase* callback =  MakeCallback( this, &WaylandManager::FileDescriptorCallback);
241
242   // monitor read and write events
243   int events = FileDescriptorMonitor::FD_READABLE;
244
245   mFileDescriptorMonitor = new FileDescriptorMonitor( mDisplayFileDescriptor, callback, events );
246
247 }
248
249 void WaylandManager::FileDescriptorCallback( FileDescriptorMonitor::EventType eventTypeMask )
250 {
251   if( eventTypeMask & FileDescriptorMonitor::FD_READABLE )
252   {
253     // read and dispatch events
254     ReadAndDispatchEvents();
255   }
256 }
257
258
259 void WaylandManager::CreateSurface( Dali::Wayland::Window& window )
260 {
261   // Create the surface
262   // A Wayland surface is a rectangular area that is displayed on the screen.
263   // It has a location, size and pixel contents.
264
265   mSurface = wl_compositor_create_surface( mCompositor );
266
267   DALI_ASSERT_ALWAYS( mSurface && "wl_compositor_create_surface failed" );
268
269   // keep track of the surface id
270   window.mSurfaceId = wl_proxy_get_id( reinterpret_cast<struct wl_proxy *>( mSurface ));
271
272   // A surface in Wayland needs to be assigned a role.
273   // This gives the surface the role of a shell surface.
274   // It allows the surface to be treated like a toplevel, fullscreen or popup window.
275   // which can be moved, resize or maximized and have associate metadata like title and class.
276   // Try the xdg shell first. XDG is a designed to create a desktop shell with features like minimise etc.
277   if( mXdgShell )
278   {
279     mXdgSurface = xdg_shell_get_xdg_surface( mXdgShell, mSurface );
280
281     DALI_ASSERT_ALWAYS( mXdgSurface&& "xdg_shell_get_xdg_surface failed" );
282
283     if( window.mTitle.length() )
284     {
285       xdg_surface_set_title(  mXdgSurface, window.mTitle.c_str() );
286     }
287     xdg_shell_add_listener( mXdgShell, &XdgShellListener, 0);
288   }
289   else
290   {
291     // try the generic Wayland Shell
292     mShellSurface = wl_shell_get_shell_surface( mShell, mSurface );
293     DALI_ASSERT_ALWAYS( mShellSurface && "wl_shell_get_shell_surface failed" );
294
295     if( window.mTitle.length() )
296     {
297        wl_shell_surface_set_title( mShellSurface, window.mTitle.c_str() );
298     }
299
300     wl_shell_surface_set_toplevel( mShellSurface);
301
302     wl_shell_surface_add_listener( mShellSurface , &ShellSurfaceListener, 0);
303   }
304
305   wl_display_flush( mDisplay );
306
307 }
308
309 WlSurface* WaylandManager::GetSurface()
310 {
311    return mSurface;
312 }
313
314 }
315 }
316 }