xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 3f953a72ff25302c43b84a4aa534a8b212c49a67)
1a10cf76eSAxel Dörfler /*
210dfe897SAxel Dörfler  * Copyright 2001-2011, Haiku.
3a10cf76eSAxel Dörfler  * Distributed under the terms of the MIT License.
4a10cf76eSAxel Dörfler  *
5a10cf76eSAxel Dörfler  * Authors:
6a10cf76eSAxel Dörfler  *		Rafael Romo
7a10cf76eSAxel Dörfler  *		Stefano Ceccherini (burton666@libero.it)
8a10cf76eSAxel Dörfler  *		Andrew Bachmann
9a10cf76eSAxel Dörfler  *		Thomas Kurschel
10a10cf76eSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
11df3f5bacSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
12b72c4836SAlexandre Deckner  *		Alexandre Deckner, alex@zappotek.com
13a10cf76eSAxel Dörfler  */
14a10cf76eSAxel Dörfler 
15a10cf76eSAxel Dörfler 
16b21d610eSAxel Dörfler #include "ScreenWindow.h"
17b21d610eSAxel Dörfler 
18b21d610eSAxel Dörfler #include <stdio.h>
19b21d610eSAxel Dörfler #include <stdlib.h>
20b21d610eSAxel Dörfler #include <string.h>
21b21d610eSAxel Dörfler 
22b21d610eSAxel Dörfler #include <Alert.h>
23b21d610eSAxel Dörfler #include <Application.h>
24b21d610eSAxel Dörfler #include <Box.h>
25b21d610eSAxel Dörfler #include <Button.h>
26c9e8f97aSAdrien Destugues #include <Catalog.h>
27b21d610eSAxel Dörfler #include <Directory.h>
28b21d610eSAxel Dörfler #include <File.h>
29b21d610eSAxel Dörfler #include <FindDirectory.h>
30b21d610eSAxel Dörfler #include <InterfaceDefs.h>
31b21d610eSAxel Dörfler #include <LayoutBuilder.h>
32b21d610eSAxel Dörfler #include <MenuBar.h>
33b21d610eSAxel Dörfler #include <MenuItem.h>
34b21d610eSAxel Dörfler #include <MenuField.h>
35b21d610eSAxel Dörfler #include <Messenger.h>
36b21d610eSAxel Dörfler #include <Path.h>
37b21d610eSAxel Dörfler #include <PopUpMenu.h>
38b21d610eSAxel Dörfler #include <Screen.h>
39b21d610eSAxel Dörfler #include <String.h>
40b21d610eSAxel Dörfler #include <StringView.h>
41b21d610eSAxel Dörfler #include <Roster.h>
42b21d610eSAxel Dörfler #include <Window.h>
43b21d610eSAxel Dörfler 
44b21d610eSAxel Dörfler #include <InterfacePrivate.h>
45b21d610eSAxel Dörfler 
46a10cf76eSAxel Dörfler #include "AlertWindow.h"
47a10cf76eSAxel Dörfler #include "Constants.h"
48a10cf76eSAxel Dörfler #include "RefreshWindow.h"
49a10cf76eSAxel Dörfler #include "MonitorView.h"
50a10cf76eSAxel Dörfler #include "ScreenSettings.h"
51a10cf76eSAxel Dörfler #include "Utility.h"
52a10cf76eSAxel Dörfler 
53a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
54a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
55a10cf76eSAxel Dörfler  * adopted.
56a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
57a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
58a10cf76eSAxel Dörfler  * be using this.
59a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
60a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
61a10cf76eSAxel Dörfler  */
62a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
63a10cf76eSAxel Dörfler 
64a10cf76eSAxel Dörfler 
65c9e8f97aSAdrien Destugues #undef B_TRANSLATE_CONTEXT
66c9e8f97aSAdrien Destugues #define B_TRANSLATE_CONTEXT "Screen"
67c9e8f97aSAdrien Destugues 
68c9e8f97aSAdrien Destugues 
6975c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
70c5d80d47SAxel Dörfler 
71a10cf76eSAxel Dörfler // list of officially supported colour spaces
72a10cf76eSAxel Dörfler static const struct {
73a10cf76eSAxel Dörfler 	color_space	space;
74a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
75a10cf76eSAxel Dörfler 	const char*	label;
76a10cf76eSAxel Dörfler } kColorSpaces[] = {
7726747978SAdrien Destugues 	{ B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") },
78c9e8f97aSAdrien Destugues 	{ B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") },
79c9e8f97aSAdrien Destugues 	{ B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") },
80c9e8f97aSAdrien Destugues 	{ B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") },
81c9e8f97aSAdrien Destugues 	{ B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") }
82a10cf76eSAxel Dörfler };
83b21d610eSAxel Dörfler static const int32 kColorSpaceCount
84b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
85a10cf76eSAxel Dörfler 
86a10cf76eSAxel Dörfler // list of standard refresh rates
87a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
88b21d610eSAxel Dörfler static const int32 kRefreshRateCount
89b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
90a10cf76eSAxel Dörfler 
91a10cf76eSAxel Dörfler // list of combine modes
92a10cf76eSAxel Dörfler static const struct {
93a10cf76eSAxel Dörfler 	combine_mode	mode;
94a10cf76eSAxel Dörfler 	const char		*name;
95a10cf76eSAxel Dörfler } kCombineModes[] = {
96c9e8f97aSAdrien Destugues 	{ kCombineDisable, B_TRANSLATE("disable") },
97c9e8f97aSAdrien Destugues 	{ kCombineHorizontally, B_TRANSLATE("horizontally") },
98c9e8f97aSAdrien Destugues 	{ kCombineVertically, B_TRANSLATE("vertically") }
99a10cf76eSAxel Dörfler };
100b21d610eSAxel Dörfler static const int32 kCombineModeCount
101b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
10229e8a73aSAxel Dörfler 
103a10cf76eSAxel Dörfler 
104a10cf76eSAxel Dörfler static BString
105a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
106a10cf76eSAxel Dörfler {
107a10cf76eSAxel Dörfler 	switch (mode) {
108a10cf76eSAxel Dörfler 		case 0:		return "disabled";
109a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
110a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
111a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
112a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
113a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
114a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
115a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
116a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
117a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
118a10cf76eSAxel Dörfler 		default:
119a10cf76eSAxel Dörfler 		{
120a10cf76eSAxel Dörfler 			BString name;
121a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
122a10cf76eSAxel Dörfler 
123a10cf76eSAxel Dörfler 			return name;
124a10cf76eSAxel Dörfler 		}
125a10cf76eSAxel Dörfler 	}
126a10cf76eSAxel Dörfler }
127a10cf76eSAxel Dörfler 
128a10cf76eSAxel Dörfler 
129a10cf76eSAxel Dörfler static void
130a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
131a10cf76eSAxel Dörfler {
132a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
133a10cf76eSAxel Dörfler }
134a10cf76eSAxel Dörfler 
135a10cf76eSAxel Dörfler 
136a10cf76eSAxel Dörfler static void
137a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
138a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
139a10cf76eSAxel Dörfler {
1408bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1418bf23e3cSAxel Dörfler 		refresh);
142a10cf76eSAxel Dörfler 	string.UnlockBuffer();
143a10cf76eSAxel Dörfler 
144a10cf76eSAxel Dörfler 	if (appendUnit)
145551c9f15SSiarzhuk Zharski 		string << " " << B_TRANSLATE("Hz");
146a10cf76eSAxel Dörfler }
147a10cf76eSAxel Dörfler 
148a10cf76eSAxel Dörfler 
14907184a9eSAxel Dörfler static const char*
15007184a9eSAxel Dörfler screen_errors(status_t status)
15107184a9eSAxel Dörfler {
15207184a9eSAxel Dörfler 	switch (status) {
15307184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
154c9e8f97aSAdrien Destugues 			return B_TRANSLATE("Unknown mode");
15507184a9eSAxel Dörfler 		// TODO: add more?
15607184a9eSAxel Dörfler 
15707184a9eSAxel Dörfler 		default:
15807184a9eSAxel Dörfler 			return strerror(status);
15907184a9eSAxel Dörfler 	}
16007184a9eSAxel Dörfler }
16107184a9eSAxel Dörfler 
16229e8a73aSAxel Dörfler 
1633dfd20c0SStephan Aßmus //	#pragma mark -
1643dfd20c0SStephan Aßmus 
1653dfd20c0SStephan Aßmus 
1665a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
167b21d610eSAxel Dörfler 	:
168560ff447SJonas Sundström 	BWindow(settings->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Screen"),
169d374a272SJonas Sundström 		B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
170b21d610eSAxel Dörfler 		B_ALL_WORKSPACES),
171*3f953a72SAxel Dörfler 	fIsVesa(false),
172199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
173a10cf76eSAxel Dörfler 	fScreenMode(this),
17461c5c89bSAxel Dörfler 	fUndoScreenMode(this),
175abc649b8SWaldemar Kornewald 	fModified(false)
176a10cf76eSAxel Dörfler {
177a10cf76eSAxel Dörfler 	BScreen screen(this);
178a10cf76eSAxel Dörfler 
17912580984SAxel Dörfler 	accelerant_device_info info;
180d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
181d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
18212580984SAxel Dörfler 		fIsVesa = true;
18312580984SAxel Dörfler 
1845de171daSAxel Dörfler 	_UpdateOriginal();
1851fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
186a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
187a10cf76eSAxel Dörfler 
1885a78744bSAxel Dörfler 	fSettings = settings;
1895a78744bSAxel Dörfler 
1905a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1915a78744bSAxel Dörfler 
192c9e8f97aSAdrien Destugues 	BPopUpMenu *popUpMenu = new BPopUpMenu(B_TRANSLATE("Current workspace"),
193c9e8f97aSAdrien Destugues 		true, true);
194c9e8f97aSAdrien Destugues 	fAllWorkspacesItem = new BMenuItem(B_TRANSLATE("All workspaces"),
195d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1965a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
197c9e8f97aSAdrien Destugues 	BMenuItem *item = new BMenuItem(B_TRANSLATE("Current workspace"),
198d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
199b72c4836SAlexandre Deckner 
2005a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
20127c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
2025a78744bSAxel Dörfler 
203b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
20410dfe897SAxel Dörfler 		popUpMenu);
2055a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
206a10cf76eSAxel Dörfler 
207a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
208a10cf76eSAxel Dörfler 
209b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2108bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
211b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
212b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
213a10cf76eSAxel Dörfler 
21412966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
21512966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
21612966d04SAxel Dörfler 
217c9e8f97aSAdrien Destugues 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0),
218551c9f15SSiarzhuk Zharski 		"monitor", screen.Frame().IntegerWidth() + 1,
219c9e8f97aSAdrien Destugues 		screen.Frame().IntegerHeight() + 1);
220b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2215a78744bSAxel Dörfler 
222c9e8f97aSAdrien Destugues 	fColumnsControl = new BTextControl(B_TRANSLATE("Columns:"), "0",
223b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
224c9e8f97aSAdrien Destugues 	fRowsControl = new BTextControl(B_TRANSLATE("Rows:"), "0",
225b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
226b21d610eSAxel Dörfler 
227b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
228c9e8f97aSAdrien Destugues 		.Add(new BStringView("", B_TRANSLATE("Workspaces")), 0, 0, 3)
229b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
230b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
231b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
232b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
233b21d610eSAxel Dörfler 			.End()
234b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
235b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
236b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
237b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
23825fd5c7bSAlex Wilson 			.End()
23925fd5c7bSAlex Wilson 		.View());
240b21d610eSAxel Dörfler 
241b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
242c9e8f97aSAdrien Destugues 		B_TRANSLATE("Set background" B_UTF8_ELLIPSIS),
243b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
244b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
245b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
246a10cf76eSAxel Dörfler 
247a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
248a10cf76eSAxel Dörfler 
249b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
250b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
25125fd5c7bSAlex Wilson 	BGroupView* outerControlsView = new BGroupView(B_VERTICAL, 10.0);
25225fd5c7bSAlex Wilson 	outerControlsView->GroupLayout()->SetInsets(10, 10, 10, 10);
253b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
254a10cf76eSAxel Dörfler 
255551c9f15SSiarzhuk Zharski 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
256a10cf76eSAxel Dörfler 
25766ab1666SAxel Dörfler 	uint16 maxWidth = 0;
25866ab1666SAxel Dörfler 	uint16 maxHeight = 0;
25966ab1666SAxel Dörfler 	uint16 previousWidth = 0;
26066ab1666SAxel Dörfler 	uint16 previousHeight = 0;
261a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
262a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
263a10cf76eSAxel Dörfler 
264a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
265a10cf76eSAxel Dörfler 			continue;
266a10cf76eSAxel Dörfler 
267a10cf76eSAxel Dörfler 		previousWidth = mode.width;
268a10cf76eSAxel Dörfler 		previousHeight = mode.height;
26966ab1666SAxel Dörfler 		if (maxWidth < mode.width)
27066ab1666SAxel Dörfler 			maxWidth = mode.width;
27166ab1666SAxel Dörfler 		if (maxHeight < mode.height)
27266ab1666SAxel Dörfler 			maxHeight = mode.height;
273a10cf76eSAxel Dörfler 
274a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
275a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
276a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
277a10cf76eSAxel Dörfler 
278a10cf76eSAxel Dörfler 		BString name;
279a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
280a10cf76eSAxel Dörfler 
281a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
282a10cf76eSAxel Dörfler 	}
283a10cf76eSAxel Dörfler 
28466ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
28566ab1666SAxel Dörfler 
286c9e8f97aSAdrien Destugues 	fResolutionField = new BMenuField("ResolutionMenu",
28710dfe897SAxel Dörfler 		B_TRANSLATE("Resolution:"), fResolutionMenu);
288a10cf76eSAxel Dörfler 
289551c9f15SSiarzhuk Zharski 	fColorsMenu = new BPopUpMenu("colors", true, false);
290a10cf76eSAxel Dörfler 
291a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
2921fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
2931fc4cb1fSAxel Dörfler 			continue;
2941fc4cb1fSAxel Dörfler 
295a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
296a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
297a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
298a10cf76eSAxel Dörfler 
2991fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
3001fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
3011fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
3021fc4cb1fSAxel Dörfler 
3031fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
304a10cf76eSAxel Dörfler 	}
305a10cf76eSAxel Dörfler 
306c9e8f97aSAdrien Destugues 	fColorsField = new BMenuField("ColorsMenu", B_TRANSLATE("Colors:"),
30710dfe897SAxel Dörfler 		fColorsMenu);
308a10cf76eSAxel Dörfler 
309551c9f15SSiarzhuk Zharski 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
310a10cf76eSAxel Dörfler 
31129e8a73aSAxel Dörfler 	BMessage *message;
31229e8a73aSAxel Dörfler 
31329e8a73aSAxel Dörfler 	float min, max;
31429e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
31529e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
31629e8a73aSAxel Dörfler 		// frequency, like the VESA driver
31729e8a73aSAxel Dörfler 		BString name;
318551c9f15SSiarzhuk Zharski 		name << min << " " << B_TRANSLATE("Hz");
31929e8a73aSAxel Dörfler 
32029e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
32129e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
32229e8a73aSAxel Dörfler 
32329e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
32429e8a73aSAxel Dörfler 		item->SetEnabled(false);
32529e8a73aSAxel Dörfler 	} else {
32670a2b1b5SAxel Dörfler 		monitor_info info;
32770a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
32870a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
32970a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
33070a2b1b5SAxel Dörfler 		}
33170a2b1b5SAxel Dörfler 
332a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
33370a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
33470a2b1b5SAxel Dörfler 				continue;
33570a2b1b5SAxel Dörfler 
336a10cf76eSAxel Dörfler 			BString name;
337551c9f15SSiarzhuk Zharski 			name << kRefreshRates[i] << " " << B_TRANSLATE("Hz");
338a10cf76eSAxel Dörfler 
33929e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
340a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
341a10cf76eSAxel Dörfler 
342a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
343a10cf76eSAxel Dörfler 		}
344a10cf76eSAxel Dörfler 
34529e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
346a10cf76eSAxel Dörfler 
347c9e8f97aSAdrien Destugues 		fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
348c9e8f97aSAdrien Destugues 			message);
349a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
35029e8a73aSAxel Dörfler 	}
351a10cf76eSAxel Dörfler 
352c9e8f97aSAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"),
35310dfe897SAxel Dörfler 		fRefreshMenu);
354b21d610eSAxel Dörfler 
35512580984SAxel Dörfler 	if (_IsVesa())
35612580984SAxel Dörfler 		fRefreshField->Hide();
357a10cf76eSAxel Dörfler 
358a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
359a10cf76eSAxel Dörfler 	{
360a10cf76eSAxel Dörfler 		bool dummy;
361a10cf76eSAxel Dörfler 		uint32 dummy32;
362a10cf76eSAxel Dörfler 		bool multiMonSupport;
363a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
364a10cf76eSAxel Dörfler 		bool tvStandardSupport;
365a10cf76eSAxel Dörfler 
366a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
367a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
368a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
369a10cf76eSAxel Dörfler 
370a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
371a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
372a10cf76eSAxel Dörfler 
373551c9f15SSiarzhuk Zharski 		fCombineMenu = new BPopUpMenu("CombineDisplays",
374c9e8f97aSAdrien Destugues 			true, true);
375a10cf76eSAxel Dörfler 
376a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
377a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
378a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
379a10cf76eSAxel Dörfler 
380d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
381d1516993SAxel Dörfler 				message));
382a10cf76eSAxel Dörfler 		}
383a10cf76eSAxel Dörfler 
384b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
38510dfe897SAxel Dörfler 			B_TRANSLATE("Combine displays:"), fCombineMenu);
386a10cf76eSAxel Dörfler 
387a10cf76eSAxel Dörfler 		if (!multiMonSupport)
388df3f5bacSStephan Aßmus 			fCombineField->Hide();
389a10cf76eSAxel Dörfler 
390551c9f15SSiarzhuk Zharski 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays",
391c9e8f97aSAdrien Destugues 			true, true);
392a10cf76eSAxel Dörfler 
393a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
394a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
395a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
396c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message));
397a10cf76eSAxel Dörfler 
398a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
399a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
400c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message));
401a10cf76eSAxel Dörfler 
402c9e8f97aSAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu",
40310dfe897SAxel Dörfler 			B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu);
404a10cf76eSAxel Dörfler 
405a10cf76eSAxel Dörfler 		if (!multiMonSupport)
406df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
407a10cf76eSAxel Dörfler 
408551c9f15SSiarzhuk Zharski 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel",
409c9e8f97aSAdrien Destugues 			true, true);
410a10cf76eSAxel Dörfler 
411a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
412a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
413a10cf76eSAxel Dörfler 		message->AddBool("use", false);
414c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"),
415c9e8f97aSAdrien Destugues 			message));
416a10cf76eSAxel Dörfler 
417a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
418a10cf76eSAxel Dörfler 		message->AddBool("use", true);
419c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"),
420c9e8f97aSAdrien Destugues 			message));
421a10cf76eSAxel Dörfler 
422b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
42310dfe897SAxel Dörfler 			B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu);
424a10cf76eSAxel Dörfler 
425a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
426df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
427a10cf76eSAxel Dörfler 
428551c9f15SSiarzhuk Zharski 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
429a10cf76eSAxel Dörfler 
430a10cf76eSAxel Dörfler 		// arbitrary limit
431a10cf76eSAxel Dörfler 		uint32 i;
432a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
433a10cf76eSAxel Dörfler 			uint32 mode;
434a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
435a10cf76eSAxel Dörfler 				break;
436a10cf76eSAxel Dörfler 
437a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
438a10cf76eSAxel Dörfler 
439a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
440a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
441a10cf76eSAxel Dörfler 
442a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
443a10cf76eSAxel Dörfler 		}
444a10cf76eSAxel Dörfler 
445c9e8f97aSAdrien Destugues 		fTVStandardField = new BMenuField("tv standard",
44610dfe897SAxel Dörfler 			B_TRANSLATE("Video format:"), fTVStandardMenu);
447df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
448a10cf76eSAxel Dörfler 
449b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
450df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
451a10cf76eSAxel Dörfler 	}
452a10cf76eSAxel Dörfler 
45325fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
45425fd5c7bSAlex Wilson 		.AddGrid(5.0, 5.0)
455b21d610eSAxel Dörfler 			.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
456b21d610eSAxel Dörfler 			.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
457b21d610eSAxel Dörfler 			.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
458b21d610eSAxel Dörfler 			.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
459b21d610eSAxel Dörfler 			.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
460b21d610eSAxel Dörfler 			.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
46125fd5c7bSAlex Wilson 			.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT)
46225fd5c7bSAlex Wilson 		.End();
463df3f5bacSStephan Aßmus 
464abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
465abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
466b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
467a10cf76eSAxel Dörfler 
468c9e8f97aSAdrien Destugues 	fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"),
469df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
470df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
47125fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
472b21d610eSAxel Dörfler 		.AddGlue()
47325fd5c7bSAlex Wilson 			.AddGroup(B_HORIZONTAL)
47425fd5c7bSAlex Wilson 			.AddGlue()
47525fd5c7bSAlex Wilson 			.Add(fApplyButton);
476b21d610eSAxel Dörfler 
477c9e8f97aSAdrien Destugues 	fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"),
478b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
479b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
480b21d610eSAxel Dörfler 
48125fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(this, B_VERTICAL, 10.0)
482b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
483b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
484b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
48525fd5c7bSAlex Wilson 				.AddStrut(controlsBox->TopBorderOffset() - 1)
486b21d610eSAxel Dörfler 				.Add(screenBox)
487b21d610eSAxel Dörfler 			.End()
488b21d610eSAxel Dörfler 			.Add(controlsBox)
489b21d610eSAxel Dörfler 		.End()
490b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
491b21d610eSAxel Dörfler 			.Add(fRevertButton)
492b21d610eSAxel Dörfler 			.AddGlue();
493b21d610eSAxel Dörfler 
4945de171daSAxel Dörfler 	_UpdateControls();
49512966d04SAxel Dörfler 	_UpdateMonitor();
496a10cf76eSAxel Dörfler }
497a10cf76eSAxel Dörfler 
498a10cf76eSAxel Dörfler 
499a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
500a10cf76eSAxel Dörfler {
501a10cf76eSAxel Dörfler 	delete fSettings;
502a10cf76eSAxel Dörfler }
503a10cf76eSAxel Dörfler 
504a10cf76eSAxel Dörfler 
505a10cf76eSAxel Dörfler bool
506a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
507a10cf76eSAxel Dörfler {
508a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
509199893c3SAxel Dörfler 
510199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
511199893c3SAxel Dörfler 	screen_mode vesaMode;
512199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
513199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
51412580984SAxel Dörfler 		if (status < B_OK) {
515c9e8f97aSAdrien Destugues 			BString warning = B_TRANSLATE("Could not write VESA mode settings"
516c9e8f97aSAdrien Destugues 				" file:\n\t");
51712580984SAxel Dörfler 			warning << strerror(status);
518551c9f15SSiarzhuk Zharski 			(new BAlert(B_TRANSLATE("Warning"), warning.String(), B_TRANSLATE("OK"), NULL,
519c9e8f97aSAdrien Destugues 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
52012580984SAxel Dörfler 		}
52112580984SAxel Dörfler 	}
52212580984SAxel Dörfler 
523a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
524a10cf76eSAxel Dörfler 
525a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
526a10cf76eSAxel Dörfler }
527a10cf76eSAxel Dörfler 
528a10cf76eSAxel Dörfler 
5295de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5301fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
531a10cf76eSAxel Dörfler */
532a10cf76eSAxel Dörfler void
5335de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
534a10cf76eSAxel Dörfler {
535a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
536a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
537a10cf76eSAxel Dörfler 
538a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
539a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
540a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
541a10cf76eSAxel Dörfler 			continue;
542a10cf76eSAxel Dörfler 
543a10cf76eSAxel Dörfler 		BString name;
544a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
545a10cf76eSAxel Dörfler 
546a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
547a10cf76eSAxel Dörfler 		if (item != NULL)
548a10cf76eSAxel Dörfler 			item->SetEnabled(true);
549a10cf76eSAxel Dörfler 	}
550a10cf76eSAxel Dörfler }
551a10cf76eSAxel Dörfler 
552a10cf76eSAxel Dörfler 
5535de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5545de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5555de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5565de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
557a10cf76eSAxel Dörfler */
558a10cf76eSAxel Dörfler void
5595de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
560a10cf76eSAxel Dörfler {
5611fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5621fc4cb1fSAxel Dörfler 	int32 index = 0;
5631fc4cb1fSAxel Dörfler 
564a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5651fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5661fc4cb1fSAxel Dörfler 			continue;
5671fc4cb1fSAxel Dörfler 
568a10cf76eSAxel Dörfler 		bool supported = false;
569a10cf76eSAxel Dörfler 
570a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
571a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
572a10cf76eSAxel Dörfler 
573a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
574a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5751fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
576a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5771fc4cb1fSAxel Dörfler 				supportsAnything = true;
578a10cf76eSAxel Dörfler 				supported = true;
579a10cf76eSAxel Dörfler 				break;
580a10cf76eSAxel Dörfler 			}
581a10cf76eSAxel Dörfler 		}
582a10cf76eSAxel Dörfler 
5831fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
584a10cf76eSAxel Dörfler 		if (item)
585a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
586a10cf76eSAxel Dörfler 	}
5871fc4cb1fSAxel Dörfler 
5881fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5891fc4cb1fSAxel Dörfler 
5901fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5911fc4cb1fSAxel Dörfler 		return;
5921fc4cb1fSAxel Dörfler 
5931fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5941fc4cb1fSAxel Dörfler 
5951fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
5961fc4cb1fSAxel Dörfler 	bool changed = false;
5971fc4cb1fSAxel Dörfler 
5981fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
5991fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
6001fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
6011fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
6021fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6031fc4cb1fSAxel Dörfler 			changed = true;
6041fc4cb1fSAxel Dörfler 		}
6051fc4cb1fSAxel Dörfler 	}
6061fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6071fc4cb1fSAxel Dörfler 		// find the next best item
6081fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6091fc4cb1fSAxel Dörfler 		bool found = false;
6101fc4cb1fSAxel Dörfler 
6111fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6121fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6131fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6141fc4cb1fSAxel Dörfler 				found = true;
6151fc4cb1fSAxel Dörfler 				break;
6161fc4cb1fSAxel Dörfler 			}
6171fc4cb1fSAxel Dörfler 		}
6181fc4cb1fSAxel Dörfler 		if (!found) {
6191fc4cb1fSAxel Dörfler 			// search backwards as well
6201fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6211fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6221fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6231fc4cb1fSAxel Dörfler 					break;
6241fc4cb1fSAxel Dörfler 			}
6251fc4cb1fSAxel Dörfler 		}
6261fc4cb1fSAxel Dörfler 
6271fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6281fc4cb1fSAxel Dörfler 		changed = true;
6291fc4cb1fSAxel Dörfler 	}
6301fc4cb1fSAxel Dörfler 
6311fc4cb1fSAxel Dörfler 	if (changed) {
6321fc4cb1fSAxel Dörfler 		// Update selected space
6331fc4cb1fSAxel Dörfler 
6341fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6351fc4cb1fSAxel Dörfler 		int32 space;
6361fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6371fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6381fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6391fc4cb1fSAxel Dörfler 		}
6401fc4cb1fSAxel Dörfler 	}
641a10cf76eSAxel Dörfler }
642a10cf76eSAxel Dörfler 
643a10cf76eSAxel Dörfler 
6445de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
645a10cf76eSAxel Dörfler void
6465de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
647a10cf76eSAxel Dörfler {
64829e8a73aSAxel Dörfler 	float min, max;
64929e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
65029e8a73aSAxel Dörfler 		return;
651a10cf76eSAxel Dörfler 
65229e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
65329e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
65429e8a73aSAxel Dörfler 		BMessage* message = item->Message();
65529e8a73aSAxel Dörfler 		float refresh;
65629e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
65729e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
658a10cf76eSAxel Dörfler 	}
659a10cf76eSAxel Dörfler }
660a10cf76eSAxel Dörfler 
661a10cf76eSAxel Dörfler 
6625de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
663a10cf76eSAxel Dörfler void
6645de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
665a10cf76eSAxel Dörfler {
666a10cf76eSAxel Dörfler 	BString string;
667a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
668a10cf76eSAxel Dörfler 
669a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
670a10cf76eSAxel Dörfler 	if (item) {
671a10cf76eSAxel Dörfler 		if (!item->IsMarked())
672a10cf76eSAxel Dörfler 			item->SetMarked(true);
67329e8a73aSAxel Dörfler 
67426747978SAdrien Destugues 		// "Other" items only contains a refresh rate when active
67526747978SAdrien Destugues 		fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
676a10cf76eSAxel Dörfler 		return;
677a10cf76eSAxel Dörfler 	}
678a10cf76eSAxel Dörfler 
679a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
680a10cf76eSAxel Dörfler 
681a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
682a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
683a10cf76eSAxel Dörfler 
684a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
685a10cf76eSAxel Dörfler 
686c9e8f97aSAdrien Destugues 	string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
687a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
688a10cf76eSAxel Dörfler }
689a10cf76eSAxel Dörfler 
690a10cf76eSAxel Dörfler 
691a10cf76eSAxel Dörfler void
6925de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
693a10cf76eSAxel Dörfler {
694a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
695a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
696a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
697a10cf76eSAxel Dörfler 
698a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
699a10cf76eSAxel Dörfler }
700a10cf76eSAxel Dörfler 
701a10cf76eSAxel Dörfler 
702a10cf76eSAxel Dörfler void
7035de171daSAxel Dörfler ScreenWindow::_UpdateControls()
704a10cf76eSAxel Dörfler {
705b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
706b21d610eSAxel Dörfler 
707a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
708a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
709a10cf76eSAxel Dörfler 		item->SetMarked(true);
710a10cf76eSAxel Dörfler 
711a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
712a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
713a10cf76eSAxel Dörfler 		item->SetMarked(true);
714a10cf76eSAxel Dörfler 
715a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
716a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
717a10cf76eSAxel Dörfler 
718a10cf76eSAxel Dörfler 		uint32 tvStandard;
719a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
720a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
721a10cf76eSAxel Dörfler 			if (!item->IsMarked())
722a10cf76eSAxel Dörfler 				item->SetMarked(true);
723a10cf76eSAxel Dörfler 			break;
724a10cf76eSAxel Dörfler 		}
725a10cf76eSAxel Dörfler 	}
726a10cf76eSAxel Dörfler 
7275de171daSAxel Dörfler 	_CheckResolutionMenu();
7285de171daSAxel Dörfler 	_CheckColorMenu();
7295de171daSAxel Dörfler 	_CheckRefreshMenu();
730a10cf76eSAxel Dörfler 
731a10cf76eSAxel Dörfler 	BString string;
732a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
733a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
734a10cf76eSAxel Dörfler 
735a10cf76eSAxel Dörfler 	if (item != NULL) {
736a10cf76eSAxel Dörfler 		if (!item->IsMarked())
737a10cf76eSAxel Dörfler 			item->SetMarked(true);
738a10cf76eSAxel Dörfler 	} else {
739a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
740a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
741a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
742a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
743a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
744a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
745a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
746a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
747a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
748a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
749a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
750a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
751a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
752a10cf76eSAxel Dörfler 		if (item)
753a10cf76eSAxel Dörfler 			item->SetMarked(true);
754a10cf76eSAxel Dörfler 
755a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
756a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
757a10cf76eSAxel Dörfler 	}
758a10cf76eSAxel Dörfler 
759a10cf76eSAxel Dörfler 	// mark active combine mode
760a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
761a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
762a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
763a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
764a10cf76eSAxel Dörfler 				item->SetMarked(true);
765a10cf76eSAxel Dörfler 			break;
766a10cf76eSAxel Dörfler 		}
767a10cf76eSAxel Dörfler 	}
768a10cf76eSAxel Dörfler 
769a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
770a10cf76eSAxel Dörfler 
7711fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7721fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7731fc4cb1fSAxel Dörfler 			continue;
7741fc4cb1fSAxel Dörfler 
7751fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7761fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
777a10cf76eSAxel Dörfler 			break;
778a10cf76eSAxel Dörfler 		}
7791fc4cb1fSAxel Dörfler 
7801fc4cb1fSAxel Dörfler 		index++;
781a10cf76eSAxel Dörfler 	}
782a10cf76eSAxel Dörfler 
783a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
784a10cf76eSAxel Dörfler 		item->SetMarked(true);
785a10cf76eSAxel Dörfler 
7861fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7875de171daSAxel Dörfler 	_UpdateMonitorView();
7885de171daSAxel Dörfler 	_UpdateRefreshControl();
789a10cf76eSAxel Dörfler 
7905de171daSAxel Dörfler 	_CheckApplyEnabled();
791a10cf76eSAxel Dörfler }
792a10cf76eSAxel Dörfler 
793a10cf76eSAxel Dörfler 
79412580984SAxel Dörfler /*! Reflect active mode in chosen settings */
795a10cf76eSAxel Dörfler void
7965de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
797a10cf76eSAxel Dörfler {
79812580984SAxel Dörfler 	// Usually, this function gets called after a mode
799a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
800a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
801a10cf76eSAxel Dörfler 	// what kind of mode we actually got
802a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
803a10cf76eSAxel Dörfler 	fSelected = fActive;
804a10cf76eSAxel Dörfler 
80512966d04SAxel Dörfler 	_UpdateMonitor();
8065de171daSAxel Dörfler 	_UpdateControls();
807a10cf76eSAxel Dörfler }
808a10cf76eSAxel Dörfler 
809a10cf76eSAxel Dörfler 
810a10cf76eSAxel Dörfler void
811b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
812b21d610eSAxel Dörfler {
813b21d610eSAxel Dörfler 	uint32 columns;
814b21d610eSAxel Dörfler 	uint32 rows;
815b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
816b21d610eSAxel Dörfler 
817b21d610eSAxel Dörfler 	char text[32];
818b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
819b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
820b21d610eSAxel Dörfler 
821b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
822b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
823b21d610eSAxel Dörfler 
824b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
825b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
826b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
827b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
828b21d610eSAxel Dörfler }
829b21d610eSAxel Dörfler 
830b21d610eSAxel Dörfler 
831b21d610eSAxel Dörfler void
832a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
833a10cf76eSAxel Dörfler {
834a10cf76eSAxel Dörfler 	// move window on screen, if necessary
835a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
836a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
837a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
838a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
839a10cf76eSAxel Dörfler 	}
840a10cf76eSAxel Dörfler }
841a10cf76eSAxel Dörfler 
842a10cf76eSAxel Dörfler 
843a10cf76eSAxel Dörfler void
844a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
845a10cf76eSAxel Dörfler {
846abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8475de171daSAxel Dörfler 	_UpdateActiveMode();
848a10cf76eSAxel Dörfler 
8496edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8506edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
851a10cf76eSAxel Dörfler }
852a10cf76eSAxel Dörfler 
853a10cf76eSAxel Dörfler 
854a10cf76eSAxel Dörfler void
855a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
856a10cf76eSAxel Dörfler {
857a10cf76eSAxel Dörfler 	switch (message->what) {
858a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8595de171daSAxel Dörfler 			_CheckApplyEnabled();
860a10cf76eSAxel Dörfler 			break;
861a10cf76eSAxel Dörfler 
862b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
863a10cf76eSAxel Dörfler 		{
864b21d610eSAxel Dörfler 			int32 deltaX = 0;
865b21d610eSAxel Dörfler 			int32 deltaY = 0;
866b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
867b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
868b21d610eSAxel Dörfler 
869b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
870b21d610eSAxel Dörfler 				break;
871b21d610eSAxel Dörfler 
872b21d610eSAxel Dörfler 			uint32 newColumns;
873b21d610eSAxel Dörfler 			uint32 newRows;
874b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
875b21d610eSAxel Dörfler 
876b21d610eSAxel Dörfler 			newColumns += deltaX;
877b21d610eSAxel Dörfler 			newRows += deltaY;
878b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
879b21d610eSAxel Dörfler 
880b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8815de171daSAxel Dörfler 			_CheckApplyEnabled();
882b21d610eSAxel Dörfler 			break;
883abc649b8SWaldemar Kornewald 		}
884b21d610eSAxel Dörfler 
885b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
886b21d610eSAxel Dörfler 		{
887b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
888b21d610eSAxel Dörfler 
889b21d610eSAxel Dörfler 			uint32 rows;
890b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
891b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
892b21d610eSAxel Dörfler 
893b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
894b21d610eSAxel Dörfler 			_CheckApplyEnabled();
895b21d610eSAxel Dörfler 			break;
896b21d610eSAxel Dörfler 		}
897b21d610eSAxel Dörfler 
898b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
899b21d610eSAxel Dörfler 		{
900b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
901b21d610eSAxel Dörfler 
902b21d610eSAxel Dörfler 			uint32 columns;
903b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
904b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
905b21d610eSAxel Dörfler 
906b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
907b21d610eSAxel Dörfler 			_CheckApplyEnabled();
908a10cf76eSAxel Dörfler 			break;
909a10cf76eSAxel Dörfler 		}
910a10cf76eSAxel Dörfler 
911a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
912a10cf76eSAxel Dörfler 		{
913a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
914a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
915a10cf76eSAxel Dörfler 
9165de171daSAxel Dörfler 			_CheckColorMenu();
9175de171daSAxel Dörfler 			_CheckRefreshMenu();
918a10cf76eSAxel Dörfler 
9195de171daSAxel Dörfler 			_UpdateMonitorView();
9205de171daSAxel Dörfler 			_UpdateRefreshControl();
921a10cf76eSAxel Dörfler 
9225de171daSAxel Dörfler 			_CheckApplyEnabled();
923a10cf76eSAxel Dörfler 			break;
924a10cf76eSAxel Dörfler 		}
925a10cf76eSAxel Dörfler 
926a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
927a10cf76eSAxel Dörfler 		{
9281fc4cb1fSAxel Dörfler 			int32 space;
9291fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9301fc4cb1fSAxel Dörfler 				break;
931a10cf76eSAxel Dörfler 
9321fc4cb1fSAxel Dörfler 			int32 index;
9331fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9341fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9351fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9361fc4cb1fSAxel Dörfler 
9371fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9381fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
939a10cf76eSAxel Dörfler 
9405de171daSAxel Dörfler 			_CheckApplyEnabled();
941a10cf76eSAxel Dörfler 			break;
942a10cf76eSAxel Dörfler 		}
943a10cf76eSAxel Dörfler 
944a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
945a40498e2SWaldemar Kornewald 		{
946a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
947c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
9481fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
949a10cf76eSAxel Dörfler 
9505de171daSAxel Dörfler 			_CheckApplyEnabled();
951a10cf76eSAxel Dörfler 			break;
952a40498e2SWaldemar Kornewald 		}
953a10cf76eSAxel Dörfler 
954a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
955a10cf76eSAxel Dörfler 		{
95629e8a73aSAxel Dörfler 			// make sure menu shows something useful
9575de171daSAxel Dörfler 			_UpdateRefreshControl();
958a10cf76eSAxel Dörfler 
95929e8a73aSAxel Dörfler 			float min = 0, max = 999;
96029e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
96129e8a73aSAxel Dörfler 			if (min < gMinRefresh)
96229e8a73aSAxel Dörfler 				min = gMinRefresh;
96329e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
96429e8a73aSAxel Dörfler 				max = gMaxRefresh;
96529e8a73aSAxel Dörfler 
96670a2b1b5SAxel Dörfler 			monitor_info info;
96770a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
96870a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
96970a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
97070a2b1b5SAxel Dörfler 			}
97170a2b1b5SAxel Dörfler 
972c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
97370a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
97470a2b1b5SAxel Dörfler 				min, max);
975a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
976a10cf76eSAxel Dörfler 			break;
977a10cf76eSAxel Dörfler 		}
978a10cf76eSAxel Dörfler 
979a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
980a10cf76eSAxel Dörfler 		{
981a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
982a10cf76eSAxel Dörfler 			// select the refresh rate chosen
983a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
984a10cf76eSAxel Dörfler 
9855de171daSAxel Dörfler 			_UpdateRefreshControl();
9865de171daSAxel Dörfler 			_CheckApplyEnabled();
987a10cf76eSAxel Dörfler 			break;
988a10cf76eSAxel Dörfler 		}
989a10cf76eSAxel Dörfler 
990a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
991a10cf76eSAxel Dörfler 		{
992a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
993a10cf76eSAxel Dörfler 			int32 mode;
994a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
995a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
996a10cf76eSAxel Dörfler 
9975de171daSAxel Dörfler 			_CheckResolutionMenu();
9985de171daSAxel Dörfler 			_CheckApplyEnabled();
999a10cf76eSAxel Dörfler 			break;
1000a10cf76eSAxel Dörfler 		}
1001a10cf76eSAxel Dörfler 
1002a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1003a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10045de171daSAxel Dörfler 			_CheckApplyEnabled();
1005a10cf76eSAxel Dörfler 			break;
1006a10cf76eSAxel Dörfler 
1007a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1008a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10095de171daSAxel Dörfler 			_CheckApplyEnabled();
1010a10cf76eSAxel Dörfler 			break;
1011a10cf76eSAxel Dörfler 
1012a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1013a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10145de171daSAxel Dörfler 			_CheckApplyEnabled();
1015a10cf76eSAxel Dörfler 			break;
1016a10cf76eSAxel Dörfler 
1017df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10186f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10196f095d6aSRyan Leavengood 				app_info info;
10206f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10216f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10226f095d6aSRyan Leavengood 			}
1023df3f5bacSStephan Aßmus 			break;
1024df3f5bacSStephan Aßmus 
1025a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1026a10cf76eSAxel Dörfler 		{
10274be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1028a10cf76eSAxel Dörfler 			fSelected.width = 640;
1029a10cf76eSAxel Dörfler 			fSelected.height = 480;
1030a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1031a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1032a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1033a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1034a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1035a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1036a10cf76eSAxel Dörfler 
1037b21d610eSAxel Dörfler 			// TODO: workspace defaults
1038abc649b8SWaldemar Kornewald 
10395de171daSAxel Dörfler 			_UpdateControls();
1040a10cf76eSAxel Dörfler 			break;
1041a10cf76eSAxel Dörfler 		}
1042a10cf76eSAxel Dörfler 
104310e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
104461c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10455de171daSAxel Dörfler 			_UpdateActiveMode();
1046abc649b8SWaldemar Kornewald 			break;
1047abc649b8SWaldemar Kornewald 
1048abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1049abc649b8SWaldemar Kornewald 		{
1050abc649b8SWaldemar Kornewald 			fModified = false;
1051199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1052abc649b8SWaldemar Kornewald 
1053b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1054b21d610eSAxel Dörfler 			// number of workspaces
1055b21d610eSAxel Dörfler 
1056b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1057b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1058b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1059b21d610eSAxel Dörfler 
1060a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10615de171daSAxel Dörfler 			_UpdateActiveMode();
1062a10cf76eSAxel Dörfler 			break;
1063abc649b8SWaldemar Kornewald 		}
1064a10cf76eSAxel Dörfler 
1065a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10665de171daSAxel Dörfler 			_Apply();
1067a10cf76eSAxel Dörfler 			break;
1068a10cf76eSAxel Dörfler 
1069abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1070abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1071abc649b8SWaldemar Kornewald 			fModified = true;
10725de171daSAxel Dörfler 			_UpdateActiveMode();
1073a10cf76eSAxel Dörfler 			break;
1074a10cf76eSAxel Dörfler 
1075a10cf76eSAxel Dörfler 		default:
1076a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1077a10cf76eSAxel Dörfler 			break;
1078a10cf76eSAxel Dörfler 	}
1079a10cf76eSAxel Dörfler }
1080a10cf76eSAxel Dörfler 
1081a10cf76eSAxel Dörfler 
108212580984SAxel Dörfler status_t
108312580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
108412580984SAxel Dörfler {
108512580984SAxel Dörfler 	BPath path;
108612580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
108712580984SAxel Dörfler 	if (status < B_OK)
108812580984SAxel Dörfler 		return status;
108912580984SAxel Dörfler 
109012580984SAxel Dörfler 	path.Append("kernel/drivers");
109112580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
109212580984SAxel Dörfler 	if (status < B_OK)
109312580984SAxel Dörfler 		return status;
109412580984SAxel Dörfler 
109512580984SAxel Dörfler 	path.Append("vesa");
109612580984SAxel Dörfler 	BFile file;
109712580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
109812580984SAxel Dörfler 	if (status < B_OK)
109912580984SAxel Dörfler 		return status;
110012580984SAxel Dörfler 
110112580984SAxel Dörfler 	char buffer[256];
110212580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
110312580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
110412580984SAxel Dörfler 
110512580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
110612580984SAxel Dörfler 	if (bytesWritten < B_OK)
110712580984SAxel Dörfler 		return bytesWritten;
110812580984SAxel Dörfler 
110912580984SAxel Dörfler 	return B_OK;
111012580984SAxel Dörfler }
111112580984SAxel Dörfler 
111212580984SAxel Dörfler 
1113b21d610eSAxel Dörfler BButton*
1114b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1115b21d610eSAxel Dörfler {
1116b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1117b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1118b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1119b21d610eSAxel Dörfler 
1120b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1121b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1122b21d610eSAxel Dörfler 
1123b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1124b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1125b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1126b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1127b21d610eSAxel Dörfler 
1128b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1129b21d610eSAxel Dörfler 	return button;
1130b21d610eSAxel Dörfler }
1131b21d610eSAxel Dörfler 
1132b21d610eSAxel Dörfler 
1133b21d610eSAxel Dörfler BButton*
1134b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1135b21d610eSAxel Dörfler {
1136b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1137b21d610eSAxel Dörfler }
1138b21d610eSAxel Dörfler 
1139b21d610eSAxel Dörfler 
1140a10cf76eSAxel Dörfler void
11411fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11421fc4cb1fSAxel Dörfler {
11431fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11441fc4cb1fSAxel Dörfler 
11451fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11461fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11471fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11481fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11491fc4cb1fSAxel Dörfler 				break;
11501fc4cb1fSAxel Dörfler 			}
11511fc4cb1fSAxel Dörfler 		}
11521fc4cb1fSAxel Dörfler 	}
11531fc4cb1fSAxel Dörfler }
11541fc4cb1fSAxel Dörfler 
11551fc4cb1fSAxel Dörfler 
11561fc4cb1fSAxel Dörfler void
11575de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1158a10cf76eSAxel Dörfler {
115927c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
116027c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1161b21d610eSAxel Dörfler 
1162b21d610eSAxel Dörfler 	uint32 columns;
1163b21d610eSAxel Dörfler 	uint32 rows;
1164b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1165b21d610eSAxel Dörfler 
1166b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1167b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11685de171daSAxel Dörfler 		|| fSelected != fOriginal);
1169a10cf76eSAxel Dörfler }
1170a10cf76eSAxel Dörfler 
1171a10cf76eSAxel Dörfler 
1172a10cf76eSAxel Dörfler void
11735de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1174abc649b8SWaldemar Kornewald {
1175b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1176b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1177b21d610eSAxel Dörfler 
1178abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1179abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1180abc649b8SWaldemar Kornewald }
1181abc649b8SWaldemar Kornewald 
1182abc649b8SWaldemar Kornewald 
1183abc649b8SWaldemar Kornewald void
118412966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
118512966d04SAxel Dörfler {
118612966d04SAxel Dörfler 	monitor_info info;
118712966d04SAxel Dörfler 	float diagonalInches;
118812966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
118955030977SAxel Dörfler 	if (status == B_OK) {
11901a8af605SAxel Dörfler 		char text[512];
119166ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
119266ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
119312966d04SAxel Dörfler 
119412966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
119512966d04SAxel Dörfler 
119612966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
119712966d04SAxel Dörfler 			fMonitorInfo->Show();
119855030977SAxel Dörfler 	} else {
119955030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
120055030977SAxel Dörfler 			fMonitorInfo->Hide();
120155030977SAxel Dörfler 	}
1202af8f9c31SAxel Dörfler 
120355030977SAxel Dörfler 	char text[512];
12041a8af605SAxel Dörfler 	size_t length = 0;
12051a8af605SAxel Dörfler 	text[0] = 0;
12061a8af605SAxel Dörfler 
120755030977SAxel Dörfler 	if (status == B_OK) {
1208af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1209af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1210af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12111a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1212c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12139c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1214c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12151a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12161a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12171a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1218af8f9c31SAxel Dörfler 		}
12191a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12201a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1221c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12221a8af605SAxel Dörfler 				info.serial_number);
12231a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12241a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12251a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12261a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12271a8af605SAxel Dörfler 	 		}
12281a8af605SAxel Dörfler 		}
122955030977SAxel Dörfler 	}
123061c5c89bSAxel Dörfler 
123161c5c89bSAxel Dörfler 	// Add info about the graphics device
123261c5c89bSAxel Dörfler 
123361c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
123461c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
123561c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
123661c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
123761c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123861c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
123961c5c89bSAxel Dörfler 				deviceInfo.chipset);
124061c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
124161c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
124261c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
124361c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
124461c5c89bSAxel Dörfler 		}
124561c5c89bSAxel Dörfler 	}
124661c5c89bSAxel Dörfler 
12471a8af605SAxel Dörfler 	if (text[0])
12481a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
124912966d04SAxel Dörfler }
125012966d04SAxel Dörfler 
125112966d04SAxel Dörfler 
125212966d04SAxel Dörfler void
12531fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12541fc4cb1fSAxel Dörfler {
12551fc4cb1fSAxel Dörfler 	BString string;
1256551c9f15SSiarzhuk Zharski 	string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel");
12571fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12581fc4cb1fSAxel Dörfler }
12591fc4cb1fSAxel Dörfler 
12601fc4cb1fSAxel Dörfler 
12611fc4cb1fSAxel Dörfler void
12625de171daSAxel Dörfler ScreenWindow::_Apply()
1263a10cf76eSAxel Dörfler {
1264abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
126561c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
126661c5c89bSAxel Dörfler 
126707184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
126807184a9eSAxel Dörfler 	if (status == B_OK) {
1269abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1270abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1271abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1272abc649b8SWaldemar Kornewald 		display_mode newMode;
1273abc649b8SWaldemar Kornewald 		BScreen screen(this);
1274abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1275abc649b8SWaldemar Kornewald 
1276abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1277abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1278abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1279abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1280abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1281abc649b8SWaldemar Kornewald 			}
1282199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1283199893c3SAxel Dörfler 		} else {
1284199893c3SAxel Dörfler 			if (current_workspace() == 0)
1285199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1286abc649b8SWaldemar Kornewald 		}
1287abc649b8SWaldemar Kornewald 
1288a10cf76eSAxel Dörfler 		fActive = fSelected;
1289a10cf76eSAxel Dörfler 
1290abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1291a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1292a10cf76eSAxel Dörfler 		window->Show();
129307184a9eSAxel Dörfler 	} else {
129407184a9eSAxel Dörfler 		char message[256];
129507184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1296c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1297c9e8f97aSAdrien Destugues 			screen_errors(status));
1298551c9f15SSiarzhuk Zharski 		BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message,
1299c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
130007184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
130107184a9eSAxel Dörfler 		alert->Go();
1302a10cf76eSAxel Dörfler 	}
130307184a9eSAxel Dörfler }
130407184a9eSAxel Dörfler 
1305