vfs: check userland buffers before reading them.
[haiku.git] / src / apps / terminal / AppearPrefView.cpp
blobcb4d9261c1ef3764ebae6d94bf206cf6c7ee5b5b
1 /*
2 * Copyright 2001-2015, Haiku, Inc.
3 * Copyright 2003-2004 Kian Duffy, myob@users.sourceforge.net
4 * Parts Copyright 1998-1999 Kazuho Okui and Takashi Murai.
5 * All rights reserved. Distributed under the terms of the MIT license.
6 */
9 #include "AppearPrefView.h"
11 #include <stdio.h>
12 #include <stdlib.h>
14 #include <Button.h>
15 #include <Catalog.h>
16 #include <CharacterSet.h>
17 #include <CharacterSetRoster.h>
18 #include <CheckBox.h>
19 #include <ColorControl.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <Menu.h>
23 #include <MenuField.h>
24 #include <MenuItem.h>
25 #include <PopUpMenu.h>
26 #include <TextControl.h>
27 #include <View.h>
29 #include "Colors.h"
30 #include "Globals.h"
31 #include "PrefHandler.h"
32 #include "TermConst.h"
33 #include "TermWindow.h"
36 #undef B_TRANSLATION_CONTEXT
37 #define B_TRANSLATION_CONTEXT "Terminal AppearancePrefView"
41 // #pragma mark -
44 AppearancePrefView::AppearancePrefView(const char* name,
45 const BMessenger& messenger)
47 BGroupView(name, B_VERTICAL, 5),
48 fTerminalMessenger(messenger)
50 const char* kColorTable[] = {
51 B_TRANSLATE_MARK("Text"),
52 B_TRANSLATE_MARK("Background"),
53 B_TRANSLATE_MARK("Cursor"),
54 B_TRANSLATE_MARK("Text under cursor"),
55 B_TRANSLATE_MARK("Selected text"),
56 B_TRANSLATE_MARK("Selected background"),
57 NULL
60 fBlinkCursor = new BCheckBox(
61 B_TRANSLATE("Blinking cursor"),
62 new BMessage(MSG_BLINK_CURSOR_CHANGED));
64 fAllowBold = new BCheckBox(
65 B_TRANSLATE("Allow bold text"),
66 new BMessage(MSG_ALLOW_BOLD_CHANGED));
68 fWarnOnExit = new BCheckBox(
69 B_TRANSLATE("Confirm exit if active programs exist"),
70 new BMessage(MSG_WARN_ON_EXIT_CHANGED));
72 BMenu* fontMenu = _MakeFontMenu(MSG_HALF_FONT_CHANGED,
73 PrefHandler::Default()->getString(PREF_HALF_FONT_FAMILY),
74 PrefHandler::Default()->getString(PREF_HALF_FONT_STYLE));
75 fFontField = new BMenuField(B_TRANSLATE("Font:"), fontMenu);
77 BMenu* sizeMenu = new (std::nothrow) BPopUpMenu(
78 B_TRANSLATE_COMMENT("Custom", "Window size"));
79 if (sizeMenu != NULL) {
80 TermWindow::MakeWindowSizeMenu(sizeMenu);
81 sizeMenu->SetLabelFromMarked(true);
83 fWindowSizeField = new BMenuField(B_TRANSLATE("Window size:"), sizeMenu);
85 BMenu* encodingMenu = new (std::nothrow) BPopUpMenu("Text encoding");
86 if (encodingMenu != NULL) {
87 TermWindow::MakeEncodingMenu(encodingMenu);
88 encodingMenu->SetLabelFromMarked(true);
90 fEncodingField = new BMenuField(B_TRANSLATE("Encoding:"), encodingMenu);
92 BPopUpMenu* schemesPopUp = _MakeColorSchemeMenu(MSG_COLOR_SCHEME_CHANGED,
93 gPredefinedColorSchemes, gPredefinedColorSchemes[0]);
94 fColorSchemeField = new BMenuField(B_TRANSLATE("Color scheme:"),
95 schemesPopUp);
97 BPopUpMenu* colorsPopUp = _MakeMenu(MSG_COLOR_FIELD_CHANGED, kColorTable,
98 kColorTable[0]);
100 fColorField = new BMenuField(B_TRANSLATE("Color:"), colorsPopUp);
102 fTabTitle = new BTextControl("tabTitle", B_TRANSLATE("Tab title:"), "",
103 NULL);
104 fTabTitle->SetModificationMessage(
105 new BMessage(MSG_TAB_TITLE_SETTING_CHANGED));
106 fTabTitle->SetToolTip(BString(B_TRANSLATE(
107 "The pattern specifying the tab titles. The following placeholders\n"
108 "can be used:")) << "\n" << kTooTipSetTabTitlePlaceholders
109 << "\n" << kToolTipCommonTitlePlaceholders);
111 fWindowTitle = new BTextControl("windowTitle", B_TRANSLATE("Window title:"),
112 "", NULL);
113 fWindowTitle->SetModificationMessage(
114 new BMessage(MSG_WINDOW_TITLE_SETTING_CHANGED));
115 fWindowTitle->SetToolTip(BString(B_TRANSLATE(
116 "The pattern specifying the window titles. The following placeholders\n"
117 "can be used:")) << "\n" << kTooTipSetWindowTitlePlaceholders
118 << "\n" << kToolTipCommonTitlePlaceholders);
120 BLayoutBuilder::Group<>(this)
121 .SetInsets(5, 5, 5, 5)
122 .AddGrid(5, 5)
123 .Add(fTabTitle->CreateLabelLayoutItem(), 0, 0)
124 .Add(fTabTitle->CreateTextViewLayoutItem(), 1, 0)
125 .Add(fWindowTitle->CreateLabelLayoutItem(), 0, 1)
126 .Add(fWindowTitle->CreateTextViewLayoutItem(), 1, 1)
127 .Add(fWindowSizeField->CreateLabelLayoutItem(), 0, 2)
128 .Add(fWindowSizeField->CreateMenuBarLayoutItem(), 1, 2)
129 .Add(fFontField->CreateLabelLayoutItem(), 0, 3)
130 .Add(fFontField->CreateMenuBarLayoutItem(), 1, 3)
131 .Add(fEncodingField->CreateLabelLayoutItem(), 0, 4)
132 .Add(fEncodingField->CreateMenuBarLayoutItem(), 1, 4)
133 .Add(fColorSchemeField->CreateLabelLayoutItem(), 0, 5)
134 .Add(fColorSchemeField->CreateMenuBarLayoutItem(), 1, 5)
135 .Add(fColorField->CreateLabelLayoutItem(), 0, 6)
136 .Add(fColorField->CreateMenuBarLayoutItem(), 1, 6)
137 .End()
138 .AddGlue()
139 .Add(fColorControl = new BColorControl(BPoint(10, 10),
140 B_CELLS_32x8, 8.0, "", new BMessage(MSG_COLOR_CHANGED)))
141 .Add(fBlinkCursor)
142 .Add(fAllowBold)
143 .Add(fWarnOnExit);
145 fTabTitle->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
146 fWindowTitle->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
147 fFontField->SetAlignment(B_ALIGN_RIGHT);
148 fWindowSizeField->SetAlignment(B_ALIGN_RIGHT);
149 fEncodingField->SetAlignment(B_ALIGN_RIGHT);
150 fColorField->SetAlignment(B_ALIGN_RIGHT);
151 fColorSchemeField->SetAlignment(B_ALIGN_RIGHT);
153 Revert();
155 BTextControl* redInput = (BTextControl*)fColorControl->ChildAt(0);
156 BTextControl* greenInput = (BTextControl*)fColorControl->ChildAt(1);
157 BTextControl* blueInput = (BTextControl*)fColorControl->ChildAt(2);
159 redInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
160 greenInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
161 blueInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
165 void
166 AppearancePrefView::Revert()
168 PrefHandler* pref = PrefHandler::Default();
170 fTabTitle->SetText(pref->getString(PREF_TAB_TITLE));
171 fWindowTitle->SetText(pref->getString(PREF_WINDOW_TITLE));
173 fBlinkCursor->SetValue(pref->getBool(PREF_BLINK_CURSOR));
174 fAllowBold->SetValue(pref->getBool(PREF_ALLOW_BOLD));
175 fWarnOnExit->SetValue(pref->getBool(PREF_WARN_ON_EXIT));
177 _SetCurrentColorScheme();
178 _SetEncoding(pref->getString(PREF_TEXT_ENCODING));
179 _SetWindowSize(pref->getInt32(PREF_ROWS), pref->getInt32(PREF_COLS));
180 fColorControl->SetValue(pref->getRGB(PREF_TEXT_FORE_COLOR));
182 const char* family = pref->getString(PREF_HALF_FONT_FAMILY);
183 const char* style = pref->getString(PREF_HALF_FONT_STYLE);
184 const char* size = pref->getString(PREF_HALF_FONT_SIZE);
186 _MarkSelectedFont(family, style, size);
190 void
191 AppearancePrefView::AttachedToWindow()
193 fTabTitle->SetTarget(this);
194 fWindowTitle->SetTarget(this);
195 fBlinkCursor->SetTarget(this);
196 fAllowBold->SetTarget(this);
197 fWarnOnExit->SetTarget(this);
199 fFontField->Menu()->SetTargetForItems(this);
200 for (int32 i = 0; i < fFontField->Menu()->CountItems(); i++) {
201 BMenu* fontSizeMenu = fFontField->Menu()->SubmenuAt(i);
202 if (fontSizeMenu == NULL)
203 continue;
205 fontSizeMenu->SetTargetForItems(this);
208 fColorControl->SetTarget(this);
209 fColorField->Menu()->SetTargetForItems(this);
210 fColorSchemeField->Menu()->SetTargetForItems(this);
211 fWindowSizeField->Menu()->SetTargetForItems(this);
212 fEncodingField->Menu()->SetTargetForItems(this);
214 _SetCurrentColorScheme();
218 void
220 AppearancePrefView::MessageReceived(BMessage* msg)
222 bool modified = false;
224 switch (msg->what) {
225 case MSG_HALF_FONT_CHANGED:
227 const char* family = NULL;
228 const char* style = NULL;
229 const char* size = NULL;
230 if (msg->FindString("font_family", &family) != B_OK
231 || msg->FindString("font_style", &style) != B_OK
232 || msg->FindString("font_size", &size) != B_OK) {
233 break;
236 PrefHandler* pref = PrefHandler::Default();
237 const char* currentFamily
238 = pref->getString(PREF_HALF_FONT_FAMILY);
239 const char* currentStyle
240 = pref->getString(PREF_HALF_FONT_STYLE);
241 const char* currentSize
242 = pref->getString(PREF_HALF_FONT_SIZE);
244 if (currentFamily == NULL || strcmp(currentFamily, family) != 0
245 || currentStyle == NULL || strcmp(currentStyle, style) != 0
246 || currentSize == NULL || strcmp(currentSize, size) != 0) {
247 pref->setString(PREF_HALF_FONT_FAMILY, family);
248 pref->setString(PREF_HALF_FONT_STYLE, style);
249 pref->setString(PREF_HALF_FONT_SIZE, size);
250 _MarkSelectedFont(family, style, size);
251 modified = true;
253 break;
256 case MSG_COLOR_CHANGED:
258 const BMessage* itemMessage
259 = fColorField->Menu()->FindMarked()->Message();
260 const char* label = NULL;
261 if (itemMessage->FindString("label", &label) != B_OK)
262 break;
263 rgb_color oldColor = PrefHandler::Default()->getRGB(label);
264 if (oldColor != fColorControl->ValueAsColor()) {
265 BMenuItem* item = fColorSchemeField->Menu()->FindMarked();
266 if (strcmp(item->Label(), gCustomColorScheme.name) != 0) {
267 item->SetMarked(false);
268 item = fColorSchemeField->Menu()->FindItem(
269 gCustomColorScheme.name);
270 if (item)
271 item->SetMarked(true);
274 PrefHandler::Default()->setRGB(label,
275 fColorControl->ValueAsColor());
276 modified = true;
278 break;
281 case MSG_COLOR_SCHEME_CHANGED:
283 color_scheme* newScheme = NULL;
284 if (msg->FindPointer("color_scheme",
285 (void**)&newScheme) == B_OK) {
286 _ChangeColorScheme(newScheme);
287 const char* label = NULL;
288 if (fColorField->Menu()->FindMarked()->Message()->FindString(
289 "label", &label) == B_OK)
290 fColorControl->SetValue(
291 PrefHandler::Default()->getRGB(label));
292 modified = true;
294 break;
297 case MSG_COLOR_FIELD_CHANGED:
299 const char* label = NULL;
300 if (msg->FindString("label", &label) == B_OK)
301 fColorControl->SetValue(PrefHandler::Default()->getRGB(label));
302 break;
305 case MSG_COLS_CHANGED:
307 int rows = msg->FindInt32("rows");
308 int columns = msg->FindInt32("columns");
309 _SetWindowSize(rows, columns);
310 PrefHandler* handler = PrefHandler::Default();
311 if (handler->getInt32(PREF_ROWS) != rows) {
312 PrefHandler::Default()->setInt32(PREF_ROWS, rows);
313 modified = true;
315 if (handler->getInt32(PREF_COLS) != columns) {
316 PrefHandler::Default()->setInt32(PREF_COLS, columns);
317 modified = true;
320 break;
323 case MSG_BLINK_CURSOR_CHANGED:
324 if (PrefHandler::Default()->getBool(PREF_BLINK_CURSOR)
325 != fBlinkCursor->Value()) {
326 PrefHandler::Default()->setBool(PREF_BLINK_CURSOR,
327 fBlinkCursor->Value());
328 modified = true;
330 break;
332 case MSG_ALLOW_BOLD_CHANGED:
333 if (PrefHandler::Default()->getBool(PREF_ALLOW_BOLD)
334 != fAllowBold->Value()) {
335 PrefHandler::Default()->setBool(PREF_ALLOW_BOLD,
336 fAllowBold->Value());
337 modified = true;
339 break;
341 case MSG_WARN_ON_EXIT_CHANGED:
342 if (PrefHandler::Default()->getBool(PREF_WARN_ON_EXIT)
343 != fWarnOnExit->Value()) {
344 PrefHandler::Default()->setBool(PREF_WARN_ON_EXIT,
345 fWarnOnExit->Value());
346 modified = true;
348 break;
350 case MSG_TAB_TITLE_SETTING_CHANGED:
352 BString oldValue(PrefHandler::Default()->getString(PREF_TAB_TITLE));
353 if (oldValue != fTabTitle->Text()) {
354 PrefHandler::Default()->setString(PREF_TAB_TITLE,
355 fTabTitle->Text());
356 modified = true;
358 break;
361 case MSG_WINDOW_TITLE_SETTING_CHANGED:
363 BString oldValue(PrefHandler::Default()->getString(
364 PREF_WINDOW_TITLE));
365 if (oldValue != fWindowTitle->Text()) {
366 PrefHandler::Default()->setString(PREF_WINDOW_TITLE,
367 fWindowTitle->Text());
368 modified = true;
370 break;
373 default:
374 BView::MessageReceived(msg);
375 return;
378 if (modified) {
379 fTerminalMessenger.SendMessage(msg);
381 BMessenger messenger(this);
382 messenger.SendMessage(MSG_PREF_MODIFIED);
387 void
388 AppearancePrefView::_ChangeColorScheme(color_scheme* scheme)
390 PrefHandler* pref = PrefHandler::Default();
392 pref->setRGB(PREF_TEXT_FORE_COLOR, scheme->text_fore_color);
393 pref->setRGB(PREF_TEXT_BACK_COLOR, scheme->text_back_color);
394 pref->setRGB(PREF_SELECT_FORE_COLOR, scheme->select_fore_color);
395 pref->setRGB(PREF_SELECT_BACK_COLOR, scheme->select_back_color);
396 pref->setRGB(PREF_CURSOR_FORE_COLOR, scheme->cursor_fore_color);
397 pref->setRGB(PREF_CURSOR_BACK_COLOR, scheme->cursor_back_color);
401 void
402 AppearancePrefView::_SetCurrentColorScheme()
404 PrefHandler* pref = PrefHandler::Default();
406 gCustomColorScheme.text_fore_color = pref->getRGB(PREF_TEXT_FORE_COLOR);
407 gCustomColorScheme.text_back_color = pref->getRGB(PREF_TEXT_BACK_COLOR);
408 gCustomColorScheme.select_fore_color = pref->getRGB(PREF_SELECT_FORE_COLOR);
409 gCustomColorScheme.select_back_color = pref->getRGB(PREF_SELECT_BACK_COLOR);
410 gCustomColorScheme.cursor_fore_color = pref->getRGB(PREF_CURSOR_FORE_COLOR);
411 gCustomColorScheme.cursor_back_color = pref->getRGB(PREF_CURSOR_BACK_COLOR);
413 const char* currentSchemeName = NULL;
415 for (const color_scheme** schemes = gPredefinedColorSchemes;
416 *schemes != NULL; schemes++) {
417 if (gCustomColorScheme == **schemes) {
418 currentSchemeName = (*schemes)->name;
419 break;
423 // If the scheme is not one of the known ones, assume a custom one.
424 if (currentSchemeName == NULL)
425 currentSchemeName = "Custom";
427 for (int32 i = 0; i < fColorSchemeField->Menu()->CountItems(); i++) {
428 BMenuItem* item = fColorSchemeField->Menu()->ItemAt(i);
429 if (strcmp(item->Label(), currentSchemeName) == 0) {
430 item->SetMarked(true);
431 break;
437 void
438 AppearancePrefView::_SetEncoding(const char* name)
440 const BPrivate::BCharacterSet* charset
441 = BPrivate::BCharacterSetRoster::FindCharacterSetByName(name);
442 if (charset == NULL)
443 return;
444 int code = charset->GetConversionID();
445 for (int32 i = 0; i < fEncodingField->Menu()->CountItems(); i++) {
446 BMenuItem* item = fEncodingField->Menu()->ItemAt(i);
447 BMessage* msg = item->Message();
448 if (msg->FindInt32("op") == code) {
449 item->SetMarked(true);
450 break;
456 void
457 AppearancePrefView::_SetWindowSize(int rows, int cols)
459 for (int32 i = 0; i < fWindowSizeField->Menu()->CountItems(); i++) {
460 BMenuItem* item = fWindowSizeField->Menu()->ItemAt(i);
461 BMessage* msg = item->Message();
462 if (msg->FindInt32("rows") == rows && msg->FindInt32("columns") == cols) {
463 item->SetMarked(true);
464 break;
470 /*static*/ BMenu*
471 AppearancePrefView::_MakeFontMenu(uint32 command,
472 const char* defaultFamily, const char* defaultStyle)
474 BPopUpMenu* menu = new BPopUpMenu("");
475 int32 numFamilies = count_font_families();
476 for (int32 i = 0; i < numFamilies; i++) {
477 font_family family;
478 uint32 flags;
479 if (get_font_family(i, &family, &flags) == B_OK) {
480 BFont font;
481 font_style style;
482 int32 numStyles = count_font_styles(family);
483 for (int32 j = 0; j < numStyles; j++) {
484 if (get_font_style(family, j, &style) == B_OK) {
485 font.SetFamilyAndStyle(family, style);
486 if (IsFontUsable(font)) {
487 BMessage* message = new BMessage(command);
488 const char* size
489 = PrefHandler::Default()->getString(PREF_HALF_FONT_SIZE);
490 message->AddString("font_family", family);
491 message->AddString("font_style", style);
492 message->AddString("font_size", size);
493 char fontMenuLabel[134];
494 snprintf(fontMenuLabel, sizeof(fontMenuLabel),
495 "%s - %s", family, style);
496 BMenu* fontSizeMenu = _MakeFontSizeMenu(fontMenuLabel,
497 MSG_HALF_FONT_CHANGED, family, style, size);
498 BMenuItem* item = new BMenuItem(fontSizeMenu, message);
499 menu->AddItem(item);
500 if (strcmp(defaultFamily, family) == 0
501 && strcmp(defaultStyle, style) == 0)
502 item->SetMarked(true);
509 if (menu->FindMarked() == NULL)
510 menu->ItemAt(0)->SetMarked(true);
512 return menu;
516 /*static*/ BMenu*
517 AppearancePrefView::_MakeFontSizeMenu(const char* label, uint32 command,
518 const char* family, const char* style, const char* size)
520 BMenu* menu = new BMenu(label);
521 menu->SetRadioMode(true);
522 menu->SetLabelFromMarked(false);
524 int32 sizes[] = {
525 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, 32, 36, 0
528 bool found = false;
530 for (uint32 i = 0; sizes[i]; i++) {
531 BString fontSize;
532 fontSize << sizes[i];
533 BMessage* message = new BMessage(command);
534 message->AddString("font_family", family);
535 message->AddString("font_style", style);
536 message->AddString("font_size", fontSize.String());
537 BMenuItem* item = new BMenuItem(fontSize.String(), message);
538 menu->AddItem(item);
539 if (sizes[i] == atoi(size)) {
540 item->SetMarked(true);
541 found = true;
545 if (!found) {
546 for (uint32 i = 0; sizes[i]; i++) {
547 if (sizes[i] > atoi(size)) {
548 BMessage* message = new BMessage(command);
549 message->AddString("font_family", family);
550 message->AddString("font_style", style);
551 message->AddString("font_size", size);
552 BMenuItem* item = new BMenuItem(size, message);
553 item->SetMarked(true);
554 menu->AddItem(item, i);
555 break;
560 return menu;
564 /*static*/ BPopUpMenu*
565 AppearancePrefView::_MakeMenu(uint32 msg, const char** items,
566 const char* defaultItemName)
568 BPopUpMenu* menu = new BPopUpMenu("");
570 while (*items) {
571 if (strcmp((*items), "") == 0)
572 menu->AddSeparatorItem();
573 else {
574 BMessage* message = new BMessage(msg);
575 message->AddString("label", *items);
576 BMenuItem* item = new BMenuItem(B_TRANSLATE(*items), message);
577 menu->AddItem(item);
578 if (strcmp(*items, defaultItemName) == 0)
579 item->SetMarked(true);
582 items++;
585 return menu;
589 /*static*/ BPopUpMenu*
590 AppearancePrefView::_MakeColorSchemeMenu(uint32 msg, const color_scheme** items,
591 const color_scheme* defaultItemName)
593 BPopUpMenu* menu = new BPopUpMenu("");
595 int32 i = 0;
596 while (*items) {
597 if (strcmp((*items)->name, "") == 0)
598 menu->AddSeparatorItem();
599 else {
600 BMessage* message = new BMessage(msg);
601 message->AddPointer("color_scheme", (const void*)*items);
602 menu->AddItem(new BMenuItem((*items)->name, message));
605 items++;
606 i++;
608 return menu;
612 void
613 AppearancePrefView::_MarkSelectedFont(const char* family, const char* style,
614 const char* size)
616 char fontMenuLabel[134];
617 snprintf(fontMenuLabel, sizeof(fontMenuLabel), "%s - %s", family, style);
619 // mark the selected font
620 BMenuItem* selectedFont = fFontField->Menu()->FindItem(fontMenuLabel);
621 if (selectedFont != NULL)
622 selectedFont->SetMarked(true);
624 // mark the selected font size on all font menus
625 for (int32 i = 0; i < fFontField->Menu()->CountItems(); i++) {
626 BMenu* fontSizeMenu = fFontField->Menu()->SubmenuAt(i);
627 if (fontSizeMenu == NULL)
628 continue;
630 BMenuItem* item = fontSizeMenu->FindItem(size);
631 if (item != NULL)
632 item->SetMarked(true);