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