xref: /haiku/src/kits/app/AppMisc.cpp (revision 830f67ef991407f287dbc1238aa5f5906d90c991)
1 /*
2  * Copyright 2001-2019, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Ingo Weinhold, bonefish@@users.sf.net
8  *		Jacob Secunda
9  */
10 
11 
12 #include <AppMisc.h>
13 
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/utsname.h>
17 #include <unistd.h>
18 
19 #include <Entry.h>
20 #include <image.h>
21 #include <Messenger.h>
22 #include <OS.h>
23 #include <Window.h>
24 
25 #include <AutoDeleter.h>
26 #include <ServerLink.h>
27 #include <ServerProtocol.h>
28 #include <WindowInfo.h>
29 
30 
31 namespace BPrivate {
32 
33 
34 static team_id sCurrentTeam = -1;
35 
36 
37 /*!	\brief Returns the path to an application's executable.
38 	\param team The application's team ID.
39 	\param buffer A pointer to a pre-allocated character array of at least
40 		   size B_PATH_NAME_LENGTH to be filled in by this function.
41 	\return
42 	- \c B_OK: Everything went fine.
43 	- \c B_BAD_VALUE: \c NULL \a buffer.
44 	- another error code
45 */
46 status_t
47 get_app_path(team_id team, char *buffer)
48 {
49 	// The only way to get the path to the application's executable seems to
50 	// be to get an image_info of its image, which also contains a path.
51 	// Several images may belong to the team (libraries, add-ons), but only
52 	// the one in question should be typed B_APP_IMAGE.
53 	if (!buffer)
54 		return B_BAD_VALUE;
55 
56 	image_info info;
57 	int32 cookie = 0;
58 
59 	while (get_next_image_info(team, &cookie, &info) == B_OK) {
60 		if (info.type == B_APP_IMAGE) {
61 			strlcpy(buffer, info.name, B_PATH_NAME_LENGTH - 1);
62 			return B_OK;
63 		}
64 	}
65 
66 	return B_ENTRY_NOT_FOUND;
67 }
68 
69 
70 /*!	\brief Returns the path to the application's executable.
71 	\param buffer A pointer to a pre-allocated character array of at least
72 		   size B_PATH_NAME_LENGTH to be filled in by this function.
73 	\return
74 	- \c B_OK: Everything went fine.
75 	- \c B_BAD_VALUE: \c NULL \a buffer.
76 	- another error code
77 */
78 status_t
79 get_app_path(char *buffer)
80 {
81 	return get_app_path(B_CURRENT_TEAM, buffer);
82 }
83 
84 
85 /*!	\brief Returns an entry_ref referring to an application's executable.
86 	\param team The application's team ID.
87 	\param ref A pointer to a pre-allocated entry_ref to be initialized
88 		   to an entry_ref referring to the application's executable.
89 	\param traverse If \c true, the function traverses symbolic links.
90 	\return
91 	- \c B_OK: Everything went fine.
92 	- \c B_BAD_VALUE: \c NULL \a ref.
93 	- another error code
94 */
95 status_t
96 get_app_ref(team_id team, entry_ref *ref, bool traverse)
97 {
98 	status_t error = (ref ? B_OK : B_BAD_VALUE);
99 	char appFilePath[B_PATH_NAME_LENGTH];
100 
101 	if (error == B_OK)
102 		error = get_app_path(team, appFilePath);
103 
104 	if (error == B_OK) {
105 		BEntry entry(appFilePath, traverse);
106 		error = entry.GetRef(ref);
107 	}
108 
109 	return error;
110 }
111 
112 
113 /*!	\brief Returns an entry_ref referring to the application's executable.
114 	\param ref A pointer to a pre-allocated entry_ref to be initialized
115 		   to an entry_ref referring to the application's executable.
116 	\param traverse If \c true, the function traverses symbolic links.
117 	\return
118 	- \c B_OK: Everything went fine.
119 	- \c B_BAD_VALUE: \c NULL \a ref.
120 	- another error code
121 */
122 status_t
123 get_app_ref(entry_ref *ref, bool traverse)
124 {
125 	return get_app_ref(B_CURRENT_TEAM, ref, traverse);
126 }
127 
128 
129 /*!	\brief Returns the ID of the current team.
130 	\return The ID of the current team.
131 */
132 team_id
133 current_team()
134 {
135 	if (sCurrentTeam < 0) {
136 		thread_info info;
137 		if (get_thread_info(find_thread(NULL), &info) == B_OK)
138 			sCurrentTeam = info.team;
139 	}
140 	return sCurrentTeam;
141 }
142 
143 
144 void
145 init_team_after_fork()
146 {
147 	sCurrentTeam = -1;
148 }
149 
150 
151 /*!	Returns the ID of the supplied team's main thread.
152 	\param team The team.
153 	\return
154 	- The thread ID of the supplied team's main thread
155 	- \c B_BAD_TEAM_ID: The supplied team ID does not identify a running team.
156 	- another error code
157 */
158 thread_id
159 main_thread_for(team_id team)
160 {
161 	// Under Haiku the team ID is equal to it's main thread ID. We just get
162 	// a team info to verify the existence of the team.
163 	team_info info;
164 	status_t error = get_team_info(team, &info);
165 	return error == B_OK ? team : error;
166 }
167 
168 
169 /*!	\brief Returns whether the application identified by the supplied
170 		   \c team_id is currently showing a modal window.
171 	\param team the ID of the application in question.
172 	\return \c true, if the application is showing a modal window, \c false
173 			otherwise.
174 */
175 bool
176 is_app_showing_modal_window(team_id team)
177 {
178 	int32 tokenCount;
179 	int32* tokens = get_token_list(team, &tokenCount);
180 
181 	if (tokens != NULL) {
182 		MemoryDeleter tokenDeleter(tokens);
183 
184 		for (int32 index = 0; index < tokenCount; index++) {
185 			client_window_info* matchWindowInfo = get_window_info(tokens[index]);
186 			if (matchWindowInfo == NULL) {
187 				// That window probably closed. Just go to the next one.
188 				continue;
189 			}
190 
191 			window_feel theFeel = (window_feel)matchWindowInfo->feel;
192 			free(matchWindowInfo);
193 
194 			if (theFeel == B_MODAL_SUBSET_WINDOW_FEEL
195 				|| theFeel == B_MODAL_APP_WINDOW_FEEL
196 				|| theFeel == B_MODAL_ALL_WINDOW_FEEL)
197 				return true;
198 		}
199 	}
200 
201 	return false;
202 }
203 
204 
205 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
206 
207 
208 /*!	Creates a connection with the desktop.
209 */
210 status_t
211 create_desktop_connection(ServerLink* link, const char* name, int32 capacity)
212 {
213 	// Create the port so that the app_server knows where to send messages
214 	port_id clientPort = create_port(capacity, name);
215 	if (clientPort < 0)
216 		return clientPort;
217 
218 	link->SetReceiverPort(clientPort);
219 
220 	BMessage request(AS_GET_DESKTOP);
221 	request.AddInt32("user", getuid());
222 	request.AddInt32("version", AS_PROTOCOL_VERSION);
223 	request.AddString("target", getenv("TARGET_SCREEN"));
224 
225 	BMessenger server("application/x-vnd.Haiku-app_server");
226 	BMessage reply;
227 	status_t status = server.SendMessage(&request, &reply);
228 	if (status != B_OK)
229 		return status;
230 
231 	port_id desktopPort = reply.GetInt32("port", B_ERROR);
232 	if (desktopPort < 0)
233 		return desktopPort;
234 
235 	link->SetSenderPort(desktopPort);
236 	return B_OK;
237 }
238 
239 
240 #else // HAIKU_TARGET_PLATFORM_LIBBE_TEST
241 
242 
243 static port_id sServerPort = -1;
244 
245 
246 port_id
247 get_app_server_port()
248 {
249 	if (sServerPort < 0) {
250 		// No need for synchronization - in the worst case, we'll call
251 		// find_port() twice.
252 		sServerPort = find_port(SERVER_PORT_NAME);
253 	}
254 
255 	return sServerPort;
256 }
257 
258 
259 /*! Creates a connection with the desktop.
260 */
261 status_t
262 create_desktop_connection(ServerLink* link, const char* name, int32 capacity)
263 {
264 	port_id serverPort = get_app_server_port();
265 	if (serverPort < 0)
266 		return serverPort;
267 
268 	// Create the port so that the app_server knows where to send messages
269 	port_id clientPort = create_port(capacity, name);
270 	if (clientPort < 0)
271 		return clientPort;
272 
273 	link->SetTo(serverPort, clientPort);
274 
275 	link->StartMessage(AS_GET_DESKTOP);
276 	link->Attach<port_id>(clientPort);
277 	link->Attach<int32>(getuid());
278 	link->AttachString(getenv("TARGET_SCREEN"));
279 	link->Attach<int32>(AS_PROTOCOL_VERSION);
280 
281 	int32 code;
282 	if (link->FlushWithReply(code) != B_OK || code != B_OK) {
283 		link->SetSenderPort(-1);
284 		return B_ERROR;
285 	}
286 
287 	link->Read<port_id>(&serverPort);
288 	link->SetSenderPort(serverPort);
289 
290 	return B_OK;
291 }
292 
293 
294 #endif // HAIKU_TARGET_PLATFORM_LIBBE_TEST
295 
296 
297 } // namespace BPrivate
298