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