Vulkan support
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / ubuntu-x11 / window-render-surface-ecore-x.cpp
1 /*
2  * Copyright (c) 2018 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
18 // CLASS HEADER
19 #include <dali/internal/window-system/ubuntu-x11/window-render-surface-ecore-x.h>
20
21 // EXTERNAL INCLUDES
22 #include <X11/Xatom.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25
26 #include <X11/extensions/Xfixes.h> // for damage notify
27 #include <X11/extensions/Xdamage.h> // for damage notify
28
29 #include <dali/integration-api/gl-abstraction.h>
30 #include <dali/integration-api/debug.h>
31
32 // INTERNAL INCLUDES
33 #include <dali/internal/window-system/ubuntu-x11/ecore-x-types.h>
34 #include <dali/internal/system/common/trigger-event.h>
35 #include <dali/internal/graphics/gles20/egl-implementation.h>
36 #include <dali/internal/window-system/common/display-connection.h>
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44
45 namespace
46 {
47
48 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE_ECORE_X");
52 #endif
53
54 } // unnamed namespace
55
56 WindowRenderSurfaceEcoreX::WindowRenderSurfaceEcoreX( Dali::PositionSize positionSize,
57                                           Any surface,
58                                           const std::string& name,
59                                           const std::string& className,
60                                           bool isTransparent)
61 : mTitle( name ),
62   mClassName( className ),
63   mPosition( positionSize ),
64   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
65   mX11Window( 0 ),
66   mOwnSurface( false ),
67   mNeedToApproveDeiconify( false )
68 {
69   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
70   Initialize( surface );
71 }
72
73 WindowRenderSurfaceEcoreX::~WindowRenderSurfaceEcoreX()
74 {
75   if( mOwnSurface )
76   {
77     ecore_x_window_free( mX11Window );
78   }
79 }
80
81 void WindowRenderSurfaceEcoreX::Initialize( Any surface )
82 {
83   // see if there is a surface in Any surface
84   unsigned int surfaceId = GetSurfaceId( surface );
85
86   // if the surface is empty, create a new one.
87   if( surfaceId == 0 )
88   {
89     // we own the surface about to created
90     mOwnSurface = true;
91     CreateRenderable();
92   }
93   else
94   {
95     // XLib should already be initialized so no point in calling XInitThreads
96     UseExistingRenderable( surfaceId );
97   }
98 }
99
100 Ecore_X_Window WindowRenderSurfaceEcoreX::GetXWindow()
101 {
102   return mX11Window;
103 }
104
105 void WindowRenderSurfaceEcoreX::RequestToApproveDeiconify()
106 {
107   mNeedToApproveDeiconify = true;
108 }
109
110 Any WindowRenderSurfaceEcoreX::GetWindow()
111 {
112   return mX11Window;
113 }
114
115 void WindowRenderSurfaceEcoreX::Map()
116 {
117   ecore_x_window_show( mX11Window );
118 }
119
120 void WindowRenderSurfaceEcoreX::SetRenderNotification( TriggerEventInterface* renderNotification )
121 {
122 }
123
124 void WindowRenderSurfaceEcoreX::SetTransparency( bool transparent )
125 {
126 }
127
128 void WindowRenderSurfaceEcoreX::RequestRotation( int angle, int width, int height )
129 {
130 }
131
132 PositionSize WindowRenderSurfaceEcoreX::GetPositionSize() const
133 {
134   return mPosition;
135 }
136
137 void WindowRenderSurfaceEcoreX::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
138 {
139   // calculate DPI
140   float xres, yres;
141
142   // 1 inch = 25.4 millimeters
143   xres = ecore_x_dpi_get();
144   yres = ecore_x_dpi_get();
145
146   dpiHorizontal = int( xres + 0.5f );  // rounding
147   dpiVertical   = int( yres + 0.5f );
148 }
149
150 void WindowRenderSurfaceEcoreX::InitializeEgl( EglInterface& eglIf )
151 {
152   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
153
154   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
155
156   eglImpl.ChooseConfig(true, mColorDepth);
157 }
158
159 void WindowRenderSurfaceEcoreX::CreateEglSurface( EglInterface& eglIf )
160 {
161   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
162
163   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
164
165   // create the EGL surface
166   // need to create X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
167   XWindow window( mX11Window );
168   eglImpl.CreateSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( window ), mColorDepth );
169 }
170
171 void WindowRenderSurfaceEcoreX::DestroyEglSurface( EglInterface& eglIf )
172 {
173   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
174
175   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
176   eglImpl.DestroySurface();
177 }
178
179 bool WindowRenderSurfaceEcoreX::ReplaceEGLSurface( EglInterface& egl )
180 {
181   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
182
183   // need to create X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
184   XWindow window( mX11Window );
185   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
186
187   return eglImpl.ReplaceSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( window ) );
188 }
189
190 void WindowRenderSurfaceEcoreX::MoveResize( Dali::PositionSize positionSize )
191 {
192   bool needToMove = false;
193   bool needToResize = false;
194
195   // check moving
196   if( (fabs(positionSize.x - mPosition.x) > MINIMUM_DIMENSION_CHANGE) ||
197       (fabs(positionSize.y - mPosition.y) > MINIMUM_DIMENSION_CHANGE) )
198   {
199     needToMove = true;
200   }
201
202   // check resizing
203   if( (fabs(positionSize.width - mPosition.width) > MINIMUM_DIMENSION_CHANGE) ||
204       (fabs(positionSize.height - mPosition.height) > MINIMUM_DIMENSION_CHANGE) )
205   {
206     needToResize = true;
207   }
208
209   if( needToMove &&  needToResize)
210   {
211     ecore_x_window_move_resize(mX11Window, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
212     mPosition = positionSize;
213   }
214   else if(needToMove)
215   {
216     ecore_x_window_move(mX11Window, positionSize.x, positionSize.y);
217     mPosition = positionSize;
218   }
219   else if (needToResize)
220   {
221     ecore_x_window_resize(mX11Window, positionSize.width, positionSize.height);
222     mPosition = positionSize;
223   }
224 }
225
226 void WindowRenderSurfaceEcoreX::SetViewMode( ViewMode viewMode )
227 {
228   Ecore_X_Atom viewModeAtom( ecore_x_atom_get( "_E_COMP_3D_APP_WIN" ) );
229
230   if( viewModeAtom != None )
231   {
232     unsigned int value( static_cast<unsigned int>( viewMode ) );
233     ecore_x_window_prop_card32_set( mX11Window, viewModeAtom, &value, 1 );
234   }
235 }
236
237 void WindowRenderSurfaceEcoreX::StartRender()
238 {
239 }
240
241 bool WindowRenderSurfaceEcoreX::PreRender( EglInterface&, Integration::GlAbstraction&, bool )
242 {
243   // nothing to do for windows
244   return true;
245 }
246
247 void WindowRenderSurfaceEcoreX::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, Dali::DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
248 {
249   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
250   eglImpl.SwapBuffers();
251
252   // When the window is deiconified, it approves the deiconify operation to window manager after rendering
253   if(mNeedToApproveDeiconify)
254   {
255     // SwapBuffer is desychronized. So make sure to sychronize when window is deiconified.
256     glAbstraction.Finish();
257
258     XDisplay* display = AnyCast<XDisplay *>(displayConnection->GetDisplay());
259
260 #ifndef DALI_PROFILE_UBUNTU
261     /* client sends immediately reply message using value 1 */
262     XEvent xev;
263
264     xev.xclient.window = mX11Window;
265     xev.xclient.type = ClientMessage;
266     xev.xclient.message_type = ECORE_X_ATOM_E_DEICONIFY_APPROVE;
267     xev.xclient.format = 32;
268     xev.xclient.data.l[0] = mX11Window;
269     xev.xclient.data.l[1] = 1;
270     xev.xclient.data.l[2] = 0;
271     xev.xclient.data.l[3] = 0;
272     xev.xclient.data.l[4] = 0;
273
274     XSendEvent(display, mX11Window, false, ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, &xev);
275 #endif // DALI_PROFILE_UBUNTU
276
277     XSync(display, false);
278
279     mNeedToApproveDeiconify = false;
280   }
281 }
282
283 void WindowRenderSurfaceEcoreX::StopRender()
284 {
285 }
286
287 void WindowRenderSurfaceEcoreX::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ )
288 {
289   // Nothing to do.
290 }
291
292 void WindowRenderSurfaceEcoreX::ReleaseLock()
293 {
294   // Nothing to do.
295 }
296
297 RenderSurface::Type WindowRenderSurfaceEcoreX::GetSurfaceType()
298 {
299   return WINDOW_RENDER_SURFACE;
300 }
301
302 void WindowRenderSurfaceEcoreX::CreateRenderable()
303 {
304    // if width or height are zero, go full screen.
305   if ( (mPosition.width == 0) || (mPosition.height == 0) )
306   {
307     // Default window size == screen size
308     mPosition.x = 0;
309     mPosition.y = 0;
310
311     ecore_x_screen_size_get( ecore_x_default_screen_get(), &mPosition.width, &mPosition.height );
312   }
313
314   if(mColorDepth == COLOR_DEPTH_32)
315   {
316     // create 32 bit window
317     mX11Window = ecore_x_window_argb_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height );
318   }
319   else
320   {
321     // create 24 bit window
322     mX11Window = ecore_x_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height );
323   }
324
325   if ( mX11Window == 0 )
326   {
327       DALI_ASSERT_ALWAYS(0 && "Failed to create X window");
328   }
329
330   // set up window title which will be helpful for debug utitilty
331   ecore_x_icccm_title_set( mX11Window, mTitle.c_str() );
332   ecore_x_netwm_name_set( mX11Window, mTitle.c_str() );
333   ecore_x_icccm_name_class_set( mX11Window, mTitle.c_str(), mClassName.c_str() );
334
335   // set up etc properties to match with ecore-evas
336   char *id = NULL;
337   if( ( id = getenv("DESKTOP_STARTUP_ID") ) )
338   {
339     ecore_x_netwm_startup_id_set( mX11Window, id );
340   }
341
342   ecore_x_icccm_hints_set( mX11Window,
343                            1,                                // accepts_focus
344                            ECORE_X_WINDOW_STATE_HINT_NORMAL, // initial_state
345                            0,                                // icon_pixmap
346                            0,                                // icon_mask
347                            0,                                // icon_window
348                            0,                                // window_group
349                            0 );                              // is_urgent
350
351   // we SHOULD guarantee the x11 window was created in x server.
352   ecore_x_sync();
353 }
354
355 void WindowRenderSurfaceEcoreX::UseExistingRenderable( unsigned int surfaceId )
356 {
357   mX11Window = static_cast< Ecore_X_Window >( surfaceId );
358 }
359
360 unsigned int WindowRenderSurfaceEcoreX::GetSurfaceId( Any surface ) const
361 {
362   unsigned int surfaceId = 0;
363
364   if ( surface.Empty() == false )
365   {
366     // check we have a valid type
367     DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) ||
368                           (surface.GetType() == typeid (Ecore_X_Window) ) )
369                         && "Surface type is invalid" );
370
371     if ( surface.GetType() == typeid (Ecore_X_Window) )
372     {
373       surfaceId = AnyCast<Ecore_X_Window>( surface );
374     }
375     else
376     {
377       surfaceId = AnyCast<XWindow>( surface );
378     }
379   }
380   return surfaceId;
381 }
382
383 } // namespace Adaptor
384
385 } // namespace internal
386
387 } // namespace Dali