From 02ee32bb0d3cc6680c421177bb490dba84230081 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 17 Nov 2010 23:46:13 +0000 Subject: [PATCH] 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 --- src/apps/terminal/AppearPrefView.cpp | 79 ++++++++++-- src/apps/terminal/AppearPrefView.h | 32 +++-- src/apps/terminal/Jamfile | 2 + src/apps/terminal/PatternEvaluator.cpp | 75 +++++++++++ src/apps/terminal/PatternEvaluator.h | 33 +++++ src/apps/terminal/PrefHandler.cpp | 2 + src/apps/terminal/TermApp.cpp | 9 +- src/apps/terminal/TermApp.h | 1 + src/apps/terminal/TermConst.h | 3 + src/apps/terminal/TermWindow.cpp | 124 +++++++++++++++---- src/apps/terminal/TermWindow.h | 22 +++- src/apps/terminal/TitlePlaceholderMapper.cpp | 121 ++++++++++++++++++ src/apps/terminal/TitlePlaceholderMapper.h | 60 +++++++++ 13 files changed, 513 insertions(+), 50 deletions(-) create mode 100644 src/apps/terminal/PatternEvaluator.cpp create mode 100644 src/apps/terminal/PatternEvaluator.h create mode 100644 src/apps/terminal/TitlePlaceholderMapper.cpp create mode 100644 src/apps/terminal/TitlePlaceholderMapper.h diff --git a/src/apps/terminal/AppearPrefView.cpp b/src/apps/terminal/AppearPrefView.cpp index 85b5732e92..c51fe32f60 100644 --- a/src/apps/terminal/AppearPrefView.cpp +++ b/src/apps/terminal/AppearPrefView.cpp @@ -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; diff --git a/src/apps/terminal/AppearPrefView.h b/src/apps/terminal/AppearPrefView.h index 01e90d268e..6f85e52835 100644 --- a/src/apps/terminal/AppearPrefView.h +++ b/src/apps/terminal/AppearPrefView.h @@ -13,28 +13,31 @@ #include -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; }; diff --git a/src/apps/terminal/Jamfile b/src/apps/terminal/Jamfile index d2d1d7f2ca..b3a2cda52a 100644 --- a/src/apps/terminal/Jamfile +++ b/src/apps/terminal/Jamfile @@ -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++) diff --git a/src/apps/terminal/PatternEvaluator.cpp b/src/apps/terminal/PatternEvaluator.cpp new file mode 100644 index 0000000000..cfe15f8386 --- /dev/null +++ b/src/apps/terminal/PatternEvaluator.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PatternEvaluator.h" + +#include +#include +#include + + + +// #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() +{ +} diff --git a/src/apps/terminal/PatternEvaluator.h b/src/apps/terminal/PatternEvaluator.h new file mode 100644 index 0000000000..68d58e21bb --- /dev/null +++ b/src/apps/terminal/PatternEvaluator.h @@ -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 + + +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 diff --git a/src/apps/terminal/PrefHandler.cpp b/src/apps/terminal/PrefHandler.cpp index 9942e410ae..8eac65cb4b 100644 --- a/src/apps/terminal/PrefHandler.cpp +++ b/src/apps/terminal/PrefHandler.cpp @@ -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}, diff --git a/src/apps/terminal/TermApp.cpp b/src/apps/terminal/TermApp.cpp index 0e2fec6bc1..4f83ed963b 100644 --- a/src/apps/terminal/TermApp.cpp +++ b/src/apps/terminal/TermApp.cpp @@ -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 (...) { diff --git a/src/apps/terminal/TermApp.h b/src/apps/terminal/TermApp.h index 05d744ef1a..f0b9abe117 100644 --- a/src/apps/terminal/TermApp.h +++ b/src/apps/terminal/TermApp.h @@ -85,6 +85,7 @@ private: private: bool fStartFullscreen; BString fWindowTitle; + bool fWindowTitleUserDefined; int32 fWindowNumber; BWindow* fTermWindow; diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index d94ac1a33b..ef372ac22a 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -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, diff --git a/src/apps/terminal/TermWindow.cpp b/src/apps/terminal/TermWindow.cpp index a1c74dfb36..cb80b0bd4f 100644 --- a/src/apps/terminal/TermWindow.cpp +++ b/src/apps/terminal/TermWindow.cpp @@ -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(Window())->SetSessionWindowTitle(this, title); + dynamic_cast(Window())->SetSessionTitle(this, title); } diff --git a/src/apps/terminal/TermWindow.h b/src/apps/terminal/TermWindow.h index fc16ffb4b8..48ed6c9ae3 100644 --- a/src/apps/terminal/TermWindow.h +++ b/src/apps/terminal/TermWindow.h @@ -32,6 +32,7 @@ #define TERM_WINDOW_H +#include #include #include @@ -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; diff --git a/src/apps/terminal/TitlePlaceholderMapper.cpp b/src/apps/terminal/TitlePlaceholderMapper.cpp new file mode 100644 index 0000000000..f3057f1806 --- /dev/null +++ b/src/apps/terminal/TitlePlaceholderMapper.cpp @@ -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 +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); +} diff --git a/src/apps/terminal/TitlePlaceholderMapper.h b/src/apps/terminal/TitlePlaceholderMapper.h new file mode 100644 index 0000000000..a341c69822 --- /dev/null +++ b/src/apps/terminal/TitlePlaceholderMapper.h @@ -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