xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 546208a53940a26c6379c48a7854ade1a8250fc5)
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 
66*546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
67*546208a5SOliver 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);
523551c9f15SSiarzhuk Zharski 			(new BAlert(B_TRANSLATE("Warning"), warning.String(), B_TRANSLATE("OK"), NULL,
524c9e8f97aSAdrien Destugues 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
52512580984SAxel Dörfler 		}
52612580984SAxel Dörfler 	}
52712580984SAxel Dörfler 
528a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
529a10cf76eSAxel Dörfler 
530a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
531a10cf76eSAxel Dörfler }
532a10cf76eSAxel Dörfler 
533a10cf76eSAxel Dörfler 
5345de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5351fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
536a10cf76eSAxel Dörfler */
537a10cf76eSAxel Dörfler void
5385de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
539a10cf76eSAxel Dörfler {
540a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
541a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
542a10cf76eSAxel Dörfler 
543a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
544a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
545a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
546a10cf76eSAxel Dörfler 			continue;
547a10cf76eSAxel Dörfler 
548a10cf76eSAxel Dörfler 		BString name;
549a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
550a10cf76eSAxel Dörfler 
551a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
552a10cf76eSAxel Dörfler 		if (item != NULL)
553a10cf76eSAxel Dörfler 			item->SetEnabled(true);
554a10cf76eSAxel Dörfler 	}
555a10cf76eSAxel Dörfler }
556a10cf76eSAxel Dörfler 
557a10cf76eSAxel Dörfler 
5585de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5595de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5605de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5615de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
562a10cf76eSAxel Dörfler */
563a10cf76eSAxel Dörfler void
5645de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
565a10cf76eSAxel Dörfler {
5661fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5671fc4cb1fSAxel Dörfler 	int32 index = 0;
5681fc4cb1fSAxel Dörfler 
569a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5701fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5711fc4cb1fSAxel Dörfler 			continue;
5721fc4cb1fSAxel Dörfler 
573a10cf76eSAxel Dörfler 		bool supported = false;
574a10cf76eSAxel Dörfler 
575a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
576a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
577a10cf76eSAxel Dörfler 
578a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
579a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5801fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
581a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5821fc4cb1fSAxel Dörfler 				supportsAnything = true;
583a10cf76eSAxel Dörfler 				supported = true;
584a10cf76eSAxel Dörfler 				break;
585a10cf76eSAxel Dörfler 			}
586a10cf76eSAxel Dörfler 		}
587a10cf76eSAxel Dörfler 
5881fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
589a10cf76eSAxel Dörfler 		if (item)
590a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
591a10cf76eSAxel Dörfler 	}
5921fc4cb1fSAxel Dörfler 
5931fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5941fc4cb1fSAxel Dörfler 
5951fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5961fc4cb1fSAxel Dörfler 		return;
5971fc4cb1fSAxel Dörfler 
5981fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5991fc4cb1fSAxel Dörfler 
6001fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
6011fc4cb1fSAxel Dörfler 	bool changed = false;
6021fc4cb1fSAxel Dörfler 
6031fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
6041fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
6051fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
6061fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
6071fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6081fc4cb1fSAxel Dörfler 			changed = true;
6091fc4cb1fSAxel Dörfler 		}
6101fc4cb1fSAxel Dörfler 	}
6111fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6121fc4cb1fSAxel Dörfler 		// find the next best item
6131fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6141fc4cb1fSAxel Dörfler 		bool found = false;
6151fc4cb1fSAxel Dörfler 
6161fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6171fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6181fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6191fc4cb1fSAxel Dörfler 				found = true;
6201fc4cb1fSAxel Dörfler 				break;
6211fc4cb1fSAxel Dörfler 			}
6221fc4cb1fSAxel Dörfler 		}
6231fc4cb1fSAxel Dörfler 		if (!found) {
6241fc4cb1fSAxel Dörfler 			// search backwards as well
6251fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6261fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6271fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6281fc4cb1fSAxel Dörfler 					break;
6291fc4cb1fSAxel Dörfler 			}
6301fc4cb1fSAxel Dörfler 		}
6311fc4cb1fSAxel Dörfler 
6321fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6331fc4cb1fSAxel Dörfler 		changed = true;
6341fc4cb1fSAxel Dörfler 	}
6351fc4cb1fSAxel Dörfler 
6361fc4cb1fSAxel Dörfler 	if (changed) {
6371fc4cb1fSAxel Dörfler 		// Update selected space
6381fc4cb1fSAxel Dörfler 
6391fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6401fc4cb1fSAxel Dörfler 		int32 space;
6411fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6421fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6431fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6441fc4cb1fSAxel Dörfler 		}
6451fc4cb1fSAxel Dörfler 	}
646a10cf76eSAxel Dörfler }
647a10cf76eSAxel Dörfler 
648a10cf76eSAxel Dörfler 
6495de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
650a10cf76eSAxel Dörfler void
6515de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
652a10cf76eSAxel Dörfler {
65329e8a73aSAxel Dörfler 	float min, max;
65429e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
65529e8a73aSAxel Dörfler 		return;
656a10cf76eSAxel Dörfler 
65729e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
65829e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
65929e8a73aSAxel Dörfler 		BMessage* message = item->Message();
66029e8a73aSAxel Dörfler 		float refresh;
66129e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
66229e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
663a10cf76eSAxel Dörfler 	}
664a10cf76eSAxel Dörfler }
665a10cf76eSAxel Dörfler 
666a10cf76eSAxel Dörfler 
6675de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
668a10cf76eSAxel Dörfler void
6695de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
670a10cf76eSAxel Dörfler {
6717e44de36SRene Gollent 	for (int32 i = 0; i < fRefreshMenu->CountItems(); i++) {
6727e44de36SRene Gollent 		BMenuItem* item = fRefreshMenu->ItemAt(i);
6737e44de36SRene Gollent 		if (item->Message()->FindFloat("refresh") == fSelected.refresh) {
674a10cf76eSAxel Dörfler 			item->SetMarked(true);
67526747978SAdrien Destugues 			// "Other" items only contains a refresh rate when active
67626747978SAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
677a10cf76eSAxel Dörfler 			return;
678a10cf76eSAxel Dörfler 		}
6797e44de36SRene Gollent 	}
680a10cf76eSAxel Dörfler 
681a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
6827e44de36SRene Gollent 	if (fOtherRefresh != NULL) {
683a10cf76eSAxel Dörfler 		fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
684a10cf76eSAxel Dörfler 		fOtherRefresh->SetMarked(true);
685a10cf76eSAxel Dörfler 
6867e44de36SRene Gollent 		BString string;
6877e44de36SRene Gollent 		refresh_rate_to_string(fSelected.refresh, string);
688a10cf76eSAxel Dörfler 		fRefreshMenu->Superitem()->SetLabel(string.String());
689a10cf76eSAxel Dörfler 
690c9e8f97aSAdrien Destugues 		string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
691a10cf76eSAxel Dörfler 		fOtherRefresh->SetLabel(string.String());
692a10cf76eSAxel Dörfler 	}
6937e44de36SRene Gollent }
694a10cf76eSAxel Dörfler 
695a10cf76eSAxel Dörfler 
696a10cf76eSAxel Dörfler void
6975de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
698a10cf76eSAxel Dörfler {
699a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
700a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
701a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
702a10cf76eSAxel Dörfler 
703a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
704a10cf76eSAxel Dörfler }
705a10cf76eSAxel Dörfler 
706a10cf76eSAxel Dörfler 
707a10cf76eSAxel Dörfler void
7085de171daSAxel Dörfler ScreenWindow::_UpdateControls()
709a10cf76eSAxel Dörfler {
710b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
711b21d610eSAxel Dörfler 
712a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
713a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
714a10cf76eSAxel Dörfler 		item->SetMarked(true);
715a10cf76eSAxel Dörfler 
716a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
717a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
718a10cf76eSAxel Dörfler 		item->SetMarked(true);
719a10cf76eSAxel Dörfler 
720a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
721a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
722a10cf76eSAxel Dörfler 
723a10cf76eSAxel Dörfler 		uint32 tvStandard;
724a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
725a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
726a10cf76eSAxel Dörfler 			if (!item->IsMarked())
727a10cf76eSAxel Dörfler 				item->SetMarked(true);
728a10cf76eSAxel Dörfler 			break;
729a10cf76eSAxel Dörfler 		}
730a10cf76eSAxel Dörfler 	}
731a10cf76eSAxel Dörfler 
7325de171daSAxel Dörfler 	_CheckResolutionMenu();
7335de171daSAxel Dörfler 	_CheckColorMenu();
7345de171daSAxel Dörfler 	_CheckRefreshMenu();
735a10cf76eSAxel Dörfler 
736a10cf76eSAxel Dörfler 	BString string;
737a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
738a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
739a10cf76eSAxel Dörfler 
740a10cf76eSAxel Dörfler 	if (item != NULL) {
741a10cf76eSAxel Dörfler 		if (!item->IsMarked())
742a10cf76eSAxel Dörfler 			item->SetMarked(true);
743a10cf76eSAxel Dörfler 	} else {
744a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
745a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
746a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
747a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
748a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
749a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
750a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
751a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
752a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
753a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
754a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
755a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
756a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
757a10cf76eSAxel Dörfler 		if (item)
758a10cf76eSAxel Dörfler 			item->SetMarked(true);
759a10cf76eSAxel Dörfler 
760a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
761a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
762a10cf76eSAxel Dörfler 	}
763a10cf76eSAxel Dörfler 
764a10cf76eSAxel Dörfler 	// mark active combine mode
765a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
766a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
767a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
768a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
769a10cf76eSAxel Dörfler 				item->SetMarked(true);
770a10cf76eSAxel Dörfler 			break;
771a10cf76eSAxel Dörfler 		}
772a10cf76eSAxel Dörfler 	}
773a10cf76eSAxel Dörfler 
774a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
775a10cf76eSAxel Dörfler 
7761fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7771fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7781fc4cb1fSAxel Dörfler 			continue;
7791fc4cb1fSAxel Dörfler 
7801fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7811fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
782a10cf76eSAxel Dörfler 			break;
783a10cf76eSAxel Dörfler 		}
7841fc4cb1fSAxel Dörfler 
7851fc4cb1fSAxel Dörfler 		index++;
786a10cf76eSAxel Dörfler 	}
787a10cf76eSAxel Dörfler 
788a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
789a10cf76eSAxel Dörfler 		item->SetMarked(true);
790a10cf76eSAxel Dörfler 
7911fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7925de171daSAxel Dörfler 	_UpdateMonitorView();
7935de171daSAxel Dörfler 	_UpdateRefreshControl();
794a10cf76eSAxel Dörfler 
7955de171daSAxel Dörfler 	_CheckApplyEnabled();
796a10cf76eSAxel Dörfler }
797a10cf76eSAxel Dörfler 
798a10cf76eSAxel Dörfler 
79912580984SAxel Dörfler /*! Reflect active mode in chosen settings */
800a10cf76eSAxel Dörfler void
8015de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
802a10cf76eSAxel Dörfler {
80312580984SAxel Dörfler 	// Usually, this function gets called after a mode
804a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
805a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
806a10cf76eSAxel Dörfler 	// what kind of mode we actually got
807a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
808a10cf76eSAxel Dörfler 	fSelected = fActive;
809a10cf76eSAxel Dörfler 
81012966d04SAxel Dörfler 	_UpdateMonitor();
8115de171daSAxel Dörfler 	_UpdateControls();
812a10cf76eSAxel Dörfler }
813a10cf76eSAxel Dörfler 
814a10cf76eSAxel Dörfler 
815a10cf76eSAxel Dörfler void
816b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
817b21d610eSAxel Dörfler {
818b21d610eSAxel Dörfler 	uint32 columns;
819b21d610eSAxel Dörfler 	uint32 rows;
820b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
821b21d610eSAxel Dörfler 
822b21d610eSAxel Dörfler 	char text[32];
823b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
824b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
825b21d610eSAxel Dörfler 
826b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
827b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
828b21d610eSAxel Dörfler 
829b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
830b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
831b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
832b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
833b21d610eSAxel Dörfler }
834b21d610eSAxel Dörfler 
835b21d610eSAxel Dörfler 
836b21d610eSAxel Dörfler void
837a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
838a10cf76eSAxel Dörfler {
839a10cf76eSAxel Dörfler 	// move window on screen, if necessary
840a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
841a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
842a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
843a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
844a10cf76eSAxel Dörfler 	}
845a10cf76eSAxel Dörfler }
846a10cf76eSAxel Dörfler 
847a10cf76eSAxel Dörfler 
848a10cf76eSAxel Dörfler void
849a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
850a10cf76eSAxel Dörfler {
851abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8525de171daSAxel Dörfler 	_UpdateActiveMode();
853a10cf76eSAxel Dörfler 
8546edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8556edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
856a10cf76eSAxel Dörfler }
857a10cf76eSAxel Dörfler 
858a10cf76eSAxel Dörfler 
859a10cf76eSAxel Dörfler void
860a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
861a10cf76eSAxel Dörfler {
862a10cf76eSAxel Dörfler 	switch (message->what) {
863a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8645de171daSAxel Dörfler 			_CheckApplyEnabled();
865a10cf76eSAxel Dörfler 			break;
866a10cf76eSAxel Dörfler 
867b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
868a10cf76eSAxel Dörfler 		{
869b21d610eSAxel Dörfler 			int32 deltaX = 0;
870b21d610eSAxel Dörfler 			int32 deltaY = 0;
871b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
872b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
873b21d610eSAxel Dörfler 
874b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
875b21d610eSAxel Dörfler 				break;
876b21d610eSAxel Dörfler 
877b21d610eSAxel Dörfler 			uint32 newColumns;
878b21d610eSAxel Dörfler 			uint32 newRows;
879b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
880b21d610eSAxel Dörfler 
881b21d610eSAxel Dörfler 			newColumns += deltaX;
882b21d610eSAxel Dörfler 			newRows += deltaY;
883b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
884b21d610eSAxel Dörfler 
885b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8865de171daSAxel Dörfler 			_CheckApplyEnabled();
887b21d610eSAxel Dörfler 			break;
888abc649b8SWaldemar Kornewald 		}
889b21d610eSAxel Dörfler 
890b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
891b21d610eSAxel Dörfler 		{
892b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
893b21d610eSAxel Dörfler 
894b21d610eSAxel Dörfler 			uint32 rows;
895b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
896b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
897b21d610eSAxel Dörfler 
898b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
899b21d610eSAxel Dörfler 			_CheckApplyEnabled();
900b21d610eSAxel Dörfler 			break;
901b21d610eSAxel Dörfler 		}
902b21d610eSAxel Dörfler 
903b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
904b21d610eSAxel Dörfler 		{
905b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
906b21d610eSAxel Dörfler 
907b21d610eSAxel Dörfler 			uint32 columns;
908b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
909b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
910b21d610eSAxel Dörfler 
911b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
912b21d610eSAxel Dörfler 			_CheckApplyEnabled();
913a10cf76eSAxel Dörfler 			break;
914a10cf76eSAxel Dörfler 		}
915a10cf76eSAxel Dörfler 
916a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
917a10cf76eSAxel Dörfler 		{
918a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
919a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
920a10cf76eSAxel Dörfler 
9215de171daSAxel Dörfler 			_CheckColorMenu();
9225de171daSAxel Dörfler 			_CheckRefreshMenu();
923a10cf76eSAxel Dörfler 
9245de171daSAxel Dörfler 			_UpdateMonitorView();
9255de171daSAxel Dörfler 			_UpdateRefreshControl();
926a10cf76eSAxel Dörfler 
9275de171daSAxel Dörfler 			_CheckApplyEnabled();
928a10cf76eSAxel Dörfler 			break;
929a10cf76eSAxel Dörfler 		}
930a10cf76eSAxel Dörfler 
931a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
932a10cf76eSAxel Dörfler 		{
9331fc4cb1fSAxel Dörfler 			int32 space;
9341fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9351fc4cb1fSAxel Dörfler 				break;
936a10cf76eSAxel Dörfler 
9371fc4cb1fSAxel Dörfler 			int32 index;
9381fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9391fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9401fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9411fc4cb1fSAxel Dörfler 
9421fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9431fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
944a10cf76eSAxel Dörfler 
9455de171daSAxel Dörfler 			_CheckApplyEnabled();
946a10cf76eSAxel Dörfler 			break;
947a10cf76eSAxel Dörfler 		}
948a10cf76eSAxel Dörfler 
949a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
950a40498e2SWaldemar Kornewald 		{
951a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
952c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
9531fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
954a10cf76eSAxel Dörfler 
9555de171daSAxel Dörfler 			_CheckApplyEnabled();
956a10cf76eSAxel Dörfler 			break;
957a40498e2SWaldemar Kornewald 		}
958a10cf76eSAxel Dörfler 
959a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
960a10cf76eSAxel Dörfler 		{
96129e8a73aSAxel Dörfler 			// make sure menu shows something useful
9625de171daSAxel Dörfler 			_UpdateRefreshControl();
963a10cf76eSAxel Dörfler 
96429e8a73aSAxel Dörfler 			float min = 0, max = 999;
96529e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
96629e8a73aSAxel Dörfler 			if (min < gMinRefresh)
96729e8a73aSAxel Dörfler 				min = gMinRefresh;
96829e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
96929e8a73aSAxel Dörfler 				max = gMaxRefresh;
97029e8a73aSAxel Dörfler 
97170a2b1b5SAxel Dörfler 			monitor_info info;
97270a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
97370a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
97470a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
97570a2b1b5SAxel Dörfler 			}
97670a2b1b5SAxel Dörfler 
977c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
97870a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
97970a2b1b5SAxel Dörfler 				min, max);
980a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
981a10cf76eSAxel Dörfler 			break;
982a10cf76eSAxel Dörfler 		}
983a10cf76eSAxel Dörfler 
984a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
985a10cf76eSAxel Dörfler 		{
986a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
987a10cf76eSAxel Dörfler 			// select the refresh rate chosen
988a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
989a10cf76eSAxel Dörfler 
9905de171daSAxel Dörfler 			_UpdateRefreshControl();
9915de171daSAxel Dörfler 			_CheckApplyEnabled();
992a10cf76eSAxel Dörfler 			break;
993a10cf76eSAxel Dörfler 		}
994a10cf76eSAxel Dörfler 
995a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
996a10cf76eSAxel Dörfler 		{
997a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
998a10cf76eSAxel Dörfler 			int32 mode;
999a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
1000a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
1001a10cf76eSAxel Dörfler 
10025de171daSAxel Dörfler 			_CheckResolutionMenu();
10035de171daSAxel Dörfler 			_CheckApplyEnabled();
1004a10cf76eSAxel Dörfler 			break;
1005a10cf76eSAxel Dörfler 		}
1006a10cf76eSAxel Dörfler 
1007a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1008a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10095de171daSAxel Dörfler 			_CheckApplyEnabled();
1010a10cf76eSAxel Dörfler 			break;
1011a10cf76eSAxel Dörfler 
1012a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1013a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10145de171daSAxel Dörfler 			_CheckApplyEnabled();
1015a10cf76eSAxel Dörfler 			break;
1016a10cf76eSAxel Dörfler 
1017a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1018a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10195de171daSAxel Dörfler 			_CheckApplyEnabled();
1020a10cf76eSAxel Dörfler 			break;
1021a10cf76eSAxel Dörfler 
1022df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10236f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10246f095d6aSRyan Leavengood 				app_info info;
10256f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10266f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10276f095d6aSRyan Leavengood 			}
1028df3f5bacSStephan Aßmus 			break;
1029df3f5bacSStephan Aßmus 
1030a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1031a10cf76eSAxel Dörfler 		{
10324be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1033a10cf76eSAxel Dörfler 			fSelected.width = 640;
1034a10cf76eSAxel Dörfler 			fSelected.height = 480;
1035a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1036a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1037a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1038a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1039a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1040a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1041a10cf76eSAxel Dörfler 
1042b21d610eSAxel Dörfler 			// TODO: workspace defaults
1043abc649b8SWaldemar Kornewald 
10445de171daSAxel Dörfler 			_UpdateControls();
1045a10cf76eSAxel Dörfler 			break;
1046a10cf76eSAxel Dörfler 		}
1047a10cf76eSAxel Dörfler 
104810e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
104961c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10505de171daSAxel Dörfler 			_UpdateActiveMode();
1051abc649b8SWaldemar Kornewald 			break;
1052abc649b8SWaldemar Kornewald 
1053abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1054abc649b8SWaldemar Kornewald 		{
1055abc649b8SWaldemar Kornewald 			fModified = false;
1056199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1057abc649b8SWaldemar Kornewald 
1058b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1059b21d610eSAxel Dörfler 			// number of workspaces
1060b21d610eSAxel Dörfler 
1061b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1062b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1063b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1064b21d610eSAxel Dörfler 
1065a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10665de171daSAxel Dörfler 			_UpdateActiveMode();
1067a10cf76eSAxel Dörfler 			break;
1068abc649b8SWaldemar Kornewald 		}
1069a10cf76eSAxel Dörfler 
1070a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10715de171daSAxel Dörfler 			_Apply();
1072a10cf76eSAxel Dörfler 			break;
1073a10cf76eSAxel Dörfler 
1074abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1075abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1076abc649b8SWaldemar Kornewald 			fModified = true;
10775de171daSAxel Dörfler 			_UpdateActiveMode();
1078a10cf76eSAxel Dörfler 			break;
1079a10cf76eSAxel Dörfler 
1080a10cf76eSAxel Dörfler 		default:
1081a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1082a10cf76eSAxel Dörfler 			break;
1083a10cf76eSAxel Dörfler 	}
1084a10cf76eSAxel Dörfler }
1085a10cf76eSAxel Dörfler 
1086a10cf76eSAxel Dörfler 
108712580984SAxel Dörfler status_t
108812580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
108912580984SAxel Dörfler {
109012580984SAxel Dörfler 	BPath path;
109112580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
109212580984SAxel Dörfler 	if (status < B_OK)
109312580984SAxel Dörfler 		return status;
109412580984SAxel Dörfler 
109512580984SAxel Dörfler 	path.Append("kernel/drivers");
109612580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
109712580984SAxel Dörfler 	if (status < B_OK)
109812580984SAxel Dörfler 		return status;
109912580984SAxel Dörfler 
110012580984SAxel Dörfler 	path.Append("vesa");
110112580984SAxel Dörfler 	BFile file;
110212580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
110312580984SAxel Dörfler 	if (status < B_OK)
110412580984SAxel Dörfler 		return status;
110512580984SAxel Dörfler 
110612580984SAxel Dörfler 	char buffer[256];
110712580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
110812580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
110912580984SAxel Dörfler 
111012580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
111112580984SAxel Dörfler 	if (bytesWritten < B_OK)
111212580984SAxel Dörfler 		return bytesWritten;
111312580984SAxel Dörfler 
111412580984SAxel Dörfler 	return B_OK;
111512580984SAxel Dörfler }
111612580984SAxel Dörfler 
111712580984SAxel Dörfler 
1118b21d610eSAxel Dörfler BButton*
1119b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1120b21d610eSAxel Dörfler {
1121b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1122b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1123b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1124b21d610eSAxel Dörfler 
1125b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1126b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1127b21d610eSAxel Dörfler 
1128b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1129b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1130b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1131b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1132b21d610eSAxel Dörfler 
1133b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1134b21d610eSAxel Dörfler 	return button;
1135b21d610eSAxel Dörfler }
1136b21d610eSAxel Dörfler 
1137b21d610eSAxel Dörfler 
1138b21d610eSAxel Dörfler BButton*
1139b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1140b21d610eSAxel Dörfler {
1141b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1142b21d610eSAxel Dörfler }
1143b21d610eSAxel Dörfler 
1144b21d610eSAxel Dörfler 
1145a10cf76eSAxel Dörfler void
11461fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11471fc4cb1fSAxel Dörfler {
11481fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11491fc4cb1fSAxel Dörfler 
11501fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11511fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11521fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11531fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11541fc4cb1fSAxel Dörfler 				break;
11551fc4cb1fSAxel Dörfler 			}
11561fc4cb1fSAxel Dörfler 		}
11571fc4cb1fSAxel Dörfler 	}
11581fc4cb1fSAxel Dörfler }
11591fc4cb1fSAxel Dörfler 
11601fc4cb1fSAxel Dörfler 
11611fc4cb1fSAxel Dörfler void
11625de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1163a10cf76eSAxel Dörfler {
116427c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
116527c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1166b21d610eSAxel Dörfler 
1167b21d610eSAxel Dörfler 	uint32 columns;
1168b21d610eSAxel Dörfler 	uint32 rows;
1169b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1170b21d610eSAxel Dörfler 
1171b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1172b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11735de171daSAxel Dörfler 		|| fSelected != fOriginal);
1174a10cf76eSAxel Dörfler }
1175a10cf76eSAxel Dörfler 
1176a10cf76eSAxel Dörfler 
1177a10cf76eSAxel Dörfler void
11785de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1179abc649b8SWaldemar Kornewald {
1180b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1181b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1182b21d610eSAxel Dörfler 
1183abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1184abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1185abc649b8SWaldemar Kornewald }
1186abc649b8SWaldemar Kornewald 
1187abc649b8SWaldemar Kornewald 
1188abc649b8SWaldemar Kornewald void
118912966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
119012966d04SAxel Dörfler {
119112966d04SAxel Dörfler 	monitor_info info;
119212966d04SAxel Dörfler 	float diagonalInches;
119312966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
119455030977SAxel Dörfler 	if (status == B_OK) {
11951a8af605SAxel Dörfler 		char text[512];
119666ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
119766ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
119812966d04SAxel Dörfler 
119912966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
120012966d04SAxel Dörfler 
120112966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
120212966d04SAxel Dörfler 			fMonitorInfo->Show();
120355030977SAxel Dörfler 	} else {
120455030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
120555030977SAxel Dörfler 			fMonitorInfo->Hide();
120655030977SAxel Dörfler 	}
1207af8f9c31SAxel Dörfler 
120855030977SAxel Dörfler 	char text[512];
12091a8af605SAxel Dörfler 	size_t length = 0;
12101a8af605SAxel Dörfler 	text[0] = 0;
12111a8af605SAxel Dörfler 
121255030977SAxel Dörfler 	if (status == B_OK) {
1213af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1214af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1215af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12161a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1217c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12189c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1219c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12201a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12211a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12221a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1223af8f9c31SAxel Dörfler 		}
12241a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12251a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1226c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12271a8af605SAxel Dörfler 				info.serial_number);
12281a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12291a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12301a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12311a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12321a8af605SAxel Dörfler 	 		}
12331a8af605SAxel Dörfler 		}
123455030977SAxel Dörfler 	}
123561c5c89bSAxel Dörfler 
123661c5c89bSAxel Dörfler 	// Add info about the graphics device
123761c5c89bSAxel Dörfler 
123861c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
123961c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
124061c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
124161c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
124261c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
124361c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
124461c5c89bSAxel Dörfler 				deviceInfo.chipset);
124561c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
124661c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
124761c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
124861c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
124961c5c89bSAxel Dörfler 		}
125061c5c89bSAxel Dörfler 	}
125161c5c89bSAxel Dörfler 
12521a8af605SAxel Dörfler 	if (text[0])
12531a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
125412966d04SAxel Dörfler }
125512966d04SAxel Dörfler 
125612966d04SAxel Dörfler 
125712966d04SAxel Dörfler void
12581fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12591fc4cb1fSAxel Dörfler {
12601fc4cb1fSAxel Dörfler 	BString string;
1261551c9f15SSiarzhuk Zharski 	string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel");
12621fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12631fc4cb1fSAxel Dörfler }
12641fc4cb1fSAxel Dörfler 
12651fc4cb1fSAxel Dörfler 
12661fc4cb1fSAxel Dörfler void
12675de171daSAxel Dörfler ScreenWindow::_Apply()
1268a10cf76eSAxel Dörfler {
1269abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
127061c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
127161c5c89bSAxel Dörfler 
127207184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
127307184a9eSAxel Dörfler 	if (status == B_OK) {
1274abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1275abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1276abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1277abc649b8SWaldemar Kornewald 		display_mode newMode;
1278abc649b8SWaldemar Kornewald 		BScreen screen(this);
1279abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1280abc649b8SWaldemar Kornewald 
1281abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1282abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1283abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1284abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1285abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1286abc649b8SWaldemar Kornewald 			}
1287199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1288199893c3SAxel Dörfler 		} else {
1289199893c3SAxel Dörfler 			if (current_workspace() == 0)
1290199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1291abc649b8SWaldemar Kornewald 		}
1292abc649b8SWaldemar Kornewald 
1293a10cf76eSAxel Dörfler 		fActive = fSelected;
1294a10cf76eSAxel Dörfler 
1295abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1296a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1297a10cf76eSAxel Dörfler 		window->Show();
129807184a9eSAxel Dörfler 	} else {
129907184a9eSAxel Dörfler 		char message[256];
130007184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1301c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1302c9e8f97aSAdrien Destugues 			screen_errors(status));
1303551c9f15SSiarzhuk Zharski 		BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message,
1304c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
130507184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
130607184a9eSAxel Dörfler 		alert->Go();
1307a10cf76eSAxel Dörfler 	}
130807184a9eSAxel Dörfler }
130907184a9eSAxel Dörfler 
1310