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