use SysPropagate() log
[platform/framework/native/appfw.git] / src / app / FApp_ActiveWindowManager.cpp
1 //
2 // Copyright (c) 2012 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  * @file         FApp_ActiveWindowManager.cpp
19  * @brief       This is the implementation for the _ActiveWindowManager.cpp class.
20  */
21
22 #include <unique_ptr.h>
23
24 #include <aul/aul.h>
25 #include <Ecore.h>
26 #include <Ecore_X.h>
27 #include <X11/Xlib.h>
28
29 #include <FBaseSysLog.h>
30 #include <FAppIActiveAppEventListener.h>
31
32 #include <FBaseRt_LibraryImpl.h>
33
34 #include "FApp_Aul.h"
35 #include "FApp_ActiveWindowManager.h"
36
37 using namespace Tizen::Base;
38 using namespace Tizen::Base::Collection;
39 using namespace Tizen::Base::Runtime;
40
41 namespace
42 {
43
44 const wchar_t OSP_ECORE_X_SONAME[] = L"libecore_x.so.1";
45 const wchar_t OSP_ECORE_SONAME[] = L"libecore.so.1";
46 const wchar_t OSP_X11_SONAME[] = L"libX11.so.6";
47
48 // ActiveWindow related function and variable from shared library.
49 // libecore_x.so.1
50 static Ecore_X_Atom(* p_ecore_x_atom_get)(const char* name) = null;
51 static int(* p_ecore_x_window_prop_window_get)(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window* val, unsigned int len) = null;
52 static Eina_Bool(* p_ecore_x_netwm_pid_get)(Ecore_X_Window win, int* pid) = null;
53 static int(* p_ecore_x_netwm_name_get)(Ecore_X_Window win, char** name) = null;
54 static Ecore_X_Window* (* p_ecore_x_window_root_list)(int* num_ret) = null;
55 static int* p_ECORE_X_EVENT_WINDOW_PROPERTY = null;
56 // libecore.so.1
57 static Ecore_Event_Handler* (* p_ecore_event_handler_add)(int type, Ecore_Event_Handler_Cb func, const void* data) = null;
58 static void* (* p_ecore_event_handler_del)(Ecore_Event_Handler* event_handler) = null;
59 // libX11.so
60 static int (* p_XSelectInput)(Display* display, Window w, long event_mask) = null;
61 static Display* (* p_XOpenDisplay)(_Xconst char* display_name) = null;
62 static int (* p_XCloseDisplay)(Display* display) = null;
63
64 static Ecore_Event_Handler* pWindowPropertyChanged = null;
65
66 struct _DisplayDeleter
67 {
68         void operator()(Display* pDisplay)
69         {
70                 if (p_XOpenDisplay)
71                 {
72                         p_XCloseDisplay(pDisplay);
73                 }
74         }
75 };
76
77 } // anonymous name-space
78
79
80 namespace Tizen { namespace App
81 {
82
83 _ActiveWindowManager::_ActiveWindowManager(void)
84         : __pX11Library(null)
85         , __pEcoreXLibrary(null)
86         , __pEcoreLibrary(null)
87 {
88 }
89
90 _ActiveWindowManager::~_ActiveWindowManager(void)
91 {
92         if (__activeAppEventListenerList.GetCount() > 0)
93         {
94                 if (p_ecore_event_handler_del == null)
95                 {
96                         _LibraryImpl& lib = GetEcoreLibraryImpl();
97                         p_ecore_event_handler_del = reinterpret_cast<void*(*)(Ecore_Event_Handler* event_handler)>(lib.GetProcAddress(L"ecore_event_handler_del"));
98                 }
99                 if (p_ecore_event_handler_del)
100                 {
101                         if (pWindowPropertyChanged)
102                         {
103                                 p_ecore_event_handler_del(pWindowPropertyChanged);
104                                 pWindowPropertyChanged = null;
105                         }
106                 }
107         }
108
109         delete __pX11Library;
110         delete __pEcoreXLibrary;
111         __pEcoreXLibrary = null;
112         delete __pEcoreLibrary;
113         __pEcoreLibrary = null;
114 }
115
116 Eina_Bool
117 _ActiveWindowManager::OnPropertyChanged(void* pData, int type, void* pEvent)
118 {
119         if (!pData)
120         {
121                 SysLog(NID_UI, "The data is not valid.");
122                 return EINA_FALSE;
123         }
124
125         _ActiveWindowManager* pThis = static_cast<_ActiveWindowManager*>(pData);
126
127         if (p_ecore_x_atom_get == null)
128         {
129                 _LibraryImpl& lib = pThis->GetEcoreXLibraryImpl();
130                 p_ecore_x_atom_get = reinterpret_cast<Ecore_X_Atom(*)(const char* name)>(lib.GetProcAddress(L"ecore_x_atom_get"));
131                 SysTryReturnResult(NID_APP, p_ecore_x_atom_get != null, EINA_FALSE,
132                                 "A system error has been occurred. Failed to get ecore_x_atom_get.");
133         }
134         if (p_ecore_x_window_prop_window_get == null)
135         {
136                 _LibraryImpl& lib = pThis->GetEcoreXLibraryImpl();
137                 p_ecore_x_window_prop_window_get = reinterpret_cast<int(*)(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window* val, unsigned int len)>(lib.GetProcAddress(L"ecore_x_window_prop_window_get"));
138                 SysTryReturnResult(NID_APP, p_ecore_x_window_prop_window_get != null, EINA_FALSE,
139                                 "A system error has been occurred. Failed to get ecore_x_window_prop_window_get.");
140         }
141         if (p_ecore_x_netwm_pid_get == null)
142         {
143                 _LibraryImpl& lib = pThis->GetEcoreXLibraryImpl();
144                 p_ecore_x_netwm_pid_get = reinterpret_cast<Eina_Bool(*)(Ecore_X_Window win, int* pid)>(lib.GetProcAddress(L"ecore_x_netwm_pid_get"));
145                 SysTryReturnResult(NID_APP, p_ecore_x_netwm_pid_get != null, EINA_FALSE,
146                                 "A system error has been occurred. Failed to get ecore_x_netwm_pid_get.");
147         }
148         if (p_ecore_x_netwm_name_get == null)
149         {
150                 _LibraryImpl& lib = pThis->GetEcoreXLibraryImpl();
151                 p_ecore_x_netwm_name_get = reinterpret_cast<int(*)(Ecore_X_Window win, char** name)>(lib.GetProcAddress(L"ecore_x_netwm_name_get"));
152                 SysTryReturnResult(NID_APP, p_ecore_x_netwm_name_get != null, EINA_FALSE,
153                                 "A system error has been occurred. Failed to get ecore_x_netwm_name_get.");
154         }
155
156         if (!pEvent)
157         {
158                 SysLog(NID_UI, "The event is not valid.");
159                 return EINA_FALSE;
160         }
161
162         Ecore_X_Event_Window_Property* pE = (Ecore_X_Event_Window_Property*) pEvent;
163         Ecore_X_Atom atom = pE->atom;
164         Ecore_X_Atom activeAtom = p_ecore_x_atom_get("_NET_ACTIVE_WINDOW");
165
166         if (atom != activeAtom)
167         {
168                 return ECORE_CALLBACK_PASS_ON;
169         }
170
171         Ecore_X_Window win = pE->win;
172         Ecore_X_Window activeWin = 0;
173         p_ecore_x_window_prop_window_get(win, activeAtom, &activeWin, 1);
174
175         int pid = 0;
176         p_ecore_x_netwm_pid_get(activeWin, &pid);
177
178         char* pAppName = null;
179         p_ecore_x_netwm_name_get(activeWin, &pAppName);
180
181         pThis->FireActiveAppEvent(activeWin, pid, pAppName);
182
183         if (pAppName)
184         {
185                 free(pAppName);
186         }
187
188         return ECORE_CALLBACK_PASS_ON;
189 }
190
191 result
192 _ActiveWindowManager::AddActiveAppEventListener(IActiveAppEventListener& listener)
193 {
194         if (p_ecore_x_window_root_list == null)
195         {
196                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
197                 p_ecore_x_window_root_list = reinterpret_cast<Ecore_X_Window*(*)(int* num_ret)>(lib.GetProcAddress(L"ecore_x_window_root_list"));
198                 SysTryReturnResult(NID_APP, p_ecore_x_window_root_list != null, E_SYSTEM,
199                                 "A system error has been occurred. Failed to get p_ecore_x_window_root_list.");
200         }
201         if (p_ECORE_X_EVENT_WINDOW_PROPERTY == null)
202         {
203                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
204                 p_ECORE_X_EVENT_WINDOW_PROPERTY = reinterpret_cast<int*>(lib.GetProcAddress(L"ECORE_X_EVENT_WINDOW_PROPERTY"));
205                 SysTryReturnResult(NID_APP, p_ECORE_X_EVENT_WINDOW_PROPERTY != null, E_SYSTEM,
206                                 "A system error has been occurred. Failed to get p_ECORE_X_EVENT_WINDOW_PROPERTY.");
207         }
208         if (p_XOpenDisplay == null)
209         {
210                 _LibraryImpl& lib = GetX11LibraryImpl();
211                 p_XOpenDisplay = reinterpret_cast<Display*(*)(_Xconst char* display_name)>(lib.GetProcAddress(L"XOpenDisplay"));
212                 SysTryReturnResult(NID_APP, p_XOpenDisplay != null, E_SYSTEM,
213                                 "A system error has been occurred. Failed to get p_XOpenDisplay.");
214         }
215         if (p_XCloseDisplay == null)
216         {
217                 _LibraryImpl& lib = GetX11LibraryImpl();
218                 p_XCloseDisplay = reinterpret_cast<int(*)(Display* display)>(lib.GetProcAddress(L"XCloseDisplay"));
219                 SysTryReturnResult(NID_APP, p_XCloseDisplay != null, E_SYSTEM,
220                                 "A system error has been occurred. Failed to get p_XCloseDisplay.");
221         }
222         if (p_XSelectInput == null)
223         {
224                 _LibraryImpl& lib = GetX11LibraryImpl();
225                 p_XSelectInput = reinterpret_cast<int(*)(Display* display, Window w, long event_mask)>(lib.GetProcAddress(L"XSelectInput"));
226                 SysTryReturnResult(NID_APP, p_XSelectInput != null, E_SYSTEM,
227                                 "A system error has been occurred. Failed to get p_XSelectInput.");
228         }
229
230         if (p_ecore_event_handler_add == null)
231         {
232                 _LibraryImpl& lib = GetEcoreLibraryImpl();
233                 p_ecore_event_handler_add = reinterpret_cast<Ecore_Event_Handler*(*)(int type, Ecore_Event_Handler_Cb func, const void* data)>(lib.GetProcAddress(L"ecore_event_handler_add"));
234                 SysTryReturnResult(NID_APP, p_ecore_event_handler_add != null, E_SYSTEM,
235                                 "A system error has been occurred. Failed to get p_ecore_event_handler_add.");
236         }
237
238         bool alreadyExist = __activeAppEventListenerList.Contains(&listener);
239         SysTryReturnResult(NID_APP, !alreadyExist, E_OBJ_ALREADY_EXIST, "The event listener already exist.");
240         result r = __activeAppEventListenerList.Add(&listener);
241         if (IsFailed(r))
242         {
243                 SysPropagate(NID_APP, r);
244                 return r;
245         }
246
247         if (!pWindowPropertyChanged)
248         {
249                 std::unique_ptr<Display, _DisplayDeleter> pDisplay(p_XOpenDisplay(NULL));
250                 SysTryReturnResult(NID_APP, pDisplay != null, E_SYSTEM, "A system error has been occurred. Failed to XOpenDisplay.");
251
252                 int num = 0;
253                 Ecore_X_Window* pRoots = p_ecore_x_window_root_list(&num);
254                 SysTryReturnResult(NID_APP, pRoots != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
255
256                 for (int i = 0; i < num; i++)
257                 {
258                         p_XSelectInput(pDisplay.get(), pRoots[i], PropertyChangeMask);
259                 }
260
261                 pWindowPropertyChanged = p_ecore_event_handler_add(*p_ECORE_X_EVENT_WINDOW_PROPERTY, OnPropertyChanged, (void*) this);
262                 free(pRoots);
263                 SysTryReturnResult(NID_APP, pWindowPropertyChanged, E_SYSTEM, "A system error has been occurred.");
264         }
265
266         return r;
267 }
268
269 result
270 _ActiveWindowManager::RemoveActiveAppEventListener(IActiveAppEventListener& listener)
271 {
272         if (p_ecore_event_handler_del == null)
273         {
274                 _LibraryImpl& lib = GetEcoreLibraryImpl();
275                 p_ecore_event_handler_del = reinterpret_cast<void*(*)(Ecore_Event_Handler* event_handler)>(lib.GetProcAddress(L"ecore_event_handler_del"));
276                 SysTryReturnResult(NID_APP, p_ecore_event_handler_del != null, E_SYSTEM,
277                                 "A system error has been occurred. Failed to get p_ecore_event_handler_del.");
278         }
279
280         result r = __activeAppEventListenerList.Remove(&listener);
281         if (IsFailed(r))
282         {
283                 SysPropagate(NID_APP, r);
284                 return r;
285         }
286
287         if (__activeAppEventListenerList.GetCount() == 0)
288         {
289                 p_ecore_event_handler_del(pWindowPropertyChanged);
290                 pWindowPropertyChanged = null;
291         }
292
293         return r;
294 }
295
296
297 void
298 _ActiveWindowManager::FireActiveAppEvent(unsigned int xid, int pid, const char* pAppName)
299 {
300         static int oldPid = 0;
301         if (oldPid != pid)
302         {
303                 oldPid = pid;
304                 char pkgname[255] = {0, };
305                 if ((AUL_R_OK != aul_app_get_pkgname_bypid(pid, pkgname, 255)) || pkgname[0] == 0)
306                 {
307                         SysSecureLog(NID_APP, "Failed to get the package name from pid=%x pAppName=%s", pid, pAppName ? pAppName : "null");
308                         return;
309                 }
310                 AppId appId(_Aul::GetRealAppId(String(pkgname)));
311
312                 std::unique_ptr<IEnumeratorT<Tizen::App::IActiveAppEventListener* > > pEnum(__activeAppEventListenerList.GetEnumeratorN());
313                 if (pEnum.get())
314                 {
315                         while (pEnum->MoveNext() == E_SUCCESS)
316                         {
317                                 Tizen::App::IActiveAppEventListener* pListener = null;
318                                 pEnum->GetCurrent(pListener);
319                                 if (pListener)
320                                 {
321                                         pListener->OnActiveAppChanged(appId);
322                                 }
323                         }
324                 }
325         }
326 }
327
328
329 result
330 _ActiveWindowManager::GetActiveApp(AppId& appId)
331 {
332         const unsigned int windowId = GetActiveWindow();
333         const int processId = GetProcessId(windowId);
334         char pkgname[255] = {0, };
335         if (aul_app_get_pkgname_bypid(processId, pkgname, 255) != AUL_R_OK)
336         {
337                 SysSecureLog(NID_APP, "Failed to get the package name from pid=%x appId=%ls", processId, appId.GetPointer());
338                 return E_SYSTEM;
339         }
340
341         appId = _Aul::GetRealAppId(String(pkgname));
342
343         SysLog(NID_APP, "ActiveApp is %ls.", appId.GetPointer());
344         return E_SUCCESS;
345 }
346
347 _LibraryImpl&
348 _ActiveWindowManager::GetEcoreXLibraryImpl(void)
349 {
350         if (__pEcoreXLibrary == null)
351         {
352                 __pEcoreXLibrary = new (std::nothrow) _LibraryImpl;
353                 SysAssertf(__pEcoreXLibrary != null, "_LibraryImpl allocation failure.");
354
355                 result r = __pEcoreXLibrary->Construct(OSP_ECORE_X_SONAME);
356                 SysAssertf(r == E_SUCCESS, "Dynamic loading error : %s.", GetErrorMessage(r));
357         }
358         return *__pEcoreXLibrary;
359 }
360
361 _LibraryImpl&
362 _ActiveWindowManager::GetEcoreLibraryImpl(void)
363 {
364         if (__pEcoreLibrary == null)
365         {
366                 __pEcoreLibrary = new (std::nothrow) _LibraryImpl;
367                 SysAssertf(__pEcoreLibrary != null, "_LibraryImpl allocation failure.");
368
369                 result r = __pEcoreLibrary->Construct(OSP_ECORE_SONAME);
370                 SysAssertf(r == E_SUCCESS, "Dynamic loading error : %s.", GetErrorMessage(r));
371         }
372         return *__pEcoreLibrary;
373 }
374
375 _LibraryImpl&
376 _ActiveWindowManager::GetX11LibraryImpl(void)
377 {
378         if (__pX11Library == null)
379         {
380                 __pX11Library = new (std::nothrow) _LibraryImpl;
381                 SysAssertf(__pX11Library != null, "_LibraryImpl allocation failure.");
382
383                 result r = __pX11Library->Construct(OSP_X11_SONAME);
384                 SysAssertf(r == E_SUCCESS, "Dynamic loading error : %s.", GetErrorMessage(r));
385         }
386         return *__pX11Library;
387 }
388
389 unsigned int
390 _ActiveWindowManager::GetActiveWindow(void)
391 {
392         if (p_ecore_x_window_root_list == null)
393         {
394                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
395                 p_ecore_x_window_root_list = reinterpret_cast<Ecore_X_Window*(*)(int* num_ret)>(lib.GetProcAddress(L"ecore_x_window_root_list"));
396                 SysTryReturnResult(NID_APP, p_ecore_x_window_root_list != null, 0,
397                                 "A system error has been occurred. Failed to get p_ecore_x_window_root_list.");
398         }
399         if (p_ecore_x_atom_get == null)
400         {
401                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
402                 p_ecore_x_atom_get = reinterpret_cast<Ecore_X_Atom(*)(const char* name)>(lib.GetProcAddress(L"ecore_x_atom_get"));
403                 SysTryReturnResult(NID_APP, p_ecore_x_atom_get != null, 0,
404                                 "A system error has been occurred. Failed to get ecore_x_atom_get.");
405         }
406         if (p_ecore_x_window_prop_window_get == null)
407         {
408                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
409                 p_ecore_x_window_prop_window_get = reinterpret_cast<int(*)(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window* val, unsigned int len)>(lib.GetProcAddress(L"ecore_x_window_prop_window_get"));
410                 SysTryReturnResult(NID_APP, p_ecore_x_window_prop_window_get != null, EINA_FALSE,
411                                 "A system error has been occurred. Failed to get ecore_x_window_prop_window_get.");
412         }
413
414         int num = 0;
415         Ecore_X_Window* pRoots = p_ecore_x_window_root_list(&num);
416
417         Ecore_X_Window activeWin = 0;
418         if (pRoots)
419         {
420                 Ecore_X_Atom activeAtom = p_ecore_x_atom_get("_NET_ACTIVE_WINDOW");
421                 p_ecore_x_window_prop_window_get(pRoots[0], activeAtom, &activeWin, 1);
422                 free(pRoots);
423         }
424
425         return activeWin;
426 }
427
428 int
429 _ActiveWindowManager::GetProcessId(unsigned int window)
430 {
431         if (p_ecore_x_netwm_pid_get == null)
432         {
433                 _LibraryImpl& lib = GetEcoreXLibraryImpl();
434                 p_ecore_x_netwm_pid_get = reinterpret_cast<Eina_Bool(*)(Ecore_X_Window win, int* pid)>(lib.GetProcAddress(L"ecore_x_netwm_pid_get"));
435                 SysTryReturnResult(NID_APP, p_ecore_x_netwm_pid_get != null, EINA_FALSE,
436                                 "A system error has been occurred. Failed to get ecore_x_netwm_pid_get.");
437         }
438
439         int pid = 0;
440         p_ecore_x_netwm_pid_get(window, &pid);
441
442         return pid;
443 }
444
445 }} // Tizen::App