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);
113 void RegistryGlobalCallbackRemove(void *data, struct wl_registry *registry, uint32_t id)
115 // occurs when a device is unplugged
118 const struct wl_registry_listener RegistryListener =
120 RegistryGlobalCallback,
121 RegistryGlobalCallbackRemove,
124 } //unnamed namespace
126 WaylandManager::WaylandManager()
130 mDisplayFileDescriptor( 0 ),
131 mFileDescriptorMonitor( NULL ),
134 mShellSurface( NULL ),
138 WaylandManager::~WaylandManager()
142 xdg_shell_destroy( mXdgShell );
146 wl_shell_destroy( mShell );
150 wl_compositor_destroy( mCompositor );
154 wl_display_disconnect( mDisplay );
157 delete mFileDescriptorMonitor;
160 void WaylandManager::Initialise()
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
170 mDisplay = wl_display_connect( NULL );
172 DALI_ASSERT_ALWAYS( mDisplay && "wl_display_connect failed");
174 // Monitor the display file descriptor used to communicate with Wayland server
175 InstallFileDescriptorMonitor();
177 // Get the interfaces to compositor / shell etc
178 GetWaylandInterfaces();
181 void WaylandManager::ReadAndDispatchEvents()
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
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 )
191 // dispatch the event, e.g. a touch event or a clipboard event
192 wl_display_dispatch_pending( mDisplay );
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 );
202 // dispatch the events from the default queue
203 wl_display_dispatch_pending( mDisplay );
207 DALI_LOG_ERROR("wl_display_read_events error");
211 void WaylandManager::AssignWindowEventInterface( WindowEventInterface* eventInterface)
213 mInputManager.AssignWindowEventInterface( eventInterface );
215 void WaylandManager::GetWaylandInterfaces()
217 // get and listen to the registry
218 WlRegistry* registry = wl_display_get_registry( mDisplay );
220 wl_registry_add_listener( registry, &RegistryListener, this);
222 // adaptor wants the DPI instantly, so we have wait for the data
223 while( !mCompositorOutput.DataReady() )
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 );
230 wl_registry_destroy( registry );
234 void WaylandManager::InstallFileDescriptorMonitor()
236 // get the file descriptor
237 mDisplayFileDescriptor = wl_display_get_fd( mDisplay );
239 // create the callback that gets triggered when a read / write event occurs
240 CallbackBase* callback = MakeCallback( this, &WaylandManager::FileDescriptorCallback);
242 // monitor read and write events
243 int events = FileDescriptorMonitor::FD_READABLE;
245 mFileDescriptorMonitor = new FileDescriptorMonitor( mDisplayFileDescriptor, callback, events );
249 void WaylandManager::FileDescriptorCallback( FileDescriptorMonitor::EventType eventTypeMask )
251 if( eventTypeMask & FileDescriptorMonitor::FD_READABLE )
253 // read and dispatch events
254 ReadAndDispatchEvents();
259 void WaylandManager::CreateSurface( Dali::Wayland::Window& window )
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.
265 mSurface = wl_compositor_create_surface( mCompositor );
267 DALI_ASSERT_ALWAYS( mSurface && "wl_compositor_create_surface failed" );
269 // keep track of the surface id
270 window.mSurfaceId = wl_proxy_get_id( reinterpret_cast<struct wl_proxy *>( mSurface ));
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.
279 mXdgSurface = xdg_shell_get_xdg_surface( mXdgShell, mSurface );
281 DALI_ASSERT_ALWAYS( mXdgSurface&& "xdg_shell_get_xdg_surface failed" );
283 if( window.mTitle.length() )
285 xdg_surface_set_title( mXdgSurface, window.mTitle.c_str() );
287 xdg_shell_add_listener( mXdgShell, &XdgShellListener, 0);
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" );
295 if( window.mTitle.length() )
297 wl_shell_surface_set_title( mShellSurface, window.mTitle.c_str() );
300 wl_shell_surface_set_toplevel( mShellSurface);
302 wl_shell_surface_add_listener( mShellSurface , &ShellSurfaceListener, 0);
305 wl_display_flush( mDisplay );
309 WlSurface* WaylandManager::GetSurface()