xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 5503097733bb2c9f3f15dad5f700e4434d551625)
1a10cf76eSAxel Dörfler /*
2b21d610eSAxel Dörfler  * Copyright 2001-2009, Haiku.
3a10cf76eSAxel Dörfler  * Distributed under the terms of the MIT License.
4a10cf76eSAxel Dörfler  *
5a10cf76eSAxel Dörfler  * Authors:
6a10cf76eSAxel Dörfler  *		Rafael Romo
7a10cf76eSAxel Dörfler  *		Stefano Ceccherini (burton666@libero.it)
8a10cf76eSAxel Dörfler  *		Andrew Bachmann
9a10cf76eSAxel Dörfler  *		Thomas Kurschel
10a10cf76eSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
11df3f5bacSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
12b72c4836SAlexandre Deckner  *		Alexandre Deckner, alex@zappotek.com
13a10cf76eSAxel Dörfler  */
14a10cf76eSAxel Dörfler 
15a10cf76eSAxel Dörfler 
16b21d610eSAxel Dörfler #include "ScreenWindow.h"
17b21d610eSAxel Dörfler 
18b21d610eSAxel Dörfler #include <stdio.h>
19b21d610eSAxel Dörfler #include <stdlib.h>
20b21d610eSAxel Dörfler #include <string.h>
21b21d610eSAxel Dörfler 
22b21d610eSAxel Dörfler #include <Alert.h>
23b21d610eSAxel Dörfler #include <Application.h>
24b21d610eSAxel Dörfler #include <Box.h>
25b21d610eSAxel Dörfler #include <Button.h>
26b21d610eSAxel Dörfler #include <Directory.h>
27b21d610eSAxel Dörfler #include <File.h>
28b21d610eSAxel Dörfler #include <FindDirectory.h>
29b21d610eSAxel Dörfler #include <InterfaceDefs.h>
30b21d610eSAxel Dörfler #include <LayoutBuilder.h>
31b21d610eSAxel Dörfler #include <MenuBar.h>
32b21d610eSAxel Dörfler #include <MenuItem.h>
33b21d610eSAxel Dörfler #include <MenuField.h>
34b21d610eSAxel Dörfler #include <Messenger.h>
35b21d610eSAxel Dörfler #include <Path.h>
36b21d610eSAxel Dörfler #include <PopUpMenu.h>
37b21d610eSAxel Dörfler #include <Screen.h>
38b21d610eSAxel Dörfler #include <String.h>
39b21d610eSAxel Dörfler #include <StringView.h>
40b21d610eSAxel Dörfler #include <Roster.h>
41b21d610eSAxel Dörfler #include <Window.h>
42b21d610eSAxel Dörfler 
43b21d610eSAxel Dörfler #include <InterfacePrivate.h>
44b21d610eSAxel Dörfler 
45a10cf76eSAxel Dörfler #include "AlertWindow.h"
46a10cf76eSAxel Dörfler #include "Constants.h"
47a10cf76eSAxel Dörfler #include "RefreshWindow.h"
48a10cf76eSAxel Dörfler #include "MonitorView.h"
49a10cf76eSAxel Dörfler #include "ScreenSettings.h"
50a10cf76eSAxel Dörfler #include "Utility.h"
51a10cf76eSAxel Dörfler 
52a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
53a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
54a10cf76eSAxel Dörfler  * adopted.
55a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
56a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
57a10cf76eSAxel Dörfler  * be using this.
58a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
59a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
60a10cf76eSAxel Dörfler  */
61a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
62a10cf76eSAxel Dörfler 
63a10cf76eSAxel Dörfler 
6475c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
65c5d80d47SAxel Dörfler 
66a10cf76eSAxel Dörfler // list of officially supported colour spaces
67a10cf76eSAxel Dörfler static const struct {
68a10cf76eSAxel Dörfler 	color_space	space;
69a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
70a10cf76eSAxel Dörfler 	const char*	label;
71a10cf76eSAxel Dörfler } kColorSpaces[] = {
72a10cf76eSAxel Dörfler 	{ B_CMAP8, 8, "8 Bits/Pixel, 256 Colors" },
73a10cf76eSAxel Dörfler 	{ B_RGB15, 15, "15 Bits/Pixel, 32768 Colors" },
74a10cf76eSAxel Dörfler 	{ B_RGB16, 16, "16 Bits/Pixel, 65536 Colors" },
751fc4cb1fSAxel Dörfler 	{ B_RGB24, 24, "24 Bits/Pixel, 16 Million Colors" },
76a10cf76eSAxel Dörfler 	{ B_RGB32, 32, "32 Bits/Pixel, 16 Million Colors" }
77a10cf76eSAxel Dörfler };
78b21d610eSAxel Dörfler static const int32 kColorSpaceCount
79b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
80a10cf76eSAxel Dörfler 
81a10cf76eSAxel Dörfler // list of standard refresh rates
82a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
83b21d610eSAxel Dörfler static const int32 kRefreshRateCount
84b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
85a10cf76eSAxel Dörfler 
86a10cf76eSAxel Dörfler // list of combine modes
87a10cf76eSAxel Dörfler static const struct {
88a10cf76eSAxel Dörfler 	combine_mode	mode;
89a10cf76eSAxel Dörfler 	const char		*name;
90a10cf76eSAxel Dörfler } kCombineModes[] = {
91a10cf76eSAxel Dörfler 	{ kCombineDisable, "disable" },
92a10cf76eSAxel Dörfler 	{ kCombineHorizontally, "horizontally" },
93a10cf76eSAxel Dörfler 	{ kCombineVertically, "vertically" }
94a10cf76eSAxel Dörfler };
95b21d610eSAxel Dörfler static const int32 kCombineModeCount
96b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
9729e8a73aSAxel Dörfler 
98a10cf76eSAxel Dörfler 
99a10cf76eSAxel Dörfler static BString
100a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
101a10cf76eSAxel Dörfler {
102a10cf76eSAxel Dörfler 	switch (mode) {
103a10cf76eSAxel Dörfler 		case 0:		return "disabled";
104a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
105a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
106a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
107a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
108a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
109a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
110a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
111a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
112a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
113a10cf76eSAxel Dörfler 		default:
114a10cf76eSAxel Dörfler 		{
115a10cf76eSAxel Dörfler 			BString name;
116a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
117a10cf76eSAxel Dörfler 
118a10cf76eSAxel Dörfler 			return name;
119a10cf76eSAxel Dörfler 		}
120a10cf76eSAxel Dörfler 	}
121a10cf76eSAxel Dörfler }
122a10cf76eSAxel Dörfler 
123a10cf76eSAxel Dörfler 
124a10cf76eSAxel Dörfler static void
125a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
126a10cf76eSAxel Dörfler {
127a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
128a10cf76eSAxel Dörfler }
129a10cf76eSAxel Dörfler 
130a10cf76eSAxel Dörfler 
131a10cf76eSAxel Dörfler static void
132a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
133a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
134a10cf76eSAxel Dörfler {
1358bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1368bf23e3cSAxel Dörfler 		refresh);
137a10cf76eSAxel Dörfler 	string.UnlockBuffer();
138a10cf76eSAxel Dörfler 
139a10cf76eSAxel Dörfler 	if (appendUnit)
140a10cf76eSAxel Dörfler 		string << " Hz";
141a10cf76eSAxel Dörfler }
142a10cf76eSAxel Dörfler 
143a10cf76eSAxel Dörfler 
14407184a9eSAxel Dörfler static const char*
14507184a9eSAxel Dörfler screen_errors(status_t status)
14607184a9eSAxel Dörfler {
14707184a9eSAxel Dörfler 	switch (status) {
14807184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
14907184a9eSAxel Dörfler 			return "Unknown Mode";
15007184a9eSAxel Dörfler 		// TODO: add more?
15107184a9eSAxel Dörfler 
15207184a9eSAxel Dörfler 		default:
15307184a9eSAxel Dörfler 			return strerror(status);
15407184a9eSAxel Dörfler 	}
15507184a9eSAxel Dörfler }
15607184a9eSAxel Dörfler 
15729e8a73aSAxel Dörfler 
1583dfd20c0SStephan Aßmus //	#pragma mark -
1593dfd20c0SStephan Aßmus 
1603dfd20c0SStephan Aßmus 
1615a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
162b21d610eSAxel Dörfler 	:
163b21d610eSAxel Dörfler 	BWindow(settings->WindowFrame(), "Screen", B_TITLED_WINDOW,
164b21d610eSAxel Dörfler 		B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
165b21d610eSAxel Dörfler 		B_ALL_WORKSPACES),
166199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
167a10cf76eSAxel Dörfler 	fScreenMode(this),
16861c5c89bSAxel Dörfler 	fUndoScreenMode(this),
169abc649b8SWaldemar Kornewald 	fModified(false)
170a10cf76eSAxel Dörfler {
171a10cf76eSAxel Dörfler 	BScreen screen(this);
172a10cf76eSAxel Dörfler 
17312580984SAxel Dörfler 	accelerant_device_info info;
174d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
175d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
17612580984SAxel Dörfler 		fIsVesa = true;
17712580984SAxel Dörfler 
1785de171daSAxel Dörfler 	_UpdateOriginal();
1791fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
180a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
181a10cf76eSAxel Dörfler 
1825a78744bSAxel Dörfler 	fSettings = settings;
1835a78744bSAxel Dörfler 
1845a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1855a78744bSAxel Dörfler 
1865a78744bSAxel Dörfler 	BPopUpMenu *popUpMenu = new BPopUpMenu("Current Workspace", true, true);
187d1516993SAxel Dörfler 	fAllWorkspacesItem = new BMenuItem("All Workspaces",
188d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1895a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
190d1516993SAxel Dörfler 	BMenuItem *item = new BMenuItem("Current Workspace",
191d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
192b72c4836SAlexandre Deckner 
1935a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
19427c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
1955a78744bSAxel Dörfler 
196b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
197b21d610eSAxel Dörfler 		popUpMenu, NULL);
1985a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
199a10cf76eSAxel Dörfler 
200a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
201a10cf76eSAxel Dörfler 
202b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2038bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
204b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
205b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
206a10cf76eSAxel Dörfler 
20712966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
20812966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
20912966d04SAxel Dörfler 
210df3f5bacSStephan Aßmus 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0), "monitor",
2116bda235aSStefano Ceccherini 		screen.Frame().IntegerWidth() + 1, screen.Frame().IntegerHeight() + 1);
212b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2135a78744bSAxel Dörfler 
214b21d610eSAxel Dörfler 	fColumnsControl = new BTextControl("Columns:", "0",
215b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
216b21d610eSAxel Dörfler 	fRowsControl = new BTextControl("Rows:", "0",
217b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
218b21d610eSAxel Dörfler 
219b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
220b21d610eSAxel Dörfler 		.Add(new BStringView("", "Workspaces"), 0, 0, 3)
221b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
222b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
223b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
224b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
225b21d610eSAxel Dörfler 		.End()
226b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
227b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
228b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
229b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
230b21d610eSAxel Dörfler 		.End());
231b21d610eSAxel Dörfler 
232b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
233b21d610eSAxel Dörfler 		"Set Background" B_UTF8_ELLIPSIS,
234b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
235b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
236b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
237a10cf76eSAxel Dörfler 
238a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
239a10cf76eSAxel Dörfler 
240b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
241b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
242b21d610eSAxel Dörfler 	BView* outerControlsView = BLayoutBuilder::Group<>(B_VERTICAL, 10.0)
243b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10);
244b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
245a10cf76eSAxel Dörfler 
246a10cf76eSAxel Dörfler 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
247a10cf76eSAxel Dörfler 
24866ab1666SAxel Dörfler 	uint16 maxWidth = 0;
24966ab1666SAxel Dörfler 	uint16 maxHeight = 0;
25066ab1666SAxel Dörfler 	uint16 previousWidth = 0;
25166ab1666SAxel Dörfler 	uint16 previousHeight = 0;
252a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
253a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
254a10cf76eSAxel Dörfler 
255a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
256a10cf76eSAxel Dörfler 			continue;
257a10cf76eSAxel Dörfler 
258a10cf76eSAxel Dörfler 		previousWidth = mode.width;
259a10cf76eSAxel Dörfler 		previousHeight = mode.height;
26066ab1666SAxel Dörfler 		if (maxWidth < mode.width)
26166ab1666SAxel Dörfler 			maxWidth = mode.width;
26266ab1666SAxel Dörfler 		if (maxHeight < mode.height)
26366ab1666SAxel Dörfler 			maxHeight = mode.height;
264a10cf76eSAxel Dörfler 
265a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
266a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
267a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
268a10cf76eSAxel Dörfler 
269a10cf76eSAxel Dörfler 		BString name;
270a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
271a10cf76eSAxel Dörfler 
272a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
273a10cf76eSAxel Dörfler 	}
274a10cf76eSAxel Dörfler 
27566ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
27666ab1666SAxel Dörfler 
27729e8a73aSAxel Dörfler 	BRect rect(0.0, 0.0, 200.0, 15.0);
278df3f5bacSStephan Aßmus 	// fResolutionField needs to be at the correct
279df3f5bacSStephan Aßmus 	// left-top offset, because all other menu fields
280df3f5bacSStephan Aßmus 	// will be layouted relative to it
281b21d610eSAxel Dörfler 	fResolutionField = new BMenuField("ResolutionMenu", "Resolution:",
282b21d610eSAxel Dörfler 		fResolutionMenu, NULL);
283a10cf76eSAxel Dörfler 
284f99cba9eSAxel Dörfler 	fColorsMenu = new BPopUpMenu("colors", true, false);
285a10cf76eSAxel Dörfler 
286a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
2871fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
2881fc4cb1fSAxel Dörfler 			continue;
2891fc4cb1fSAxel Dörfler 
290a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
291a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
292a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
293a10cf76eSAxel Dörfler 
2941fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
2951fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
2961fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
2971fc4cb1fSAxel Dörfler 
2981fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
299a10cf76eSAxel Dörfler 	}
300a10cf76eSAxel Dörfler 
301df3f5bacSStephan Aßmus 	rect.OffsetTo(B_ORIGIN);
302df3f5bacSStephan Aßmus 
303b21d610eSAxel Dörfler 	fColorsField = new BMenuField("ColorsMenu", "Colors:", fColorsMenu, NULL);
304a10cf76eSAxel Dörfler 
305a10cf76eSAxel Dörfler 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
306a10cf76eSAxel Dörfler 
30729e8a73aSAxel Dörfler 	BMessage *message;
30829e8a73aSAxel Dörfler 
30929e8a73aSAxel Dörfler 	float min, max;
31029e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
31129e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
31229e8a73aSAxel Dörfler 		// frequency, like the VESA driver
31329e8a73aSAxel Dörfler 		BString name;
31429e8a73aSAxel Dörfler 		name << min << " Hz";
31529e8a73aSAxel Dörfler 
31629e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
31729e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
31829e8a73aSAxel Dörfler 
31929e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
32029e8a73aSAxel Dörfler 		item->SetEnabled(false);
32129e8a73aSAxel Dörfler 	} else {
32270a2b1b5SAxel Dörfler 		monitor_info info;
32370a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
32470a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
32570a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
32670a2b1b5SAxel Dörfler 		}
32770a2b1b5SAxel Dörfler 
328a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
32970a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
33070a2b1b5SAxel Dörfler 				continue;
33170a2b1b5SAxel Dörfler 
332a10cf76eSAxel Dörfler 			BString name;
333a10cf76eSAxel Dörfler 			name << kRefreshRates[i] << " Hz";
334a10cf76eSAxel Dörfler 
33529e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
336a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
337a10cf76eSAxel Dörfler 
338a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
339a10cf76eSAxel Dörfler 		}
340a10cf76eSAxel Dörfler 
34129e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
342a10cf76eSAxel Dörfler 
343a10cf76eSAxel Dörfler 		fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
344a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
34529e8a73aSAxel Dörfler 	}
346a10cf76eSAxel Dörfler 
347b21d610eSAxel Dörfler 	fRefreshField = new BMenuField("RefreshMenu", "Refresh Rate:",
348b21d610eSAxel Dörfler 		fRefreshMenu, NULL);
349b21d610eSAxel Dörfler 
35012580984SAxel Dörfler 	if (_IsVesa())
35112580984SAxel Dörfler 		fRefreshField->Hide();
352a10cf76eSAxel Dörfler 
353a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
354a10cf76eSAxel Dörfler 	{
355a10cf76eSAxel Dörfler 		bool dummy;
356a10cf76eSAxel Dörfler 		uint32 dummy32;
357a10cf76eSAxel Dörfler 		bool multiMonSupport;
358a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
359a10cf76eSAxel Dörfler 		bool tvStandardSupport;
360a10cf76eSAxel Dörfler 
361a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
362a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
363a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
364a10cf76eSAxel Dörfler 
365a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
366a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
367a10cf76eSAxel Dörfler 
368a10cf76eSAxel Dörfler 		fCombineMenu = new BPopUpMenu("CombineDisplays", true, true);
369a10cf76eSAxel Dörfler 
370a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
371a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
372a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
373a10cf76eSAxel Dörfler 
374d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
375d1516993SAxel Dörfler 				message));
376a10cf76eSAxel Dörfler 		}
377a10cf76eSAxel Dörfler 
378b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
379b21d610eSAxel Dörfler 			"Combine Displays:", fCombineMenu, NULL);
380a10cf76eSAxel Dörfler 
381a10cf76eSAxel Dörfler 		if (!multiMonSupport)
382df3f5bacSStephan Aßmus 			fCombineField->Hide();
383a10cf76eSAxel Dörfler 
384a10cf76eSAxel Dörfler 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", true, true);
385a10cf76eSAxel Dörfler 
386a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
387a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
388a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
389a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("no", message));
390a10cf76eSAxel Dörfler 
391a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
392a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
393a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("yes", message));
394a10cf76eSAxel Dörfler 
395b21d610eSAxel Dörfler 		fSwapDisplaysField = new BMenuField("SwapMenu", "Swap Displays:",
396b21d610eSAxel Dörfler 			fSwapDisplaysMenu, NULL);
397a10cf76eSAxel Dörfler 
398a10cf76eSAxel Dörfler 		if (!multiMonSupport)
399df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
400a10cf76eSAxel Dörfler 
401a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", true, true);
402a10cf76eSAxel Dörfler 
403a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
404a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
405a10cf76eSAxel Dörfler 		message->AddBool("use", false);
406a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("if needed", message));
407a10cf76eSAxel Dörfler 
408a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
409a10cf76eSAxel Dörfler 		message->AddBool("use", true);
410a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("always", message));
411a10cf76eSAxel Dörfler 
412b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
413b21d610eSAxel Dörfler 			"Use Laptop Panel:", fUseLaptopPanelMenu, NULL);
414a10cf76eSAxel Dörfler 
415a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
416df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
417a10cf76eSAxel Dörfler 
418a10cf76eSAxel Dörfler 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
419a10cf76eSAxel Dörfler 
420a10cf76eSAxel Dörfler 		// arbitrary limit
421a10cf76eSAxel Dörfler 		uint32 i;
422a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
423a10cf76eSAxel Dörfler 			uint32 mode;
424a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
425a10cf76eSAxel Dörfler 				break;
426a10cf76eSAxel Dörfler 
427a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
428a10cf76eSAxel Dörfler 
429a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
430a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
431a10cf76eSAxel Dörfler 
432a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
433a10cf76eSAxel Dörfler 		}
434a10cf76eSAxel Dörfler 
435b21d610eSAxel Dörfler 		fTVStandardField = new BMenuField("tv standard", "Video Format:",
436b21d610eSAxel Dörfler 			fTVStandardMenu, NULL);
437df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
438a10cf76eSAxel Dörfler 
439b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
440df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
441a10cf76eSAxel Dörfler 	}
442a10cf76eSAxel Dörfler 
443b21d610eSAxel Dörfler 	BView* controlsView = BLayoutBuilder::Grid<>(5.0, 5.0)
444b21d610eSAxel Dörfler 		.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
445b21d610eSAxel Dörfler 		.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
446b21d610eSAxel Dörfler 		.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
447b21d610eSAxel Dörfler 		.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
448b21d610eSAxel Dörfler 		.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
449b21d610eSAxel Dörfler 		.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
450b21d610eSAxel Dörfler 		.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT);
451b21d610eSAxel Dörfler 	outerControlsView->AddChild(controlsView);
452df3f5bacSStephan Aßmus 
453abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
454abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
455b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
456a10cf76eSAxel Dörfler 
457b21d610eSAxel Dörfler 	fApplyButton = new BButton("ApplyButton", "Apply",
458df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
459df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
460b21d610eSAxel Dörfler 	outerControlsView->GetLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
461b21d610eSAxel Dörfler 	outerControlsView->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL)
462b21d610eSAxel Dörfler 		.AddGlue()
463b21d610eSAxel Dörfler 		.Add(fApplyButton));
464b21d610eSAxel Dörfler 
465b21d610eSAxel Dörfler 	fRevertButton = new BButton("RevertButton", "Revert",
466b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
467b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
468b21d610eSAxel Dörfler 
469b21d610eSAxel Dörfler 	SetLayout(new BGroupLayout(B_VERTICAL, 10.0));
470b21d610eSAxel Dörfler 	GetLayout()->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
471b21d610eSAxel Dörfler 
472b21d610eSAxel Dörfler 	BLayoutBuilder::Group<>(static_cast<BGroupLayout*>(GetLayout()))
473b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
474b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
475b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
476b21d610eSAxel Dörfler 				.Add(screenBox)
477b21d610eSAxel Dörfler 			.End()
478b21d610eSAxel Dörfler 			.Add(controlsBox)
479b21d610eSAxel Dörfler 		.End()
480b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
481b21d610eSAxel Dörfler 			.Add(fRevertButton)
482b21d610eSAxel Dörfler 			.AddGlue();
483b21d610eSAxel Dörfler 
484b21d610eSAxel Dörfler 	screenBox->Parent()->GetLayout()->AddItem(0,
485b21d610eSAxel Dörfler 		BSpaceLayoutItem::CreateVerticalStrut(
486b21d610eSAxel Dörfler 			controlsBox->TopBorderOffset() - 1));
4875a78744bSAxel Dörfler 
4885de171daSAxel Dörfler 	_UpdateControls();
48912966d04SAxel Dörfler 	_UpdateMonitor();
490a10cf76eSAxel Dörfler }
491a10cf76eSAxel Dörfler 
492a10cf76eSAxel Dörfler 
493a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
494a10cf76eSAxel Dörfler {
495a10cf76eSAxel Dörfler 	delete fSettings;
496a10cf76eSAxel Dörfler }
497a10cf76eSAxel Dörfler 
498a10cf76eSAxel Dörfler 
499a10cf76eSAxel Dörfler bool
500a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
501a10cf76eSAxel Dörfler {
502a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
503199893c3SAxel Dörfler 
504199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
505199893c3SAxel Dörfler 	screen_mode vesaMode;
506199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
507199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
50812580984SAxel Dörfler 		if (status < B_OK) {
50912580984SAxel Dörfler 			BString warning = "Could not write VESA mode settings file:\n\t";
51012580984SAxel Dörfler 			warning << strerror(status);
51112580984SAxel Dörfler 			(new BAlert("VesaAlert", warning.String(), "Okay", NULL, NULL,
51212580984SAxel Dörfler 				B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
51312580984SAxel Dörfler 		}
51412580984SAxel Dörfler 	}
51512580984SAxel Dörfler 
516a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
517a10cf76eSAxel Dörfler 
518a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
519a10cf76eSAxel Dörfler }
520a10cf76eSAxel Dörfler 
521a10cf76eSAxel Dörfler 
5225de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5231fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
524a10cf76eSAxel Dörfler */
525a10cf76eSAxel Dörfler void
5265de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
527a10cf76eSAxel Dörfler {
528a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
529a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
530a10cf76eSAxel Dörfler 
531a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
532a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
533a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
534a10cf76eSAxel Dörfler 			continue;
535a10cf76eSAxel Dörfler 
536a10cf76eSAxel Dörfler 		BString name;
537a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
538a10cf76eSAxel Dörfler 
539a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
540a10cf76eSAxel Dörfler 		if (item != NULL)
541a10cf76eSAxel Dörfler 			item->SetEnabled(true);
542a10cf76eSAxel Dörfler 	}
543a10cf76eSAxel Dörfler }
544a10cf76eSAxel Dörfler 
545a10cf76eSAxel Dörfler 
5465de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5475de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5485de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5495de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
550a10cf76eSAxel Dörfler */
551a10cf76eSAxel Dörfler void
5525de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
553a10cf76eSAxel Dörfler {
5541fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5551fc4cb1fSAxel Dörfler 	int32 index = 0;
5561fc4cb1fSAxel Dörfler 
557a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5581fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5591fc4cb1fSAxel Dörfler 			continue;
5601fc4cb1fSAxel Dörfler 
561a10cf76eSAxel Dörfler 		bool supported = false;
562a10cf76eSAxel Dörfler 
563a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
564a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
565a10cf76eSAxel Dörfler 
566a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
567a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5681fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
569a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5701fc4cb1fSAxel Dörfler 				supportsAnything = true;
571a10cf76eSAxel Dörfler 				supported = true;
572a10cf76eSAxel Dörfler 				break;
573a10cf76eSAxel Dörfler 			}
574a10cf76eSAxel Dörfler 		}
575a10cf76eSAxel Dörfler 
5761fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
577a10cf76eSAxel Dörfler 		if (item)
578a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
579a10cf76eSAxel Dörfler 	}
5801fc4cb1fSAxel Dörfler 
5811fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5821fc4cb1fSAxel Dörfler 
5831fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5841fc4cb1fSAxel Dörfler 		return;
5851fc4cb1fSAxel Dörfler 
5861fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5871fc4cb1fSAxel Dörfler 
5881fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
5891fc4cb1fSAxel Dörfler 	bool changed = false;
5901fc4cb1fSAxel Dörfler 
5911fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
5921fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
5931fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
5941fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
5951fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
5961fc4cb1fSAxel Dörfler 			changed = true;
5971fc4cb1fSAxel Dörfler 		}
5981fc4cb1fSAxel Dörfler 	}
5991fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6001fc4cb1fSAxel Dörfler 		// find the next best item
6011fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6021fc4cb1fSAxel Dörfler 		bool found = false;
6031fc4cb1fSAxel Dörfler 
6041fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6051fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6061fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6071fc4cb1fSAxel Dörfler 				found = true;
6081fc4cb1fSAxel Dörfler 				break;
6091fc4cb1fSAxel Dörfler 			}
6101fc4cb1fSAxel Dörfler 		}
6111fc4cb1fSAxel Dörfler 		if (!found) {
6121fc4cb1fSAxel Dörfler 			// search backwards as well
6131fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6141fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6151fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6161fc4cb1fSAxel Dörfler 					break;
6171fc4cb1fSAxel Dörfler 			}
6181fc4cb1fSAxel Dörfler 		}
6191fc4cb1fSAxel Dörfler 
6201fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6211fc4cb1fSAxel Dörfler 		changed = true;
6221fc4cb1fSAxel Dörfler 	}
6231fc4cb1fSAxel Dörfler 
6241fc4cb1fSAxel Dörfler 	if (changed) {
6251fc4cb1fSAxel Dörfler 		// Update selected space
6261fc4cb1fSAxel Dörfler 
6271fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6281fc4cb1fSAxel Dörfler 		int32 space;
6291fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6301fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6311fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6321fc4cb1fSAxel Dörfler 		}
6331fc4cb1fSAxel Dörfler 	}
634a10cf76eSAxel Dörfler }
635a10cf76eSAxel Dörfler 
636a10cf76eSAxel Dörfler 
6375de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
638a10cf76eSAxel Dörfler void
6395de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
640a10cf76eSAxel Dörfler {
64129e8a73aSAxel Dörfler 	float min, max;
64229e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
64329e8a73aSAxel Dörfler 		return;
644a10cf76eSAxel Dörfler 
64529e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
64629e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
64729e8a73aSAxel Dörfler 		BMessage* message = item->Message();
64829e8a73aSAxel Dörfler 		float refresh;
64929e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
65029e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
651a10cf76eSAxel Dörfler 	}
652a10cf76eSAxel Dörfler }
653a10cf76eSAxel Dörfler 
654a10cf76eSAxel Dörfler 
6555de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
656a10cf76eSAxel Dörfler void
6575de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
658a10cf76eSAxel Dörfler {
659a10cf76eSAxel Dörfler 	BString string;
660a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
661a10cf76eSAxel Dörfler 
662a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
663a10cf76eSAxel Dörfler 	if (item) {
664a10cf76eSAxel Dörfler 		if (!item->IsMarked())
665a10cf76eSAxel Dörfler 			item->SetMarked(true);
66629e8a73aSAxel Dörfler 
667a10cf76eSAxel Dörfler 		// "Other…" items only contains a refresh rate when active
668e6b421a9SJérôme Duval 		fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
669a10cf76eSAxel Dörfler 		return;
670a10cf76eSAxel Dörfler 	}
671a10cf76eSAxel Dörfler 
672a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
673a10cf76eSAxel Dörfler 
674a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
675a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
676a10cf76eSAxel Dörfler 
677a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
678a10cf76eSAxel Dörfler 
679a10cf76eSAxel Dörfler 	string.Append("/Other" B_UTF8_ELLIPSIS);
680a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
681a10cf76eSAxel Dörfler }
682a10cf76eSAxel Dörfler 
683a10cf76eSAxel Dörfler 
684a10cf76eSAxel Dörfler void
6855de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
686a10cf76eSAxel Dörfler {
687a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
688a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
689a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
690a10cf76eSAxel Dörfler 
691a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
692a10cf76eSAxel Dörfler }
693a10cf76eSAxel Dörfler 
694a10cf76eSAxel Dörfler 
695a10cf76eSAxel Dörfler void
6965de171daSAxel Dörfler ScreenWindow::_UpdateControls()
697a10cf76eSAxel Dörfler {
698b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
699b21d610eSAxel Dörfler 
700a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
701a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
702a10cf76eSAxel Dörfler 		item->SetMarked(true);
703a10cf76eSAxel Dörfler 
704a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
705a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
706a10cf76eSAxel Dörfler 		item->SetMarked(true);
707a10cf76eSAxel Dörfler 
708a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
709a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
710a10cf76eSAxel Dörfler 
711a10cf76eSAxel Dörfler 		uint32 tvStandard;
712a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
713a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
714a10cf76eSAxel Dörfler 			if (!item->IsMarked())
715a10cf76eSAxel Dörfler 				item->SetMarked(true);
716a10cf76eSAxel Dörfler 			break;
717a10cf76eSAxel Dörfler 		}
718a10cf76eSAxel Dörfler 	}
719a10cf76eSAxel Dörfler 
7205de171daSAxel Dörfler 	_CheckResolutionMenu();
7215de171daSAxel Dörfler 	_CheckColorMenu();
7225de171daSAxel Dörfler 	_CheckRefreshMenu();
723a10cf76eSAxel Dörfler 
724a10cf76eSAxel Dörfler 	BString string;
725a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
726a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
727a10cf76eSAxel Dörfler 
728a10cf76eSAxel Dörfler 	if (item != NULL) {
729a10cf76eSAxel Dörfler 		if (!item->IsMarked())
730a10cf76eSAxel Dörfler 			item->SetMarked(true);
731a10cf76eSAxel Dörfler 	} else {
732a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
733a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
734a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
735a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
736a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
737a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
738a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
739a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
740a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
741a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
742a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
743a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
744a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
745a10cf76eSAxel Dörfler 		if (item)
746a10cf76eSAxel Dörfler 			item->SetMarked(true);
747a10cf76eSAxel Dörfler 
748a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
749a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
750a10cf76eSAxel Dörfler 	}
751a10cf76eSAxel Dörfler 
752a10cf76eSAxel Dörfler 	// mark active combine mode
753a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
754a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
755a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
756a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
757a10cf76eSAxel Dörfler 				item->SetMarked(true);
758a10cf76eSAxel Dörfler 			break;
759a10cf76eSAxel Dörfler 		}
760a10cf76eSAxel Dörfler 	}
761a10cf76eSAxel Dörfler 
762a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
763a10cf76eSAxel Dörfler 
7641fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7651fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7661fc4cb1fSAxel Dörfler 			continue;
7671fc4cb1fSAxel Dörfler 
7681fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7691fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
770a10cf76eSAxel Dörfler 			break;
771a10cf76eSAxel Dörfler 		}
7721fc4cb1fSAxel Dörfler 
7731fc4cb1fSAxel Dörfler 		index++;
774a10cf76eSAxel Dörfler 	}
775a10cf76eSAxel Dörfler 
776a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
777a10cf76eSAxel Dörfler 		item->SetMarked(true);
778a10cf76eSAxel Dörfler 
7791fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7805de171daSAxel Dörfler 	_UpdateMonitorView();
7815de171daSAxel Dörfler 	_UpdateRefreshControl();
782a10cf76eSAxel Dörfler 
7835de171daSAxel Dörfler 	_CheckApplyEnabled();
784a10cf76eSAxel Dörfler }
785a10cf76eSAxel Dörfler 
786a10cf76eSAxel Dörfler 
78712580984SAxel Dörfler /*! Reflect active mode in chosen settings */
788a10cf76eSAxel Dörfler void
7895de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
790a10cf76eSAxel Dörfler {
79112580984SAxel Dörfler 	// Usually, this function gets called after a mode
792a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
793a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
794a10cf76eSAxel Dörfler 	// what kind of mode we actually got
795a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
796a10cf76eSAxel Dörfler 	fSelected = fActive;
797a10cf76eSAxel Dörfler 
79812966d04SAxel Dörfler 	_UpdateMonitor();
7995de171daSAxel Dörfler 	_UpdateControls();
800a10cf76eSAxel Dörfler }
801a10cf76eSAxel Dörfler 
802a10cf76eSAxel Dörfler 
803a10cf76eSAxel Dörfler void
804b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
805b21d610eSAxel Dörfler {
806b21d610eSAxel Dörfler 	uint32 columns;
807b21d610eSAxel Dörfler 	uint32 rows;
808b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
809b21d610eSAxel Dörfler 
810b21d610eSAxel Dörfler 	char text[32];
811b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
812b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
813b21d610eSAxel Dörfler 
814b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
815b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
816b21d610eSAxel Dörfler 
817b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
818b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
819b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
820b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
821b21d610eSAxel Dörfler }
822b21d610eSAxel Dörfler 
823b21d610eSAxel Dörfler 
824b21d610eSAxel Dörfler void
825a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
826a10cf76eSAxel Dörfler {
827a10cf76eSAxel Dörfler 	// move window on screen, if necessary
828a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
829a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
830a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
831a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
832a10cf76eSAxel Dörfler 	}
833a10cf76eSAxel Dörfler }
834a10cf76eSAxel Dörfler 
835a10cf76eSAxel Dörfler 
836a10cf76eSAxel Dörfler void
837a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
838a10cf76eSAxel Dörfler {
839abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8405de171daSAxel Dörfler 	_UpdateActiveMode();
841a10cf76eSAxel Dörfler 
8426edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8436edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
844a10cf76eSAxel Dörfler }
845a10cf76eSAxel Dörfler 
846a10cf76eSAxel Dörfler 
847a10cf76eSAxel Dörfler void
848a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
849a10cf76eSAxel Dörfler {
850a10cf76eSAxel Dörfler 	switch (message->what) {
851a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8525de171daSAxel Dörfler 			_CheckApplyEnabled();
853a10cf76eSAxel Dörfler 			break;
854a10cf76eSAxel Dörfler 
855b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
856a10cf76eSAxel Dörfler 		{
857b21d610eSAxel Dörfler 			int32 deltaX = 0;
858b21d610eSAxel Dörfler 			int32 deltaY = 0;
859b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
860b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
861b21d610eSAxel Dörfler 
862b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
863b21d610eSAxel Dörfler 				break;
864b21d610eSAxel Dörfler 
865b21d610eSAxel Dörfler 			uint32 newColumns;
866b21d610eSAxel Dörfler 			uint32 newRows;
867b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
868b21d610eSAxel Dörfler 
869b21d610eSAxel Dörfler 			newColumns += deltaX;
870b21d610eSAxel Dörfler 			newRows += deltaY;
871b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
872b21d610eSAxel Dörfler 
873b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8745de171daSAxel Dörfler 			_CheckApplyEnabled();
875b21d610eSAxel Dörfler 			break;
876abc649b8SWaldemar Kornewald 		}
877b21d610eSAxel Dörfler 
878b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
879b21d610eSAxel Dörfler 		{
880b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
881b21d610eSAxel Dörfler 
882b21d610eSAxel Dörfler 			uint32 rows;
883b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
884b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
885b21d610eSAxel Dörfler 
886b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
887b21d610eSAxel Dörfler 			_CheckApplyEnabled();
888b21d610eSAxel Dörfler 			break;
889b21d610eSAxel Dörfler 		}
890b21d610eSAxel Dörfler 
891b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
892b21d610eSAxel Dörfler 		{
893b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
894b21d610eSAxel Dörfler 
895b21d610eSAxel Dörfler 			uint32 columns;
896b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
897b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
898b21d610eSAxel Dörfler 
899b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
900b21d610eSAxel Dörfler 			_CheckApplyEnabled();
901a10cf76eSAxel Dörfler 			break;
902a10cf76eSAxel Dörfler 		}
903a10cf76eSAxel Dörfler 
904a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
905a10cf76eSAxel Dörfler 		{
906a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
907a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
908a10cf76eSAxel Dörfler 
9095de171daSAxel Dörfler 			_CheckColorMenu();
9105de171daSAxel Dörfler 			_CheckRefreshMenu();
911a10cf76eSAxel Dörfler 
9125de171daSAxel Dörfler 			_UpdateMonitorView();
9135de171daSAxel Dörfler 			_UpdateRefreshControl();
914a10cf76eSAxel Dörfler 
9155de171daSAxel Dörfler 			_CheckApplyEnabled();
916a10cf76eSAxel Dörfler 			break;
917a10cf76eSAxel Dörfler 		}
918a10cf76eSAxel Dörfler 
919a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
920a10cf76eSAxel Dörfler 		{
9211fc4cb1fSAxel Dörfler 			int32 space;
9221fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9231fc4cb1fSAxel Dörfler 				break;
924a10cf76eSAxel Dörfler 
9251fc4cb1fSAxel Dörfler 			int32 index;
9261fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9271fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9281fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9291fc4cb1fSAxel Dörfler 
9301fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9311fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
932a10cf76eSAxel Dörfler 
9335de171daSAxel Dörfler 			_CheckApplyEnabled();
934a10cf76eSAxel Dörfler 			break;
935a10cf76eSAxel Dörfler 		}
936a10cf76eSAxel Dörfler 
937a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
938a40498e2SWaldemar Kornewald 		{
939a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
940a10cf76eSAxel Dörfler 			fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
9411fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
942a10cf76eSAxel Dörfler 
9435de171daSAxel Dörfler 			_CheckApplyEnabled();
944a10cf76eSAxel Dörfler 			break;
945a40498e2SWaldemar Kornewald 		}
946a10cf76eSAxel Dörfler 
947a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
948a10cf76eSAxel Dörfler 		{
94929e8a73aSAxel Dörfler 			// make sure menu shows something useful
9505de171daSAxel Dörfler 			_UpdateRefreshControl();
951a10cf76eSAxel Dörfler 
95229e8a73aSAxel Dörfler 			float min = 0, max = 999;
95329e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
95429e8a73aSAxel Dörfler 			if (min < gMinRefresh)
95529e8a73aSAxel Dörfler 				min = gMinRefresh;
95629e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
95729e8a73aSAxel Dörfler 				max = gMaxRefresh;
95829e8a73aSAxel Dörfler 
95970a2b1b5SAxel Dörfler 			monitor_info info;
96070a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
96170a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
96270a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
96370a2b1b5SAxel Dörfler 			}
96470a2b1b5SAxel Dörfler 
965c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
96670a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
96770a2b1b5SAxel Dörfler 				min, max);
968a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
969a10cf76eSAxel Dörfler 			break;
970a10cf76eSAxel Dörfler 		}
971a10cf76eSAxel Dörfler 
972a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
973a10cf76eSAxel Dörfler 		{
974a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
975a10cf76eSAxel Dörfler 			// select the refresh rate chosen
976a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
977a10cf76eSAxel Dörfler 
9785de171daSAxel Dörfler 			_UpdateRefreshControl();
9795de171daSAxel Dörfler 			_CheckApplyEnabled();
980a10cf76eSAxel Dörfler 			break;
981a10cf76eSAxel Dörfler 		}
982a10cf76eSAxel Dörfler 
983a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
984a10cf76eSAxel Dörfler 		{
985a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
986a10cf76eSAxel Dörfler 			int32 mode;
987a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
988a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
989a10cf76eSAxel Dörfler 
9905de171daSAxel Dörfler 			_CheckResolutionMenu();
9915de171daSAxel Dörfler 			_CheckApplyEnabled();
992a10cf76eSAxel Dörfler 			break;
993a10cf76eSAxel Dörfler 		}
994a10cf76eSAxel Dörfler 
995a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
996a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
9975de171daSAxel Dörfler 			_CheckApplyEnabled();
998a10cf76eSAxel Dörfler 			break;
999a10cf76eSAxel Dörfler 
1000a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1001a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10025de171daSAxel Dörfler 			_CheckApplyEnabled();
1003a10cf76eSAxel Dörfler 			break;
1004a10cf76eSAxel Dörfler 
1005a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1006a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10075de171daSAxel Dörfler 			_CheckApplyEnabled();
1008a10cf76eSAxel Dörfler 			break;
1009a10cf76eSAxel Dörfler 
1010df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10116f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10126f095d6aSRyan Leavengood 				app_info info;
10136f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10146f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10156f095d6aSRyan Leavengood 			}
1016df3f5bacSStephan Aßmus 			break;
1017df3f5bacSStephan Aßmus 
1018a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1019a10cf76eSAxel Dörfler 		{
10204be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1021a10cf76eSAxel Dörfler 			fSelected.width = 640;
1022a10cf76eSAxel Dörfler 			fSelected.height = 480;
1023a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1024a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1025a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1026a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1027a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1028a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1029a10cf76eSAxel Dörfler 
1030b21d610eSAxel Dörfler 			// TODO: workspace defaults
1031abc649b8SWaldemar Kornewald 
10325de171daSAxel Dörfler 			_UpdateControls();
1033a10cf76eSAxel Dörfler 			break;
1034a10cf76eSAxel Dörfler 		}
1035a10cf76eSAxel Dörfler 
103610e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
103761c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10385de171daSAxel Dörfler 			_UpdateActiveMode();
1039abc649b8SWaldemar Kornewald 			break;
1040abc649b8SWaldemar Kornewald 
1041abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1042abc649b8SWaldemar Kornewald 		{
1043abc649b8SWaldemar Kornewald 			fModified = false;
1044199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1045abc649b8SWaldemar Kornewald 
1046b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1047b21d610eSAxel Dörfler 			// number of workspaces
1048b21d610eSAxel Dörfler 
1049b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1050b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1051b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1052b21d610eSAxel Dörfler 
1053a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10545de171daSAxel Dörfler 			_UpdateActiveMode();
1055a10cf76eSAxel Dörfler 			break;
1056abc649b8SWaldemar Kornewald 		}
1057a10cf76eSAxel Dörfler 
1058a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10595de171daSAxel Dörfler 			_Apply();
1060a10cf76eSAxel Dörfler 			break;
1061a10cf76eSAxel Dörfler 
1062abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1063abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1064abc649b8SWaldemar Kornewald 			fModified = true;
10655de171daSAxel Dörfler 			_UpdateActiveMode();
1066a10cf76eSAxel Dörfler 			break;
1067a10cf76eSAxel Dörfler 
1068a10cf76eSAxel Dörfler 		default:
1069a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1070a10cf76eSAxel Dörfler 			break;
1071a10cf76eSAxel Dörfler 	}
1072a10cf76eSAxel Dörfler }
1073a10cf76eSAxel Dörfler 
1074a10cf76eSAxel Dörfler 
107512580984SAxel Dörfler status_t
107612580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
107712580984SAxel Dörfler {
107812580984SAxel Dörfler 	BPath path;
107912580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
108012580984SAxel Dörfler 	if (status < B_OK)
108112580984SAxel Dörfler 		return status;
108212580984SAxel Dörfler 
108312580984SAxel Dörfler 	path.Append("kernel/drivers");
108412580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
108512580984SAxel Dörfler 	if (status < B_OK)
108612580984SAxel Dörfler 		return status;
108712580984SAxel Dörfler 
108812580984SAxel Dörfler 	path.Append("vesa");
108912580984SAxel Dörfler 	BFile file;
109012580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
109112580984SAxel Dörfler 	if (status < B_OK)
109212580984SAxel Dörfler 		return status;
109312580984SAxel Dörfler 
109412580984SAxel Dörfler 	char buffer[256];
109512580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
109612580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
109712580984SAxel Dörfler 
109812580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
109912580984SAxel Dörfler 	if (bytesWritten < B_OK)
110012580984SAxel Dörfler 		return bytesWritten;
110112580984SAxel Dörfler 
110212580984SAxel Dörfler 	return B_OK;
110312580984SAxel Dörfler }
110412580984SAxel Dörfler 
110512580984SAxel Dörfler 
1106b21d610eSAxel Dörfler BButton*
1107b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1108b21d610eSAxel Dörfler {
1109b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1110b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1111b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1112b21d610eSAxel Dörfler 
1113b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1114b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1115b21d610eSAxel Dörfler 
1116b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1117b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1118b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1119b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1120b21d610eSAxel Dörfler 
1121b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1122b21d610eSAxel Dörfler 	return button;
1123b21d610eSAxel Dörfler }
1124b21d610eSAxel Dörfler 
1125b21d610eSAxel Dörfler 
1126b21d610eSAxel Dörfler BButton*
1127b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1128b21d610eSAxel Dörfler {
1129b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1130b21d610eSAxel Dörfler }
1131b21d610eSAxel Dörfler 
1132b21d610eSAxel Dörfler 
1133a10cf76eSAxel Dörfler void
11341fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11351fc4cb1fSAxel Dörfler {
11361fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11371fc4cb1fSAxel Dörfler 
11381fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11391fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11401fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11411fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11421fc4cb1fSAxel Dörfler 				break;
11431fc4cb1fSAxel Dörfler 			}
11441fc4cb1fSAxel Dörfler 		}
11451fc4cb1fSAxel Dörfler 	}
11461fc4cb1fSAxel Dörfler }
11471fc4cb1fSAxel Dörfler 
11481fc4cb1fSAxel Dörfler 
11491fc4cb1fSAxel Dörfler void
11505de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1151a10cf76eSAxel Dörfler {
115227c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
115327c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1154b21d610eSAxel Dörfler 
1155b21d610eSAxel Dörfler 	uint32 columns;
1156b21d610eSAxel Dörfler 	uint32 rows;
1157b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1158b21d610eSAxel Dörfler 
1159b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1160b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11615de171daSAxel Dörfler 		|| fSelected != fOriginal);
1162a10cf76eSAxel Dörfler }
1163a10cf76eSAxel Dörfler 
1164a10cf76eSAxel Dörfler 
1165a10cf76eSAxel Dörfler void
11665de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1167abc649b8SWaldemar Kornewald {
1168b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1169b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1170b21d610eSAxel Dörfler 
1171abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1172abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1173abc649b8SWaldemar Kornewald }
1174abc649b8SWaldemar Kornewald 
1175abc649b8SWaldemar Kornewald 
1176abc649b8SWaldemar Kornewald void
117712966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
117812966d04SAxel Dörfler {
117912966d04SAxel Dörfler 	monitor_info info;
118012966d04SAxel Dörfler 	float diagonalInches;
118112966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
1182*55030977SAxel Dörfler 	if (status == B_OK) {
11831a8af605SAxel Dörfler 		char text[512];
118466ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
118566ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
118612966d04SAxel Dörfler 
118712966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
118812966d04SAxel Dörfler 
118912966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
119012966d04SAxel Dörfler 			fMonitorInfo->Show();
1191*55030977SAxel Dörfler 	} else {
1192*55030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
1193*55030977SAxel Dörfler 			fMonitorInfo->Hide();
1194*55030977SAxel Dörfler 	}
1195af8f9c31SAxel Dörfler 
1196*55030977SAxel Dörfler 	char text[512];
11971a8af605SAxel Dörfler 	size_t length = 0;
11981a8af605SAxel Dörfler 	text[0] = 0;
11991a8af605SAxel Dörfler 
1200*55030977SAxel Dörfler 	if (status == B_OK) {
1201af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1202af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1203af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12041a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
12051a8af605SAxel Dörfler 				"Horizonal Frequency:\t%lu - %lu kHz\n"
1206af8f9c31SAxel Dörfler 				"Vertical Frequency:\t%lu - %lu Hz\n\n"
12071a8af605SAxel Dörfler 				"Maximum Pixel Clock:\t%g MHz",
12081a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12091a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12101a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1211af8f9c31SAxel Dörfler 		}
12121a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12131a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
12141a8af605SAxel Dörfler 				"%sSerial no.: %s", length ? "\n\n" : "",
12151a8af605SAxel Dörfler 				info.serial_number);
12161a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12171a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12181a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12191a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12201a8af605SAxel Dörfler 	 		}
12211a8af605SAxel Dörfler 		}
1222*55030977SAxel Dörfler 	}
122361c5c89bSAxel Dörfler 
122461c5c89bSAxel Dörfler 	// Add info about the graphics device
122561c5c89bSAxel Dörfler 
122661c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
122761c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
122861c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
122961c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
123061c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123161c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
123261c5c89bSAxel Dörfler 				deviceInfo.chipset);
123361c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
123461c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
123561c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
123661c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
123761c5c89bSAxel Dörfler 		}
123861c5c89bSAxel Dörfler 	}
123961c5c89bSAxel Dörfler 
12401a8af605SAxel Dörfler 	if (text[0])
12411a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
124212966d04SAxel Dörfler }
124312966d04SAxel Dörfler 
124412966d04SAxel Dörfler 
124512966d04SAxel Dörfler void
12461fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12471fc4cb1fSAxel Dörfler {
12481fc4cb1fSAxel Dörfler 	BString string;
12491fc4cb1fSAxel Dörfler 	string << fSelected.BitsPerPixel() << " Bits/Pixel";
12501fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12511fc4cb1fSAxel Dörfler }
12521fc4cb1fSAxel Dörfler 
12531fc4cb1fSAxel Dörfler 
12541fc4cb1fSAxel Dörfler void
12555de171daSAxel Dörfler ScreenWindow::_Apply()
1256a10cf76eSAxel Dörfler {
1257abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
125861c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
125961c5c89bSAxel Dörfler 
126007184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
126107184a9eSAxel Dörfler 	if (status == B_OK) {
1262abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1263abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1264abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1265abc649b8SWaldemar Kornewald 		display_mode newMode;
1266abc649b8SWaldemar Kornewald 		BScreen screen(this);
1267abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1268abc649b8SWaldemar Kornewald 
1269abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1270abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1271abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1272abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1273abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1274abc649b8SWaldemar Kornewald 			}
1275199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1276199893c3SAxel Dörfler 		} else {
1277199893c3SAxel Dörfler 			if (current_workspace() == 0)
1278199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1279abc649b8SWaldemar Kornewald 		}
1280abc649b8SWaldemar Kornewald 
1281a10cf76eSAxel Dörfler 		fActive = fSelected;
1282a10cf76eSAxel Dörfler 
1283abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1284a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1285a10cf76eSAxel Dörfler 		window->Show();
128607184a9eSAxel Dörfler 	} else {
128707184a9eSAxel Dörfler 		char message[256];
128807184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
128907184a9eSAxel Dörfler 			"The screen mode could not be set:\n\t%s\n", screen_errors(status));
129007184a9eSAxel Dörfler 		BAlert* alert = new BAlert("Screen Alert", message, "Okay", NULL, NULL,
129107184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
129207184a9eSAxel Dörfler 		alert->Go();
1293a10cf76eSAxel Dörfler 	}
129407184a9eSAxel Dörfler }
129507184a9eSAxel Dörfler 
1296