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 31namespace BPrivate { 32 33 34static 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*/ 46status_t 47get_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*/ 78status_t 79get_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*/ 95status_t 96get_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*/ 122status_t 123get_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*/ 132team_id 133current_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 144void 145init_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*/ 158thread_id 159main_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*/ 175bool 176is_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*/ 210status_t 211create_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 243static port_id sServerPort = -1; 244 245 246port_id 247get_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*/ 261status_t 262create_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