Wayland virtual keyboard support
[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   else if( strcmp( interface, wl_text_input_manager_interface.name ) == 0 )
109   {
110     Dali::WlTextInputManager* inputManager = static_cast< Dali::WlTextInputManager* >( wl_registry_bind( wlRegistry, name, &wl_text_input_manager_interface, version ) );
111
112     client->mInputManager.AddTextInputManager( inputManager );
113   }
114
115
116 }
117
118
119 void RegistryGlobalCallbackRemove(void *data, struct wl_registry *registry, uint32_t id)
120 {
121   // occurs when a device is unplugged
122 }
123
124 const struct wl_registry_listener RegistryListener =
125 {
126    RegistryGlobalCallback,
127    RegistryGlobalCallbackRemove,
128 };
129
130 } //unnamed namespace
131
132 WaylandManager::WaylandManager()
133 :mDisplay( NULL ),
134  mShell( NULL ),
135  mCompositor( NULL ),
136  mDisplayFileDescriptor( 0 ),
137  mFileDescriptorMonitor( NULL ),
138  mXdgShell( NULL ),
139  mSurface( NULL ),
140  mShellSurface( NULL ),
141  mXdgSurface( NULL )
142 {
143 }
144 WaylandManager::~WaylandManager()
145 {
146   if( mXdgShell)
147   {
148     xdg_shell_destroy( mXdgShell );
149   }
150   if( mShell )
151   {
152     wl_shell_destroy( mShell );
153   }
154   if( mCompositor )
155   {
156     wl_compositor_destroy( mCompositor );
157   }
158   if( mDisplay )
159   {
160     wl_display_disconnect( mDisplay );
161   }
162
163   delete mFileDescriptorMonitor;
164 }
165
166 void WaylandManager::Initialise()
167 {
168   if( mDisplay )
169   {
170     return;
171   }
172   // Connect to a Wayland socket on the Wayland server/
173   // NULL = use default display aka "wayland-0"
174   // returns a new display context object
175
176   mDisplay =  wl_display_connect( NULL );
177
178   DALI_ASSERT_ALWAYS( mDisplay && "wl_display_connect failed");
179
180   // Monitor the display file descriptor used to communicate with Wayland server
181   InstallFileDescriptorMonitor();
182
183   mInputManager.AssignDisplay( mDisplay );
184
185   // Get the interfaces to compositor / shell etc
186   GetWaylandInterfaces();
187
188 }
189 void WaylandManager::ReadAndDispatchEvents()
190 {
191   // Wayland client uses a single file descriptor to communicate with the compositor.
192   // Because DALi can have multiple client threads ( event thread for input, render thread for Tizen buffer management / TPL )
193   // it has to use the Wayland client thread safe API to prevent a dead lock
194
195   // prepare_read announces the calling thread's intention to read from the file descriptor
196   // If there is already events queued up in the default queue, then dispatch those first
197   while( wl_display_prepare_read( mDisplay ) != NO_EVENTS_ALREADY_IN_QUEUE )
198   {
199     // dispatch the event, e.g. a touch event or a clipboard event
200     wl_display_dispatch_pending( mDisplay );
201   }
202
203   // At this point the default queue is empty.
204   // We read data from the file descriptor in their respective queues
205   // This is thread safe. No other threads will read from the fd and queue events during this operation.
206   int ret = wl_display_read_events( mDisplay );
207
208   if( ret == 0 )
209   {
210     // dispatch the events from the default queue
211     wl_display_dispatch_pending( mDisplay );
212   }
213   else
214   {
215     DALI_LOG_ERROR("wl_display_read_events error");
216   }
217
218 }
219 void WaylandManager::AssignWindowEventInterface( WindowEventInterface* eventInterface)
220 {
221   mInputManager.AssignWindowEventInterface( eventInterface );
222 }
223 void WaylandManager::GetWaylandInterfaces()
224 {
225   // get and listen to the registry
226   WlRegistry* registry = wl_display_get_registry( mDisplay );
227
228   wl_registry_add_listener( registry, &RegistryListener, this);
229
230   // adaptor wants the DPI instantly, so we have wait for the data
231   while( !mCompositorOutput.DataReady() )
232   {
233     // This is the first and last time we use wl_display_roundtrip as its not thread safe
234     // however at this point we haven't started rendering it is safe.
235     wl_display_flush( mDisplay );
236     wl_display_roundtrip( mDisplay );
237   }
238   wl_registry_destroy( registry );
239
240 }
241
242 void WaylandManager::InstallFileDescriptorMonitor()
243 {
244   // get the file descriptor
245   mDisplayFileDescriptor = wl_display_get_fd( mDisplay );
246
247   // create the callback that gets triggered when a read / write event occurs
248   CallbackBase* callback =  MakeCallback( this, &WaylandManager::FileDescriptorCallback);
249
250   // monitor read and write events
251   int events = FileDescriptorMonitor::FD_READABLE;
252
253   mFileDescriptorMonitor = new FileDescriptorMonitor( mDisplayFileDescriptor, callback, events );
254
255 }
256
257 void WaylandManager::FileDescriptorCallback( FileDescriptorMonitor::EventType eventTypeMask )
258 {
259   if( eventTypeMask & FileDescriptorMonitor::FD_READABLE )
260   {
261     // read and dispatch events
262     ReadAndDispatchEvents();
263   }
264 }
265
266
267 void WaylandManager::CreateSurface( Dali::Wayland::Window& window )
268 {
269   // Create the surface
270   // A Wayland surface is a rectangular area that is displayed on the screen.
271   // It has a location, size and pixel contents.
272
273   mSurface = wl_compositor_create_surface( mCompositor );
274
275   // the Input panel (Virtual keyboard ) needs to know which surface it should display on.
276   mInputManager.AssignSurface( mSurface );
277
278   DALI_ASSERT_ALWAYS( mSurface && "wl_compositor_create_surface failed" );
279
280   // keep track of the surface id
281   window.mSurfaceId = wl_proxy_get_id( reinterpret_cast<struct wl_proxy *>( mSurface ));
282
283   // A surface in Wayland needs to be assigned a role.
284   // This gives the surface the role of a shell surface.
285   // It allows the surface to be treated like a toplevel, fullscreen or popup window.
286   // which can be moved, resize or maximized and have associate metadata like title and class.
287   // Try the xdg shell first. XDG is a designed to create a desktop shell with features like minimise etc.
288   if( mXdgShell )
289   {
290     mXdgSurface = xdg_shell_get_xdg_surface( mXdgShell, mSurface );
291
292     DALI_ASSERT_ALWAYS( mXdgSurface&& "xdg_shell_get_xdg_surface failed" );
293
294     if( window.mTitle.length() )
295     {
296       xdg_surface_set_title(  mXdgSurface, window.mTitle.c_str() );
297     }
298     xdg_shell_add_listener( mXdgShell, &XdgShellListener, 0);
299   }
300   else
301   {
302     // try the generic Wayland Shell
303     mShellSurface = wl_shell_get_shell_surface( mShell, mSurface );
304     DALI_ASSERT_ALWAYS( mShellSurface && "wl_shell_get_shell_surface failed" );
305
306     if( window.mTitle.length() )
307     {
308        wl_shell_surface_set_title( mShellSurface, window.mTitle.c_str() );
309     }
310
311     wl_shell_surface_set_toplevel( mShellSurface);
312
313     wl_shell_surface_add_listener( mShellSurface , &ShellSurfaceListener, 0);
314   }
315
316   wl_display_flush( mDisplay );
317
318 }
319
320 WlSurface* WaylandManager::GetSurface()
321 {
322    return mSurface;
323 }
324
325 }
326 }
327 }