1 /* 2 * Copyright 2007 Haiku, Inc. 3 * Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net> 4 * Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net> 5 * Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. 6 * 7 * Distributed under the terms of the MIT license. 8 */ 9 10 #include "TermWindow.h" 11 12 #include "Arguments.h" 13 #include "Coding.h" 14 #include "ColorWindow.h" 15 #include "MenuUtil.h" 16 #include "FindWindow.h" 17 #include "PrefWindow.h" 18 #include "PrefView.h" 19 #include "PrefHandler.h" 20 #include "SmartTabView.h" 21 #include "TermConst.h" 22 #include "TermView.h" 23 24 #include <Alert.h> 25 #include <Application.h> 26 #include <Clipboard.h> 27 #include <Dragger.h> 28 #include <Menu.h> 29 #include <MenuBar.h> 30 #include <MenuItem.h> 31 #include <Path.h> 32 #include <PrintJob.h> 33 #include <Roster.h> 34 #include <Screen.h> 35 #include <ScrollBar.h> 36 #include <ScrollView.h> 37 #include <String.h> 38 39 #include <stdio.h> 40 #include <string.h> 41 #include <time.h> 42 43 // 44 // help and GPL URL 45 // 46 //#define URL_PREFIX "file:///boot/home/config/settings/MuTerminal/help/" 47 //#define INDEX_FILE "/index.html" 48 //#define GPL_FILE "/gpl.html" 49 //#define CHLP_FILE "file:///boot/beos/documentation/Shell%20Tools/index.html" 50 51 52 const static float kViewOffset = 3; 53 const static uint32 kNewTab = 'NTab'; 54 const static uint32 kCloseView = 'ClVw'; 55 56 57 class CustomTermView : public TermView { 58 public: 59 CustomTermView(int32 rows, int32 columns, int32 argc, const char **argv, int32 historySize = 1000); 60 virtual void NotifyQuit(int32 reason); 61 virtual void SetTitle(const char *title); 62 }; 63 64 65 TermWindow::TermWindow(BRect frame, const char* title, Arguments *args) 66 : BWindow(frame, title, B_DOCUMENT_WINDOW, B_CURRENT_WORKSPACE|B_QUIT_ON_WINDOW_CLOSE), 67 fTabView(NULL), 68 fMenubar(NULL), 69 fFilemenu(NULL), 70 fEditmenu(NULL), 71 fEncodingmenu(NULL), 72 fHelpmenu(NULL), 73 fWindowSizeMenu(NULL), 74 fPrintSettings(NULL), 75 fPrefWindow(NULL), 76 fFindPanel(NULL), 77 fSavedFrame(0, 0, -1, -1), 78 fFindString(""), 79 fFindForwardMenuItem(NULL), 80 fFindBackwardMenuItem(NULL), 81 fFindSelection(false), 82 fForwardSearch(false), 83 fMatchCase(false), 84 fMatchWord(false) 85 { 86 _InitWindow(); 87 _AddTab(args); 88 } 89 90 91 TermWindow::~TermWindow() 92 { 93 if (fPrefWindow) 94 fPrefWindow->PostMessage(B_QUIT_REQUESTED); 95 96 if (fFindPanel && fFindPanel->Lock()) { 97 fFindPanel->Quit(); 98 fFindPanel = NULL; 99 } 100 101 PrefHandler::DeleteDefault(); 102 } 103 104 105 // #pragma mark - public methods 106 107 108 /** Initialize Window object. */ 109 void 110 TermWindow::_InitWindow() 111 { 112 // make menu bar 113 _SetupMenu(); 114 115 BRect textFrame = Bounds(); 116 textFrame.top = fMenubar->Bounds().bottom + 1.0; 117 118 fTabView = new SmartTabView(textFrame, "tab view"); 119 AddChild(fTabView); 120 } 121 122 123 void 124 TermWindow::MenusBeginning() 125 { 126 // Syncronize Encode Menu Pop-up menu and Preference. 127 BMenuItem *item = fEncodingmenu->FindItem(id2longname(_ActiveTermView()->Encoding())); 128 if (item != NULL) 129 item->SetMarked(true); 130 BWindow::MenusBeginning(); 131 } 132 133 134 void 135 TermWindow::_SetupMenu() 136 { 137 PrefHandler menuText; 138 139 LoadLocaleFile (&menuText); 140 141 // Menu bar object. 142 fMenubar = new BMenuBar(Bounds(), "mbar"); 143 144 // Make File Menu. 145 fFilemenu = new BMenu("Terminal"); 146 fFilemenu->AddItem(new BMenuItem("Switch Terminals", new BMessage(MENU_SWITCH_TERM),'G')); 147 fFilemenu->AddItem(new BMenuItem("New Terminal" B_UTF8_ELLIPSIS, new BMessage(MENU_NEW_TERM), 'N')); 148 fFilemenu->AddItem(new BMenuItem("New Tab", new BMessage(kNewTab), 'T')); 149 150 fFilemenu->AddSeparatorItem(); 151 fFilemenu->AddItem(new BMenuItem("Page Setup...", new BMessage(MENU_PAGE_SETUP))); 152 fFilemenu->AddItem(new BMenuItem("Print", new BMessage(MENU_PRINT),'P')); 153 fFilemenu->AddSeparatorItem(); 154 fFilemenu->AddItem(new BMenuItem("About Terminal" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED))); 155 fFilemenu->AddSeparatorItem(); 156 fFilemenu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q')); 157 fMenubar->AddItem(fFilemenu); 158 159 // Make Edit Menu. 160 fEditmenu = new BMenu ("Edit"); 161 fEditmenu->AddItem (new BMenuItem ("Copy", new BMessage (B_COPY),'C')); 162 fEditmenu->AddItem (new BMenuItem ("Paste", new BMessage (B_PASTE),'V')); 163 fEditmenu->AddSeparatorItem(); 164 fEditmenu->AddItem (new BMenuItem ("Select All", new BMessage (B_SELECT_ALL), 'A')); 165 fEditmenu->AddItem (new BMenuItem ("Clear All", new BMessage (MENU_CLEAR_ALL), 'L')); 166 fEditmenu->AddSeparatorItem(); 167 fEditmenu->AddItem (new BMenuItem ("Find" B_UTF8_ELLIPSIS, new BMessage (MENU_FIND_STRING),'F')); 168 fFindBackwardMenuItem = new BMenuItem ("Find Backward", new BMessage (MENU_FIND_BACKWARD), '['); 169 fEditmenu->AddItem(fFindBackwardMenuItem); 170 fFindBackwardMenuItem->SetEnabled(false); 171 fFindForwardMenuItem = new BMenuItem ("Find Forward", new BMessage (MENU_FIND_FORWARD), ']'); 172 fEditmenu->AddItem (fFindForwardMenuItem); 173 fFindForwardMenuItem->SetEnabled(false); 174 175 fMenubar->AddItem (fEditmenu); 176 177 // Make Help Menu. 178 fHelpmenu = new BMenu("Settings"); 179 fWindowSizeMenu = new BMenu("Window Size"); 180 fWindowSizeMenu->AddItem(new BMenuItem("80x24", new BMessage(EIGHTYTWENTYFOUR))); 181 fWindowSizeMenu->AddItem(new BMenuItem("80x25", new BMessage(EIGHTYTWENTYFIVE))); 182 fWindowSizeMenu->AddItem(new BMenuItem("80x40", new BMessage(EIGHTYFORTY))); 183 fWindowSizeMenu->AddItem(new BMenuItem("132x24", new BMessage(ONETHREETWOTWENTYFOUR))); 184 fWindowSizeMenu->AddItem(new BMenuItem("132x25", new BMessage(ONETHREETWOTWENTYFIVE))); 185 fWindowSizeMenu->AddItem(new BMenuItem("Fullscreen", new BMessage(FULLSCREEN), B_ENTER)); 186 187 fEncodingmenu = new BMenu("Font Encoding"); 188 fEncodingmenu->SetRadioMode(true); 189 MakeEncodingMenu(fEncodingmenu, true); 190 fHelpmenu->AddItem(fWindowSizeMenu); 191 fHelpmenu->AddItem(fEncodingmenu); 192 fHelpmenu->AddSeparatorItem(); 193 fHelpmenu->AddItem(new BMenuItem("Preferences" B_UTF8_ELLIPSIS, new BMessage(MENU_PREF_OPEN))); 194 fHelpmenu->AddSeparatorItem(); 195 fHelpmenu->AddItem(new BMenuItem("Save as default", new BMessage(SAVE_AS_DEFAULT))); 196 fMenubar->AddItem(fHelpmenu); 197 198 AddChild(fMenubar); 199 } 200 201 202 void 203 TermWindow::_GetPreferredFonts(BFont &fullFont, BFont &halfFont) 204 { 205 const char *family = PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY); 206 207 halfFont.SetFamilyAndStyle(family, NULL); 208 float size = PrefHandler::Default()->getFloat(PREF_HALF_FONT_SIZE); 209 if (size < 6.0f) 210 size = 6.0f; 211 halfFont.SetSize(size); 212 halfFont.SetSpacing(B_FIXED_SPACING); 213 214 family = PrefHandler::Default()->getString(PREF_FULL_FONT_FAMILY); 215 216 fullFont.SetFamilyAndStyle(family, NULL); 217 size = PrefHandler::Default()->getFloat(PREF_FULL_FONT_SIZE); 218 if (size < 6.0f) 219 size = 6.0f; 220 fullFont.SetSize(size); 221 fullFont.SetSpacing(B_FIXED_SPACING); 222 } 223 224 225 void 226 TermWindow::MessageReceived(BMessage *message) 227 { 228 int32 encodingId; 229 bool findresult; 230 231 switch (message->what) { 232 case B_COPY: 233 _ActiveTermView()->Copy(be_clipboard); 234 break; 235 236 case B_PASTE: 237 _ActiveTermView()->Paste(be_clipboard); 238 break; 239 240 case B_SELECT_ALL: 241 _ActiveTermView()->SelectAll(); 242 break; 243 244 case MENU_CLEAR_ALL: 245 _ActiveTermView()->Clear(); 246 break; 247 248 case MENU_SWITCH_TERM: 249 be_app->PostMessage(MENU_SWITCH_TERM); 250 break; 251 252 case kNewTab: 253 _AddTab(NULL); 254 break; 255 256 case kCloseView: 257 { 258 TermView* termView; 259 if (message->FindPointer("termView", (void**)&termView) == B_OK) { 260 int32 index = _IndexOfTermView(termView); 261 if (index >= 0) 262 _RemoveTab(index); 263 } 264 break; 265 } 266 267 case MENU_NEW_TERM: 268 { 269 app_info info; 270 be_app->GetAppInfo(&info); 271 272 // try launching two different ways to work around possible problems 273 if (be_roster->Launch(&info.ref)!=B_OK) 274 be_roster->Launch(TERM_SIGNATURE); 275 break; 276 } 277 case MENU_PREF_OPEN: 278 if (!fPrefWindow) 279 fPrefWindow = new PrefWindow(this); 280 else 281 fPrefWindow->Activate(); 282 break; 283 284 case MSG_PREF_CLOSED: 285 fPrefWindow = NULL; 286 break; 287 288 case MENU_FIND_STRING: 289 if (!fFindPanel) { 290 BRect r = Frame(); 291 r.left += 20; 292 r.top += 20; 293 r.right = r.left + 260; 294 r.bottom = r.top + 190; 295 fFindPanel = new FindWindow(r, this, fFindString, fFindSelection, fMatchWord, fMatchCase, fForwardSearch); 296 } 297 else 298 fFindPanel->Activate(); 299 break; 300 301 case MSG_FIND: 302 fFindPanel->PostMessage(B_QUIT_REQUESTED); 303 message->FindBool("findselection", &fFindSelection); 304 if (!fFindSelection) 305 message->FindString("findstring", &fFindString); 306 else 307 _ActiveTermView()->GetSelection(fFindString); 308 309 if (fFindString.Length() == 0) { 310 BAlert *alert = new BAlert("find failed", "No search string.", "Okay", NULL, 311 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 312 alert->Go(); 313 fFindBackwardMenuItem->SetEnabled(false); 314 fFindForwardMenuItem->SetEnabled(false); 315 break; 316 } 317 318 message->FindBool("forwardsearch", &fForwardSearch); 319 message->FindBool("matchcase", &fMatchCase); 320 message->FindBool("matchword", &fMatchWord); 321 findresult = _ActiveTermView()->Find(fFindString, fForwardSearch, fMatchCase, fMatchWord); 322 323 if (!findresult) { 324 BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, 325 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 326 alert->Go(); 327 fFindBackwardMenuItem->SetEnabled(false); 328 fFindForwardMenuItem->SetEnabled(false); 329 break; 330 } 331 332 // Enable the menu items Find Forward and Find Backward 333 fFindBackwardMenuItem->SetEnabled(true); 334 fFindForwardMenuItem->SetEnabled(true); 335 break; 336 337 case MENU_FIND_FORWARD: 338 findresult = _ActiveTermView()->Find(fFindString, true, fMatchCase, fMatchWord); 339 if (!findresult) { 340 BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, 341 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 342 alert->Go(); 343 } 344 break; 345 346 case MENU_FIND_BACKWARD: 347 findresult = _ActiveTermView()->Find(fFindString, false, fMatchCase, fMatchWord); 348 if (!findresult) { 349 BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, 350 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 351 alert->Go(); 352 } 353 break; 354 355 case MSG_FIND_CLOSED: 356 fFindPanel = NULL; 357 break; 358 359 case MENU_ENCODING: 360 if (message->FindInt32("op", &encodingId) == B_OK) 361 _ActiveTermView()->SetEncoding(encodingId); 362 break; 363 364 // Message from Preference panel. 365 case MSG_ROWS_CHANGED: 366 case MSG_COLS_CHANGED: 367 { 368 BRect rect = _ActiveTermView()->SetTermSize(PrefHandler::Default()->getInt32 (PREF_ROWS), 369 PrefHandler::Default()->getInt32 (PREF_COLS), 0); 370 371 ResizeTo (rect.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2, 372 rect.Height()+fMenubar->Bounds().Height() + kViewOffset *2); 373 374 BPath path; 375 if (PrefHandler::GetDefaultPath(path) == B_OK) 376 PrefHandler::Default()->SaveAsText(path.Path(), PREFFILE_MIMETYPE); 377 break; 378 } 379 case MSG_HALF_FONT_CHANGED: 380 case MSG_FULL_FONT_CHANGED: 381 case MSG_HALF_SIZE_CHANGED: 382 case MSG_FULL_SIZE_CHANGED: 383 { 384 BFont halfFont, fullFont; 385 _GetPreferredFonts(fullFont, halfFont); 386 _ActiveTermView()->SetTermFont (&halfFont, &fullFont); 387 BRect rect = _ActiveTermView()->SetTermSize(0, 0, 0); 388 389 int width, height; 390 _ActiveTermView()->GetFontSize(&width, &height); 391 392 float minimumHeight = 0; 393 if (fMenubar) 394 minimumHeight += fMenubar->Bounds().Height(); 395 if (fTabView && fTabView->CountTabs() > 1) 396 minimumHeight += fTabView->TabHeight(); 397 SetSizeLimits (MIN_COLS * width, MAX_COLS * width, 398 minimumHeight + MIN_ROWS * height, 399 minimumHeight + MAX_ROWS * height); 400 401 ResizeTo(rect.Width()+ B_V_SCROLL_BAR_WIDTH + kViewOffset * 2, 402 rect.Height()+fMenubar->Bounds().Height() + kViewOffset * 2); 403 404 _ActiveTermView()->Invalidate(); 405 break; 406 } 407 case EIGHTYTWENTYFOUR: 408 PrefHandler::Default()->setString(PREF_COLS, "80"); 409 PrefHandler::Default()->setString(PREF_ROWS, "24"); 410 PostMessage (MSG_COLS_CHANGED); 411 break; 412 413 case EIGHTYTWENTYFIVE: 414 PrefHandler::Default()->setString(PREF_COLS, "80"); 415 PrefHandler::Default()->setString(PREF_ROWS, "25"); 416 PostMessage (MSG_COLS_CHANGED); 417 break; 418 419 case EIGHTYFORTY: 420 PrefHandler::Default()->setString(PREF_COLS, "80"); 421 PrefHandler::Default()->setString(PREF_ROWS, "40"); 422 PostMessage (MSG_COLS_CHANGED); 423 break; 424 425 case ONETHREETWOTWENTYFOUR: 426 PrefHandler::Default()->setString(PREF_COLS, "132"); 427 PrefHandler::Default()->setString(PREF_ROWS, "24"); 428 PostMessage (MSG_COLS_CHANGED); 429 break; 430 431 case ONETHREETWOTWENTYFIVE: 432 PrefHandler::Default()->setString(PREF_COLS, "132"); 433 PrefHandler::Default()->setString(PREF_ROWS, "25"); 434 PostMessage (MSG_COLS_CHANGED); 435 break; 436 437 case FULLSCREEN: 438 if (!fSavedFrame.IsValid()) { // go fullscreen 439 float mbHeight = fMenubar->Bounds().Height() + 1; 440 fSavedFrame = Frame(); 441 BScreen screen(this); 442 _ActiveTermView()->ScrollBar()->Hide(); 443 fMenubar->Hide(); 444 fTabView->ResizeBy(0, mbHeight); 445 fTabView->MoveBy(0, -mbHeight); 446 fSavedLook = Look(); 447 // done before ResizeTo to work around a Dano bug (not erasing the decor) 448 SetLook(B_NO_BORDER_WINDOW_LOOK); 449 ResizeTo(screen.Frame().Width()+1, screen.Frame().Height()+1); 450 MoveTo(screen.Frame().left, screen.Frame().top); 451 } else { // exit fullscreen 452 float mbHeight = fMenubar->Bounds().Height() + 1; 453 fMenubar->Show(); 454 _ActiveTermView()->ScrollBar()->Show(); 455 ResizeTo(fSavedFrame.Width(), fSavedFrame.Height()); 456 MoveTo(fSavedFrame.left, fSavedFrame.top); 457 fTabView->ResizeBy(0, -mbHeight); 458 fTabView->MoveBy(0, mbHeight); 459 SetLook(fSavedLook); 460 fSavedFrame = BRect(0,0,-1,-1); 461 } 462 break; 463 464 case MSG_FONT_CHANGED: 465 PostMessage(MSG_HALF_FONT_CHANGED); 466 break; 467 468 case MSG_COLOR_CHANGED: 469 _SetTermColors(_ActiveTermView()); 470 _ActiveTermView()->Invalidate(); 471 break; 472 473 case SAVE_AS_DEFAULT: 474 { 475 BPath path; 476 if (PrefHandler::GetDefaultPath(path) == B_OK) 477 PrefHandler::Default()->SaveAsText(path.Path(), PREFFILE_MIMETYPE); 478 break; 479 } 480 case MENU_PAGE_SETUP: 481 _DoPageSetup(); 482 break; 483 484 case MENU_PRINT: 485 _DoPrint(); 486 break; 487 488 case MSG_CHECK_CHILDREN: 489 _CheckChildren(); 490 break; 491 492 case B_ABOUT_REQUESTED: 493 be_app->PostMessage(B_ABOUT_REQUESTED); 494 break; 495 496 default: 497 BWindow::MessageReceived(message); 498 break; 499 } 500 } 501 502 503 void 504 TermWindow::WindowActivated(bool activated) 505 { 506 BWindow::WindowActivated(activated); 507 } 508 509 510 bool 511 TermWindow::QuitRequested() 512 { 513 be_app->PostMessage(B_QUIT_REQUESTED); 514 return BWindow::QuitRequested(); 515 } 516 517 518 void 519 TermWindow::_SetTermColors(TermView *termView) 520 { 521 termView->SetTextColor(PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR), 522 PrefHandler::Default()->getRGB(PREF_TEXT_BACK_COLOR)); 523 524 termView->SetSelectColor(PrefHandler::Default()->getRGB(PREF_SELECT_FORE_COLOR), 525 PrefHandler::Default()->getRGB(PREF_SELECT_BACK_COLOR)); 526 527 termView->SetCursorColor(PrefHandler::Default()->getRGB(PREF_CURSOR_FORE_COLOR), 528 PrefHandler::Default()->getRGB(PREF_CURSOR_BACK_COLOR)); 529 } 530 531 532 status_t 533 TermWindow::_DoPageSetup() 534 { 535 BPrintJob job("PageSetup"); 536 537 // display the page configure panel 538 status_t status = job.ConfigPage(); 539 540 // save a pointer to the settings 541 fPrintSettings = job.Settings(); 542 543 return status; 544 } 545 546 547 void 548 TermWindow::_DoPrint() 549 { 550 if (!fPrintSettings || (_DoPageSetup() != B_OK)) { 551 (new BAlert("Cancel", "Print cancelled.", "OK"))->Go(); 552 return; 553 } 554 555 BPrintJob job("Print"); 556 job.SetSettings(new BMessage(*fPrintSettings)); 557 558 BRect pageRect = job.PrintableRect(); 559 BRect curPageRect = pageRect; 560 561 int pHeight = (int)pageRect.Height(); 562 int pWidth = (int)pageRect.Width(); 563 float w,h; 564 _ActiveTermView()->GetFrameSize(&w, &h); 565 int xPages = (int)ceil(w / pWidth); 566 int yPages = (int)ceil(h / pHeight); 567 568 job.BeginJob(); 569 570 // loop through and draw each page, and write to spool 571 for (int x = 0; x < xPages; x++) { 572 for (int y = 0; y < yPages; y++) { 573 curPageRect.OffsetTo(x * pWidth, y * pHeight); 574 job.DrawView(_ActiveTermView(), curPageRect, B_ORIGIN); 575 job.SpoolPage(); 576 577 if (!job.CanContinue()){ 578 // It is likely that the only way that the job was cancelled is 579 // because the user hit 'Cancel' in the page setup window, in which 580 // case, the user does *not* need to be told that it was cancelled. 581 // He/she will simply expect that it was done. 582 // (new BAlert("Cancel", "Print job cancelled", "OK"))->Go(); 583 return; 584 } 585 } 586 } 587 588 job.CommitJob(); 589 } 590 591 592 void 593 TermWindow::_AddTab(Arguments *args) 594 { 595 int argc = 0; 596 const char *const *argv = NULL; 597 if (args != NULL) 598 args->GetShellArguments(argc, argv); 599 600 try { 601 // Note: I don't pass the Arguments class directly to the termview, 602 // only to avoid adding it as a dependency: in other words, to keep 603 // the TermView class as agnostic as possible about the surrounding world. 604 CustomTermView *view = 605 new CustomTermView(PrefHandler::Default()->getInt32(PREF_ROWS), 606 PrefHandler::Default()->getInt32(PREF_COLS), 607 argc, (const char **)argv); 608 609 BScrollView *scrollView = new BScrollView("scrollView", view, B_FOLLOW_ALL, 610 B_WILL_DRAW|B_FRAME_EVENTS, false, true); 611 612 BTab *tab = new BTab; 613 // TODO: Use a better name. For example, do like MacOsX's Terminal 614 // and update the title using the last executed command ? 615 // Or like Gnome's Terminal and use the current path ? 616 fTabView->AddTab(scrollView, tab); 617 tab->SetLabel("Terminal"); 618 view->SetScrollBar(scrollView->ScrollBar(B_VERTICAL)); 619 620 // Resize the vertical scrollbar to take the window gripping handle into account 621 // TODO: shouldn't this be done in BScrollView itself ? At least BScrollBar does that. 622 scrollView->ScrollBar(B_VERTICAL)->ResizeBy(0, -13); 623 624 view->SetEncoding(longname2id(PrefHandler::Default()->getString(PREF_TEXT_ENCODING))); 625 626 BFont fullFont, halfFont; 627 _GetPreferredFonts(fullFont, halfFont); 628 view->SetTermFont(&halfFont, &fullFont); 629 630 _SetTermColors(view); 631 632 if (fTabView->CountTabs() >= 1) { 633 int width, height; 634 view->GetFontSize(&width, &height); 635 636 float minimumHeight = 0; 637 if (fMenubar) 638 minimumHeight += fMenubar->Bounds().Height(); 639 if (fTabView && fTabView->CountTabs() > 1) 640 minimumHeight += fTabView->TabHeight(); 641 SetSizeLimits (MIN_COLS * width, MAX_COLS * width, 642 minimumHeight + MIN_ROWS * height, 643 minimumHeight + MAX_ROWS * height); 644 } 645 646 // If it's the first time we're called, setup the window 647 if (fTabView->CountTabs() == 1) { 648 float fWidth, fHeight; 649 view->GetPreferredSize(&fWidth, &fHeight); 650 651 // Resize Window 652 ResizeTo(fWidth + B_V_SCROLL_BAR_WIDTH, fHeight + fMenubar->Bounds().Height()); 653 654 // TODO: If I don't do this, the view won't show up. 655 // Bug in BTabView or in my code ? 656 fTabView->Select(0); 657 } 658 } catch (...) { 659 // most probably out of memory. That's bad. 660 // TODO: Should cleanup, I guess 661 } 662 } 663 664 void 665 TermWindow::_RemoveTab(int32 index) 666 { 667 if (fTabView->CountTabs() > 1) 668 delete fTabView->RemoveTab(fTabView->Selection()); 669 else 670 PostMessage(B_QUIT_REQUESTED); 671 } 672 673 674 TermView * 675 TermWindow::_ActiveTermView() 676 { 677 // TODO: BAD HACK: 678 // We should probably use the observer api to tell 679 // the various "tabs" when settings are changed. Fix this. 680 return (TermView *)((BScrollView *)fTabView->ViewForTab(fTabView->Selection()))->Target(); 681 } 682 683 684 int32 685 TermWindow::_IndexOfTermView(TermView* termView) const 686 { 687 if (!termView) 688 return -1; 689 690 // find the view 691 int32 count = fTabView->CountTabs(); 692 for (int32 i = count - 1; i >= 0; i--) { 693 BScrollView* scrollView 694 = dynamic_cast<BScrollView*>(fTabView->ViewForTab(i)); 695 if (!scrollView) 696 continue; 697 698 if (termView == scrollView->Target()) 699 return i; 700 } 701 702 return -1; 703 } 704 705 706 void 707 TermWindow::_CheckChildren() 708 { 709 // There seems to be no separate list of sessions, so we have to iterate 710 // through the tabs. 711 int32 count = fTabView->CountTabs(); 712 for (int32 i = count - 1; i >= 0; i--) { 713 // get the term view 714 BScrollView* scrollView 715 = dynamic_cast<BScrollView*>(fTabView->ViewForTab(i)); 716 if (!scrollView) 717 continue; 718 TermView* termView = dynamic_cast<TermView*>(scrollView->Target()); 719 if (!termView) 720 continue; 721 722 termView->CheckShellGone(); 723 } 724 } 725 726 727 728 // CustomTermView 729 CustomTermView::CustomTermView(int32 rows, int32 columns, int32 argc, const char **argv, int32 historySize) 730 : 731 TermView(rows, columns, argc, argv, historySize) 732 { 733 } 734 735 736 void 737 CustomTermView::NotifyQuit(int32 reason) 738 { 739 if (Window()) { 740 BMessage message(kCloseView); 741 message.AddPointer("termView", this); 742 message.AddInt32("reason", reason); 743 Window()->PostMessage(&message); 744 } 745 } 746 747 748 void 749 CustomTermView::SetTitle(const char *title) 750 { 751 //Window()->SetTitle(title); 752 } 753 754