2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "wayland-manager.h"
22 #include <dali/integration-api/debug.h>
25 #include <base/interfaces/window-event-interface.h>
26 #include <base/interfaces/performance-interface.h>
39 const int NO_EVENTS_ALREADY_IN_QUEUE = 0;
42 void ShellSurfacePing( void* data, struct wl_shell_surface* shell_surface, uint32_t serial)
44 // The ping event comes from the compositor to checks if we're still alive.
45 wl_shell_surface_pong(shell_surface, serial);
48 void ShellSurfaceConfigure( void* data, struct wl_shell_surface* shell_surface, uint32_t edges, int32_t width, int32_t height)
52 const struct wl_shell_surface_listener ShellSurfaceListener =
55 ShellSurfaceConfigure,
59 void XdgShellPing( void* data, Dali::WlXdgShell* shell, uint32_t serial)
61 // The ping event comes from the compositor to checks if we're still alive.
62 xdg_shell_pong( shell, serial);
65 struct xdg_shell_listener XdgShellListener=
71 void RegistryGlobalCallback( void *data,
72 struct wl_registry *wlRegistry,
74 const char *interface,
78 WaylandManager* client = static_cast< WaylandManager* >( data );
80 if( strcmp( interface, wl_compositor_interface.name ) == 0 )
82 client->mCompositor = static_cast< Dali::WlCompositor* >( wl_registry_bind( wlRegistry, name, &wl_compositor_interface, version ) );
84 else if( strcmp( interface, wl_seat_interface.name ) == 0 )
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 ) );
89 client->mInputManager.AddSeatListener( seatInterface );
91 else if( strcmp( interface, wl_output_interface.name ) == 0 )
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 );
97 else if( strcmp( interface, wl_shell_interface.name ) == 0 )
99 client->mShell = static_cast< Dali::WlShell* >( wl_registry_bind( wlRegistry, name, &wl_shell_interface, version ) );
101 else if( strcmp( interface, xdg_shell_interface.name ) == 0 )
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 );
108 else if( strcmp( interface, wl_text_input_manager_interface.name ) == 0 )
110 Dali::WlTextInputManager* inputManager = static_cast< Dali::WlTextInputManager* >( wl_registry_bind( wlRegistry, name, &wl_text_input_manager_interface, version ) );
112 client->mInputManager.AddTextInputManager( inputManager );
119 void RegistryGlobalCallbackRemove(void *data, struct wl_registry *registry, uint32_t id)
121 // occurs when a device is unplugged
124 const struct wl_registry_listener RegistryListener =
126 RegistryGlobalCallback,
127 RegistryGlobalCallbackRemove,
130 } //unnamed namespace
132 WaylandManager::WaylandManager()
136 mDisplayFileDescriptor( 0 ),
137 mFileDescriptorMonitor( NULL ),
140 mShellSurface( NULL ),
144 WaylandManager::~WaylandManager()
148 xdg_shell_destroy( mXdgShell );
152 wl_shell_destroy( mShell );
156 wl_compositor_destroy( mCompositor );
160 wl_display_disconnect( mDisplay );
163 delete mFileDescriptorMonitor;
166 void WaylandManager::Initialise()
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
176 mDisplay = wl_display_connect( NULL );
178 DALI_ASSERT_ALWAYS( mDisplay && "wl_display_connect failed");
180 // Monitor the display file descriptor used to communicate with Wayland server
181 InstallFileDescriptorMonitor();
183 mInputManager.AssignDisplay( mDisplay );
185 // Get the interfaces to compositor / shell etc
186 GetWaylandInterfaces();
189 void WaylandManager::ReadAndDispatchEvents()
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
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 )
199 // dispatch the event, e.g. a touch event or a clipboard event
200 wl_display_dispatch_pending( mDisplay );
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 );
210 // dispatch the events from the default queue
211 wl_display_dispatch_pending( mDisplay );
215 DALI_LOG_ERROR("wl_display_read_events error");
219 void WaylandManager::AssignWindowEventInterface( WindowEventInterface* eventInterface)
221 mInputManager.AssignWindowEventInterface( eventInterface );
223 void WaylandManager::GetWaylandInterfaces()
225 // get and listen to the registry
226 WlRegistry* registry = wl_display_get_registry( mDisplay );
228 wl_registry_add_listener( registry, &RegistryListener, this);
230 // adaptor wants the DPI instantly, so we have wait for the data
231 while( !mCompositorOutput.DataReady() )
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 );
238 wl_registry_destroy( registry );
242 void WaylandManager::InstallFileDescriptorMonitor()
244 // get the file descriptor
245 mDisplayFileDescriptor = wl_display_get_fd( mDisplay );
247 // create the callback that gets triggered when a read / write event occurs
248 CallbackBase* callback = MakeCallback( this, &WaylandManager::FileDescriptorCallback);
250 // monitor read and write events
251 int events = FileDescriptorMonitor::FD_READABLE;
253 mFileDescriptorMonitor = new FileDescriptorMonitor( mDisplayFileDescriptor, callback, events );
257 void WaylandManager::FileDescriptorCallback( FileDescriptorMonitor::EventType eventTypeMask )
259 if( eventTypeMask & FileDescriptorMonitor::FD_READABLE )
261 // read and dispatch events
262 ReadAndDispatchEvents();
267 void WaylandManager::CreateSurface( Dali::Wayland::Window& window )
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.
273 mSurface = wl_compositor_create_surface( mCompositor );
275 // the Input panel (Virtual keyboard ) needs to know which surface it should display on.
276 mInputManager.AssignSurface( mSurface );
278 DALI_ASSERT_ALWAYS( mSurface && "wl_compositor_create_surface failed" );
280 // keep track of the surface id
281 window.mSurfaceId = wl_proxy_get_id( reinterpret_cast<struct wl_proxy *>( mSurface ));
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.
290 mXdgSurface = xdg_shell_get_xdg_surface( mXdgShell, mSurface );
292 DALI_ASSERT_ALWAYS( mXdgSurface&& "xdg_shell_get_xdg_surface failed" );
294 if( window.mTitle.length() )
296 xdg_surface_set_title( mXdgSurface, window.mTitle.c_str() );
298 xdg_shell_add_listener( mXdgShell, &XdgShellListener, 0);
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" );
306 if( window.mTitle.length() )
308 wl_shell_surface_set_title( mShellSurface, window.mTitle.c_str() );
311 wl_shell_surface_set_toplevel( mShellSurface);
313 wl_shell_surface_add_listener( mShellSurface , &ShellSurfaceListener, 0);
316 wl_display_flush( mDisplay );
320 WlSurface* WaylandManager::GetSurface()