1 /*
2 * Copyright 2001-2015 Haiku, inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Jerome Duval
8 * Erik Jaesler, erik@cgsoftware.com
9 */
10
11
12 #include <Application.h>
13
14 #include <new>
15 #include <pthread.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <strings.h>
20 #include <unistd.h>
21
22 #include <Alert.h>
23 #include <AppFileInfo.h>
24 #include <Cursor.h>
25 #include <Debug.h>
26 #include <Entry.h>
27 #include <File.h>
28 #include <Locker.h>
29 #include <MessageRunner.h>
30 #include <ObjectList.h>
31 #include <Path.h>
32 #include <PropertyInfo.h>
33 #include <RegistrarDefs.h>
34 #include <Resources.h>
35 #include <Roster.h>
36 #include <Window.h>
37
38 #include <AppMisc.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>
48 #include <PortLink.h>
49 #include <RosterPrivate.h>
50 #include <ServerMemoryAllocator.h>
51 #include <ServerProtocol.h>
52
53
54 using namespace BPrivate;
55
56
57 static const char* kDefaultLooperName = "AppLooperPort";
58
59 BApplication* be_app = NULL;
60 BMessenger be_app_messenger;
61
62 pthread_once_t sAppResourcesInitOnce = PTHREAD_ONCE_INIT;
63 BResources* BApplication::sAppResources = NULL;
64 BObjectList<BLooper> sOnQuitLooperList;
65
66
67 enum {
68 kWindowByIndex,
69 kWindowByName,
70 kLooperByIndex,
71 kLooperByID,
72 kLooperByName,
73 kApplication
74 };
75
76
77 static property_info sPropertyInfo[] = {
78 {
79 "Window",
80 {},
81 {B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
82 NULL, kWindowByIndex,
83 {},
84 {},
85 {}
86 },
87 {
88 "Window",
89 {},
90 {B_NAME_SPECIFIER},
91 NULL, kWindowByName,
92 {},
93 {},
94 {}
95 },
96 {
97 "Looper",
98 {},
99 {B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER},
100 NULL, kLooperByIndex,
101 {},
102 {},
103 {}
104 },
105 {
106 "Looper",
107 {},
108 {B_ID_SPECIFIER},
109 NULL, kLooperByID,
110 {},
111 {},
112 {}
113 },
114 {
115 "Looper",
116 {},
117 {B_NAME_SPECIFIER},
118 NULL, kLooperByName,
119 {},
120 {},
121 {}
122 },
123 {
124 "Name",
125 {B_GET_PROPERTY},
126 {B_DIRECT_SPECIFIER},
127 NULL, kApplication,
128 {B_STRING_TYPE},
129 {},
130 {}
131 },
132 {
133 "Window",
134 {B_COUNT_PROPERTIES},
135 {B_DIRECT_SPECIFIER},
136 NULL, kApplication,
137 {B_INT32_TYPE},
138 {},
139 {}
140 },
141 {
142 "Loopers",
143 {B_GET_PROPERTY},
144 {B_DIRECT_SPECIFIER},
145 NULL, kApplication,
146 {B_MESSENGER_TYPE},
147 {},
148 {}
149 },
150 {
151 "Windows",
152 {B_GET_PROPERTY},
153 {B_DIRECT_SPECIFIER},
154 NULL, kApplication,
155 {B_MESSENGER_TYPE},
156 {},
157 {}
158 },
159 {
160 "Looper",
161 {B_COUNT_PROPERTIES},
162 {B_DIRECT_SPECIFIER},
163 NULL, kApplication,
164 {B_INT32_TYPE},
165 {},
166 {}
167 },
168
169 { 0 }
170 };
171
172
173 // argc/argv
174 extern const int __libc_argc;
175 extern const char* const *__libc_argv;
176
177
178 // debugging
179 //#define DBG(x) x
180 #define DBG(x)
181 #define OUT printf
182
183
184 // #pragma mark - static helper functions
185
186
187 /*!
188 \brief Checks whether the supplied string is a valid application signature.
189
190 An error message is printed, if the string is no valid app signature.
191
192 \param signature The string to be checked.
193
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.
197 */
198 static status_t
check_app_signature(const char * signature)199 check_app_signature(const char* signature)
200 {
201 bool isValid = false;
202 BMimeType type(signature);
203
204 if (type.IsValid() && !type.IsSupertypeOnly()
205 && BMimeType("application").Contains(&type)) {
206 isValid = true;
207 }
208
209 if (!isValid) {
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);
213 }
214
215 return (isValid ? B_OK : B_BAD_VALUE);
216 }
217
218
219 #ifndef RUN_WITHOUT_REGISTRAR
220 // Fills the passed BMessage with B_ARGV_RECEIVED infos.
221 static void
fill_argv_message(BMessage & message)222 fill_argv_message(BMessage &message)
223 {
224 message.what = B_ARGV_RECEIVED;
225
226 int32 argc = __libc_argc;
227 const char* const *argv = __libc_argv;
228
229 // add argc
230 message.AddInt32("argc", argc);
231
232 // add argv
233 for (int32 i = 0; i < argc; i++) {
234 if (argv[i] != NULL)
235 message.AddString("argv", argv[i]);
236 }
237
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);
242 }
243 #endif
244
245
246 // #pragma mark - BApplication
247
248
BApplication(const char * signature)249 BApplication::BApplication(const char* signature)
250 :
251 BLooper(kDefaultLooperName)
252 {
253 _InitData(signature, true, NULL);
254 }
255
256
BApplication(const char * signature,status_t * _error)257 BApplication::BApplication(const char* signature, status_t* _error)
258 :
259 BLooper(kDefaultLooperName)
260 {
261 _InitData(signature, true, _error);
262 }
263
264
BApplication(const char * signature,const char * looperName,port_id port,bool initGUI,status_t * _error)265 BApplication::BApplication(const char* signature, const char* looperName,
266 port_id port, bool initGUI, status_t* _error)
267 :
268 BLooper(B_NORMAL_PRIORITY + 1, port < 0 ? _GetPort(signature) : port,
269 looperName != NULL ? looperName : kDefaultLooperName)
270 {
271 _InitData(signature, initGUI, _error);
272 if (port < 0)
273 fOwnsPort = false;
274 }
275
276
BApplication(BMessage * data)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
280 :
281 BLooper(kDefaultLooperName)
282 {
283 const char* signature = NULL;
284 data->FindString("mime_sig", &signature);
285
286 _InitData(signature, true, NULL);
287
288 bigtime_t pulseRate;
289 if (data->FindInt64("_pulse", &pulseRate) == B_OK)
290 SetPulseRate(pulseRate);
291 }
292
293
294 #ifdef __HAIKU_BEOS_COMPATIBLE
BApplication(uint32 signature)295 BApplication::BApplication(uint32 signature)
296 {
297 }
298
299
BApplication(const BApplication & rhs)300 BApplication::BApplication(const BApplication &rhs)
301 {
302 }
303
304
305 BApplication&
operator =(const BApplication & rhs)306 BApplication::operator=(const BApplication &rhs)
307 {
308 return *this;
309 }
310 #endif
311
312
~BApplication()313 BApplication::~BApplication()
314 {
315 Lock();
316
317 // tell all loopers(usually windows) to quit. Also, wait for them.
318 _QuitAllWindows(true);
319
320 // quit registered loopers
321 for (int32 i = 0; i < sOnQuitLooperList.CountItems(); i++) {
322 BLooper* looper = sOnQuitLooperList.ItemAt(i);
323 if (looper->Lock())
324 looper->Quit();
325 }
326
327 // unregister from the roster
328 BRoster::Private().RemoveApp(Team());
329
330 #ifndef RUN_WITHOUT_APP_SERVER
331 // tell app_server we're quitting...
332 if (be_app) {
333 // be_app can be NULL here if the application fails to initialize
334 // correctly. For example, if it's already running and it's set to
335 // exclusive launch.
336 BPrivate::AppServerLink link;
337 link.StartMessage(B_QUIT_REQUESTED);
338 link.Flush();
339 }
340 // the sender port belongs to the app_server
341 delete_port(fServerLink->ReceiverPort());
342 delete fServerLink;
343 #endif // RUN_WITHOUT_APP_SERVER
344
345 delete fServerAllocator;
346
347 // uninitialize be_app, the be_app_messenger is invalidated automatically
348 be_app = NULL;
349 }
350
351
352 void
_InitData(const char * signature,bool initGUI,status_t * _error)353 BApplication::_InitData(const char* signature, bool initGUI, status_t* _error)
354 {
355 DBG(OUT("BApplication::InitData(`%s', %p)\n", signature, _error));
356 // check whether there exists already an application
357 if (be_app != NULL)
358 debugger("2 BApplication objects were created. Only one is allowed.");
359
360 fServerLink = new BPrivate::PortLink(-1, -1);
361 fServerAllocator = NULL;
362 fServerReadOnlyMemory = NULL;
363 fInitialWorkspace = 0;
364 //fDraggedMessage = NULL;
365 fReadyToRunCalled = false;
366
367 // initially, there is no pulse
368 fPulseRunner = NULL;
369 fPulseRate = 0;
370
371 // check signature
372 fInitError = check_app_signature(signature);
373 fAppName = signature;
374
375 #ifndef RUN_WITHOUT_REGISTRAR
376 bool registerApp = signature == NULL
377 || (strcasecmp(signature, B_REGISTRAR_SIGNATURE) != 0
378 && strcasecmp(signature, kLaunchDaemonSignature) != 0);
379 // get team and thread
380 team_id team = Team();
381 thread_id thread = BPrivate::main_thread_for(team);
382 #endif
383
384 // get app executable ref
385 entry_ref ref;
386 if (fInitError == B_OK) {
387 fInitError = BPrivate::get_app_ref(&ref);
388 if (fInitError != B_OK) {
389 DBG(OUT("BApplication::InitData(): Failed to get app ref: %s\n",
390 strerror(fInitError)));
391 }
392 }
393
394 // get the BAppFileInfo and extract the information we need
395 uint32 appFlags = B_REG_DEFAULT_APP_FLAGS;
396 if (fInitError == B_OK) {
397 BAppFileInfo fileInfo;
398 BFile file(&ref, B_READ_ONLY);
399 fInitError = fileInfo.SetTo(&file);
400 if (fInitError == B_OK) {
401 fileInfo.GetAppFlags(&appFlags);
402 char appFileSignature[B_MIME_TYPE_LENGTH];
403 // compare the file signature and the supplied signature
404 if (fileInfo.GetSignature(appFileSignature) == B_OK
405 && strcasecmp(appFileSignature, signature) != 0) {
406 printf("Signature in rsrc doesn't match constructor arg. (%s, %s)\n",
407 signature, appFileSignature);
408 }
409 } else {
410 DBG(OUT("BApplication::InitData(): Failed to get info from: "
411 "BAppFileInfo: %s\n", strerror(fInitError)));
412 }
413 }
414
415 #ifndef RUN_WITHOUT_REGISTRAR
416 // check whether be_roster is valid
417 if (fInitError == B_OK && registerApp
418 && !BRoster::Private().IsMessengerValid(false)) {
419 printf("FATAL: be_roster is not valid. Is the registrar running?\n");
420 fInitError = B_NO_INIT;
421 }
422
423 // check whether or not we are pre-registered
424 bool preRegistered = false;
425 app_info appInfo;
426 if (fInitError == B_OK && registerApp) {
427 if (BRoster::Private().IsAppRegistered(&ref, team, 0, &preRegistered,
428 &appInfo) != B_OK) {
429 preRegistered = false;
430 }
431 }
432 if (preRegistered) {
433 // we are pre-registered => the app info has been filled in
434 // Check whether we need to replace the looper port with a port
435 // created by the roster.
436 if (appInfo.port >= 0 && appInfo.port != fMsgPort) {
437 delete_port(fMsgPort);
438 fMsgPort = appInfo.port;
439 } else
440 appInfo.port = fMsgPort;
441 // check the signature and correct it, if necessary, also the case
442 if (strcmp(appInfo.signature, fAppName))
443 BRoster::Private().SetSignature(team, fAppName);
444 // complete the registration
445 fInitError = BRoster::Private().CompleteRegistration(team, thread,
446 appInfo.port);
447 } else if (fInitError == B_OK) {
448 // not pre-registered -- try to register the application
449 team_id otherTeam = -1;
450 if (registerApp) {
451 fInitError = BRoster::Private().AddApplication(signature, &ref,
452 appFlags, team, thread, fMsgPort, true, NULL, &otherTeam);
453 if (fInitError != B_OK) {
454 DBG(OUT("BApplication::InitData(): Failed to add app: %s\n",
455 strerror(fInitError)));
456 }
457 }
458 if (fInitError == B_ALREADY_RUNNING) {
459 // An instance is already running and we asked for
460 // single/exclusive launch. Send our argv to the running app.
461 // Do that only, if the app is NOT B_ARGV_ONLY.
462 if (otherTeam >= 0) {
463 BMessenger otherApp(NULL, otherTeam);
464 app_info otherAppInfo;
465 bool argvOnly = be_roster->GetRunningAppInfo(otherTeam,
466 &otherAppInfo) == B_OK
467 && (otherAppInfo.flags & B_ARGV_ONLY) != 0;
468
469 if (__libc_argc > 1 && !argvOnly) {
470 // create an B_ARGV_RECEIVED message
471 BMessage argvMessage(B_ARGV_RECEIVED);
472 fill_argv_message(argvMessage);
473
474 // replace the first argv string with the path of the
475 // other application
476 BPath path;
477 if (path.SetTo(&otherAppInfo.ref) == B_OK)
478 argvMessage.ReplaceString("argv", 0, path.Path());
479
480 // send the message
481 otherApp.SendMessage(&argvMessage);
482 } else if (!argvOnly)
483 otherApp.SendMessage(B_SILENT_RELAUNCH);
484 }
485 } else if (fInitError == B_OK) {
486 // the registrations was successful
487 // Create a B_ARGV_RECEIVED message and send it to ourselves.
488 // Do that even, if we are B_ARGV_ONLY.
489 // TODO: When BLooper::AddMessage() is done, use that instead of
490 // PostMessage().
491
492 DBG(OUT("info: BApplication successfully registered.\n"));
493
494 if (__libc_argc > 1) {
495 BMessage argvMessage(B_ARGV_RECEIVED);
496 fill_argv_message(argvMessage);
497 PostMessage(&argvMessage, this);
498 }
499 // send a B_READY_TO_RUN message as well
500 PostMessage(B_READY_TO_RUN, this);
501 } else if (fInitError > B_ERRORS_END) {
502 // Registrar internal errors shouldn't fall into the user's hands.
503 fInitError = B_ERROR;
504 }
505 }
506 #else
507 // We need to have ReadyToRun called even when we're not using the registrar
508 PostMessage(B_READY_TO_RUN, this);
509 #endif // ifndef RUN_WITHOUT_REGISTRAR
510
511 if (fInitError == B_OK) {
512 // TODO: Not completely sure about the order, but this should be close.
513
514 // init be_app and be_app_messenger
515 be_app = this;
516 be_app_messenger = BMessenger(NULL, this);
517
518 // set the BHandler's name
519 SetName(ref.name);
520
521 // create meta MIME
522 BPath path;
523 if (registerApp && path.SetTo(&ref) == B_OK)
524 create_app_meta_mime(path.Path(), false, true, false);
525
526 #ifndef RUN_WITHOUT_APP_SERVER
527 // app server connection and IK initialization
528 if (initGUI)
529 fInitError = _InitGUIContext();
530 #endif // RUN_WITHOUT_APP_SERVER
531 }
532
533 // Return the error or exit, if there was an error and no error variable
534 // has been supplied.
535 if (_error != NULL) {
536 *_error = fInitError;
537 } else if (fInitError != B_OK) {
538 DBG(OUT("BApplication::InitData() failed: %s\n", strerror(fInitError)));
539 exit(0);
540 }
541 DBG(OUT("BApplication::InitData() done\n"));
542 }
543
544
545 port_id
_GetPort(const char * signature)546 BApplication::_GetPort(const char* signature)
547 {
548 return BLaunchRoster().GetPort(signature, NULL);
549 }
550
551
552 BArchivable*
Instantiate(BMessage * data)553 BApplication::Instantiate(BMessage* data)
554 {
555 if (validate_instantiation(data, "BApplication"))
556 return new BApplication(data);
557
558 return NULL;
559 }
560
561
562 status_t
Archive(BMessage * data,bool deep) const563 BApplication::Archive(BMessage* data, bool deep) const
564 {
565 status_t status = BLooper::Archive(data, deep);
566 if (status < B_OK)
567 return status;
568
569 app_info info;
570 status = GetAppInfo(&info);
571 if (status < B_OK)
572 return status;
573
574 status = data->AddString("mime_sig", info.signature);
575 if (status < B_OK)
576 return status;
577
578 return data->AddInt64("_pulse", fPulseRate);
579 }
580
581
582 status_t
InitCheck() const583 BApplication::InitCheck() const
584 {
585 return fInitError;
586 }
587
588
589 thread_id
Run()590 BApplication::Run()
591 {
592 if (fInitError != B_OK)
593 return fInitError;
594
595 Loop();
596
597 delete fPulseRunner;
598 return fThread;
599 }
600
601
602 void
Quit()603 BApplication::Quit()
604 {
605 bool unlock = false;
606 if (!IsLocked()) {
607 const char* name = Name();
608 if (name == NULL)
609 name = "no-name";
610
611 printf("ERROR - you must Lock the application object before calling "
612 "Quit(), team=%" B_PRId32 ", looper=%s\n", Team(), name);
613 unlock = true;
614 if (!Lock())
615 return;
616 }
617 // Delete the object, if not running only.
618 if (!fRunCalled) {
619 delete this;
620 } else if (find_thread(NULL) != fThread) {
621 // ToDo: why shouldn't we set fTerminating to true directly in this case?
622 // We are not the looper thread.
623 // We push a _QUIT_ into the queue.
624 // TODO: When BLooper::AddMessage() is done, use that instead of
625 // PostMessage()??? This would overtake messages that are still at
626 // the port.
627 // NOTE: We must not unlock here -- otherwise we had to re-lock, which
628 // may not work. This is bad, since, if the port is full, it
629 // won't get emptier, as the looper thread needs to lock the object
630 // before dispatching messages.
631 while (PostMessage(_QUIT_, this) == B_WOULD_BLOCK)
632 snooze(10000);
633 } else {
634 // We are the looper thread.
635 // Just set fTerminating to true which makes us fall through the
636 // message dispatching loop and return from Run().
637 fTerminating = true;
638 }
639
640 // If we had to lock the object, unlock now.
641 if (unlock)
642 Unlock();
643 }
644
645
646 bool
QuitRequested()647 BApplication::QuitRequested()
648 {
649 return _QuitAllWindows(false);
650 }
651
652
653 void
Pulse()654 BApplication::Pulse()
655 {
656 // supposed to be implemented by subclasses
657 }
658
659
660 void
ReadyToRun()661 BApplication::ReadyToRun()
662 {
663 // supposed to be implemented by subclasses
664 }
665
666
667 void
MessageReceived(BMessage * message)668 BApplication::MessageReceived(BMessage* message)
669 {
670 switch (message->what) {
671 case B_COUNT_PROPERTIES:
672 case B_GET_PROPERTY:
673 case B_SET_PROPERTY:
674 {
675 int32 index;
676 BMessage specifier;
677 int32 what;
678 const char* property = NULL;
679 if (message->GetCurrentSpecifier(&index, &specifier, &what,
680 &property) < B_OK
681 || !ScriptReceived(message, index, &specifier, what,
682 property)) {
683 BLooper::MessageReceived(message);
684 }
685 break;
686 }
687
688 case B_SILENT_RELAUNCH:
689 // Sent to a B_SINGLE_LAUNCH application when it's launched again
690 // (see _InitData())
691 be_roster->ActivateApp(Team());
692 break;
693
694 case kMsgAppServerRestarted:
695 _ReconnectToServer();
696 break;
697
698 case kMsgDeleteServerMemoryArea:
699 {
700 int32 serverArea;
701 if (message->FindInt32("server area", &serverArea) == B_OK) {
702 // The link is not used, but we currently borrow its lock
703 BPrivate::AppServerLink link;
704 fServerAllocator->RemoveArea(serverArea);
705 }
706 break;
707 }
708
709 default:
710 BLooper::MessageReceived(message);
711 }
712 }
713
714
715 void
ArgvReceived(int32 argc,char ** argv)716 BApplication::ArgvReceived(int32 argc, char** argv)
717 {
718 // supposed to be implemented by subclasses
719 }
720
721
722 void
AppActivated(bool active)723 BApplication::AppActivated(bool active)
724 {
725 // supposed to be implemented by subclasses
726 }
727
728
729 void
RefsReceived(BMessage * message)730 BApplication::RefsReceived(BMessage* message)
731 {
732 // supposed to be implemented by subclasses
733 }
734
735
736 void
AboutRequested()737 BApplication::AboutRequested()
738 {
739 // supposed to be implemented by subclasses
740 }
741
742
743 BHandler*
ResolveSpecifier(BMessage * message,int32 index,BMessage * specifier,int32 what,const char * property)744 BApplication::ResolveSpecifier(BMessage* message, int32 index,
745 BMessage* specifier, int32 what, const char* property)
746 {
747 BPropertyInfo propInfo(sPropertyInfo);
748 status_t err = B_OK;
749 uint32 data;
750
751 if (propInfo.FindMatch(message, 0, specifier, what, property, &data) >= 0) {
752 switch (data) {
753 case kWindowByIndex:
754 {
755 int32 index;
756 err = specifier->FindInt32("index", &index);
757 if (err != B_OK)
758 break;
759
760 if (what == B_REVERSE_INDEX_SPECIFIER)
761 index = CountWindows() - index;
762
763 BWindow* window = WindowAt(index);
764 if (window != NULL) {
765 message->PopSpecifier();
766 BMessenger(window).SendMessage(message);
767 } else
768 err = B_BAD_INDEX;
769 break;
770 }
771
772 case kWindowByName:
773 {
774 const char* name;
775 err = specifier->FindString("name", &name);
776 if (err != B_OK)
777 break;
778
779 for (int32 i = 0;; i++) {
780 BWindow* window = WindowAt(i);
781 if (window == NULL) {
782 err = B_NAME_NOT_FOUND;
783 break;
784 }
785 if (window->Title() != NULL && !strcmp(window->Title(),
786 name)) {
787 message->PopSpecifier();
788 BMessenger(window).SendMessage(message);
789 break;
790 }
791 }
792 break;
793 }
794
795 case kLooperByIndex:
796 {
797 int32 index;
798 err = specifier->FindInt32("index", &index);
799 if (err != B_OK)
800 break;
801
802 if (what == B_REVERSE_INDEX_SPECIFIER)
803 index = CountLoopers() - index;
804
805 BLooper* looper = LooperAt(index);
806 if (looper != NULL) {
807 message->PopSpecifier();
808 BMessenger(looper).SendMessage(message);
809 } else
810 err = B_BAD_INDEX;
811
812 break;
813 }
814
815 case kLooperByID:
816 // TODO: implement getting looper by ID!
817 break;
818
819 case kLooperByName:
820 {
821 const char* name;
822 err = specifier->FindString("name", &name);
823 if (err != B_OK)
824 break;
825
826 for (int32 i = 0;; i++) {
827 BLooper* looper = LooperAt(i);
828 if (looper == NULL) {
829 err = B_NAME_NOT_FOUND;
830 break;
831 }
832 if (looper->Name() != NULL
833 && strcmp(looper->Name(), name) == 0) {
834 message->PopSpecifier();
835 BMessenger(looper).SendMessage(message);
836 break;
837 }
838 }
839 break;
840 }
841
842 case kApplication:
843 return this;
844 }
845 } else {
846 return BLooper::ResolveSpecifier(message, index, specifier, what,
847 property);
848 }
849
850 if (err != B_OK) {
851 BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
852 reply.AddInt32("error", err);
853 reply.AddString("message", strerror(err));
854 message->SendReply(&reply);
855 }
856
857 return NULL;
858
859 }
860
861
862 void
ShowCursor()863 BApplication::ShowCursor()
864 {
865 BPrivate::AppServerLink link;
866 link.StartMessage(AS_SHOW_CURSOR);
867 link.Flush();
868 }
869
870
871 void
HideCursor()872 BApplication::HideCursor()
873 {
874 BPrivate::AppServerLink link;
875 link.StartMessage(AS_HIDE_CURSOR);
876 link.Flush();
877 }
878
879
880 void
ObscureCursor()881 BApplication::ObscureCursor()
882 {
883 BPrivate::AppServerLink link;
884 link.StartMessage(AS_OBSCURE_CURSOR);
885 link.Flush();
886 }
887
888
889 bool
IsCursorHidden() const890 BApplication::IsCursorHidden() const
891 {
892 BPrivate::AppServerLink link;
893 int32 status = B_ERROR;
894 link.StartMessage(AS_QUERY_CURSOR_HIDDEN);
895 link.FlushWithReply(status);
896
897 return status == B_OK;
898 }
899
900
901 void
SetCursor(const void * cursorData)902 BApplication::SetCursor(const void* cursorData)
903 {
904 BCursor cursor(cursorData);
905 SetCursor(&cursor, true);
906 // forces the cursor to be sync'ed
907 }
908
909
910 void
SetCursor(const BCursor * cursor,bool sync)911 BApplication::SetCursor(const BCursor* cursor, bool sync)
912 {
913 BPrivate::AppServerLink link;
914 link.StartMessage(AS_SET_CURSOR);
915 link.Attach<bool>(sync);
916 link.Attach<int32>(cursor->fServerToken);
917
918 if (sync) {
919 int32 code;
920 link.FlushWithReply(code);
921 } else
922 link.Flush();
923 }
924
925
926 int32
CountWindows() const927 BApplication::CountWindows() const
928 {
929 return _CountWindows(false);
930 // we're ignoring menu windows
931 }
932
933
934 BWindow*
WindowAt(int32 index) const935 BApplication::WindowAt(int32 index) const
936 {
937 return _WindowAt(index, false);
938 // we're ignoring menu windows
939 }
940
941
942 int32
CountLoopers() const943 BApplication::CountLoopers() const
944 {
945 AutoLocker<BLooperList> ListLock(gLooperList);
946 if (ListLock.IsLocked())
947 return gLooperList.CountLoopers();
948
949 // Some bad, non-specific thing has happened
950 return B_ERROR;
951 }
952
953
954 BLooper*
LooperAt(int32 index) const955 BApplication::LooperAt(int32 index) const
956 {
957 BLooper* looper = NULL;
958 AutoLocker<BLooperList> listLock(gLooperList);
959 if (listLock.IsLocked())
960 looper = gLooperList.LooperAt(index);
961
962 return looper;
963 }
964
965
966 status_t
RegisterLooper(BLooper * looper)967 BApplication::RegisterLooper(BLooper* looper)
968 {
969 BWindow* window = dynamic_cast<BWindow*>(looper);
970 if (window != NULL)
971 return B_BAD_VALUE;
972
973 if (sOnQuitLooperList.HasItem(looper))
974 return B_ERROR;
975
976 if (sOnQuitLooperList.AddItem(looper) != true)
977 return B_ERROR;
978
979 return B_OK;
980 }
981
982
983 status_t
UnregisterLooper(BLooper * looper)984 BApplication::UnregisterLooper(BLooper* looper)
985 {
986 BWindow* window = dynamic_cast<BWindow*>(looper);
987 if (window != NULL)
988 return B_BAD_VALUE;
989
990 if (!sOnQuitLooperList.HasItem(looper))
991 return B_ERROR;
992
993 if (sOnQuitLooperList.RemoveItem(looper) != true)
994 return B_ERROR;
995
996 return B_OK;
997 }
998
999
1000 bool
IsLaunching() const1001 BApplication::IsLaunching() const
1002 {
1003 return !fReadyToRunCalled;
1004 }
1005
1006
1007 const char*
Signature() const1008 BApplication::Signature() const
1009 {
1010 return fAppName;
1011 }
1012
1013
1014 status_t
GetAppInfo(app_info * info) const1015 BApplication::GetAppInfo(app_info* info) const
1016 {
1017 if (be_app == NULL || be_roster == NULL)
1018 return B_NO_INIT;
1019 return be_roster->GetRunningAppInfo(be_app->Team(), info);
1020 }
1021
1022
1023 BResources*
AppResources()1024 BApplication::AppResources()
1025 {
1026 if (sAppResources == NULL)
1027 pthread_once(&sAppResourcesInitOnce, &_InitAppResources);
1028
1029 return sAppResources;
1030 }
1031
1032
1033 void
DispatchMessage(BMessage * message,BHandler * handler)1034 BApplication::DispatchMessage(BMessage* message, BHandler* handler)
1035 {
1036 if (handler != this) {
1037 // it's not ours to dispatch
1038 BLooper::DispatchMessage(message, handler);
1039 return;
1040 }
1041
1042 switch (message->what) {
1043 case B_ARGV_RECEIVED:
1044 _ArgvReceived(message);
1045 break;
1046
1047 case B_REFS_RECEIVED:
1048 {
1049 // this adds the refs that are part of this message to the recent
1050 // lists, but only folders and documents are handled here
1051 entry_ref ref;
1052 int32 i = 0;
1053 while (message->FindRef("refs", i++, &ref) == B_OK) {
1054 BEntry entry(&ref, true);
1055 if (entry.InitCheck() != B_OK)
1056 continue;
1057
1058 if (entry.IsDirectory())
1059 BRoster().AddToRecentFolders(&ref);
1060 else {
1061 // filter out applications, we only want to have documents
1062 // in the recent files list
1063 BNode node(&entry);
1064 BNodeInfo info(&node);
1065
1066 char mimeType[B_MIME_TYPE_LENGTH];
1067 if (info.GetType(mimeType) != B_OK
1068 || strcasecmp(mimeType, B_APP_MIME_TYPE))
1069 BRoster().AddToRecentDocuments(&ref);
1070 }
1071 }
1072
1073 RefsReceived(message);
1074 break;
1075 }
1076
1077 case B_READY_TO_RUN:
1078 if (!fReadyToRunCalled) {
1079 ReadyToRun();
1080 fReadyToRunCalled = true;
1081 }
1082 break;
1083
1084 case B_ABOUT_REQUESTED:
1085 AboutRequested();
1086 break;
1087
1088 case B_PULSE:
1089 Pulse();
1090 break;
1091
1092 case B_APP_ACTIVATED:
1093 {
1094 bool active;
1095 if (message->FindBool("active", &active) == B_OK)
1096 AppActivated(active);
1097 break;
1098 }
1099
1100 case B_COLORS_UPDATED:
1101 {
1102 AutoLocker<BLooperList> listLock(gLooperList);
1103 if (!listLock.IsLocked())
1104 break;
1105
1106 BWindow* window = NULL;
1107 uint32 count = gLooperList.CountLoopers();
1108 for (uint32 index = 0; index < count; ++index) {
1109 window = dynamic_cast<BWindow*>(gLooperList.LooperAt(index));
1110 if (window == NULL || (window != NULL && window->fOffscreen))
1111 continue;
1112 window->PostMessage(message);
1113 }
1114 break;
1115 }
1116
1117 case _SHOW_DRAG_HANDLES_:
1118 {
1119 bool show;
1120 if (message->FindBool("show", &show) != B_OK)
1121 break;
1122
1123 BDragger::Private::UpdateShowAllDraggers(show);
1124 break;
1125 }
1126
1127 // TODO: Handle these as well
1128 case _DISPOSE_DRAG_:
1129 case _PING_:
1130 puts("not yet handled message:");
1131 DBG(message->PrintToStream());
1132 break;
1133
1134 default:
1135 BLooper::DispatchMessage(message, handler);
1136 break;
1137 }
1138 }
1139
1140
1141 void
SetPulseRate(bigtime_t rate)1142 BApplication::SetPulseRate(bigtime_t rate)
1143 {
1144 if (rate < 0)
1145 rate = 0;
1146
1147 // BeBook states that we have only 100,000 microseconds granularity
1148 rate -= rate % 100000;
1149
1150 if (!Lock())
1151 return;
1152
1153 if (rate != 0) {
1154 // reset existing pulse runner, or create new one
1155 if (fPulseRunner == NULL) {
1156 BMessage pulse(B_PULSE);
1157 fPulseRunner = new BMessageRunner(be_app_messenger, &pulse, rate);
1158 } else
1159 fPulseRunner->SetInterval(rate);
1160 } else {
1161 // turn off pulse messages
1162 delete fPulseRunner;
1163 fPulseRunner = NULL;
1164 }
1165
1166 fPulseRate = rate;
1167 Unlock();
1168 }
1169
1170
1171 status_t
GetSupportedSuites(BMessage * data)1172 BApplication::GetSupportedSuites(BMessage* data)
1173 {
1174 if (data == NULL)
1175 return B_BAD_VALUE;
1176
1177 status_t status = data->AddString("suites", "suite/vnd.Be-application");
1178 if (status == B_OK) {
1179 BPropertyInfo propertyInfo(sPropertyInfo);
1180 status = data->AddFlat("messages", &propertyInfo);
1181 if (status == B_OK)
1182 status = BLooper::GetSupportedSuites(data);
1183 }
1184
1185 return status;
1186 }
1187
1188
1189 status_t
Perform(perform_code d,void * arg)1190 BApplication::Perform(perform_code d, void* arg)
1191 {
1192 return BLooper::Perform(d, arg);
1193 }
1194
1195
_ReservedApplication1()1196 void BApplication::_ReservedApplication1() {}
_ReservedApplication2()1197 void BApplication::_ReservedApplication2() {}
_ReservedApplication3()1198 void BApplication::_ReservedApplication3() {}
_ReservedApplication4()1199 void BApplication::_ReservedApplication4() {}
_ReservedApplication5()1200 void BApplication::_ReservedApplication5() {}
_ReservedApplication6()1201 void BApplication::_ReservedApplication6() {}
_ReservedApplication7()1202 void BApplication::_ReservedApplication7() {}
_ReservedApplication8()1203 void BApplication::_ReservedApplication8() {}
1204
1205
1206 bool
ScriptReceived(BMessage * message,int32 index,BMessage * specifier,int32 what,const char * property)1207 BApplication::ScriptReceived(BMessage* message, int32 index,
1208 BMessage* specifier, int32 what, const char* property)
1209 {
1210 BMessage reply(B_REPLY);
1211 status_t err = B_BAD_SCRIPT_SYNTAX;
1212
1213 switch (message->what) {
1214 case B_GET_PROPERTY:
1215 if (strcmp("Loopers", property) == 0) {
1216 int32 count = CountLoopers();
1217 err = B_OK;
1218 for (int32 i=0; err == B_OK && i<count; i++) {
1219 BMessenger messenger(LooperAt(i));
1220 err = reply.AddMessenger("result", messenger);
1221 }
1222 } else if (strcmp("Windows", property) == 0) {
1223 int32 count = CountWindows();
1224 err = B_OK;
1225 for (int32 i=0; err == B_OK && i<count; i++) {
1226 BMessenger messenger(WindowAt(i));
1227 err = reply.AddMessenger("result", messenger);
1228 }
1229 } else if (strcmp("Window", property) == 0) {
1230 switch (what) {
1231 case B_INDEX_SPECIFIER:
1232 case B_REVERSE_INDEX_SPECIFIER:
1233 {
1234 int32 index = -1;
1235 err = specifier->FindInt32("index", &index);
1236 if (err != B_OK)
1237 break;
1238
1239 if (what == B_REVERSE_INDEX_SPECIFIER)
1240 index = CountWindows() - index;
1241
1242 err = B_BAD_INDEX;
1243 BWindow* window = WindowAt(index);
1244 if (window == NULL)
1245 break;
1246
1247 BMessenger messenger(window);
1248 err = reply.AddMessenger("result", messenger);
1249 break;
1250 }
1251
1252 case B_NAME_SPECIFIER:
1253 {
1254 const char* name;
1255 err = specifier->FindString("name", &name);
1256 if (err != B_OK)
1257 break;
1258 err = B_NAME_NOT_FOUND;
1259 for (int32 i = 0; i < CountWindows(); i++) {
1260 BWindow* window = WindowAt(i);
1261 if (window && window->Name() != NULL
1262 && !strcmp(window->Name(), name)) {
1263 BMessenger messenger(window);
1264 err = reply.AddMessenger("result", messenger);
1265 break;
1266 }
1267 }
1268 break;
1269 }
1270 }
1271 } else if (strcmp("Looper", property) == 0) {
1272 switch (what) {
1273 case B_INDEX_SPECIFIER:
1274 case B_REVERSE_INDEX_SPECIFIER:
1275 {
1276 int32 index = -1;
1277 err = specifier->FindInt32("index", &index);
1278 if (err != B_OK)
1279 break;
1280
1281 if (what == B_REVERSE_INDEX_SPECIFIER)
1282 index = CountLoopers() - index;
1283
1284 err = B_BAD_INDEX;
1285 BLooper* looper = LooperAt(index);
1286 if (looper == NULL)
1287 break;
1288
1289 BMessenger messenger(looper);
1290 err = reply.AddMessenger("result", messenger);
1291 break;
1292 }
1293
1294 case B_NAME_SPECIFIER:
1295 {
1296 const char* name;
1297 err = specifier->FindString("name", &name);
1298 if (err != B_OK)
1299 break;
1300 err = B_NAME_NOT_FOUND;
1301 for (int32 i = 0; i < CountLoopers(); i++) {
1302 BLooper* looper = LooperAt(i);
1303 if (looper != NULL && looper->Name()
1304 && strcmp(looper->Name(), name) == 0) {
1305 BMessenger messenger(looper);
1306 err = reply.AddMessenger("result", messenger);
1307 break;
1308 }
1309 }
1310 break;
1311 }
1312
1313 case B_ID_SPECIFIER:
1314 {
1315 // TODO
1316 debug_printf("Looper's ID specifier used but not "
1317 "implemented.\n");
1318 break;
1319 }
1320 }
1321 } else if (strcmp("Name", property) == 0)
1322 err = reply.AddString("result", Name());
1323
1324 break;
1325
1326 case B_COUNT_PROPERTIES:
1327 if (strcmp("Looper", property) == 0)
1328 err = reply.AddInt32("result", CountLoopers());
1329 else if (strcmp("Window", property) == 0)
1330 err = reply.AddInt32("result", CountWindows());
1331
1332 break;
1333 }
1334 if (err == B_BAD_SCRIPT_SYNTAX)
1335 return false;
1336
1337 if (err < B_OK) {
1338 reply.what = B_MESSAGE_NOT_UNDERSTOOD;
1339 reply.AddString("message", strerror(err));
1340 }
1341 reply.AddInt32("error", err);
1342 message->SendReply(&reply);
1343
1344 return true;
1345 }
1346
1347
1348 void
BeginRectTracking(BRect rect,bool trackWhole)1349 BApplication::BeginRectTracking(BRect rect, bool trackWhole)
1350 {
1351 BPrivate::AppServerLink link;
1352 link.StartMessage(AS_BEGIN_RECT_TRACKING);
1353 link.Attach<BRect>(rect);
1354 link.Attach<int32>(trackWhole);
1355 link.Flush();
1356 }
1357
1358
1359 void
EndRectTracking()1360 BApplication::EndRectTracking()
1361 {
1362 BPrivate::AppServerLink link;
1363 link.StartMessage(AS_END_RECT_TRACKING);
1364 link.Flush();
1365 }
1366
1367
1368 status_t
_SetupServerAllocator()1369 BApplication::_SetupServerAllocator()
1370 {
1371 fServerAllocator = new (std::nothrow) BPrivate::ServerMemoryAllocator();
1372 if (fServerAllocator == NULL)
1373 return B_NO_MEMORY;
1374
1375 return fServerAllocator->InitCheck();
1376 }
1377
1378
1379 status_t
_InitGUIContext()1380 BApplication::_InitGUIContext()
1381 {
1382 // An app_server connection is necessary for a lot of stuff, so get that first.
1383 status_t error = _ConnectToServer();
1384 if (error != B_OK)
1385 return error;
1386
1387 // Initialize the IK after we have set be_app because of a construction
1388 // of a AppServerLink (which depends on be_app) nested inside the call
1389 // to get_menu_info.
1390 error = _init_interface_kit_();
1391 if (error != B_OK)
1392 return error;
1393
1394 // create global system cursors
1395 B_CURSOR_SYSTEM_DEFAULT = new BCursor(B_HAND_CURSOR);
1396 B_CURSOR_I_BEAM = new BCursor(B_I_BEAM_CURSOR);
1397
1398 // TODO: would be nice to get the workspace at launch time from the registrar
1399 fInitialWorkspace = current_workspace();
1400
1401 return B_OK;
1402 }
1403
1404
1405 status_t
_ConnectToServer()1406 BApplication::_ConnectToServer()
1407 {
1408 status_t status
1409 = create_desktop_connection(fServerLink, "a<app_server", 100);
1410 if (status != B_OK)
1411 return status;
1412
1413 // AS_CREATE_APP:
1414 //
1415 // Attach data:
1416 // 1) port_id - receiver port of a regular app
1417 // 2) port_id - looper port for this BApplication
1418 // 3) team_id - team identification field
1419 // 4) int32 - handler ID token of the app
1420 // 5) char* - signature of the regular app
1421
1422 fServerLink->StartMessage(AS_CREATE_APP);
1423 fServerLink->Attach<port_id>(fServerLink->ReceiverPort());
1424 fServerLink->Attach<port_id>(_get_looper_port_(this));
1425 fServerLink->Attach<team_id>(Team());
1426 fServerLink->Attach<int32>(_get_object_token_(this));
1427 fServerLink->AttachString(fAppName);
1428
1429 area_id sharedReadOnlyArea;
1430 team_id serverTeam;
1431 port_id serverPort;
1432
1433 int32 code;
1434 if (fServerLink->FlushWithReply(code) == B_OK
1435 && code == B_OK) {
1436 // We don't need to contact the main app_server anymore
1437 // directly; we now talk to our server alter ego only.
1438 fServerLink->Read<port_id>(&serverPort);
1439 fServerLink->Read<area_id>(&sharedReadOnlyArea);
1440 fServerLink->Read<team_id>(&serverTeam);
1441 } else {
1442 fServerLink->SetSenderPort(-1);
1443 debugger("BApplication: couldn't obtain new app_server comm port");
1444 return B_ERROR;
1445 }
1446 fServerLink->SetTargetTeam(serverTeam);
1447 fServerLink->SetSenderPort(serverPort);
1448
1449 status = _SetupServerAllocator();
1450 if (status != B_OK)
1451 return status;
1452
1453 area_id area;
1454 uint8* base;
1455 status = fServerAllocator->AddArea(sharedReadOnlyArea, area, base, true);
1456 if (status < B_OK)
1457 return status;
1458
1459 fServerReadOnlyMemory = base;
1460
1461 return B_OK;
1462 }
1463
1464
1465 void
_ReconnectToServer()1466 BApplication::_ReconnectToServer()
1467 {
1468 // the sender port belongs to the app_server
1469 delete_port(fServerLink->ReceiverPort());
1470
1471 if (_ConnectToServer() != B_OK)
1472 debugger("Can't reconnect to app server!");
1473
1474 AutoLocker<BLooperList> listLock(gLooperList);
1475 if (!listLock.IsLocked())
1476 return;
1477
1478 uint32 count = gLooperList.CountLoopers();
1479 for (uint32 i = 0; i < count ; i++) {
1480 BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1481 if (window == NULL)
1482 continue;
1483 BMessenger windowMessenger(window);
1484 windowMessenger.SendMessage(kMsgAppServerRestarted);
1485 }
1486
1487 reconnect_bitmaps_to_app_server();
1488 reconnect_pictures_to_app_server();
1489 }
1490
1491
1492 #if 0
1493 void
1494 BApplication::send_drag(BMessage* message, int32 vs_token, BPoint offset,
1495 BRect dragRect, BHandler* replyTo)
1496 {
1497 // TODO: implement
1498 }
1499
1500
1501 void
1502 BApplication::send_drag(BMessage* message, int32 vs_token, BPoint offset,
1503 int32 bitmapToken, drawing_mode dragMode, BHandler* replyTo)
1504 {
1505 // TODO: implement
1506 }
1507
1508
1509 void
1510 BApplication::write_drag(_BSession_* session, BMessage* message)
1511 {
1512 // TODO: implement
1513 }
1514 #endif
1515
1516
1517 bool
_WindowQuitLoop(bool quitFilePanels,bool force)1518 BApplication::_WindowQuitLoop(bool quitFilePanels, bool force)
1519 {
1520 int32 index = 0;
1521 while (true) {
1522 BWindow* window = WindowAt(index);
1523 if (window == NULL)
1524 break;
1525
1526 // NOTE: the window pointer might be stale, in case the looper
1527 // was already quit by quitting an earlier looper... but fortunately,
1528 // we can still call Lock() on the invalid pointer, and it
1529 // will return false...
1530 if (!window->Lock())
1531 continue;
1532
1533 // don't quit file panels if we haven't been asked for it
1534 if (!quitFilePanels && window->IsFilePanel()) {
1535 window->Unlock();
1536 index++;
1537 continue;
1538 }
1539
1540 if (!force && !window->QuitRequested()
1541 && !(quitFilePanels && window->IsFilePanel())) {
1542 // the window does not want to quit, so we don't either
1543 window->Unlock();
1544 return false;
1545 }
1546
1547 // Re-lock, just to make sure that the user hasn't done nasty
1548 // things in QuitRequested(). Quit() unlocks fully, thus
1549 // double-locking is harmless.
1550 if (window->Lock())
1551 window->Quit();
1552
1553 index = 0;
1554 // we need to continue at the start of the list again - it
1555 // might have changed
1556 }
1557
1558 return true;
1559 }
1560
1561
1562 bool
_QuitAllWindows(bool force)1563 BApplication::_QuitAllWindows(bool force)
1564 {
1565 AssertLocked();
1566
1567 // We need to unlock here because BWindow::QuitRequested() must be
1568 // allowed to lock the application - which would cause a deadlock
1569 Unlock();
1570
1571 bool quit = _WindowQuitLoop(false, force);
1572 if (quit)
1573 quit = _WindowQuitLoop(true, force);
1574
1575 Lock();
1576
1577 return quit;
1578 }
1579
1580
1581 void
_ArgvReceived(BMessage * message)1582 BApplication::_ArgvReceived(BMessage* message)
1583 {
1584 ASSERT(message != NULL);
1585
1586 // build the argv vector
1587 status_t error = B_OK;
1588 int32 argc = 0;
1589 char** argv = NULL;
1590 if (message->FindInt32("argc", &argc) == B_OK && argc > 0) {
1591 // allocate a NULL terminated array
1592 argv = new(std::nothrow) char*[argc + 1];
1593 if (argv == NULL)
1594 return;
1595
1596 // copy the arguments
1597 for (int32 i = 0; error == B_OK && i < argc; i++) {
1598 const char* arg = NULL;
1599 error = message->FindString("argv", i, &arg);
1600 if (error == B_OK && arg) {
1601 argv[i] = strdup(arg);
1602 if (argv[i] == NULL)
1603 error = B_NO_MEMORY;
1604 } else
1605 argc = i;
1606 }
1607
1608 argv[argc] = NULL;
1609 }
1610
1611 // call the hook
1612 if (error == B_OK && argc > 0)
1613 ArgvReceived(argc, argv);
1614
1615 if (error != B_OK) {
1616 printf("Error parsing B_ARGV_RECEIVED message. Message:\n");
1617 message->PrintToStream();
1618 }
1619
1620 // cleanup
1621 if (argv) {
1622 for (int32 i = 0; i < argc; i++)
1623 free(argv[i]);
1624 delete[] argv;
1625 }
1626 }
1627
1628
1629 uint32
InitialWorkspace()1630 BApplication::InitialWorkspace()
1631 {
1632 return fInitialWorkspace;
1633 }
1634
1635
1636 int32
_CountWindows(bool includeMenus) const1637 BApplication::_CountWindows(bool includeMenus) const
1638 {
1639 uint32 count = 0;
1640 for (int32 i = 0; i < gLooperList.CountLoopers(); i++) {
1641 BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1642 if (window != NULL && !window->fOffscreen && (includeMenus
1643 || dynamic_cast<BMenuWindow*>(window) == NULL)) {
1644 count++;
1645 }
1646 }
1647
1648 return count;
1649 }
1650
1651
1652 BWindow*
_WindowAt(uint32 index,bool includeMenus) const1653 BApplication::_WindowAt(uint32 index, bool includeMenus) const
1654 {
1655 AutoLocker<BLooperList> listLock(gLooperList);
1656 if (!listLock.IsLocked())
1657 return NULL;
1658
1659 uint32 count = gLooperList.CountLoopers();
1660 for (uint32 i = 0; i < count && index < count; i++) {
1661 BWindow* window = dynamic_cast<BWindow*>(gLooperList.LooperAt(i));
1662 if (window == NULL || (window != NULL && window->fOffscreen)
1663 || (!includeMenus && dynamic_cast<BMenuWindow*>(window) != NULL)) {
1664 index++;
1665 continue;
1666 }
1667
1668 if (i == index)
1669 return window;
1670 }
1671
1672 return NULL;
1673 }
1674
1675
1676 /*static*/ void
_InitAppResources()1677 BApplication::_InitAppResources()
1678 {
1679 entry_ref ref;
1680 bool found = false;
1681
1682 // App is already running. Get its entry ref with
1683 // GetAppInfo()
1684 app_info appInfo;
1685 if (be_app && be_app->GetAppInfo(&appInfo) == B_OK) {
1686 ref = appInfo.ref;
1687 found = true;
1688 } else {
1689 // Run() hasn't been called yet
1690 found = BPrivate::get_app_ref(&ref) == B_OK;
1691 }
1692
1693 if (!found)
1694 return;
1695
1696 BFile file(&ref, B_READ_ONLY);
1697 if (file.InitCheck() != B_OK)
1698 return;
1699
1700 BResources* resources = new (std::nothrow) BResources(&file, false);
1701 if (resources == NULL || resources->InitCheck() != B_OK) {
1702 delete resources;
1703 return;
1704 }
1705
1706 sAppResources = resources;
1707 }
1708