1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Application.cpp 23 // Author: Erik Jaesler (erik@cgsoftware.com) 24 // Description: BApplication class is the center of the application 25 // universe. The global be_app and be_app_messenger 26 // variables are defined here as well. 27 //------------------------------------------------------------------------------ 28 29 // Standard Includes ----------------------------------------------------------- 30 #include <new> 31 #include <stdio.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 // System Includes ------------------------------------------------------------- 36 #include <Alert.h> 37 #include <AppFileInfo.h> 38 #include <Application.h> 39 #include <AppMisc.h> 40 #include <Cursor.h> 41 #include <Entry.h> 42 #include <File.h> 43 #include <InterfaceDefs.h> 44 #include <Locker.h> 45 #include <Path.h> 46 #include <PropertyInfo.h> 47 #include <RegistrarDefs.h> 48 #include <Roster.h> 49 #include <RosterPrivate.h> 50 #include <Window.h> 51 52 // Project Includes ------------------------------------------------------------ 53 #include <LooperList.h> 54 #include <ObjectLocker.h> 55 #include <AppServerLink.h> 56 #include <ServerProtocol.h> 57 #include <PortLink.h> 58 #include <PortMessage.h> 59 60 // Local Includes -------------------------------------------------------------- 61 62 // Local Defines --------------------------------------------------------------- 63 64 // Globals --------------------------------------------------------------------- 65 BApplication* be_app = NULL; 66 BMessenger be_app_messenger; 67 68 BResources* BApplication::_app_resources = NULL; 69 BLocker BApplication::_app_resources_lock("_app_resources_lock"); 70 71 property_info gApplicationPropInfo[] = 72 { 73 { 74 "Window", 75 {}, 76 {B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER}, 77 NULL, 0, 78 {}, 79 {}, 80 {} 81 }, 82 { 83 "Window", 84 {}, 85 {B_NAME_SPECIFIER}, 86 NULL, 1, 87 {}, 88 {}, 89 {} 90 }, 91 { 92 "Looper", 93 {}, 94 {B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER}, 95 NULL, 2, 96 {}, 97 {}, 98 {} 99 }, 100 { 101 "Looper", 102 {}, 103 {B_ID_SPECIFIER}, 104 NULL, 3, 105 {}, 106 {}, 107 {} 108 }, 109 { 110 "Looper", 111 {}, 112 {B_NAME_SPECIFIER}, 113 NULL, 4, 114 {}, 115 {}, 116 {} 117 }, 118 { 119 "Name", 120 {B_GET_PROPERTY}, 121 {B_DIRECT_SPECIFIER}, 122 NULL, 5, 123 {B_STRING_TYPE}, 124 {}, 125 {} 126 }, 127 { 128 "Window", 129 {B_COUNT_PROPERTIES}, 130 {B_DIRECT_SPECIFIER}, 131 NULL, 5, 132 {B_INT32_TYPE}, 133 {}, 134 {} 135 }, 136 { 137 "Loopers", 138 {B_GET_PROPERTY}, 139 {B_DIRECT_SPECIFIER}, 140 NULL, 5, 141 {B_MESSENGER_TYPE}, 142 {}, 143 {} 144 }, 145 { 146 "Windows", 147 {B_GET_PROPERTY}, 148 {B_DIRECT_SPECIFIER}, 149 NULL, 5, 150 {B_MESSENGER_TYPE}, 151 {}, 152 {} 153 }, 154 { 155 "Looper", 156 {B_COUNT_PROPERTIES}, 157 {B_DIRECT_SPECIFIER}, 158 NULL, 5, 159 {B_INT32_TYPE}, 160 {}, 161 {} 162 }, 163 {} 164 }; 165 166 // argc/argv 167 extern const int __libc_argc; 168 extern const char * const *__libc_argv; 169 170 class BMenuWindow : public BWindow 171 { 172 }; 173 //------------------------------------------------------------------------------ 174 175 // debugging 176 //#define DBG(x) x 177 #define DBG(x) 178 #define OUT printf 179 180 enum { 181 NOT_IMPLEMENTED = B_ERROR, 182 }; 183 184 // prototypes of helper functions 185 static const char* looper_name_for(const char *signature); 186 static status_t check_app_signature(const char *signature); 187 188 //------------------------------------------------------------------------------ 189 BApplication::BApplication(const char* signature) 190 : BLooper(looper_name_for(signature)), 191 fAppName(NULL), 192 fServerFrom(-1), 193 fServerTo(-1), 194 fServerHeap(NULL), 195 fPulseRate(500000), 196 fInitialWorkspace(0), 197 fDraggedMessage(NULL), 198 fPulseRunner(NULL), 199 fInitError(B_NO_INIT), 200 fReadyToRunCalled(false) 201 { 202 InitData(signature, NULL); 203 } 204 //------------------------------------------------------------------------------ 205 BApplication::BApplication(const char* signature, status_t* error) 206 : BLooper(looper_name_for(signature)), 207 fAppName(NULL), 208 fServerFrom(-1), 209 fServerTo(-1), 210 fServerHeap(NULL), 211 fPulseRate(500000), 212 fInitialWorkspace(0), 213 fDraggedMessage(NULL), 214 fPulseRunner(NULL), 215 fInitError(B_NO_INIT), 216 fReadyToRunCalled(false) 217 { 218 InitData(signature, error); 219 } 220 //------------------------------------------------------------------------------ 221 BApplication::~BApplication() 222 { 223 // tell all loopers(usualy windows) to quit. Also, wait for them. 224 BWindow* window = NULL; 225 BList looperList; 226 { 227 using namespace BPrivate; 228 BObjectLocker<BLooperList> ListLock(gLooperList); 229 if (ListLock.IsLocked()) 230 gLooperList.GetLooperList(&looperList); 231 } 232 233 for (int32 i = 0; i < looperList.CountItems(); i++) 234 { 235 window = dynamic_cast<BWindow*>((BLooper*)looperList.ItemAt(i)); 236 if (window) 237 { 238 window->Lock(); 239 window->Quit(); 240 } 241 } 242 243 // unregister from the roster 244 BRoster::Private().RemoveApp(Team()); 245 246 // tell app_server we're quiting... 247 PortLink link(fServerFrom); 248 link.SetOpCode(B_QUIT_REQUESTED); 249 link.Flush(); 250 251 // uninitialize be_app and be_app_messenger 252 be_app = NULL; 253 // R5 doesn't uninitialize be_app_messenger. 254 // be_app_messenger = BMessenger(); 255 } 256 //------------------------------------------------------------------------------ 257 BApplication::BApplication(BMessage* data) 258 : BLooper(looper_name_for(NULL)), 259 fAppName(NULL), 260 fServerFrom(-1), 261 fServerTo(-1), 262 fServerHeap(NULL), 263 fPulseRate(500000), 264 fInitialWorkspace(0), 265 fDraggedMessage(NULL), 266 fPulseRunner(NULL), 267 fInitError(B_NO_INIT), 268 fReadyToRunCalled(false) 269 { 270 } 271 //------------------------------------------------------------------------------ 272 BArchivable* BApplication::Instantiate(BMessage* data) 273 { 274 if (!validate_instantiation(data, "BApplication")) 275 { 276 return NULL; 277 } 278 279 return new BApplication(data); 280 } 281 //------------------------------------------------------------------------------ 282 status_t BApplication::Archive(BMessage* data, bool deep) const 283 { 284 return NOT_IMPLEMENTED; 285 } 286 //------------------------------------------------------------------------------ 287 status_t BApplication::InitCheck() const 288 { 289 return fInitError; 290 } 291 //------------------------------------------------------------------------------ 292 thread_id BApplication::Run() 293 { 294 AssertLocked(); 295 296 if (fRunCalled) 297 { 298 // Not allowed to call Run() more than once 299 // TODO: test 300 // find out what message is actually here 301 debugger(""); 302 } 303 304 // Note: We need a local variable too (for the return value), since 305 // fTaskID is cleared by Quit(). 306 thread_id thread = fTaskID = find_thread(NULL); 307 308 if (fMsgPort == B_NO_MORE_PORTS || fMsgPort == B_BAD_VALUE) 309 { 310 return fMsgPort; 311 } 312 313 fRunCalled = true; 314 315 run_task(); 316 317 return thread; 318 } 319 //------------------------------------------------------------------------------ 320 void BApplication::Quit() 321 { 322 bool unlock = false; 323 if (!IsLocked()) { 324 const char* name = Name(); 325 if (!name) 326 name = "no-name"; 327 printf("ERROR - you must Lock the application object before calling " 328 "Quit(), team=%ld, looper=%s\n", Team(), name); 329 unlock = true; 330 if (!Lock()) 331 return; 332 } 333 // Delete the object, if not running only. 334 if (!fRunCalled) { 335 delete this; 336 } else if (find_thread(NULL) != fTaskID) { 337 // We are not the looper thread. 338 // We push a _QUIT_ into the queue. 339 // TODO: When BLooper::AddMessage() is done, use that instead of 340 // PostMessage()??? This would overtake messages that are still at 341 // the port. 342 // NOTE: We must not unlock here -- otherwise we had to re-lock, which 343 // may not work. This is bad, since, if the port is full, it 344 // won't get emptier, as the looper thread needs to lock the object 345 // before dispatching messages. 346 while (PostMessage(_QUIT_, this) == B_WOULD_BLOCK) 347 snooze(10000); 348 } else { 349 // We are the looper thread. 350 // Just set fTerminating to true which makes us fall through the 351 // message dispatching loop and return from Run(). 352 fTerminating = true; 353 } 354 // If we had to lock the object, unlock now. 355 if (unlock) 356 Unlock(); 357 } 358 //------------------------------------------------------------------------------ 359 bool BApplication::QuitRequested() 360 { 361 // No windows -- nothing to do. 362 return BLooper::QuitRequested(); 363 } 364 //------------------------------------------------------------------------------ 365 void BApplication::Pulse() 366 { 367 } 368 //------------------------------------------------------------------------------ 369 void BApplication::ReadyToRun() 370 { 371 } 372 //------------------------------------------------------------------------------ 373 void BApplication::MessageReceived(BMessage* msg) 374 { 375 BLooper::MessageReceived(msg); 376 } 377 //------------------------------------------------------------------------------ 378 void BApplication::ArgvReceived(int32 argc, char** argv) 379 { 380 } 381 //------------------------------------------------------------------------------ 382 void BApplication::AppActivated(bool active) 383 { 384 } 385 //------------------------------------------------------------------------------ 386 void BApplication::RefsReceived(BMessage* a_message) 387 { 388 } 389 //------------------------------------------------------------------------------ 390 void BApplication::AboutRequested() 391 { 392 thread_info info; 393 if (get_thread_info(Thread(), &info) == B_OK) { 394 BAlert *alert = new BAlert("_about_", info.name, "OK"); 395 alert->Go(NULL); 396 } 397 } 398 //------------------------------------------------------------------------------ 399 BHandler* BApplication::ResolveSpecifier(BMessage* msg, int32 index, 400 BMessage* specifier, int32 form, 401 const char* property) 402 { 403 return NULL; // not implemented 404 } 405 //------------------------------------------------------------------------------ 406 void BApplication::ShowCursor() 407 { 408 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 409 int32 foo=AS_SHOW_CURSOR; 410 write_port(fServerTo,AS_SHOW_CURSOR,&foo,sizeof(int32)); 411 } 412 //------------------------------------------------------------------------------ 413 void BApplication::HideCursor() 414 { 415 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 416 int32 foo=AS_HIDE_CURSOR; 417 write_port(fServerTo,AS_HIDE_CURSOR,&foo,sizeof(int32)); 418 } 419 //------------------------------------------------------------------------------ 420 void BApplication::ObscureCursor() 421 { 422 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 423 int32 foo=AS_OBSCURE_CURSOR; 424 write_port(fServerTo,AS_OBSCURE_CURSOR,&foo,sizeof(int32)); 425 } 426 //------------------------------------------------------------------------------ 427 bool BApplication::IsCursorHidden() const 428 { 429 PortMessage msg; 430 431 BPrivate::BAppServerLink link; 432 link.SetOpCode(AS_QUERY_CURSOR_HIDDEN); 433 link.FlushWithReply(&msg); 434 return (msg.Code()==SERVER_TRUE)?true:false; 435 } 436 //------------------------------------------------------------------------------ 437 void BApplication::SetCursor(const void* cursor) 438 { 439 // BeBook sez: If you want to call SetCursor() without forcing an immediate 440 // sync of the Application Server, you have to use a BCursor. 441 // By deductive reasoning, this function forces a sync. =) 442 BCursor Cursor(cursor); 443 SetCursor(&Cursor, true); 444 } 445 //------------------------------------------------------------------------------ 446 void BApplication::SetCursor(const BCursor* cursor, bool sync) 447 { 448 BPrivate::BAppServerLink link; 449 PortMessage msg; 450 451 link.SetOpCode(AS_SET_CURSOR_BCURSOR); 452 link.Attach<bool>(sync); 453 link.Attach<int32>(cursor->m_serverToken); 454 if(sync) 455 link.FlushWithReply(&msg); 456 else 457 link.Flush(); 458 } 459 //------------------------------------------------------------------------------ 460 int32 BApplication::CountWindows() const 461 { 462 // BeBook sez: The windows list includes all windows explicitely created by 463 // the app ... but excludes private windows create by Be 464 // classes. 465 // I'm taking this to include private menu windows, thus the incl_menus 466 // param is false. 467 return count_windows(false); 468 } 469 //------------------------------------------------------------------------------ 470 BWindow* BApplication::WindowAt(int32 index) const 471 { 472 // BeBook sez: The windows list includes all windows explicitely created by 473 // the app ... but excludes private windows create by Be 474 // classes. 475 // I'm taking this to include private menu windows, thus the incl_menus 476 // param is false. 477 return window_at(index, false); 478 } 479 //------------------------------------------------------------------------------ 480 int32 BApplication::CountLoopers() const 481 { 482 using namespace BPrivate; 483 BObjectLocker<BLooperList> ListLock(gLooperList); 484 if (ListLock.IsLocked()) 485 { 486 return gLooperList.CountLoopers(); 487 } 488 489 return B_ERROR; // Some bad, non-specific thing has happened 490 } 491 //------------------------------------------------------------------------------ 492 BLooper* BApplication::LooperAt(int32 index) const 493 { 494 using namespace BPrivate; 495 BLooper* Looper = NULL; 496 BObjectLocker<BLooperList> ListLock(gLooperList); 497 if (ListLock.IsLocked()) 498 { 499 Looper = gLooperList.LooperAt(index); 500 } 501 502 return Looper; 503 } 504 //------------------------------------------------------------------------------ 505 bool BApplication::IsLaunching() const 506 { 507 return !fReadyToRunCalled; 508 } 509 //------------------------------------------------------------------------------ 510 status_t BApplication::GetAppInfo(app_info* info) const 511 { 512 return be_roster->GetRunningAppInfo(be_app->Team(), info); 513 } 514 //------------------------------------------------------------------------------ 515 BResources* BApplication::AppResources() 516 { 517 return NULL; // not implemented 518 } 519 //------------------------------------------------------------------------------ 520 void BApplication::DispatchMessage(BMessage* message, BHandler* handler) 521 { 522 switch (message->what) { 523 case B_ARGV_RECEIVED: 524 { 525 // build the argv vector 526 status_t error = B_OK; 527 int32 argc; 528 char **argv = NULL; 529 if (message->FindInt32("argc", &argc) == B_OK && argc > 0) { 530 argv = new char*[argc]; 531 for (int32 i = 0; error == B_OK && i < argc; i++) 532 argv[i] = NULL; 533 // copy the arguments 534 for (int32 i = 0; error == B_OK && i < argc; i++) { 535 const char *arg = NULL; 536 error = message->FindString("argv", i, &arg); 537 if (error == B_OK && arg) { 538 argv[i] = new(std::nothrow) char[strlen(arg) + 1]; 539 if (argv[i]) 540 strcpy(argv[i], arg); 541 else 542 error = B_NO_MEMORY; 543 } 544 } 545 } 546 // call the hook 547 if (error == B_OK) 548 ArgvReceived(argc, argv); 549 // cleanup 550 if (argv) { 551 for (int32 i = 0; i < argc; i++) 552 delete[] argv[i]; 553 delete[] argv; 554 } 555 break; 556 } 557 case B_REFS_RECEIVED: 558 RefsReceived(message); 559 break; 560 case B_READY_TO_RUN: 561 // TODO: Find out, whether to set fReadyToRunCalled before or 562 // after calling the hook. 563 ReadyToRun(); 564 fReadyToRunCalled = true; 565 break; 566 default: 567 BLooper::DispatchMessage(message, handler); 568 break; 569 } 570 } 571 //------------------------------------------------------------------------------ 572 void BApplication::SetPulseRate(bigtime_t rate) 573 { 574 fPulseRate = rate; 575 } 576 //------------------------------------------------------------------------------ 577 status_t BApplication::GetSupportedSuites(BMessage* data) 578 { 579 status_t err = B_OK; 580 if (!data) 581 { 582 err = B_BAD_VALUE; 583 } 584 585 if (!err) 586 { 587 err = data->AddString("Suites", "suite/vnd.Be-application"); 588 if (!err) 589 { 590 BPropertyInfo PropertyInfo(gApplicationPropInfo); 591 err = data->AddFlat("message", &PropertyInfo); 592 if (!err) 593 { 594 err = BHandler::GetSupportedSuites(data); 595 } 596 } 597 } 598 599 return err; 600 } 601 //------------------------------------------------------------------------------ 602 status_t BApplication::Perform(perform_code d, void* arg) 603 { 604 return NOT_IMPLEMENTED; 605 } 606 //------------------------------------------------------------------------------ 607 BApplication::BApplication(uint32 signature) 608 { 609 } 610 //------------------------------------------------------------------------------ 611 BApplication::BApplication(const BApplication& rhs) 612 { 613 } 614 //------------------------------------------------------------------------------ 615 BApplication& BApplication::operator=(const BApplication& rhs) 616 { 617 return *this; 618 } 619 //------------------------------------------------------------------------------ 620 void BApplication::_ReservedApplication1() 621 { 622 } 623 //------------------------------------------------------------------------------ 624 void BApplication::_ReservedApplication2() 625 { 626 } 627 //------------------------------------------------------------------------------ 628 void BApplication::_ReservedApplication3() 629 { 630 } 631 //------------------------------------------------------------------------------ 632 void BApplication::_ReservedApplication4() 633 { 634 } 635 //------------------------------------------------------------------------------ 636 void BApplication::_ReservedApplication5() 637 { 638 } 639 //------------------------------------------------------------------------------ 640 void BApplication::_ReservedApplication6() 641 { 642 } 643 //------------------------------------------------------------------------------ 644 void BApplication::_ReservedApplication7() 645 { 646 } 647 //------------------------------------------------------------------------------ 648 void BApplication::_ReservedApplication8() 649 { 650 } 651 //------------------------------------------------------------------------------ 652 bool BApplication::ScriptReceived(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property) 653 { 654 return false; // not implemented 655 } 656 //------------------------------------------------------------------------------ 657 void BApplication::run_task() 658 { 659 task_looper(); 660 } 661 //------------------------------------------------------------------------------ 662 void BApplication::InitData(const char* signature, status_t* error) 663 { 664 // check whether there exists already an application 665 if (be_app) 666 debugger("2 BApplication objects were created. Only one is allowed."); 667 // check signature 668 fInitError = check_app_signature(signature); 669 fAppName = signature; 670 bool isRegistrar 671 = (signature && !strcasecmp(signature, kRegistrarSignature)); 672 // get team and thread 673 team_id team = Team(); 674 thread_id thread = BPrivate::main_thread_for(team); 675 // get app executable ref 676 entry_ref ref; 677 if (fInitError == B_OK) 678 fInitError = BPrivate::get_app_ref(&ref); 679 // get the BAppFileInfo and extract the information we need 680 uint32 appFlags = B_REG_DEFAULT_APP_FLAGS; 681 if (fInitError == B_OK) { 682 BAppFileInfo fileInfo; 683 BFile file(&ref, B_READ_ONLY); 684 fInitError = fileInfo.SetTo(&file); 685 if (fInitError == B_OK) { 686 fileInfo.GetAppFlags(&appFlags); 687 char appFileSignature[B_MIME_TYPE_LENGTH + 1]; 688 // compare the file signature and the supplied signature 689 if (fileInfo.GetSignature(appFileSignature) == B_OK) { 690 if (strcasecmp(appFileSignature, signature) != 0) { 691 printf("Signature in rsrc doesn't match constructor arg. " 692 "(%s,%s)\n", signature, appFileSignature); 693 } 694 } 695 } 696 } 697 #ifndef RUN_WITHOUT_REGISTRAR 698 // check whether be_roster is valid 699 if (fInitError == B_OK && !isRegistrar 700 && !BRoster::Private().IsMessengerValid(false)) { 701 printf("FATAL: be_roster is not valid. Is the registrar running?\n"); 702 fInitError = B_NO_INIT; 703 } 704 705 // check whether or not we are pre-registered 706 bool preRegistered = false; 707 app_info appInfo; 708 if (fInitError == B_OK && !isRegistrar) { 709 preRegistered = BRoster::Private().IsAppPreRegistered(&ref, team, 710 &appInfo); 711 } 712 if (preRegistered) { 713 // we are pre-registered => the app info has been filled in 714 // Check whether we need to replace the looper port with a port 715 // created by the roster. 716 if (appInfo.port >= 0 && appInfo.port != fMsgPort) { 717 delete_port(fMsgPort); 718 fMsgPort = appInfo.port; 719 } else 720 appInfo.port = fMsgPort; 721 // check the signature and correct it, if necessary 722 if (strcasecmp(appInfo.signature, fAppName)) 723 BRoster::Private().SetSignature(team, fAppName); 724 // complete the registration 725 fInitError = BRoster::Private().CompleteRegistration(team, thread, 726 appInfo.port); 727 } else if (fInitError == B_OK) { 728 // not pre-registered -- try to register the application 729 team_id otherTeam = -1; 730 // the registrar must not register 731 if (!isRegistrar) { 732 fInitError = BRoster::Private().AddApplication(signature, &ref, 733 appFlags, team, thread, fMsgPort, true, NULL, &otherTeam); 734 } 735 if (fInitError == B_ALREADY_RUNNING) { 736 // An instance is already running and we asked for 737 // single/exclusive launch. Send our argv to the running app. 738 // Do that only, if the app is NOT B_ARGV_ONLY. 739 if (otherTeam >= 0 && __libc_argc > 1) { 740 app_info otherAppInfo; 741 if (be_roster->GetRunningAppInfo(otherTeam, &otherAppInfo) 742 == B_OK && !(otherAppInfo.flags & B_ARGV_ONLY)) { 743 // create an B_ARGV_RECEIVED message 744 BMessage argvMessage(B_ARGV_RECEIVED); 745 do_argv(&argvMessage); 746 // replace the first argv string with the path of the 747 // other application 748 BPath path; 749 if (path.SetTo(&otherAppInfo.ref) == B_OK) 750 argvMessage.ReplaceString("argv", 0, path.Path()); 751 // send the message 752 BMessenger(NULL, otherTeam).SendMessage(&argvMessage); 753 } 754 } 755 } else if (fInitError == B_OK) { 756 // the registrations was successful 757 // Create a B_ARGV_RECEIVED message and send it to ourselves. 758 // Do that even, if we are B_ARGV_ONLY. 759 // TODO: When BLooper::AddMessage() is done, use that instead of 760 // PostMessage(). 761 if (__libc_argc > 1) { 762 BMessage argvMessage(B_ARGV_RECEIVED); 763 do_argv(&argvMessage); 764 PostMessage(&argvMessage, this); 765 } 766 // send a B_READY_TO_RUN message as well 767 PostMessage(B_READY_TO_RUN, this); 768 } else if (fInitError > B_ERRORS_END) { 769 // Registrar internal errors shouldn't fall into the user's hands. 770 fInitError = B_ERROR; 771 } 772 } 773 #endif // ifdef RUN_WITHOUT_REGISTRAR 774 775 // TODO: Not completely sure about the order, but this should be close. 776 777 // An app_server connection is necessary for a lot of stuff, so get that first. 778 if (fInitError == B_OK) 779 connect_to_app_server(); 780 if (fInitError == B_OK) 781 setup_server_heaps(); 782 if (fInitError == B_OK) 783 get_scs(); 784 785 786 // init be_app and be_app_messenger 787 if (fInitError == B_OK) { 788 be_app = this; 789 be_app_messenger = BMessenger(NULL, this); 790 } 791 792 // Initialize the IK after we have set be_app because of a construction of a 793 // BAppServerLink (which depends on be_app) nested inside the call to get_menu_info. 794 if (fInitError == B_OK) 795 fInitError = _init_interface_kit_(); 796 // set the BHandler's name 797 if (fInitError == B_OK) 798 SetName(ref.name); 799 // create meta MIME 800 if (fInitError == B_OK) { 801 BPath path; 802 if (path.SetTo(&ref) == B_OK) 803 create_app_meta_mime(path.Path(), false, true, false); 804 } 805 // Return the error or exit, if there was an error and no error variable 806 // has been supplied. 807 if (error) 808 *error = fInitError; 809 else if (fInitError != B_OK) 810 exit(0); 811 } 812 //------------------------------------------------------------------------------ 813 void BApplication::BeginRectTracking(BRect r, bool trackWhole) 814 { 815 BPrivate::BAppServerLink link; 816 link.Attach<int32>(AS_BEGIN_RECT_TRACKING); 817 link.Attach<BRect>(r); 818 link.Attach<int32>(trackWhole); 819 link.Flush(); 820 } 821 //------------------------------------------------------------------------------ 822 void BApplication::EndRectTracking() 823 { 824 int32 foo=AS_END_RECT_TRACKING; 825 write_port(fServerTo,AS_END_RECT_TRACKING,&foo,sizeof(int32)); 826 } 827 //------------------------------------------------------------------------------ 828 void BApplication::get_scs() 829 { 830 //gPrivateScreen = new BPrivateScreen(); 831 } 832 //------------------------------------------------------------------------------ 833 void BApplication::setup_server_heaps() 834 { 835 } 836 //------------------------------------------------------------------------------ 837 void* BApplication::rw_offs_to_ptr(uint32 offset) 838 { 839 return NULL; // not implemented 840 } 841 //------------------------------------------------------------------------------ 842 void* BApplication::ro_offs_to_ptr(uint32 offset) 843 { 844 return NULL; // not implemented 845 } 846 //------------------------------------------------------------------------------ 847 void* BApplication::global_ro_offs_to_ptr(uint32 offset) 848 { 849 return NULL; // not implemented 850 } 851 //------------------------------------------------------------------------------ 852 void BApplication::connect_to_app_server() 853 { 854 fServerFrom = find_port(SERVER_PORT_NAME); 855 if (fServerFrom > 0) { 856 // Create the port so that the app_server knows where to send messages 857 fServerTo = create_port(100, "a<fServerTo"); 858 if (fServerTo > 0) { 859 // AS_CREATE_APP: 860 861 // Attach data: 862 // 1) port_id - receiver port of a regular app 863 // 2) port_id - looper port for this BApplication 864 // 3) team_id - team identification field 865 // 4) int32 - handler ID token of the app 866 // 5) char * - signature of the regular app 867 PortLink link(fServerFrom); 868 PortMessage pmsg; 869 870 link.SetOpCode(AS_CREATE_APP); 871 link.Attach<port_id>(fServerTo); 872 link.Attach<port_id>(_get_looper_port_(this)); 873 link.Attach<team_id>(Team()); 874 link.Attach<int32>(_get_object_token_(this)); 875 link.AttachString(fAppName); 876 link.FlushWithReply(&pmsg); 877 878 // Reply code: AS_CREATE_APP 879 // Reply data: 880 // 1) port_id server-side application port (fServerFrom value) 881 pmsg.Read<port_id>(&fServerFrom); 882 } 883 else 884 fInitError = fServerTo; 885 } else 886 fInitError = fServerFrom; 887 } 888 //------------------------------------------------------------------------------ 889 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, BRect drag_rect, BHandler* reply_to) 890 { 891 } 892 //------------------------------------------------------------------------------ 893 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, int32 bitmap_token, drawing_mode dragMode, BHandler* reply_to) 894 { 895 } 896 //------------------------------------------------------------------------------ 897 void BApplication::write_drag(_BSession_* session, BMessage* a_message) 898 { 899 } 900 //------------------------------------------------------------------------------ 901 bool BApplication::quit_all_windows(bool force) 902 { 903 return false; // not implemented 904 } 905 //------------------------------------------------------------------------------ 906 bool BApplication::window_quit_loop(bool, bool) 907 { 908 return false; // not implemented 909 } 910 //------------------------------------------------------------------------------ 911 void BApplication::do_argv(BMessage* message) 912 { 913 if (message) { 914 int32 argc = __libc_argc; 915 const char * const *argv = __libc_argv; 916 // add argc 917 message->AddInt32("argc", argc); 918 // add argv 919 for (int32 i = 0; i < argc; i++) 920 message->AddString("argv", argv[i]); 921 // add current working directory 922 char cwd[B_PATH_NAME_LENGTH + 1]; 923 if (getcwd(cwd, B_PATH_NAME_LENGTH + 1)) 924 message->AddString("cwd", cwd); 925 } 926 } 927 //------------------------------------------------------------------------------ 928 uint32 BApplication::InitialWorkspace() 929 { 930 return 0; // not implemented 931 } 932 //------------------------------------------------------------------------------ 933 int32 BApplication::count_windows(bool incl_menus) const 934 { 935 using namespace BPrivate; 936 937 // Windows are BLoopers, so we can just check each BLooper to see if it's 938 // a BWindow (or BMenuWindow) 939 int32 count = 0; 940 BObjectLocker<BLooperList> ListLock(gLooperList); 941 if (ListLock.IsLocked()) 942 { 943 BLooper* Looper = NULL; 944 for (int32 i = 0; i < gLooperList.CountLoopers(); ++i) 945 { 946 Looper = gLooperList.LooperAt(i); 947 if (dynamic_cast<BWindow*>(Looper)) 948 { 949 if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL) 950 { 951 ++count; 952 } 953 } 954 } 955 } 956 957 return count; 958 } 959 //------------------------------------------------------------------------------ 960 BWindow* BApplication::window_at(uint32 index, bool incl_menus) const 961 { 962 using namespace BPrivate; 963 964 // Windows are BLoopers, so we can just check each BLooper to see if it's 965 // a BWindow (or BMenuWindow) 966 uint32 count = 0; 967 BWindow* Window = NULL; 968 BObjectLocker<BLooperList> ListLock(gLooperList); 969 if (ListLock.IsLocked()) 970 { 971 BLooper* Looper = NULL; 972 for (int32 i = 0; i < gLooperList.CountLoopers() && !Window; ++i) 973 { 974 Looper = gLooperList.LooperAt(i); 975 if (dynamic_cast<BWindow*>(Looper)) 976 { 977 if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL) 978 { 979 if (count == index) 980 { 981 Window = dynamic_cast<BWindow*>(Looper); 982 } 983 else 984 { 985 ++count; 986 } 987 } 988 } 989 } 990 } 991 992 return Window; 993 } 994 //------------------------------------------------------------------------------ 995 status_t BApplication::get_window_list(BList* list, bool incl_menus) const 996 { 997 return NOT_IMPLEMENTED; 998 } 999 //------------------------------------------------------------------------------ 1000 int32 BApplication::async_quit_entry(void* data) 1001 { 1002 return 0; // not implemented 1003 } 1004 //------------------------------------------------------------------------------ 1005 1006 // check_app_signature 1007 /*! \brief Checks whether the supplied string is a valid application signature. 1008 1009 An error message is printed, if the string is no valid app signature. 1010 1011 \param signature The string to be checked. 1012 \return 1013 - \c B_OK: \a signature is a valid app signature. 1014 - \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature. 1015 */ 1016 static 1017 status_t 1018 check_app_signature(const char *signature) 1019 { 1020 bool isValid = false; 1021 BMimeType type(signature); 1022 if (type.IsValid() && !type.IsSupertypeOnly() 1023 && BMimeType("application").Contains(&type)) { 1024 isValid = true; 1025 } 1026 if (!isValid) { 1027 printf("bad signature (%s), must begin with \"application/\" and " 1028 "can't conflict with existing registered mime types inside " 1029 "the \"application\" media type.\n", signature); 1030 } 1031 return (isValid ? B_OK : B_BAD_VALUE); 1032 } 1033 1034 // looper_name_for 1035 /*! \brief Returns the looper name for a given signature. 1036 1037 Normally this is "AppLooperPort", but in case of the registrar a 1038 special name. 1039 1040 \return The looper name. 1041 */ 1042 static 1043 const char* 1044 looper_name_for(const char *signature) 1045 { 1046 if (signature && !strcasecmp(signature, kRegistrarSignature)) 1047 return kRosterPortName; 1048 return "AppLooperPort"; 1049 } 1050 1051 1052 /* 1053 * $Log $ 1054 * 1055 * $Id $ 1056 * 1057 */ 1058 1059