1/*
2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors.
3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com>
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include <libfoundation/Logger.h>
10#include <libfoundation/ProcessInfo.h>
11#include <libipc/ClientConnection.h>
12#include <libui/Connection.h>
13#include <libui/Window.h>
14#include <memory>
15#include <new>
16#include <sched.h>
17#include <sys/socket.h>
18
19// #define DEBUG_CONNECTION
20
21namespace UI {
22
23static Connection* s_the = nullptr;
24
25Connection& Connection::the()
26{
27 // FIXME: Thread-safe method to be applied
28 if (!s_the) {
29 new Connection(socket(PF_LOCAL, 0, 0));
30 }
31 return *s_the;
32}
33
34Connection::Connection(int connection_fd)
35 : m_connection_fd(connection_fd)
36 , m_server_decoder()
37 , m_client_decoder()
38 , m_connection_with_server(m_connection_fd, m_server_decoder, m_client_decoder)
39{
40 s_the = this;
41 if (m_connection_fd > 0) {
42 bool connected = false;
43 // Trying to connect for 100 times. If unsuccesfull, it crashes.
44 for (int i = 0; i < 100; i++) {
45 if (connect(m_connection_fd, "/tmp/win.sock", 13) == 0) {
46 connected = true;
47 break;
48 }
49 sched_yield();
50 }
51 if (!connected) {
52 goto crash;
53 }
54
55 greeting();
56 setup_listners();
57 return;
58 }
59crash:
60 exit(-1);
61}
62
63void Connection::setup_listners()
64{
65 LFoundation::EventLoop::the().add(
66 m_connection_fd, [] {
67 Connection::the().listen();
68 },
69 nullptr);
70}
71
72void Connection::greeting()
73{
74 auto resp_message = send_sync_message<GreetMessageReply>(GreetMessage(getpid()));
75 m_connection_id = resp_message->connection_id();
76 m_connection_with_server.set_accepted_key(m_connection_id);
77#ifdef DEBUG_CONNECTION
78 Logger::debug << "Got greet with server" << std::endl;
79#endif
80}
81
82int Connection::new_window(const Window& window)
83{
84 const std::string& bundle_id = LFoundation::ProcessInfo::the().bundle_id();
85 auto message = CreateWindowMessage(key(), window.type(), window.bounds().width(), window.bounds().height(),
86 window.buffer().id(), window.title(), window.icon_path(), bundle_id,
87 window.status_bar_style().color().u32(), window.status_bar_style().flags());
88 auto resp_message = send_sync_message<CreateWindowMessageReply>(message);
89#ifdef DEBUG_CONNECTION
90 Logger::debug << "New window created" << std::endl;
91#endif
92 return resp_message->window_id();
93}
94} // namespace UI