2 * Copyright 2001-2015 Haiku, inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
8 * Erik Jaesler, erik@cgsoftware.com
12 #include <Application.h>
23 #include <AppFileInfo.h>
29 #include <MessageRunner.h>
30 #include <ObjectList.h>
32 #include <PropertyInfo.h>
33 #include <RegistrarDefs.h>
34 #include <Resources.h>
39 #include <AppServerLink.h>
40 #include <AutoLocker.h>
41 #include <BitmapPrivate.h>
42 #include <DraggerPrivate.h>
43 #include <LaunchDaemonDefs.h>
44 #include <LaunchRoster.h>
45 #include <LooperList.h>
46 #include <MenuWindow.h>
47 #include <PicturePrivate.h>
49 #include <RosterPrivate.h>
50 #include <ServerMemoryAllocator.h>
51 #include <ServerProtocol.h>
54 using namespace BPrivate
;
57 static const char* kDefaultLooperName
= "AppLooperPort";
59 BApplication
* be_app
= NULL
;
60 BMessenger be_app_messenger
;
62 pthread_once_t sAppResourcesInitOnce
= PTHREAD_ONCE_INIT
;
63 BResources
* BApplication::sAppResources
= NULL
;
76 static property_info sPropertyInfo
[] = {
80 {B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
},
98 {B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
},
125 {B_DIRECT_SPECIFIER
},
133 {B_COUNT_PROPERTIES
},
134 {B_DIRECT_SPECIFIER
},
143 {B_DIRECT_SPECIFIER
},
152 {B_DIRECT_SPECIFIER
},
160 {B_COUNT_PROPERTIES
},
161 {B_DIRECT_SPECIFIER
},
172 extern const int __libc_argc
;
173 extern const char* const *__libc_argv
;
182 // #pragma mark - static helper functions
186 \brief Checks whether the supplied string is a valid application signature.
188 An error message is printed, if the string is no valid app signature.
190 \param signature The string to be checked.
192 \return A status code.
193 \retval B_OK \a signature is a valid app signature.
194 \retval B_BAD_VALUE \a signature is \c NULL or no valid app signature.
197 check_app_signature(const char* signature
)
199 bool isValid
= false;
200 BMimeType
type(signature
);
202 if (type
.IsValid() && !type
.IsSupertypeOnly()
203 && BMimeType("application").Contains(&type
)) {
208 printf("bad signature (%s), must begin with \"application/\" and "
209 "can't conflict with existing registered mime types inside "
210 "the \"application\" media type.\n", signature
);
213 return (isValid
? B_OK
: B_BAD_VALUE
);
217 #ifndef RUN_WITHOUT_REGISTRAR
218 // Fills the passed BMessage with B_ARGV_RECEIVED infos.
220 fill_argv_message(BMessage
&message
)
222 message
.what
= B_ARGV_RECEIVED
;
224 int32 argc
= __libc_argc
;
225 const char* const *argv
= __libc_argv
;
228 message
.AddInt32("argc", argc
);
231 for (int32 i
= 0; i
< argc
; i
++) {
233 message
.AddString("argv", argv
[i
]);
236 // add current working directory
237 char cwd
[B_PATH_NAME_LENGTH
];
238 if (getcwd(cwd
, B_PATH_NAME_LENGTH
))
239 message
.AddString("cwd", cwd
);
244 // #pragma mark - BApplication
247 BApplication::BApplication(const char* signature
)
249 BLooper(kDefaultLooperName
)
251 _InitData(signature
, true, NULL
);
255 BApplication::BApplication(const char* signature
, status_t
* _error
)
257 BLooper(kDefaultLooperName
)
259 _InitData(signature
, true, _error
);
263 BApplication::BApplication(const char* signature
, const char* looperName
,
264 port_id port
, bool initGUI
, status_t
* _error
)
266 BLooper(B_NORMAL_PRIORITY
+ 1, port
< 0 ? _GetPort(signature
) : port
,
267 looperName
!= NULL
? looperName
: kDefaultLooperName
)
269 _InitData(signature
, initGUI
, _error
);
275 BApplication::BApplication(BMessage
* data
)
276 // Note: BeOS calls the private BLooper(int32, port_id, const char*)
277 // constructor here, test if it's needed
279 BLooper(kDefaultLooperName
)
281 const char* signature
= NULL
;
282 data
->FindString("mime_sig", &signature
);
284 _InitData(signature
, true, NULL
);
287 if (data
->FindInt64("_pulse", &pulseRate
) == B_OK
)
288 SetPulseRate(pulseRate
);
292 BApplication::BApplication(uint32 signature
)
297 BApplication::BApplication(const BApplication
&rhs
)
302 BApplication::~BApplication()
306 // tell all loopers(usually windows) to quit. Also, wait for them.
307 _QuitAllWindows(true);
309 // unregister from the roster
310 BRoster::Private().RemoveApp(Team());
312 #ifndef RUN_WITHOUT_APP_SERVER
313 // tell app_server we're quitting...
315 // be_app can be NULL here if the application fails to initialize
316 // correctly. For example, if it's already running and it's set to
318 BPrivate::AppServerLink link
;
319 link
.StartMessage(B_QUIT_REQUESTED
);
322 delete_port(fServerLink
->SenderPort());
323 delete_port(fServerLink
->ReceiverPort());
325 #endif // RUN_WITHOUT_APP_SERVER
327 delete fServerAllocator
;
329 // uninitialize be_app, the be_app_messenger is invalidated automatically
335 BApplication::operator=(const BApplication
&rhs
)
342 BApplication::_InitData(const char* signature
, bool initGUI
, status_t
* _error
)
344 DBG(OUT("BApplication::InitData(`%s', %p)\n", signature
, _error
));
345 // check whether there exists already an application
347 debugger("2 BApplication objects were created. Only one is allowed.");
349 fServerLink
= new BPrivate::PortLink(-1, -1);
350 fServerAllocator
= NULL
;
351 fServerReadOnlyMemory
= NULL
;
352 fInitialWorkspace
= 0;
353 //fDraggedMessage = NULL;
354 fReadyToRunCalled
= false;
356 // initially, there is no pulse
361 fInitError
= check_app_signature(signature
);
362 fAppName
= signature
;
364 #ifndef RUN_WITHOUT_REGISTRAR
365 bool registerApp
= signature
== NULL
366 || (strcasecmp(signature
, B_REGISTRAR_SIGNATURE
) != 0
367 && strcasecmp(signature
, kLaunchDaemonSignature
) != 0);
368 // get team and thread
369 team_id team
= Team();
370 thread_id thread
= BPrivate::main_thread_for(team
);
373 // get app executable ref
375 if (fInitError
== B_OK
) {
376 fInitError
= BPrivate::get_app_ref(&ref
);
377 if (fInitError
!= B_OK
) {
378 DBG(OUT("BApplication::InitData(): Failed to get app ref: %s\n",
379 strerror(fInitError
)));
383 // get the BAppFileInfo and extract the information we need
384 uint32 appFlags
= B_REG_DEFAULT_APP_FLAGS
;
385 if (fInitError
== B_OK
) {
386 BAppFileInfo fileInfo
;
387 BFile
file(&ref
, B_READ_ONLY
);
388 fInitError
= fileInfo
.SetTo(&file
);
389 if (fInitError
== B_OK
) {
390 fileInfo
.GetAppFlags(&appFlags
);
391 char appFileSignature
[B_MIME_TYPE_LENGTH
];
392 // compare the file signature and the supplied signature
393 if (fileInfo
.GetSignature(appFileSignature
) == B_OK
394 && strcasecmp(appFileSignature
, signature
) != 0) {
395 printf("Signature in rsrc doesn't match constructor arg. (%s, %s)\n",
396 signature
, appFileSignature
);
399 DBG(OUT("BApplication::InitData(): Failed to get info from: "
400 "BAppFileInfo: %s\n", strerror(fInitError
)));
404 #ifndef RUN_WITHOUT_REGISTRAR
405 // check whether be_roster is valid
406 if (fInitError
== B_OK
&& registerApp
407 && !BRoster::Private().IsMessengerValid(false)) {
408 printf("FATAL: be_roster is not valid. Is the registrar running?\n");
409 fInitError
= B_NO_INIT
;
412 // check whether or not we are pre-registered
413 bool preRegistered
= false;
415 if (fInitError
== B_OK
&& registerApp
) {
416 if (BRoster::Private().IsAppRegistered(&ref
, team
, 0, &preRegistered
,
418 preRegistered
= false;
422 // we are pre-registered => the app info has been filled in
423 // Check whether we need to replace the looper port with a port
424 // created by the roster.
425 if (appInfo
.port
>= 0 && appInfo
.port
!= fMsgPort
) {
426 delete_port(fMsgPort
);
427 fMsgPort
= appInfo
.port
;
429 appInfo
.port
= fMsgPort
;
430 // check the signature and correct it, if necessary, also the case
431 if (strcmp(appInfo
.signature
, fAppName
))
432 BRoster::Private().SetSignature(team
, fAppName
);
433 // complete the registration
434 fInitError
= BRoster::Private().CompleteRegistration(team
, thread
,
436 } else if (fInitError
== B_OK
) {
437 // not pre-registered -- try to register the application
438 team_id otherTeam
= -1;
440 fInitError
= BRoster::Private().AddApplication(signature
, &ref
,
441 appFlags
, team
, thread
, fMsgPort
, true, NULL
, &otherTeam
);
442 if (fInitError
!= B_OK
) {
443 DBG(OUT("BApplication::InitData(): Failed to add app: %s\n",
444 strerror(fInitError
)));
447 if (fInitError
== B_ALREADY_RUNNING
) {
448 // An instance is already running and we asked for
449 // single/exclusive launch. Send our argv to the running app.
450 // Do that only, if the app is NOT B_ARGV_ONLY.
451 if (otherTeam
>= 0) {
452 BMessenger
otherApp(NULL
, otherTeam
);
453 app_info otherAppInfo
;
454 bool argvOnly
= be_roster
->GetRunningAppInfo(otherTeam
,
455 &otherAppInfo
) == B_OK
456 && (otherAppInfo
.flags
& B_ARGV_ONLY
) != 0;
458 if (__libc_argc
> 1 && !argvOnly
) {
459 // create an B_ARGV_RECEIVED message
460 BMessage
argvMessage(B_ARGV_RECEIVED
);
461 fill_argv_message(argvMessage
);
463 // replace the first argv string with the path of the
466 if (path
.SetTo(&otherAppInfo
.ref
) == B_OK
)
467 argvMessage
.ReplaceString("argv", 0, path
.Path());
470 otherApp
.SendMessage(&argvMessage
);
471 } else if (!argvOnly
)
472 otherApp
.SendMessage(B_SILENT_RELAUNCH
);
474 } else if (fInitError
== B_OK
) {
475 // the registrations was successful
476 // Create a B_ARGV_RECEIVED message and send it to ourselves.
477 // Do that even, if we are B_ARGV_ONLY.
478 // TODO: When BLooper::AddMessage() is done, use that instead of
481 DBG(OUT("info: BApplication successfully registered.\n"));
483 if (__libc_argc
> 1) {
484 BMessage
argvMessage(B_ARGV_RECEIVED
);
485 fill_argv_message(argvMessage
);
486 PostMessage(&argvMessage
, this);
488 // send a B_READY_TO_RUN message as well
489 PostMessage(B_READY_TO_RUN
, this);
490 } else if (fInitError
> B_ERRORS_END
) {
491 // Registrar internal errors shouldn't fall into the user's hands.
492 fInitError
= B_ERROR
;
496 // We need to have ReadyToRun called even when we're not using the registrar
497 PostMessage(B_READY_TO_RUN
, this);
498 #endif // ifndef RUN_WITHOUT_REGISTRAR
500 if (fInitError
== B_OK
) {
501 // TODO: Not completely sure about the order, but this should be close.
503 // init be_app and be_app_messenger
505 be_app_messenger
= BMessenger(NULL
, this);
507 // set the BHandler's name
512 if (registerApp
&& path
.SetTo(&ref
) == B_OK
)
513 create_app_meta_mime(path
.Path(), false, true, false);
515 #ifndef RUN_WITHOUT_APP_SERVER
516 // app server connection and IK initialization
518 fInitError
= _InitGUIContext();
519 #endif // RUN_WITHOUT_APP_SERVER
522 // Return the error or exit, if there was an error and no error variable
523 // has been supplied.
524 if (_error
!= NULL
) {
525 *_error
= fInitError
;
526 } else if (fInitError
!= B_OK
) {
527 DBG(OUT("BApplication::InitData() failed: %s\n", strerror(fInitError
)));
530 DBG(OUT("BApplication::InitData() done\n"));
535 BApplication::_GetPort(const char* signature
)
537 return BLaunchRoster().GetPort(signature
, NULL
);
542 BApplication::Instantiate(BMessage
* data
)
544 if (validate_instantiation(data
, "BApplication"))
545 return new BApplication(data
);
552 BApplication::Archive(BMessage
* data
, bool deep
) const
554 status_t status
= BLooper::Archive(data
, deep
);
559 status
= GetAppInfo(&info
);
563 status
= data
->AddString("mime_sig", info
.signature
);
567 return data
->AddInt64("_pulse", fPulseRate
);
572 BApplication::InitCheck() const
581 if (fInitError
!= B_OK
)
587 debugger("BApplication::Run was already called. Can only be called once.");
589 fThread
= find_thread(NULL
);
604 const char* name
= Name();
608 printf("ERROR - you must Lock the application object before calling "
609 "Quit(), team=%" B_PRId32
", looper=%s\n", Team(), name
);
614 // Delete the object, if not running only.
617 } else if (find_thread(NULL
) != fThread
) {
618 // ToDo: why shouldn't we set fTerminating to true directly in this case?
619 // We are not the looper thread.
620 // We push a _QUIT_ into the queue.
621 // TODO: When BLooper::AddMessage() is done, use that instead of
622 // PostMessage()??? This would overtake messages that are still at
624 // NOTE: We must not unlock here -- otherwise we had to re-lock, which
625 // may not work. This is bad, since, if the port is full, it
626 // won't get emptier, as the looper thread needs to lock the object
627 // before dispatching messages.
628 while (PostMessage(_QUIT_
, this) == B_WOULD_BLOCK
)
631 // We are the looper thread.
632 // Just set fTerminating to true which makes us fall through the
633 // message dispatching loop and return from Run().
637 // If we had to lock the object, unlock now.
644 BApplication::QuitRequested()
646 return _QuitAllWindows(false);
651 BApplication::Pulse()
653 // supposed to be implemented by subclasses
658 BApplication::ReadyToRun()
660 // supposed to be implemented by subclasses
665 BApplication::MessageReceived(BMessage
* message
)
667 switch (message
->what
) {
668 case B_COUNT_PROPERTIES
:
675 const char* property
= NULL
;
676 if (message
->GetCurrentSpecifier(&index
, &specifier
, &what
,
678 || !ScriptReceived(message
, index
, &specifier
, what
,
680 BLooper::MessageReceived(message
);
685 case B_SILENT_RELAUNCH
:
686 // Sent to a B_SINGLE_LAUNCH application when it's launched again
688 be_roster
->ActivateApp(Team());
691 case kMsgAppServerRestarted
:
692 _ReconnectToServer();
695 case kMsgDeleteServerMemoryArea
:
698 if (message
->FindInt32("server area", &serverArea
) == B_OK
) {
699 // The link is not used, but we currently borrow its lock
700 BPrivate::AppServerLink link
;
701 fServerAllocator
->RemoveArea(serverArea
);
707 BLooper::MessageReceived(message
);
713 BApplication::ArgvReceived(int32 argc
, char** argv
)
715 // supposed to be implemented by subclasses
720 BApplication::AppActivated(bool active
)
722 // supposed to be implemented by subclasses
727 BApplication::RefsReceived(BMessage
* message
)
729 // supposed to be implemented by subclasses
734 BApplication::AboutRequested()
736 // supposed to be implemented by subclasses
741 BApplication::ResolveSpecifier(BMessage
* message
, int32 index
,
742 BMessage
* specifier
, int32 what
, const char* property
)
744 BPropertyInfo
propInfo(sPropertyInfo
);
748 if (propInfo
.FindMatch(message
, 0, specifier
, what
, property
, &data
) >= 0) {
753 err
= specifier
->FindInt32("index", &index
);
757 if (what
== B_REVERSE_INDEX_SPECIFIER
)
758 index
= CountWindows() - index
;
760 BWindow
* window
= WindowAt(index
);
761 if (window
!= NULL
) {
762 message
->PopSpecifier();
763 BMessenger(window
).SendMessage(message
);
772 err
= specifier
->FindString("name", &name
);
776 for (int32 i
= 0;; i
++) {
777 BWindow
* window
= WindowAt(i
);
778 if (window
== NULL
) {
779 err
= B_NAME_NOT_FOUND
;
782 if (window
->Title() != NULL
&& !strcmp(window
->Title(),
784 message
->PopSpecifier();
785 BMessenger(window
).SendMessage(message
);
795 err
= specifier
->FindInt32("index", &index
);
799 if (what
== B_REVERSE_INDEX_SPECIFIER
)
800 index
= CountLoopers() - index
;
802 BLooper
* looper
= LooperAt(index
);
803 if (looper
!= NULL
) {
804 message
->PopSpecifier();
805 BMessenger(looper
).SendMessage(message
);
813 // TODO: implement getting looper by ID!
819 err
= specifier
->FindString("name", &name
);
823 for (int32 i
= 0;; i
++) {
824 BLooper
* looper
= LooperAt(i
);
825 if (looper
== NULL
) {
826 err
= B_NAME_NOT_FOUND
;
829 if (looper
->Name() != NULL
830 && strcmp(looper
->Name(), name
) == 0) {
831 message
->PopSpecifier();
832 BMessenger(looper
).SendMessage(message
);
843 return BLooper::ResolveSpecifier(message
, index
, specifier
, what
,
848 BMessage
reply(B_MESSAGE_NOT_UNDERSTOOD
);
849 reply
.AddInt32("error", err
);
850 reply
.AddString("message", strerror(err
));
851 message
->SendReply(&reply
);
860 BApplication::ShowCursor()
862 BPrivate::AppServerLink link
;
863 link
.StartMessage(AS_SHOW_CURSOR
);
869 BApplication::HideCursor()
871 BPrivate::AppServerLink link
;
872 link
.StartMessage(AS_HIDE_CURSOR
);
878 BApplication::ObscureCursor()
880 BPrivate::AppServerLink link
;
881 link
.StartMessage(AS_OBSCURE_CURSOR
);
887 BApplication::IsCursorHidden() const
889 BPrivate::AppServerLink link
;
890 int32 status
= B_ERROR
;
891 link
.StartMessage(AS_QUERY_CURSOR_HIDDEN
);
892 link
.FlushWithReply(status
);
894 return status
== B_OK
;
899 BApplication::SetCursor(const void* cursorData
)
901 BCursor
cursor(cursorData
);
902 SetCursor(&cursor
, true);
903 // forces the cursor to be sync'ed
908 BApplication::SetCursor(const BCursor
* cursor
, bool sync
)
910 BPrivate::AppServerLink link
;
911 link
.StartMessage(AS_SET_CURSOR
);
912 link
.Attach
<bool>(sync
);
913 link
.Attach
<int32
>(cursor
->fServerToken
);
917 link
.FlushWithReply(code
);
924 BApplication::CountWindows() const
926 return _CountWindows(false);
927 // we're ignoring menu windows
932 BApplication::WindowAt(int32 index
) const
934 return _WindowAt(index
, false);
935 // we're ignoring menu windows
940 BApplication::CountLoopers() const
942 AutoLocker
<BLooperList
> ListLock(gLooperList
);
943 if (ListLock
.IsLocked())
944 return gLooperList
.CountLoopers();
946 // Some bad, non-specific thing has happened
952 BApplication::LooperAt(int32 index
) const
954 BLooper
* looper
= NULL
;
955 AutoLocker
<BLooperList
> listLock(gLooperList
);
956 if (listLock
.IsLocked())
957 looper
= gLooperList
.LooperAt(index
);
964 BApplication::IsLaunching() const
966 return !fReadyToRunCalled
;
971 BApplication::Signature() const
978 BApplication::GetAppInfo(app_info
* info
) const
980 if (be_app
== NULL
|| be_roster
== NULL
)
982 return be_roster
->GetRunningAppInfo(be_app
->Team(), info
);
987 BApplication::AppResources()
989 if (sAppResources
== NULL
)
990 pthread_once(&sAppResourcesInitOnce
, &_InitAppResources
);
992 return sAppResources
;
997 BApplication::DispatchMessage(BMessage
* message
, BHandler
* handler
)
999 if (handler
!= this) {
1000 // it's not ours to dispatch
1001 BLooper::DispatchMessage(message
, handler
);
1005 switch (message
->what
) {
1006 case B_ARGV_RECEIVED
:
1007 _ArgvReceived(message
);
1010 case B_REFS_RECEIVED
:
1012 // this adds the refs that are part of this message to the recent
1013 // lists, but only folders and documents are handled here
1016 while (message
->FindRef("refs", i
++, &ref
) == B_OK
) {
1017 BEntry
entry(&ref
, true);
1018 if (entry
.InitCheck() != B_OK
)
1021 if (entry
.IsDirectory())
1022 BRoster().AddToRecentFolders(&ref
);
1024 // filter out applications, we only want to have documents
1025 // in the recent files list
1027 BNodeInfo
info(&node
);
1029 char mimeType
[B_MIME_TYPE_LENGTH
];
1030 if (info
.GetType(mimeType
) != B_OK
1031 || strcasecmp(mimeType
, B_APP_MIME_TYPE
))
1032 BRoster().AddToRecentDocuments(&ref
);
1036 RefsReceived(message
);
1040 case B_READY_TO_RUN
:
1041 if (!fReadyToRunCalled
) {
1043 fReadyToRunCalled
= true;
1047 case B_ABOUT_REQUESTED
:
1055 case B_APP_ACTIVATED
:
1058 if (message
->FindBool("active", &active
) == B_OK
)
1059 AppActivated(active
);
1063 case _SHOW_DRAG_HANDLES_
:
1066 if (message
->FindBool("show", &show
) != B_OK
)
1069 BDragger::Private::UpdateShowAllDraggers(show
);
1073 // TODO: Handle these as well
1074 case _DISPOSE_DRAG_
:
1076 puts("not yet handled message:");
1077 DBG(message
->PrintToStream());
1081 BLooper::DispatchMessage(message
, handler
);
1088 BApplication::SetPulseRate(bigtime_t rate
)
1093 // BeBook states that we have only 100,000 microseconds granularity
1094 rate
-= rate
% 100000;
1100 // reset existing pulse runner, or create new one
1101 if (fPulseRunner
== NULL
) {
1102 BMessage
pulse(B_PULSE
);
1103 fPulseRunner
= new BMessageRunner(be_app_messenger
, &pulse
, rate
);
1105 fPulseRunner
->SetInterval(rate
);
1107 // turn off pulse messages
1108 delete fPulseRunner
;
1109 fPulseRunner
= NULL
;
1118 BApplication::GetSupportedSuites(BMessage
* data
)
1123 status_t status
= data
->AddString("suites", "suite/vnd.Be-application");
1124 if (status
== B_OK
) {
1125 BPropertyInfo
propertyInfo(sPropertyInfo
);
1126 status
= data
->AddFlat("messages", &propertyInfo
);
1128 status
= BLooper::GetSupportedSuites(data
);
1136 BApplication::Perform(perform_code d
, void* arg
)
1138 return BLooper::Perform(d
, arg
);
1142 void BApplication::_ReservedApplication1() {}
1143 void BApplication::_ReservedApplication2() {}
1144 void BApplication::_ReservedApplication3() {}
1145 void BApplication::_ReservedApplication4() {}
1146 void BApplication::_ReservedApplication5() {}
1147 void BApplication::_ReservedApplication6() {}
1148 void BApplication::_ReservedApplication7() {}
1149 void BApplication::_ReservedApplication8() {}
1153 BApplication::ScriptReceived(BMessage
* message
, int32 index
,
1154 BMessage
* specifier
, int32 what
, const char* property
)
1156 BMessage
reply(B_REPLY
);
1157 status_t err
= B_BAD_SCRIPT_SYNTAX
;
1159 switch (message
->what
) {
1160 case B_GET_PROPERTY
:
1161 if (strcmp("Loopers", property
) == 0) {
1162 int32 count
= CountLoopers();
1164 for (int32 i
=0; err
== B_OK
&& i
<count
; i
++) {
1165 BMessenger
messenger(LooperAt(i
));
1166 err
= reply
.AddMessenger("result", messenger
);
1168 } else if (strcmp("Windows", property
) == 0) {
1169 int32 count
= CountWindows();
1171 for (int32 i
=0; err
== B_OK
&& i
<count
; i
++) {
1172 BMessenger
messenger(WindowAt(i
));
1173 err
= reply
.AddMessenger("result", messenger
);
1175 } else if (strcmp("Window", property
) == 0) {
1177 case B_INDEX_SPECIFIER
:
1178 case B_REVERSE_INDEX_SPECIFIER
:
1181 err
= specifier
->FindInt32("index", &index
);
1185 if (what
== B_REVERSE_INDEX_SPECIFIER
)
1186 index
= CountWindows() - index
;
1189 BWindow
* window
= WindowAt(index
);
1193 BMessenger
messenger(window
);
1194 err
= reply
.AddMessenger("result", messenger
);
1198 case B_NAME_SPECIFIER
:
1201 err
= specifier
->FindString("name", &name
);
1204 err
= B_NAME_NOT_FOUND
;
1205 for (int32 i
= 0; i
< CountWindows(); i
++) {
1206 BWindow
* window
= WindowAt(i
);
1207 if (window
&& window
->Name() != NULL
1208 && !strcmp(window
->Name(), name
)) {
1209 BMessenger
messenger(window
);
1210 err
= reply
.AddMessenger("result", messenger
);
1217 } else if (strcmp("Looper", property
) == 0) {
1219 case B_INDEX_SPECIFIER
:
1220 case B_REVERSE_INDEX_SPECIFIER
:
1223 err
= specifier
->FindInt32("index", &index
);
1227 if (what
== B_REVERSE_INDEX_SPECIFIER
)
1228 index
= CountLoopers() - index
;
1231 BLooper
* looper
= LooperAt(index
);
1235 BMessenger
messenger(looper
);
1236 err
= reply
.AddMessenger("result", messenger
);
1240 case B_NAME_SPECIFIER
:
1243 err
= specifier
->FindString("name", &name
);
1246 err
= B_NAME_NOT_FOUND
;
1247 for (int32 i
= 0; i
< CountLoopers(); i
++) {
1248 BLooper
* looper
= LooperAt(i
);
1249 if (looper
!= NULL
&& looper
->Name()
1250 && strcmp(looper
->Name(), name
) == 0) {
1251 BMessenger
messenger(looper
);
1252 err
= reply
.AddMessenger("result", messenger
);
1259 case B_ID_SPECIFIER
:
1262 debug_printf("Looper's ID specifier used but not "
1267 } else if (strcmp("Name", property
) == 0)
1268 err
= reply
.AddString("result", Name());
1272 case B_COUNT_PROPERTIES
:
1273 if (strcmp("Looper", property
) == 0)
1274 err
= reply
.AddInt32("result", CountLoopers());
1275 else if (strcmp("Window", property
) == 0)
1276 err
= reply
.AddInt32("result", CountWindows());
1280 if (err
== B_BAD_SCRIPT_SYNTAX
)
1284 reply
.what
= B_MESSAGE_NOT_UNDERSTOOD
;
1285 reply
.AddString("message", strerror(err
));
1287 reply
.AddInt32("error", err
);
1288 message
->SendReply(&reply
);
1295 BApplication::BeginRectTracking(BRect rect
, bool trackWhole
)
1297 BPrivate::AppServerLink link
;
1298 link
.StartMessage(AS_BEGIN_RECT_TRACKING
);
1299 link
.Attach
<BRect
>(rect
);
1300 link
.Attach
<int32
>(trackWhole
);
1306 BApplication::EndRectTracking()
1308 BPrivate::AppServerLink link
;
1309 link
.StartMessage(AS_END_RECT_TRACKING
);
1315 BApplication::_SetupServerAllocator()
1317 fServerAllocator
= new (std::nothrow
) BPrivate::ServerMemoryAllocator();
1318 if (fServerAllocator
== NULL
)
1321 return fServerAllocator
->InitCheck();
1326 BApplication::_InitGUIContext()
1328 // An app_server connection is necessary for a lot of stuff, so get that first.
1329 status_t error
= _ConnectToServer();
1333 // Initialize the IK after we have set be_app because of a construction
1334 // of a AppServerLink (which depends on be_app) nested inside the call
1335 // to get_menu_info.
1336 error
= _init_interface_kit_();
1340 // create global system cursors
1341 B_CURSOR_SYSTEM_DEFAULT
= new BCursor(B_HAND_CURSOR
);
1342 B_CURSOR_I_BEAM
= new BCursor(B_I_BEAM_CURSOR
);
1344 // TODO: would be nice to get the workspace at launch time from the registrar
1345 fInitialWorkspace
= current_workspace();
1352 BApplication::_ConnectToServer()
1355 = create_desktop_connection(fServerLink
, "a<app_server", 100);
1362 // 1) port_id - receiver port of a regular app
1363 // 2) port_id - looper port for this BApplication
1364 // 3) team_id - team identification field
1365 // 4) int32 - handler ID token of the app
1366 // 5) char* - signature of the regular app
1368 fServerLink
->StartMessage(AS_CREATE_APP
);
1369 fServerLink
->Attach
<port_id
>(fServerLink
->ReceiverPort());
1370 fServerLink
->Attach
<port_id
>(_get_looper_port_(this));
1371 fServerLink
->Attach
<team_id
>(Team());
1372 fServerLink
->Attach
<int32
>(_get_object_token_(this));
1373 fServerLink
->AttachString(fAppName
);
1375 area_id sharedReadOnlyArea
;
1380 if (fServerLink
->FlushWithReply(code
) == B_OK
1382 // We don't need to contact the main app_server anymore
1383 // directly; we now talk to our server alter ego only.
1384 fServerLink
->Read
<port_id
>(&serverPort
);
1385 fServerLink
->Read
<area_id
>(&sharedReadOnlyArea
);
1386 fServerLink
->Read
<team_id
>(&serverTeam
);
1388 fServerLink
->SetSenderPort(-1);
1389 debugger("BApplication: couldn't obtain new app_server comm port");
1392 fServerLink
->SetTargetTeam(serverTeam
);
1393 fServerLink
->SetSenderPort(serverPort
);
1395 status
= _SetupServerAllocator();
1401 status
= fServerAllocator
->AddArea(sharedReadOnlyArea
, area
, base
, true);
1405 fServerReadOnlyMemory
= base
;
1412 BApplication::_ReconnectToServer()
1414 delete_port(fServerLink
->SenderPort());
1415 delete_port(fServerLink
->ReceiverPort());
1417 if (_ConnectToServer() != B_OK
)
1418 debugger("Can't reconnect to app server!");
1420 AutoLocker
<BLooperList
> listLock(gLooperList
);
1421 if (!listLock
.IsLocked())
1424 uint32 count
= gLooperList
.CountLoopers();
1425 for (uint32 i
= 0; i
< count
; i
++) {
1426 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1429 BMessenger
windowMessenger(window
);
1430 windowMessenger
.SendMessage(kMsgAppServerRestarted
);
1433 reconnect_bitmaps_to_app_server();
1434 reconnect_pictures_to_app_server();
1440 BApplication::send_drag(BMessage
* message
, int32 vs_token
, BPoint offset
,
1441 BRect dragRect
, BHandler
* replyTo
)
1448 BApplication::send_drag(BMessage
* message
, int32 vs_token
, BPoint offset
,
1449 int32 bitmapToken
, drawing_mode dragMode
, BHandler
* replyTo
)
1456 BApplication::write_drag(_BSession_
* session
, BMessage
* message
)
1464 BApplication::_WindowQuitLoop(bool quitFilePanels
, bool force
)
1468 BWindow
* window
= WindowAt(index
);
1472 // NOTE: the window pointer might be stale, in case the looper
1473 // was already quit by quitting an earlier looper... but fortunately,
1474 // we can still call Lock() on the invalid pointer, and it
1475 // will return false...
1476 if (!window
->Lock())
1479 // don't quit file panels if we haven't been asked for it
1480 if (!quitFilePanels
&& window
->IsFilePanel()) {
1486 if (!force
&& !window
->QuitRequested()
1487 && !(quitFilePanels
&& window
->IsFilePanel())) {
1488 // the window does not want to quit, so we don't either
1493 // Re-lock, just to make sure that the user hasn't done nasty
1494 // things in QuitRequested(). Quit() unlocks fully, thus
1495 // double-locking is harmless.
1500 // we need to continue at the start of the list again - it
1501 // might have changed
1509 BApplication::_QuitAllWindows(bool force
)
1513 // We need to unlock here because BWindow::QuitRequested() must be
1514 // allowed to lock the application - which would cause a deadlock
1517 bool quit
= _WindowQuitLoop(false, force
);
1519 quit
= _WindowQuitLoop(true, force
);
1528 BApplication::_ArgvReceived(BMessage
* message
)
1530 ASSERT(message
!= NULL
);
1532 // build the argv vector
1533 status_t error
= B_OK
;
1536 if (message
->FindInt32("argc", &argc
) == B_OK
&& argc
> 0) {
1537 // allocate a NULL terminated array
1538 argv
= new(std::nothrow
) char*[argc
+ 1];
1542 // copy the arguments
1543 for (int32 i
= 0; error
== B_OK
&& i
< argc
; i
++) {
1544 const char* arg
= NULL
;
1545 error
= message
->FindString("argv", i
, &arg
);
1546 if (error
== B_OK
&& arg
) {
1547 argv
[i
] = strdup(arg
);
1548 if (argv
[i
] == NULL
)
1549 error
= B_NO_MEMORY
;
1558 if (error
== B_OK
&& argc
> 0)
1559 ArgvReceived(argc
, argv
);
1561 if (error
!= B_OK
) {
1562 printf("Error parsing B_ARGV_RECEIVED message. Message:\n");
1563 message
->PrintToStream();
1568 for (int32 i
= 0; i
< argc
; i
++)
1576 BApplication::InitialWorkspace()
1578 return fInitialWorkspace
;
1583 BApplication::_CountWindows(bool includeMenus
) const
1586 for (int32 i
= 0; i
< gLooperList
.CountLoopers(); i
++) {
1587 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1588 if (window
!= NULL
&& !window
->fOffscreen
&& (includeMenus
1589 || dynamic_cast<BMenuWindow
*>(window
) == NULL
)) {
1599 BApplication::_WindowAt(uint32 index
, bool includeMenus
) const
1601 AutoLocker
<BLooperList
> listLock(gLooperList
);
1602 if (!listLock
.IsLocked())
1605 uint32 count
= gLooperList
.CountLoopers();
1606 for (uint32 i
= 0; i
< count
&& index
< count
; i
++) {
1607 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1608 if (window
== NULL
|| (window
!= NULL
&& window
->fOffscreen
)
1609 || (!includeMenus
&& dynamic_cast<BMenuWindow
*>(window
) != NULL
)) {
1623 BApplication::_InitAppResources()
1628 // App is already running. Get its entry ref with
1631 if (be_app
&& be_app
->GetAppInfo(&appInfo
) == B_OK
) {
1635 // Run() hasn't been called yet
1636 found
= BPrivate::get_app_ref(&ref
) == B_OK
;
1642 BFile
file(&ref
, B_READ_ONLY
);
1643 if (file
.InitCheck() != B_OK
)
1646 BResources
* resources
= new (std::nothrow
) BResources(&file
, false);
1647 if (resources
== NULL
|| resources
->InitCheck() != B_OK
) {
1652 sAppResources
= resources
;