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:
Ingo Weinhold 2010-11-17 23:46:13 +00:00
parent e492be3195
commit 02ee32bb0d
13 changed files with 513 additions and 50 deletions

View File

@ -106,17 +106,48 @@ AppearancePrefView::AppearancePrefView(const char* name,
colorsPopUp); colorsPopUp);
fColorField->SetEnabled(false); 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) BLayoutBuilder::Group<>(this)
.SetInsets(5, 5, 5, 5) .SetInsets(5, 5, 5, 5)
.AddGrid(5, 5) .AddGrid(5, 5)
.Add(fFont->CreateLabelLayoutItem(), 0, 0) .AddTextControl(fTabTitle, 0, 0, B_ALIGN_RIGHT)
.Add(fFont->CreateMenuBarLayoutItem(), 1, 0) .AddTextControl(fWindowTitle, 0, 1, B_ALIGN_RIGHT)
.Add(fFontSize->CreateLabelLayoutItem(), 0, 1) .Add(fFont->CreateLabelLayoutItem(), 0, 2)
.Add(fFontSize->CreateMenuBarLayoutItem(), 1, 1) .Add(fFont->CreateMenuBarLayoutItem(), 1, 2)
.Add(fColorSchemaField->CreateLabelLayoutItem(), 0, 2) .Add(fFontSize->CreateLabelLayoutItem(), 0, 3)
.Add(fColorSchemaField->CreateMenuBarLayoutItem(), 1, 2) .Add(fFontSize->CreateMenuBarLayoutItem(), 1, 3)
.Add(fColorField->CreateLabelLayoutItem(), 0, 3) .Add(fColorSchemaField->CreateLabelLayoutItem(), 0, 4)
.Add(fColorField->CreateMenuBarLayoutItem(), 1, 3) .Add(fColorSchemaField->CreateMenuBarLayoutItem(), 1, 4)
.Add(fColorField->CreateLabelLayoutItem(), 0, 5)
.Add(fColorField->CreateMenuBarLayoutItem(), 1, 5)
.End() .End()
.AddGlue() .AddGlue()
.Add(fColorControl = new BColorControl(BPoint(10, 10), .Add(fColorControl = new BColorControl(BPoint(10, 10),
@ -128,6 +159,9 @@ AppearancePrefView::AppearancePrefView(const char* name,
fColorField->SetAlignment(B_ALIGN_RIGHT); fColorField->SetAlignment(B_ALIGN_RIGHT);
fColorSchemaField->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->SetEnabled(false);
fColorControl->SetValue( fColorControl->SetValue(
PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR)); PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR));
@ -158,6 +192,9 @@ AppearancePrefView::GetPreferredSize(float* _width, float* _height)
void void
AppearancePrefView::Revert() AppearancePrefView::Revert()
{ {
fTabTitle->SetText(PrefHandler::Default()->getString(PREF_TAB_TITLE));
fWindowTitle->SetText(PrefHandler::Default()->getString(PREF_WINDOW_TITLE));
fWarnOnExit->SetValue(PrefHandler::Default()->getBool( fWarnOnExit->SetValue(PrefHandler::Default()->getBool(
PREF_WARN_ON_EXIT)); PREF_WARN_ON_EXIT));
@ -175,6 +212,8 @@ AppearancePrefView::Revert()
void void
AppearancePrefView::AttachedToWindow() AppearancePrefView::AttachedToWindow()
{ {
fTabTitle->SetTarget(this);
fWindowTitle->SetTarget(this);
fWarnOnExit->SetTarget(this); fWarnOnExit->SetTarget(this);
fFontSize->Menu()->SetTargetForItems(this); fFontSize->Menu()->SetTargetForItems(this);
@ -271,6 +310,30 @@ AppearancePrefView::MessageReceived(BMessage* msg)
modified = true; modified = true;
} }
break; 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: default:
BView::MessageReceived(msg); BView::MessageReceived(msg);
return; return;

View File

@ -13,28 +13,31 @@
#include <String.h> #include <String.h>
const ulong MSG_HALF_FONT_CHANGED = 'mchf'; static const uint32 MSG_HALF_FONT_CHANGED = 'mchf';
const ulong MSG_HALF_SIZE_CHANGED = 'mchs'; static const uint32 MSG_HALF_SIZE_CHANGED = 'mchs';
const ulong MSG_FULL_FONT_CHANGED = 'mcff'; static const uint32 MSG_FULL_FONT_CHANGED = 'mcff';
const ulong MSG_FULL_SIZE_CHANGED = 'mcfs'; static const uint32 MSG_FULL_SIZE_CHANGED = 'mcfs';
const ulong MSG_COLOR_FIELD_CHANGED = 'mccf'; static const uint32 MSG_COLOR_FIELD_CHANGED = 'mccf';
const ulong MSG_COLOR_CHANGED = 'mcbc'; static const uint32 MSG_COLOR_CHANGED = 'mcbc';
const ulong MSG_COLOR_SCHEMA_CHANGED = 'mccs'; static const uint32 MSG_COLOR_SCHEMA_CHANGED = 'mccs';
const ulong MSG_WARN_ON_EXIT_CHANGED = 'mwec'; static const uint32 MSG_TAB_TITLE_SETTING_CHANGED = 'mtts';
const ulong MSG_COLS_CHANGED = 'mccl'; static const uint32 MSG_WINDOW_TITLE_SETTING_CHANGED = 'mwts';
const ulong MSG_ROWS_CHANGED = 'mcrw'; static const uint32 MSG_WARN_ON_EXIT_CHANGED = 'mwec';
const ulong MSG_HISTORY_CHANGED = 'mhst'; 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; struct color_schema;
class BCheckBox;
class BColorControl; class BColorControl;
class BMenu; class BMenu;
class BMenuField; class BMenuField;
class BPopUpMenu; class BPopUpMenu;
class BCheckBox; class BTextControl;
class AppearancePrefView : public BGroupView { class AppearancePrefView : public BGroupView {
@ -76,6 +79,9 @@ private:
BMenuField* fColorField; BMenuField* fColorField;
BColorControl* fColorControl; BColorControl* fColorControl;
BTextControl* fTabTitle;
BTextControl* fWindowTitle;
BMessenger fTerminalMessenger; BMessenger fTerminalMessenger;
}; };

View File

@ -17,6 +17,7 @@ Application Terminal :
Globals.cpp Globals.cpp
HistoryBuffer.cpp HistoryBuffer.cpp
InlineInput.cpp InlineInput.cpp
PatternEvaluator.cpp
PrefHandler.cpp PrefHandler.cpp
PrefWindow.cpp PrefWindow.cpp
Shell.cpp Shell.cpp
@ -29,6 +30,7 @@ Application Terminal :
TermScrollView.cpp TermScrollView.cpp
TermView.cpp TermView.cpp
TermWindow.cpp TermWindow.cpp
TitlePlaceholderMapper.cpp
VTKeyTbl.c VTKeyTbl.c
VTPrsTbl.c VTPrsTbl.c
: be $(HAIKU_LOCALE_LIBS) tracker textencoding $(TARGET_LIBSUPC++) : be $(HAIKU_LOCALE_LIBS) tracker textencoding $(TARGET_LIBSUPC++)

View 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()
{
}

View 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

View File

@ -57,6 +57,8 @@ static const pref_defaults kTermDefaults[] = {
{ PREF_GUI_LANGUAGE, "English"}, { PREF_GUI_LANGUAGE, "English"},
{ PREF_IM_AWARE, "0"}, { PREF_IM_AWARE, "0"},
{ PREF_TAB_TITLE, "%1d: %p" },
{ PREF_WINDOW_TITLE, "Terminal %i: %t" },
{ PREF_WARN_ON_EXIT, PREF_TRUE }, { PREF_WARN_ON_EXIT, PREF_TRUE },
{ NULL, NULL}, { NULL, NULL},

View File

@ -59,6 +59,7 @@ main()
TermApp::TermApp() TermApp::TermApp()
: BApplication(TERM_SIGNATURE), : BApplication(TERM_SIGNATURE),
fStartFullscreen(false), fStartFullscreen(false),
fWindowTitleUserDefined(false),
fWindowNumber(-1), fWindowNumber(-1),
fTermWindow(NULL), fTermWindow(NULL),
fArgs(NULL) fArgs(NULL)
@ -222,8 +223,10 @@ TermApp::ArgvReceived(int32 argc, char **argv)
return; return;
} }
if (fArgs->Title() != NULL) if (fArgs->Title() != NULL) {
fWindowTitle = fArgs->Title(); fWindowTitle = fArgs->Title();
fWindowTitleUserDefined = true;
}
fStartFullscreen = fArgs->FullScreen(); fStartFullscreen = fArgs->FullScreen();
} }
@ -361,8 +364,8 @@ status_t
TermApp::_MakeTermWindow(BRect &frame, uint32 workspaces) TermApp::_MakeTermWindow(BRect &frame, uint32 workspaces)
{ {
try { try {
fTermWindow = new TermWindow(frame, fWindowTitle.String(), workspaces, fTermWindow = new TermWindow(frame, fWindowTitle,
fArgs); fWindowTitleUserDefined, fWindowNumber, workspaces, fArgs);
} catch (int error) { } catch (int error) {
return (status_t)error; return (status_t)error;
} catch (...) { } catch (...) {

View File

@ -85,6 +85,7 @@ private:
private: private:
bool fStartFullscreen; bool fStartFullscreen;
BString fWindowTitle; BString fWindowTitle;
bool fWindowTitleUserDefined;
int32 fWindowNumber; int32 fWindowNumber;
BWindow* fTermWindow; BWindow* fTermWindow;

View File

@ -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_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 // Color type
enum { enum {
TEXT_FOREGROUND_COLOR, TEXT_FOREGROUND_COLOR,

View File

@ -44,6 +44,7 @@
#include "TermConst.h" #include "TermConst.h"
#include "TermScrollView.h" #include "TermScrollView.h"
#include "TermView.h" #include "TermView.h"
#include "TitlePlaceholderMapper.h"
const static int32 kMaxTabs = 6; const static int32 kMaxTabs = 6;
@ -55,6 +56,7 @@ const static uint32 kCloseView = 'ClVw';
const static uint32 kIncreaseFontSize = 'InFs'; const static uint32 kIncreaseFontSize = 'InFs';
const static uint32 kDecreaseFontSize = 'DcFs'; const static uint32 kDecreaseFontSize = 'DcFs';
const static uint32 kSetActiveTab = 'STab'; const static uint32 kSetActiveTab = 'STab';
const static uint32 kUpdateTitles = 'UPti';
#undef B_TRANSLATE_CONTEXT #undef B_TRANSLATE_CONTEXT
@ -100,8 +102,7 @@ private:
struct TermWindow::Session { struct TermWindow::Session {
int32 id; int32 id;
BString name; Title title;
BString windowTitle;
TermViewContainerView* containerView; TermViewContainerView* containerView;
Session(int32 id, TermViewContainerView* containerView) Session(int32 id, TermViewContainerView* containerView)
@ -109,8 +110,9 @@ struct TermWindow::Session {
id(id), id(id),
containerView(containerView) containerView(containerView)
{ {
name = B_TRANSLATE("Shell "); title.title = B_TRANSLATE("Shell ");
name << id; 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) Arguments* args)
: :
BWindow(frame, title, B_DOCUMENT_WINDOW, BWindow(frame, title, B_DOCUMENT_WINDOW,
B_CURRENT_WORKSPACE | B_QUIT_ON_WINDOW_CLOSE, workspaces), B_CURRENT_WORKSPACE | B_QUIT_ON_WINDOW_CLOSE, workspaces),
fInitialTitle(title), fWindowIndex(windowIndex),
fTitleUpdateRunner(this, BMessage(kUpdateTitles), 1000000),
fTabView(NULL), fTabView(NULL),
fMenubar(NULL), fMenubar(NULL),
fFilemenu(NULL), fFilemenu(NULL),
@ -166,6 +170,12 @@ TermWindow::TermWindow(BRect frame, const char* title, uint32 workspaces,
fMatchWord(false), fMatchWord(false),
fFullScreen(false) fFullScreen(false)
{ {
// apply the title settings
fTitle.title = title;
fTitle.pattern = title;
fTitle.patternUserDefined = isUserDefinedTitle;
_TitleSettingsChanged();
_InitWindow(); _InitWindow();
_AddTab(args); _AddTab(args);
} }
@ -189,15 +199,13 @@ TermWindow::~TermWindow()
void void
TermWindow::SetSessionWindowTitle(TermView* termView, const char* title) TermWindow::SetSessionTitle(TermView* termView, const char* title)
{ {
int32 index = _IndexOfTermView(termView); int32 index = _IndexOfTermView(termView);
if (Session* session = (Session*)fSessions.ItemAt(index)) { if (Session* session = (Session*)fSessions.ItemAt(index)) {
session->windowTitle = title; session->title.pattern = title;
BTab* tab = fTabView->TabAt(index); session->title.patternUserDefined = true;
tab->SetLabel(session->windowTitle.String()); _UpdateSessionTitle(index);
if (index == fTabView->Selection())
SetTitle(session->windowTitle.String());
} }
} }
@ -205,9 +213,7 @@ TermWindow::SetSessionWindowTitle(TermView* termView, const char* title)
void void
TermWindow::SessionChanged() TermWindow::SessionChanged()
{ {
int32 index = fTabView->Selection(); _UpdateSessionTitle(fTabView->Selection());
if (Session* session = (Session*)fSessions.ItemAt(index))
SetTitle(session->windowTitle.String());
} }
@ -509,6 +515,11 @@ TermWindow::MessageReceived(BMessage *message)
fPrefWindow = NULL; fPrefWindow = NULL;
break; break;
case MSG_WINDOW_TITLE_SETTING_CHANGED:
case MSG_TAB_TITLE_SETTING_CHANGED:
_TitleSettingsChanged();
break;
case MENU_FIND_STRING: case MENU_FIND_STRING:
if (!fFindPanel) { if (!fFindPanel) {
fFindPanel = new FindWindow(this, fFindString, fFindSelection, fFindPanel = new FindWindow(this, fFindString, fFindSelection,
@ -755,6 +766,10 @@ TermWindow::MessageReceived(BMessage *message)
break; break;
} }
case kUpdateTitles:
_UpdateTitles();
break;
default: default:
BWindow::MessageReceived(message); BWindow::MessageReceived(message);
break; break;
@ -870,7 +885,6 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
fTabView->SetScrollView(scrollView); fTabView->SetScrollView(scrollView);
Session* session = new Session(_NewSessionID(), containerView); Session* session = new Session(_NewSessionID(), containerView);
session->windowTitle = fInitialTitle;
fSessions.AddItem(session); fSessions.AddItem(session);
BFont font; BFont font;
@ -905,10 +919,6 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
BTab* tab = new BTab; BTab* tab = new BTab;
fTabView->AddTab(scrollView, tab); 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->SetScrollBar(scrollView->ScrollBar(B_VERTICAL));
view->SetMouseClipboard(gMouseClipboard); view->SetMouseClipboard(gMouseClipboard);
view->SetEncoding(EncodingID( view->SetEncoding(EncodingID(
@ -916,8 +926,10 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory)
_SetTermColors(containerView); _SetTermColors(containerView);
// TODO: No fTabView->Select(tab); ? int32 tabIndex = fTabView->CountTabs() - 1;
fTabView->Select(fTabView->CountTabs() - 1); fTabView->Select(tabIndex);
_UpdateSessionTitle(tabIndex);
} catch (...) { } catch (...) {
// most probably out of memory. That's bad. // most probably out of memory. That's bad.
// TODO: Should cleanup, I guess // 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 int32
TermWindow::_NewSessionID() TermWindow::_NewSessionID()
{ {
@ -1152,6 +1230,6 @@ CustomTermView::NotifyQuit(int32 reason)
void void
CustomTermView::SetTitle(const char* title) CustomTermView::SetTitle(const char* title)
{ {
dynamic_cast<TermWindow*>(Window())->SetSessionWindowTitle(this, title); dynamic_cast<TermWindow*>(Window())->SetSessionTitle(this, title);
} }

View File

@ -32,6 +32,7 @@
#define TERM_WINDOW_H #define TERM_WINDOW_H
#include <MessageRunner.h>
#include <String.h> #include <String.h>
#include <Window.h> #include <Window.h>
@ -49,11 +50,12 @@ class TermViewContainerView;
class TermWindow : public BWindow { class TermWindow : public BWindow {
public: public:
TermWindow(BRect frame, const char* title, TermWindow(BRect frame, const BString& title,
bool isUserDefinedTitle, int32 windowIndex,
uint32 workspaces, Arguments* args); uint32 workspaces, Arguments* args);
virtual ~TermWindow(); virtual ~TermWindow();
void SetSessionWindowTitle(TermView* termView, void SetSessionTitle(TermView* termView,
const char* title); const char* title);
void SessionChanged(); void SessionChanged();
@ -66,6 +68,12 @@ protected:
virtual void FrameResized(float newWidth, float newHeight); virtual void FrameResized(float newWidth, float newHeight);
private: private:
struct Title {
BString title;
BString pattern;
bool patternUserDefined;
};
struct Session; struct Session;
class TabView; class TabView;
friend class TabView; friend class TabView;
@ -92,10 +100,18 @@ private:
void _CheckChildren(); void _CheckChildren();
void _ResizeView(TermView* view); void _ResizeView(TermView* view);
void _TitleSettingsChanged();
void _UpdateTitles();
void _UpdateSessionTitle(int32 index);
int32 _NewSessionID(); int32 _NewSessionID();
private: private:
BString fInitialTitle; Title fTitle;
BString fSessionTitlePattern;
int32 fWindowIndex;
BMessageRunner fTitleUpdateRunner;
BList fSessions; BList fSessions;
TabView* fTabView; TabView* fTabView;

View 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);
}

View 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