2 * Copyright 2007-2015, Haiku, Inc. All rights reserved.
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.
7 * Distributed under the terms of the MIT license.
10 * Kian Duffy, myob@users.sourceforge.net
11 * Daniel Furrer, assimil8or@users.sourceforge.net
12 * John Scipione, jscipione@gmail.com
13 * Siarzhuk Zharski, zharik@gmx.li
17 #include "TermWindow.h"
26 #include <Application.h>
28 #include <CharacterSet.h>
29 #include <CharacterSetRoster.h>
30 #include <Clipboard.h>
33 #include <FindDirectory.h>
34 #include <LayoutBuilder.h>
35 #include <LayoutUtils.h>
41 #include <PopUpMenu.h>
46 #include <ScrollBar.h>
47 #include <ScrollView.h>
51 #include <AutoLocker.h>
53 #include "ActiveProcessInfo.h"
54 #include "Arguments.h"
55 #include "AppearPrefView.h"
56 #include "FindWindow.h"
58 #include "PrefWindow.h"
59 #include "PrefHandler.h"
60 #include "SetTitleDialog.h"
61 #include "ShellParameters.h"
62 #include "TermConst.h"
63 #include "TermScrollView.h"
64 #include "TitlePlaceholderMapper.h"
67 const static int32 kTermViewOffset
= 3;
69 const static int32 kMinimumFontSize
= 8;
70 const static int32 kMaximumFontSize
= 36;
73 static const uint32 kNewTab
= 'NTab';
74 static const uint32 kCloseView
= 'ClVw';
75 static const uint32 kCloseOtherViews
= 'CloV';
76 static const uint32 kIncreaseFontSize
= 'InFs';
77 static const uint32 kDecreaseFontSize
= 'DcFs';
78 static const uint32 kSetActiveTab
= 'STab';
79 static const uint32 kUpdateTitles
= 'UPti';
80 static const uint32 kEditTabTitle
= 'ETti';
81 static const uint32 kEditWindowTitle
= 'EWti';
82 static const uint32 kTabTitleChanged
= 'TTch';
83 static const uint32 kWindowTitleChanged
= 'WTch';
84 static const uint32 kUpdateSwitchTerminalsMenuItem
= 'Ustm';
86 using namespace BPrivate
; // BCharacterSet stuff
88 #undef B_TRANSLATION_CONTEXT
89 #define B_TRANSLATION_CONTEXT "Terminal TermWindow"
92 #define UTF8_ENTER "\xe2\x86\xb5"
95 // #pragma mark - TermViewContainerView
98 class TermViewContainerView
: public BView
{
100 TermViewContainerView(TermView
* termView
)
102 BView(BRect(), "term view container", B_FOLLOW_ALL
, 0),
105 termView
->MoveTo(kTermViewOffset
, kTermViewOffset
);
106 BRect
frame(termView
->Frame());
107 ResizeTo(frame
.right
+ kTermViewOffset
, frame
.bottom
+ kTermViewOffset
);
111 TermView
* GetTermView() const { return fTermView
; }
113 virtual void GetPreferredSize(float* _width
, float* _height
)
116 fTermView
->GetPreferredSize(&width
, &height
);
117 *_width
= width
+ 2 * kTermViewOffset
;
118 *_height
= height
+ 2 * kTermViewOffset
;
126 // #pragma mark - SessionID
129 TermWindow::SessionID::SessionID(int32 id
)
136 TermWindow::SessionID::SessionID(const BMessage
& message
, const char* field
)
138 if (message
.FindInt32(field
, &fID
) != B_OK
)
144 TermWindow::SessionID::AddToMessage(BMessage
& message
, const char* field
) const
146 return message
.AddInt32(field
, fID
);
150 // #pragma mark - Session
153 struct TermWindow::Session
{
157 TermViewContainerView
* containerView
;
159 Session(SessionID id
, int32 index
, TermViewContainerView
* containerView
)
163 containerView(containerView
)
165 title
.title
= B_TRANSLATE("Shell ");
166 title
.title
<< index
;
167 title
.patternUserDefined
= false;
172 // #pragma mark - TermWindow
175 TermWindow::TermWindow(const BString
& title
, Arguments
* args
)
177 BWindow(BRect(0, 0, 0, 0), title
, B_DOCUMENT_WINDOW
,
178 B_CURRENT_WORKSPACE
| B_QUIT_ON_WINDOW_CLOSE
),
179 fTitleUpdateRunner(this, BMessage(kUpdateTitles
), 1000000),
183 fSwitchTerminalsMenuItem(NULL
),
185 fPrintSettings(NULL
),
188 fSavedFrame(0, 0, -1, -1),
189 fSetWindowTitleDialog(NULL
),
190 fSetTabTitleDialog(NULL
),
192 fFindNextMenuItem(NULL
),
193 fFindPreviousMenuItem(NULL
),
194 fFindSelection(false),
195 fForwardSearch(false),
200 // register this terminal
201 fTerminalRoster
.Register(Team(), this);
202 fTerminalRoster
.SetListener(this);
203 int32 id
= fTerminalRoster
.ID();
205 // apply the title settings
206 fTitle
.pattern
= title
;
207 if (fTitle
.pattern
.Length() == 0) {
208 fTitle
.pattern
= B_TRANSLATE_SYSTEM_NAME("Terminal");
211 fTitle
.pattern
<< " " << id
+ 1;
213 fTitle
.patternUserDefined
= false;
215 fTitle
.patternUserDefined
= true;
217 fTitle
.title
= fTitle
.pattern
;
218 fTitle
.pattern
= title
;
220 _TitleSettingsChanged();
222 // get the saved window position and workspaces
225 if (_LoadWindowPosition(&frame
, &workspaces
) == B_OK
) {
226 // make sure the window is still on screen
227 // (for example if there was a resolution change)
228 BRect screenFrame
= BScreen(this).Frame();
229 if (frame
.Width() <= screenFrame
.Width()
230 && frame
.Height() <= screenFrame
.Height())
231 ResizeTo(frame
.Width(), frame
.Height());
233 MoveTo(frame
.LeftTop());
234 MoveOnScreen(B_MOVE_IF_PARTIALLY_OFFSCREEN
);
236 SetWorkspaces(workspaces
);
238 // use computed defaults
240 int column
= id
% 16;
241 int x
= (column
* 16) + (row
* 64) + 50;
242 int y
= (column
* 16) + 50;
247 // init the GUI and add a tab
251 // Announce our window as no longer minimized. That's not true, since it's
252 // still hidden at this point, but it will be shown very soon.
253 fTerminalRoster
.SetWindowInfo(false, Workspaces());
257 TermWindow::~TermWindow()
259 fTerminalRoster
.Unregister();
261 _FinishTitleDialog();
264 fPrefWindow
->PostMessage(B_QUIT_REQUESTED
);
266 if (fFindPanel
&& fFindPanel
->Lock()) {
271 PrefHandler::DeleteDefault();
273 for (int32 i
= 0; Session
* session
= _SessionAt(i
); i
++)
279 TermWindow::SessionChanged()
281 _UpdateSessionTitle(fTabView
->Selection());
286 TermWindow::_InitWindow()
291 // shortcuts to switch tabs
292 for (int32 i
= 0; i
< 9; i
++) {
293 BMessage
* message
= new BMessage(kSetActiveTab
);
294 message
->AddInt32("index", i
);
295 AddShortcut('1' + i
, B_COMMAND_KEY
, message
);
298 AddShortcut(B_LEFT_ARROW
, B_COMMAND_KEY
| B_SHIFT_KEY
,
299 new BMessage(MSG_MOVE_TAB_LEFT
));
300 AddShortcut(B_RIGHT_ARROW
, B_COMMAND_KEY
| B_SHIFT_KEY
,
301 new BMessage(MSG_MOVE_TAB_RIGHT
));
303 BRect textFrame
= Bounds();
304 textFrame
.top
= fMenuBar
->Bounds().bottom
+ 1.0;
306 fTabView
= new SmartTabView(textFrame
, "tab view", B_WIDTH_FROM_LABEL
);
307 fTabView
->SetListener(this);
310 // Make the scroll view one pixel wider than the tab view container view, so
311 // the scroll bar will look good.
312 fTabView
->SetInsets(0, 0, -1, 0);
317 TermWindow::_CanClose(int32 index
)
319 bool warnOnExit
= PrefHandler::Default()->getBool(PREF_WARN_ON_EXIT
);
324 uint32 busyProcessCount
= 0;
325 BString busyProcessNames
;
326 // all names, separated by "\n\t"
330 ActiveProcessInfo info
;
331 TermView
* termView
= _TermViewAt(index
);
332 if (termView
->GetShellInfo(shellInfo
)
333 && termView
->GetActiveProcessInfo(info
)
334 && (info
.ID() != shellInfo
.ProcessID()
335 || !shellInfo
.IsDefaultShell())) {
337 busyProcessNames
= info
.Name();
340 for (int32 i
= 0; i
< fSessions
.CountItems(); i
++) {
342 ActiveProcessInfo info
;
343 TermView
* termView
= _TermViewAt(i
);
344 if (termView
->GetShellInfo(shellInfo
)
345 && termView
->GetActiveProcessInfo(info
)
346 && (info
.ID() != shellInfo
.ProcessID()
347 || !shellInfo
.IsDefaultShell())) {
348 if (++busyProcessCount
> 1)
349 busyProcessNames
<< "\n\t";
350 busyProcessNames
<< info
.Name();
355 if (busyProcessCount
== 0)
358 BString alertMessage
;
359 if (busyProcessCount
== 1) {
360 // Only one pending process. Select the alert text depending on whether
361 // the terminal will be closed.
362 alertMessage
= index
== -1 || fSessions
.CountItems() == 1
363 ? B_TRANSLATE("The process \"%1\" is still running.\n"
364 "If you close the Terminal, the process will be killed.")
365 : B_TRANSLATE("The process \"%1\" is still running.\n"
366 "If you close the tab, the process will be killed.");
368 // multiple pending processes
369 alertMessage
= B_TRANSLATE(
370 "The following processes are still running:\n\n"
372 "If you close the Terminal, the processes will be killed.");
375 alertMessage
.ReplaceFirst("%1", busyProcessNames
);
377 BAlert
* alert
= new BAlert(B_TRANSLATE("Really close?"),
378 alertMessage
, B_TRANSLATE("Close"), B_TRANSLATE("Cancel"), NULL
,
379 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
380 alert
->SetShortcut(1, B_ESCAPE
);
381 return alert
->Go() == 0;
386 TermWindow::QuitRequested()
388 _FinishTitleDialog();
393 _SaveWindowPosition();
395 return BWindow::QuitRequested();
400 TermWindow::MenusBeginning()
402 TermView
* view
= _ActiveTermView();
404 // Syncronize Encode Menu Pop-up menu and Preference.
405 const BCharacterSet
* charset
406 = BCharacterSetRoster::GetCharacterSetByConversionID(view
->Encoding());
407 if (charset
!= NULL
) {
408 BString
name(charset
->GetPrintName());
409 const char* mime
= charset
->GetMIMEName();
411 name
<< " (" << mime
<< ")";
413 BMenuItem
* item
= fEncodingMenu
->FindItem(name
);
415 item
->SetMarked(true);
419 view
->GetTermFont(&font
);
421 float size
= font
.Size();
423 fDecreaseFontSizeMenuItem
->SetEnabled(size
> kMinimumFontSize
);
424 fIncreaseFontSizeMenuItem
->SetEnabled(size
< kMaximumFontSize
);
426 BWindow::MenusBeginning();
431 TermWindow::MakeEncodingMenu(BMenu
* menu
)
433 BCharacterSetRoster roster
;
434 BCharacterSet charset
;
435 while (roster
.GetNextCharacterSet(&charset
) == B_OK
) {
436 int encoding
= M_UTF8
;
437 const char* mime
= charset
.GetMIMEName();
438 if (mime
== NULL
|| strcasecmp(mime
, "UTF-8") != 0)
439 encoding
= charset
.GetConversionID();
441 // filter out currently (???) not supported USC-2 and UTF-16
442 if (encoding
== B_UTF16_CONVERSION
|| encoding
== B_UNICODE_CONVERSION
)
445 BString
name(charset
.GetPrintName());
447 name
<< " (" << mime
<< ")";
449 BMessage
*message
= new BMessage(MENU_ENCODING
);
450 if (message
!= NULL
) {
451 message
->AddInt32("op", (int32
)encoding
);
452 menu
->AddItem(new BMenuItem(name
, message
));
456 menu
->SetRadioMode(true);
461 TermWindow::_SetupMenu()
463 fFontSizeMenu
= _MakeFontSizeMenu(MSG_HALF_SIZE_CHANGED
,
464 PrefHandler::Default()->getInt32(PREF_HALF_FONT_SIZE
));
465 fIncreaseFontSizeMenuItem
= new BMenuItem(B_TRANSLATE("Increase"),
466 new BMessage(kIncreaseFontSize
), '+', B_COMMAND_KEY
);
467 fDecreaseFontSizeMenuItem
= new BMenuItem(B_TRANSLATE("Decrease"),
468 new BMessage(kDecreaseFontSize
), '-', B_COMMAND_KEY
);
469 fFontSizeMenu
->AddSeparatorItem();
470 fFontSizeMenu
->AddItem(fIncreaseFontSizeMenuItem
);
471 fFontSizeMenu
->AddItem(fDecreaseFontSizeMenuItem
);
473 BMenu
* windowSize
= new(std::nothrow
) BMenu(B_TRANSLATE("Window size"));
474 if (windowSize
!= NULL
) {
475 MakeWindowSizeMenu(windowSize
);
476 windowSize
->AddSeparatorItem();
477 windowSize
->AddItem(new BMenuItem(B_TRANSLATE("Full screen"),
478 new BMessage(FULLSCREEN
), B_ENTER
));
481 fEncodingMenu
= new(std::nothrow
) BMenu(B_TRANSLATE("Text encoding"));
482 if (fEncodingMenu
!= NULL
)
483 MakeEncodingMenu(fEncodingMenu
);
485 BLayoutBuilder::Menu
<>(fMenuBar
= new BMenuBar(Bounds(), "mbar"))
487 .AddMenu(B_TRANSLATE_COMMENT("Terminal", "The title for the main window"
488 " menubar entry related to terminal sessions"))
489 .AddItem(B_TRANSLATE("Switch Terminals"), MENU_SWITCH_TERM
, B_TAB
)
490 .GetItem(fSwitchTerminalsMenuItem
)
491 .AddItem(B_TRANSLATE("New Terminal"), MENU_NEW_TERM
, 'N')
492 .AddItem(B_TRANSLATE("New tab"), kNewTab
, 'T')
494 .AddItem(B_TRANSLATE("Page setup" B_UTF8_ELLIPSIS
), MENU_PAGE_SETUP
)
495 .AddItem(B_TRANSLATE("Print"), MENU_PRINT
, 'P')
497 .AddItem(B_TRANSLATE("Close window"), B_QUIT_REQUESTED
, 'W',
499 .AddItem(B_TRANSLATE("Close active tab"), kCloseView
, 'W')
500 .AddItem(B_TRANSLATE("Quit"), B_QUIT_REQUESTED
, 'Q')
504 .AddMenu(B_TRANSLATE("Edit"))
505 .AddItem(B_TRANSLATE("Copy"), B_COPY
, 'C')
506 .AddItem(B_TRANSLATE("Paste"), B_PASTE
, 'V')
508 .AddItem(B_TRANSLATE("Select all"), B_SELECT_ALL
, 'A')
509 .AddItem(B_TRANSLATE("Clear all"), MENU_CLEAR_ALL
, 'L')
511 .AddItem(B_TRANSLATE("Find" B_UTF8_ELLIPSIS
), MENU_FIND_STRING
, 'F')
512 .AddItem(B_TRANSLATE("Find previous"), MENU_FIND_PREVIOUS
, 'G',
514 .GetItem(fFindPreviousMenuItem
)
516 .AddItem(B_TRANSLATE("Find next"), MENU_FIND_NEXT
, 'G')
517 .GetItem(fFindNextMenuItem
)
522 .AddMenu(B_TRANSLATE("Settings"))
523 .AddItem(B_TRANSLATE("Window title" B_UTF8_ELLIPSIS
),
526 .AddItem(fEncodingMenu
)
527 .AddItem(fFontSizeMenu
)
528 .AddItem(B_TRANSLATE("Save as default"), MSG_SAVE_AS_DEFAULT
)
530 .AddItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS
), MENU_PREF_OPEN
)
535 _UpdateSwitchTerminalsMenuItem();
537 #ifdef USE_DEBUG_SNAPSHOTS
538 AddShortcut('S', B_COMMAND_KEY
| B_CONTROL_KEY
,
539 new BMessage(SHORTCUT_DEBUG_SNAPSHOTS
));
540 AddShortcut('C', B_COMMAND_KEY
| B_CONTROL_KEY
,
541 new BMessage(SHORTCUT_DEBUG_CAPTURE
));
547 TermWindow::_GetWindowPositionFile(BFile
* file
, uint32 openMode
)
550 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true);
554 status
= path
.Append("Terminal");
558 status
= path
.Append("Windows");
562 return file
->SetTo(path
.Path(), openMode
);
567 TermWindow::_LoadWindowPosition(BRect
* frame
, uint32
* workspaces
)
573 status
= _GetWindowPositionFile(&file
, B_READ_ONLY
);
577 status
= position
.Unflatten(&file
);
584 int32 id
= fTerminalRoster
.ID();
585 status
= position
.FindRect("rect", id
, frame
);
590 status
= position
.FindInt32("workspaces", id
, &_workspaces
);
593 if (modifiers() & B_SHIFT_KEY
)
594 *workspaces
= _workspaces
;
596 *workspaces
= B_CURRENT_WORKSPACE
;
603 TermWindow::_SaveWindowPosition()
606 BMessage originalSettings
;
608 // Read the settings file if it exists and is a valid BMessage.
609 status_t status
= _GetWindowPositionFile(&file
, B_READ_ONLY
);
610 if (status
== B_OK
) {
611 status
= originalSettings
.Unflatten(&file
);
615 status
= originalSettings
.MakeEmpty();
621 // Replace the settings
622 int32 id
= fTerminalRoster
.ID();
624 if (originalSettings
.ReplaceRect("rect", id
, rect
) != B_OK
)
625 originalSettings
.AddRect("rect", rect
);
627 int32 workspaces
= Workspaces();
628 if (originalSettings
.ReplaceInt32("workspaces", id
, workspaces
) != B_OK
)
629 originalSettings
.AddInt32("workspaces", workspaces
);
631 // Resave the whole thing
632 status
= _GetWindowPositionFile (&file
,
633 B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
637 return originalSettings
.Flatten(&file
);
642 TermWindow::_GetPreferredFont(BFont
& font
)
644 // Default to be_fixed_font
645 font
= be_fixed_font
;
648 = PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY
);
650 = PrefHandler::Default()->getString(PREF_HALF_FONT_STYLE
);
651 const char* size
= PrefHandler::Default()->getString(PREF_HALF_FONT_SIZE
);
653 font
.SetFamilyAndStyle(family
, style
);
654 font
.SetSize(atoi(size
));
656 // mark the font size menu item
657 for (int32 i
= 0; i
< fFontSizeMenu
->CountItems(); i
++) {
658 BMenuItem
* item
= fFontSizeMenu
->ItemAt(i
);
662 item
->SetMarked(false);
663 if (strcmp(item
->Label(), size
) == 0)
664 item
->SetMarked(true);
670 TermWindow::MessageReceived(BMessage
*message
)
675 switch (message
->what
) {
677 _ActiveTermView()->Copy(be_clipboard
);
681 _ActiveTermView()->Paste(be_clipboard
);
684 #ifdef USE_DEBUG_SNAPSHOTS
685 case SHORTCUT_DEBUG_SNAPSHOTS
:
686 _ActiveTermView()->MakeDebugSnapshots();
689 case SHORTCUT_DEBUG_CAPTURE
:
690 _ActiveTermView()->StartStopDebugCapture();
695 _ActiveTermView()->SelectAll();
699 _ActiveTermView()->Clear();
702 case MENU_SWITCH_TERM
:
708 // Set our current working directory to that of the active tab, so
709 // that the new terminal and its shell inherit it.
710 // Note: That's a bit lame. We should rather fork() and change the
711 // CWD in the child, but since ATM there aren't any side effects of
712 // changing our CWD, we save ourselves the trouble.
713 ActiveProcessInfo activeProcessInfo
;
714 if (_ActiveTermView()->GetActiveProcessInfo(activeProcessInfo
))
715 chdir(activeProcessInfo
.CurrentDirectory());
718 be_app
->GetAppInfo(&info
);
720 // try launching two different ways to work around possible problems
721 if (be_roster
->Launch(&info
.ref
) != B_OK
)
722 be_roster
->Launch(TERM_SIGNATURE
);
728 fPrefWindow
= new PrefWindow(this);
730 fPrefWindow
->Activate();
733 case MSG_PREF_CLOSED
:
737 case MSG_WINDOW_TITLE_SETTING_CHANGED
:
738 case MSG_TAB_TITLE_SETTING_CHANGED
:
739 _TitleSettingsChanged();
742 case MENU_FIND_STRING
:
743 if (fFindPanel
== NULL
) {
744 fFindPanel
= new FindWindow(this, fFindString
, fFindSelection
,
745 fMatchWord
, fMatchCase
, fForwardSearch
);
747 fFindPanel
->CenterIn(Frame());
748 _MoveWindowInScreen(fFindPanel
);
751 fFindPanel
->Activate();
756 fFindPanel
->PostMessage(B_QUIT_REQUESTED
);
757 message
->FindBool("findselection", &fFindSelection
);
759 message
->FindString("findstring", &fFindString
);
761 _ActiveTermView()->GetSelection(fFindString
);
763 if (fFindString
.Length() == 0) {
764 const char* errorMsg
= !fFindSelection
765 ? B_TRANSLATE("No search string was entered.")
766 : B_TRANSLATE("Nothing is selected.");
767 BAlert
* alert
= new BAlert(B_TRANSLATE("Find failed"),
768 errorMsg
, B_TRANSLATE("OK"), NULL
, NULL
,
769 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
770 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
773 fFindPreviousMenuItem
->SetEnabled(false);
774 fFindNextMenuItem
->SetEnabled(false);
778 message
->FindBool("forwardsearch", &fForwardSearch
);
779 message
->FindBool("matchcase", &fMatchCase
);
780 message
->FindBool("matchword", &fMatchWord
);
781 findresult
= _ActiveTermView()->Find(fFindString
, fForwardSearch
,
782 fMatchCase
, fMatchWord
);
785 BAlert
* alert
= new BAlert(B_TRANSLATE("Find failed"),
786 B_TRANSLATE("Text not found."),
787 B_TRANSLATE("OK"), NULL
, NULL
,
788 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
789 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
791 fFindPreviousMenuItem
->SetEnabled(false);
792 fFindNextMenuItem
->SetEnabled(false);
796 // Enable the menu items Find Next and Find Previous
797 fFindPreviousMenuItem
->SetEnabled(true);
798 fFindNextMenuItem
->SetEnabled(true);
803 case MENU_FIND_PREVIOUS
:
804 findresult
= _ActiveTermView()->Find(fFindString
,
805 (message
->what
== MENU_FIND_NEXT
) == fForwardSearch
,
806 fMatchCase
, fMatchWord
);
808 BAlert
* alert
= new BAlert(B_TRANSLATE("Find failed"),
809 B_TRANSLATE("Not found."), B_TRANSLATE("OK"),
810 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
811 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
816 case MSG_FIND_CLOSED
:
821 if (message
->FindInt32("op", &encodingId
) == B_OK
)
822 _ActiveTermView()->SetEncoding(encodingId
);
825 case MSG_COLS_CHANGED
:
828 if (message
->FindInt32("columns", &columns
) != B_OK
829 || message
->FindInt32("rows", &rows
) != B_OK
) {
833 for (int32 i
= 0; i
< fTabView
->CountTabs(); i
++) {
834 TermView
* view
= _TermViewAt(i
);
835 view
->SetTermSize(rows
, columns
, true);
841 case MSG_HALF_FONT_CHANGED
:
842 case MSG_FULL_FONT_CHANGED
:
843 case MSG_ALLOW_BOLD_CHANGED
:
846 _GetPreferredFont(font
);
847 for (int32 i
= 0; i
< fTabView
->CountTabs(); i
++) {
848 TermView
* view
= _TermViewAt(i
);
849 view
->SetTermFont(&font
);
855 case MSG_HALF_SIZE_CHANGED
:
856 case MSG_FULL_SIZE_CHANGED
:
858 const char* size
= NULL
;
859 if (message
->FindString("font_size", &size
) != B_OK
)
862 // mark the font size menu item
863 for (int32 i
= 0; i
< fFontSizeMenu
->CountItems(); i
++) {
864 BMenuItem
* item
= fFontSizeMenu
->ItemAt(i
);
868 item
->SetMarked(false);
869 if (strcmp(item
->Label(), size
) == 0)
870 item
->SetMarked(true);
874 _ActiveTermView()->GetTermFont(&font
);
875 font
.SetSize(atoi(size
));
876 PrefHandler::Default()->setInt32(PREF_HALF_FONT_SIZE
,
878 for (int32 i
= 0; i
< fTabView
->CountTabs(); i
++) {
879 TermView
* view
= _TermViewAt(i
);
880 _TermViewAt(i
)->SetTermFont(&font
);
887 if (!fSavedFrame
.IsValid()) { // go fullscreen
888 _ActiveTermView()->DisableResizeView();
889 float mbHeight
= fMenuBar
->Bounds().Height() + 1;
890 fSavedFrame
= Frame();
891 BScreen
screen(this);
893 for (int32 i
= fTabView
->CountTabs() - 1; i
>= 0 ; i
--)
894 _TermViewAt(i
)->ScrollBar()->ResizeBy(0,
895 (B_H_SCROLL_BAR_HEIGHT
- 1));
898 fTabView
->ResizeBy(0, mbHeight
);
899 fTabView
->MoveBy(0, -mbHeight
);
901 // done before ResizeTo to work around a Dano bug
902 // (not erasing the decor)
903 SetLook(B_NO_BORDER_WINDOW_LOOK
);
904 ResizeTo(screen
.Frame().Width() + 1, screen
.Frame().Height() + 1);
905 MoveTo(screen
.Frame().left
, screen
.Frame().top
);
906 SetFlags(Flags() | (B_NOT_RESIZABLE
| B_NOT_MOVABLE
));
908 } else { // exit fullscreen
909 _ActiveTermView()->DisableResizeView();
910 float mbHeight
= fMenuBar
->Bounds().Height() + 1;
913 for (int32 i
= fTabView
->CountTabs() - 1; i
>= 0 ; i
--)
914 _TermViewAt(i
)->ScrollBar()->ResizeBy(0,
915 -(B_H_SCROLL_BAR_HEIGHT
- 1));
917 ResizeTo(fSavedFrame
.Width(), fSavedFrame
.Height());
918 MoveTo(fSavedFrame
.left
, fSavedFrame
.top
);
919 fTabView
->ResizeBy(0, -mbHeight
);
920 fTabView
->MoveBy(0, mbHeight
);
922 fSavedFrame
= BRect(0, 0, -1, -1);
923 SetFlags(Flags() & ~(B_NOT_RESIZABLE
| B_NOT_MOVABLE
));
928 case MSG_FONT_CHANGED
:
929 PostMessage(MSG_HALF_FONT_CHANGED
);
932 case MSG_COLOR_CHANGED
:
933 case MSG_COLOR_SCHEME_CHANGED
:
935 _SetTermColors(_ActiveTermViewContainerView());
936 _ActiveTermViewContainerView()->Invalidate();
937 _ActiveTermView()->Invalidate();
940 case MSG_SAVE_AS_DEFAULT
:
943 if (PrefHandler::GetDefaultPath(path
) == B_OK
) {
944 PrefHandler::Default()->SaveAsText(path
.Path(),
950 case MENU_PAGE_SETUP
:
958 case MSG_CHECK_CHILDREN
:
962 case MSG_MOVE_TAB_LEFT
:
963 case MSG_MOVE_TAB_RIGHT
:
964 _NavigateTab(_IndexOfTermView(_ActiveTermView()),
965 message
->what
== MSG_MOVE_TAB_LEFT
? -1 : 1, true);
968 case kTabTitleChanged
:
970 // tab title changed message from SetTitleDialog
971 SessionID
sessionID(*message
, "session");
972 if (Session
* session
= _SessionForID(sessionID
)) {
974 if (message
->FindString("title", &title
) == B_OK
) {
975 session
->title
.pattern
= title
;
976 session
->title
.patternUserDefined
= true;
978 session
->title
.pattern
.Truncate(0);
979 session
->title
.patternUserDefined
= false;
981 _UpdateSessionTitle(_IndexOfSession(session
));
986 case kWindowTitleChanged
:
988 // window title changed message from SetTitleDialog
990 if (message
->FindString("title", &title
) == B_OK
) {
991 fTitle
.pattern
= title
;
992 fTitle
.patternUserDefined
= true;
995 = PrefHandler::Default()->getString(PREF_WINDOW_TITLE
);
996 fTitle
.patternUserDefined
= false;
999 _UpdateSessionTitle(fTabView
->Selection());
1000 // updates the window title as a side effect
1008 if (message
->FindInt32("index", &index
) == B_OK
1009 && index
>= 0 && index
< fSessions
.CountItems()) {
1010 fTabView
->Select(index
);
1022 SessionID
sessionID(*message
, "session");
1023 if (sessionID
.IsValid()) {
1024 if (Session
* session
= _SessionForID(sessionID
))
1025 index
= _IndexOfSession(session
);
1027 index
= _IndexOfTermView(_ActiveTermView());
1035 case kCloseOtherViews
:
1037 Session
* session
= _SessionForID(SessionID(*message
, "session"));
1038 if (session
== NULL
)
1041 int32 count
= fSessions
.CountItems();
1042 for (int32 i
= count
- 1; i
>= 0; i
--) {
1043 if (_SessionAt(i
) != session
)
1050 case kIncreaseFontSize
:
1051 case kDecreaseFontSize
:
1054 _ActiveTermView()->GetTermFont(&font
);
1055 float size
= font
.Size();
1057 if (message
->what
== kIncreaseFontSize
) {
1067 else if (size
<= 24)
1073 // constrain the font size
1074 if (size
< kMinimumFontSize
)
1075 size
= kMinimumFontSize
;
1076 if (size
> kMaximumFontSize
)
1077 size
= kMaximumFontSize
;
1079 // mark the font size menu item
1080 for (int32 i
= 0; i
< fFontSizeMenu
->CountItems(); i
++) {
1081 BMenuItem
* item
= fFontSizeMenu
->ItemAt(i
);
1085 item
->SetMarked(false);
1086 if (atoi(item
->Label()) == size
)
1087 item
->SetMarked(true);
1091 PrefHandler::Default()->setInt32(PREF_HALF_FONT_SIZE
, (int32
)size
);
1092 for (int32 i
= 0; i
< fTabView
->CountTabs(); i
++) {
1093 TermView
* view
= _TermViewAt(i
);
1094 _TermViewAt(i
)->SetTermFont(&font
);
1106 SessionID
sessionID(*message
, "session");
1107 if (Session
* session
= _SessionForID(sessionID
))
1108 _OpenSetTabTitleDialog(_IndexOfSession(session
));
1112 case kEditWindowTitle
:
1113 _OpenSetWindowTitleDialog();
1116 case kUpdateSwitchTerminalsMenuItem
:
1117 _UpdateSwitchTerminalsMenuItem();
1121 BWindow::MessageReceived(message
);
1128 TermWindow::WindowActivated(bool activated
)
1131 _UpdateSwitchTerminalsMenuItem();
1136 TermWindow::_SetTermColors(TermViewContainerView
* containerView
)
1138 PrefHandler
* handler
= PrefHandler::Default();
1139 rgb_color background
= handler
->getRGB(PREF_TEXT_BACK_COLOR
);
1141 containerView
->SetViewColor(background
);
1143 TermView
*termView
= containerView
->GetTermView();
1144 termView
->SetTextColor(handler
->getRGB(PREF_TEXT_FORE_COLOR
), background
);
1146 termView
->SetCursorColor(handler
->getRGB(PREF_CURSOR_FORE_COLOR
),
1147 handler
->getRGB(PREF_CURSOR_BACK_COLOR
));
1148 termView
->SetSelectColor(handler
->getRGB(PREF_SELECT_FORE_COLOR
),
1149 handler
->getRGB(PREF_SELECT_BACK_COLOR
));
1154 TermWindow::_DoPageSetup()
1156 BPrintJob
job("PageSetup");
1158 // display the page configure panel
1159 status_t status
= job
.ConfigPage();
1161 // save a pointer to the settings
1162 fPrintSettings
= job
.Settings();
1169 TermWindow::_DoPrint()
1171 BPrintJob
job("Print");
1173 job
.SetSettings(new BMessage(*fPrintSettings
));
1175 if (job
.ConfigJob() != B_OK
)
1178 BRect pageRect
= job
.PrintableRect();
1179 BRect curPageRect
= pageRect
;
1181 int pHeight
= (int)pageRect
.Height();
1182 int pWidth
= (int)pageRect
.Width();
1184 _ActiveTermView()->GetFrameSize(&w
, &h
);
1185 int xPages
= (int)ceil(w
/ pWidth
);
1186 int yPages
= (int)ceil(h
/ pHeight
);
1190 // loop through and draw each page, and write to spool
1191 for (int x
= 0; x
< xPages
; x
++) {
1192 for (int y
= 0; y
< yPages
; y
++) {
1193 curPageRect
.OffsetTo(x
* pWidth
, y
* pHeight
);
1194 job
.DrawView(_ActiveTermView(), curPageRect
, B_ORIGIN
);
1197 if (!job
.CanContinue()) {
1198 // It is likely that the only way that the job was cancelled is
1199 // because the user hit 'Cancel' in the page setup window, in
1200 // which case, the user does *not* need to be told that it was
1202 // He/she will simply expect that it was done.
1213 TermWindow::_NewTab()
1215 ActiveProcessInfo info
;
1216 if (_ActiveTermView()->GetActiveProcessInfo(info
))
1217 _AddTab(NULL
, info
.CurrentDirectory());
1224 TermWindow::_AddTab(Arguments
* args
, const BString
& currentDirectory
)
1227 const char* const* argv
= NULL
;
1229 args
->GetShellArguments(argc
, argv
);
1230 ShellParameters
shellParameters(argc
, argv
, currentDirectory
);
1233 TermView
* view
= new TermView(
1234 PrefHandler::Default()->getInt32(PREF_ROWS
),
1235 PrefHandler::Default()->getInt32(PREF_COLS
),
1237 PrefHandler::Default()->getInt32(PREF_HISTORY_SIZE
));
1238 view
->SetListener(this);
1240 TermViewContainerView
* containerView
= new TermViewContainerView(view
);
1241 BScrollView
* scrollView
= new TermScrollView("scrollView",
1242 containerView
, view
, fSessions
.IsEmpty());
1244 scrollView
->ScrollBar(B_VERTICAL
)
1245 ->ResizeBy(0, -(B_H_SCROLL_BAR_HEIGHT
- 1));
1247 if (fSessions
.IsEmpty())
1248 fTabView
->SetScrollView(scrollView
);
1250 Session
* session
= new Session(_NewSessionID(), _NewSessionIndex(),
1252 fSessions
.AddItem(session
);
1255 _GetPreferredFont(font
);
1256 view
->SetTermFont(&font
);
1259 view
->GetFontSize(&width
, &height
);
1261 float minimumHeight
= -1;
1262 if (fMenuBar
!= NULL
)
1263 minimumHeight
+= fMenuBar
->Bounds().Height() + 1;
1265 if (fTabView
!= NULL
&& fTabView
->CountTabs() > 0)
1266 minimumHeight
+= fTabView
->TabHeight() + 1;
1268 SetSizeLimits(MIN_COLS
* width
- 1, MAX_COLS
* width
- 1,
1269 minimumHeight
+ MIN_ROWS
* height
- 1,
1270 minimumHeight
+ MAX_ROWS
* height
- 1);
1271 // TODO: The size limit computation is apparently broken, since
1272 // the terminal can be resized smaller than MIN_ROWS/MIN_COLS!
1274 // If it's the first time we're called, setup the window
1275 if (fTabView
!= NULL
&& fTabView
->CountTabs() == 0) {
1276 float viewWidth
, viewHeight
;
1277 containerView
->GetPreferredSize(&viewWidth
, &viewHeight
);
1280 ResizeTo(viewWidth
+ B_V_SCROLL_BAR_WIDTH
,
1281 viewHeight
+ fMenuBar
->Bounds().Height() + 1);
1282 // NOTE: Width is one pixel too small, since the scroll view
1283 // is one pixel wider than its parent.
1286 BTab
* tab
= new BTab
;
1287 fTabView
->AddTab(scrollView
, tab
);
1288 view
->SetScrollBar(scrollView
->ScrollBar(B_VERTICAL
));
1289 view
->SetMouseClipboard(gMouseClipboard
);
1291 const BCharacterSet
* charset
1292 = BCharacterSetRoster::FindCharacterSetByName(
1293 PrefHandler::Default()->getString(PREF_TEXT_ENCODING
));
1294 if (charset
!= NULL
)
1295 view
->SetEncoding(charset
->GetConversionID());
1297 _SetTermColors(containerView
);
1299 int32 tabIndex
= fTabView
->CountTabs() - 1;
1300 fTabView
->Select(tabIndex
);
1302 _UpdateSessionTitle(tabIndex
);
1304 // most probably out of memory. That's bad.
1305 // TODO: Should cleanup, I guess
1307 // Quit the application if we don't have a shell already
1308 if (fTabView
->CountTabs() == 0) {
1309 fprintf(stderr
, "Terminal couldn't open a shell\n");
1310 PostMessage(B_QUIT_REQUESTED
);
1317 TermWindow::_RemoveTab(int32 index
)
1319 _FinishTitleDialog();
1320 // always close to avoid confusion
1322 if (fSessions
.CountItems() > 1) {
1323 if (!_CanClose(index
))
1325 if (Session
* session
= (Session
*)fSessions
.RemoveItem(index
)) {
1326 if (fSessions
.CountItems() == 1) {
1327 fTabView
->SetScrollView(dynamic_cast<BScrollView
*>(
1328 _SessionAt(0)->containerView
->Parent()));
1332 delete fTabView
->RemoveTab(index
);
1335 PostMessage(B_QUIT_REQUESTED
);
1340 TermWindow::_NavigateTab(int32 index
, int32 direction
, bool move
)
1342 int32 count
= fSessions
.CountItems();
1343 if (count
<= 1 || index
< 0 || index
>= count
)
1346 int32 newIndex
= (index
+ direction
+ count
) % count
;
1347 if (newIndex
== index
)
1351 // move the given tab to the new index
1352 Session
* session
= (Session
*)fSessions
.RemoveItem(index
);
1353 fSessions
.AddItem(session
, newIndex
);
1354 fTabView
->MoveTab(index
, newIndex
);
1357 // activate the respective tab
1358 fTabView
->Select(newIndex
);
1362 TermViewContainerView
*
1363 TermWindow::_ActiveTermViewContainerView() const
1365 return _TermViewContainerViewAt(fTabView
->Selection());
1369 TermViewContainerView
*
1370 TermWindow::_TermViewContainerViewAt(int32 index
) const
1372 if (Session
* session
= _SessionAt(index
))
1373 return session
->containerView
;
1379 TermWindow::_ActiveTermView() const
1381 return _ActiveTermViewContainerView()->GetTermView();
1386 TermWindow::_TermViewAt(int32 index
) const
1388 TermViewContainerView
* view
= _TermViewContainerViewAt(index
);
1389 return view
!= NULL
? view
->GetTermView() : NULL
;
1394 TermWindow::_IndexOfTermView(TermView
* termView
) const
1400 int32 count
= fTabView
->CountTabs();
1401 for (int32 i
= count
- 1; i
>= 0; i
--) {
1402 if (termView
== _TermViewAt(i
))
1410 TermWindow::Session
*
1411 TermWindow::_SessionAt(int32 index
) const
1413 return (Session
*)fSessions
.ItemAt(index
);
1417 TermWindow::Session
*
1418 TermWindow::_SessionForID(const SessionID
& sessionID
) const
1420 for (int32 i
= 0; Session
* session
= _SessionAt(i
); i
++) {
1421 if (session
->id
== sessionID
)
1430 TermWindow::_IndexOfSession(Session
* session
) const
1432 return fSessions
.IndexOf(session
);
1437 TermWindow::_CheckChildren()
1439 int32 count
= fSessions
.CountItems();
1440 for (int32 i
= count
- 1; i
>= 0; i
--) {
1441 Session
* session
= _SessionAt(i
);
1442 if (session
->containerView
->GetTermView()->CheckShellGone())
1443 NotifyTermViewQuit(session
->containerView
->GetTermView(), 0);
1449 TermWindow::Zoom(BPoint leftTop
, float width
, float height
)
1451 _ActiveTermView()->DisableResizeView();
1452 BWindow::Zoom(leftTop
, width
, height
);
1457 TermWindow::FrameResized(float newWidth
, float newHeight
)
1459 BWindow::FrameResized(newWidth
, newHeight
);
1461 TermView
* view
= _ActiveTermView();
1462 PrefHandler::Default()->setInt32(PREF_COLS
, view
->Columns());
1463 PrefHandler::Default()->setInt32(PREF_ROWS
, view
->Rows());
1468 TermWindow::WorkspacesChanged(uint32 oldWorkspaces
, uint32 newWorkspaces
)
1470 fTerminalRoster
.SetWindowInfo(IsMinimized(), Workspaces());
1475 TermWindow::WorkspaceActivated(int32 workspace
, bool state
)
1477 fTerminalRoster
.SetWindowInfo(IsMinimized(), Workspaces());
1482 TermWindow::Minimize(bool minimize
)
1484 BWindow::Minimize(minimize
);
1485 fTerminalRoster
.SetWindowInfo(IsMinimized(), Workspaces());
1490 TermWindow::TabSelected(SmartTabView
* tabView
, int32 index
)
1497 TermWindow::TabDoubleClicked(SmartTabView
* tabView
, BPoint point
, int32 index
)
1500 // clicked on a tab -- open the title dialog
1501 _OpenSetTabTitleDialog(index
);
1503 // not clicked on a tab -- create a new one
1510 TermWindow::TabMiddleClicked(SmartTabView
* tabView
, BPoint point
, int32 index
)
1518 TermWindow::TabRightClicked(SmartTabView
* tabView
, BPoint point
, int32 index
)
1523 TermView
* termView
= _TermViewAt(index
);
1524 if (termView
== NULL
)
1527 BMessage
* closeMessage
= new BMessage(kCloseView
);
1528 _SessionAt(index
)->id
.AddToMessage(*closeMessage
, "session");
1530 BMessage
* closeOthersMessage
= new BMessage(kCloseOtherViews
);
1531 _SessionAt(index
)->id
.AddToMessage(*closeOthersMessage
, "session");
1533 BMessage
* editTitleMessage
= new BMessage(kEditTabTitle
);
1534 _SessionAt(index
)->id
.AddToMessage(*editTitleMessage
, "session");
1536 BPopUpMenu
* popUpMenu
= new BPopUpMenu("tab menu");
1537 BLayoutBuilder::Menu
<>(popUpMenu
)
1538 .AddItem(B_TRANSLATE("Close tab"), closeMessage
)
1539 .AddItem(B_TRANSLATE("Close other tabs"), closeOthersMessage
)
1541 .AddItem(B_TRANSLATE("Edit tab title" B_UTF8_ELLIPSIS
),
1545 popUpMenu
->SetAsyncAutoDestruct(true);
1546 popUpMenu
->SetTargetForItems(BMessenger(this));
1548 BPoint screenWhere
= tabView
->ConvertToScreen(point
);
1549 BRect
mouseRect(screenWhere
, screenWhere
);
1550 mouseRect
.InsetBy(-4.0, -4.0);
1551 popUpMenu
->Go(screenWhere
, true, true, mouseRect
, true);
1556 TermWindow::NotifyTermViewQuit(TermView
* view
, int32 reason
)
1558 // Since the notification can come from the view, we send a message to
1559 // ourselves to avoid deleting the caller synchronously.
1560 if (Session
* session
= _SessionAt(_IndexOfTermView(view
))) {
1561 BMessage
message(kCloseView
);
1562 session
->id
.AddToMessage(message
, "session");
1563 message
.AddInt32("reason", reason
);
1564 PostMessage(&message
);
1570 TermWindow::SetTermViewTitle(TermView
* view
, const char* title
)
1572 int32 index
= _IndexOfTermView(view
);
1573 if (Session
* session
= _SessionAt(index
)) {
1574 session
->title
.pattern
= title
;
1575 session
->title
.patternUserDefined
= true;
1576 _UpdateSessionTitle(index
);
1582 TermWindow::TitleChanged(SetTitleDialog
* dialog
, const BString
& title
,
1583 bool titleUserDefined
)
1585 if (dialog
== fSetTabTitleDialog
) {
1587 BMessage
message(kTabTitleChanged
);
1588 fSetTabTitleSession
.AddToMessage(message
, "session");
1589 if (titleUserDefined
)
1590 message
.AddString("title", title
);
1592 PostMessage(&message
);
1593 } else if (dialog
== fSetWindowTitleDialog
) {
1595 BMessage
message(kWindowTitleChanged
);
1596 if (titleUserDefined
)
1597 message
.AddString("title", title
);
1599 PostMessage(&message
);
1605 TermWindow::SetTitleDialogDone(SetTitleDialog
* dialog
)
1607 if (dialog
== fSetTabTitleDialog
) {
1608 fSetTabTitleSession
= SessionID();
1609 fSetTabTitleDialog
= NULL
;
1610 // assuming this is atomic
1616 TermWindow::TerminalInfosUpdated(TerminalRoster
* roster
)
1618 PostMessage(kUpdateSwitchTerminalsMenuItem
);
1623 TermWindow::PreviousTermView(TermView
* view
)
1625 _NavigateTab(_IndexOfTermView(view
), -1, false);
1630 TermWindow::NextTermView(TermView
* view
)
1632 _NavigateTab(_IndexOfTermView(view
), 1, false);
1637 TermWindow::_ResizeView(TermView
*view
)
1639 int fontWidth
, fontHeight
;
1640 view
->GetFontSize(&fontWidth
, &fontHeight
);
1642 float minimumHeight
= -1;
1643 if (fMenuBar
!= NULL
)
1644 minimumHeight
+= fMenuBar
->Bounds().Height() + 1;
1646 if (fTabView
!= NULL
&& fTabView
->CountTabs() > 1)
1647 minimumHeight
+= fTabView
->TabHeight() + 1;
1649 SetSizeLimits(MIN_COLS
* fontWidth
- 1, MAX_COLS
* fontWidth
- 1,
1650 minimumHeight
+ MIN_ROWS
* fontHeight
- 1,
1651 minimumHeight
+ MAX_ROWS
* fontHeight
- 1);
1655 view
->Parent()->GetPreferredSize(&width
, &height
);
1657 width
+= B_V_SCROLL_BAR_WIDTH
;
1658 // NOTE: Width is one pixel too small, since the scroll view
1659 // is one pixel wider than its parent.
1660 if (fMenuBar
!= NULL
)
1661 height
+= fMenuBar
->Bounds().Height() + 1;
1662 if (fTabView
!= NULL
&& fTabView
->CountTabs() > 1)
1663 height
+= fTabView
->TabHeight() + 1;
1665 ResizeTo(width
, height
);
1671 TermWindow::MakeWindowSizeMenu(BMenu
* menu
)
1673 const int32 windowSizes
[4][2] = {
1680 const int32 sizeNum
= sizeof(windowSizes
) / sizeof(windowSizes
[0]);
1681 for (int32 i
= 0; i
< sizeNum
; i
++) {
1683 int32 columns
= windowSizes
[i
][0];
1684 int32 rows
= windowSizes
[i
][1];
1685 snprintf(label
, sizeof(label
), "%" B_PRId32
"x%" B_PRId32
, columns
,
1687 BMessage
* message
= new BMessage(MSG_COLS_CHANGED
);
1688 message
->AddInt32("columns", columns
);
1689 message
->AddInt32("rows", rows
);
1690 menu
->AddItem(new BMenuItem(label
, message
));
1696 TermWindow::_MakeFontSizeMenu(uint32 command
, uint8 defaultSize
)
1698 BMenu
* menu
= new (std::nothrow
) BMenu(B_TRANSLATE("Font size"));
1703 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 0
1708 for (uint32 i
= 0; sizes
[i
]; i
++) {
1711 BMessage
* message
= new BMessage(command
);
1712 message
->AddString("font_size", string
);
1713 BMenuItem
* item
= new BMenuItem(string
.String(), message
);
1714 menu
->AddItem(item
);
1715 if (sizes
[i
] == defaultSize
) {
1716 item
->SetMarked(true);
1722 for (uint32 i
= 0; sizes
[i
]; i
++) {
1723 if (sizes
[i
] > defaultSize
) {
1725 string
<< defaultSize
;
1726 BMessage
* message
= new BMessage(command
);
1727 message
->AddString("font_size", string
);
1728 BMenuItem
* item
= new BMenuItem(string
.String(), message
);
1729 item
->SetMarked(true);
1730 menu
->AddItem(item
, i
);
1741 TermWindow::_UpdateSwitchTerminalsMenuItem()
1743 fSwitchTerminalsMenuItem
->SetEnabled(_FindSwitchTerminalTarget() >= 0);
1748 TermWindow::_TitleSettingsChanged()
1750 if (!fTitle
.patternUserDefined
)
1751 fTitle
.pattern
= PrefHandler::Default()->getString(PREF_WINDOW_TITLE
);
1753 fSessionTitlePattern
= PrefHandler::Default()->getString(PREF_TAB_TITLE
);
1760 TermWindow::_UpdateTitles()
1762 int32 sessionCount
= fSessions
.CountItems();
1763 for (int32 i
= 0; i
< sessionCount
; i
++)
1764 _UpdateSessionTitle(i
);
1769 TermWindow::_UpdateSessionTitle(int32 index
)
1771 Session
* session
= _SessionAt(index
);
1772 if (session
== NULL
)
1775 // get the shell and active process infos
1776 ShellInfo shellInfo
;
1777 ActiveProcessInfo activeProcessInfo
;
1778 TermView
* termView
= _TermViewAt(index
);
1779 if (!termView
->GetShellInfo(shellInfo
)
1780 || !termView
->GetActiveProcessInfo(activeProcessInfo
)) {
1784 // evaluate the session title pattern
1785 BString sessionTitlePattern
= session
->title
.patternUserDefined
1786 ? session
->title
.pattern
: fSessionTitlePattern
;
1787 TabTitlePlaceholderMapper
tabMapper(shellInfo
, activeProcessInfo
,
1789 const BString
& sessionTitle
= PatternEvaluator::Evaluate(
1790 sessionTitlePattern
, tabMapper
);
1792 // set the tab title
1793 if (sessionTitle
!= session
->title
.title
) {
1794 session
->title
.title
= sessionTitle
;
1795 fTabView
->TabAt(index
)->SetLabel(session
->title
.title
);
1796 fTabView
->Invalidate();
1797 // Invalidate the complete tab view, since other tabs might change
1801 // If this is the active tab, also recompute the window title.
1802 if (index
!= fTabView
->Selection())
1805 // evaluate the window title pattern
1806 WindowTitlePlaceholderMapper
windowMapper(shellInfo
, activeProcessInfo
,
1807 fTerminalRoster
.CountTerminals() > 1
1808 ? fTerminalRoster
.ID() + 1 : 0, sessionTitle
);
1809 const BString
& windowTitle
= PatternEvaluator::Evaluate(fTitle
.pattern
,
1812 // set the window title
1813 if (windowTitle
!= fTitle
.title
) {
1814 fTitle
.title
= windowTitle
;
1815 SetTitle(fTitle
.title
);
1818 // If fullscreen, add a tooltip with the title and a keyboard shortcut hint
1820 BString
toolTip(fTitle
.title
);
1822 toolTip
+= B_TRANSLATE("Full screen");
1823 toolTip
+= " (ALT " UTF8_ENTER
"))";
1824 termView
->SetToolTip(toolTip
.String());
1826 termView
->SetToolTip((const char *)NULL
);
1831 TermWindow::_OpenSetTabTitleDialog(int32 index
)
1833 // If a dialog is active, finish it.
1834 _FinishTitleDialog();
1836 BString toolTip
= BString(B_TRANSLATE(
1837 "The pattern specifying the current tab title. The following "
1839 "can be used:\n")) << kTooTipSetTabTitlePlaceholders
;
1840 fSetTabTitleDialog
= new SetTitleDialog(
1841 B_TRANSLATE("Set tab title"), B_TRANSLATE("Tab title:"),
1844 Session
* session
= _SessionAt(index
);
1845 bool userDefined
= session
->title
.patternUserDefined
;
1846 const BString
& title
= userDefined
1847 ? session
->title
.pattern
: fSessionTitlePattern
;
1848 fSetTabTitleSession
= session
->id
;
1850 // place the dialog window directly under the tab, but keep it on screen
1851 BPoint location
= fTabView
->ConvertToScreen(
1852 fTabView
->TabFrame(index
).LeftBottom() + BPoint(0, 1));
1853 fSetTabTitleDialog
->MoveTo(location
);
1854 _MoveWindowInScreen(fSetTabTitleDialog
);
1856 fSetTabTitleDialog
->Go(title
, userDefined
, this);
1861 TermWindow::_OpenSetWindowTitleDialog()
1863 // If a dialog is active, finish it.
1864 _FinishTitleDialog();
1866 BString toolTip
= BString(B_TRANSLATE(
1867 "The pattern specifying the window title. The following placeholders\n"
1868 "can be used:\n")) << kTooTipSetTabTitlePlaceholders
;
1869 fSetWindowTitleDialog
= new SetTitleDialog(B_TRANSLATE("Set window title"),
1870 B_TRANSLATE("Window title:"), toolTip
);
1872 // center the dialog in the window frame, but keep it on screen
1873 fSetWindowTitleDialog
->CenterIn(Frame());
1874 _MoveWindowInScreen(fSetWindowTitleDialog
);
1876 fSetWindowTitleDialog
->Go(fTitle
.pattern
, fTitle
.patternUserDefined
, this);
1881 TermWindow::_FinishTitleDialog()
1883 SetTitleDialog
* oldDialog
= fSetTabTitleDialog
;
1884 if (oldDialog
!= NULL
&& oldDialog
->Lock()) {
1885 // might have been unset in the meantime, so recheck
1886 if (fSetTabTitleDialog
== oldDialog
) {
1887 oldDialog
->Finish();
1888 // this also unsets the variables
1890 oldDialog
->Unlock();
1894 oldDialog
= fSetWindowTitleDialog
;
1895 if (oldDialog
!= NULL
&& oldDialog
->Lock()) {
1896 // might have been unset in the meantime, so recheck
1897 if (fSetWindowTitleDialog
== oldDialog
) {
1898 oldDialog
->Finish();
1899 // this also unsets the variable
1901 oldDialog
->Unlock();
1908 TermWindow::_SwitchTerminal()
1910 team_id teamID
= _FindSwitchTerminalTarget();
1914 BMessenger
app(TERM_SIGNATURE
, teamID
);
1915 app
.SendMessage(MSG_ACTIVATE_TERM
);
1920 TermWindow::_FindSwitchTerminalTarget()
1922 AutoLocker
<TerminalRoster
> rosterLocker(fTerminalRoster
);
1924 team_id myTeamID
= Team();
1926 int32 numTerms
= fTerminalRoster
.CountTerminals();
1930 // Find our position in the Terminal teams.
1933 for (i
= 0; i
< numTerms
; i
++) {
1934 if (myTeamID
== fTerminalRoster
.TerminalAt(i
)->team
)
1938 if (i
== numTerms
) {
1939 // we didn't find ourselves -- that shouldn't happen
1943 uint32 currentWorkspace
= 1L << current_workspace();
1949 const TerminalRoster::Info
* info
= fTerminalRoster
.TerminalAt(i
);
1950 if (info
->team
== myTeamID
) {
1951 // That's ourselves again. We've run through the complete list.
1955 if (!info
->minimized
&& (info
->workspaces
& currentWorkspace
) != 0)
1961 TermWindow::SessionID
1962 TermWindow::_NewSessionID()
1964 return fNextSessionID
++;
1969 TermWindow::_NewSessionIndex()
1971 for (int32 id
= 1; ; id
++) {
1975 Session
* session
= _SessionAt(i
); i
++) {
1976 if (id
== session
->index
) {
1989 TermWindow::_MoveWindowInScreen(BWindow
* window
)
1991 BRect frame
= window
->Frame();
1992 BSize
screenSize(BScreen(window
).Frame().Size());
1993 window
->MoveTo(BLayoutUtils::MoveIntoFrame(frame
, screenSize
).LeftTop());