Add new internal APIs
[platform/core/appfw/aul-1.git] / src / aul_window.cc
1 /*
2  * Copyright (c) 2017 - 2021 Samsung Electronics Co., Ltd. All rights reserved.
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 #include <gio/gio.h>
18 #include <glib.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21
22 #include <bundle_cpp.h>
23
24 #include <memory>
25 #include <mutex>
26 #include <string>
27
28 #include "app_request.h"
29 #include "aul_api.h"
30 #include "aul_util.h"
31 #include "include/aul.h"
32 #include "include/aul_app_com.h"
33 #include "include/aul_cmd.h"
34 #include "include/aul_window.h"
35 #include "launch.h"
36
37 using namespace aul;
38 using namespace aul::internal;
39
40 namespace {
41
42 constexpr const char kWmBusName[] = "org.enlightenment.wm";
43 constexpr const char kWmObjectPath[] = "/org/enlightenment/wm";
44 constexpr const char kWmInterfaceName[] = "org.enlightenment.wm.proc";
45 constexpr const char kWmMethodNameInfo[] = "GetVisibleWinInfo";
46 constexpr const char kWmMethodNameFocus[] = "GetFocusProc";
47 constexpr const unsigned int kWmDbusTimeout = 5000;
48
49 GDBusConnection* system_conn;
50
51 GDBusConnection* GetConn() {
52   if (system_conn == nullptr) {
53     GError* error = nullptr;
54     system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
55     if (system_conn == nullptr) {
56       _E("g_bus_get_sync() is failed. error(%s)",
57           error ? error->message : "Unknown");
58       g_clear_error(&error);
59       return nullptr;
60     }
61   }
62
63   return system_conn;
64 }
65
66 class WindowInfo {
67  public:
68   WindowInfo(unsigned int rid, int x, int y, int w, int h,
69       bool alpha, int visibility, bool focused, int pid, int ppid,
70       int apid, int noti_level, bool opaque)
71       : rid_(rid), x_(x), y_(y), w_(w), h_(h), alpha_(alpha),
72         visibility_(visibility), focused_(focused), pid_(pid),
73         ppid_(ppid), apid_(apid), noti_level_(noti_level), opaque_(opaque) {
74   }
75
76   unsigned int GetResourceId() const {
77     return rid_;
78   }
79
80   int GetPositionX() const {
81     return x_;
82   }
83
84   int GetPositionY() const {
85     return y_;
86   }
87
88   int GetWidth() const {
89     return w_;
90   }
91
92   int GetHeight() const {
93     return h_;
94   }
95
96   bool HasAlpha() const {
97     return alpha_;
98   }
99
100   int GetVisibility() const {
101     return visibility_;
102   }
103
104   bool IsFocused() const {
105     return focused_;
106   }
107
108   int GetPid() const {
109     return pid_;
110   }
111
112   int GetParentPid() const {
113     return ppid_;
114   }
115
116   int GetAncestorPid() const {
117     return apid_;
118   }
119
120   int GetNotificationLevel() const {
121     return noti_level_;
122   }
123
124   bool IsOpaque() const {
125     return opaque_;
126   }
127
128  private:
129   unsigned int rid_;
130   int x_;
131   int y_;
132   int w_;
133   int h_;
134   bool alpha_;
135   int visibility_;
136   bool focused_;
137   int pid_;
138   int ppid_;
139   int apid_;
140   int noti_level_;
141   bool opaque_;
142 };
143
144 void WindowInfoDestroyFunc(gpointer data) {
145   auto* info = static_cast<WindowInfo*>(data);
146   if (info == nullptr)
147     return;
148
149   delete info;
150 }
151
152 class WindowEventListener {
153  public:
154   WindowEventListener() = default;
155
156   ~WindowEventListener() {
157     Deregister();
158   }
159
160   int Register(aul_window_event_cb cb, void* user_data) {
161     std::lock_guard<std::recursive_mutex> lock(GetMutex());
162     cb_ = cb;
163     user_data_ = user_data;
164
165     if (conn_ != nullptr)
166       return AUL_R_OK;
167
168     int ret = aul_app_com_create_async("aul_window_event", nullptr,
169         AppComMessageCb, this, &conn_);
170     if (ret != AUL_R_OK) {
171       _E("aul_app_com_create_async() is failed. error(%d)", ret);
172       return ret;
173     }
174
175     return AUL_R_OK;
176   }
177
178   void Deregister() {
179     std::lock_guard<std::recursive_mutex> lock(GetMutex());
180     cb_ = nullptr;
181     user_data_ = nullptr;
182
183     if (conn_ == nullptr)
184       return;
185
186     aul_app_com_leave(conn_);
187     conn_ = nullptr;
188   }
189
190  private:
191   static int AppComMessageCb(const char* endpoint, aul_app_com_result_e res,
192       bundle* envelope, void* user_data) {
193     tizen_base::Bundle b(envelope, false, false);
194     std::string event_name = b.GetString(AUL_K_EVENT_NAME);
195     std::string appid = b.GetString(AUL_K_APPID);
196     int wid = std::stoi(b.GetString(AUL_K_WID));
197     int pid = std::stoi(b.GetString(AUL_K_PID));
198
199     auto* handle = static_cast<WindowEventListener*>(user_data);
200     std::lock_guard<std::recursive_mutex> lock(handle->GetMutex());
201     if (handle->cb_) {
202       handle->cb_(event_name.c_str(), appid.c_str(), wid, pid,
203           handle->user_data_);
204     }
205
206     return 0;
207   }
208
209   std::recursive_mutex& GetMutex() const {
210     return mutex_;
211   }
212
213  private:
214   aul_app_com_connection_h conn_ = nullptr;
215   aul_window_event_cb cb_ = nullptr;
216   void* user_data_ = nullptr;
217   mutable std::recursive_mutex mutex_;
218 };
219
220 WindowEventListener listener;
221
222 }  // namespace
223
224 extern "C" API int aul_window_stack_get(aul_window_stack_h* handle) {
225   if (handle == nullptr) {
226     _E("Invalid parameter");
227     return AUL_R_EINVAL;
228   }
229
230   GDBusConnection* conn = GetConn();
231   if (conn == nullptr)
232     return AUL_R_ERROR;
233
234   auto* msg = g_dbus_message_new_method_call(kWmBusName,
235       kWmObjectPath, kWmInterfaceName, kWmMethodNameInfo);
236   if (msg == nullptr) {
237     _E("g_dbus_message_new_method_call() is faield");
238     return AUL_R_ERROR;
239   }
240   std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> msg_auto(
241       msg, g_object_unref);
242
243   GError* error = nullptr;
244   auto* reply = g_dbus_connection_send_message_with_reply_sync(conn, msg,
245       G_DBUS_SEND_MESSAGE_FLAGS_NONE, kWmDbusTimeout, nullptr, nullptr, &error);
246   if (reply == nullptr || error != nullptr) {
247     _E("g_dbus_connection_send_message_with_reply_sync() is failed. error(%s)",
248         error ? error->message : "Unknown");
249     g_clear_error(&error);
250     return AUL_R_ERROR;
251   }
252   std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> reply_auto(
253       reply, g_object_unref);
254
255   auto* body = g_dbus_message_get_body(reply);
256   if (body == nullptr) {
257     _E("g_dbus_message_get_body() is failed");
258     return AUL_R_ERROR;
259   }
260
261   unsigned int rid = 0;
262   int x = -1;
263   int y = -1;
264   int w = -1;
265   int h = -1;
266   gboolean alpha = FALSE;
267   int visibility = -1;
268   gboolean focused = FALSE;
269   int pid = -1;
270   int ppid = -1;
271   int apid = -1;
272   int noti_level = -1;
273   gboolean opaque = FALSE;
274
275   GVariantIter* iter = nullptr;
276   g_variant_get(body, "(a(uiiiibibiiiib))", &iter);
277   if (iter == nullptr)
278     return AUL_R_ERROR;
279
280   std::unique_ptr<GVariantIter, decltype(g_variant_iter_free)*> iter_auto(
281       iter, g_variant_iter_free);
282
283   GList* list = nullptr;
284   while (g_variant_iter_loop(iter, "(uiiiibibiiiib)",
285         &rid,
286         &x,
287         &y,
288         &w,
289         &h,
290         &alpha,
291         &visibility,
292         &focused,
293         &pid,
294         &ppid,
295         &apid,
296         &noti_level,
297         &opaque)) {
298     auto* info = new (std::nothrow) WindowInfo(rid, x, y, w, h,
299         alpha ? true : false, visibility, focused ? true : false,
300         pid, ppid, apid, noti_level, opaque ? true : false);
301     if (info == nullptr) {
302       _E("Out of memory");
303       g_list_free_full(list, WindowInfoDestroyFunc);
304       return AUL_R_ENOMEM;
305     }
306
307     list = g_list_append(list, info);
308   }
309
310   *handle = static_cast<aul_window_stack_h>(list);
311   return AUL_R_OK;
312 }
313
314 extern "C" API int aul_window_stack_del(aul_window_stack_h handle) {
315   if (handle == nullptr) {
316     _E("Invalid parameter");
317     return AUL_R_EINVAL;
318   }
319
320   auto* list = static_cast<GList*>(handle);
321   g_list_free_full(list, WindowInfoDestroyFunc);
322   return AUL_R_OK;
323 }
324
325 extern "C" API int aul_window_stack_foreach(aul_window_stack_h handle,
326     void (*iter_cb)(aul_window_info_h info, void* data), void* data) {
327   if (handle == nullptr || iter_cb == nullptr) {
328     _E("Invalid parameter");
329     return AUL_R_EINVAL;
330   }
331
332   auto* iter = static_cast<GList*>(handle);
333   while (iter) {
334     iter_cb(static_cast<aul_window_info_h>(iter->data), data);
335     iter = g_list_next(iter);
336   }
337
338   return AUL_R_OK;
339 }
340
341 extern "C" API int aul_window_stack_info_get_resource_id(aul_window_info_h info,
342     unsigned int* rid) {
343   if (info == nullptr || rid == nullptr) {
344     _E("Invalid parameter");
345     return AUL_R_EINVAL;
346   }
347
348   auto* handle = static_cast<WindowInfo*>(info);
349   *rid = handle->GetResourceId();
350   return AUL_R_OK;
351 }
352
353 extern "C" API int aul_window_info_get_pid(aul_window_info_h info, int* pid) {
354   if (info == nullptr || pid == nullptr) {
355     _E("Invalid parameter");
356     return AUL_R_EINVAL;
357   }
358
359   auto* handle = static_cast<WindowInfo*>(info);
360   *pid = handle->GetPid();
361   return AUL_R_OK;
362 }
363
364 extern "C" API int aul_window_info_get_parent_pid(aul_window_info_h info,
365     int* ppid) {
366   if (info == nullptr || ppid == nullptr) {
367     _E("Invalid parameter");
368     return AUL_R_EINVAL;
369   }
370
371   auto* handle = static_cast<WindowInfo*>(info);
372   *ppid = handle->GetParentPid();
373   return AUL_R_OK;
374 }
375
376 extern "C" API int aul_window_info_get_ancestor_pid(aul_window_info_h info,
377     int* apid) {
378   if (info == nullptr || apid == nullptr) {
379     _E("Invalid parameter");
380     return AUL_R_EINVAL;
381   }
382
383   auto* handle = static_cast<WindowInfo*>(info);
384   *apid = handle->GetAncestorPid();
385   return AUL_R_OK;
386 }
387
388 extern "C" API int aul_window_info_get_visibility(aul_window_info_h info,
389     int* visibility) {
390   if (info == nullptr || visibility == nullptr) {
391     _E("Invalid parameter");
392     return AUL_R_EINVAL;
393   }
394
395   auto* handle = static_cast<WindowInfo*>(info);
396   *visibility = handle->GetVisibility();
397   return AUL_R_OK;
398 }
399
400 extern "C" API int aul_window_info_has_alpha(aul_window_info_h info,
401     bool* alpha) {
402   if (info == nullptr || alpha == nullptr) {
403     _E("Invalid parameter");
404     return AUL_R_EINVAL;
405   }
406
407   auto* handle = static_cast<WindowInfo*>(info);
408   *alpha = handle->HasAlpha();
409   return AUL_R_OK;
410 }
411
412 extern "C" API int aul_window_info_is_focused(aul_window_info_h info,
413     bool* focused) {
414   if (info == nullptr || focused == nullptr) {
415     _E("Invalid parameter");
416     return AUL_R_EINVAL;
417   }
418
419   auto* handle = static_cast<WindowInfo*>(info);
420   *focused = handle->IsFocused();
421   return AUL_R_OK;
422 }
423
424 extern "C" API int aul_window_info_get_geometry(aul_window_info_h info,
425     int* x, int* y, int* w, int* h) {
426   if (info == nullptr ||
427       x == nullptr ||
428       y == nullptr ||
429       w == nullptr ||
430       h == nullptr) {
431     _E("Invalid parameter");
432     return AUL_R_EINVAL;
433   }
434
435   auto* handle = static_cast<WindowInfo*>(info);
436   *x = handle->GetPositionX();
437   *y = handle->GetPositionY();
438   *w = handle->GetWidth();
439   *h = handle->GetHeight();
440   return AUL_R_OK;
441 }
442
443 extern "C" API int aul_window_info_get_notification_level(
444     aul_window_info_h info, aul_window_notification_level_e* level) {
445   if (info == nullptr || level == nullptr) {
446     _E("Invalid parameter");
447     return AUL_R_EINVAL;
448   }
449
450   auto* handle = static_cast<WindowInfo*>(info);
451   *level = static_cast<aul_window_notification_level_e>(
452       handle->GetNotificationLevel());
453   return AUL_R_OK;
454 }
455
456 extern "C" API int aul_window_info_get_opaque(aul_window_info_h info,
457     bool* opaque) {
458   if (info == nullptr || opaque == nullptr) {
459     _E("Invalid parameter");
460     return AUL_R_EINVAL;
461   }
462
463   auto* handle = static_cast<WindowInfo*>(info);
464   *opaque = handle->IsOpaque();
465   return AUL_R_OK;
466 }
467
468 extern "C" API int aul_window_get_focused_pid(pid_t* pid) {
469   if (pid == nullptr) {
470     _E("Invalid parameter");
471     return AUL_R_EINVAL;
472   }
473
474   GDBusConnection* conn = GetConn();
475   if (conn == nullptr)
476     return AUL_R_ERROR;
477
478   auto* msg = g_dbus_message_new_method_call(kWmBusName,
479       kWmObjectPath, kWmInterfaceName, kWmMethodNameFocus);
480   if (msg == nullptr) {
481     _E("g_dbus_message_new_method_call() is failed");
482     return AUL_R_ERROR;
483   }
484   std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> msg_auto(
485       msg, g_object_unref);
486
487   GError* error = nullptr;
488   auto* reply = g_dbus_connection_send_message_with_reply_sync(conn, msg,
489       G_DBUS_SEND_MESSAGE_FLAGS_NONE, kWmDbusTimeout, nullptr, nullptr,
490       &error);
491   if (reply == nullptr || error != nullptr) {
492     _E("g_dbus_connection_send_message_with_reply_sync() is failed. error(%s)",
493         error ? error->message : "Unknown");
494     g_clear_error(&error);
495     return AUL_R_ERROR;
496   }
497   std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> reply_auto(
498       reply, g_object_unref);
499
500   auto* body = g_dbus_message_get_body(reply);
501   if (body == nullptr) {
502     _E("g_dbus_message_get_body() is failed");
503     return AUL_R_ERROR;
504   }
505
506   gint focused_pid = -1;
507   g_variant_get(body, "(i)", &focused_pid);
508   *pid = static_cast<pid_t>(focused_pid);
509   _W("Result = %d", focused_pid);
510   return AUL_R_OK;
511 }
512
513 extern "C" API int aul_window_attach(const char* parent_appid,
514     const char* child_appid) {
515   if (parent_appid == nullptr || child_appid == nullptr) {
516     _E("Invalid parameter");
517     return AUL_R_EINVAL;
518   }
519
520   tizen_base::Bundle b {
521     { AUL_K_PARENT_APPID, parent_appid },
522     { AUL_K_CHILD_APPID, child_appid }
523   };
524   int ret = AppRequest(APP_WINDOW_ATTACH, getuid())
525       .With(b)
526       .SendSimply();
527   if (ret < 0) {
528     _E("Failed to send request. error(%d)", ret);
529     return ret;
530   }
531
532   return AUL_R_OK;
533 }
534
535 extern "C" API int aul_window_detach(const char* child_appid) {
536   if (child_appid == nullptr) {
537     _E("Invalid parameter");
538     return AUL_R_EINVAL;
539   }
540
541   tizen_base::Bundle b {{ AUL_K_CHILD_APPID, child_appid }};
542   int ret = AppRequest(APP_WINDOW_DETACH, getuid())
543       .With(b)
544       .SendSimply();
545   if (ret < 0) {
546     _E("Failed to send request. error(%d)", ret);
547     return ret;
548   }
549
550   return AUL_R_OK;
551 }
552
553 extern "C" API int aul_window_attach_below(const char* parent_appid,
554     const char* child_appid) {
555   if (parent_appid == nullptr || child_appid == nullptr) {
556     _E("Invalid parameter");
557     return AUL_R_EINVAL;
558   }
559
560   tizen_base::Bundle b {
561     { AUL_K_PARENT_APPID, parent_appid },
562     { AUL_K_CHILD_APPID, child_appid }
563   };
564   int ret = AppRequest(APP_WINDOW_ATTACH_BELOW, getuid())
565       .With(b)
566       .SendSimply();
567   if (ret < 0) {
568     _E("Failed to send request. error(%d)", ret);
569     return ret;
570   }
571
572   return AUL_R_OK;
573 }
574
575 extern "C" API int aul_window_register_event_cb(aul_window_event_cb callback,
576     void* user_data) {
577   if (callback == nullptr) {
578     _E("Invalid parameter");
579     return AUL_R_EINVAL;
580   }
581
582   int ret = listener.Register(callback, user_data);
583   if (ret != AUL_R_OK)
584     return ret;
585
586   return AUL_R_OK;
587 }
588
589 extern "C" API void aul_window_deregister_event_cb(void) {
590   listener.Deregister();
591 }