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 // TODO: Au contraire, we can have opened windows, and we have 363 // to quit them. 364 365 return BLooper::QuitRequested(); 366 } 367 //------------------------------------------------------------------------------ 368 void BApplication::Pulse() 369 { 370 } 371 //------------------------------------------------------------------------------ 372 void BApplication::ReadyToRun() 373 { 374 } 375 //------------------------------------------------------------------------------ 376 void BApplication::MessageReceived(BMessage* msg) 377 { 378 BLooper::MessageReceived(msg); 379 } 380 //------------------------------------------------------------------------------ 381 void BApplication::ArgvReceived(int32 argc, char** argv) 382 { 383 } 384 //------------------------------------------------------------------------------ 385 void BApplication::AppActivated(bool active) 386 { 387 } 388 //------------------------------------------------------------------------------ 389 void BApplication::RefsReceived(BMessage* a_message) 390 { 391 } 392 //------------------------------------------------------------------------------ 393 void BApplication::AboutRequested() 394 { 395 thread_info info; 396 if (get_thread_info(Thread(), &info) == B_OK) { 397 BAlert *alert = new BAlert("_about_", info.name, "OK"); 398 alert->Go(NULL); 399 } 400 } 401 //------------------------------------------------------------------------------ 402 BHandler* BApplication::ResolveSpecifier(BMessage* msg, int32 index, 403 BMessage* specifier, int32 form, 404 const char* property) 405 { 406 return NULL; // not implemented 407 } 408 //------------------------------------------------------------------------------ 409 void BApplication::ShowCursor() 410 { 411 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 412 int32 foo=AS_SHOW_CURSOR; 413 write_port(fServerTo,AS_SHOW_CURSOR,&foo,sizeof(int32)); 414 } 415 //------------------------------------------------------------------------------ 416 void BApplication::HideCursor() 417 { 418 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 419 int32 foo=AS_HIDE_CURSOR; 420 write_port(fServerTo,AS_HIDE_CURSOR,&foo,sizeof(int32)); 421 } 422 //------------------------------------------------------------------------------ 423 void BApplication::ObscureCursor() 424 { 425 // Because we're just sending an opcode, we can skip the BSession and fake the protocol 426 int32 foo=AS_OBSCURE_CURSOR; 427 write_port(fServerTo,AS_OBSCURE_CURSOR,&foo,sizeof(int32)); 428 } 429 //------------------------------------------------------------------------------ 430 bool BApplication::IsCursorHidden() const 431 { 432 PortMessage msg; 433 434 BPrivate::BAppServerLink link; 435 link.SetOpCode(AS_QUERY_CURSOR_HIDDEN); 436 link.FlushWithReply(&msg); 437 return (msg.Code()==SERVER_TRUE)?true:false; 438 } 439 //------------------------------------------------------------------------------ 440 void BApplication::SetCursor(const void* cursor) 441 { 442 // BeBook sez: If you want to call SetCursor() without forcing an immediate 443 // sync of the Application Server, you have to use a BCursor. 444 // By deductive reasoning, this function forces a sync. =) 445 BCursor Cursor(cursor); 446 SetCursor(&Cursor, true); 447 } 448 //------------------------------------------------------------------------------ 449 void BApplication::SetCursor(const BCursor* cursor, bool sync) 450 { 451 BPrivate::BAppServerLink link; 452 PortMessage msg; 453 454 link.SetOpCode(AS_SET_CURSOR_BCURSOR); 455 link.Attach<bool>(sync); 456 link.Attach<int32>(cursor->m_serverToken); 457 if(sync) 458 link.FlushWithReply(&msg); 459 else 460 link.Flush(); 461 } 462 //------------------------------------------------------------------------------ 463 int32 BApplication::CountWindows() const 464 { 465 // BeBook sez: The windows list includes all windows explicitely created by 466 // the app ... but excludes private windows create by Be 467 // classes. 468 // I'm taking this to include private menu windows, thus the incl_menus 469 // param is false. 470 return count_windows(false); 471 } 472 //------------------------------------------------------------------------------ 473 BWindow* BApplication::WindowAt(int32 index) const 474 { 475 // BeBook sez: The windows list includes all windows explicitely created by 476 // the app ... but excludes private windows create by Be 477 // classes. 478 // I'm taking this to include private menu windows, thus the incl_menus 479 // param is false. 480 return window_at(index, false); 481 } 482 //------------------------------------------------------------------------------ 483 int32 BApplication::CountLoopers() const 484 { 485 using namespace BPrivate; 486 BObjectLocker<BLooperList> ListLock(gLooperList); 487 if (ListLock.IsLocked()) 488 { 489 return gLooperList.CountLoopers(); 490 } 491 492 return B_ERROR; // Some bad, non-specific thing has happened 493 } 494 //------------------------------------------------------------------------------ 495 BLooper* BApplication::LooperAt(int32 index) const 496 { 497 using namespace BPrivate; 498 BLooper* Looper = NULL; 499 BObjectLocker<BLooperList> ListLock(gLooperList); 500 if (ListLock.IsLocked()) 501 { 502 Looper = gLooperList.LooperAt(index); 503 } 504 505 return Looper; 506 } 507 //------------------------------------------------------------------------------ 508 bool BApplication::IsLaunching() const 509 { 510 return !fReadyToRunCalled; 511 } 512 //------------------------------------------------------------------------------ 513 status_t BApplication::GetAppInfo(app_info* info) const 514 { 515 return be_roster->GetRunningAppInfo(be_app->Team(), info); 516 } 517 //------------------------------------------------------------------------------ 518 BResources* BApplication::AppResources() 519 { 520 return NULL; // not implemented 521 } 522 //------------------------------------------------------------------------------ 523 void BApplication::DispatchMessage(BMessage* message, BHandler* handler) 524 { 525 switch (message->what) { 526 case B_ARGV_RECEIVED: 527 { 528 // build the argv vector 529 status_t error = B_OK; 530 int32 argc; 531 char **argv = NULL; 532 if (message->FindInt32("argc", &argc) == B_OK && argc > 0) { 533 argv = new char*[argc]; 534 for (int32 i = 0; error == B_OK && i < argc; i++) 535 argv[i] = NULL; 536 // copy the arguments 537 for (int32 i = 0; error == B_OK && i < argc; i++) { 538 const char *arg = NULL; 539 error = message->FindString("argv", i, &arg); 540 if (error == B_OK && arg) { 541 argv[i] = new(std::nothrow) char[strlen(arg) + 1]; 542 if (argv[i]) 543 strcpy(argv[i], arg); 544 else 545 error = B_NO_MEMORY; 546 } 547 } 548 } 549 // call the hook 550 if (error == B_OK) 551 ArgvReceived(argc, argv); 552 // cleanup 553 if (argv) { 554 for (int32 i = 0; i < argc; i++) 555 delete[] argv[i]; 556 delete[] argv; 557 } 558 break; 559 } 560 case B_REFS_RECEIVED: 561 RefsReceived(message); 562 break; 563 case B_READY_TO_RUN: 564 // TODO: Find out, whether to set fReadyToRunCalled before or 565 // after calling the hook. 566 ReadyToRun(); 567 fReadyToRunCalled = true; 568 break; 569 default: 570 BLooper::DispatchMessage(message, handler); 571 break; 572 } 573 } 574 //------------------------------------------------------------------------------ 575 void BApplication::SetPulseRate(bigtime_t rate) 576 { 577 fPulseRate = rate; 578 } 579 //------------------------------------------------------------------------------ 580 status_t BApplication::GetSupportedSuites(BMessage* data) 581 { 582 status_t err = B_OK; 583 if (!data) 584 { 585 err = B_BAD_VALUE; 586 } 587 588 if (!err) 589 { 590 err = data->AddString("Suites", "suite/vnd.Be-application"); 591 if (!err) 592 { 593 BPropertyInfo PropertyInfo(gApplicationPropInfo); 594 err = data->AddFlat("message", &PropertyInfo); 595 if (!err) 596 { 597 err = BHandler::GetSupportedSuites(data); 598 } 599 } 600 } 601 602 return err; 603 } 604 //------------------------------------------------------------------------------ 605 status_t BApplication::Perform(perform_code d, void* arg) 606 { 607 return NOT_IMPLEMENTED; 608 } 609 //------------------------------------------------------------------------------ 610 BApplication::BApplication(uint32 signature) 611 { 612 } 613 //------------------------------------------------------------------------------ 614 BApplication::BApplication(const BApplication& rhs) 615 { 616 } 617 //------------------------------------------------------------------------------ 618 BApplication& BApplication::operator=(const BApplication& rhs) 619 { 620 return *this; 621 } 622 //------------------------------------------------------------------------------ 623 void BApplication::_ReservedApplication1() 624 { 625 } 626 //------------------------------------------------------------------------------ 627 void BApplication::_ReservedApplication2() 628 { 629 } 630 //------------------------------------------------------------------------------ 631 void BApplication::_ReservedApplication3() 632 { 633 } 634 //------------------------------------------------------------------------------ 635 void BApplication::_ReservedApplication4() 636 { 637 } 638 //------------------------------------------------------------------------------ 639 void BApplication::_ReservedApplication5() 640 { 641 } 642 //------------------------------------------------------------------------------ 643 void BApplication::_ReservedApplication6() 644 { 645 } 646 //------------------------------------------------------------------------------ 647 void BApplication::_ReservedApplication7() 648 { 649 } 650 //------------------------------------------------------------------------------ 651 void BApplication::_ReservedApplication8() 652 { 653 } 654 //------------------------------------------------------------------------------ 655 bool BApplication::ScriptReceived(BMessage* msg, int32 index, BMessage* specifier, int32 form, const char* property) 656 { 657 return false; // not implemented 658 } 659 //------------------------------------------------------------------------------ 660 void BApplication::run_task() 661 { 662 task_looper(); 663 } 664 //------------------------------------------------------------------------------ 665 void BApplication::InitData(const char* signature, status_t* error) 666 { 667 // check whether there exists already an application 668 if (be_app) 669 debugger("2 BApplication objects were created. Only one is allowed."); 670 // check signature 671 fInitError = check_app_signature(signature); 672 fAppName = signature; 673 bool isRegistrar 674 = (signature && !strcasecmp(signature, kRegistrarSignature)); 675 // get team and thread 676 team_id team = Team(); 677 thread_id thread = BPrivate::main_thread_for(team); 678 // get app executable ref 679 entry_ref ref; 680 if (fInitError == B_OK) 681 fInitError = BPrivate::get_app_ref(&ref); 682 // get the BAppFileInfo and extract the information we need 683 uint32 appFlags = B_REG_DEFAULT_APP_FLAGS; 684 if (fInitError == B_OK) { 685 BAppFileInfo fileInfo; 686 BFile file(&ref, B_READ_ONLY); 687 fInitError = fileInfo.SetTo(&file); 688 if (fInitError == B_OK) { 689 fileInfo.GetAppFlags(&appFlags); 690 char appFileSignature[B_MIME_TYPE_LENGTH + 1]; 691 // compare the file signature and the supplied signature 692 if (fileInfo.GetSignature(appFileSignature) == B_OK) { 693 if (strcasecmp(appFileSignature, signature) != 0) { 694 printf("Signature in rsrc doesn't match constructor arg. " 695 "(%s,%s)\n", signature, appFileSignature); 696 } 697 } 698 } 699 } 700 #ifndef RUN_WITHOUT_REGISTRAR 701 // check whether be_roster is valid 702 if (fInitError == B_OK && !isRegistrar 703 && !BRoster::Private().IsMessengerValid(false)) { 704 printf("FATAL: be_roster is not valid. Is the registrar running?\n"); 705 fInitError = B_NO_INIT; 706 } 707 708 // check whether or not we are pre-registered 709 bool preRegistered = false; 710 app_info appInfo; 711 if (fInitError == B_OK && !isRegistrar) { 712 preRegistered = BRoster::Private().IsAppPreRegistered(&ref, team, 713 &appInfo); 714 } 715 if (preRegistered) { 716 // we are pre-registered => the app info has been filled in 717 // Check whether we need to replace the looper port with a port 718 // created by the roster. 719 if (appInfo.port >= 0 && appInfo.port != fMsgPort) { 720 delete_port(fMsgPort); 721 fMsgPort = appInfo.port; 722 } else 723 appInfo.port = fMsgPort; 724 // check the signature and correct it, if necessary 725 if (strcasecmp(appInfo.signature, fAppName)) 726 BRoster::Private().SetSignature(team, fAppName); 727 // complete the registration 728 fInitError = BRoster::Private().CompleteRegistration(team, thread, 729 appInfo.port); 730 } else if (fInitError == B_OK) { 731 // not pre-registered -- try to register the application 732 team_id otherTeam = -1; 733 // the registrar must not register 734 if (!isRegistrar) { 735 fInitError = BRoster::Private().AddApplication(signature, &ref, 736 appFlags, team, thread, fMsgPort, true, NULL, &otherTeam); 737 } 738 if (fInitError == B_ALREADY_RUNNING) { 739 // An instance is already running and we asked for 740 // single/exclusive launch. Send our argv to the running app. 741 // Do that only, if the app is NOT B_ARGV_ONLY. 742 if (otherTeam >= 0 && __libc_argc > 1) { 743 app_info otherAppInfo; 744 if (be_roster->GetRunningAppInfo(otherTeam, &otherAppInfo) 745 == B_OK && !(otherAppInfo.flags & B_ARGV_ONLY)) { 746 // create an B_ARGV_RECEIVED message 747 BMessage argvMessage(B_ARGV_RECEIVED); 748 do_argv(&argvMessage); 749 // replace the first argv string with the path of the 750 // other application 751 BPath path; 752 if (path.SetTo(&otherAppInfo.ref) == B_OK) 753 argvMessage.ReplaceString("argv", 0, path.Path()); 754 // send the message 755 BMessenger(NULL, otherTeam).SendMessage(&argvMessage); 756 } 757 } 758 } else if (fInitError == B_OK) { 759 // the registrations was successful 760 // Create a B_ARGV_RECEIVED message and send it to ourselves. 761 // Do that even, if we are B_ARGV_ONLY. 762 // TODO: When BLooper::AddMessage() is done, use that instead of 763 // PostMessage(). 764 if (__libc_argc > 1) { 765 BMessage argvMessage(B_ARGV_RECEIVED); 766 do_argv(&argvMessage); 767 PostMessage(&argvMessage, this); 768 } 769 // send a B_READY_TO_RUN message as well 770 PostMessage(B_READY_TO_RUN, this); 771 } else if (fInitError > B_ERRORS_END) { 772 // Registrar internal errors shouldn't fall into the user's hands. 773 fInitError = B_ERROR; 774 } 775 } 776 #endif // ifdef RUN_WITHOUT_REGISTRAR 777 778 // TODO: Not completely sure about the order, but this should be close. 779 780 // An app_server connection is necessary for a lot of stuff, so get that first. 781 if (fInitError == B_OK) 782 connect_to_app_server(); 783 if (fInitError == B_OK) 784 setup_server_heaps(); 785 if (fInitError == B_OK) 786 get_scs(); 787 788 789 // init be_app and be_app_messenger 790 if (fInitError == B_OK) { 791 be_app = this; 792 be_app_messenger = BMessenger(NULL, this); 793 } 794 795 // Initialize the IK after we have set be_app because of a construction of a 796 // BAppServerLink (which depends on be_app) nested inside the call to get_menu_info. 797 if (fInitError == B_OK) 798 fInitError = _init_interface_kit_(); 799 // set the BHandler's name 800 if (fInitError == B_OK) 801 SetName(ref.name); 802 // create meta MIME 803 if (fInitError == B_OK) { 804 BPath path; 805 if (path.SetTo(&ref) == B_OK) 806 create_app_meta_mime(path.Path(), false, true, false); 807 } 808 // Return the error or exit, if there was an error and no error variable 809 // has been supplied. 810 if (error) 811 *error = fInitError; 812 else if (fInitError != B_OK) 813 exit(0); 814 } 815 //------------------------------------------------------------------------------ 816 void BApplication::BeginRectTracking(BRect r, bool trackWhole) 817 { 818 BPrivate::BAppServerLink link; 819 link.Attach<int32>(AS_BEGIN_RECT_TRACKING); 820 link.Attach<BRect>(r); 821 link.Attach<int32>(trackWhole); 822 link.Flush(); 823 } 824 //------------------------------------------------------------------------------ 825 void BApplication::EndRectTracking() 826 { 827 int32 foo=AS_END_RECT_TRACKING; 828 write_port(fServerTo,AS_END_RECT_TRACKING,&foo,sizeof(int32)); 829 } 830 //------------------------------------------------------------------------------ 831 void BApplication::get_scs() 832 { 833 //gPrivateScreen = new BPrivateScreen(); 834 } 835 //------------------------------------------------------------------------------ 836 void BApplication::setup_server_heaps() 837 { 838 } 839 //------------------------------------------------------------------------------ 840 void* BApplication::rw_offs_to_ptr(uint32 offset) 841 { 842 return NULL; // not implemented 843 } 844 //------------------------------------------------------------------------------ 845 void* BApplication::ro_offs_to_ptr(uint32 offset) 846 { 847 return NULL; // not implemented 848 } 849 //------------------------------------------------------------------------------ 850 void* BApplication::global_ro_offs_to_ptr(uint32 offset) 851 { 852 return NULL; // not implemented 853 } 854 //------------------------------------------------------------------------------ 855 void BApplication::connect_to_app_server() 856 { 857 fServerFrom = find_port(SERVER_PORT_NAME); 858 if (fServerFrom > 0) { 859 // Create the port so that the app_server knows where to send messages 860 fServerTo = create_port(100, "a<fServerTo"); 861 if (fServerTo > 0) { 862 // AS_CREATE_APP: 863 864 // Attach data: 865 // 1) port_id - receiver port of a regular app 866 // 2) port_id - looper port for this BApplication 867 // 3) team_id - team identification field 868 // 4) int32 - handler ID token of the app 869 // 5) char * - signature of the regular app 870 PortLink link(fServerFrom); 871 PortMessage pmsg; 872 873 link.SetOpCode(AS_CREATE_APP); 874 link.Attach<port_id>(fServerTo); 875 link.Attach<port_id>(_get_looper_port_(this)); 876 link.Attach<team_id>(Team()); 877 link.Attach<int32>(_get_object_token_(this)); 878 link.AttachString(fAppName); 879 link.FlushWithReply(&pmsg); 880 881 // Reply code: AS_CREATE_APP 882 // Reply data: 883 // 1) port_id server-side application port (fServerFrom value) 884 pmsg.Read<port_id>(&fServerFrom); 885 } 886 else 887 fInitError = fServerTo; 888 } else 889 fInitError = fServerFrom; 890 } 891 //------------------------------------------------------------------------------ 892 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, BRect drag_rect, BHandler* reply_to) 893 { 894 } 895 //------------------------------------------------------------------------------ 896 void BApplication::send_drag(BMessage* msg, int32 vs_token, BPoint offset, int32 bitmap_token, drawing_mode dragMode, BHandler* reply_to) 897 { 898 } 899 //------------------------------------------------------------------------------ 900 void BApplication::write_drag(_BSession_* session, BMessage* a_message) 901 { 902 } 903 //------------------------------------------------------------------------------ 904 bool BApplication::quit_all_windows(bool force) 905 { 906 return false; // not implemented 907 } 908 //------------------------------------------------------------------------------ 909 bool BApplication::window_quit_loop(bool, bool) 910 { 911 // TODO: Implement and use in BApplication::QuitRequested() 912 return false; 913 } 914 //------------------------------------------------------------------------------ 915 void BApplication::do_argv(BMessage* message) 916 { 917 if (message) { 918 int32 argc = __libc_argc; 919 const char * const *argv = __libc_argv; 920 // add argc 921 message->AddInt32("argc", argc); 922 // add argv 923 for (int32 i = 0; i < argc; i++) 924 message->AddString("argv", argv[i]); 925 // add current working directory 926 char cwd[B_PATH_NAME_LENGTH + 1]; 927 if (getcwd(cwd, B_PATH_NAME_LENGTH + 1)) 928 message->AddString("cwd", cwd); 929 } 930 } 931 //------------------------------------------------------------------------------ 932 uint32 BApplication::InitialWorkspace() 933 { 934 return 0; // not implemented 935 } 936 //------------------------------------------------------------------------------ 937 int32 BApplication::count_windows(bool incl_menus) const 938 { 939 using namespace BPrivate; 940 941 // Windows are BLoopers, so we can just check each BLooper to see if it's 942 // a BWindow (or BMenuWindow) 943 int32 count = 0; 944 BObjectLocker<BLooperList> ListLock(gLooperList); 945 if (ListLock.IsLocked()) 946 { 947 BLooper* Looper = NULL; 948 for (int32 i = 0; i < gLooperList.CountLoopers(); ++i) 949 { 950 Looper = gLooperList.LooperAt(i); 951 if (dynamic_cast<BWindow*>(Looper)) 952 { 953 if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL) 954 { 955 ++count; 956 } 957 } 958 } 959 } 960 961 return count; 962 } 963 //------------------------------------------------------------------------------ 964 BWindow* BApplication::window_at(uint32 index, bool incl_menus) const 965 { 966 using namespace BPrivate; 967 968 // Windows are BLoopers, so we can just check each BLooper to see if it's 969 // a BWindow (or BMenuWindow) 970 uint32 count = 0; 971 BWindow* Window = NULL; 972 BObjectLocker<BLooperList> ListLock(gLooperList); 973 if (ListLock.IsLocked()) 974 { 975 BLooper* Looper = NULL; 976 for (int32 i = 0; i < gLooperList.CountLoopers() && !Window; ++i) 977 { 978 Looper = gLooperList.LooperAt(i); 979 if (dynamic_cast<BWindow*>(Looper)) 980 { 981 if (incl_menus || dynamic_cast<BMenuWindow*>(Looper) == NULL) 982 { 983 if (count == index) 984 { 985 Window = dynamic_cast<BWindow*>(Looper); 986 } 987 else 988 { 989 ++count; 990 } 991 } 992 } 993 } 994 } 995 996 return Window; 997 } 998 //------------------------------------------------------------------------------ 999 status_t BApplication::get_window_list(BList* list, bool incl_menus) const 1000 { 1001 return NOT_IMPLEMENTED; 1002 } 1003 //------------------------------------------------------------------------------ 1004 int32 BApplication::async_quit_entry(void* data) 1005 { 1006 return 0; // not implemented 1007 } 1008 //------------------------------------------------------------------------------ 1009 1010 // check_app_signature 1011 /*! \brief Checks whether the supplied string is a valid application signature. 1012 1013 An error message is printed, if the string is no valid app signature. 1014 1015 \param signature The string to be checked. 1016 \return 1017 - \c B_OK: \a signature is a valid app signature. 1018 - \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature. 1019 */ 1020 static 1021 status_t 1022 check_app_signature(const char *signature) 1023 { 1024 bool isValid = false; 1025 BMimeType type(signature); 1026 if (type.IsValid() && !type.IsSupertypeOnly() 1027 && BMimeType("application").Contains(&type)) { 1028 isValid = true; 1029 } 1030 if (!isValid) { 1031 printf("bad signature (%s), must begin with \"application/\" and " 1032 "can't conflict with existing registered mime types inside " 1033 "the \"application\" media type.\n", signature); 1034 } 1035 return (isValid ? B_OK : B_BAD_VALUE); 1036 } 1037 1038 // looper_name_for 1039 /*! \brief Returns the looper name for a given signature. 1040 1041 Normally this is "AppLooperPort", but in case of the registrar a 1042 special name. 1043 1044 \return The looper name. 1045 */ 1046 static 1047 const char* 1048 looper_name_for(const char *signature) 1049 { 1050 if (signature && !strcasecmp(signature, kRegistrarSignature)) 1051 return kRosterPortName; 1052 return "AppLooperPort"; 1053 } 1054 1055 1056 /* 1057 * $Log $ 1058 * 1059 * $Id $ 1060 * 1061 */ 1062 1063