Fix coordinate error
[platform/framework/native/shell.git] / src / FShell_AppWidgetBuffer.cpp
1 //
2 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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  * @file                FShell_AppWidgetBuffer.cpp
18  * @brief               This is the implementation file for the _AppWidgetBuffer class.
19  */
20
21 #include <new>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <sys/mman.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <stddef.h>
32 #include <sys/shm.h>
33 #include <sys/ipc.h>
34 #include <FBaseSysLog.h>
35 #include "FShell_AppWidgetBuffer.h"
36
37 using namespace std;
38 using namespace Tizen::Base;
39 using namespace Tizen::Graphics;
40
41 namespace Tizen { namespace Shell
42 {
43
44 _AppWidgetBuffer::_AppWidgetBuffer(void)
45         : __screen(0)
46         , __pVisual(null)
47         , __dri2FileDescriptor(-1)
48 {
49 }
50
51 _AppWidgetBuffer::~_AppWidgetBuffer(void)
52 {
53 }
54
55 struct _Deleter
56 {
57         void operator()(char* pStr)
58         {
59                 free(pStr);
60         }
61 };
62
63 void
64 _AppWidgetBuffer::Initialize(void)
65 {
66         __pDisplay.reset(XOpenDisplay(null));
67         SysTryReturnVoidResult(NID_SHELL, __pDisplay, E_SYSTEM, "[E_SYSTEM] Propagating.");
68
69         Screen* pScreen = DefaultScreenOfDisplay(__pDisplay.get());
70         __screen = DefaultScreen(__pDisplay.get());
71         __pVisual = DefaultVisualOfScreen(pScreen);
72         SysTryReturnVoidResult(NID_SHELL, __pVisual, E_SYSTEM, "[E_SYSTEM] Propagating.");
73
74         Bool ret = False;
75         int eventBase = 0;
76         int errorBase = 0;
77         ret = DRI2QueryExtension(__pDisplay.get(), &eventBase, &errorBase);
78         if (!ret)
79         {
80                 SysLog(NID_SHELL, "Do not support");
81                 return;
82         }
83
84         int dri2Major = 0;
85         int dri2Minor = 0;
86         ret = DRI2QueryVersion(__pDisplay.get(), &dri2Major, &dri2Minor);
87         if (!ret)
88         {
89                 SysLog(NID_SHELL, "Do not support");
90                 return;
91         }
92
93         char* pDriverNameTemp = null;
94         char* pDeviceNameTemp = null;
95
96         ret = DRI2Connect(__pDisplay.get(), DefaultRootWindow(__pDisplay.get()), &pDriverNameTemp, &pDeviceNameTemp);
97         if (!ret)
98         {
99                 SysLog(NID_SHELL, "Do not support");
100                 return;
101         }
102
103         unique_ptr<char, _Deleter> pDriverName(pDriverNameTemp);
104         unique_ptr<char, _Deleter> pDeviceName(pDeviceNameTemp);
105
106         unique_ptr<int, _FileDescriptorDeleter> fileDescriptor(open(pDeviceName.get(), O_RDWR));
107         if (fileDescriptor.get() < 0)
108         {
109                 SysLog(NID_SHELL, "Do not support");
110                 return;
111         }
112
113         drm_magic_t magic = 0;
114         drmGetMagic(fileDescriptor.get(), &magic);
115         SysLog(NID_SHELL, "Magic [0x%x]", magic);
116         ret = DRI2Authenticate(__pDisplay.get(), DefaultRootWindow(__pDisplay.get()), magic);
117         SysTryReturnVoidResult(NID_SHELL, ret == True, E_SYSTEM, "[E_SYSTEM] Propagating.");
118
119         unique_ptr<tbm_bufmgr, _TbmBufMgrDeleter> pBufMgr(tbm_bufmgr_init(fileDescriptor.get()));
120         SysTryReturnVoidResult(NID_SHELL, pBufMgr, E_SYSTEM, "[E_SYSTEM] Propagating.");
121
122         __dri2FileDescriptor = move(fileDescriptor);
123         __pBufMgr = move(pBufMgr);
124 }
125
126 void*
127 _AppWidgetBuffer::AllocBuffer(Pixmap pixmap, const Tizen::Graphics::Dimension& size)
128 {
129         unique_ptr<_Buffer> pBuffer;
130
131         if (!IsGemBufferEnabled())
132         {
133                 pBuffer.reset(new (std::nothrow) _Buffer(this));
134         }
135         else
136         {
137                 pBuffer.reset(new (std::nothrow) _GemBuffer(this));
138         }
139
140         SysTryReturn(NID_SHELL, pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
141
142         void* pNativeBuffer = pBuffer->AllocBuffer(pixmap, size);
143         SysTryReturn(NID_SHELL, pNativeBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
144
145         __pBuffer = move(pBuffer);
146
147         return pNativeBuffer;
148 }
149
150 void
151 _AppWidgetBuffer::DeallocBuffer(void)
152 {
153         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
154
155         __pBuffer->DeallocBuffer();
156 }
157
158 void*
159 _AppWidgetBuffer::LockBuffer(void)
160 {
161         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
162
163         void* pNativeBuffer = __pBuffer->LockBuffer();
164         SysTryReturn(NID_SHELL, pNativeBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
165
166         return pNativeBuffer;
167 }
168
169 void
170 _AppWidgetBuffer::UnlockBuffer(void)
171 {
172         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
173
174         __pBuffer->UnlockBuffer();
175 }
176
177 bool
178 _AppWidgetBuffer::IsGemBufferEnabled(void) const
179 {
180         return  (__dri2FileDescriptor.get() >= 0);
181 }
182
183 Display*
184 _AppWidgetBuffer::GetDisplay(void) const
185 {
186         return __pDisplay.get();
187 }
188
189 GC
190 _AppWidgetBuffer::GetGc(void) const
191 {
192         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
193
194         return __pBuffer->GetGc();
195 }
196
197 XImage*
198 _AppWidgetBuffer::GetXImage(void) const
199 {
200         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
201
202         return __pBuffer->GetXImage();
203 }
204
205 Pixmap
206 _AppWidgetBuffer::GetPixmap(void) const
207 {
208         SysTryReturn(NID_SHELL, __pBuffer, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
209
210         return __pBuffer->GetPixmap();
211 }
212
213 void
214 _AppWidgetBuffer::Dump(const char* pName)
215 {
216         SysTryReturnVoidResult(NID_SHELL, pName, E_INVALID_ARG, "[E_INVALID_ARG] The argument is invalid.");
217         SysTryReturnVoidResult(NID_SHELL, __pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
218
219         return __pBuffer->Dump(pName);
220 }
221
222 _AppWidgetBuffer::_Buffer::_Buffer(_AppWidgetBuffer* pAppWidgetBuffer)
223         : __locked(false)
224         , __pixmap(0)
225         , __depth(sizeof(int))
226         , __pAppWidgetBuffer(pAppWidgetBuffer)
227         , __dumpFileIndex(0)
228         , __gc(null)
229         , __pXImage(null)
230 {
231         __xShmSegmentInfo.shmseg = 0;
232         __xShmSegmentInfo.shmid = -1;
233         __xShmSegmentInfo.shmaddr = 0;
234         __xShmSegmentInfo.readOnly = False;
235 }
236
237 _AppWidgetBuffer::_Buffer::~_Buffer(void)
238 {
239         DeleteBuffer();
240 }
241
242 void*
243 _AppWidgetBuffer::_Buffer::AllocBuffer(Pixmap pixmap, const Tizen::Graphics::Dimension& size)
244 {
245         __pixmap = pixmap;
246         __size = size;
247
248         OnCreateBuffer();
249
250         return LockBuffer();
251 }
252
253 void
254 _AppWidgetBuffer::_Buffer::DeallocBuffer(void)
255 {
256         OnDeleteBuffer();
257 }
258
259 void*
260 _AppWidgetBuffer::_Buffer::LockBuffer(void)
261 {
262         __locked = true;
263
264         return OnLockBuffer();
265 }
266
267 void
268 _AppWidgetBuffer::_Buffer::UnlockBuffer(void)
269 {
270         __locked = false;
271
272         return OnUnlockBuffer();
273 }
274
275 GC
276 _AppWidgetBuffer::_Buffer::GetGc(void) const
277 {
278         return __gc;
279 }
280
281 XImage*
282 _AppWidgetBuffer::_Buffer::GetXImage(void) const
283 {
284         return __pXImage;
285 }
286
287 Pixmap
288 _AppWidgetBuffer::_Buffer::GetPixmap(void) const
289 {
290         return __pixmap;
291 }
292
293 void
294 _AppWidgetBuffer::_Buffer::Dump(const char* pName)
295 {
296         void* pBuffer = null;
297         bool lock = false;
298         if (__locked)
299         {
300                 pBuffer = GetBuffer();
301         }
302         else
303         {
304                 lock = true;
305                 pBuffer = LockBuffer();
306         }
307
308         SysTryReturnVoidResult(NID_SHELL, pBuffer, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
309
310         int size = __size.width * __size.height * __depth;
311
312         char fileName[1024];
313         memset(fileName, 0, sizeof(fileName));
314         snprintf(fileName, sizeof(fileName), "./dump-%s-%d.raw", pName, __dumpFileIndex++);
315
316         FILE* pFile = fopen(fileName, "w+b");
317         if (pFile)
318         {
319                 fwrite(pBuffer, size, 1, pFile);
320                 fclose(pFile);
321                 SysSecureLog(NID_SHELL, "buffer (0x%x) size (%d) pixmapId (%d)", pBuffer, size, __pixmap);
322         }
323         else
324         {
325                 SysSecureLog(NID_SHELL, "File open failed: (%s) buffer (0x%x) size (%d) pixmapId (%d)", strerror(errno), pBuffer, size, __pixmap);
326         }
327
328         if (lock)
329         {
330                 UnlockBuffer(); 
331         }
332 }
333
334 void*
335 _AppWidgetBuffer::_Buffer::GetBuffer(void)
336 {
337         return OnLockBuffer();
338 }
339
340 void
341 _AppWidgetBuffer::_Buffer::DeleteBuffer(void)
342 {
343         if (__pAppWidgetBuffer->__pDisplay.get())
344         {
345                 if (__gc)
346                 {
347                         XFreeGC(__pAppWidgetBuffer->__pDisplay.get(), __gc);
348                         XShmDetach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
349
350                         if (__pXImage)
351                         {
352                                 XDestroyImage(__pXImage);
353                                 __pXImage = null;
354                         }
355
356                         if (__xShmSegmentInfo.shmaddr)
357                         {
358                                 shmdt(__xShmSegmentInfo.shmaddr);
359                                 __xShmSegmentInfo.shmaddr = null;
360                         }
361
362                         if (__xShmSegmentInfo.shmid >= 0)
363                         {
364                                 shmctl(__xShmSegmentInfo.shmid, IPC_RMID, 0);
365                                 __xShmSegmentInfo.shmid = -1;
366                         }
367
368                         __gc = null;
369                 }
370         }
371 }
372
373 void
374 _AppWidgetBuffer::_Buffer::OnCreateBuffer(void)
375 {
376         int bufferSize = __size.width * __size.height * __depth;
377         SysLog(NID_SHELL, "%d [%d %d %d]", bufferSize, __size.width, __size.height, __depth);
378
379         __xShmSegmentInfo.shmid = shmget(IPC_PRIVATE, bufferSize, IPC_CREAT | 0666);
380         SysTryReturnVoidResult(NID_SHELL, __xShmSegmentInfo.shmid >= 0, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
381
382         __xShmSegmentInfo.readOnly = False;
383         __xShmSegmentInfo.shmaddr = static_cast<char*>(shmat(__xShmSegmentInfo.shmid, null, 0));
384         SysTryCatch(NID_SHELL, __xShmSegmentInfo.shmaddr != (void*)-1, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
385
386         __pXImage = XShmCreateImage(__pAppWidgetBuffer->__pDisplay.get(), __pAppWidgetBuffer->__pVisual, 32, ZPixmap, null, &__xShmSegmentInfo, __size.width, __size.height);
387         SysTryCatch(NID_SHELL, __pXImage, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
388
389         __pXImage->data = __xShmSegmentInfo.shmaddr;
390         XShmAttach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
391         XSync(__pAppWidgetBuffer->__pDisplay.get(), False);
392
393         __gc = XCreateGC(__pAppWidgetBuffer->__pDisplay.get(), static_cast<Pixmap>(__pixmap), 0, null);
394         SysTryCatch(NID_SHELL, __gc, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
395
396         return;
397
398 CATCH:
399
400         XShmDetach(__pAppWidgetBuffer->__pDisplay.get(), &__xShmSegmentInfo);
401
402         if (__pXImage)
403         {
404                 XDestroyImage(__pXImage);
405                 __pXImage = null;
406         }
407
408         if (__xShmSegmentInfo.shmaddr != (void *)-1)
409         {
410                 shmdt(__xShmSegmentInfo.shmaddr);
411                 __xShmSegmentInfo.shmaddr = null;
412         }
413
414         if (__xShmSegmentInfo.shmid >= 0)
415         {
416                 shmctl(__xShmSegmentInfo.shmid, IPC_RMID, 0);
417                 __xShmSegmentInfo.shmid = -1;
418         }
419 }
420
421 void
422 _AppWidgetBuffer::_Buffer::OnDeleteBuffer(void)
423 {
424         DeleteBuffer();
425 }
426
427 void*
428 _AppWidgetBuffer::_Buffer::OnLockBuffer(void)
429 {
430         return __xShmSegmentInfo.shmaddr;
431 }
432
433 void
434 _AppWidgetBuffer::_Buffer::OnUnlockBuffer(void)
435 {
436 //      DeleteBuffer();
437 }
438
439 void*
440 _AppWidgetBuffer::_Buffer::OnGetBuffer(void)
441 {
442         return __xShmSegmentInfo.shmaddr;
443 }
444
445 _AppWidgetBuffer::_GemBuffer::_GemBuffer(_AppWidgetBuffer* pAppWidgetBuffer)
446         : _Buffer(pAppWidgetBuffer)
447         , __pDri2Buffer(null)
448         , __count(1)
449         , __outCount(0)
450         , __pTbmBo(null)
451         , __pGemBuffer(null)
452         , __pCompensateBuffer(null)
453 {
454         __attachments[0] = DRI2BufferFrontLeft;
455 }
456
457 _AppWidgetBuffer::_GemBuffer::~_GemBuffer(void)
458 {
459         DeleteGemBuffer();
460 }
461
462 void
463 _AppWidgetBuffer::_GemBuffer::DeleteGemBuffer(void)
464 {
465         if (__pCompensateBuffer)
466         {
467                 free(__pCompensateBuffer);
468                 __pCompensateBuffer = null;
469         }
470
471         if (__pTbmBo)
472         {
473                 tbm_bo_unref(__pTbmBo);
474                 __pTbmBo = null;
475
476                 DRI2DestroyDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
477         }
478 }
479
480 void
481 _AppWidgetBuffer::_GemBuffer::OnCreateBuffer(void)
482 {
483         SysLog(NID_SHELL, "[%d %d]", __size.width, __size.height);
484
485         unsigned int pitch = 0;
486
487         DRI2CreateDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
488
489         int width = __size.width;
490         int height = __size.height;
491
492         __pDri2Buffer = DRI2GetBuffers(__pAppWidgetBuffer->__pDisplay.get(), __pixmap, &width, &height, __attachments, __count, &__outCount);
493         SysTryCatch(NID_SHELL, __pDri2Buffer && __pDri2Buffer->name, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
494
495         __gemSize.width = width;
496         __gemSize.height = height;
497
498         SysSecureLog(NID_SHELL, "0x%x [%d %d %d] [%d %d]", __pDri2Buffer, __outCount, __pDri2Buffer->name, __pDri2Buffer->pitch, width, height);
499
500         __pTbmBo = tbm_bo_import(__pAppWidgetBuffer->__pBufMgr.get(), __pDri2Buffer->name);
501         SysTryCatch(NID_SHELL, __pTbmBo, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
502         
503         pitch = __gemSize.width * __depth;
504         if (__pDri2Buffer->pitch != pitch)
505         {
506                 __pCompensateBuffer = calloc(1, pitch * __gemSize.height);
507                 SysTryCatch(NID_SHELL, __pCompensateBuffer, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory is insufficient.");
508
509                 SysLog(NID_SHELL, "0x%x [%d %d %d]", __pCompensateBuffer, __depth, __gemSize.width, __gemSize.height);
510         }
511
512         return;
513
514 CATCH:
515
516         DRI2DestroyDrawable(__pAppWidgetBuffer->__pDisplay.get(), __pixmap);
517 }
518
519 void
520 _AppWidgetBuffer::_GemBuffer::OnDeleteBuffer(void)
521 {
522         DeleteGemBuffer();
523 }
524
525 void*
526 _AppWidgetBuffer::_GemBuffer::OnLockBuffer(void)
527 {
528         if (!__pGemBuffer)
529         {
530                 tbm_bo_handle handle;
531                 handle = tbm_bo_map(__pTbmBo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
532                 __pGemBuffer = handle.ptr;
533         }
534
535         return __pCompensateBuffer ? __pCompensateBuffer : __pGemBuffer;
536 }
537
538 void
539 _AppWidgetBuffer::_GemBuffer::OnUnlockBuffer(void)
540 {
541         if (__pGemBuffer)
542         {
543                 if (__pCompensateBuffer)
544                 {
545                         int* pPixel = (int*)__pCompensateBuffer;
546                         int* pGemPixel = (int*)__pGemBuffer;
547                         int gap = __pDri2Buffer->pitch - (__gemSize.width * __depth);
548
549                         for (int y = 0; y < __gemSize.height; y++)
550                         {
551                                 for (int x = 0; x < __gemSize.width; x++)
552                                 {
553                                         *pGemPixel++ = *pPixel++;
554                                 }
555
556                                 pGemPixel = (int*)(((char*)pGemPixel) + gap);
557                         }
558                 }
559
560                 tbm_bo_unmap(__pTbmBo);
561                 __pGemBuffer = null;
562         }
563 }
564
565 void*
566 _AppWidgetBuffer::_GemBuffer::OnGetBuffer(void)
567 {
568         return __pGemBuffer;
569 }
570
571 }} // Tizen::Shell