xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 267479782d9bfb61695ace95cc46e594186bdfd0)
1a10cf76eSAxel Dörfler /*
2b21d610eSAxel Dörfler  * Copyright 2001-2009, Haiku.
3a10cf76eSAxel Dörfler  * Distributed under the terms of the MIT License.
4a10cf76eSAxel Dörfler  *
5a10cf76eSAxel Dörfler  * Authors:
6a10cf76eSAxel Dörfler  *		Rafael Romo
7a10cf76eSAxel Dörfler  *		Stefano Ceccherini (burton666@libero.it)
8a10cf76eSAxel Dörfler  *		Andrew Bachmann
9a10cf76eSAxel Dörfler  *		Thomas Kurschel
10a10cf76eSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
11df3f5bacSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
12b72c4836SAlexandre Deckner  *		Alexandre Deckner, alex@zappotek.com
13a10cf76eSAxel Dörfler  */
14a10cf76eSAxel Dörfler 
15a10cf76eSAxel Dörfler 
16b21d610eSAxel Dörfler #include "ScreenWindow.h"
17b21d610eSAxel Dörfler 
18b21d610eSAxel Dörfler #include <stdio.h>
19b21d610eSAxel Dörfler #include <stdlib.h>
20b21d610eSAxel Dörfler #include <string.h>
21b21d610eSAxel Dörfler 
22b21d610eSAxel Dörfler #include <Alert.h>
23b21d610eSAxel Dörfler #include <Application.h>
24b21d610eSAxel Dörfler #include <Box.h>
25b21d610eSAxel Dörfler #include <Button.h>
26c9e8f97aSAdrien Destugues #include <Catalog.h>
27b21d610eSAxel Dörfler #include <Directory.h>
28b21d610eSAxel Dörfler #include <File.h>
29b21d610eSAxel Dörfler #include <FindDirectory.h>
30b21d610eSAxel Dörfler #include <InterfaceDefs.h>
31b21d610eSAxel Dörfler #include <LayoutBuilder.h>
32b21d610eSAxel Dörfler #include <MenuBar.h>
33b21d610eSAxel Dörfler #include <MenuItem.h>
34b21d610eSAxel Dörfler #include <MenuField.h>
35b21d610eSAxel Dörfler #include <Messenger.h>
36b21d610eSAxel Dörfler #include <Path.h>
37b21d610eSAxel Dörfler #include <PopUpMenu.h>
38b21d610eSAxel Dörfler #include <Screen.h>
39b21d610eSAxel Dörfler #include <String.h>
40b21d610eSAxel Dörfler #include <StringView.h>
41b21d610eSAxel Dörfler #include <Roster.h>
42b21d610eSAxel Dörfler #include <Window.h>
43b21d610eSAxel Dörfler 
44b21d610eSAxel Dörfler #include <InterfacePrivate.h>
45b21d610eSAxel Dörfler 
46a10cf76eSAxel Dörfler #include "AlertWindow.h"
47a10cf76eSAxel Dörfler #include "Constants.h"
48a10cf76eSAxel Dörfler #include "RefreshWindow.h"
49a10cf76eSAxel Dörfler #include "MonitorView.h"
50a10cf76eSAxel Dörfler #include "ScreenSettings.h"
51a10cf76eSAxel Dörfler #include "Utility.h"
52a10cf76eSAxel Dörfler 
53a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
54a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
55a10cf76eSAxel Dörfler  * adopted.
56a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
57a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
58a10cf76eSAxel Dörfler  * be using this.
59a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
60a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
61a10cf76eSAxel Dörfler  */
62a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
63a10cf76eSAxel Dörfler 
64a10cf76eSAxel Dörfler 
65c9e8f97aSAdrien Destugues #undef B_TRANSLATE_CONTEXT
66c9e8f97aSAdrien Destugues #define B_TRANSLATE_CONTEXT "Screen"
67c9e8f97aSAdrien Destugues 
68c9e8f97aSAdrien Destugues 
6975c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
70c5d80d47SAxel Dörfler 
71a10cf76eSAxel Dörfler // list of officially supported colour spaces
72a10cf76eSAxel Dörfler static const struct {
73a10cf76eSAxel Dörfler 	color_space	space;
74a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
75a10cf76eSAxel Dörfler 	const char*	label;
76a10cf76eSAxel Dörfler } kColorSpaces[] = {
77*26747978SAdrien Destugues 	{ B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") },
78c9e8f97aSAdrien Destugues 	{ B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") },
79c9e8f97aSAdrien Destugues 	{ B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") },
80c9e8f97aSAdrien Destugues 	{ B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") },
81c9e8f97aSAdrien Destugues 	{ B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") }
82a10cf76eSAxel Dörfler };
83b21d610eSAxel Dörfler static const int32 kColorSpaceCount
84b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
85a10cf76eSAxel Dörfler 
86a10cf76eSAxel Dörfler // list of standard refresh rates
87a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
88b21d610eSAxel Dörfler static const int32 kRefreshRateCount
89b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
90a10cf76eSAxel Dörfler 
91a10cf76eSAxel Dörfler // list of combine modes
92a10cf76eSAxel Dörfler static const struct {
93a10cf76eSAxel Dörfler 	combine_mode	mode;
94a10cf76eSAxel Dörfler 	const char		*name;
95a10cf76eSAxel Dörfler } kCombineModes[] = {
96c9e8f97aSAdrien Destugues 	{ kCombineDisable, B_TRANSLATE("disable") },
97c9e8f97aSAdrien Destugues 	{ kCombineHorizontally, B_TRANSLATE("horizontally") },
98c9e8f97aSAdrien Destugues 	{ kCombineVertically, B_TRANSLATE("vertically") }
99a10cf76eSAxel Dörfler };
100b21d610eSAxel Dörfler static const int32 kCombineModeCount
101b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
10229e8a73aSAxel Dörfler 
103a10cf76eSAxel Dörfler 
104a10cf76eSAxel Dörfler static BString
105a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
106a10cf76eSAxel Dörfler {
107a10cf76eSAxel Dörfler 	switch (mode) {
108a10cf76eSAxel Dörfler 		case 0:		return "disabled";
109a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
110a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
111a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
112a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
113a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
114a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
115a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
116a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
117a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
118a10cf76eSAxel Dörfler 		default:
119a10cf76eSAxel Dörfler 		{
120a10cf76eSAxel Dörfler 			BString name;
121a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
122a10cf76eSAxel Dörfler 
123a10cf76eSAxel Dörfler 			return name;
124a10cf76eSAxel Dörfler 		}
125a10cf76eSAxel Dörfler 	}
126a10cf76eSAxel Dörfler }
127a10cf76eSAxel Dörfler 
128a10cf76eSAxel Dörfler 
129a10cf76eSAxel Dörfler static void
130a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
131a10cf76eSAxel Dörfler {
132a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
133a10cf76eSAxel Dörfler }
134a10cf76eSAxel Dörfler 
135a10cf76eSAxel Dörfler 
136a10cf76eSAxel Dörfler static void
137a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
138a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
139a10cf76eSAxel Dörfler {
1408bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1418bf23e3cSAxel Dörfler 		refresh);
142a10cf76eSAxel Dörfler 	string.UnlockBuffer();
143a10cf76eSAxel Dörfler 
144a10cf76eSAxel Dörfler 	if (appendUnit)
145c9e8f97aSAdrien Destugues 		string << B_TRANSLATE(" Hz");
146a10cf76eSAxel Dörfler }
147a10cf76eSAxel Dörfler 
148a10cf76eSAxel Dörfler 
14907184a9eSAxel Dörfler static const char*
15007184a9eSAxel Dörfler screen_errors(status_t status)
15107184a9eSAxel Dörfler {
15207184a9eSAxel Dörfler 	switch (status) {
15307184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
154c9e8f97aSAdrien Destugues 			return B_TRANSLATE("Unknown mode");
15507184a9eSAxel Dörfler 		// TODO: add more?
15607184a9eSAxel Dörfler 
15707184a9eSAxel Dörfler 		default:
15807184a9eSAxel Dörfler 			return strerror(status);
15907184a9eSAxel Dörfler 	}
16007184a9eSAxel Dörfler }
16107184a9eSAxel Dörfler 
16229e8a73aSAxel Dörfler 
1633dfd20c0SStephan Aßmus //	#pragma mark -
1643dfd20c0SStephan Aßmus 
1653dfd20c0SStephan Aßmus 
1665a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
167b21d610eSAxel Dörfler 	:
168c9e8f97aSAdrien Destugues 	BWindow(settings->WindowFrame(), B_TRANSLATE("Screen"), B_TITLED_WINDOW,
169b21d610eSAxel Dörfler 		B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
170b21d610eSAxel Dörfler 		B_ALL_WORKSPACES),
171199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
172a10cf76eSAxel Dörfler 	fScreenMode(this),
17361c5c89bSAxel Dörfler 	fUndoScreenMode(this),
174abc649b8SWaldemar Kornewald 	fModified(false)
175a10cf76eSAxel Dörfler {
176a10cf76eSAxel Dörfler 	BScreen screen(this);
177a10cf76eSAxel Dörfler 
17812580984SAxel Dörfler 	accelerant_device_info info;
179d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
180d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
18112580984SAxel Dörfler 		fIsVesa = true;
18212580984SAxel Dörfler 
1835de171daSAxel Dörfler 	_UpdateOriginal();
1841fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
185a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
186a10cf76eSAxel Dörfler 
1875a78744bSAxel Dörfler 	fSettings = settings;
1885a78744bSAxel Dörfler 
1895a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1905a78744bSAxel Dörfler 
191c9e8f97aSAdrien Destugues 	BPopUpMenu *popUpMenu = new BPopUpMenu(B_TRANSLATE("Current workspace"),
192c9e8f97aSAdrien Destugues 		true, true);
193c9e8f97aSAdrien Destugues 	fAllWorkspacesItem = new BMenuItem(B_TRANSLATE("All workspaces"),
194d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1955a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
196c9e8f97aSAdrien Destugues 	BMenuItem *item = new BMenuItem(B_TRANSLATE("Current workspace"),
197d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
198b72c4836SAlexandre Deckner 
1995a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
20027c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
2015a78744bSAxel Dörfler 
202b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
203b21d610eSAxel Dörfler 		popUpMenu, NULL);
2045a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
205a10cf76eSAxel Dörfler 
206a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
207a10cf76eSAxel Dörfler 
208b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2098bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
210b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
211b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
212a10cf76eSAxel Dörfler 
21312966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
21412966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
21512966d04SAxel Dörfler 
216c9e8f97aSAdrien Destugues 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0),
217c9e8f97aSAdrien Destugues 		B_TRANSLATE("monitor"), screen.Frame().IntegerWidth() + 1,
218c9e8f97aSAdrien Destugues 		screen.Frame().IntegerHeight() + 1);
219b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2205a78744bSAxel Dörfler 
221c9e8f97aSAdrien Destugues 	fColumnsControl = new BTextControl(B_TRANSLATE("Columns:"), "0",
222b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
223c9e8f97aSAdrien Destugues 	fRowsControl = new BTextControl(B_TRANSLATE("Rows:"), "0",
224b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
225b21d610eSAxel Dörfler 
226b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
227c9e8f97aSAdrien Destugues 		.Add(new BStringView("", B_TRANSLATE("Workspaces")), 0, 0, 3)
228b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
229b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
230b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
231b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
232b21d610eSAxel Dörfler 			.End()
233b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
234b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
235b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
236b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
23725fd5c7bSAlex Wilson 			.End()
23825fd5c7bSAlex Wilson 		.View());
239b21d610eSAxel Dörfler 
240b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
241c9e8f97aSAdrien Destugues 		B_TRANSLATE("Set background" B_UTF8_ELLIPSIS),
242b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
243b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
244b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
245a10cf76eSAxel Dörfler 
246a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
247a10cf76eSAxel Dörfler 
248b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
249b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
25025fd5c7bSAlex Wilson 	BGroupView* outerControlsView = new BGroupView(B_VERTICAL, 10.0);
25125fd5c7bSAlex Wilson 	outerControlsView->GroupLayout()->SetInsets(10, 10, 10, 10);
252b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
253a10cf76eSAxel Dörfler 
254c9e8f97aSAdrien Destugues 	fResolutionMenu = new BPopUpMenu(B_TRANSLATE("resolution"), true, true);
255a10cf76eSAxel Dörfler 
25666ab1666SAxel Dörfler 	uint16 maxWidth = 0;
25766ab1666SAxel Dörfler 	uint16 maxHeight = 0;
25866ab1666SAxel Dörfler 	uint16 previousWidth = 0;
25966ab1666SAxel Dörfler 	uint16 previousHeight = 0;
260a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
261a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
262a10cf76eSAxel Dörfler 
263a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
264a10cf76eSAxel Dörfler 			continue;
265a10cf76eSAxel Dörfler 
266a10cf76eSAxel Dörfler 		previousWidth = mode.width;
267a10cf76eSAxel Dörfler 		previousHeight = mode.height;
26866ab1666SAxel Dörfler 		if (maxWidth < mode.width)
26966ab1666SAxel Dörfler 			maxWidth = mode.width;
27066ab1666SAxel Dörfler 		if (maxHeight < mode.height)
27166ab1666SAxel Dörfler 			maxHeight = mode.height;
272a10cf76eSAxel Dörfler 
273a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
274a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
275a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
276a10cf76eSAxel Dörfler 
277a10cf76eSAxel Dörfler 		BString name;
278a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
279a10cf76eSAxel Dörfler 
280a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
281a10cf76eSAxel Dörfler 	}
282a10cf76eSAxel Dörfler 
28366ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
28466ab1666SAxel Dörfler 
285c9e8f97aSAdrien Destugues 	fResolutionField = new BMenuField("ResolutionMenu",
286c9e8f97aSAdrien Destugues 		B_TRANSLATE("Resolution:"), fResolutionMenu, NULL);
287a10cf76eSAxel Dörfler 
288c9e8f97aSAdrien Destugues 	fColorsMenu = new BPopUpMenu(B_TRANSLATE("colors"), true, false);
289a10cf76eSAxel Dörfler 
290a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
2911fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
2921fc4cb1fSAxel Dörfler 			continue;
2931fc4cb1fSAxel Dörfler 
294a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
295a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
296a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
297a10cf76eSAxel Dörfler 
2981fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
2991fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
3001fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
3011fc4cb1fSAxel Dörfler 
3021fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
303a10cf76eSAxel Dörfler 	}
304a10cf76eSAxel Dörfler 
305c9e8f97aSAdrien Destugues 	fColorsField = new BMenuField("ColorsMenu", B_TRANSLATE("Colors:"),
306c9e8f97aSAdrien Destugues 		fColorsMenu, NULL);
307a10cf76eSAxel Dörfler 
308c9e8f97aSAdrien Destugues 	fRefreshMenu = new BPopUpMenu(B_TRANSLATE("refresh rate"), true, true);
309a10cf76eSAxel Dörfler 
31029e8a73aSAxel Dörfler 	BMessage *message;
31129e8a73aSAxel Dörfler 
31229e8a73aSAxel Dörfler 	float min, max;
31329e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
31429e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
31529e8a73aSAxel Dörfler 		// frequency, like the VESA driver
31629e8a73aSAxel Dörfler 		BString name;
317c9e8f97aSAdrien Destugues 		name << min << B_TRANSLATE(" Hz");
31829e8a73aSAxel Dörfler 
31929e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
32029e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
32129e8a73aSAxel Dörfler 
32229e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
32329e8a73aSAxel Dörfler 		item->SetEnabled(false);
32429e8a73aSAxel Dörfler 	} else {
32570a2b1b5SAxel Dörfler 		monitor_info info;
32670a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
32770a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
32870a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
32970a2b1b5SAxel Dörfler 		}
33070a2b1b5SAxel Dörfler 
331a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
33270a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
33370a2b1b5SAxel Dörfler 				continue;
33470a2b1b5SAxel Dörfler 
335a10cf76eSAxel Dörfler 			BString name;
336c9e8f97aSAdrien Destugues 			name << kRefreshRates[i] << B_TRANSLATE(" Hz");
337a10cf76eSAxel Dörfler 
33829e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
339a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
340a10cf76eSAxel Dörfler 
341a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
342a10cf76eSAxel Dörfler 		}
343a10cf76eSAxel Dörfler 
34429e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
345a10cf76eSAxel Dörfler 
346c9e8f97aSAdrien Destugues 		fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
347c9e8f97aSAdrien Destugues 			message);
348a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
34929e8a73aSAxel Dörfler 	}
350a10cf76eSAxel Dörfler 
351c9e8f97aSAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"),
352b21d610eSAxel Dörfler 		fRefreshMenu, NULL);
353b21d610eSAxel Dörfler 
35412580984SAxel Dörfler 	if (_IsVesa())
35512580984SAxel Dörfler 		fRefreshField->Hide();
356a10cf76eSAxel Dörfler 
357a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
358a10cf76eSAxel Dörfler 	{
359a10cf76eSAxel Dörfler 		bool dummy;
360a10cf76eSAxel Dörfler 		uint32 dummy32;
361a10cf76eSAxel Dörfler 		bool multiMonSupport;
362a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
363a10cf76eSAxel Dörfler 		bool tvStandardSupport;
364a10cf76eSAxel Dörfler 
365a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
366a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
367a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
368a10cf76eSAxel Dörfler 
369a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
370a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
371a10cf76eSAxel Dörfler 
372c9e8f97aSAdrien Destugues 		fCombineMenu = new BPopUpMenu(B_TRANSLATE("CombineDisplays"),
373c9e8f97aSAdrien Destugues 			true, true);
374a10cf76eSAxel Dörfler 
375a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
376a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
377a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
378a10cf76eSAxel Dörfler 
379d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
380d1516993SAxel Dörfler 				message));
381a10cf76eSAxel Dörfler 		}
382a10cf76eSAxel Dörfler 
383b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
384c9e8f97aSAdrien Destugues 			B_TRANSLATE("Combine displays:"), fCombineMenu, NULL);
385a10cf76eSAxel Dörfler 
386a10cf76eSAxel Dörfler 		if (!multiMonSupport)
387df3f5bacSStephan Aßmus 			fCombineField->Hide();
388a10cf76eSAxel Dörfler 
389c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu = new BPopUpMenu(B_TRANSLATE("SwapDisplays"),
390c9e8f97aSAdrien Destugues 			true, true);
391a10cf76eSAxel Dörfler 
392a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
393a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
394a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
395c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message));
396a10cf76eSAxel Dörfler 
397a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
398a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
399c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message));
400a10cf76eSAxel Dörfler 
401c9e8f97aSAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu",
402c9e8f97aSAdrien Destugues 			B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu, NULL);
403a10cf76eSAxel Dörfler 
404a10cf76eSAxel Dörfler 		if (!multiMonSupport)
405df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
406a10cf76eSAxel Dörfler 
407c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu = new BPopUpMenu(B_TRANSLATE("UseLaptopPanel"),
408c9e8f97aSAdrien Destugues 			true, true);
409a10cf76eSAxel Dörfler 
410a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
411a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
412a10cf76eSAxel Dörfler 		message->AddBool("use", false);
413c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"),
414c9e8f97aSAdrien Destugues 			message));
415a10cf76eSAxel Dörfler 
416a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
417a10cf76eSAxel Dörfler 		message->AddBool("use", true);
418c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"),
419c9e8f97aSAdrien Destugues 			message));
420a10cf76eSAxel Dörfler 
421b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
422c9e8f97aSAdrien Destugues 			B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu, NULL);
423a10cf76eSAxel Dörfler 
424a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
425df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
426a10cf76eSAxel Dörfler 
427c9e8f97aSAdrien Destugues 		fTVStandardMenu = new BPopUpMenu(B_TRANSLATE("TVStandard"), true, true);
428a10cf76eSAxel Dörfler 
429a10cf76eSAxel Dörfler 		// arbitrary limit
430a10cf76eSAxel Dörfler 		uint32 i;
431a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
432a10cf76eSAxel Dörfler 			uint32 mode;
433a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
434a10cf76eSAxel Dörfler 				break;
435a10cf76eSAxel Dörfler 
436a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
437a10cf76eSAxel Dörfler 
438a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
439a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
440a10cf76eSAxel Dörfler 
441a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
442a10cf76eSAxel Dörfler 		}
443a10cf76eSAxel Dörfler 
444c9e8f97aSAdrien Destugues 		fTVStandardField = new BMenuField("tv standard",
445c9e8f97aSAdrien Destugues 			B_TRANSLATE("Video format:"), fTVStandardMenu, NULL);
446df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
447a10cf76eSAxel Dörfler 
448b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
449df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
450a10cf76eSAxel Dörfler 	}
451a10cf76eSAxel Dörfler 
45225fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
45325fd5c7bSAlex Wilson 		.AddGrid(5.0, 5.0)
454b21d610eSAxel Dörfler 			.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
455b21d610eSAxel Dörfler 			.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
456b21d610eSAxel Dörfler 			.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
457b21d610eSAxel Dörfler 			.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
458b21d610eSAxel Dörfler 			.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
459b21d610eSAxel Dörfler 			.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
46025fd5c7bSAlex Wilson 			.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT)
46125fd5c7bSAlex Wilson 		.End();
462df3f5bacSStephan Aßmus 
463abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
464abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
465b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
466a10cf76eSAxel Dörfler 
467c9e8f97aSAdrien Destugues 	fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"),
468df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
469df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
47025fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
471b21d610eSAxel Dörfler 		.AddGlue()
47225fd5c7bSAlex Wilson 			.AddGroup(B_HORIZONTAL)
47325fd5c7bSAlex Wilson 			.AddGlue()
47425fd5c7bSAlex Wilson 			.Add(fApplyButton);
475b21d610eSAxel Dörfler 
476c9e8f97aSAdrien Destugues 	fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"),
477b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
478b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
479b21d610eSAxel Dörfler 
48025fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(this, B_VERTICAL, 10.0)
481b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
482b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
483b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
48425fd5c7bSAlex Wilson 				.AddStrut(controlsBox->TopBorderOffset() - 1)
485b21d610eSAxel Dörfler 				.Add(screenBox)
486b21d610eSAxel Dörfler 			.End()
487b21d610eSAxel Dörfler 			.Add(controlsBox)
488b21d610eSAxel Dörfler 		.End()
489b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
490b21d610eSAxel Dörfler 			.Add(fRevertButton)
491b21d610eSAxel Dörfler 			.AddGlue();
492b21d610eSAxel Dörfler 
4935de171daSAxel Dörfler 	_UpdateControls();
49412966d04SAxel Dörfler 	_UpdateMonitor();
495a10cf76eSAxel Dörfler }
496a10cf76eSAxel Dörfler 
497a10cf76eSAxel Dörfler 
498a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
499a10cf76eSAxel Dörfler {
500a10cf76eSAxel Dörfler 	delete fSettings;
501a10cf76eSAxel Dörfler }
502a10cf76eSAxel Dörfler 
503a10cf76eSAxel Dörfler 
504a10cf76eSAxel Dörfler bool
505a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
506a10cf76eSAxel Dörfler {
507a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
508199893c3SAxel Dörfler 
509199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
510199893c3SAxel Dörfler 	screen_mode vesaMode;
511199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
512199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
51312580984SAxel Dörfler 		if (status < B_OK) {
514c9e8f97aSAdrien Destugues 			BString warning = B_TRANSLATE("Could not write VESA mode settings"
515c9e8f97aSAdrien Destugues 				" file:\n\t");
51612580984SAxel Dörfler 			warning << strerror(status);
517c9e8f97aSAdrien Destugues 			(new BAlert("VesaAlert", warning.String(), B_TRANSLATE("OK"), NULL,
518c9e8f97aSAdrien Destugues 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
51912580984SAxel Dörfler 		}
52012580984SAxel Dörfler 	}
52112580984SAxel Dörfler 
522a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
523a10cf76eSAxel Dörfler 
524a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
525a10cf76eSAxel Dörfler }
526a10cf76eSAxel Dörfler 
527a10cf76eSAxel Dörfler 
5285de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5291fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
530a10cf76eSAxel Dörfler */
531a10cf76eSAxel Dörfler void
5325de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
533a10cf76eSAxel Dörfler {
534a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
535a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
536a10cf76eSAxel Dörfler 
537a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
538a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
539a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
540a10cf76eSAxel Dörfler 			continue;
541a10cf76eSAxel Dörfler 
542a10cf76eSAxel Dörfler 		BString name;
543a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
544a10cf76eSAxel Dörfler 
545a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
546a10cf76eSAxel Dörfler 		if (item != NULL)
547a10cf76eSAxel Dörfler 			item->SetEnabled(true);
548a10cf76eSAxel Dörfler 	}
549a10cf76eSAxel Dörfler }
550a10cf76eSAxel Dörfler 
551a10cf76eSAxel Dörfler 
5525de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5535de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5545de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5555de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
556a10cf76eSAxel Dörfler */
557a10cf76eSAxel Dörfler void
5585de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
559a10cf76eSAxel Dörfler {
5601fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5611fc4cb1fSAxel Dörfler 	int32 index = 0;
5621fc4cb1fSAxel Dörfler 
563a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5641fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5651fc4cb1fSAxel Dörfler 			continue;
5661fc4cb1fSAxel Dörfler 
567a10cf76eSAxel Dörfler 		bool supported = false;
568a10cf76eSAxel Dörfler 
569a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
570a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
571a10cf76eSAxel Dörfler 
572a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
573a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5741fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
575a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5761fc4cb1fSAxel Dörfler 				supportsAnything = true;
577a10cf76eSAxel Dörfler 				supported = true;
578a10cf76eSAxel Dörfler 				break;
579a10cf76eSAxel Dörfler 			}
580a10cf76eSAxel Dörfler 		}
581a10cf76eSAxel Dörfler 
5821fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
583a10cf76eSAxel Dörfler 		if (item)
584a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
585a10cf76eSAxel Dörfler 	}
5861fc4cb1fSAxel Dörfler 
5871fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5881fc4cb1fSAxel Dörfler 
5891fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5901fc4cb1fSAxel Dörfler 		return;
5911fc4cb1fSAxel Dörfler 
5921fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5931fc4cb1fSAxel Dörfler 
5941fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
5951fc4cb1fSAxel Dörfler 	bool changed = false;
5961fc4cb1fSAxel Dörfler 
5971fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
5981fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
5991fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
6001fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
6011fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6021fc4cb1fSAxel Dörfler 			changed = true;
6031fc4cb1fSAxel Dörfler 		}
6041fc4cb1fSAxel Dörfler 	}
6051fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6061fc4cb1fSAxel Dörfler 		// find the next best item
6071fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6081fc4cb1fSAxel Dörfler 		bool found = false;
6091fc4cb1fSAxel Dörfler 
6101fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6111fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6121fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6131fc4cb1fSAxel Dörfler 				found = true;
6141fc4cb1fSAxel Dörfler 				break;
6151fc4cb1fSAxel Dörfler 			}
6161fc4cb1fSAxel Dörfler 		}
6171fc4cb1fSAxel Dörfler 		if (!found) {
6181fc4cb1fSAxel Dörfler 			// search backwards as well
6191fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6201fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6211fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6221fc4cb1fSAxel Dörfler 					break;
6231fc4cb1fSAxel Dörfler 			}
6241fc4cb1fSAxel Dörfler 		}
6251fc4cb1fSAxel Dörfler 
6261fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6271fc4cb1fSAxel Dörfler 		changed = true;
6281fc4cb1fSAxel Dörfler 	}
6291fc4cb1fSAxel Dörfler 
6301fc4cb1fSAxel Dörfler 	if (changed) {
6311fc4cb1fSAxel Dörfler 		// Update selected space
6321fc4cb1fSAxel Dörfler 
6331fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6341fc4cb1fSAxel Dörfler 		int32 space;
6351fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6361fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6371fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6381fc4cb1fSAxel Dörfler 		}
6391fc4cb1fSAxel Dörfler 	}
640a10cf76eSAxel Dörfler }
641a10cf76eSAxel Dörfler 
642a10cf76eSAxel Dörfler 
6435de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
644a10cf76eSAxel Dörfler void
6455de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
646a10cf76eSAxel Dörfler {
64729e8a73aSAxel Dörfler 	float min, max;
64829e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
64929e8a73aSAxel Dörfler 		return;
650a10cf76eSAxel Dörfler 
65129e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
65229e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
65329e8a73aSAxel Dörfler 		BMessage* message = item->Message();
65429e8a73aSAxel Dörfler 		float refresh;
65529e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
65629e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
657a10cf76eSAxel Dörfler 	}
658a10cf76eSAxel Dörfler }
659a10cf76eSAxel Dörfler 
660a10cf76eSAxel Dörfler 
6615de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
662a10cf76eSAxel Dörfler void
6635de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
664a10cf76eSAxel Dörfler {
665a10cf76eSAxel Dörfler 	BString string;
666a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
667a10cf76eSAxel Dörfler 
668a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
669a10cf76eSAxel Dörfler 	if (item) {
670a10cf76eSAxel Dörfler 		if (!item->IsMarked())
671a10cf76eSAxel Dörfler 			item->SetMarked(true);
67229e8a73aSAxel Dörfler 
673*26747978SAdrien Destugues 		// "Other" items only contains a refresh rate when active
674*26747978SAdrien Destugues 		fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
675a10cf76eSAxel Dörfler 		return;
676a10cf76eSAxel Dörfler 	}
677a10cf76eSAxel Dörfler 
678a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
679a10cf76eSAxel Dörfler 
680a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
681a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
682a10cf76eSAxel Dörfler 
683a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
684a10cf76eSAxel Dörfler 
685c9e8f97aSAdrien Destugues 	string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
686a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
687a10cf76eSAxel Dörfler }
688a10cf76eSAxel Dörfler 
689a10cf76eSAxel Dörfler 
690a10cf76eSAxel Dörfler void
6915de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
692a10cf76eSAxel Dörfler {
693a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
694a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
695a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
696a10cf76eSAxel Dörfler 
697a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
698a10cf76eSAxel Dörfler }
699a10cf76eSAxel Dörfler 
700a10cf76eSAxel Dörfler 
701a10cf76eSAxel Dörfler void
7025de171daSAxel Dörfler ScreenWindow::_UpdateControls()
703a10cf76eSAxel Dörfler {
704b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
705b21d610eSAxel Dörfler 
706a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
707a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
708a10cf76eSAxel Dörfler 		item->SetMarked(true);
709a10cf76eSAxel Dörfler 
710a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
711a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
712a10cf76eSAxel Dörfler 		item->SetMarked(true);
713a10cf76eSAxel Dörfler 
714a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
715a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
716a10cf76eSAxel Dörfler 
717a10cf76eSAxel Dörfler 		uint32 tvStandard;
718a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
719a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
720a10cf76eSAxel Dörfler 			if (!item->IsMarked())
721a10cf76eSAxel Dörfler 				item->SetMarked(true);
722a10cf76eSAxel Dörfler 			break;
723a10cf76eSAxel Dörfler 		}
724a10cf76eSAxel Dörfler 	}
725a10cf76eSAxel Dörfler 
7265de171daSAxel Dörfler 	_CheckResolutionMenu();
7275de171daSAxel Dörfler 	_CheckColorMenu();
7285de171daSAxel Dörfler 	_CheckRefreshMenu();
729a10cf76eSAxel Dörfler 
730a10cf76eSAxel Dörfler 	BString string;
731a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
732a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
733a10cf76eSAxel Dörfler 
734a10cf76eSAxel Dörfler 	if (item != NULL) {
735a10cf76eSAxel Dörfler 		if (!item->IsMarked())
736a10cf76eSAxel Dörfler 			item->SetMarked(true);
737a10cf76eSAxel Dörfler 	} else {
738a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
739a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
740a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
741a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
742a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
743a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
744a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
745a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
746a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
747a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
748a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
749a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
750a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
751a10cf76eSAxel Dörfler 		if (item)
752a10cf76eSAxel Dörfler 			item->SetMarked(true);
753a10cf76eSAxel Dörfler 
754a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
755a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
756a10cf76eSAxel Dörfler 	}
757a10cf76eSAxel Dörfler 
758a10cf76eSAxel Dörfler 	// mark active combine mode
759a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
760a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
761a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
762a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
763a10cf76eSAxel Dörfler 				item->SetMarked(true);
764a10cf76eSAxel Dörfler 			break;
765a10cf76eSAxel Dörfler 		}
766a10cf76eSAxel Dörfler 	}
767a10cf76eSAxel Dörfler 
768a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
769a10cf76eSAxel Dörfler 
7701fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7711fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7721fc4cb1fSAxel Dörfler 			continue;
7731fc4cb1fSAxel Dörfler 
7741fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7751fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
776a10cf76eSAxel Dörfler 			break;
777a10cf76eSAxel Dörfler 		}
7781fc4cb1fSAxel Dörfler 
7791fc4cb1fSAxel Dörfler 		index++;
780a10cf76eSAxel Dörfler 	}
781a10cf76eSAxel Dörfler 
782a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
783a10cf76eSAxel Dörfler 		item->SetMarked(true);
784a10cf76eSAxel Dörfler 
7851fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7865de171daSAxel Dörfler 	_UpdateMonitorView();
7875de171daSAxel Dörfler 	_UpdateRefreshControl();
788a10cf76eSAxel Dörfler 
7895de171daSAxel Dörfler 	_CheckApplyEnabled();
790a10cf76eSAxel Dörfler }
791a10cf76eSAxel Dörfler 
792a10cf76eSAxel Dörfler 
79312580984SAxel Dörfler /*! Reflect active mode in chosen settings */
794a10cf76eSAxel Dörfler void
7955de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
796a10cf76eSAxel Dörfler {
79712580984SAxel Dörfler 	// Usually, this function gets called after a mode
798a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
799a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
800a10cf76eSAxel Dörfler 	// what kind of mode we actually got
801a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
802a10cf76eSAxel Dörfler 	fSelected = fActive;
803a10cf76eSAxel Dörfler 
80412966d04SAxel Dörfler 	_UpdateMonitor();
8055de171daSAxel Dörfler 	_UpdateControls();
806a10cf76eSAxel Dörfler }
807a10cf76eSAxel Dörfler 
808a10cf76eSAxel Dörfler 
809a10cf76eSAxel Dörfler void
810b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
811b21d610eSAxel Dörfler {
812b21d610eSAxel Dörfler 	uint32 columns;
813b21d610eSAxel Dörfler 	uint32 rows;
814b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
815b21d610eSAxel Dörfler 
816b21d610eSAxel Dörfler 	char text[32];
817b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
818b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
819b21d610eSAxel Dörfler 
820b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
821b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
822b21d610eSAxel Dörfler 
823b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
824b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
825b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
826b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
827b21d610eSAxel Dörfler }
828b21d610eSAxel Dörfler 
829b21d610eSAxel Dörfler 
830b21d610eSAxel Dörfler void
831a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
832a10cf76eSAxel Dörfler {
833a10cf76eSAxel Dörfler 	// move window on screen, if necessary
834a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
835a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
836a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
837a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
838a10cf76eSAxel Dörfler 	}
839a10cf76eSAxel Dörfler }
840a10cf76eSAxel Dörfler 
841a10cf76eSAxel Dörfler 
842a10cf76eSAxel Dörfler void
843a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
844a10cf76eSAxel Dörfler {
845abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8465de171daSAxel Dörfler 	_UpdateActiveMode();
847a10cf76eSAxel Dörfler 
8486edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8496edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
850a10cf76eSAxel Dörfler }
851a10cf76eSAxel Dörfler 
852a10cf76eSAxel Dörfler 
853a10cf76eSAxel Dörfler void
854a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
855a10cf76eSAxel Dörfler {
856a10cf76eSAxel Dörfler 	switch (message->what) {
857a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8585de171daSAxel Dörfler 			_CheckApplyEnabled();
859a10cf76eSAxel Dörfler 			break;
860a10cf76eSAxel Dörfler 
861b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
862a10cf76eSAxel Dörfler 		{
863b21d610eSAxel Dörfler 			int32 deltaX = 0;
864b21d610eSAxel Dörfler 			int32 deltaY = 0;
865b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
866b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
867b21d610eSAxel Dörfler 
868b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
869b21d610eSAxel Dörfler 				break;
870b21d610eSAxel Dörfler 
871b21d610eSAxel Dörfler 			uint32 newColumns;
872b21d610eSAxel Dörfler 			uint32 newRows;
873b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
874b21d610eSAxel Dörfler 
875b21d610eSAxel Dörfler 			newColumns += deltaX;
876b21d610eSAxel Dörfler 			newRows += deltaY;
877b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
878b21d610eSAxel Dörfler 
879b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8805de171daSAxel Dörfler 			_CheckApplyEnabled();
881b21d610eSAxel Dörfler 			break;
882abc649b8SWaldemar Kornewald 		}
883b21d610eSAxel Dörfler 
884b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
885b21d610eSAxel Dörfler 		{
886b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
887b21d610eSAxel Dörfler 
888b21d610eSAxel Dörfler 			uint32 rows;
889b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
890b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
891b21d610eSAxel Dörfler 
892b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
893b21d610eSAxel Dörfler 			_CheckApplyEnabled();
894b21d610eSAxel Dörfler 			break;
895b21d610eSAxel Dörfler 		}
896b21d610eSAxel Dörfler 
897b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
898b21d610eSAxel Dörfler 		{
899b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
900b21d610eSAxel Dörfler 
901b21d610eSAxel Dörfler 			uint32 columns;
902b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
903b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
904b21d610eSAxel Dörfler 
905b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
906b21d610eSAxel Dörfler 			_CheckApplyEnabled();
907a10cf76eSAxel Dörfler 			break;
908a10cf76eSAxel Dörfler 		}
909a10cf76eSAxel Dörfler 
910a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
911a10cf76eSAxel Dörfler 		{
912a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
913a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
914a10cf76eSAxel Dörfler 
9155de171daSAxel Dörfler 			_CheckColorMenu();
9165de171daSAxel Dörfler 			_CheckRefreshMenu();
917a10cf76eSAxel Dörfler 
9185de171daSAxel Dörfler 			_UpdateMonitorView();
9195de171daSAxel Dörfler 			_UpdateRefreshControl();
920a10cf76eSAxel Dörfler 
9215de171daSAxel Dörfler 			_CheckApplyEnabled();
922a10cf76eSAxel Dörfler 			break;
923a10cf76eSAxel Dörfler 		}
924a10cf76eSAxel Dörfler 
925a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
926a10cf76eSAxel Dörfler 		{
9271fc4cb1fSAxel Dörfler 			int32 space;
9281fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9291fc4cb1fSAxel Dörfler 				break;
930a10cf76eSAxel Dörfler 
9311fc4cb1fSAxel Dörfler 			int32 index;
9321fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9331fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9341fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9351fc4cb1fSAxel Dörfler 
9361fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9371fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
938a10cf76eSAxel Dörfler 
9395de171daSAxel Dörfler 			_CheckApplyEnabled();
940a10cf76eSAxel Dörfler 			break;
941a10cf76eSAxel Dörfler 		}
942a10cf76eSAxel Dörfler 
943a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
944a40498e2SWaldemar Kornewald 		{
945a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
946c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
9471fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
948a10cf76eSAxel Dörfler 
9495de171daSAxel Dörfler 			_CheckApplyEnabled();
950a10cf76eSAxel Dörfler 			break;
951a40498e2SWaldemar Kornewald 		}
952a10cf76eSAxel Dörfler 
953a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
954a10cf76eSAxel Dörfler 		{
95529e8a73aSAxel Dörfler 			// make sure menu shows something useful
9565de171daSAxel Dörfler 			_UpdateRefreshControl();
957a10cf76eSAxel Dörfler 
95829e8a73aSAxel Dörfler 			float min = 0, max = 999;
95929e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
96029e8a73aSAxel Dörfler 			if (min < gMinRefresh)
96129e8a73aSAxel Dörfler 				min = gMinRefresh;
96229e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
96329e8a73aSAxel Dörfler 				max = gMaxRefresh;
96429e8a73aSAxel Dörfler 
96570a2b1b5SAxel Dörfler 			monitor_info info;
96670a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
96770a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
96870a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
96970a2b1b5SAxel Dörfler 			}
97070a2b1b5SAxel Dörfler 
971c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
97270a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
97370a2b1b5SAxel Dörfler 				min, max);
974a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
975a10cf76eSAxel Dörfler 			break;
976a10cf76eSAxel Dörfler 		}
977a10cf76eSAxel Dörfler 
978a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
979a10cf76eSAxel Dörfler 		{
980a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
981a10cf76eSAxel Dörfler 			// select the refresh rate chosen
982a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
983a10cf76eSAxel Dörfler 
9845de171daSAxel Dörfler 			_UpdateRefreshControl();
9855de171daSAxel Dörfler 			_CheckApplyEnabled();
986a10cf76eSAxel Dörfler 			break;
987a10cf76eSAxel Dörfler 		}
988a10cf76eSAxel Dörfler 
989a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
990a10cf76eSAxel Dörfler 		{
991a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
992a10cf76eSAxel Dörfler 			int32 mode;
993a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
994a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
995a10cf76eSAxel Dörfler 
9965de171daSAxel Dörfler 			_CheckResolutionMenu();
9975de171daSAxel Dörfler 			_CheckApplyEnabled();
998a10cf76eSAxel Dörfler 			break;
999a10cf76eSAxel Dörfler 		}
1000a10cf76eSAxel Dörfler 
1001a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1002a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10035de171daSAxel Dörfler 			_CheckApplyEnabled();
1004a10cf76eSAxel Dörfler 			break;
1005a10cf76eSAxel Dörfler 
1006a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1007a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10085de171daSAxel Dörfler 			_CheckApplyEnabled();
1009a10cf76eSAxel Dörfler 			break;
1010a10cf76eSAxel Dörfler 
1011a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1012a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10135de171daSAxel Dörfler 			_CheckApplyEnabled();
1014a10cf76eSAxel Dörfler 			break;
1015a10cf76eSAxel Dörfler 
1016df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10176f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10186f095d6aSRyan Leavengood 				app_info info;
10196f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10206f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10216f095d6aSRyan Leavengood 			}
1022df3f5bacSStephan Aßmus 			break;
1023df3f5bacSStephan Aßmus 
1024a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1025a10cf76eSAxel Dörfler 		{
10264be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1027a10cf76eSAxel Dörfler 			fSelected.width = 640;
1028a10cf76eSAxel Dörfler 			fSelected.height = 480;
1029a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1030a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1031a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1032a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1033a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1034a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1035a10cf76eSAxel Dörfler 
1036b21d610eSAxel Dörfler 			// TODO: workspace defaults
1037abc649b8SWaldemar Kornewald 
10385de171daSAxel Dörfler 			_UpdateControls();
1039a10cf76eSAxel Dörfler 			break;
1040a10cf76eSAxel Dörfler 		}
1041a10cf76eSAxel Dörfler 
104210e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
104361c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10445de171daSAxel Dörfler 			_UpdateActiveMode();
1045abc649b8SWaldemar Kornewald 			break;
1046abc649b8SWaldemar Kornewald 
1047abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1048abc649b8SWaldemar Kornewald 		{
1049abc649b8SWaldemar Kornewald 			fModified = false;
1050199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1051abc649b8SWaldemar Kornewald 
1052b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1053b21d610eSAxel Dörfler 			// number of workspaces
1054b21d610eSAxel Dörfler 
1055b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1056b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1057b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1058b21d610eSAxel Dörfler 
1059a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10605de171daSAxel Dörfler 			_UpdateActiveMode();
1061a10cf76eSAxel Dörfler 			break;
1062abc649b8SWaldemar Kornewald 		}
1063a10cf76eSAxel Dörfler 
1064a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10655de171daSAxel Dörfler 			_Apply();
1066a10cf76eSAxel Dörfler 			break;
1067a10cf76eSAxel Dörfler 
1068abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1069abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1070abc649b8SWaldemar Kornewald 			fModified = true;
10715de171daSAxel Dörfler 			_UpdateActiveMode();
1072a10cf76eSAxel Dörfler 			break;
1073a10cf76eSAxel Dörfler 
1074a10cf76eSAxel Dörfler 		default:
1075a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1076a10cf76eSAxel Dörfler 			break;
1077a10cf76eSAxel Dörfler 	}
1078a10cf76eSAxel Dörfler }
1079a10cf76eSAxel Dörfler 
1080a10cf76eSAxel Dörfler 
108112580984SAxel Dörfler status_t
108212580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
108312580984SAxel Dörfler {
108412580984SAxel Dörfler 	BPath path;
108512580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
108612580984SAxel Dörfler 	if (status < B_OK)
108712580984SAxel Dörfler 		return status;
108812580984SAxel Dörfler 
108912580984SAxel Dörfler 	path.Append("kernel/drivers");
109012580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
109112580984SAxel Dörfler 	if (status < B_OK)
109212580984SAxel Dörfler 		return status;
109312580984SAxel Dörfler 
109412580984SAxel Dörfler 	path.Append("vesa");
109512580984SAxel Dörfler 	BFile file;
109612580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
109712580984SAxel Dörfler 	if (status < B_OK)
109812580984SAxel Dörfler 		return status;
109912580984SAxel Dörfler 
110012580984SAxel Dörfler 	char buffer[256];
110112580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
110212580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
110312580984SAxel Dörfler 
110412580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
110512580984SAxel Dörfler 	if (bytesWritten < B_OK)
110612580984SAxel Dörfler 		return bytesWritten;
110712580984SAxel Dörfler 
110812580984SAxel Dörfler 	return B_OK;
110912580984SAxel Dörfler }
111012580984SAxel Dörfler 
111112580984SAxel Dörfler 
1112b21d610eSAxel Dörfler BButton*
1113b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1114b21d610eSAxel Dörfler {
1115b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1116b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1117b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1118b21d610eSAxel Dörfler 
1119b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1120b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1121b21d610eSAxel Dörfler 
1122b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1123b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1124b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1125b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1126b21d610eSAxel Dörfler 
1127b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1128b21d610eSAxel Dörfler 	return button;
1129b21d610eSAxel Dörfler }
1130b21d610eSAxel Dörfler 
1131b21d610eSAxel Dörfler 
1132b21d610eSAxel Dörfler BButton*
1133b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1134b21d610eSAxel Dörfler {
1135b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1136b21d610eSAxel Dörfler }
1137b21d610eSAxel Dörfler 
1138b21d610eSAxel Dörfler 
1139a10cf76eSAxel Dörfler void
11401fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11411fc4cb1fSAxel Dörfler {
11421fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11431fc4cb1fSAxel Dörfler 
11441fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11451fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11461fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11471fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11481fc4cb1fSAxel Dörfler 				break;
11491fc4cb1fSAxel Dörfler 			}
11501fc4cb1fSAxel Dörfler 		}
11511fc4cb1fSAxel Dörfler 	}
11521fc4cb1fSAxel Dörfler }
11531fc4cb1fSAxel Dörfler 
11541fc4cb1fSAxel Dörfler 
11551fc4cb1fSAxel Dörfler void
11565de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1157a10cf76eSAxel Dörfler {
115827c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
115927c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1160b21d610eSAxel Dörfler 
1161b21d610eSAxel Dörfler 	uint32 columns;
1162b21d610eSAxel Dörfler 	uint32 rows;
1163b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1164b21d610eSAxel Dörfler 
1165b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1166b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11675de171daSAxel Dörfler 		|| fSelected != fOriginal);
1168a10cf76eSAxel Dörfler }
1169a10cf76eSAxel Dörfler 
1170a10cf76eSAxel Dörfler 
1171a10cf76eSAxel Dörfler void
11725de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1173abc649b8SWaldemar Kornewald {
1174b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1175b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1176b21d610eSAxel Dörfler 
1177abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1178abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1179abc649b8SWaldemar Kornewald }
1180abc649b8SWaldemar Kornewald 
1181abc649b8SWaldemar Kornewald 
1182abc649b8SWaldemar Kornewald void
118312966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
118412966d04SAxel Dörfler {
118512966d04SAxel Dörfler 	monitor_info info;
118612966d04SAxel Dörfler 	float diagonalInches;
118712966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
118855030977SAxel Dörfler 	if (status == B_OK) {
11891a8af605SAxel Dörfler 		char text[512];
119066ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
119166ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
119212966d04SAxel Dörfler 
119312966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
119412966d04SAxel Dörfler 
119512966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
119612966d04SAxel Dörfler 			fMonitorInfo->Show();
119755030977SAxel Dörfler 	} else {
119855030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
119955030977SAxel Dörfler 			fMonitorInfo->Hide();
120055030977SAxel Dörfler 	}
1201af8f9c31SAxel Dörfler 
120255030977SAxel Dörfler 	char text[512];
12031a8af605SAxel Dörfler 	size_t length = 0;
12041a8af605SAxel Dörfler 	text[0] = 0;
12051a8af605SAxel Dörfler 
120655030977SAxel Dörfler 	if (status == B_OK) {
1207af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1208af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1209af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12101a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1211c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12129c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1213c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12141a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12151a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12161a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1217af8f9c31SAxel Dörfler 		}
12181a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12191a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1220c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12211a8af605SAxel Dörfler 				info.serial_number);
12221a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12231a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12241a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12251a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12261a8af605SAxel Dörfler 	 		}
12271a8af605SAxel Dörfler 		}
122855030977SAxel Dörfler 	}
122961c5c89bSAxel Dörfler 
123061c5c89bSAxel Dörfler 	// Add info about the graphics device
123161c5c89bSAxel Dörfler 
123261c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
123361c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
123461c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
123561c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
123661c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123761c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
123861c5c89bSAxel Dörfler 				deviceInfo.chipset);
123961c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
124061c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
124161c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
124261c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
124361c5c89bSAxel Dörfler 		}
124461c5c89bSAxel Dörfler 	}
124561c5c89bSAxel Dörfler 
12461a8af605SAxel Dörfler 	if (text[0])
12471a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
124812966d04SAxel Dörfler }
124912966d04SAxel Dörfler 
125012966d04SAxel Dörfler 
125112966d04SAxel Dörfler void
12521fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12531fc4cb1fSAxel Dörfler {
12541fc4cb1fSAxel Dörfler 	BString string;
1255c9e8f97aSAdrien Destugues 	string << fSelected.BitsPerPixel() << B_TRANSLATE(" bits/pixel");
12561fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12571fc4cb1fSAxel Dörfler }
12581fc4cb1fSAxel Dörfler 
12591fc4cb1fSAxel Dörfler 
12601fc4cb1fSAxel Dörfler void
12615de171daSAxel Dörfler ScreenWindow::_Apply()
1262a10cf76eSAxel Dörfler {
1263abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
126461c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
126561c5c89bSAxel Dörfler 
126607184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
126707184a9eSAxel Dörfler 	if (status == B_OK) {
1268abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1269abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1270abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1271abc649b8SWaldemar Kornewald 		display_mode newMode;
1272abc649b8SWaldemar Kornewald 		BScreen screen(this);
1273abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1274abc649b8SWaldemar Kornewald 
1275abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1276abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1277abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1278abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1279abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1280abc649b8SWaldemar Kornewald 			}
1281199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1282199893c3SAxel Dörfler 		} else {
1283199893c3SAxel Dörfler 			if (current_workspace() == 0)
1284199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1285abc649b8SWaldemar Kornewald 		}
1286abc649b8SWaldemar Kornewald 
1287a10cf76eSAxel Dörfler 		fActive = fSelected;
1288a10cf76eSAxel Dörfler 
1289abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1290a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1291a10cf76eSAxel Dörfler 		window->Show();
129207184a9eSAxel Dörfler 	} else {
129307184a9eSAxel Dörfler 		char message[256];
129407184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1295c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1296c9e8f97aSAdrien Destugues 			screen_errors(status));
1297c9e8f97aSAdrien Destugues 		BAlert* alert = new BAlert(B_TRANSLATE("Screen Alert"), message,
1298c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
129907184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
130007184a9eSAxel Dörfler 		alert->Go();
1301a10cf76eSAxel Dörfler 	}
130207184a9eSAxel Dörfler }
130307184a9eSAxel Dörfler 
1304