xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision c33a865c7c3ce73ab74354a41ac83cf4de20d726)
1a10cf76eSAxel Dörfler /*
27e44de36SRene Gollent  * Copyright 2001-2012, 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
97e44de36SRene Gollent  *		Rene Gollent, rene@gollent.com
10a10cf76eSAxel Dörfler  *		Thomas Kurschel
11a10cf76eSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
12df3f5bacSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
13b72c4836SAlexandre Deckner  *		Alexandre Deckner, alex@zappotek.com
14a10cf76eSAxel Dörfler  */
15a10cf76eSAxel Dörfler 
16a10cf76eSAxel Dörfler 
17b21d610eSAxel Dörfler #include "ScreenWindow.h"
18b21d610eSAxel Dörfler 
19b21d610eSAxel Dörfler #include <stdio.h>
20b21d610eSAxel Dörfler #include <stdlib.h>
21b21d610eSAxel Dörfler #include <string.h>
22b21d610eSAxel Dörfler 
23b21d610eSAxel Dörfler #include <Alert.h>
24b21d610eSAxel Dörfler #include <Application.h>
25b21d610eSAxel Dörfler #include <Box.h>
26b21d610eSAxel Dörfler #include <Button.h>
27c9e8f97aSAdrien Destugues #include <Catalog.h>
28b21d610eSAxel Dörfler #include <Directory.h>
29b21d610eSAxel Dörfler #include <File.h>
30b21d610eSAxel Dörfler #include <FindDirectory.h>
31b21d610eSAxel Dörfler #include <InterfaceDefs.h>
32b21d610eSAxel Dörfler #include <LayoutBuilder.h>
33b21d610eSAxel Dörfler #include <MenuBar.h>
34b21d610eSAxel Dörfler #include <MenuItem.h>
35b21d610eSAxel Dörfler #include <MenuField.h>
36b21d610eSAxel Dörfler #include <Messenger.h>
37b21d610eSAxel Dörfler #include <Path.h>
38b21d610eSAxel Dörfler #include <PopUpMenu.h>
39b21d610eSAxel Dörfler #include <Screen.h>
40b21d610eSAxel Dörfler #include <String.h>
41b21d610eSAxel Dörfler #include <StringView.h>
42b21d610eSAxel Dörfler #include <Roster.h>
43b21d610eSAxel Dörfler #include <Window.h>
44b21d610eSAxel Dörfler 
45b21d610eSAxel Dörfler #include <InterfacePrivate.h>
46b21d610eSAxel Dörfler 
47a10cf76eSAxel Dörfler #include "AlertWindow.h"
48a10cf76eSAxel Dörfler #include "Constants.h"
49a10cf76eSAxel Dörfler #include "RefreshWindow.h"
50a10cf76eSAxel Dörfler #include "MonitorView.h"
51a10cf76eSAxel Dörfler #include "ScreenSettings.h"
52a10cf76eSAxel Dörfler #include "Utility.h"
53a10cf76eSAxel Dörfler 
54a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
55a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
56a10cf76eSAxel Dörfler  * adopted.
57a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
58a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
59a10cf76eSAxel Dörfler  * be using this.
60a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
61a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
62a10cf76eSAxel Dörfler  */
63a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
64a10cf76eSAxel Dörfler 
65a10cf76eSAxel Dörfler 
66546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
67546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "Screen"
68c9e8f97aSAdrien Destugues 
69c9e8f97aSAdrien Destugues 
7075c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
71c5d80d47SAxel Dörfler 
72a10cf76eSAxel Dörfler // list of officially supported colour spaces
73a10cf76eSAxel Dörfler static const struct {
74a10cf76eSAxel Dörfler 	color_space	space;
75a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
76a10cf76eSAxel Dörfler 	const char*	label;
77a10cf76eSAxel Dörfler } kColorSpaces[] = {
7826747978SAdrien Destugues 	{ B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") },
79c9e8f97aSAdrien Destugues 	{ B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") },
80c9e8f97aSAdrien Destugues 	{ B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") },
81c9e8f97aSAdrien Destugues 	{ B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") },
82c9e8f97aSAdrien Destugues 	{ B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") }
83a10cf76eSAxel Dörfler };
84b21d610eSAxel Dörfler static const int32 kColorSpaceCount
85b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
86a10cf76eSAxel Dörfler 
87a10cf76eSAxel Dörfler // list of standard refresh rates
88a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
89b21d610eSAxel Dörfler static const int32 kRefreshRateCount
90b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
91a10cf76eSAxel Dörfler 
92a10cf76eSAxel Dörfler // list of combine modes
93a10cf76eSAxel Dörfler static const struct {
94a10cf76eSAxel Dörfler 	combine_mode	mode;
95a10cf76eSAxel Dörfler 	const char		*name;
96a10cf76eSAxel Dörfler } kCombineModes[] = {
97c9e8f97aSAdrien Destugues 	{ kCombineDisable, B_TRANSLATE("disable") },
98c9e8f97aSAdrien Destugues 	{ kCombineHorizontally, B_TRANSLATE("horizontally") },
99c9e8f97aSAdrien Destugues 	{ kCombineVertically, B_TRANSLATE("vertically") }
100a10cf76eSAxel Dörfler };
101b21d610eSAxel Dörfler static const int32 kCombineModeCount
102b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
10329e8a73aSAxel Dörfler 
104a10cf76eSAxel Dörfler 
105a10cf76eSAxel Dörfler static BString
106a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
107a10cf76eSAxel Dörfler {
108a10cf76eSAxel Dörfler 	switch (mode) {
109a10cf76eSAxel Dörfler 		case 0:		return "disabled";
110a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
111a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
112a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
113a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
114a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
115a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
116a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
117a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
118a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
119a10cf76eSAxel Dörfler 		default:
120a10cf76eSAxel Dörfler 		{
121a10cf76eSAxel Dörfler 			BString name;
122a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
123a10cf76eSAxel Dörfler 
124a10cf76eSAxel Dörfler 			return name;
125a10cf76eSAxel Dörfler 		}
126a10cf76eSAxel Dörfler 	}
127a10cf76eSAxel Dörfler }
128a10cf76eSAxel Dörfler 
129a10cf76eSAxel Dörfler 
130a10cf76eSAxel Dörfler static void
131a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
132a10cf76eSAxel Dörfler {
133a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
134a10cf76eSAxel Dörfler }
135a10cf76eSAxel Dörfler 
136a10cf76eSAxel Dörfler 
137a10cf76eSAxel Dörfler static void
138a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
139a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
140a10cf76eSAxel Dörfler {
1418bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1428bf23e3cSAxel Dörfler 		refresh);
143a10cf76eSAxel Dörfler 	string.UnlockBuffer();
144a10cf76eSAxel Dörfler 
145a10cf76eSAxel Dörfler 	if (appendUnit)
146551c9f15SSiarzhuk Zharski 		string << " " << B_TRANSLATE("Hz");
147a10cf76eSAxel Dörfler }
148a10cf76eSAxel Dörfler 
149a10cf76eSAxel Dörfler 
15007184a9eSAxel Dörfler static const char*
15107184a9eSAxel Dörfler screen_errors(status_t status)
15207184a9eSAxel Dörfler {
15307184a9eSAxel Dörfler 	switch (status) {
15407184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
155c9e8f97aSAdrien Destugues 			return B_TRANSLATE("Unknown mode");
15607184a9eSAxel Dörfler 		// TODO: add more?
15707184a9eSAxel Dörfler 
15807184a9eSAxel Dörfler 		default:
15907184a9eSAxel Dörfler 			return strerror(status);
16007184a9eSAxel Dörfler 	}
16107184a9eSAxel Dörfler }
16207184a9eSAxel Dörfler 
16329e8a73aSAxel Dörfler 
1643dfd20c0SStephan Aßmus //	#pragma mark -
1653dfd20c0SStephan Aßmus 
1663dfd20c0SStephan Aßmus 
1675a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
168b21d610eSAxel Dörfler 	:
169560ff447SJonas Sundström 	BWindow(settings->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Screen"),
170958e0ca5SJohn Scipione 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE
171958e0ca5SJohn Scipione 		| B_AUTO_UPDATE_SIZE_LIMITS, B_ALL_WORKSPACES),
1723f953a72SAxel Dörfler 	fIsVesa(false),
173199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
1747e44de36SRene Gollent 	fOtherRefresh(NULL),
175294a85aaSRene Gollent 	fScreenMode(this),
17661c5c89bSAxel Dörfler 	fUndoScreenMode(this),
177abc649b8SWaldemar Kornewald 	fModified(false)
178a10cf76eSAxel Dörfler {
179a10cf76eSAxel Dörfler 	BScreen screen(this);
180a10cf76eSAxel Dörfler 
18112580984SAxel Dörfler 	accelerant_device_info info;
182d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
183d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
18412580984SAxel Dörfler 		fIsVesa = true;
18512580984SAxel Dörfler 
1865de171daSAxel Dörfler 	_UpdateOriginal();
1871fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
188a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
189a10cf76eSAxel Dörfler 
1905a78744bSAxel Dörfler 	fSettings = settings;
1915a78744bSAxel Dörfler 
1925a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1935a78744bSAxel Dörfler 
194c9e8f97aSAdrien Destugues 	BPopUpMenu *popUpMenu = new BPopUpMenu(B_TRANSLATE("Current workspace"),
195c9e8f97aSAdrien Destugues 		true, true);
196c9e8f97aSAdrien Destugues 	fAllWorkspacesItem = new BMenuItem(B_TRANSLATE("All workspaces"),
197d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1985a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
199c9e8f97aSAdrien Destugues 	BMenuItem *item = new BMenuItem(B_TRANSLATE("Current workspace"),
200d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
201b72c4836SAlexandre Deckner 
2025a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
20327c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
2045a78744bSAxel Dörfler 
205b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
20610dfe897SAxel Dörfler 		popUpMenu);
2075a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
208a10cf76eSAxel Dörfler 
209a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
210a10cf76eSAxel Dörfler 
211b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2128bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
213b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
214b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
215a10cf76eSAxel Dörfler 
21612966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
21712966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
21812966d04SAxel Dörfler 
219c9e8f97aSAdrien Destugues 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0),
220551c9f15SSiarzhuk Zharski 		"monitor", screen.Frame().IntegerWidth() + 1,
221c9e8f97aSAdrien Destugues 		screen.Frame().IntegerHeight() + 1);
222b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2235a78744bSAxel Dörfler 
224c9e8f97aSAdrien Destugues 	fColumnsControl = new BTextControl(B_TRANSLATE("Columns:"), "0",
225b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
226c9e8f97aSAdrien Destugues 	fRowsControl = new BTextControl(B_TRANSLATE("Rows:"), "0",
227b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
228b21d610eSAxel Dörfler 
229b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
230c9e8f97aSAdrien Destugues 		.Add(new BStringView("", B_TRANSLATE("Workspaces")), 0, 0, 3)
231b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
232b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
233b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
234b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
235b21d610eSAxel Dörfler 			.End()
236b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
237b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
238b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
239b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
24025fd5c7bSAlex Wilson 			.End()
24125fd5c7bSAlex Wilson 		.View());
242b21d610eSAxel Dörfler 
243b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
244c9e8f97aSAdrien Destugues 		B_TRANSLATE("Set background" B_UTF8_ELLIPSIS),
245b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
246b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
247b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
248a10cf76eSAxel Dörfler 
249a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
250a10cf76eSAxel Dörfler 
251b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
252b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
25325fd5c7bSAlex Wilson 	BGroupView* outerControlsView = new BGroupView(B_VERTICAL, 10.0);
25425fd5c7bSAlex Wilson 	outerControlsView->GroupLayout()->SetInsets(10, 10, 10, 10);
255b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
256a10cf76eSAxel Dörfler 
257551c9f15SSiarzhuk Zharski 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
258a10cf76eSAxel Dörfler 
25966ab1666SAxel Dörfler 	uint16 maxWidth = 0;
26066ab1666SAxel Dörfler 	uint16 maxHeight = 0;
26166ab1666SAxel Dörfler 	uint16 previousWidth = 0;
26266ab1666SAxel Dörfler 	uint16 previousHeight = 0;
263a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
264a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
265a10cf76eSAxel Dörfler 
266a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
267a10cf76eSAxel Dörfler 			continue;
268a10cf76eSAxel Dörfler 
269a10cf76eSAxel Dörfler 		previousWidth = mode.width;
270a10cf76eSAxel Dörfler 		previousHeight = mode.height;
27166ab1666SAxel Dörfler 		if (maxWidth < mode.width)
27266ab1666SAxel Dörfler 			maxWidth = mode.width;
27366ab1666SAxel Dörfler 		if (maxHeight < mode.height)
27466ab1666SAxel Dörfler 			maxHeight = mode.height;
275a10cf76eSAxel Dörfler 
276a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
277a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
278a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
279a10cf76eSAxel Dörfler 
280a10cf76eSAxel Dörfler 		BString name;
281a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
282a10cf76eSAxel Dörfler 
283a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
284a10cf76eSAxel Dörfler 	}
285a10cf76eSAxel Dörfler 
28666ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
28766ab1666SAxel Dörfler 
288c9e8f97aSAdrien Destugues 	fResolutionField = new BMenuField("ResolutionMenu",
28910dfe897SAxel Dörfler 		B_TRANSLATE("Resolution:"), fResolutionMenu);
290a10cf76eSAxel Dörfler 
291551c9f15SSiarzhuk Zharski 	fColorsMenu = new BPopUpMenu("colors", true, false);
292a10cf76eSAxel Dörfler 
293a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
2941fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
2951fc4cb1fSAxel Dörfler 			continue;
2961fc4cb1fSAxel Dörfler 
297a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
298a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
299a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
300a10cf76eSAxel Dörfler 
3011fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
3021fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
3031fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
3041fc4cb1fSAxel Dörfler 
3051fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
306a10cf76eSAxel Dörfler 	}
307a10cf76eSAxel Dörfler 
308c9e8f97aSAdrien Destugues 	fColorsField = new BMenuField("ColorsMenu", B_TRANSLATE("Colors:"),
30910dfe897SAxel Dörfler 		fColorsMenu);
310a10cf76eSAxel Dörfler 
311551c9f15SSiarzhuk Zharski 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
312a10cf76eSAxel Dörfler 
31329e8a73aSAxel Dörfler 	float min, max;
314ec495b30SRene Gollent 	if (fScreenMode.GetRefreshLimits(fActive, min, max) != B_OK) {
315ec495b30SRene Gollent 		// if we couldn't obtain the refresh limits, reset to the default
316ec495b30SRene Gollent 		// range. Constraints from detected monitors will fine-tune this
317ec495b30SRene Gollent 		// later.
318ec495b30SRene Gollent 		min = kRefreshRates[0];
319ec495b30SRene Gollent 		max = kRefreshRates[kRefreshRateCount - 1];
320ec495b30SRene Gollent 	}
321ec495b30SRene Gollent 
322ec495b30SRene Gollent 	if (min == max) {
32329e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
32429e8a73aSAxel Dörfler 		// frequency, like the VESA driver
32529e8a73aSAxel Dörfler 		BString name;
3267e44de36SRene Gollent 		refresh_rate_to_string(min, name);
327cf076964SRene Gollent 		BMessage *message = new BMessage(POP_REFRESH_MSG);
328cf076964SRene Gollent 		message->AddFloat("refresh", min);
329cf076964SRene Gollent 		BMenuItem *item = new BMenuItem(name.String(), message);
3300efb8b66SJerome Duval 		fRefreshMenu->AddItem(item);
33129e8a73aSAxel Dörfler 		item->SetEnabled(false);
33229e8a73aSAxel Dörfler 	} else {
33370a2b1b5SAxel Dörfler 		monitor_info info;
33470a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
33570a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
33670a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
33770a2b1b5SAxel Dörfler 		}
33870a2b1b5SAxel Dörfler 
339a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
34070a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
34170a2b1b5SAxel Dörfler 				continue;
34270a2b1b5SAxel Dörfler 
343a10cf76eSAxel Dörfler 			BString name;
344551c9f15SSiarzhuk Zharski 			name << kRefreshRates[i] << " " << B_TRANSLATE("Hz");
345a10cf76eSAxel Dörfler 
3460efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_REFRESH_MSG);
347a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
348a10cf76eSAxel Dörfler 
349a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
350a10cf76eSAxel Dörfler 		}
351a10cf76eSAxel Dörfler 
352c9e8f97aSAdrien Destugues 		fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
3530efb8b66SJerome Duval 			new BMessage(POP_OTHER_REFRESH_MSG));
354a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
35529e8a73aSAxel Dörfler 	}
356a10cf76eSAxel Dörfler 
357c9e8f97aSAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"),
35810dfe897SAxel Dörfler 		fRefreshMenu);
359b21d610eSAxel Dörfler 
36012580984SAxel Dörfler 	if (_IsVesa())
36112580984SAxel Dörfler 		fRefreshField->Hide();
362a10cf76eSAxel Dörfler 
363a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
364a10cf76eSAxel Dörfler 	{
365a10cf76eSAxel Dörfler 		bool dummy;
366a10cf76eSAxel Dörfler 		uint32 dummy32;
367a10cf76eSAxel Dörfler 		bool multiMonSupport;
368a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
369a10cf76eSAxel Dörfler 		bool tvStandardSupport;
370a10cf76eSAxel Dörfler 
371a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
372a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
373a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
374a10cf76eSAxel Dörfler 
375a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
376a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
377a10cf76eSAxel Dörfler 
378551c9f15SSiarzhuk Zharski 		fCombineMenu = new BPopUpMenu("CombineDisplays",
379c9e8f97aSAdrien Destugues 			true, true);
380a10cf76eSAxel Dörfler 
381a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
3820efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
383a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
384a10cf76eSAxel Dörfler 
385d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
386d1516993SAxel Dörfler 				message));
387a10cf76eSAxel Dörfler 		}
388a10cf76eSAxel Dörfler 
389b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
39010dfe897SAxel Dörfler 			B_TRANSLATE("Combine displays:"), fCombineMenu);
391a10cf76eSAxel Dörfler 
392a10cf76eSAxel Dörfler 		if (!multiMonSupport)
393df3f5bacSStephan Aßmus 			fCombineField->Hide();
394a10cf76eSAxel Dörfler 
395551c9f15SSiarzhuk Zharski 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays",
396c9e8f97aSAdrien Destugues 			true, true);
397a10cf76eSAxel Dörfler 
398a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
3990efb8b66SJerome Duval 		BMessage *message = new BMessage(POP_SWAP_DISPLAYS_MSG);
400a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
401c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message));
402a10cf76eSAxel Dörfler 
403a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
404a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
405c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message));
406a10cf76eSAxel Dörfler 
407c9e8f97aSAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu",
40810dfe897SAxel Dörfler 			B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu);
409a10cf76eSAxel Dörfler 
410a10cf76eSAxel Dörfler 		if (!multiMonSupport)
411df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
412a10cf76eSAxel Dörfler 
413551c9f15SSiarzhuk Zharski 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel",
414c9e8f97aSAdrien Destugues 			true, true);
415a10cf76eSAxel Dörfler 
416a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
417a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
418a10cf76eSAxel Dörfler 		message->AddBool("use", false);
419c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"),
420c9e8f97aSAdrien Destugues 			message));
421a10cf76eSAxel Dörfler 
422a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
423a10cf76eSAxel Dörfler 		message->AddBool("use", true);
424c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"),
425c9e8f97aSAdrien Destugues 			message));
426a10cf76eSAxel Dörfler 
427b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
42810dfe897SAxel Dörfler 			B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu);
429a10cf76eSAxel Dörfler 
430a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
431df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
432a10cf76eSAxel Dörfler 
433551c9f15SSiarzhuk Zharski 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
434a10cf76eSAxel Dörfler 
435a10cf76eSAxel Dörfler 		// arbitrary limit
436a10cf76eSAxel Dörfler 		uint32 i;
437a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
438a10cf76eSAxel Dörfler 			uint32 mode;
439a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
440a10cf76eSAxel Dörfler 				break;
441a10cf76eSAxel Dörfler 
442a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
443a10cf76eSAxel Dörfler 
444a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
445a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
446a10cf76eSAxel Dörfler 
447a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
448a10cf76eSAxel Dörfler 		}
449a10cf76eSAxel Dörfler 
450c9e8f97aSAdrien Destugues 		fTVStandardField = new BMenuField("tv standard",
45110dfe897SAxel Dörfler 			B_TRANSLATE("Video format:"), fTVStandardMenu);
452df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
453a10cf76eSAxel Dörfler 
454b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
455df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
456a10cf76eSAxel Dörfler 	}
457a10cf76eSAxel Dörfler 
45825fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
45925fd5c7bSAlex Wilson 		.AddGrid(5.0, 5.0)
460b21d610eSAxel Dörfler 			.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
461b21d610eSAxel Dörfler 			.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
462b21d610eSAxel Dörfler 			.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
463b21d610eSAxel Dörfler 			.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
464b21d610eSAxel Dörfler 			.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
465b21d610eSAxel Dörfler 			.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
46625fd5c7bSAlex Wilson 			.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT)
46725fd5c7bSAlex Wilson 		.End();
468df3f5bacSStephan Aßmus 
469abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
470abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
471b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
472a10cf76eSAxel Dörfler 
473c9e8f97aSAdrien Destugues 	fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"),
474df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
475df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
47625fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
477b21d610eSAxel Dörfler 		.AddGlue()
47825fd5c7bSAlex Wilson 			.AddGroup(B_HORIZONTAL)
47925fd5c7bSAlex Wilson 			.AddGlue()
48025fd5c7bSAlex Wilson 			.Add(fApplyButton);
481b21d610eSAxel Dörfler 
482c9e8f97aSAdrien Destugues 	fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"),
483b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
484b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
485b21d610eSAxel Dörfler 
48625fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(this, B_VERTICAL, 10.0)
487b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
488b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
489b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
490958e0ca5SJohn Scipione 				.AddStrut(floor(controlsBox->TopBorderOffset() / 16) - 1)
491b21d610eSAxel Dörfler 				.Add(screenBox)
492b21d610eSAxel Dörfler 			.End()
493b21d610eSAxel Dörfler 			.Add(controlsBox)
494b21d610eSAxel Dörfler 		.End()
495b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
496b21d610eSAxel Dörfler 			.Add(fRevertButton)
497b21d610eSAxel Dörfler 			.AddGlue();
498b21d610eSAxel Dörfler 
4995de171daSAxel Dörfler 	_UpdateControls();
50012966d04SAxel Dörfler 	_UpdateMonitor();
501a10cf76eSAxel Dörfler }
502a10cf76eSAxel Dörfler 
503a10cf76eSAxel Dörfler 
504a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
505a10cf76eSAxel Dörfler {
506a10cf76eSAxel Dörfler 	delete fSettings;
507a10cf76eSAxel Dörfler }
508a10cf76eSAxel Dörfler 
509a10cf76eSAxel Dörfler 
510a10cf76eSAxel Dörfler bool
511a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
512a10cf76eSAxel Dörfler {
513a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
514199893c3SAxel Dörfler 
515199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
516199893c3SAxel Dörfler 	screen_mode vesaMode;
517199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
518199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
51912580984SAxel Dörfler 		if (status < B_OK) {
520c9e8f97aSAdrien Destugues 			BString warning = B_TRANSLATE("Could not write VESA mode settings"
521c9e8f97aSAdrien Destugues 				" file:\n\t");
52212580984SAxel Dörfler 			warning << strerror(status);
523aed35104SHumdinger 			BAlert* alert = new BAlert(B_TRANSLATE("Warning"),
524aed35104SHumdinger 				warning.String(), B_TRANSLATE("OK"), NULL,
525aed35104SHumdinger 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
526aed35104SHumdinger 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
527aed35104SHumdinger 			alert->Go();
52812580984SAxel Dörfler 		}
52912580984SAxel Dörfler 	}
53012580984SAxel Dörfler 
531a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
532a10cf76eSAxel Dörfler 
533a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
534a10cf76eSAxel Dörfler }
535a10cf76eSAxel Dörfler 
536a10cf76eSAxel Dörfler 
5375de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5381fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
539a10cf76eSAxel Dörfler */
540a10cf76eSAxel Dörfler void
5415de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
542a10cf76eSAxel Dörfler {
543a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
544a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
545a10cf76eSAxel Dörfler 
546a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
547a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
548a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
549a10cf76eSAxel Dörfler 			continue;
550a10cf76eSAxel Dörfler 
551a10cf76eSAxel Dörfler 		BString name;
552a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
553a10cf76eSAxel Dörfler 
554a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
555a10cf76eSAxel Dörfler 		if (item != NULL)
556a10cf76eSAxel Dörfler 			item->SetEnabled(true);
557a10cf76eSAxel Dörfler 	}
558a10cf76eSAxel Dörfler }
559a10cf76eSAxel Dörfler 
560a10cf76eSAxel Dörfler 
5615de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5625de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5635de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5645de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
565a10cf76eSAxel Dörfler */
566a10cf76eSAxel Dörfler void
5675de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
568a10cf76eSAxel Dörfler {
5691fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5701fc4cb1fSAxel Dörfler 	int32 index = 0;
5711fc4cb1fSAxel Dörfler 
572a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5731fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5741fc4cb1fSAxel Dörfler 			continue;
5751fc4cb1fSAxel Dörfler 
576a10cf76eSAxel Dörfler 		bool supported = false;
577a10cf76eSAxel Dörfler 
578a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
579a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
580a10cf76eSAxel Dörfler 
581a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
582a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5831fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
584a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5851fc4cb1fSAxel Dörfler 				supportsAnything = true;
586a10cf76eSAxel Dörfler 				supported = true;
587a10cf76eSAxel Dörfler 				break;
588a10cf76eSAxel Dörfler 			}
589a10cf76eSAxel Dörfler 		}
590a10cf76eSAxel Dörfler 
5911fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
592a10cf76eSAxel Dörfler 		if (item)
593a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
594a10cf76eSAxel Dörfler 	}
5951fc4cb1fSAxel Dörfler 
5961fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5971fc4cb1fSAxel Dörfler 
5981fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5991fc4cb1fSAxel Dörfler 		return;
6001fc4cb1fSAxel Dörfler 
6011fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
6021fc4cb1fSAxel Dörfler 
6031fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
6041fc4cb1fSAxel Dörfler 	bool changed = false;
6051fc4cb1fSAxel Dörfler 
6061fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
6071fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
6081fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
6091fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
6101fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6111fc4cb1fSAxel Dörfler 			changed = true;
6121fc4cb1fSAxel Dörfler 		}
6131fc4cb1fSAxel Dörfler 	}
6141fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6151fc4cb1fSAxel Dörfler 		// find the next best item
6161fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6171fc4cb1fSAxel Dörfler 		bool found = false;
6181fc4cb1fSAxel Dörfler 
6191fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6201fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6211fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6221fc4cb1fSAxel Dörfler 				found = true;
6231fc4cb1fSAxel Dörfler 				break;
6241fc4cb1fSAxel Dörfler 			}
6251fc4cb1fSAxel Dörfler 		}
6261fc4cb1fSAxel Dörfler 		if (!found) {
6271fc4cb1fSAxel Dörfler 			// search backwards as well
6281fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6291fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6301fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6311fc4cb1fSAxel Dörfler 					break;
6321fc4cb1fSAxel Dörfler 			}
6331fc4cb1fSAxel Dörfler 		}
6341fc4cb1fSAxel Dörfler 
6351fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6361fc4cb1fSAxel Dörfler 		changed = true;
6371fc4cb1fSAxel Dörfler 	}
6381fc4cb1fSAxel Dörfler 
6391fc4cb1fSAxel Dörfler 	if (changed) {
6401fc4cb1fSAxel Dörfler 		// Update selected space
6411fc4cb1fSAxel Dörfler 
6421fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6431fc4cb1fSAxel Dörfler 		int32 space;
6441fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6451fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6461fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6471fc4cb1fSAxel Dörfler 		}
6481fc4cb1fSAxel Dörfler 	}
649a10cf76eSAxel Dörfler }
650a10cf76eSAxel Dörfler 
651a10cf76eSAxel Dörfler 
6525de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
653a10cf76eSAxel Dörfler void
6545de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
655a10cf76eSAxel Dörfler {
65629e8a73aSAxel Dörfler 	float min, max;
65729e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
65829e8a73aSAxel Dörfler 		return;
659a10cf76eSAxel Dörfler 
66029e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
66129e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
66229e8a73aSAxel Dörfler 		BMessage* message = item->Message();
66329e8a73aSAxel Dörfler 		float refresh;
66429e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
66529e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
666a10cf76eSAxel Dörfler 	}
667a10cf76eSAxel Dörfler }
668a10cf76eSAxel Dörfler 
669a10cf76eSAxel Dörfler 
6705de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
671a10cf76eSAxel Dörfler void
6725de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
673a10cf76eSAxel Dörfler {
6747e44de36SRene Gollent 	for (int32 i = 0; i < fRefreshMenu->CountItems(); i++) {
6757e44de36SRene Gollent 		BMenuItem* item = fRefreshMenu->ItemAt(i);
6767e44de36SRene Gollent 		if (item->Message()->FindFloat("refresh") == fSelected.refresh) {
677a10cf76eSAxel Dörfler 			item->SetMarked(true);
67826747978SAdrien Destugues 			// "Other" items only contains a refresh rate when active
67926747978SAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
680a10cf76eSAxel Dörfler 			return;
681a10cf76eSAxel Dörfler 		}
6827e44de36SRene Gollent 	}
683a10cf76eSAxel Dörfler 
684a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
6857e44de36SRene Gollent 	if (fOtherRefresh != NULL) {
686a10cf76eSAxel Dörfler 		fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
687a10cf76eSAxel Dörfler 		fOtherRefresh->SetMarked(true);
688a10cf76eSAxel Dörfler 
6897e44de36SRene Gollent 		BString string;
6907e44de36SRene Gollent 		refresh_rate_to_string(fSelected.refresh, string);
691a10cf76eSAxel Dörfler 		fRefreshMenu->Superitem()->SetLabel(string.String());
692a10cf76eSAxel Dörfler 
693c9e8f97aSAdrien Destugues 		string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
694a10cf76eSAxel Dörfler 		fOtherRefresh->SetLabel(string.String());
695a10cf76eSAxel Dörfler 	}
6967e44de36SRene Gollent }
697a10cf76eSAxel Dörfler 
698a10cf76eSAxel Dörfler 
699a10cf76eSAxel Dörfler void
7005de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
701a10cf76eSAxel Dörfler {
702a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
703a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
704a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
705a10cf76eSAxel Dörfler 
706a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
707a10cf76eSAxel Dörfler }
708a10cf76eSAxel Dörfler 
709a10cf76eSAxel Dörfler 
710a10cf76eSAxel Dörfler void
7115de171daSAxel Dörfler ScreenWindow::_UpdateControls()
712a10cf76eSAxel Dörfler {
713b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
714b21d610eSAxel Dörfler 
715a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
716*c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
717a10cf76eSAxel Dörfler 		item->SetMarked(true);
718a10cf76eSAxel Dörfler 
719a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
720*c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
721a10cf76eSAxel Dörfler 		item->SetMarked(true);
722a10cf76eSAxel Dörfler 
723a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
724a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
725a10cf76eSAxel Dörfler 
726a10cf76eSAxel Dörfler 		uint32 tvStandard;
727a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
728a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
729a10cf76eSAxel Dörfler 			if (!item->IsMarked())
730a10cf76eSAxel Dörfler 				item->SetMarked(true);
731a10cf76eSAxel Dörfler 			break;
732a10cf76eSAxel Dörfler 		}
733a10cf76eSAxel Dörfler 	}
734a10cf76eSAxel Dörfler 
7355de171daSAxel Dörfler 	_CheckResolutionMenu();
7365de171daSAxel Dörfler 	_CheckColorMenu();
7375de171daSAxel Dörfler 	_CheckRefreshMenu();
738a10cf76eSAxel Dörfler 
739a10cf76eSAxel Dörfler 	BString string;
740a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
741a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
742a10cf76eSAxel Dörfler 
743a10cf76eSAxel Dörfler 	if (item != NULL) {
744a10cf76eSAxel Dörfler 		if (!item->IsMarked())
745a10cf76eSAxel Dörfler 			item->SetMarked(true);
746a10cf76eSAxel Dörfler 	} else {
747a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
748a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
749a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
750a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
751a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
752a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
753a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
754a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
755a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
756a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
757a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
758a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
759a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
760a10cf76eSAxel Dörfler 		if (item)
761a10cf76eSAxel Dörfler 			item->SetMarked(true);
762a10cf76eSAxel Dörfler 
763a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
764a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
765a10cf76eSAxel Dörfler 	}
766a10cf76eSAxel Dörfler 
767a10cf76eSAxel Dörfler 	// mark active combine mode
768a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
769a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
770a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
771*c33a865cSJohn Scipione 			if (item != NULL && !item->IsMarked())
772a10cf76eSAxel Dörfler 				item->SetMarked(true);
773a10cf76eSAxel Dörfler 			break;
774a10cf76eSAxel Dörfler 		}
775a10cf76eSAxel Dörfler 	}
776a10cf76eSAxel Dörfler 
777a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
778a10cf76eSAxel Dörfler 
7791fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7801fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7811fc4cb1fSAxel Dörfler 			continue;
7821fc4cb1fSAxel Dörfler 
7831fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7841fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
785a10cf76eSAxel Dörfler 			break;
786a10cf76eSAxel Dörfler 		}
7871fc4cb1fSAxel Dörfler 
7881fc4cb1fSAxel Dörfler 		index++;
789a10cf76eSAxel Dörfler 	}
790a10cf76eSAxel Dörfler 
791*c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
792a10cf76eSAxel Dörfler 		item->SetMarked(true);
793a10cf76eSAxel Dörfler 
7941fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7955de171daSAxel Dörfler 	_UpdateMonitorView();
7965de171daSAxel Dörfler 	_UpdateRefreshControl();
797a10cf76eSAxel Dörfler 
7985de171daSAxel Dörfler 	_CheckApplyEnabled();
799a10cf76eSAxel Dörfler }
800a10cf76eSAxel Dörfler 
801a10cf76eSAxel Dörfler 
80212580984SAxel Dörfler /*! Reflect active mode in chosen settings */
803a10cf76eSAxel Dörfler void
8045de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
805a10cf76eSAxel Dörfler {
806c491b5adSJohn Scipione 	_UpdateActiveMode(current_workspace());
807c491b5adSJohn Scipione }
808c491b5adSJohn Scipione 
809c491b5adSJohn Scipione 
810c491b5adSJohn Scipione void
811c491b5adSJohn Scipione ScreenWindow::_UpdateActiveMode(int32 workspace)
812c491b5adSJohn Scipione {
81312580984SAxel Dörfler 	// Usually, this function gets called after a mode
814a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
815a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
816a10cf76eSAxel Dörfler 	// what kind of mode we actually got
817c491b5adSJohn Scipione 	if (fScreenMode.Get(fActive, workspace) == B_OK) {
818a10cf76eSAxel Dörfler 		fSelected = fActive;
819a10cf76eSAxel Dörfler 
82012966d04SAxel Dörfler 		_UpdateMonitor();
821c491b5adSJohn Scipione 		_BuildSupportedColorSpaces();
8225de171daSAxel Dörfler 		_UpdateControls();
823a10cf76eSAxel Dörfler 	}
824c491b5adSJohn Scipione }
825a10cf76eSAxel Dörfler 
826a10cf76eSAxel Dörfler 
827a10cf76eSAxel Dörfler void
828b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
829b21d610eSAxel Dörfler {
830b21d610eSAxel Dörfler 	uint32 columns;
831b21d610eSAxel Dörfler 	uint32 rows;
832b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
833b21d610eSAxel Dörfler 
834b21d610eSAxel Dörfler 	char text[32];
8355084d0d4SAlex Smith 	snprintf(text, sizeof(text), "%" B_PRId32, columns);
836b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
837b21d610eSAxel Dörfler 
8385084d0d4SAlex Smith 	snprintf(text, sizeof(text), "%" B_PRId32, rows);
839b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
840b21d610eSAxel Dörfler 
841b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
842b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
843b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
844b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
845b21d610eSAxel Dörfler }
846b21d610eSAxel Dörfler 
847b21d610eSAxel Dörfler 
848b21d610eSAxel Dörfler void
849a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
850a10cf76eSAxel Dörfler {
851a10cf76eSAxel Dörfler 	// move window on screen, if necessary
852a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
853a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
854a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
855a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
856a10cf76eSAxel Dörfler 	}
857a10cf76eSAxel Dörfler }
858a10cf76eSAxel Dörfler 
859a10cf76eSAxel Dörfler 
860a10cf76eSAxel Dörfler void
861a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
862a10cf76eSAxel Dörfler {
863c491b5adSJohn Scipione 	if (fScreenMode.GetOriginalMode(fOriginal, workspace) == B_OK) {
864c491b5adSJohn Scipione 		_UpdateActiveMode(workspace);
865a10cf76eSAxel Dörfler 
8666edaa0f6SStefano Ceccherini 		BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8676edaa0f6SStefano Ceccherini 		PostMessage(&message, fMonitorView);
868a10cf76eSAxel Dörfler 	}
869c491b5adSJohn Scipione }
870a10cf76eSAxel Dörfler 
871a10cf76eSAxel Dörfler 
872a10cf76eSAxel Dörfler void
873a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
874a10cf76eSAxel Dörfler {
875a10cf76eSAxel Dörfler 	switch (message->what) {
876a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8775de171daSAxel Dörfler 			_CheckApplyEnabled();
878a10cf76eSAxel Dörfler 			break;
879a10cf76eSAxel Dörfler 
880b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
881a10cf76eSAxel Dörfler 		{
882b21d610eSAxel Dörfler 			int32 deltaX = 0;
883b21d610eSAxel Dörfler 			int32 deltaY = 0;
884b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
885b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
886b21d610eSAxel Dörfler 
887b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
888b21d610eSAxel Dörfler 				break;
889b21d610eSAxel Dörfler 
890b21d610eSAxel Dörfler 			uint32 newColumns;
891b21d610eSAxel Dörfler 			uint32 newRows;
892b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
893b21d610eSAxel Dörfler 
894b21d610eSAxel Dörfler 			newColumns += deltaX;
895b21d610eSAxel Dörfler 			newRows += deltaY;
896b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
897b21d610eSAxel Dörfler 
898b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8995de171daSAxel Dörfler 			_CheckApplyEnabled();
900b21d610eSAxel Dörfler 			break;
901abc649b8SWaldemar Kornewald 		}
902b21d610eSAxel Dörfler 
903b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
904b21d610eSAxel Dörfler 		{
905b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
906b21d610eSAxel Dörfler 
907b21d610eSAxel Dörfler 			uint32 rows;
908b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
909b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
910b21d610eSAxel Dörfler 
911b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
912b21d610eSAxel Dörfler 			_CheckApplyEnabled();
913b21d610eSAxel Dörfler 			break;
914b21d610eSAxel Dörfler 		}
915b21d610eSAxel Dörfler 
916b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
917b21d610eSAxel Dörfler 		{
918b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
919b21d610eSAxel Dörfler 
920b21d610eSAxel Dörfler 			uint32 columns;
921b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
922b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
923b21d610eSAxel Dörfler 
924b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
925b21d610eSAxel Dörfler 			_CheckApplyEnabled();
926a10cf76eSAxel Dörfler 			break;
927a10cf76eSAxel Dörfler 		}
928a10cf76eSAxel Dörfler 
929a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
930a10cf76eSAxel Dörfler 		{
931a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
932a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
933a10cf76eSAxel Dörfler 
9345de171daSAxel Dörfler 			_CheckColorMenu();
9355de171daSAxel Dörfler 			_CheckRefreshMenu();
936a10cf76eSAxel Dörfler 
9375de171daSAxel Dörfler 			_UpdateMonitorView();
9385de171daSAxel Dörfler 			_UpdateRefreshControl();
939a10cf76eSAxel Dörfler 
9405de171daSAxel Dörfler 			_CheckApplyEnabled();
941a10cf76eSAxel Dörfler 			break;
942a10cf76eSAxel Dörfler 		}
943a10cf76eSAxel Dörfler 
944a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
945a10cf76eSAxel Dörfler 		{
9461fc4cb1fSAxel Dörfler 			int32 space;
9471fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9481fc4cb1fSAxel Dörfler 				break;
949a10cf76eSAxel Dörfler 
9501fc4cb1fSAxel Dörfler 			int32 index;
9511fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9521fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9531fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9541fc4cb1fSAxel Dörfler 
9551fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9561fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
957a10cf76eSAxel Dörfler 
9585de171daSAxel Dörfler 			_CheckApplyEnabled();
959a10cf76eSAxel Dörfler 			break;
960a10cf76eSAxel Dörfler 		}
961a10cf76eSAxel Dörfler 
962a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
963a40498e2SWaldemar Kornewald 		{
964a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
965c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
9661fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
967a10cf76eSAxel Dörfler 
9685de171daSAxel Dörfler 			_CheckApplyEnabled();
969a10cf76eSAxel Dörfler 			break;
970a40498e2SWaldemar Kornewald 		}
971a10cf76eSAxel Dörfler 
972a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
973a10cf76eSAxel Dörfler 		{
97429e8a73aSAxel Dörfler 			// make sure menu shows something useful
9755de171daSAxel Dörfler 			_UpdateRefreshControl();
976a10cf76eSAxel Dörfler 
97729e8a73aSAxel Dörfler 			float min = 0, max = 999;
97829e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
97929e8a73aSAxel Dörfler 			if (min < gMinRefresh)
98029e8a73aSAxel Dörfler 				min = gMinRefresh;
98129e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
98229e8a73aSAxel Dörfler 				max = gMaxRefresh;
98329e8a73aSAxel Dörfler 
98470a2b1b5SAxel Dörfler 			monitor_info info;
98570a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
98670a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
98770a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
98870a2b1b5SAxel Dörfler 			}
98970a2b1b5SAxel Dörfler 
990c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
99170a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
99270a2b1b5SAxel Dörfler 				min, max);
993a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
994a10cf76eSAxel Dörfler 			break;
995a10cf76eSAxel Dörfler 		}
996a10cf76eSAxel Dörfler 
997a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
998a10cf76eSAxel Dörfler 		{
999a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
1000a10cf76eSAxel Dörfler 			// select the refresh rate chosen
1001a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
1002a10cf76eSAxel Dörfler 
10035de171daSAxel Dörfler 			_UpdateRefreshControl();
10045de171daSAxel Dörfler 			_CheckApplyEnabled();
1005a10cf76eSAxel Dörfler 			break;
1006a10cf76eSAxel Dörfler 		}
1007a10cf76eSAxel Dörfler 
1008a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
1009a10cf76eSAxel Dörfler 		{
1010a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
1011a10cf76eSAxel Dörfler 			int32 mode;
1012a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
1013a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
1014a10cf76eSAxel Dörfler 
10155de171daSAxel Dörfler 			_CheckResolutionMenu();
10165de171daSAxel Dörfler 			_CheckApplyEnabled();
1017a10cf76eSAxel Dörfler 			break;
1018a10cf76eSAxel Dörfler 		}
1019a10cf76eSAxel Dörfler 
1020a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1021a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10225de171daSAxel Dörfler 			_CheckApplyEnabled();
1023a10cf76eSAxel Dörfler 			break;
1024a10cf76eSAxel Dörfler 
1025a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1026a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10275de171daSAxel Dörfler 			_CheckApplyEnabled();
1028a10cf76eSAxel Dörfler 			break;
1029a10cf76eSAxel Dörfler 
1030a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1031a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10325de171daSAxel Dörfler 			_CheckApplyEnabled();
1033a10cf76eSAxel Dörfler 			break;
1034a10cf76eSAxel Dörfler 
1035df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10366f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10376f095d6aSRyan Leavengood 				app_info info;
10386f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10396f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10406f095d6aSRyan Leavengood 			}
1041df3f5bacSStephan Aßmus 			break;
1042df3f5bacSStephan Aßmus 
1043a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1044a10cf76eSAxel Dörfler 		{
10454be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1046a10cf76eSAxel Dörfler 			fSelected.width = 640;
1047a10cf76eSAxel Dörfler 			fSelected.height = 480;
1048a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1049a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1050a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1051a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1052a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1053a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1054a10cf76eSAxel Dörfler 
1055b21d610eSAxel Dörfler 			// TODO: workspace defaults
1056abc649b8SWaldemar Kornewald 
10575de171daSAxel Dörfler 			_UpdateControls();
1058a10cf76eSAxel Dörfler 			break;
1059a10cf76eSAxel Dörfler 		}
1060a10cf76eSAxel Dörfler 
106110e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
106261c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10635de171daSAxel Dörfler 			_UpdateActiveMode();
1064abc649b8SWaldemar Kornewald 			break;
1065abc649b8SWaldemar Kornewald 
1066abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1067abc649b8SWaldemar Kornewald 		{
1068abc649b8SWaldemar Kornewald 			fModified = false;
1069199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1070abc649b8SWaldemar Kornewald 
1071b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1072b21d610eSAxel Dörfler 			// number of workspaces
1073b21d610eSAxel Dörfler 
1074b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1075b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1076b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1077b21d610eSAxel Dörfler 
1078a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10795de171daSAxel Dörfler 			_UpdateActiveMode();
1080a10cf76eSAxel Dörfler 			break;
1081abc649b8SWaldemar Kornewald 		}
1082a10cf76eSAxel Dörfler 
1083a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10845de171daSAxel Dörfler 			_Apply();
1085a10cf76eSAxel Dörfler 			break;
1086a10cf76eSAxel Dörfler 
1087abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1088abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1089abc649b8SWaldemar Kornewald 			fModified = true;
10905de171daSAxel Dörfler 			_UpdateActiveMode();
1091a10cf76eSAxel Dörfler 			break;
1092a10cf76eSAxel Dörfler 
1093a10cf76eSAxel Dörfler 		default:
1094a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1095a10cf76eSAxel Dörfler 			break;
1096a10cf76eSAxel Dörfler 	}
1097a10cf76eSAxel Dörfler }
1098a10cf76eSAxel Dörfler 
1099a10cf76eSAxel Dörfler 
110012580984SAxel Dörfler status_t
110112580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
110212580984SAxel Dörfler {
110312580984SAxel Dörfler 	BPath path;
110412580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
110512580984SAxel Dörfler 	if (status < B_OK)
110612580984SAxel Dörfler 		return status;
110712580984SAxel Dörfler 
110812580984SAxel Dörfler 	path.Append("kernel/drivers");
110912580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
111012580984SAxel Dörfler 	if (status < B_OK)
111112580984SAxel Dörfler 		return status;
111212580984SAxel Dörfler 
111312580984SAxel Dörfler 	path.Append("vesa");
111412580984SAxel Dörfler 	BFile file;
111512580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
111612580984SAxel Dörfler 	if (status < B_OK)
111712580984SAxel Dörfler 		return status;
111812580984SAxel Dörfler 
111912580984SAxel Dörfler 	char buffer[256];
11205084d0d4SAlex Smith 	snprintf(buffer, sizeof(buffer), "mode %" B_PRId32 " %" B_PRId32 " %"
11215084d0d4SAlex Smith 		B_PRId32 "\n", mode.width, mode.height, mode.BitsPerPixel());
112212580984SAxel Dörfler 
112312580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
112412580984SAxel Dörfler 	if (bytesWritten < B_OK)
112512580984SAxel Dörfler 		return bytesWritten;
112612580984SAxel Dörfler 
112712580984SAxel Dörfler 	return B_OK;
112812580984SAxel Dörfler }
112912580984SAxel Dörfler 
113012580984SAxel Dörfler 
1131b21d610eSAxel Dörfler BButton*
1132b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1133b21d610eSAxel Dörfler {
1134b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1135b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1136b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1137b21d610eSAxel Dörfler 
1138b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1139b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1140b21d610eSAxel Dörfler 
1141b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1142b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1143b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1144b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1145b21d610eSAxel Dörfler 
1146b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1147b21d610eSAxel Dörfler 	return button;
1148b21d610eSAxel Dörfler }
1149b21d610eSAxel Dörfler 
1150b21d610eSAxel Dörfler 
1151b21d610eSAxel Dörfler BButton*
1152b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1153b21d610eSAxel Dörfler {
1154b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1155b21d610eSAxel Dörfler }
1156b21d610eSAxel Dörfler 
1157b21d610eSAxel Dörfler 
1158a10cf76eSAxel Dörfler void
11591fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11601fc4cb1fSAxel Dörfler {
11611fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11621fc4cb1fSAxel Dörfler 
11631fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11641fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11651fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11661fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11671fc4cb1fSAxel Dörfler 				break;
11681fc4cb1fSAxel Dörfler 			}
11691fc4cb1fSAxel Dörfler 		}
11701fc4cb1fSAxel Dörfler 	}
11711fc4cb1fSAxel Dörfler }
11721fc4cb1fSAxel Dörfler 
11731fc4cb1fSAxel Dörfler 
11741fc4cb1fSAxel Dörfler void
11755de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1176a10cf76eSAxel Dörfler {
117727c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
117827c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1179b21d610eSAxel Dörfler 
1180b21d610eSAxel Dörfler 	uint32 columns;
1181b21d610eSAxel Dörfler 	uint32 rows;
1182b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1183b21d610eSAxel Dörfler 
1184b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1185b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11865de171daSAxel Dörfler 		|| fSelected != fOriginal);
1187a10cf76eSAxel Dörfler }
1188a10cf76eSAxel Dörfler 
1189a10cf76eSAxel Dörfler 
1190a10cf76eSAxel Dörfler void
11915de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1192abc649b8SWaldemar Kornewald {
1193b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1194b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1195b21d610eSAxel Dörfler 
1196abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1197abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1198abc649b8SWaldemar Kornewald }
1199abc649b8SWaldemar Kornewald 
1200abc649b8SWaldemar Kornewald 
1201abc649b8SWaldemar Kornewald void
120212966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
120312966d04SAxel Dörfler {
120412966d04SAxel Dörfler 	monitor_info info;
120512966d04SAxel Dörfler 	float diagonalInches;
120612966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
120755030977SAxel Dörfler 	if (status == B_OK) {
12081a8af605SAxel Dörfler 		char text[512];
120966ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
121066ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
121112966d04SAxel Dörfler 
121212966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
121312966d04SAxel Dörfler 
121412966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
121512966d04SAxel Dörfler 			fMonitorInfo->Show();
121655030977SAxel Dörfler 	} else {
121755030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
121855030977SAxel Dörfler 			fMonitorInfo->Hide();
121955030977SAxel Dörfler 	}
1220af8f9c31SAxel Dörfler 
122155030977SAxel Dörfler 	char text[512];
12221a8af605SAxel Dörfler 	size_t length = 0;
12231a8af605SAxel Dörfler 	text[0] = 0;
12241a8af605SAxel Dörfler 
122555030977SAxel Dörfler 	if (status == B_OK) {
1226af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1227af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1228af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12291a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1230c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12319c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1232c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12331a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12341a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12351a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1236af8f9c31SAxel Dörfler 		}
12371a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12381a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1239c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12401a8af605SAxel Dörfler 				info.serial_number);
12411a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12421a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12431a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12441a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12451a8af605SAxel Dörfler 	 		}
12461a8af605SAxel Dörfler 		}
124755030977SAxel Dörfler 	}
124861c5c89bSAxel Dörfler 
124961c5c89bSAxel Dörfler 	// Add info about the graphics device
125061c5c89bSAxel Dörfler 
125161c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
125261c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
125361c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
125461c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
125561c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
125661c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
125761c5c89bSAxel Dörfler 				deviceInfo.chipset);
125861c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
125961c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
126061c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
126161c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
126261c5c89bSAxel Dörfler 		}
126361c5c89bSAxel Dörfler 	}
126461c5c89bSAxel Dörfler 
12651a8af605SAxel Dörfler 	if (text[0])
12661a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
126712966d04SAxel Dörfler }
126812966d04SAxel Dörfler 
126912966d04SAxel Dörfler 
127012966d04SAxel Dörfler void
12711fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12721fc4cb1fSAxel Dörfler {
12731fc4cb1fSAxel Dörfler 	BString string;
1274551c9f15SSiarzhuk Zharski 	string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel");
12751fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12761fc4cb1fSAxel Dörfler }
12771fc4cb1fSAxel Dörfler 
12781fc4cb1fSAxel Dörfler 
12791fc4cb1fSAxel Dörfler void
12805de171daSAxel Dörfler ScreenWindow::_Apply()
1281a10cf76eSAxel Dörfler {
1282abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
128361c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
128461c5c89bSAxel Dörfler 
128507184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
128607184a9eSAxel Dörfler 	if (status == B_OK) {
1287abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1288abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1289abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1290abc649b8SWaldemar Kornewald 		display_mode newMode;
1291abc649b8SWaldemar Kornewald 		BScreen screen(this);
1292abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1293abc649b8SWaldemar Kornewald 
1294abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1295abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1296abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1297abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1298abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1299abc649b8SWaldemar Kornewald 			}
1300199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1301199893c3SAxel Dörfler 		} else {
1302199893c3SAxel Dörfler 			if (current_workspace() == 0)
1303199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1304abc649b8SWaldemar Kornewald 		}
1305abc649b8SWaldemar Kornewald 
1306a10cf76eSAxel Dörfler 		fActive = fSelected;
1307a10cf76eSAxel Dörfler 
1308abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1309a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1310a10cf76eSAxel Dörfler 		window->Show();
131107184a9eSAxel Dörfler 	} else {
131207184a9eSAxel Dörfler 		char message[256];
131307184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1314c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1315c9e8f97aSAdrien Destugues 			screen_errors(status));
1316551c9f15SSiarzhuk Zharski 		BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message,
1317c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
131807184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1319aed35104SHumdinger 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
132007184a9eSAxel Dörfler 		alert->Go();
1321a10cf76eSAxel Dörfler 	}
132207184a9eSAxel Dörfler }
1323