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
;
64 BObjectList
<BLooper
> sOnQuitLooperList
;
77 static property_info sPropertyInfo
[] = {
81 {B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
},
99 {B_INDEX_SPECIFIER
, B_REVERSE_INDEX_SPECIFIER
},
100 NULL
, kLooperByIndex
,
126 {B_DIRECT_SPECIFIER
},
134 {B_COUNT_PROPERTIES
},
135 {B_DIRECT_SPECIFIER
},
144 {B_DIRECT_SPECIFIER
},
153 {B_DIRECT_SPECIFIER
},
161 {B_COUNT_PROPERTIES
},
162 {B_DIRECT_SPECIFIER
},
174 extern const int __libc_argc
;
175 extern const char* const *__libc_argv
;
184 // #pragma mark - static helper functions
188 \brief Checks whether the supplied string is a valid application signature.
190 An error message is printed, if the string is no valid app signature.
192 \param signature The string to be checked.
194 \return A status code.
195 \retval B_OK \a signature is a valid app signature.
196 \retval B_BAD_VALUE \a signature is \c NULL or no valid app signature.
199 check_app_signature(const char* signature
)
201 bool isValid
= false;
202 BMimeType
type(signature
);
204 if (type
.IsValid() && !type
.IsSupertypeOnly()
205 && BMimeType("application").Contains(&type
)) {
210 printf("bad signature (%s), must begin with \"application/\" and "
211 "can't conflict with existing registered mime types inside "
212 "the \"application\" media type.\n", signature
);
215 return (isValid
? B_OK
: B_BAD_VALUE
);
219 #ifndef RUN_WITHOUT_REGISTRAR
220 // Fills the passed BMessage with B_ARGV_RECEIVED infos.
222 fill_argv_message(BMessage
&message
)
224 message
.what
= B_ARGV_RECEIVED
;
226 int32 argc
= __libc_argc
;
227 const char* const *argv
= __libc_argv
;
230 message
.AddInt32("argc", argc
);
233 for (int32 i
= 0; i
< argc
; i
++) {
235 message
.AddString("argv", argv
[i
]);
238 // add current working directory
239 char cwd
[B_PATH_NAME_LENGTH
];
240 if (getcwd(cwd
, B_PATH_NAME_LENGTH
))
241 message
.AddString("cwd", cwd
);
246 // #pragma mark - BApplication
249 BApplication::BApplication(const char* signature
)
251 BLooper(kDefaultLooperName
)
253 _InitData(signature
, true, NULL
);
257 BApplication::BApplication(const char* signature
, status_t
* _error
)
259 BLooper(kDefaultLooperName
)
261 _InitData(signature
, true, _error
);
265 BApplication::BApplication(const char* signature
, const char* looperName
,
266 port_id port
, bool initGUI
, status_t
* _error
)
268 BLooper(B_NORMAL_PRIORITY
+ 1, port
< 0 ? _GetPort(signature
) : port
,
269 looperName
!= NULL
? looperName
: kDefaultLooperName
)
271 _InitData(signature
, initGUI
, _error
);
277 BApplication::BApplication(BMessage
* data
)
278 // Note: BeOS calls the private BLooper(int32, port_id, const char*)
279 // constructor here, test if it's needed
281 BLooper(kDefaultLooperName
)
283 const char* signature
= NULL
;
284 data
->FindString("mime_sig", &signature
);
286 _InitData(signature
, true, NULL
);
289 if (data
->FindInt64("_pulse", &pulseRate
) == B_OK
)
290 SetPulseRate(pulseRate
);
294 BApplication::BApplication(uint32 signature
)
299 BApplication::BApplication(const BApplication
&rhs
)
304 BApplication::~BApplication()
308 // tell all loopers(usually windows) to quit. Also, wait for them.
309 _QuitAllWindows(true);
311 // quit registered loopers
312 for (int32 i
= 0; i
< sOnQuitLooperList
.CountItems(); i
++) {
313 BLooper
* looper
= sOnQuitLooperList
.ItemAt(i
);
318 // unregister from the roster
319 BRoster::Private().RemoveApp(Team());
321 #ifndef RUN_WITHOUT_APP_SERVER
322 // tell app_server we're quitting...
324 // be_app can be NULL here if the application fails to initialize
325 // correctly. For example, if it's already running and it's set to
327 BPrivate::AppServerLink link
;
328 link
.StartMessage(B_QUIT_REQUESTED
);
331 delete_port(fServerLink
->SenderPort());
332 delete_port(fServerLink
->ReceiverPort());
334 #endif // RUN_WITHOUT_APP_SERVER
336 delete fServerAllocator
;
338 // uninitialize be_app, the be_app_messenger is invalidated automatically
344 BApplication::operator=(const BApplication
&rhs
)
351 BApplication::_InitData(const char* signature
, bool initGUI
, status_t
* _error
)
353 DBG(OUT("BApplication::InitData(`%s', %p)\n", signature
, _error
));
354 // check whether there exists already an application
356 debugger("2 BApplication objects were created. Only one is allowed.");
358 fServerLink
= new BPrivate::PortLink(-1, -1);
359 fServerAllocator
= NULL
;
360 fServerReadOnlyMemory
= NULL
;
361 fInitialWorkspace
= 0;
362 //fDraggedMessage = NULL;
363 fReadyToRunCalled
= false;
365 // initially, there is no pulse
370 fInitError
= check_app_signature(signature
);
371 fAppName
= signature
;
373 #ifndef RUN_WITHOUT_REGISTRAR
374 bool registerApp
= signature
== NULL
375 || (strcasecmp(signature
, B_REGISTRAR_SIGNATURE
) != 0
376 && strcasecmp(signature
, kLaunchDaemonSignature
) != 0);
377 // get team and thread
378 team_id team
= Team();
379 thread_id thread
= BPrivate::main_thread_for(team
);
382 // get app executable ref
384 if (fInitError
== B_OK
) {
385 fInitError
= BPrivate::get_app_ref(&ref
);
386 if (fInitError
!= B_OK
) {
387 DBG(OUT("BApplication::InitData(): Failed to get app ref: %s\n",
388 strerror(fInitError
)));
392 // get the BAppFileInfo and extract the information we need
393 uint32 appFlags
= B_REG_DEFAULT_APP_FLAGS
;
394 if (fInitError
== B_OK
) {
395 BAppFileInfo fileInfo
;
396 BFile
file(&ref
, B_READ_ONLY
);
397 fInitError
= fileInfo
.SetTo(&file
);
398 if (fInitError
== B_OK
) {
399 fileInfo
.GetAppFlags(&appFlags
);
400 char appFileSignature
[B_MIME_TYPE_LENGTH
];
401 // compare the file signature and the supplied signature
402 if (fileInfo
.GetSignature(appFileSignature
) == B_OK
403 && strcasecmp(appFileSignature
, signature
) != 0) {
404 printf("Signature in rsrc doesn't match constructor arg. (%s, %s)\n",
405 signature
, appFileSignature
);
408 DBG(OUT("BApplication::InitData(): Failed to get info from: "
409 "BAppFileInfo: %s\n", strerror(fInitError
)));
413 #ifndef RUN_WITHOUT_REGISTRAR
414 // check whether be_roster is valid
415 if (fInitError
== B_OK
&& registerApp
416 && !BRoster::Private().IsMessengerValid(false)) {
417 printf("FATAL: be_roster is not valid. Is the registrar running?\n");
418 fInitError
= B_NO_INIT
;
421 // check whether or not we are pre-registered
422 bool preRegistered
= false;
424 if (fInitError
== B_OK
&& registerApp
) {
425 if (BRoster::Private().IsAppRegistered(&ref
, team
, 0, &preRegistered
,
427 preRegistered
= false;
431 // we are pre-registered => the app info has been filled in
432 // Check whether we need to replace the looper port with a port
433 // created by the roster.
434 if (appInfo
.port
>= 0 && appInfo
.port
!= fMsgPort
) {
435 delete_port(fMsgPort
);
436 fMsgPort
= appInfo
.port
;
438 appInfo
.port
= fMsgPort
;
439 // check the signature and correct it, if necessary, also the case
440 if (strcmp(appInfo
.signature
, fAppName
))
441 BRoster::Private().SetSignature(team
, fAppName
);
442 // complete the registration
443 fInitError
= BRoster::Private().CompleteRegistration(team
, thread
,
445 } else if (fInitError
== B_OK
) {
446 // not pre-registered -- try to register the application
447 team_id otherTeam
= -1;
449 fInitError
= BRoster::Private().AddApplication(signature
, &ref
,
450 appFlags
, team
, thread
, fMsgPort
, true, NULL
, &otherTeam
);
451 if (fInitError
!= B_OK
) {
452 DBG(OUT("BApplication::InitData(): Failed to add app: %s\n",
453 strerror(fInitError
)));
456 if (fInitError
== B_ALREADY_RUNNING
) {
457 // An instance is already running and we asked for
458 // single/exclusive launch. Send our argv to the running app.
459 // Do that only, if the app is NOT B_ARGV_ONLY.
460 if (otherTeam
>= 0) {
461 BMessenger
otherApp(NULL
, otherTeam
);
462 app_info otherAppInfo
;
463 bool argvOnly
= be_roster
->GetRunningAppInfo(otherTeam
,
464 &otherAppInfo
) == B_OK
465 && (otherAppInfo
.flags
& B_ARGV_ONLY
) != 0;
467 if (__libc_argc
> 1 && !argvOnly
) {
468 // create an B_ARGV_RECEIVED message
469 BMessage
argvMessage(B_ARGV_RECEIVED
);
470 fill_argv_message(argvMessage
);
472 // replace the first argv string with the path of the
475 if (path
.SetTo(&otherAppInfo
.ref
) == B_OK
)
476 argvMessage
.ReplaceString("argv", 0, path
.Path());
479 otherApp
.SendMessage(&argvMessage
);
480 } else if (!argvOnly
)
481 otherApp
.SendMessage(B_SILENT_RELAUNCH
);
483 } else if (fInitError
== B_OK
) {
484 // the registrations was successful
485 // Create a B_ARGV_RECEIVED message and send it to ourselves.
486 // Do that even, if we are B_ARGV_ONLY.
487 // TODO: When BLooper::AddMessage() is done, use that instead of
490 DBG(OUT("info: BApplication successfully registered.\n"));
492 if (__libc_argc
> 1) {
493 BMessage
argvMessage(B_ARGV_RECEIVED
);
494 fill_argv_message(argvMessage
);
495 PostMessage(&argvMessage
, this);
497 // send a B_READY_TO_RUN message as well
498 PostMessage(B_READY_TO_RUN
, this);
499 } else if (fInitError
> B_ERRORS_END
) {
500 // Registrar internal errors shouldn't fall into the user's hands.
501 fInitError
= B_ERROR
;
505 // We need to have ReadyToRun called even when we're not using the registrar
506 PostMessage(B_READY_TO_RUN
, this);
507 #endif // ifndef RUN_WITHOUT_REGISTRAR
509 if (fInitError
== B_OK
) {
510 // TODO: Not completely sure about the order, but this should be close.
512 // init be_app and be_app_messenger
514 be_app_messenger
= BMessenger(NULL
, this);
516 // set the BHandler's name
521 if (registerApp
&& path
.SetTo(&ref
) == B_OK
)
522 create_app_meta_mime(path
.Path(), false, true, false);
524 #ifndef RUN_WITHOUT_APP_SERVER
525 // app server connection and IK initialization
527 fInitError
= _InitGUIContext();
528 #endif // RUN_WITHOUT_APP_SERVER
531 // Return the error or exit, if there was an error and no error variable
532 // has been supplied.
533 if (_error
!= NULL
) {
534 *_error
= fInitError
;
535 } else if (fInitError
!= B_OK
) {
536 DBG(OUT("BApplication::InitData() failed: %s\n", strerror(fInitError
)));
539 DBG(OUT("BApplication::InitData() done\n"));
544 BApplication::_GetPort(const char* signature
)
546 return BLaunchRoster().GetPort(signature
, NULL
);
551 BApplication::Instantiate(BMessage
* data
)
553 if (validate_instantiation(data
, "BApplication"))
554 return new BApplication(data
);
561 BApplication::Archive(BMessage
* data
, bool deep
) const
563 status_t status
= BLooper::Archive(data
, deep
);
568 status
= GetAppInfo(&info
);
572 status
= data
->AddString("mime_sig", info
.signature
);
576 return data
->AddInt64("_pulse", fPulseRate
);
581 BApplication::InitCheck() const
590 if (fInitError
!= B_OK
)
596 debugger("BApplication::Run was already called. Can only be called once.");
598 fThread
= find_thread(NULL
);
613 const char* name
= Name();
617 printf("ERROR - you must Lock the application object before calling "
618 "Quit(), team=%" B_PRId32
", looper=%s\n", Team(), name
);
623 // Delete the object, if not running only.
626 } else if (find_thread(NULL
) != fThread
) {
627 // ToDo: why shouldn't we set fTerminating to true directly in this case?
628 // We are not the looper thread.
629 // We push a _QUIT_ into the queue.
630 // TODO: When BLooper::AddMessage() is done, use that instead of
631 // PostMessage()??? This would overtake messages that are still at
633 // NOTE: We must not unlock here -- otherwise we had to re-lock, which
634 // may not work. This is bad, since, if the port is full, it
635 // won't get emptier, as the looper thread needs to lock the object
636 // before dispatching messages.
637 while (PostMessage(_QUIT_
, this) == B_WOULD_BLOCK
)
640 // We are the looper thread.
641 // Just set fTerminating to true which makes us fall through the
642 // message dispatching loop and return from Run().
646 // If we had to lock the object, unlock now.
653 BApplication::QuitRequested()
655 return _QuitAllWindows(false);
660 BApplication::Pulse()
662 // supposed to be implemented by subclasses
667 BApplication::ReadyToRun()
669 // supposed to be implemented by subclasses
674 BApplication::MessageReceived(BMessage
* message
)
676 switch (message
->what
) {
677 case B_COUNT_PROPERTIES
:
684 const char* property
= NULL
;
685 if (message
->GetCurrentSpecifier(&index
, &specifier
, &what
,
687 || !ScriptReceived(message
, index
, &specifier
, what
,
689 BLooper::MessageReceived(message
);
694 case B_SILENT_RELAUNCH
:
695 // Sent to a B_SINGLE_LAUNCH application when it's launched again
697 be_roster
->ActivateApp(Team());
700 case kMsgAppServerRestarted
:
701 _ReconnectToServer();
704 case kMsgDeleteServerMemoryArea
:
707 if (message
->FindInt32("server area", &serverArea
) == B_OK
) {
708 // The link is not used, but we currently borrow its lock
709 BPrivate::AppServerLink link
;
710 fServerAllocator
->RemoveArea(serverArea
);
716 BLooper::MessageReceived(message
);
722 BApplication::ArgvReceived(int32 argc
, char** argv
)
724 // supposed to be implemented by subclasses
729 BApplication::AppActivated(bool active
)
731 // supposed to be implemented by subclasses
736 BApplication::RefsReceived(BMessage
* message
)
738 // supposed to be implemented by subclasses
743 BApplication::AboutRequested()
745 // supposed to be implemented by subclasses
750 BApplication::ResolveSpecifier(BMessage
* message
, int32 index
,
751 BMessage
* specifier
, int32 what
, const char* property
)
753 BPropertyInfo
propInfo(sPropertyInfo
);
757 if (propInfo
.FindMatch(message
, 0, specifier
, what
, property
, &data
) >= 0) {
762 err
= specifier
->FindInt32("index", &index
);
766 if (what
== B_REVERSE_INDEX_SPECIFIER
)
767 index
= CountWindows() - index
;
769 BWindow
* window
= WindowAt(index
);
770 if (window
!= NULL
) {
771 message
->PopSpecifier();
772 BMessenger(window
).SendMessage(message
);
781 err
= specifier
->FindString("name", &name
);
785 for (int32 i
= 0;; i
++) {
786 BWindow
* window
= WindowAt(i
);
787 if (window
== NULL
) {
788 err
= B_NAME_NOT_FOUND
;
791 if (window
->Title() != NULL
&& !strcmp(window
->Title(),
793 message
->PopSpecifier();
794 BMessenger(window
).SendMessage(message
);
804 err
= specifier
->FindInt32("index", &index
);
808 if (what
== B_REVERSE_INDEX_SPECIFIER
)
809 index
= CountLoopers() - index
;
811 BLooper
* looper
= LooperAt(index
);
812 if (looper
!= NULL
) {
813 message
->PopSpecifier();
814 BMessenger(looper
).SendMessage(message
);
822 // TODO: implement getting looper by ID!
828 err
= specifier
->FindString("name", &name
);
832 for (int32 i
= 0;; i
++) {
833 BLooper
* looper
= LooperAt(i
);
834 if (looper
== NULL
) {
835 err
= B_NAME_NOT_FOUND
;
838 if (looper
->Name() != NULL
839 && strcmp(looper
->Name(), name
) == 0) {
840 message
->PopSpecifier();
841 BMessenger(looper
).SendMessage(message
);
852 return BLooper::ResolveSpecifier(message
, index
, specifier
, what
,
857 BMessage
reply(B_MESSAGE_NOT_UNDERSTOOD
);
858 reply
.AddInt32("error", err
);
859 reply
.AddString("message", strerror(err
));
860 message
->SendReply(&reply
);
869 BApplication::ShowCursor()
871 BPrivate::AppServerLink link
;
872 link
.StartMessage(AS_SHOW_CURSOR
);
878 BApplication::HideCursor()
880 BPrivate::AppServerLink link
;
881 link
.StartMessage(AS_HIDE_CURSOR
);
887 BApplication::ObscureCursor()
889 BPrivate::AppServerLink link
;
890 link
.StartMessage(AS_OBSCURE_CURSOR
);
896 BApplication::IsCursorHidden() const
898 BPrivate::AppServerLink link
;
899 int32 status
= B_ERROR
;
900 link
.StartMessage(AS_QUERY_CURSOR_HIDDEN
);
901 link
.FlushWithReply(status
);
903 return status
== B_OK
;
908 BApplication::SetCursor(const void* cursorData
)
910 BCursor
cursor(cursorData
);
911 SetCursor(&cursor
, true);
912 // forces the cursor to be sync'ed
917 BApplication::SetCursor(const BCursor
* cursor
, bool sync
)
919 BPrivate::AppServerLink link
;
920 link
.StartMessage(AS_SET_CURSOR
);
921 link
.Attach
<bool>(sync
);
922 link
.Attach
<int32
>(cursor
->fServerToken
);
926 link
.FlushWithReply(code
);
933 BApplication::CountWindows() const
935 return _CountWindows(false);
936 // we're ignoring menu windows
941 BApplication::WindowAt(int32 index
) const
943 return _WindowAt(index
, false);
944 // we're ignoring menu windows
949 BApplication::CountLoopers() const
951 AutoLocker
<BLooperList
> ListLock(gLooperList
);
952 if (ListLock
.IsLocked())
953 return gLooperList
.CountLoopers();
955 // Some bad, non-specific thing has happened
961 BApplication::LooperAt(int32 index
) const
963 BLooper
* looper
= NULL
;
964 AutoLocker
<BLooperList
> listLock(gLooperList
);
965 if (listLock
.IsLocked())
966 looper
= gLooperList
.LooperAt(index
);
973 BApplication::RegisterLooper(BLooper
* looper
)
975 BWindow
* window
= dynamic_cast<BWindow
*>(looper
);
979 if (sOnQuitLooperList
.HasItem(looper
))
982 if (sOnQuitLooperList
.AddItem(looper
) != true)
990 BApplication::UnregisterLooper(BLooper
* looper
)
992 BWindow
* window
= dynamic_cast<BWindow
*>(looper
);
996 if (!sOnQuitLooperList
.HasItem(looper
))
999 if (sOnQuitLooperList
.RemoveItem(looper
) != true)
1007 BApplication::IsLaunching() const
1009 return !fReadyToRunCalled
;
1014 BApplication::Signature() const
1021 BApplication::GetAppInfo(app_info
* info
) const
1023 if (be_app
== NULL
|| be_roster
== NULL
)
1025 return be_roster
->GetRunningAppInfo(be_app
->Team(), info
);
1030 BApplication::AppResources()
1032 if (sAppResources
== NULL
)
1033 pthread_once(&sAppResourcesInitOnce
, &_InitAppResources
);
1035 return sAppResources
;
1040 BApplication::DispatchMessage(BMessage
* message
, BHandler
* handler
)
1042 if (handler
!= this) {
1043 // it's not ours to dispatch
1044 BLooper::DispatchMessage(message
, handler
);
1048 switch (message
->what
) {
1049 case B_ARGV_RECEIVED
:
1050 _ArgvReceived(message
);
1053 case B_REFS_RECEIVED
:
1055 // this adds the refs that are part of this message to the recent
1056 // lists, but only folders and documents are handled here
1059 while (message
->FindRef("refs", i
++, &ref
) == B_OK
) {
1060 BEntry
entry(&ref
, true);
1061 if (entry
.InitCheck() != B_OK
)
1064 if (entry
.IsDirectory())
1065 BRoster().AddToRecentFolders(&ref
);
1067 // filter out applications, we only want to have documents
1068 // in the recent files list
1070 BNodeInfo
info(&node
);
1072 char mimeType
[B_MIME_TYPE_LENGTH
];
1073 if (info
.GetType(mimeType
) != B_OK
1074 || strcasecmp(mimeType
, B_APP_MIME_TYPE
))
1075 BRoster().AddToRecentDocuments(&ref
);
1079 RefsReceived(message
);
1083 case B_READY_TO_RUN
:
1084 if (!fReadyToRunCalled
) {
1086 fReadyToRunCalled
= true;
1090 case B_ABOUT_REQUESTED
:
1098 case B_APP_ACTIVATED
:
1101 if (message
->FindBool("active", &active
) == B_OK
)
1102 AppActivated(active
);
1106 case B_COLORS_UPDATED
:
1108 AutoLocker
<BLooperList
> listLock(gLooperList
);
1109 if (!listLock
.IsLocked())
1112 BWindow
* window
= NULL
;
1113 uint32 count
= gLooperList
.CountLoopers();
1114 for (uint32 index
= 0; index
< count
; ++index
) {
1115 window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(index
));
1116 if (window
== NULL
|| (window
!= NULL
&& window
->fOffscreen
))
1118 window
->PostMessage(message
);
1123 case _SHOW_DRAG_HANDLES_
:
1126 if (message
->FindBool("show", &show
) != B_OK
)
1129 BDragger::Private::UpdateShowAllDraggers(show
);
1133 // TODO: Handle these as well
1134 case _DISPOSE_DRAG_
:
1136 puts("not yet handled message:");
1137 DBG(message
->PrintToStream());
1141 BLooper::DispatchMessage(message
, handler
);
1148 BApplication::SetPulseRate(bigtime_t rate
)
1153 // BeBook states that we have only 100,000 microseconds granularity
1154 rate
-= rate
% 100000;
1160 // reset existing pulse runner, or create new one
1161 if (fPulseRunner
== NULL
) {
1162 BMessage
pulse(B_PULSE
);
1163 fPulseRunner
= new BMessageRunner(be_app_messenger
, &pulse
, rate
);
1165 fPulseRunner
->SetInterval(rate
);
1167 // turn off pulse messages
1168 delete fPulseRunner
;
1169 fPulseRunner
= NULL
;
1178 BApplication::GetSupportedSuites(BMessage
* data
)
1183 status_t status
= data
->AddString("suites", "suite/vnd.Be-application");
1184 if (status
== B_OK
) {
1185 BPropertyInfo
propertyInfo(sPropertyInfo
);
1186 status
= data
->AddFlat("messages", &propertyInfo
);
1188 status
= BLooper::GetSupportedSuites(data
);
1196 BApplication::Perform(perform_code d
, void* arg
)
1198 return BLooper::Perform(d
, arg
);
1202 void BApplication::_ReservedApplication1() {}
1203 void BApplication::_ReservedApplication2() {}
1204 void BApplication::_ReservedApplication3() {}
1205 void BApplication::_ReservedApplication4() {}
1206 void BApplication::_ReservedApplication5() {}
1207 void BApplication::_ReservedApplication6() {}
1208 void BApplication::_ReservedApplication7() {}
1209 void BApplication::_ReservedApplication8() {}
1213 BApplication::ScriptReceived(BMessage
* message
, int32 index
,
1214 BMessage
* specifier
, int32 what
, const char* property
)
1216 BMessage
reply(B_REPLY
);
1217 status_t err
= B_BAD_SCRIPT_SYNTAX
;
1219 switch (message
->what
) {
1220 case B_GET_PROPERTY
:
1221 if (strcmp("Loopers", property
) == 0) {
1222 int32 count
= CountLoopers();
1224 for (int32 i
=0; err
== B_OK
&& i
<count
; i
++) {
1225 BMessenger
messenger(LooperAt(i
));
1226 err
= reply
.AddMessenger("result", messenger
);
1228 } else if (strcmp("Windows", property
) == 0) {
1229 int32 count
= CountWindows();
1231 for (int32 i
=0; err
== B_OK
&& i
<count
; i
++) {
1232 BMessenger
messenger(WindowAt(i
));
1233 err
= reply
.AddMessenger("result", messenger
);
1235 } else if (strcmp("Window", property
) == 0) {
1237 case B_INDEX_SPECIFIER
:
1238 case B_REVERSE_INDEX_SPECIFIER
:
1241 err
= specifier
->FindInt32("index", &index
);
1245 if (what
== B_REVERSE_INDEX_SPECIFIER
)
1246 index
= CountWindows() - index
;
1249 BWindow
* window
= WindowAt(index
);
1253 BMessenger
messenger(window
);
1254 err
= reply
.AddMessenger("result", messenger
);
1258 case B_NAME_SPECIFIER
:
1261 err
= specifier
->FindString("name", &name
);
1264 err
= B_NAME_NOT_FOUND
;
1265 for (int32 i
= 0; i
< CountWindows(); i
++) {
1266 BWindow
* window
= WindowAt(i
);
1267 if (window
&& window
->Name() != NULL
1268 && !strcmp(window
->Name(), name
)) {
1269 BMessenger
messenger(window
);
1270 err
= reply
.AddMessenger("result", messenger
);
1277 } else if (strcmp("Looper", property
) == 0) {
1279 case B_INDEX_SPECIFIER
:
1280 case B_REVERSE_INDEX_SPECIFIER
:
1283 err
= specifier
->FindInt32("index", &index
);
1287 if (what
== B_REVERSE_INDEX_SPECIFIER
)
1288 index
= CountLoopers() - index
;
1291 BLooper
* looper
= LooperAt(index
);
1295 BMessenger
messenger(looper
);
1296 err
= reply
.AddMessenger("result", messenger
);
1300 case B_NAME_SPECIFIER
:
1303 err
= specifier
->FindString("name", &name
);
1306 err
= B_NAME_NOT_FOUND
;
1307 for (int32 i
= 0; i
< CountLoopers(); i
++) {
1308 BLooper
* looper
= LooperAt(i
);
1309 if (looper
!= NULL
&& looper
->Name()
1310 && strcmp(looper
->Name(), name
) == 0) {
1311 BMessenger
messenger(looper
);
1312 err
= reply
.AddMessenger("result", messenger
);
1319 case B_ID_SPECIFIER
:
1322 debug_printf("Looper's ID specifier used but not "
1327 } else if (strcmp("Name", property
) == 0)
1328 err
= reply
.AddString("result", Name());
1332 case B_COUNT_PROPERTIES
:
1333 if (strcmp("Looper", property
) == 0)
1334 err
= reply
.AddInt32("result", CountLoopers());
1335 else if (strcmp("Window", property
) == 0)
1336 err
= reply
.AddInt32("result", CountWindows());
1340 if (err
== B_BAD_SCRIPT_SYNTAX
)
1344 reply
.what
= B_MESSAGE_NOT_UNDERSTOOD
;
1345 reply
.AddString("message", strerror(err
));
1347 reply
.AddInt32("error", err
);
1348 message
->SendReply(&reply
);
1355 BApplication::BeginRectTracking(BRect rect
, bool trackWhole
)
1357 BPrivate::AppServerLink link
;
1358 link
.StartMessage(AS_BEGIN_RECT_TRACKING
);
1359 link
.Attach
<BRect
>(rect
);
1360 link
.Attach
<int32
>(trackWhole
);
1366 BApplication::EndRectTracking()
1368 BPrivate::AppServerLink link
;
1369 link
.StartMessage(AS_END_RECT_TRACKING
);
1375 BApplication::_SetupServerAllocator()
1377 fServerAllocator
= new (std::nothrow
) BPrivate::ServerMemoryAllocator();
1378 if (fServerAllocator
== NULL
)
1381 return fServerAllocator
->InitCheck();
1386 BApplication::_InitGUIContext()
1388 // An app_server connection is necessary for a lot of stuff, so get that first.
1389 status_t error
= _ConnectToServer();
1393 // Initialize the IK after we have set be_app because of a construction
1394 // of a AppServerLink (which depends on be_app) nested inside the call
1395 // to get_menu_info.
1396 error
= _init_interface_kit_();
1400 // create global system cursors
1401 B_CURSOR_SYSTEM_DEFAULT
= new BCursor(B_HAND_CURSOR
);
1402 B_CURSOR_I_BEAM
= new BCursor(B_I_BEAM_CURSOR
);
1404 // TODO: would be nice to get the workspace at launch time from the registrar
1405 fInitialWorkspace
= current_workspace();
1412 BApplication::_ConnectToServer()
1415 = create_desktop_connection(fServerLink
, "a<app_server", 100);
1422 // 1) port_id - receiver port of a regular app
1423 // 2) port_id - looper port for this BApplication
1424 // 3) team_id - team identification field
1425 // 4) int32 - handler ID token of the app
1426 // 5) char* - signature of the regular app
1428 fServerLink
->StartMessage(AS_CREATE_APP
);
1429 fServerLink
->Attach
<port_id
>(fServerLink
->ReceiverPort());
1430 fServerLink
->Attach
<port_id
>(_get_looper_port_(this));
1431 fServerLink
->Attach
<team_id
>(Team());
1432 fServerLink
->Attach
<int32
>(_get_object_token_(this));
1433 fServerLink
->AttachString(fAppName
);
1435 area_id sharedReadOnlyArea
;
1440 if (fServerLink
->FlushWithReply(code
) == B_OK
1442 // We don't need to contact the main app_server anymore
1443 // directly; we now talk to our server alter ego only.
1444 fServerLink
->Read
<port_id
>(&serverPort
);
1445 fServerLink
->Read
<area_id
>(&sharedReadOnlyArea
);
1446 fServerLink
->Read
<team_id
>(&serverTeam
);
1448 fServerLink
->SetSenderPort(-1);
1449 debugger("BApplication: couldn't obtain new app_server comm port");
1452 fServerLink
->SetTargetTeam(serverTeam
);
1453 fServerLink
->SetSenderPort(serverPort
);
1455 status
= _SetupServerAllocator();
1461 status
= fServerAllocator
->AddArea(sharedReadOnlyArea
, area
, base
, true);
1465 fServerReadOnlyMemory
= base
;
1472 BApplication::_ReconnectToServer()
1474 delete_port(fServerLink
->SenderPort());
1475 delete_port(fServerLink
->ReceiverPort());
1477 if (_ConnectToServer() != B_OK
)
1478 debugger("Can't reconnect to app server!");
1480 AutoLocker
<BLooperList
> listLock(gLooperList
);
1481 if (!listLock
.IsLocked())
1484 uint32 count
= gLooperList
.CountLoopers();
1485 for (uint32 i
= 0; i
< count
; i
++) {
1486 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1489 BMessenger
windowMessenger(window
);
1490 windowMessenger
.SendMessage(kMsgAppServerRestarted
);
1493 reconnect_bitmaps_to_app_server();
1494 reconnect_pictures_to_app_server();
1500 BApplication::send_drag(BMessage
* message
, int32 vs_token
, BPoint offset
,
1501 BRect dragRect
, BHandler
* replyTo
)
1508 BApplication::send_drag(BMessage
* message
, int32 vs_token
, BPoint offset
,
1509 int32 bitmapToken
, drawing_mode dragMode
, BHandler
* replyTo
)
1516 BApplication::write_drag(_BSession_
* session
, BMessage
* message
)
1524 BApplication::_WindowQuitLoop(bool quitFilePanels
, bool force
)
1528 BWindow
* window
= WindowAt(index
);
1532 // NOTE: the window pointer might be stale, in case the looper
1533 // was already quit by quitting an earlier looper... but fortunately,
1534 // we can still call Lock() on the invalid pointer, and it
1535 // will return false...
1536 if (!window
->Lock())
1539 // don't quit file panels if we haven't been asked for it
1540 if (!quitFilePanels
&& window
->IsFilePanel()) {
1546 if (!force
&& !window
->QuitRequested()
1547 && !(quitFilePanels
&& window
->IsFilePanel())) {
1548 // the window does not want to quit, so we don't either
1553 // Re-lock, just to make sure that the user hasn't done nasty
1554 // things in QuitRequested(). Quit() unlocks fully, thus
1555 // double-locking is harmless.
1560 // we need to continue at the start of the list again - it
1561 // might have changed
1569 BApplication::_QuitAllWindows(bool force
)
1573 // We need to unlock here because BWindow::QuitRequested() must be
1574 // allowed to lock the application - which would cause a deadlock
1577 bool quit
= _WindowQuitLoop(false, force
);
1579 quit
= _WindowQuitLoop(true, force
);
1588 BApplication::_ArgvReceived(BMessage
* message
)
1590 ASSERT(message
!= NULL
);
1592 // build the argv vector
1593 status_t error
= B_OK
;
1596 if (message
->FindInt32("argc", &argc
) == B_OK
&& argc
> 0) {
1597 // allocate a NULL terminated array
1598 argv
= new(std::nothrow
) char*[argc
+ 1];
1602 // copy the arguments
1603 for (int32 i
= 0; error
== B_OK
&& i
< argc
; i
++) {
1604 const char* arg
= NULL
;
1605 error
= message
->FindString("argv", i
, &arg
);
1606 if (error
== B_OK
&& arg
) {
1607 argv
[i
] = strdup(arg
);
1608 if (argv
[i
] == NULL
)
1609 error
= B_NO_MEMORY
;
1618 if (error
== B_OK
&& argc
> 0)
1619 ArgvReceived(argc
, argv
);
1621 if (error
!= B_OK
) {
1622 printf("Error parsing B_ARGV_RECEIVED message. Message:\n");
1623 message
->PrintToStream();
1628 for (int32 i
= 0; i
< argc
; i
++)
1636 BApplication::InitialWorkspace()
1638 return fInitialWorkspace
;
1643 BApplication::_CountWindows(bool includeMenus
) const
1646 for (int32 i
= 0; i
< gLooperList
.CountLoopers(); i
++) {
1647 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1648 if (window
!= NULL
&& !window
->fOffscreen
&& (includeMenus
1649 || dynamic_cast<BMenuWindow
*>(window
) == NULL
)) {
1659 BApplication::_WindowAt(uint32 index
, bool includeMenus
) const
1661 AutoLocker
<BLooperList
> listLock(gLooperList
);
1662 if (!listLock
.IsLocked())
1665 uint32 count
= gLooperList
.CountLoopers();
1666 for (uint32 i
= 0; i
< count
&& index
< count
; i
++) {
1667 BWindow
* window
= dynamic_cast<BWindow
*>(gLooperList
.LooperAt(i
));
1668 if (window
== NULL
|| (window
!= NULL
&& window
->fOffscreen
)
1669 || (!includeMenus
&& dynamic_cast<BMenuWindow
*>(window
) != NULL
)) {
1683 BApplication::_InitAppResources()
1688 // App is already running. Get its entry ref with
1691 if (be_app
&& be_app
->GetAppInfo(&appInfo
) == B_OK
) {
1695 // Run() hasn't been called yet
1696 found
= BPrivate::get_app_ref(&ref
) == B_OK
;
1702 BFile
file(&ref
, B_READ_ONLY
);
1703 if (file
.InitCheck() != B_OK
)
1706 BResources
* resources
= new (std::nothrow
) BResources(&file
, false);
1707 if (resources
== NULL
|| resources
->InitCheck() != B_OK
) {
1712 sAppResources
= resources
;