Modify AppCoreUiThreadBase class
[platform/core/appfw/app-core.git] / tizen-cpp / app-core-ui-cpp / app_core_ui_thread_base.cc
1 /*
2  * Copyright (c) 2023 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 #include "app-core-ui-cpp/app_core_ui_thread_base.hh"
18
19 #include <Ecore.h>
20 #include <glib.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23
24 #include <thread>
25 #include <string>
26
27 #include <shared-queue.hpp>
28
29 #include "common/glib_private.hh"
30 #include "common/log_private.hh"
31
32 namespace tizen_cpp {
33 namespace {
34
35 AppCoreUiThreadBase* context = nullptr;
36
37 }  // namespace
38
39 class AppCoreUiThreadBase::Impl {
40  public:
41   Impl(AppCoreUiThreadBase* parent) : parent_(parent) {
42     context_ = g_main_context_new();
43     std::string context_str = std::to_string(
44         reinterpret_cast<unsigned long int>(context_));
45     setenv("TIZEN_GLIB_CONTEXT", context_str.c_str(), 1);
46   }
47
48   ~Impl() {
49     if (thread_.joinable())
50       thread_.join();
51
52     if (context_ != nullptr) {
53       setenv("TIZEN_GLIB_CONTEXT", "0", 1);
54       g_main_context_unref(context_);
55     }
56   }
57
58   void Run(int argc, char** argv) {
59     if (running_) {
60       _E("Already running");
61       return;
62     }
63
64     running_ = true;
65     thread_ = std::thread([&] {
66           pthread_setname_np(pthread_self(), "UIThread+");
67           parent_->OnLoopInit(argc, argv);
68           parent_->OnLoopRun();
69           running_ = false;
70           parent_->OnLoopFinish();
71         });
72   }
73
74   void Exit() {
75     if (!running_)
76       return;
77
78     parent_->OnLoopExit();
79   }
80
81   void Post(Runner runner) {
82     queue_.Push(std::move(runner));
83
84     guint source = GLib::IdleAdd(context_,
85         [](gpointer user_data) {
86           auto* impl = static_cast<AppCoreUiThreadBase::Impl*>(user_data);
87           auto action = std::move(impl->queue_.WaitAndPop());
88           action();
89           return G_SOURCE_REMOVE;
90         }, this);
91     if (source == 0)
92       _E("Failed to add idle source");
93   }
94
95  private:
96   friend class AppCoreUiThreadBase;
97   AppCoreUiThreadBase* parent_;
98
99  private:
100   std::thread thread_;
101   GMainContext* context_ = nullptr;
102   tizen_base::SharedQueue<Runner> queue_;
103   bool running_ = false;
104 };
105
106 AppCoreUiThreadBase::AppCoreUiThreadBase() : impl_(new Impl(this)) {
107   if (context != nullptr)
108     _E("Already exists");
109
110   context = this;
111 }
112
113 AppCoreUiThreadBase::~AppCoreUiThreadBase() {
114   context = nullptr;
115 }
116
117 void AppCoreUiThreadBase::Run(int argc, char** argv) {
118   impl_->Run(argc, argv);
119 }
120
121 void AppCoreUiThreadBase::Exit() {
122   impl_->Exit();
123 }
124
125 void AppCoreUiThreadBase::Post(Runner runner) {
126   impl_->Post(std::move(runner));
127 }
128
129 void AppCoreUiThreadBase::OnLoopInit(int argc, char** argv) {
130   _W("Loop init");
131   ecore_init();
132 }
133
134 void AppCoreUiThreadBase::OnLoopRun() {
135   _W("Loop run");
136   ecore_main_loop_begin();
137 }
138
139 void AppCoreUiThreadBase::OnLoopExit() {
140   _W("Loop quit");
141   ecore_main_loop_thread_safe_call_sync([](void* data) -> void* {
142         ecore_main_loop_quit();
143         return nullptr;
144       }, nullptr);
145 }
146
147 void AppCoreUiThreadBase::OnLoopFinish() {
148   _W("Loop finish");
149   ecore_shutdown();
150 }
151
152 AppCoreUiThreadBase* AppCoreUiThreadBase::GetContext() {
153   return context;
154 }
155
156 }  // namespace tizen_cpp