xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision cf0769649ecb448f3f1be418cfdd459f7c14486d)
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 
66c9e8f97aSAdrien Destugues #undef B_TRANSLATE_CONTEXT
67c9e8f97aSAdrien Destugues #define B_TRANSLATE_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;
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;
3187e44de36SRene Gollent 		refresh_rate_to_string(min, name);
319*cf076964SRene Gollent 		BMessage *message = new BMessage(POP_REFRESH_MSG);
320*cf076964SRene Gollent 		message->AddFloat("refresh", min);
321*cf076964SRene Gollent 		BMenuItem *item = new BMenuItem(name.String(), message);
3220efb8b66SJerome Duval 		fRefreshMenu->AddItem(item);
32329e8a73aSAxel Dörfler 		item->SetEnabled(false);
32429e8a73aSAxel Dörfler 	} else {
32570a2b1b5SAxel Dörfler 		monitor_info info;
32670a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
32770a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
32870a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
32970a2b1b5SAxel Dörfler 		}
33070a2b1b5SAxel Dörfler 
331a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
33270a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
33370a2b1b5SAxel Dörfler 				continue;
33470a2b1b5SAxel Dörfler 
335a10cf76eSAxel Dörfler 			BString name;
336551c9f15SSiarzhuk Zharski 			name << kRefreshRates[i] << " " << B_TRANSLATE("Hz");
337a10cf76eSAxel Dörfler 
3380efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_REFRESH_MSG);
339a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
340a10cf76eSAxel Dörfler 
341a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
342a10cf76eSAxel Dörfler 		}
343a10cf76eSAxel Dörfler 
344c9e8f97aSAdrien Destugues 		fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
3450efb8b66SJerome Duval 			new BMessage(POP_OTHER_REFRESH_MSG));
346a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
34729e8a73aSAxel Dörfler 	}
348a10cf76eSAxel Dörfler 
349c9e8f97aSAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"),
35010dfe897SAxel Dörfler 		fRefreshMenu);
351b21d610eSAxel Dörfler 
35212580984SAxel Dörfler 	if (_IsVesa())
35312580984SAxel Dörfler 		fRefreshField->Hide();
354a10cf76eSAxel Dörfler 
355a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
356a10cf76eSAxel Dörfler 	{
357a10cf76eSAxel Dörfler 		bool dummy;
358a10cf76eSAxel Dörfler 		uint32 dummy32;
359a10cf76eSAxel Dörfler 		bool multiMonSupport;
360a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
361a10cf76eSAxel Dörfler 		bool tvStandardSupport;
362a10cf76eSAxel Dörfler 
363a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
364a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
365a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
366a10cf76eSAxel Dörfler 
367a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
368a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
369a10cf76eSAxel Dörfler 
370551c9f15SSiarzhuk Zharski 		fCombineMenu = new BPopUpMenu("CombineDisplays",
371c9e8f97aSAdrien Destugues 			true, true);
372a10cf76eSAxel Dörfler 
373a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
3740efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
375a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
376a10cf76eSAxel Dörfler 
377d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
378d1516993SAxel Dörfler 				message));
379a10cf76eSAxel Dörfler 		}
380a10cf76eSAxel Dörfler 
381b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
38210dfe897SAxel Dörfler 			B_TRANSLATE("Combine displays:"), fCombineMenu);
383a10cf76eSAxel Dörfler 
384a10cf76eSAxel Dörfler 		if (!multiMonSupport)
385df3f5bacSStephan Aßmus 			fCombineField->Hide();
386a10cf76eSAxel Dörfler 
387551c9f15SSiarzhuk Zharski 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays",
388c9e8f97aSAdrien Destugues 			true, true);
389a10cf76eSAxel Dörfler 
390a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
3910efb8b66SJerome Duval 		BMessage *message = new BMessage(POP_SWAP_DISPLAYS_MSG);
392a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
393c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message));
394a10cf76eSAxel Dörfler 
395a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
396a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
397c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message));
398a10cf76eSAxel Dörfler 
399c9e8f97aSAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu",
40010dfe897SAxel Dörfler 			B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu);
401a10cf76eSAxel Dörfler 
402a10cf76eSAxel Dörfler 		if (!multiMonSupport)
403df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
404a10cf76eSAxel Dörfler 
405551c9f15SSiarzhuk Zharski 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel",
406c9e8f97aSAdrien Destugues 			true, true);
407a10cf76eSAxel Dörfler 
408a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
409a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
410a10cf76eSAxel Dörfler 		message->AddBool("use", false);
411c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"),
412c9e8f97aSAdrien Destugues 			message));
413a10cf76eSAxel Dörfler 
414a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
415a10cf76eSAxel Dörfler 		message->AddBool("use", true);
416c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"),
417c9e8f97aSAdrien Destugues 			message));
418a10cf76eSAxel Dörfler 
419b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
42010dfe897SAxel Dörfler 			B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu);
421a10cf76eSAxel Dörfler 
422a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
423df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
424a10cf76eSAxel Dörfler 
425551c9f15SSiarzhuk Zharski 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
426a10cf76eSAxel Dörfler 
427a10cf76eSAxel Dörfler 		// arbitrary limit
428a10cf76eSAxel Dörfler 		uint32 i;
429a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
430a10cf76eSAxel Dörfler 			uint32 mode;
431a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
432a10cf76eSAxel Dörfler 				break;
433a10cf76eSAxel Dörfler 
434a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
435a10cf76eSAxel Dörfler 
436a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
437a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
438a10cf76eSAxel Dörfler 
439a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
440a10cf76eSAxel Dörfler 		}
441a10cf76eSAxel Dörfler 
442c9e8f97aSAdrien Destugues 		fTVStandardField = new BMenuField("tv standard",
44310dfe897SAxel Dörfler 			B_TRANSLATE("Video format:"), fTVStandardMenu);
444df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
445a10cf76eSAxel Dörfler 
446b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
447df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
448a10cf76eSAxel Dörfler 	}
449a10cf76eSAxel Dörfler 
45025fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
45125fd5c7bSAlex Wilson 		.AddGrid(5.0, 5.0)
452b21d610eSAxel Dörfler 			.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
453b21d610eSAxel Dörfler 			.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
454b21d610eSAxel Dörfler 			.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
455b21d610eSAxel Dörfler 			.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
456b21d610eSAxel Dörfler 			.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
457b21d610eSAxel Dörfler 			.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
45825fd5c7bSAlex Wilson 			.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT)
45925fd5c7bSAlex Wilson 		.End();
460df3f5bacSStephan Aßmus 
461abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
462abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
463b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
464a10cf76eSAxel Dörfler 
465c9e8f97aSAdrien Destugues 	fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"),
466df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
467df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
46825fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
469b21d610eSAxel Dörfler 		.AddGlue()
47025fd5c7bSAlex Wilson 			.AddGroup(B_HORIZONTAL)
47125fd5c7bSAlex Wilson 			.AddGlue()
47225fd5c7bSAlex Wilson 			.Add(fApplyButton);
473b21d610eSAxel Dörfler 
474c9e8f97aSAdrien Destugues 	fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"),
475b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
476b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
477b21d610eSAxel Dörfler 
47825fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(this, B_VERTICAL, 10.0)
479b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
480b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
481b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
482958e0ca5SJohn Scipione 				.AddStrut(floor(controlsBox->TopBorderOffset() / 16) - 1)
483b21d610eSAxel Dörfler 				.Add(screenBox)
484b21d610eSAxel Dörfler 			.End()
485b21d610eSAxel Dörfler 			.Add(controlsBox)
486b21d610eSAxel Dörfler 		.End()
487b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
488b21d610eSAxel Dörfler 			.Add(fRevertButton)
489b21d610eSAxel Dörfler 			.AddGlue();
490b21d610eSAxel Dörfler 
4915de171daSAxel Dörfler 	_UpdateControls();
49212966d04SAxel Dörfler 	_UpdateMonitor();
493a10cf76eSAxel Dörfler }
494a10cf76eSAxel Dörfler 
495a10cf76eSAxel Dörfler 
496a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
497a10cf76eSAxel Dörfler {
498a10cf76eSAxel Dörfler 	delete fSettings;
499a10cf76eSAxel Dörfler }
500a10cf76eSAxel Dörfler 
501a10cf76eSAxel Dörfler 
502a10cf76eSAxel Dörfler bool
503a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
504a10cf76eSAxel Dörfler {
505a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
506199893c3SAxel Dörfler 
507199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
508199893c3SAxel Dörfler 	screen_mode vesaMode;
509199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
510199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
51112580984SAxel Dörfler 		if (status < B_OK) {
512c9e8f97aSAdrien Destugues 			BString warning = B_TRANSLATE("Could not write VESA mode settings"
513c9e8f97aSAdrien Destugues 				" file:\n\t");
51412580984SAxel Dörfler 			warning << strerror(status);
515551c9f15SSiarzhuk Zharski 			(new BAlert(B_TRANSLATE("Warning"), warning.String(), B_TRANSLATE("OK"), NULL,
516c9e8f97aSAdrien Destugues 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
51712580984SAxel Dörfler 		}
51812580984SAxel Dörfler 	}
51912580984SAxel Dörfler 
520a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
521a10cf76eSAxel Dörfler 
522a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
523a10cf76eSAxel Dörfler }
524a10cf76eSAxel Dörfler 
525a10cf76eSAxel Dörfler 
5265de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5271fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
528a10cf76eSAxel Dörfler */
529a10cf76eSAxel Dörfler void
5305de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
531a10cf76eSAxel Dörfler {
532a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
533a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
534a10cf76eSAxel Dörfler 
535a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
536a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
537a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
538a10cf76eSAxel Dörfler 			continue;
539a10cf76eSAxel Dörfler 
540a10cf76eSAxel Dörfler 		BString name;
541a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
542a10cf76eSAxel Dörfler 
543a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
544a10cf76eSAxel Dörfler 		if (item != NULL)
545a10cf76eSAxel Dörfler 			item->SetEnabled(true);
546a10cf76eSAxel Dörfler 	}
547a10cf76eSAxel Dörfler }
548a10cf76eSAxel Dörfler 
549a10cf76eSAxel Dörfler 
5505de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5515de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5525de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5535de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
554a10cf76eSAxel Dörfler */
555a10cf76eSAxel Dörfler void
5565de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
557a10cf76eSAxel Dörfler {
5581fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5591fc4cb1fSAxel Dörfler 	int32 index = 0;
5601fc4cb1fSAxel Dörfler 
561a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5621fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5631fc4cb1fSAxel Dörfler 			continue;
5641fc4cb1fSAxel Dörfler 
565a10cf76eSAxel Dörfler 		bool supported = false;
566a10cf76eSAxel Dörfler 
567a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
568a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
569a10cf76eSAxel Dörfler 
570a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
571a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5721fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
573a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5741fc4cb1fSAxel Dörfler 				supportsAnything = true;
575a10cf76eSAxel Dörfler 				supported = true;
576a10cf76eSAxel Dörfler 				break;
577a10cf76eSAxel Dörfler 			}
578a10cf76eSAxel Dörfler 		}
579a10cf76eSAxel Dörfler 
5801fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
581a10cf76eSAxel Dörfler 		if (item)
582a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
583a10cf76eSAxel Dörfler 	}
5841fc4cb1fSAxel Dörfler 
5851fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5861fc4cb1fSAxel Dörfler 
5871fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5881fc4cb1fSAxel Dörfler 		return;
5891fc4cb1fSAxel Dörfler 
5901fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5911fc4cb1fSAxel Dörfler 
5921fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
5931fc4cb1fSAxel Dörfler 	bool changed = false;
5941fc4cb1fSAxel Dörfler 
5951fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
5961fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
5971fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
5981fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
5991fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6001fc4cb1fSAxel Dörfler 			changed = true;
6011fc4cb1fSAxel Dörfler 		}
6021fc4cb1fSAxel Dörfler 	}
6031fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6041fc4cb1fSAxel Dörfler 		// find the next best item
6051fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6061fc4cb1fSAxel Dörfler 		bool found = false;
6071fc4cb1fSAxel Dörfler 
6081fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6091fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6101fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6111fc4cb1fSAxel Dörfler 				found = true;
6121fc4cb1fSAxel Dörfler 				break;
6131fc4cb1fSAxel Dörfler 			}
6141fc4cb1fSAxel Dörfler 		}
6151fc4cb1fSAxel Dörfler 		if (!found) {
6161fc4cb1fSAxel Dörfler 			// search backwards as well
6171fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6181fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6191fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6201fc4cb1fSAxel Dörfler 					break;
6211fc4cb1fSAxel Dörfler 			}
6221fc4cb1fSAxel Dörfler 		}
6231fc4cb1fSAxel Dörfler 
6241fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6251fc4cb1fSAxel Dörfler 		changed = true;
6261fc4cb1fSAxel Dörfler 	}
6271fc4cb1fSAxel Dörfler 
6281fc4cb1fSAxel Dörfler 	if (changed) {
6291fc4cb1fSAxel Dörfler 		// Update selected space
6301fc4cb1fSAxel Dörfler 
6311fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6321fc4cb1fSAxel Dörfler 		int32 space;
6331fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6341fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6351fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6361fc4cb1fSAxel Dörfler 		}
6371fc4cb1fSAxel Dörfler 	}
638a10cf76eSAxel Dörfler }
639a10cf76eSAxel Dörfler 
640a10cf76eSAxel Dörfler 
6415de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
642a10cf76eSAxel Dörfler void
6435de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
644a10cf76eSAxel Dörfler {
64529e8a73aSAxel Dörfler 	float min, max;
64629e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
64729e8a73aSAxel Dörfler 		return;
648a10cf76eSAxel Dörfler 
64929e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
65029e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
65129e8a73aSAxel Dörfler 		BMessage* message = item->Message();
65229e8a73aSAxel Dörfler 		float refresh;
65329e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
65429e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
655a10cf76eSAxel Dörfler 	}
656a10cf76eSAxel Dörfler }
657a10cf76eSAxel Dörfler 
658a10cf76eSAxel Dörfler 
6595de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
660a10cf76eSAxel Dörfler void
6615de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
662a10cf76eSAxel Dörfler {
6637e44de36SRene Gollent 	for (int32 i = 0; i < fRefreshMenu->CountItems(); i++) {
6647e44de36SRene Gollent 		BMenuItem* item = fRefreshMenu->ItemAt(i);
6657e44de36SRene Gollent 		if (item->Message()->FindFloat("refresh") == fSelected.refresh) {
666a10cf76eSAxel Dörfler 			item->SetMarked(true);
66726747978SAdrien Destugues 			// "Other" items only contains a refresh rate when active
66826747978SAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
669a10cf76eSAxel Dörfler 			return;
670a10cf76eSAxel Dörfler 		}
6717e44de36SRene Gollent 	}
672a10cf76eSAxel Dörfler 
673a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
6747e44de36SRene Gollent 	if (fOtherRefresh != NULL) {
675a10cf76eSAxel Dörfler 		fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
676a10cf76eSAxel Dörfler 		fOtherRefresh->SetMarked(true);
677a10cf76eSAxel Dörfler 
6787e44de36SRene Gollent 		BString string;
6797e44de36SRene Gollent 		refresh_rate_to_string(fSelected.refresh, string);
680a10cf76eSAxel Dörfler 		fRefreshMenu->Superitem()->SetLabel(string.String());
681a10cf76eSAxel Dörfler 
682c9e8f97aSAdrien Destugues 		string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
683a10cf76eSAxel Dörfler 		fOtherRefresh->SetLabel(string.String());
684a10cf76eSAxel Dörfler 	}
6857e44de36SRene Gollent }
686a10cf76eSAxel Dörfler 
687a10cf76eSAxel Dörfler 
688a10cf76eSAxel Dörfler void
6895de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
690a10cf76eSAxel Dörfler {
691a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
692a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
693a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
694a10cf76eSAxel Dörfler 
695a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
696a10cf76eSAxel Dörfler }
697a10cf76eSAxel Dörfler 
698a10cf76eSAxel Dörfler 
699a10cf76eSAxel Dörfler void
7005de171daSAxel Dörfler ScreenWindow::_UpdateControls()
701a10cf76eSAxel Dörfler {
702b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
703b21d610eSAxel Dörfler 
704a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
705a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
706a10cf76eSAxel Dörfler 		item->SetMarked(true);
707a10cf76eSAxel Dörfler 
708a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
709a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
710a10cf76eSAxel Dörfler 		item->SetMarked(true);
711a10cf76eSAxel Dörfler 
712a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
713a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
714a10cf76eSAxel Dörfler 
715a10cf76eSAxel Dörfler 		uint32 tvStandard;
716a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
717a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
718a10cf76eSAxel Dörfler 			if (!item->IsMarked())
719a10cf76eSAxel Dörfler 				item->SetMarked(true);
720a10cf76eSAxel Dörfler 			break;
721a10cf76eSAxel Dörfler 		}
722a10cf76eSAxel Dörfler 	}
723a10cf76eSAxel Dörfler 
7245de171daSAxel Dörfler 	_CheckResolutionMenu();
7255de171daSAxel Dörfler 	_CheckColorMenu();
7265de171daSAxel Dörfler 	_CheckRefreshMenu();
727a10cf76eSAxel Dörfler 
728a10cf76eSAxel Dörfler 	BString string;
729a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
730a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
731a10cf76eSAxel Dörfler 
732a10cf76eSAxel Dörfler 	if (item != NULL) {
733a10cf76eSAxel Dörfler 		if (!item->IsMarked())
734a10cf76eSAxel Dörfler 			item->SetMarked(true);
735a10cf76eSAxel Dörfler 	} else {
736a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
737a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
738a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
739a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
740a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
741a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
742a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
743a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
744a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
745a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
746a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
747a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
748a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
749a10cf76eSAxel Dörfler 		if (item)
750a10cf76eSAxel Dörfler 			item->SetMarked(true);
751a10cf76eSAxel Dörfler 
752a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
753a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
754a10cf76eSAxel Dörfler 	}
755a10cf76eSAxel Dörfler 
756a10cf76eSAxel Dörfler 	// mark active combine mode
757a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
758a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
759a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
760a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
761a10cf76eSAxel Dörfler 				item->SetMarked(true);
762a10cf76eSAxel Dörfler 			break;
763a10cf76eSAxel Dörfler 		}
764a10cf76eSAxel Dörfler 	}
765a10cf76eSAxel Dörfler 
766a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
767a10cf76eSAxel Dörfler 
7681fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7691fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7701fc4cb1fSAxel Dörfler 			continue;
7711fc4cb1fSAxel Dörfler 
7721fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7731fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
774a10cf76eSAxel Dörfler 			break;
775a10cf76eSAxel Dörfler 		}
7761fc4cb1fSAxel Dörfler 
7771fc4cb1fSAxel Dörfler 		index++;
778a10cf76eSAxel Dörfler 	}
779a10cf76eSAxel Dörfler 
780a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
781a10cf76eSAxel Dörfler 		item->SetMarked(true);
782a10cf76eSAxel Dörfler 
7831fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7845de171daSAxel Dörfler 	_UpdateMonitorView();
7855de171daSAxel Dörfler 	_UpdateRefreshControl();
786a10cf76eSAxel Dörfler 
7875de171daSAxel Dörfler 	_CheckApplyEnabled();
788a10cf76eSAxel Dörfler }
789a10cf76eSAxel Dörfler 
790a10cf76eSAxel Dörfler 
79112580984SAxel Dörfler /*! Reflect active mode in chosen settings */
792a10cf76eSAxel Dörfler void
7935de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
794a10cf76eSAxel Dörfler {
79512580984SAxel Dörfler 	// Usually, this function gets called after a mode
796a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
797a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
798a10cf76eSAxel Dörfler 	// what kind of mode we actually got
799a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
800a10cf76eSAxel Dörfler 	fSelected = fActive;
801a10cf76eSAxel Dörfler 
80212966d04SAxel Dörfler 	_UpdateMonitor();
8035de171daSAxel Dörfler 	_UpdateControls();
804a10cf76eSAxel Dörfler }
805a10cf76eSAxel Dörfler 
806a10cf76eSAxel Dörfler 
807a10cf76eSAxel Dörfler void
808b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
809b21d610eSAxel Dörfler {
810b21d610eSAxel Dörfler 	uint32 columns;
811b21d610eSAxel Dörfler 	uint32 rows;
812b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
813b21d610eSAxel Dörfler 
814b21d610eSAxel Dörfler 	char text[32];
815b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
816b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
817b21d610eSAxel Dörfler 
818b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
819b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
820b21d610eSAxel Dörfler 
821b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
822b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
823b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
824b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
825b21d610eSAxel Dörfler }
826b21d610eSAxel Dörfler 
827b21d610eSAxel Dörfler 
828b21d610eSAxel Dörfler void
829a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
830a10cf76eSAxel Dörfler {
831a10cf76eSAxel Dörfler 	// move window on screen, if necessary
832a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
833a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
834a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
835a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
836a10cf76eSAxel Dörfler 	}
837a10cf76eSAxel Dörfler }
838a10cf76eSAxel Dörfler 
839a10cf76eSAxel Dörfler 
840a10cf76eSAxel Dörfler void
841a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
842a10cf76eSAxel Dörfler {
843abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8445de171daSAxel Dörfler 	_UpdateActiveMode();
845a10cf76eSAxel Dörfler 
8466edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8476edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
848a10cf76eSAxel Dörfler }
849a10cf76eSAxel Dörfler 
850a10cf76eSAxel Dörfler 
851a10cf76eSAxel Dörfler void
852a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
853a10cf76eSAxel Dörfler {
854a10cf76eSAxel Dörfler 	switch (message->what) {
855a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8565de171daSAxel Dörfler 			_CheckApplyEnabled();
857a10cf76eSAxel Dörfler 			break;
858a10cf76eSAxel Dörfler 
859b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
860a10cf76eSAxel Dörfler 		{
861b21d610eSAxel Dörfler 			int32 deltaX = 0;
862b21d610eSAxel Dörfler 			int32 deltaY = 0;
863b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
864b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
865b21d610eSAxel Dörfler 
866b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
867b21d610eSAxel Dörfler 				break;
868b21d610eSAxel Dörfler 
869b21d610eSAxel Dörfler 			uint32 newColumns;
870b21d610eSAxel Dörfler 			uint32 newRows;
871b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
872b21d610eSAxel Dörfler 
873b21d610eSAxel Dörfler 			newColumns += deltaX;
874b21d610eSAxel Dörfler 			newRows += deltaY;
875b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
876b21d610eSAxel Dörfler 
877b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8785de171daSAxel Dörfler 			_CheckApplyEnabled();
879b21d610eSAxel Dörfler 			break;
880abc649b8SWaldemar Kornewald 		}
881b21d610eSAxel Dörfler 
882b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
883b21d610eSAxel Dörfler 		{
884b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
885b21d610eSAxel Dörfler 
886b21d610eSAxel Dörfler 			uint32 rows;
887b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
888b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
889b21d610eSAxel Dörfler 
890b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
891b21d610eSAxel Dörfler 			_CheckApplyEnabled();
892b21d610eSAxel Dörfler 			break;
893b21d610eSAxel Dörfler 		}
894b21d610eSAxel Dörfler 
895b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
896b21d610eSAxel Dörfler 		{
897b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
898b21d610eSAxel Dörfler 
899b21d610eSAxel Dörfler 			uint32 columns;
900b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
901b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
902b21d610eSAxel Dörfler 
903b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
904b21d610eSAxel Dörfler 			_CheckApplyEnabled();
905a10cf76eSAxel Dörfler 			break;
906a10cf76eSAxel Dörfler 		}
907a10cf76eSAxel Dörfler 
908a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
909a10cf76eSAxel Dörfler 		{
910a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
911a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
912a10cf76eSAxel Dörfler 
9135de171daSAxel Dörfler 			_CheckColorMenu();
9145de171daSAxel Dörfler 			_CheckRefreshMenu();
915a10cf76eSAxel Dörfler 
9165de171daSAxel Dörfler 			_UpdateMonitorView();
9175de171daSAxel Dörfler 			_UpdateRefreshControl();
918a10cf76eSAxel Dörfler 
9195de171daSAxel Dörfler 			_CheckApplyEnabled();
920a10cf76eSAxel Dörfler 			break;
921a10cf76eSAxel Dörfler 		}
922a10cf76eSAxel Dörfler 
923a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
924a10cf76eSAxel Dörfler 		{
9251fc4cb1fSAxel Dörfler 			int32 space;
9261fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9271fc4cb1fSAxel Dörfler 				break;
928a10cf76eSAxel Dörfler 
9291fc4cb1fSAxel Dörfler 			int32 index;
9301fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9311fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9321fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9331fc4cb1fSAxel Dörfler 
9341fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9351fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
936a10cf76eSAxel Dörfler 
9375de171daSAxel Dörfler 			_CheckApplyEnabled();
938a10cf76eSAxel Dörfler 			break;
939a10cf76eSAxel Dörfler 		}
940a10cf76eSAxel Dörfler 
941a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
942a40498e2SWaldemar Kornewald 		{
943a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
944c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
9451fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
946a10cf76eSAxel Dörfler 
9475de171daSAxel Dörfler 			_CheckApplyEnabled();
948a10cf76eSAxel Dörfler 			break;
949a40498e2SWaldemar Kornewald 		}
950a10cf76eSAxel Dörfler 
951a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
952a10cf76eSAxel Dörfler 		{
95329e8a73aSAxel Dörfler 			// make sure menu shows something useful
9545de171daSAxel Dörfler 			_UpdateRefreshControl();
955a10cf76eSAxel Dörfler 
95629e8a73aSAxel Dörfler 			float min = 0, max = 999;
95729e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
95829e8a73aSAxel Dörfler 			if (min < gMinRefresh)
95929e8a73aSAxel Dörfler 				min = gMinRefresh;
96029e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
96129e8a73aSAxel Dörfler 				max = gMaxRefresh;
96229e8a73aSAxel Dörfler 
96370a2b1b5SAxel Dörfler 			monitor_info info;
96470a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
96570a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
96670a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
96770a2b1b5SAxel Dörfler 			}
96870a2b1b5SAxel Dörfler 
969c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
97070a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
97170a2b1b5SAxel Dörfler 				min, max);
972a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
973a10cf76eSAxel Dörfler 			break;
974a10cf76eSAxel Dörfler 		}
975a10cf76eSAxel Dörfler 
976a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
977a10cf76eSAxel Dörfler 		{
978a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
979a10cf76eSAxel Dörfler 			// select the refresh rate chosen
980a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
981a10cf76eSAxel Dörfler 
9825de171daSAxel Dörfler 			_UpdateRefreshControl();
9835de171daSAxel Dörfler 			_CheckApplyEnabled();
984a10cf76eSAxel Dörfler 			break;
985a10cf76eSAxel Dörfler 		}
986a10cf76eSAxel Dörfler 
987a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
988a10cf76eSAxel Dörfler 		{
989a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
990a10cf76eSAxel Dörfler 			int32 mode;
991a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
992a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
993a10cf76eSAxel Dörfler 
9945de171daSAxel Dörfler 			_CheckResolutionMenu();
9955de171daSAxel Dörfler 			_CheckApplyEnabled();
996a10cf76eSAxel Dörfler 			break;
997a10cf76eSAxel Dörfler 		}
998a10cf76eSAxel Dörfler 
999a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1000a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10015de171daSAxel Dörfler 			_CheckApplyEnabled();
1002a10cf76eSAxel Dörfler 			break;
1003a10cf76eSAxel Dörfler 
1004a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1005a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10065de171daSAxel Dörfler 			_CheckApplyEnabled();
1007a10cf76eSAxel Dörfler 			break;
1008a10cf76eSAxel Dörfler 
1009a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1010a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10115de171daSAxel Dörfler 			_CheckApplyEnabled();
1012a10cf76eSAxel Dörfler 			break;
1013a10cf76eSAxel Dörfler 
1014df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10156f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10166f095d6aSRyan Leavengood 				app_info info;
10176f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10186f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10196f095d6aSRyan Leavengood 			}
1020df3f5bacSStephan Aßmus 			break;
1021df3f5bacSStephan Aßmus 
1022a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1023a10cf76eSAxel Dörfler 		{
10244be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1025a10cf76eSAxel Dörfler 			fSelected.width = 640;
1026a10cf76eSAxel Dörfler 			fSelected.height = 480;
1027a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1028a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1029a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1030a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1031a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1032a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1033a10cf76eSAxel Dörfler 
1034b21d610eSAxel Dörfler 			// TODO: workspace defaults
1035abc649b8SWaldemar Kornewald 
10365de171daSAxel Dörfler 			_UpdateControls();
1037a10cf76eSAxel Dörfler 			break;
1038a10cf76eSAxel Dörfler 		}
1039a10cf76eSAxel Dörfler 
104010e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
104161c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10425de171daSAxel Dörfler 			_UpdateActiveMode();
1043abc649b8SWaldemar Kornewald 			break;
1044abc649b8SWaldemar Kornewald 
1045abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1046abc649b8SWaldemar Kornewald 		{
1047abc649b8SWaldemar Kornewald 			fModified = false;
1048199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1049abc649b8SWaldemar Kornewald 
1050b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1051b21d610eSAxel Dörfler 			// number of workspaces
1052b21d610eSAxel Dörfler 
1053b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1054b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1055b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1056b21d610eSAxel Dörfler 
1057a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10585de171daSAxel Dörfler 			_UpdateActiveMode();
1059a10cf76eSAxel Dörfler 			break;
1060abc649b8SWaldemar Kornewald 		}
1061a10cf76eSAxel Dörfler 
1062a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10635de171daSAxel Dörfler 			_Apply();
1064a10cf76eSAxel Dörfler 			break;
1065a10cf76eSAxel Dörfler 
1066abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1067abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1068abc649b8SWaldemar Kornewald 			fModified = true;
10695de171daSAxel Dörfler 			_UpdateActiveMode();
1070a10cf76eSAxel Dörfler 			break;
1071a10cf76eSAxel Dörfler 
1072a10cf76eSAxel Dörfler 		default:
1073a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1074a10cf76eSAxel Dörfler 			break;
1075a10cf76eSAxel Dörfler 	}
1076a10cf76eSAxel Dörfler }
1077a10cf76eSAxel Dörfler 
1078a10cf76eSAxel Dörfler 
107912580984SAxel Dörfler status_t
108012580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
108112580984SAxel Dörfler {
108212580984SAxel Dörfler 	BPath path;
108312580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
108412580984SAxel Dörfler 	if (status < B_OK)
108512580984SAxel Dörfler 		return status;
108612580984SAxel Dörfler 
108712580984SAxel Dörfler 	path.Append("kernel/drivers");
108812580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
108912580984SAxel Dörfler 	if (status < B_OK)
109012580984SAxel Dörfler 		return status;
109112580984SAxel Dörfler 
109212580984SAxel Dörfler 	path.Append("vesa");
109312580984SAxel Dörfler 	BFile file;
109412580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
109512580984SAxel Dörfler 	if (status < B_OK)
109612580984SAxel Dörfler 		return status;
109712580984SAxel Dörfler 
109812580984SAxel Dörfler 	char buffer[256];
109912580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
110012580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
110112580984SAxel Dörfler 
110212580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
110312580984SAxel Dörfler 	if (bytesWritten < B_OK)
110412580984SAxel Dörfler 		return bytesWritten;
110512580984SAxel Dörfler 
110612580984SAxel Dörfler 	return B_OK;
110712580984SAxel Dörfler }
110812580984SAxel Dörfler 
110912580984SAxel Dörfler 
1110b21d610eSAxel Dörfler BButton*
1111b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1112b21d610eSAxel Dörfler {
1113b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1114b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1115b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1116b21d610eSAxel Dörfler 
1117b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1118b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1119b21d610eSAxel Dörfler 
1120b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1121b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1122b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1123b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1124b21d610eSAxel Dörfler 
1125b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1126b21d610eSAxel Dörfler 	return button;
1127b21d610eSAxel Dörfler }
1128b21d610eSAxel Dörfler 
1129b21d610eSAxel Dörfler 
1130b21d610eSAxel Dörfler BButton*
1131b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1132b21d610eSAxel Dörfler {
1133b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1134b21d610eSAxel Dörfler }
1135b21d610eSAxel Dörfler 
1136b21d610eSAxel Dörfler 
1137a10cf76eSAxel Dörfler void
11381fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11391fc4cb1fSAxel Dörfler {
11401fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11411fc4cb1fSAxel Dörfler 
11421fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11431fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11441fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11451fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11461fc4cb1fSAxel Dörfler 				break;
11471fc4cb1fSAxel Dörfler 			}
11481fc4cb1fSAxel Dörfler 		}
11491fc4cb1fSAxel Dörfler 	}
11501fc4cb1fSAxel Dörfler }
11511fc4cb1fSAxel Dörfler 
11521fc4cb1fSAxel Dörfler 
11531fc4cb1fSAxel Dörfler void
11545de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1155a10cf76eSAxel Dörfler {
115627c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
115727c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1158b21d610eSAxel Dörfler 
1159b21d610eSAxel Dörfler 	uint32 columns;
1160b21d610eSAxel Dörfler 	uint32 rows;
1161b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1162b21d610eSAxel Dörfler 
1163b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1164b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11655de171daSAxel Dörfler 		|| fSelected != fOriginal);
1166a10cf76eSAxel Dörfler }
1167a10cf76eSAxel Dörfler 
1168a10cf76eSAxel Dörfler 
1169a10cf76eSAxel Dörfler void
11705de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1171abc649b8SWaldemar Kornewald {
1172b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1173b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1174b21d610eSAxel Dörfler 
1175abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1176abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1177abc649b8SWaldemar Kornewald }
1178abc649b8SWaldemar Kornewald 
1179abc649b8SWaldemar Kornewald 
1180abc649b8SWaldemar Kornewald void
118112966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
118212966d04SAxel Dörfler {
118312966d04SAxel Dörfler 	monitor_info info;
118412966d04SAxel Dörfler 	float diagonalInches;
118512966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
118655030977SAxel Dörfler 	if (status == B_OK) {
11871a8af605SAxel Dörfler 		char text[512];
118866ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
118966ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
119012966d04SAxel Dörfler 
119112966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
119212966d04SAxel Dörfler 
119312966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
119412966d04SAxel Dörfler 			fMonitorInfo->Show();
119555030977SAxel Dörfler 	} else {
119655030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
119755030977SAxel Dörfler 			fMonitorInfo->Hide();
119855030977SAxel Dörfler 	}
1199af8f9c31SAxel Dörfler 
120055030977SAxel Dörfler 	char text[512];
12011a8af605SAxel Dörfler 	size_t length = 0;
12021a8af605SAxel Dörfler 	text[0] = 0;
12031a8af605SAxel Dörfler 
120455030977SAxel Dörfler 	if (status == B_OK) {
1205af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1206af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1207af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12081a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1209c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12109c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1211c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12121a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12131a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12141a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1215af8f9c31SAxel Dörfler 		}
12161a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12171a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1218c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12191a8af605SAxel Dörfler 				info.serial_number);
12201a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12211a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12221a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12231a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12241a8af605SAxel Dörfler 	 		}
12251a8af605SAxel Dörfler 		}
122655030977SAxel Dörfler 	}
122761c5c89bSAxel Dörfler 
122861c5c89bSAxel Dörfler 	// Add info about the graphics device
122961c5c89bSAxel Dörfler 
123061c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
123161c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
123261c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
123361c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
123461c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123561c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
123661c5c89bSAxel Dörfler 				deviceInfo.chipset);
123761c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
123861c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123961c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
124061c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
124161c5c89bSAxel Dörfler 		}
124261c5c89bSAxel Dörfler 	}
124361c5c89bSAxel Dörfler 
12441a8af605SAxel Dörfler 	if (text[0])
12451a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
124612966d04SAxel Dörfler }
124712966d04SAxel Dörfler 
124812966d04SAxel Dörfler 
124912966d04SAxel Dörfler void
12501fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12511fc4cb1fSAxel Dörfler {
12521fc4cb1fSAxel Dörfler 	BString string;
1253551c9f15SSiarzhuk Zharski 	string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel");
12541fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12551fc4cb1fSAxel Dörfler }
12561fc4cb1fSAxel Dörfler 
12571fc4cb1fSAxel Dörfler 
12581fc4cb1fSAxel Dörfler void
12595de171daSAxel Dörfler ScreenWindow::_Apply()
1260a10cf76eSAxel Dörfler {
1261abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
126261c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
126361c5c89bSAxel Dörfler 
126407184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
126507184a9eSAxel Dörfler 	if (status == B_OK) {
1266abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1267abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1268abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1269abc649b8SWaldemar Kornewald 		display_mode newMode;
1270abc649b8SWaldemar Kornewald 		BScreen screen(this);
1271abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1272abc649b8SWaldemar Kornewald 
1273abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1274abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1275abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1276abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1277abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1278abc649b8SWaldemar Kornewald 			}
1279199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1280199893c3SAxel Dörfler 		} else {
1281199893c3SAxel Dörfler 			if (current_workspace() == 0)
1282199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1283abc649b8SWaldemar Kornewald 		}
1284abc649b8SWaldemar Kornewald 
1285a10cf76eSAxel Dörfler 		fActive = fSelected;
1286a10cf76eSAxel Dörfler 
1287abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1288a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1289a10cf76eSAxel Dörfler 		window->Show();
129007184a9eSAxel Dörfler 	} else {
129107184a9eSAxel Dörfler 		char message[256];
129207184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1293c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1294c9e8f97aSAdrien Destugues 			screen_errors(status));
1295551c9f15SSiarzhuk Zharski 		BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message,
1296c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
129707184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
129807184a9eSAxel Dörfler 		alert->Go();
1299a10cf76eSAxel Dörfler 	}
130007184a9eSAxel Dörfler }
130107184a9eSAxel Dörfler 
1302