BPicture: Fix archive constructor.
[haiku.git] / src / kits / app / Messenger.cpp
blob47e0b076885e024b03c8455c02f3a528e49c6cf9
1 /*
2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold (bonefish@users.sf.net)
7 */
10 #include <Messenger.h>
12 #include <new>
13 #include <stdio.h>
14 #include <strings.h>
16 #include <Application.h>
17 #include <AutoLocker.h>
18 #include <Handler.h>
19 #include <Looper.h>
20 #include <Message.h>
21 #include <OS.h>
22 #include <Roster.h>
24 #include <AppMisc.h>
25 #include <LaunchRoster.h>
26 #include <LooperList.h>
27 #include <MessagePrivate.h>
28 #include <MessageUtils.h>
29 #include <TokenSpace.h>
32 // debugging
33 //#define DBG(x) x
34 #define DBG(x)
35 #define OUT printf
37 using BPrivate::gDefaultTokens;
38 using BPrivate::gLooperList;
39 using BPrivate::BLooperList;
41 enum {
42 NOT_IMPLEMENTED = B_ERROR,
46 BMessenger::BMessenger()
48 fPort(-1),
49 fHandlerToken(B_NULL_TOKEN),
50 fTeam(-1)
55 BMessenger::BMessenger(const char* signature, team_id team, status_t* result)
57 fPort(-1),
58 fHandlerToken(B_NULL_TOKEN),
59 fTeam(-1)
61 _InitData(signature, team, result);
65 BMessenger::BMessenger(const BHandler* handler, const BLooper* looper,
66 status_t* _result)
68 fPort(-1),
69 fHandlerToken(B_NULL_TOKEN),
70 fTeam(-1)
72 _InitData(handler, looper, _result);
76 BMessenger::BMessenger(const BMessenger& other)
78 fPort(other.fPort),
79 fHandlerToken(other.fHandlerToken),
80 fTeam(other.fTeam)
85 BMessenger::~BMessenger()
90 // #pragma mark - Target
93 bool
94 BMessenger::IsTargetLocal() const
96 return BPrivate::current_team() == fTeam;
100 BHandler*
101 BMessenger::Target(BLooper** _looper) const
103 BHandler* handler = NULL;
104 if (IsTargetLocal()
105 && (fHandlerToken > B_NULL_TOKEN
106 || fHandlerToken == B_PREFERRED_TOKEN)) {
107 gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN,
108 (void**)&handler);
109 if (_looper)
110 *_looper = BPrivate::gLooperList.LooperForPort(fPort);
111 } else if (_looper)
112 *_looper = NULL;
114 return handler;
118 bool
119 BMessenger::LockTarget() const
121 BLooper* looper = NULL;
122 Target(&looper);
123 if (looper != NULL && looper->Lock()) {
124 if (looper->fMsgPort == fPort)
125 return true;
127 looper->Unlock();
128 return false;
131 return false;
135 status_t
136 BMessenger::LockTargetWithTimeout(bigtime_t timeout) const
138 BLooper* looper = NULL;
139 Target(&looper);
140 if (looper == NULL)
141 return B_BAD_VALUE;
143 status_t result = looper->LockWithTimeout(timeout);
145 if (result == B_OK && looper->fMsgPort != fPort) {
146 looper->Unlock();
147 return B_BAD_PORT_ID;
150 return result;
154 // #pragma mark - Message sending
157 status_t
158 BMessenger::SendMessage(uint32 command, BHandler* replyTo) const
160 BMessage message(command);
161 return SendMessage(&message, replyTo);
165 status_t
166 BMessenger::SendMessage(BMessage* message, BHandler* replyTo,
167 bigtime_t timeout) const
169 DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what));
171 status_t result = message != NULL ? B_OK : B_BAD_VALUE;
172 if (result == B_OK) {
173 BMessenger replyMessenger(replyTo);
174 result = SendMessage(message, replyMessenger, timeout);
177 DBG(OUT("BMessenger::SendMessage2() done: %lx\n", result));
179 return result;
183 status_t
184 BMessenger::SendMessage(BMessage* message, BMessenger replyTo,
185 bigtime_t timeout) const
187 if (message == NULL)
188 return B_BAD_VALUE;
190 return BMessage::Private(message).SendMessage(fPort, fTeam, fHandlerToken,
191 timeout, false, replyTo);
195 status_t
196 BMessenger::SendMessage(uint32 command, BMessage* reply) const
198 BMessage message(command);
200 return SendMessage(&message, reply);
204 status_t
205 BMessenger::SendMessage(BMessage* message, BMessage* reply,
206 bigtime_t deliveryTimeout, bigtime_t replyTimeout) const
208 if (message == NULL || reply == NULL)
209 return B_BAD_VALUE;
211 status_t result = BMessage::Private(message).SendMessage(fPort, fTeam,
212 fHandlerToken, reply, deliveryTimeout, replyTimeout);
214 // map this result for now
215 if (result == B_BAD_TEAM_ID)
216 result = B_BAD_PORT_ID;
218 return result;
222 // #pragma mark - Operators and misc
225 status_t
226 BMessenger::SetTo(const char* signature, team_id team)
228 status_t result = B_OK;
229 _InitData(signature, team, &result);
231 return result;
235 status_t
236 BMessenger::SetTo(const BHandler* handler, const BLooper* looper)
238 status_t result = B_OK;
239 _InitData(handler, looper, &result);
241 return result;
245 BMessenger&
246 BMessenger::operator=(const BMessenger& other)
248 if (this != &other) {
249 fPort = other.fPort;
250 fHandlerToken = other.fHandlerToken;
251 fTeam = other.fTeam;
254 return *this;
258 bool
259 BMessenger::operator==(const BMessenger& other) const
261 // Note: The fTeam fields are not compared.
262 return fPort == other.fPort && fHandlerToken == other.fHandlerToken;
266 bool
267 BMessenger::IsValid() const
269 port_info info;
270 return fPort >= 0 && get_port_info(fPort, &info) == B_OK;
274 team_id
275 BMessenger::Team() const
277 return fTeam;
281 uint32
282 BMessenger::HashValue() const
284 return fPort * 19 + fHandlerToken;
288 // #pragma mark - Private or reserved
291 /*! Sets the messenger's team, target looper port and handler token.
293 To target the preferred handler, use \c B_PREFERRED_TOKEN as token.
295 \param team The target's team.
296 \param port The target looper port.
297 \param token The target handler token.
299 void
300 BMessenger::_SetTo(team_id team, port_id port, int32 token)
302 fTeam = team;
303 fPort = port;
304 fHandlerToken = token;
308 /*! Initializes the BMessenger object's data given the signature and/or
309 team ID of a target.
311 When only a signature is given, and multiple instances of the application
312 are running it is undeterminate which one is chosen as the target. In case
313 only a team ID is passed, the target application is identified uniquely.
314 If both are supplied, the application identified by the team ID must have
315 a matching signature, otherwise the initilization fails.
317 \param signature The target application's signature. May be \c NULL.
318 \param team The target application's team ID. May be < 0.
319 \param result An optional pointer to a pre-allocated status_t into which
320 the result of the initialization is written.
322 void
323 BMessenger::_InitData(const char* signature, team_id team, status_t* _result)
325 status_t result = B_OK;
327 // get an app_info
328 app_info info;
329 if (team < 0) {
330 // no team ID given
331 if (signature != NULL) {
332 // Try existing launch communication data first
333 BMessage data;
334 if (BLaunchRoster().GetData(signature, data) == B_OK) {
335 info.port = data.GetInt32("port", -1);
336 team = data.GetInt32("team", -5);
338 if (info.port < 0) {
339 result = be_roster->GetAppInfo(signature, &info);
340 team = info.team;
341 // B_ERROR means that no application with the given signature
342 // is running. But we are supposed to return B_BAD_VALUE.
343 if (result == B_ERROR)
344 result = B_BAD_VALUE;
345 } else
346 info.flags = 0;
347 } else
348 result = B_BAD_TYPE;
349 } else {
350 // a team ID is given
351 result = be_roster->GetRunningAppInfo(team, &info);
352 // Compare the returned signature with the supplied one.
353 if (result == B_OK && signature != NULL
354 && strcasecmp(signature, info.signature) != 0) {
355 result = B_MISMATCHED_VALUES;
358 // check whether the app flags say B_ARGV_ONLY
359 if (result == B_OK && (info.flags & B_ARGV_ONLY) != 0) {
360 result = B_BAD_TYPE;
361 // Set the team ID nevertheless -- that's what Be's implementation
362 // does. Don't know, if that is a bug, but at least it doesn't harm.
363 fTeam = team;
365 // init our members
366 if (result == B_OK) {
367 fTeam = team;
368 fPort = info.port;
369 fHandlerToken = B_PREFERRED_TOKEN;
372 // return the result
373 if (_result != NULL)
374 *_result = result;
378 /*! Initializes the BMessenger to target the local BHandler and/or BLooper.
380 When a \c NULL handler is supplied, the preferred handler in the given
381 looper is targeted. If no looper is supplied the looper the given handler
382 belongs to is used -- that means in particular, that the handler must
383 already belong to a looper. If both are supplied the handler must actually
384 belong to looper.
386 \param handler The target handler. May be \c NULL.
387 \param looper The target looper. May be \c NULL.
388 \param result An optional pointer to a pre-allocated status_t into which
389 the result of the initialization is written.
391 void
392 BMessenger::_InitData(const BHandler* handler, const BLooper* looper,
393 status_t* _result)
395 status_t result = handler || looper != NULL ? B_OK : B_BAD_VALUE;
396 if (result == B_OK) {
397 if (handler != NULL) {
398 // BHandler is given, check/retrieve the looper.
399 if (looper != NULL) {
400 if (handler->Looper() != looper)
401 result = B_MISMATCHED_VALUES;
402 } else {
403 looper = handler->Looper();
404 if (looper == NULL)
405 result = B_MISMATCHED_VALUES;
409 // set port, token,...
410 if (result == B_OK) {
411 AutoLocker<BLooperList> locker(gLooperList);
412 if (locker.IsLocked() && gLooperList.IsLooperValid(looper)) {
413 fPort = looper->fMsgPort;
414 fHandlerToken = handler != NULL
415 ? _get_object_token_(handler)
416 : B_PREFERRED_TOKEN;
417 fTeam = looper->Team();
418 } else
419 result = B_BAD_VALUE;
423 if (_result != NULL)
424 *_result = result;
428 // #pragma mark - Operator functions
431 bool
432 operator<(const BMessenger& _a, const BMessenger& _b)
434 BMessenger::Private a(const_cast<BMessenger&>(_a));
435 BMessenger::Private b(const_cast<BMessenger&>(_b));
437 // significance:
438 // 1. fPort
439 // 2. fHandlerToken
440 // 3. fPreferredTarget
441 // fTeam is insignificant
442 return (a.Port() < b.Port()
443 || (a.Port() == b.Port()
444 && (a.Token() < b.Token()
445 || (a.Token() == b.Token()
446 && !a.IsPreferredTarget()
447 && b.IsPreferredTarget()))));
451 bool
452 operator!=(const BMessenger& a, const BMessenger& b)
454 return !(a == b);