Implemented support for dynamic tab and window titles:
* Added settings for tab and window titles. Both are strings with optional placeholders for tab/terminal index, currently active process name and current directory. * Added a generic utility class PatternEvaluator that allows to expand this kind of pattern strings and callback classes [Tab,Window]TitlePlaceholderMapper that provide the specific expansion for the tab and window title placeholders. * TermWindow: - Separated the notions of session (== tab) and window titles. The tty clients no longer set the window, but the session title. - Use the patterns instead of the hard-coded window/tab titles. - Recompute all titles once a second, so changes of running programs are reflected. * The default patterns for tab and window titles are "%1d: %p" (last CWD component and name of the running process) and "Terminal %i: %t" (Terminal ID and active tab title). Unfortunately the space on the tabs is seriously limited, so that the tab title is virtually always truncated. Ideas welcome. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39473 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e492be3195
commit
02ee32bb0d
@ -106,17 +106,48 @@ AppearancePrefView::AppearancePrefView(const char* name,
|
||||
colorsPopUp);
|
||||
fColorField->SetEnabled(false);
|
||||
|
||||
fTabTitle = new BTextControl("tabTitle", B_TRANSLATE("Tab title:"), "",
|
||||
NULL);
|
||||
fTabTitle->SetModificationMessage(
|
||||
new BMessage(MSG_TAB_TITLE_SETTING_CHANGED));
|
||||
fTabTitle->SetToolTip(B_TRANSLATE(
|
||||
"The pattern specifying the tab titles. The following placeholders\n"
|
||||
"can be used:\n"
|
||||
"\t%d\t-\tThe current working directory of the active process.\n"
|
||||
"\t\t\tOptionally the maximum number of path components can be\n"
|
||||
"\t\t\tspecified. E.g. '%2d' for at most two components.\n"
|
||||
"\t%i\t-\tThe index of the tab.\n"
|
||||
"\t%p\t-\tThe name of the active process.\n"
|
||||
"\t%%\t-\tThe character '%'."));
|
||||
|
||||
fWindowTitle = new BTextControl("windowTitle", B_TRANSLATE("Window title:"),
|
||||
"", NULL);
|
||||
fWindowTitle->SetModificationMessage(
|
||||
new BMessage(MSG_WINDOW_TITLE_SETTING_CHANGED));
|
||||
fWindowTitle->SetToolTip(B_TRANSLATE(
|
||||
"The pattern specifying the window titles. The following placeholders\n"
|
||||
"can be used:\n"
|
||||
"\t%d\t-\tThe current working directory of the active process in the.\n"
|
||||
"\t\t\tcurrent tab. Optionally the maximum number of path components\n"
|
||||
"\t\t\tcan be specified. E.g. '%2d' for at most two components.\n"
|
||||
"\t%i\t-\tThe index of the window.\n"
|
||||
"\t%p\t-\tThe name of the active process in the current tab.\n"
|
||||
"\t%t\t-\tThe title of the current tab.\n"
|
||||
"\t%%\t-\tThe character '%'."));
|
||||
|
||||
BLayoutBuilder::Group<>(this)
|
||||
.SetInsets(5, 5, 5, 5)
|
||||
.AddGrid(5, 5)
|
||||
.Add(fFont->CreateLabelLayoutItem(), 0, 0)
|
||||
.Add(fFont->CreateMenuBarLayoutItem(), 1, 0)
|
||||
.Add(fFontSize->CreateLabelLayoutItem(), 0, 1)
|
||||
.Add(fFontSize->CreateMenuBarLayoutItem(), 1, 1)
|
||||
.Add(fColorSchemaField->CreateLabelLayoutItem(), 0, 2)
|
||||
.Add(fColorSchemaField->CreateMenuBarLayoutItem(), 1, 2)
|
||||
.Add(fColorField->CreateLabelLayoutItem(), 0, 3)
|
||||
.Add(fColorField->CreateMenuBarLayoutItem(), 1, 3)
|
||||
.AddTextControl(fTabTitle, 0, 0, B_ALIGN_RIGHT)
|
||||
.AddTextControl(fWindowTitle, 0, 1, B_ALIGN_RIGHT)
|
||||
.Add(fFont->CreateLabelLayoutItem(), 0, 2)
|
||||
.Add(fFont->CreateMenuBarLayoutItem(), 1, 2)
|
||||
.Add(fFontSize->CreateLabelLayoutItem(), 0, 3)
|
||||
.Add(fFontSize->CreateMenuBarLayoutItem(), 1, 3)
|
||||
.Add(fColorSchemaField->CreateLabelLayoutItem(), 0, 4)
|
||||
.Add(fColorSchemaField->CreateMenuBarLayoutItem(), 1, 4)
|
||||
.Add(fColorField->CreateLabelLayoutItem(), 0, 5)
|
||||
.Add(fColorField->CreateMenuBarLayoutItem(), 1, 5)
|
||||
.End()
|
||||
.AddGlue()
|
||||
.Add(fColorControl = new BColorControl(BPoint(10, 10),
|
||||
@ -128,6 +159,9 @@ AppearancePrefView::AppearancePrefView(const char* name,
|
||||
fColorField->SetAlignment(B_ALIGN_RIGHT);
|
||||
fColorSchemaField->SetAlignment(B_ALIGN_RIGHT);
|
||||
|
||||
fTabTitle->SetText(PrefHandler::Default()->getString(PREF_TAB_TITLE));
|
||||
fWindowTitle->SetText(PrefHandler::Default()->getString(PREF_WINDOW_TITLE));
|
||||
|
||||
fColorControl->SetEnabled(false);
|
||||
fColorControl->SetValue(
|
||||
PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR));
|
||||
@ -158,6 +192,9 @@ AppearancePrefView::GetPreferredSize(float* _width, float* _height)
|
||||
void
|
||||
AppearancePrefView::Revert()
|
||||
{
|
||||
fTabTitle->SetText(PrefHandler::Default()->getString(PREF_TAB_TITLE));
|
||||
fWindowTitle->SetText(PrefHandler::Default()->getString(PREF_WINDOW_TITLE));
|
||||
|
||||
fWarnOnExit->SetValue(PrefHandler::Default()->getBool(
|
||||
PREF_WARN_ON_EXIT));
|
||||
|
||||
@ -175,6 +212,8 @@ AppearancePrefView::Revert()
|
||||
void
|
||||
AppearancePrefView::AttachedToWindow()
|
||||
{
|
||||
fTabTitle->SetTarget(this);
|
||||
fWindowTitle->SetTarget(this);
|
||||
fWarnOnExit->SetTarget(this);
|
||||
|
||||
fFontSize->Menu()->SetTargetForItems(this);
|
||||
@ -271,6 +310,30 @@ AppearancePrefView::MessageReceived(BMessage* msg)
|
||||
modified = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_TAB_TITLE_SETTING_CHANGED:
|
||||
{
|
||||
BString oldValue(PrefHandler::Default()->getString(PREF_TAB_TITLE));
|
||||
if (oldValue != fTabTitle->Text()) {
|
||||
PrefHandler::Default()->setString(PREF_TAB_TITLE,
|
||||
fTabTitle->Text());
|
||||
modified = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_WINDOW_TITLE_SETTING_CHANGED:
|
||||
{
|
||||
BString oldValue(PrefHandler::Default()->getString(
|
||||
PREF_WINDOW_TITLE));
|
||||
if (oldValue != fWindowTitle->Text()) {
|
||||
PrefHandler::Default()->setString(PREF_WINDOW_TITLE,
|
||||
fWindowTitle->Text());
|
||||
modified = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
return;
|
||||
|
@ -13,28 +13,31 @@
|
||||
#include <String.h>
|
||||
|
||||
|
||||
const ulong MSG_HALF_FONT_CHANGED = 'mchf';
|
||||
const ulong MSG_HALF_SIZE_CHANGED = 'mchs';
|
||||
const ulong MSG_FULL_FONT_CHANGED = 'mcff';
|
||||
const ulong MSG_FULL_SIZE_CHANGED = 'mcfs';
|
||||
const ulong MSG_COLOR_FIELD_CHANGED = 'mccf';
|
||||
const ulong MSG_COLOR_CHANGED = 'mcbc';
|
||||
const ulong MSG_COLOR_SCHEMA_CHANGED = 'mccs';
|
||||
static const uint32 MSG_HALF_FONT_CHANGED = 'mchf';
|
||||
static const uint32 MSG_HALF_SIZE_CHANGED = 'mchs';
|
||||
static const uint32 MSG_FULL_FONT_CHANGED = 'mcff';
|
||||
static const uint32 MSG_FULL_SIZE_CHANGED = 'mcfs';
|
||||
static const uint32 MSG_COLOR_FIELD_CHANGED = 'mccf';
|
||||
static const uint32 MSG_COLOR_CHANGED = 'mcbc';
|
||||
static const uint32 MSG_COLOR_SCHEMA_CHANGED = 'mccs';
|
||||
|
||||
const ulong MSG_WARN_ON_EXIT_CHANGED = 'mwec';
|
||||
const ulong MSG_COLS_CHANGED = 'mccl';
|
||||
const ulong MSG_ROWS_CHANGED = 'mcrw';
|
||||
const ulong MSG_HISTORY_CHANGED = 'mhst';
|
||||
static const uint32 MSG_TAB_TITLE_SETTING_CHANGED = 'mtts';
|
||||
static const uint32 MSG_WINDOW_TITLE_SETTING_CHANGED = 'mwts';
|
||||
static const uint32 MSG_WARN_ON_EXIT_CHANGED = 'mwec';
|
||||
static const uint32 MSG_COLS_CHANGED = 'mccl';
|
||||
static const uint32 MSG_ROWS_CHANGED = 'mcrw';
|
||||
static const uint32 MSG_HISTORY_CHANGED = 'mhst';
|
||||
|
||||
const ulong MSG_PREF_MODIFIED = 'mpmo';
|
||||
static const uint32 MSG_PREF_MODIFIED = 'mpmo';
|
||||
|
||||
|
||||
struct color_schema;
|
||||
class BCheckBox;
|
||||
class BColorControl;
|
||||
class BMenu;
|
||||
class BMenuField;
|
||||
class BPopUpMenu;
|
||||
class BCheckBox;
|
||||
class BTextControl;
|
||||
|
||||
|
||||
class AppearancePrefView : public BGroupView {
|
||||
@ -76,6 +79,9 @@ private:
|
||||
BMenuField* fColorField;
|
||||
BColorControl* fColorControl;
|
||||
|
||||
BTextControl* fTabTitle;
|
||||
BTextControl* fWindowTitle;
|
||||
|
||||
BMessenger fTerminalMessenger;
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@ Application Terminal :
|
||||
Globals.cpp
|
||||
HistoryBuffer.cpp
|
||||
InlineInput.cpp
|
||||
PatternEvaluator.cpp
|
||||
PrefHandler.cpp
|
||||
PrefWindow.cpp
|
||||
Shell.cpp
|
||||
@ -29,6 +30,7 @@ Application Terminal :
|
||||
TermScrollView.cpp
|
||||
TermView.cpp
|
||||
TermWindow.cpp
|
||||
TitlePlaceholderMapper.cpp
|
||||
VTKeyTbl.c
|
||||
VTPrsTbl.c
|
||||
: be $(HAIKU_LOCALE_LIBS) tracker textencoding $(TARGET_LIBSUPC++)
|
||||
|
75
src/apps/terminal/PatternEvaluator.cpp
Normal file
75
src/apps/terminal/PatternEvaluator.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "PatternEvaluator.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
// #pragma mark - PatternEvaluator
|
||||
|
||||
|
||||
/*static*/ BString
|
||||
PatternEvaluator::Evaluate(const char* pattern, PlaceholderMapper& mapper)
|
||||
{
|
||||
BString result;
|
||||
|
||||
while (*pattern != '\0') {
|
||||
// find next placeholder
|
||||
const char* placeholder = strchr(pattern, '%');
|
||||
if (placeholder == NULL)
|
||||
return result.Append(pattern);
|
||||
|
||||
// append skipped chars
|
||||
if (placeholder != pattern)
|
||||
result.Append(pattern, placeholder - pattern);
|
||||
|
||||
pattern = placeholder + 1;
|
||||
|
||||
// check for an escaped '%'
|
||||
if (*pattern == '%') {
|
||||
result += '%';
|
||||
pattern++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse a number, if there is one
|
||||
int64 number = 0;
|
||||
bool hasNumber = false;
|
||||
if (isdigit(*pattern)) {
|
||||
char* numberEnd;
|
||||
number = strtoll(pattern, &numberEnd, 10);
|
||||
pattern = numberEnd;
|
||||
hasNumber = true;
|
||||
}
|
||||
|
||||
BString mappedValue;
|
||||
if (*pattern != '\0' && mapper.MapPlaceholder(*pattern,
|
||||
number, hasNumber, mappedValue)) {
|
||||
// mapped successfully -- append the replacement string
|
||||
result += mappedValue;
|
||||
pattern++;
|
||||
} else {
|
||||
// something went wrong -- just append the literal part of the
|
||||
// pattern
|
||||
result.Append(placeholder, pattern - placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - PlaceholderMapper
|
||||
|
||||
|
||||
PatternEvaluator::PlaceholderMapper::~PlaceholderMapper()
|
||||
{
|
||||
}
|
33
src/apps/terminal/PatternEvaluator.h
Normal file
33
src/apps/terminal/PatternEvaluator.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PATTERN_EVALUATOR_H
|
||||
#define PATTERN_EVALUATOR_H
|
||||
|
||||
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class PatternEvaluator {
|
||||
public:
|
||||
class PlaceholderMapper;
|
||||
|
||||
public:
|
||||
static BString Evaluate(const char* pattern,
|
||||
PlaceholderMapper& mapper);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PatternEvaluator::PlaceholderMapper {
|
||||
public:
|
||||
virtual ~PlaceholderMapper();
|
||||
|
||||
virtual bool MapPlaceholder(char placeholder,
|
||||
int64 number, bool numberGiven,
|
||||
BString& _string) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // PATTERN_EVALUATOR_H
|
@ -57,6 +57,8 @@ static const pref_defaults kTermDefaults[] = {
|
||||
{ PREF_GUI_LANGUAGE, "English"},
|
||||
{ PREF_IM_AWARE, "0"},
|
||||
|
||||
{ PREF_TAB_TITLE, "%1d: %p" },
|
||||
{ PREF_WINDOW_TITLE, "Terminal %i: %t" },
|
||||
{ PREF_WARN_ON_EXIT, PREF_TRUE },
|
||||
|
||||
{ NULL, NULL},
|
||||
|
@ -59,6 +59,7 @@ main()
|
||||
TermApp::TermApp()
|
||||
: BApplication(TERM_SIGNATURE),
|
||||
fStartFullscreen(false),
|
||||
fWindowTitleUserDefined(false),
|
||||
fWindowNumber(-1),
|
||||
fTermWindow(NULL),
|
||||
fArgs(NULL)
|
||||
@ -222,8 +223,10 @@ TermApp::ArgvReceived(int32 argc, char **argv)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fArgs->Title() != NULL)
|
||||
if (fArgs->Title() != NULL) {
|
||||
fWindowTitle = fArgs->Title();
|
||||
fWindowTitleUserDefined = true;
|
||||
}
|
||||
|
||||
fStartFullscreen = fArgs->FullScreen();
|
||||
}
|
||||
@ -361,8 +364,8 @@ status_t
|
||||
TermApp::_MakeTermWindow(BRect &frame, uint32 workspaces)
|
||||
{
|
||||
try {
|
||||
fTermWindow = new TermWindow(frame, fWindowTitle.String(), workspaces,
|
||||
fArgs);
|
||||
fTermWindow = new TermWindow(frame, fWindowTitle,
|
||||
fWindowTitleUserDefined, fWindowNumber, workspaces, fArgs);
|
||||
} catch (int error) {
|
||||
return (status_t)error;
|
||||
} catch (...) {
|
||||
|
@ -85,6 +85,7 @@ private:
|
||||
private:
|
||||
bool fStartFullscreen;
|
||||
BString fWindowTitle;
|
||||
bool fWindowTitleUserDefined;
|
||||
int32 fWindowNumber;
|
||||
|
||||
BWindow* fTermWindow;
|
||||
|
@ -131,6 +131,9 @@ static const char* const PREF_GUI_LANGUAGE = "Language";
|
||||
|
||||
static const char* const PREF_WARN_ON_EXIT = "Warn on exit";
|
||||
|
||||
static const char* const PREF_TAB_TITLE = "Tab title";
|
||||
static const char* const PREF_WINDOW_TITLE = "Window title";
|
||||
|
||||
// Color type
|
||||
enum {
|
||||
TEXT_FOREGROUND_COLOR,
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "TermConst.h"
|
||||
#include "TermScrollView.h"
|
||||
#include "TermView.h"
|
||||
#include "TitlePlaceholderMapper.h"
|
||||
|
||||
|
||||
const static int32 kMaxTabs = 6;
|
||||
@ -55,6 +56,7 @@ const static uint32 kCloseView = 'ClVw';
|
||||
const static uint32 kIncreaseFontSize = 'InFs';
|
||||
const static uint32 kDecreaseFontSize = 'DcFs';
|
||||
const static uint32 kSetActiveTab = 'STab';
|
||||
const static uint32 kUpdateTitles = 'UPti';
|
||||
|
||||
|
||||
#undef B_TRANSLATE_CONTEXT
|
||||
@ -100,8 +102,7 @@ private:
|
||||
|
||||
struct TermWindow::Session {
|
||||
int32 id;
|
||||
BString name;
|
||||
BString windowTitle;
|
||||
Title title;
|
||||
TermViewContainerView* containerView;
|
||||
|
||||
Session(int32 id, TermViewContainerView* containerView)
|
||||
@ -109,8 +110,9 @@ struct TermWindow::Session {
|
||||
id(id),
|
||||
containerView(containerView)
|
||||
{
|
||||
name = B_TRANSLATE("Shell ");
|
||||
name << id;
|
||||
title.title = B_TRANSLATE("Shell ");
|
||||
title.title << id;
|
||||
title.patternUserDefined = false;
|
||||
}
|
||||
};
|
||||
|
||||
@ -140,12 +142,14 @@ private:
|
||||
};
|
||||
|
||||
|
||||
TermWindow::TermWindow(BRect frame, const char* title, uint32 workspaces,
|
||||
TermWindow::TermWindow(BRect frame, const BString& title,
|
||||
bool isUserDefinedTitle, int32 windowIndex, uint32 workspaces,
|
||||
Arguments* args)
|
||||
:
|
||||
BWindow(frame, title, B_DOCUMENT_WINDOW,
|
||||
B_CURRENT_WORKSPACE | B_QUIT_ON_WINDOW_CLOSE, workspaces),
|
||||
fInitialTitle(title),
|
||||
fWindowIndex(windowIndex),
|
||||
fTitleUpdateRunner(this, BMessage(kUpdateTitles), 1000000),
|
||||
fTabView(NULL),
|
||||
fMenubar(NULL),
|
||||
fFilemenu(NULL),
|
||||
@ -166,6 +170,12 @@ TermWindow::TermWindow(BRect frame, const char* title, uint32 workspaces,
|
||||
fMatchWord(false),
|
||||
fFullScreen(false)
|
||||
{
|
||||
// apply the title settings
|
||||
fTitle.title = title;
|
||||
fTitle.pattern = title;
|
||||
fTitle.patternUserDefined = isUserDefinedTitle;
|
||||
_TitleSettingsChanged();
|
||||
|
||||
_InitWindow();
|
||||
_AddTab(args);
|
||||
}
|
||||
@ -189,15 +199,13 @@ TermWindow::~TermWindow()
|
||||
|
||||
|
||||
void
|
||||
TermWindow::SetSessionWindowTitle(TermView* termView, const char* title)
|
||||
TermWindow::SetSessionTitle(TermView* termView, const char* title)
|
||||
{
|
||||
int32 index = _IndexOfTermView(termView);
|
||||
if (Session* session = (Session*)fSessions.ItemAt(index)) {
|
||||
session->windowTitle = title;
|
||||
BTab* tab = fTabView->TabAt(index);
|
||||
tab->SetLabel(session->windowTitle.String());
|
||||
if (index == fTabView->Selection())
|
||||
SetTitle(session->windowTitle.String());
|
||||
session->title.pattern = title;
|
||||
session->title.patternUserDefined = true;
|
||||
_UpdateSessionTitle(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,9 +213,7 @@ TermWindow::SetSessionWindowTitle(TermView* termView, const char* title)
|
||||
void
|
||||
TermWindow::SessionChanged()
|
||||
{
|
||||
int32 index = fTabView->Selection();
|
||||
if (Session* session = (Session*)fSessions.ItemAt(index))
|
||||
SetTitle(session->windowTitle.String());
|
||||
_UpdateSessionTitle(fTabView->Selection());
|
||||
}
|
||||
|
||||
|
||||
@ -509,6 +515,11 @@ TermWindow::MessageReceived(BMessage *message)
|
||||
fPrefWindow = NULL;
|
||||
break;
|
||||
|
||||
case MSG_WINDOW_TITLE_SETTING_CHANGED:
|
||||
case MSG_TAB_TITLE_SETTING_CHANGED:
|
||||
_TitleSettingsChanged();
|
||||
break;
|
||||
|
||||
case MENU_FIND_STRING:
|
||||
if (!fFindPanel) {
|
||||
fFindPanel = new FindWindow(this, fFindString, fFindSelection,
|
||||
@ -755,6 +766,10 @@ TermWindow::MessageReceived(BMessage *message)
|
||||
break;
|
||||
}
|
||||
|
||||
case kUpdateTitles:
|
||||
_UpdateTitles();
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
break;
|
||||
@ -870,7 +885,6 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
|
||||
fTabView->SetScrollView(scrollView);
|
||||
|
||||
Session* session = new Session(_NewSessionID(), containerView);
|
||||
session->windowTitle = fInitialTitle;
|
||||
fSessions.AddItem(session);
|
||||
|
||||
BFont font;
|
||||
@ -905,10 +919,6 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
|
||||
|
||||
BTab* tab = new BTab;
|
||||
fTabView->AddTab(scrollView, tab);
|
||||
tab->SetLabel(session->name.String());
|
||||
// TODO: Use a better name. For example, do like MacOS X's Terminal
|
||||
// and update the title using the last executed command ?
|
||||
// Or like Gnome's Terminal and use the current path ?
|
||||
view->SetScrollBar(scrollView->ScrollBar(B_VERTICAL));
|
||||
view->SetMouseClipboard(gMouseClipboard);
|
||||
view->SetEncoding(EncodingID(
|
||||
@ -916,8 +926,10 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
|
||||
|
||||
_SetTermColors(containerView);
|
||||
|
||||
// TODO: No fTabView->Select(tab); ?
|
||||
fTabView->Select(fTabView->CountTabs() - 1);
|
||||
int32 tabIndex = fTabView->CountTabs() - 1;
|
||||
fTabView->Select(tabIndex);
|
||||
|
||||
_UpdateSessionTitle(tabIndex);
|
||||
} catch (...) {
|
||||
// most probably out of memory. That's bad.
|
||||
// TODO: Should cleanup, I guess
|
||||
@ -1096,6 +1108,72 @@ TermWindow::_MakeWindowSizeMenu()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TermWindow::_TitleSettingsChanged()
|
||||
{
|
||||
if (!fTitle.patternUserDefined)
|
||||
fTitle.pattern = PrefHandler::Default()->getString(PREF_WINDOW_TITLE);
|
||||
|
||||
fSessionTitlePattern = PrefHandler::Default()->getString(PREF_TAB_TITLE);
|
||||
|
||||
_UpdateTitles();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TermWindow::_UpdateTitles()
|
||||
{
|
||||
int32 sessionCount = fSessions.CountItems();
|
||||
for (int32 i = 0; i < sessionCount; i++)
|
||||
_UpdateSessionTitle(i);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TermWindow::_UpdateSessionTitle(int32 index)
|
||||
{
|
||||
Session* session = (Session*)fSessions.ItemAt(index);
|
||||
if (session == NULL)
|
||||
return;
|
||||
|
||||
// get the active process info
|
||||
ActiveProcessInfo activeProcessInfo;
|
||||
if (!_TermViewAt(index)->GetActiveProcessInfo(activeProcessInfo))
|
||||
return;
|
||||
|
||||
// evaluate the session title pattern
|
||||
BString sessionTitlePattern = session->title.patternUserDefined
|
||||
? session->title.pattern : fSessionTitlePattern;
|
||||
TabTitlePlaceholderMapper tabMapper(activeProcessInfo, session->id);
|
||||
const BString& sessionTitle = PatternEvaluator::Evaluate(
|
||||
sessionTitlePattern, tabMapper);
|
||||
|
||||
// set the tab title
|
||||
if (sessionTitle != session->title.title) {
|
||||
session->title.title = sessionTitle;
|
||||
BTab* tab = fTabView->TabAt(index);
|
||||
tab->SetLabel(session->title.title);
|
||||
fTabView->Invalidate(fTabView->TabFrame(index));
|
||||
}
|
||||
|
||||
// If this is the active tab, also recompute the window title.
|
||||
if (index != fTabView->Selection())
|
||||
return;
|
||||
|
||||
// evaluate the window title pattern
|
||||
WindowTitlePlaceholderMapper windowMapper(activeProcessInfo, fWindowIndex,
|
||||
sessionTitle);
|
||||
const BString& windowTitle = PatternEvaluator::Evaluate(fTitle.pattern,
|
||||
windowMapper);
|
||||
|
||||
// set the window title
|
||||
if (windowTitle != fTitle.title) {
|
||||
fTitle.title = windowTitle;
|
||||
SetTitle(fTitle.title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
TermWindow::_NewSessionID()
|
||||
{
|
||||
@ -1152,6 +1230,6 @@ CustomTermView::NotifyQuit(int32 reason)
|
||||
void
|
||||
CustomTermView::SetTitle(const char* title)
|
||||
{
|
||||
dynamic_cast<TermWindow*>(Window())->SetSessionWindowTitle(this, title);
|
||||
dynamic_cast<TermWindow*>(Window())->SetSessionTitle(this, title);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define TERM_WINDOW_H
|
||||
|
||||
|
||||
#include <MessageRunner.h>
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
@ -49,11 +50,12 @@ class TermViewContainerView;
|
||||
|
||||
class TermWindow : public BWindow {
|
||||
public:
|
||||
TermWindow(BRect frame, const char* title,
|
||||
TermWindow(BRect frame, const BString& title,
|
||||
bool isUserDefinedTitle, int32 windowIndex,
|
||||
uint32 workspaces, Arguments* args);
|
||||
virtual ~TermWindow();
|
||||
|
||||
void SetSessionWindowTitle(TermView* termView,
|
||||
void SetSessionTitle(TermView* termView,
|
||||
const char* title);
|
||||
void SessionChanged();
|
||||
|
||||
@ -66,6 +68,12 @@ protected:
|
||||
virtual void FrameResized(float newWidth, float newHeight);
|
||||
|
||||
private:
|
||||
struct Title {
|
||||
BString title;
|
||||
BString pattern;
|
||||
bool patternUserDefined;
|
||||
};
|
||||
|
||||
struct Session;
|
||||
class TabView;
|
||||
friend class TabView;
|
||||
@ -92,10 +100,18 @@ private:
|
||||
void _CheckChildren();
|
||||
void _ResizeView(TermView* view);
|
||||
|
||||
void _TitleSettingsChanged();
|
||||
void _UpdateTitles();
|
||||
void _UpdateSessionTitle(int32 index);
|
||||
|
||||
int32 _NewSessionID();
|
||||
|
||||
private:
|
||||
BString fInitialTitle;
|
||||
Title fTitle;
|
||||
BString fSessionTitlePattern;
|
||||
int32 fWindowIndex;
|
||||
BMessageRunner fTitleUpdateRunner;
|
||||
|
||||
BList fSessions;
|
||||
|
||||
TabView* fTabView;
|
||||
|
121
src/apps/terminal/TitlePlaceholderMapper.cpp
Normal file
121
src/apps/terminal/TitlePlaceholderMapper.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "TitlePlaceholderMapper.h"
|
||||
|
||||
|
||||
// #pragma mark - TitlePlaceholderMapper
|
||||
|
||||
|
||||
TitlePlaceholderMapper::TitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo)
|
||||
:
|
||||
fProcessInfo(processInfo)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
bool
|
||||
TitlePlaceholderMapper::MapPlaceholder(char placeholder, int64 number,
|
||||
bool numberGiven, BString& _string)
|
||||
{
|
||||
switch (placeholder) {
|
||||
case 'd':
|
||||
{
|
||||
// current working directory
|
||||
|
||||
// If a number is given, extract the respective number of rightmost
|
||||
// components.
|
||||
BString directory(fProcessInfo.CurrentDirectory());
|
||||
if (numberGiven && number > 0) {
|
||||
int32 index = directory.Length();
|
||||
while (number > 0 && index > 0) {
|
||||
index = directory.FindLast('/', index - 1);
|
||||
number--;
|
||||
}
|
||||
|
||||
if (index >= 0 && index + 1 < directory.Length())
|
||||
directory.Remove(0, index + 1);
|
||||
}
|
||||
|
||||
_string = directory;
|
||||
return true;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
// process name
|
||||
_string = fProcessInfo.Name();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - WindowTitlePlaceholderMapper
|
||||
|
||||
|
||||
WindowTitlePlaceholderMapper::WindowTitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo, int32 windowIndex,
|
||||
const BString& tabTitle)
|
||||
:
|
||||
TitlePlaceholderMapper(processInfo),
|
||||
fWindowIndex(windowIndex),
|
||||
fTabTitle(tabTitle)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
WindowTitlePlaceholderMapper::MapPlaceholder(char placeholder, int64 number,
|
||||
bool numberGiven, BString& _string)
|
||||
{
|
||||
switch (placeholder) {
|
||||
case 'i':
|
||||
// window index
|
||||
_string.Truncate(0);
|
||||
_string << fWindowIndex;
|
||||
return true;
|
||||
|
||||
case 't':
|
||||
// the tab title
|
||||
_string = fTabTitle;
|
||||
return true;
|
||||
}
|
||||
|
||||
return TitlePlaceholderMapper::MapPlaceholder(placeholder, number,
|
||||
numberGiven, _string);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - TabTitlePlaceholderMapper
|
||||
|
||||
|
||||
TabTitlePlaceholderMapper::TabTitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo, int32 tabIndex)
|
||||
:
|
||||
TitlePlaceholderMapper(processInfo),
|
||||
fTabIndex(tabIndex)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TabTitlePlaceholderMapper::MapPlaceholder(char placeholder, int64 number,
|
||||
bool numberGiven, BString& _string)
|
||||
{
|
||||
switch (placeholder) {
|
||||
case 'i':
|
||||
// tab index
|
||||
_string.Truncate(0);
|
||||
_string << fTabIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
return TitlePlaceholderMapper::MapPlaceholder(placeholder, number,
|
||||
numberGiven, _string);
|
||||
}
|
60
src/apps/terminal/TitlePlaceholderMapper.h
Normal file
60
src/apps/terminal/TitlePlaceholderMapper.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TITLE_PLACEHOLDER_MAPPER_H
|
||||
#define TITLE_PLACEHOLDER_MAPPER_H
|
||||
|
||||
|
||||
#include "ActiveProcessInfo.h"
|
||||
#include "PatternEvaluator.h"
|
||||
|
||||
|
||||
/*! Class mapping the placeholders common for window and tab titles.
|
||||
*/
|
||||
class TitlePlaceholderMapper : public PatternEvaluator::PlaceholderMapper {
|
||||
public:
|
||||
TitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo);
|
||||
|
||||
virtual bool MapPlaceholder(char placeholder,
|
||||
int64 number, bool numberGiven,
|
||||
BString& _string);
|
||||
|
||||
private:
|
||||
ActiveProcessInfo fProcessInfo;
|
||||
};
|
||||
|
||||
|
||||
class WindowTitlePlaceholderMapper : public TitlePlaceholderMapper {
|
||||
public:
|
||||
WindowTitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo,
|
||||
int32 windowIndex, const BString& tabTitle);
|
||||
|
||||
virtual bool MapPlaceholder(char placeholder,
|
||||
int64 number, bool numberGiven,
|
||||
BString& _string);
|
||||
|
||||
private:
|
||||
int32 fWindowIndex;
|
||||
BString fTabTitle;
|
||||
};
|
||||
|
||||
|
||||
class TabTitlePlaceholderMapper : public TitlePlaceholderMapper {
|
||||
public:
|
||||
TabTitlePlaceholderMapper(
|
||||
const ActiveProcessInfo& processInfo,
|
||||
int32 tabIndex);
|
||||
|
||||
virtual bool MapPlaceholder(char placeholder,
|
||||
int64 number, bool numberGiven,
|
||||
BString& _string);
|
||||
|
||||
private:
|
||||
int32 fTabIndex;
|
||||
};
|
||||
|
||||
|
||||
#endif // TITLE_PLACEHOLDER_MAPPER_H
|
Loading…
Reference in New Issue
Block a user