xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 1a8af60548374f85f30796b0cacf28bef11d0c8d)
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 
64c5d80d47SAxel Dörfler 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" },
75a10cf76eSAxel Dörfler 	{ B_RGB32, 32, "32 Bits/Pixel, 16 Million Colors" }
76a10cf76eSAxel Dörfler };
77b21d610eSAxel Dörfler static const int32 kColorSpaceCount
78b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
79a10cf76eSAxel Dörfler 
80a10cf76eSAxel Dörfler // list of standard refresh rates
81a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
82b21d610eSAxel Dörfler static const int32 kRefreshRateCount
83b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
84a10cf76eSAxel Dörfler 
85a10cf76eSAxel Dörfler // list of combine modes
86a10cf76eSAxel Dörfler static const struct {
87a10cf76eSAxel Dörfler 	combine_mode	mode;
88a10cf76eSAxel Dörfler 	const char		*name;
89a10cf76eSAxel Dörfler } kCombineModes[] = {
90a10cf76eSAxel Dörfler 	{ kCombineDisable, "disable" },
91a10cf76eSAxel Dörfler 	{ kCombineHorizontally, "horizontally" },
92a10cf76eSAxel Dörfler 	{ kCombineVertically, "vertically" }
93a10cf76eSAxel Dörfler };
94b21d610eSAxel Dörfler static const int32 kCombineModeCount
95b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
9629e8a73aSAxel Dörfler 
97a10cf76eSAxel Dörfler 
98a10cf76eSAxel Dörfler static BString
99a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
100a10cf76eSAxel Dörfler {
101a10cf76eSAxel Dörfler 	switch (mode) {
102a10cf76eSAxel Dörfler 		case 0:		return "disabled";
103a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
104a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
105a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
106a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
107a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
108a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
109a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
110a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
111a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
112a10cf76eSAxel Dörfler 		default:
113a10cf76eSAxel Dörfler 		{
114a10cf76eSAxel Dörfler 			BString name;
115a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
116a10cf76eSAxel Dörfler 
117a10cf76eSAxel Dörfler 			return name;
118a10cf76eSAxel Dörfler 		}
119a10cf76eSAxel Dörfler 	}
120a10cf76eSAxel Dörfler }
121a10cf76eSAxel Dörfler 
122a10cf76eSAxel Dörfler 
123a10cf76eSAxel Dörfler static void
124a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
125a10cf76eSAxel Dörfler {
126a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
127a10cf76eSAxel Dörfler }
128a10cf76eSAxel Dörfler 
129a10cf76eSAxel Dörfler 
130a10cf76eSAxel Dörfler static void
131a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
132a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
133a10cf76eSAxel Dörfler {
1348bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1358bf23e3cSAxel Dörfler 		refresh);
136a10cf76eSAxel Dörfler 	string.UnlockBuffer();
137a10cf76eSAxel Dörfler 
138a10cf76eSAxel Dörfler 	if (appendUnit)
139a10cf76eSAxel Dörfler 		string << " Hz";
140a10cf76eSAxel Dörfler }
141a10cf76eSAxel Dörfler 
142a10cf76eSAxel Dörfler 
14307184a9eSAxel Dörfler static const char*
14407184a9eSAxel Dörfler screen_errors(status_t status)
14507184a9eSAxel Dörfler {
14607184a9eSAxel Dörfler 	switch (status) {
14707184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
14807184a9eSAxel Dörfler 			return "Unknown Mode";
14907184a9eSAxel Dörfler 		// TODO: add more?
15007184a9eSAxel Dörfler 
15107184a9eSAxel Dörfler 		default:
15207184a9eSAxel Dörfler 			return strerror(status);
15307184a9eSAxel Dörfler 	}
15407184a9eSAxel Dörfler }
15507184a9eSAxel Dörfler 
15629e8a73aSAxel Dörfler 
1573dfd20c0SStephan Aßmus //	#pragma mark -
1583dfd20c0SStephan Aßmus 
1593dfd20c0SStephan Aßmus 
1605a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
161b21d610eSAxel Dörfler 	:
162b21d610eSAxel Dörfler 	BWindow(settings->WindowFrame(), "Screen", B_TITLED_WINDOW,
163b21d610eSAxel Dörfler 		B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
164b21d610eSAxel Dörfler 		B_ALL_WORKSPACES),
165199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
166a10cf76eSAxel Dörfler 	fScreenMode(this),
167abc649b8SWaldemar Kornewald 	fTempScreenMode(this),
168abc649b8SWaldemar Kornewald 	fModified(false)
169a10cf76eSAxel Dörfler {
170a10cf76eSAxel Dörfler 	BScreen screen(this);
171a10cf76eSAxel Dörfler 
17212580984SAxel Dörfler 	accelerant_device_info info;
173d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
174d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
17512580984SAxel Dörfler 		fIsVesa = true;
17612580984SAxel Dörfler 
1775de171daSAxel Dörfler 	_UpdateOriginal();
178a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
179a10cf76eSAxel Dörfler 
1805a78744bSAxel Dörfler 	fSettings = settings;
1815a78744bSAxel Dörfler 
1825a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1835a78744bSAxel Dörfler 
1845a78744bSAxel Dörfler 	BPopUpMenu *popUpMenu = new BPopUpMenu("Current Workspace", true, true);
185d1516993SAxel Dörfler 	fAllWorkspacesItem = new BMenuItem("All Workspaces",
186d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1875a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
188d1516993SAxel Dörfler 	BMenuItem *item = new BMenuItem("Current Workspace",
189d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
190b72c4836SAlexandre Deckner 
1915a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
19227c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
1935a78744bSAxel Dörfler 
194b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
195b21d610eSAxel Dörfler 		popUpMenu, NULL);
1965a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
197a10cf76eSAxel Dörfler 
198a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
199a10cf76eSAxel Dörfler 
200b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2018bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
202b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
203b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
204a10cf76eSAxel Dörfler 
20512966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
20612966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
20712966d04SAxel Dörfler 
208df3f5bacSStephan Aßmus 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0), "monitor",
2096bda235aSStefano Ceccherini 		screen.Frame().IntegerWidth() + 1, screen.Frame().IntegerHeight() + 1);
210b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2115a78744bSAxel Dörfler 
212b21d610eSAxel Dörfler 	fColumnsControl = new BTextControl("Columns:", "0",
213b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
214b21d610eSAxel Dörfler 	fRowsControl = new BTextControl("Rows:", "0",
215b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
216b21d610eSAxel Dörfler 
217b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
218b21d610eSAxel Dörfler 		.Add(new BStringView("", "Workspaces"), 0, 0, 3)
219b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
220b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
221b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
222b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
223b21d610eSAxel Dörfler 		.End()
224b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
225b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
226b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
227b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
228b21d610eSAxel Dörfler 		.End());
229b21d610eSAxel Dörfler 
230b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
231b21d610eSAxel Dörfler 		"Set Background" B_UTF8_ELLIPSIS,
232b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
233b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
234b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
235a10cf76eSAxel Dörfler 
236a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
237a10cf76eSAxel Dörfler 
238b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
239b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
240b21d610eSAxel Dörfler 	BView* outerControlsView = BLayoutBuilder::Group<>(B_VERTICAL, 10.0)
241b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10);
242b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
243a10cf76eSAxel Dörfler 
244a10cf76eSAxel Dörfler 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
245a10cf76eSAxel Dörfler 
24666ab1666SAxel Dörfler 	uint16 maxWidth = 0;
24766ab1666SAxel Dörfler 	uint16 maxHeight = 0;
24866ab1666SAxel Dörfler 	uint16 previousWidth = 0;
24966ab1666SAxel Dörfler 	uint16 previousHeight = 0;
250a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
251a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
252a10cf76eSAxel Dörfler 
253a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
254a10cf76eSAxel Dörfler 			continue;
255a10cf76eSAxel Dörfler 
256a10cf76eSAxel Dörfler 		previousWidth = mode.width;
257a10cf76eSAxel Dörfler 		previousHeight = mode.height;
25866ab1666SAxel Dörfler 		if (maxWidth < mode.width)
25966ab1666SAxel Dörfler 			maxWidth = mode.width;
26066ab1666SAxel Dörfler 		if (maxHeight < mode.height)
26166ab1666SAxel Dörfler 			maxHeight = mode.height;
262a10cf76eSAxel Dörfler 
263a10cf76eSAxel Dörfler 		BMessage *message = new BMessage(POP_RESOLUTION_MSG);
264a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
265a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
266a10cf76eSAxel Dörfler 
267a10cf76eSAxel Dörfler 		BString name;
268a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
269a10cf76eSAxel Dörfler 
270a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
271a10cf76eSAxel Dörfler 	}
272a10cf76eSAxel Dörfler 
27366ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
27466ab1666SAxel Dörfler 
27529e8a73aSAxel Dörfler 	BRect rect(0.0, 0.0, 200.0, 15.0);
276df3f5bacSStephan Aßmus 	// fResolutionField needs to be at the correct
277df3f5bacSStephan Aßmus 	// left-top offset, because all other menu fields
278df3f5bacSStephan Aßmus 	// will be layouted relative to it
279b21d610eSAxel Dörfler 	fResolutionField = new BMenuField("ResolutionMenu", "Resolution:",
280b21d610eSAxel Dörfler 		fResolutionMenu, NULL);
281a10cf76eSAxel Dörfler 
282a10cf76eSAxel Dörfler 	fColorsMenu = new BPopUpMenu("colors", true, true);
283a10cf76eSAxel Dörfler 
284a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
285a10cf76eSAxel Dörfler 		BMessage *message = new BMessage(POP_COLORS_MSG);
286a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
287a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
288a10cf76eSAxel Dörfler 
289a10cf76eSAxel Dörfler 		fColorsMenu->AddItem(new BMenuItem(kColorSpaces[i].label, message));
290a10cf76eSAxel Dörfler 	}
291a10cf76eSAxel Dörfler 
292df3f5bacSStephan Aßmus 	rect.OffsetTo(B_ORIGIN);
293df3f5bacSStephan Aßmus 
294b21d610eSAxel Dörfler 	fColorsField = new BMenuField("ColorsMenu", "Colors:", fColorsMenu, NULL);
295a10cf76eSAxel Dörfler 
296a10cf76eSAxel Dörfler 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
297a10cf76eSAxel Dörfler 
29829e8a73aSAxel Dörfler 	BMessage *message;
29929e8a73aSAxel Dörfler 
30029e8a73aSAxel Dörfler 	float min, max;
30129e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
30229e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
30329e8a73aSAxel Dörfler 		// frequency, like the VESA driver
30429e8a73aSAxel Dörfler 		BString name;
30529e8a73aSAxel Dörfler 		name << min << " Hz";
30629e8a73aSAxel Dörfler 
30729e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
30829e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
30929e8a73aSAxel Dörfler 
31029e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
31129e8a73aSAxel Dörfler 		item->SetEnabled(false);
31229e8a73aSAxel Dörfler 	} else {
31370a2b1b5SAxel Dörfler 		monitor_info info;
31470a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
31570a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
31670a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
31770a2b1b5SAxel Dörfler 		}
31870a2b1b5SAxel Dörfler 
319a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
32070a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
32170a2b1b5SAxel Dörfler 				continue;
32270a2b1b5SAxel Dörfler 
323a10cf76eSAxel Dörfler 			BString name;
324a10cf76eSAxel Dörfler 			name << kRefreshRates[i] << " Hz";
325a10cf76eSAxel Dörfler 
32629e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
327a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
328a10cf76eSAxel Dörfler 
329a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
330a10cf76eSAxel Dörfler 		}
331a10cf76eSAxel Dörfler 
33229e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
333a10cf76eSAxel Dörfler 
334a10cf76eSAxel Dörfler 		fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
335a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
33629e8a73aSAxel Dörfler 	}
337a10cf76eSAxel Dörfler 
338b21d610eSAxel Dörfler 	fRefreshField = new BMenuField("RefreshMenu", "Refresh Rate:",
339b21d610eSAxel Dörfler 		fRefreshMenu, NULL);
340b21d610eSAxel Dörfler 
34112580984SAxel Dörfler 	if (_IsVesa())
34212580984SAxel Dörfler 		fRefreshField->Hide();
343a10cf76eSAxel Dörfler 
344a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
345a10cf76eSAxel Dörfler 	{
346a10cf76eSAxel Dörfler 		bool dummy;
347a10cf76eSAxel Dörfler 		uint32 dummy32;
348a10cf76eSAxel Dörfler 		bool multiMonSupport;
349a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
350a10cf76eSAxel Dörfler 		bool tvStandardSupport;
351a10cf76eSAxel Dörfler 
352a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
353a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
354a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
355a10cf76eSAxel Dörfler 
356a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
357a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
358a10cf76eSAxel Dörfler 
359a10cf76eSAxel Dörfler 		fCombineMenu = new BPopUpMenu("CombineDisplays", true, true);
360a10cf76eSAxel Dörfler 
361a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
362a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
363a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
364a10cf76eSAxel Dörfler 
365d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
366d1516993SAxel Dörfler 				message));
367a10cf76eSAxel Dörfler 		}
368a10cf76eSAxel Dörfler 
369b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
370b21d610eSAxel Dörfler 			"Combine Displays:", fCombineMenu, NULL);
371a10cf76eSAxel Dörfler 
372a10cf76eSAxel Dörfler 		if (!multiMonSupport)
373df3f5bacSStephan Aßmus 			fCombineField->Hide();
374a10cf76eSAxel Dörfler 
375a10cf76eSAxel Dörfler 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", true, true);
376a10cf76eSAxel Dörfler 
377a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
378a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
379a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
380a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("no", message));
381a10cf76eSAxel Dörfler 
382a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
383a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
384a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("yes", message));
385a10cf76eSAxel Dörfler 
386b21d610eSAxel Dörfler 		fSwapDisplaysField = new BMenuField("SwapMenu", "Swap Displays:",
387b21d610eSAxel Dörfler 			fSwapDisplaysMenu, NULL);
388a10cf76eSAxel Dörfler 
389a10cf76eSAxel Dörfler 		if (!multiMonSupport)
390df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
391a10cf76eSAxel Dörfler 
392a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", true, true);
393a10cf76eSAxel Dörfler 
394a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
395a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
396a10cf76eSAxel Dörfler 		message->AddBool("use", false);
397a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("if needed", message));
398a10cf76eSAxel Dörfler 
399a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
400a10cf76eSAxel Dörfler 		message->AddBool("use", true);
401a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("always", message));
402a10cf76eSAxel Dörfler 
403b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
404b21d610eSAxel Dörfler 			"Use Laptop Panel:", fUseLaptopPanelMenu, NULL);
405a10cf76eSAxel Dörfler 
406a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
407df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
408a10cf76eSAxel Dörfler 
409a10cf76eSAxel Dörfler 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
410a10cf76eSAxel Dörfler 
411a10cf76eSAxel Dörfler 		// arbitrary limit
412a10cf76eSAxel Dörfler 		uint32 i;
413a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
414a10cf76eSAxel Dörfler 			uint32 mode;
415a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
416a10cf76eSAxel Dörfler 				break;
417a10cf76eSAxel Dörfler 
418a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
419a10cf76eSAxel Dörfler 
420a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
421a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
422a10cf76eSAxel Dörfler 
423a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
424a10cf76eSAxel Dörfler 		}
425a10cf76eSAxel Dörfler 
426b21d610eSAxel Dörfler 		fTVStandardField = new BMenuField("tv standard", "Video Format:",
427b21d610eSAxel Dörfler 			fTVStandardMenu, NULL);
428df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
429a10cf76eSAxel Dörfler 
430b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
431df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
432a10cf76eSAxel Dörfler 	}
433a10cf76eSAxel Dörfler 
434b21d610eSAxel Dörfler 	BView* controlsView = BLayoutBuilder::Grid<>(5.0, 5.0)
435b21d610eSAxel Dörfler 		.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
436b21d610eSAxel Dörfler 		.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
437b21d610eSAxel Dörfler 		.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
438b21d610eSAxel Dörfler 		.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
439b21d610eSAxel Dörfler 		.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
440b21d610eSAxel Dörfler 		.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
441b21d610eSAxel Dörfler 		.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT);
442b21d610eSAxel Dörfler 	outerControlsView->AddChild(controlsView);
443df3f5bacSStephan Aßmus 
444abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
445abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
446b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
447a10cf76eSAxel Dörfler 
448b21d610eSAxel Dörfler 	fApplyButton = new BButton("ApplyButton", "Apply",
449df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
450df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
451b21d610eSAxel Dörfler 	outerControlsView->GetLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
452b21d610eSAxel Dörfler 	outerControlsView->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL)
453b21d610eSAxel Dörfler 		.AddGlue()
454b21d610eSAxel Dörfler 		.Add(fApplyButton));
455b21d610eSAxel Dörfler 
456b21d610eSAxel Dörfler 	fRevertButton = new BButton("RevertButton", "Revert",
457b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
458b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
459b21d610eSAxel Dörfler 
460b21d610eSAxel Dörfler 	SetLayout(new BGroupLayout(B_VERTICAL, 10.0));
461b21d610eSAxel Dörfler 	GetLayout()->View()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
462b21d610eSAxel Dörfler 
463b21d610eSAxel Dörfler 	BLayoutBuilder::Group<>(static_cast<BGroupLayout*>(GetLayout()))
464b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
465b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
466b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
467b21d610eSAxel Dörfler 				.Add(screenBox)
468b21d610eSAxel Dörfler 			.End()
469b21d610eSAxel Dörfler 			.Add(controlsBox)
470b21d610eSAxel Dörfler 		.End()
471b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
472b21d610eSAxel Dörfler 			.Add(fRevertButton)
473b21d610eSAxel Dörfler 			.AddGlue();
474b21d610eSAxel Dörfler 
475b21d610eSAxel Dörfler 	screenBox->Parent()->GetLayout()->AddItem(0,
476b21d610eSAxel Dörfler 		BSpaceLayoutItem::CreateVerticalStrut(
477b21d610eSAxel Dörfler 			controlsBox->TopBorderOffset() - 1));
4785a78744bSAxel Dörfler 
4795de171daSAxel Dörfler 	_UpdateControls();
48012966d04SAxel Dörfler 	_UpdateMonitor();
481a10cf76eSAxel Dörfler }
482a10cf76eSAxel Dörfler 
483a10cf76eSAxel Dörfler 
484a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
485a10cf76eSAxel Dörfler {
486a10cf76eSAxel Dörfler 	delete fSettings;
487a10cf76eSAxel Dörfler }
488a10cf76eSAxel Dörfler 
489a10cf76eSAxel Dörfler 
490a10cf76eSAxel Dörfler bool
491a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
492a10cf76eSAxel Dörfler {
493a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
494199893c3SAxel Dörfler 
495199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
496199893c3SAxel Dörfler 	screen_mode vesaMode;
497199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
498199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
49912580984SAxel Dörfler 		if (status < B_OK) {
50012580984SAxel Dörfler 			BString warning = "Could not write VESA mode settings file:\n\t";
50112580984SAxel Dörfler 			warning << strerror(status);
50212580984SAxel Dörfler 			(new BAlert("VesaAlert", warning.String(), "Okay", NULL, NULL,
50312580984SAxel Dörfler 				B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
50412580984SAxel Dörfler 		}
50512580984SAxel Dörfler 	}
50612580984SAxel Dörfler 
507a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
508a10cf76eSAxel Dörfler 
509a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
510a10cf76eSAxel Dörfler }
511a10cf76eSAxel Dörfler 
512a10cf76eSAxel Dörfler 
5135de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5145de171daSAxel Dörfler 	(some resolution may not be combinable due to memory restrictions)
515a10cf76eSAxel Dörfler */
516a10cf76eSAxel Dörfler void
5175de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
518a10cf76eSAxel Dörfler {
519a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
520a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
521a10cf76eSAxel Dörfler 
522a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
523a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
524a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
525a10cf76eSAxel Dörfler 			continue;
526a10cf76eSAxel Dörfler 
527a10cf76eSAxel Dörfler 		BString name;
528a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
529a10cf76eSAxel Dörfler 
530a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
531a10cf76eSAxel Dörfler 		if (item != NULL)
532a10cf76eSAxel Dörfler 			item->SetEnabled(true);
533a10cf76eSAxel Dörfler 	}
534a10cf76eSAxel Dörfler }
535a10cf76eSAxel Dörfler 
536a10cf76eSAxel Dörfler 
5375de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5385de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5395de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5405de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
541a10cf76eSAxel Dörfler */
542a10cf76eSAxel Dörfler void
5435de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
544a10cf76eSAxel Dörfler {
545a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
546a10cf76eSAxel Dörfler 		bool supported = false;
547a10cf76eSAxel Dörfler 
548a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
549a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
550a10cf76eSAxel Dörfler 
551a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
552a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5535de171daSAxel Dörfler 				&& (kColorSpaces[i].space == mode.space
5545de171daSAxel Dörfler 					// advertize 24 bit mode as 32 bit to avoid confusion
5555de171daSAxel Dörfler 					|| (kColorSpaces[i].space == B_RGB32
5565de171daSAxel Dörfler 						&& mode.space == B_RGB24))
557a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
558a10cf76eSAxel Dörfler 				supported = true;
559a10cf76eSAxel Dörfler 				break;
560a10cf76eSAxel Dörfler 			}
561a10cf76eSAxel Dörfler 		}
562a10cf76eSAxel Dörfler 
563a10cf76eSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(i);
564a10cf76eSAxel Dörfler 		if (item)
565a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
566a10cf76eSAxel Dörfler 	}
567a10cf76eSAxel Dörfler }
568a10cf76eSAxel Dörfler 
569a10cf76eSAxel Dörfler 
5705de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
571a10cf76eSAxel Dörfler void
5725de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
573a10cf76eSAxel Dörfler {
57429e8a73aSAxel Dörfler 	float min, max;
57529e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
57629e8a73aSAxel Dörfler 		return;
577a10cf76eSAxel Dörfler 
57829e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
57929e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
58029e8a73aSAxel Dörfler 		BMessage* message = item->Message();
58129e8a73aSAxel Dörfler 		float refresh;
58229e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
58329e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
584a10cf76eSAxel Dörfler 	}
585a10cf76eSAxel Dörfler }
586a10cf76eSAxel Dörfler 
587a10cf76eSAxel Dörfler 
5885de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
589a10cf76eSAxel Dörfler void
5905de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
591a10cf76eSAxel Dörfler {
592a10cf76eSAxel Dörfler 	BString string;
593a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
594a10cf76eSAxel Dörfler 
595a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
596a10cf76eSAxel Dörfler 	if (item) {
597a10cf76eSAxel Dörfler 		if (!item->IsMarked())
598a10cf76eSAxel Dörfler 			item->SetMarked(true);
59929e8a73aSAxel Dörfler 
600a10cf76eSAxel Dörfler 		// "Other…" items only contains a refresh rate when active
601e6b421a9SJérôme Duval 		fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
602a10cf76eSAxel Dörfler 		return;
603a10cf76eSAxel Dörfler 	}
604a10cf76eSAxel Dörfler 
605a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
606a10cf76eSAxel Dörfler 
607a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
608a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
609a10cf76eSAxel Dörfler 
610a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
611a10cf76eSAxel Dörfler 
612a10cf76eSAxel Dörfler 	string.Append("/Other" B_UTF8_ELLIPSIS);
613a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
614a10cf76eSAxel Dörfler }
615a10cf76eSAxel Dörfler 
616a10cf76eSAxel Dörfler 
617a10cf76eSAxel Dörfler void
6185de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
619a10cf76eSAxel Dörfler {
620a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
621a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
622a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
623a10cf76eSAxel Dörfler 
624a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
625a10cf76eSAxel Dörfler }
626a10cf76eSAxel Dörfler 
627a10cf76eSAxel Dörfler 
628a10cf76eSAxel Dörfler void
6295de171daSAxel Dörfler ScreenWindow::_UpdateControls()
630a10cf76eSAxel Dörfler {
631b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
632b21d610eSAxel Dörfler 
633a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
634a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
635a10cf76eSAxel Dörfler 		item->SetMarked(true);
636a10cf76eSAxel Dörfler 
637a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
638a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
639a10cf76eSAxel Dörfler 		item->SetMarked(true);
640a10cf76eSAxel Dörfler 
641a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
642a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
643a10cf76eSAxel Dörfler 
644a10cf76eSAxel Dörfler 		uint32 tvStandard;
645a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
646a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
647a10cf76eSAxel Dörfler 			if (!item->IsMarked())
648a10cf76eSAxel Dörfler 				item->SetMarked(true);
649a10cf76eSAxel Dörfler 			break;
650a10cf76eSAxel Dörfler 		}
651a10cf76eSAxel Dörfler 	}
652a10cf76eSAxel Dörfler 
6535de171daSAxel Dörfler 	_CheckResolutionMenu();
6545de171daSAxel Dörfler 	_CheckColorMenu();
6555de171daSAxel Dörfler 	_CheckRefreshMenu();
656a10cf76eSAxel Dörfler 
657a10cf76eSAxel Dörfler 	BString string;
658a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
659a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
660a10cf76eSAxel Dörfler 
661a10cf76eSAxel Dörfler 	if (item != NULL) {
662a10cf76eSAxel Dörfler 		if (!item->IsMarked())
663a10cf76eSAxel Dörfler 			item->SetMarked(true);
664a10cf76eSAxel Dörfler 	} else {
665a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
666a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
667a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
668a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
669a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
670a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
671a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
672a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
673a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
674a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
675a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
676a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
677a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
678a10cf76eSAxel Dörfler 		if (item)
679a10cf76eSAxel Dörfler 			item->SetMarked(true);
680a10cf76eSAxel Dörfler 
681a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
682a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
683a10cf76eSAxel Dörfler 	}
684a10cf76eSAxel Dörfler 
685a10cf76eSAxel Dörfler 	// mark active combine mode
686a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
687a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
688a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
689a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
690a10cf76eSAxel Dörfler 				item->SetMarked(true);
691a10cf76eSAxel Dörfler 			break;
692a10cf76eSAxel Dörfler 		}
693a10cf76eSAxel Dörfler 	}
694a10cf76eSAxel Dörfler 
695a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
696a10cf76eSAxel Dörfler 
697a10cf76eSAxel Dörfler 	for (int32 i = kColorSpaceCount; i-- > 0;) {
6985de171daSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space
6995de171daSAxel Dörfler 			|| (kColorSpaces[i].space == B_RGB32
7005de171daSAxel Dörfler 				&& fSelected.space == B_RGB24)) {
701a10cf76eSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
702a10cf76eSAxel Dörfler 			break;
703a10cf76eSAxel Dörfler 		}
704a10cf76eSAxel Dörfler 	}
705a10cf76eSAxel Dörfler 
706a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
707a10cf76eSAxel Dörfler 		item->SetMarked(true);
708a10cf76eSAxel Dörfler 
709a10cf76eSAxel Dörfler 	string.Truncate(0);
7105de171daSAxel Dörfler 	uint32 bitsPerPixel = fSelected.BitsPerPixel();
7115de171daSAxel Dörfler 	// advertize 24 bit mode as 32 bit to avoid confusion
7125de171daSAxel Dörfler 	if (bitsPerPixel == 24)
7135de171daSAxel Dörfler 		bitsPerPixel = 32;
7145de171daSAxel Dörfler 
7155de171daSAxel Dörfler 	string << bitsPerPixel << " Bits/Pixel";
716a10cf76eSAxel Dörfler 	if (string != fColorsMenu->Superitem()->Label())
717a10cf76eSAxel Dörfler 		fColorsMenu->Superitem()->SetLabel(string.String());
718a10cf76eSAxel Dörfler 
7195de171daSAxel Dörfler 	_UpdateMonitorView();
7205de171daSAxel Dörfler 	_UpdateRefreshControl();
721a10cf76eSAxel Dörfler 
7225de171daSAxel Dörfler 	_CheckApplyEnabled();
723a10cf76eSAxel Dörfler }
724a10cf76eSAxel Dörfler 
725a10cf76eSAxel Dörfler 
72612580984SAxel Dörfler /*! Reflect active mode in chosen settings */
727a10cf76eSAxel Dörfler void
7285de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
729a10cf76eSAxel Dörfler {
73012580984SAxel Dörfler 	// Usually, this function gets called after a mode
731a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
732a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
733a10cf76eSAxel Dörfler 	// what kind of mode we actually got
734a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
735a10cf76eSAxel Dörfler 	fSelected = fActive;
736a10cf76eSAxel Dörfler 
73712966d04SAxel Dörfler 	_UpdateMonitor();
7385de171daSAxel Dörfler 	_UpdateControls();
739a10cf76eSAxel Dörfler }
740a10cf76eSAxel Dörfler 
741a10cf76eSAxel Dörfler 
742a10cf76eSAxel Dörfler void
743b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
744b21d610eSAxel Dörfler {
745b21d610eSAxel Dörfler 	uint32 columns;
746b21d610eSAxel Dörfler 	uint32 rows;
747b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
748b21d610eSAxel Dörfler 
749b21d610eSAxel Dörfler 	char text[32];
750b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
751b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
752b21d610eSAxel Dörfler 
753b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
754b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
755b21d610eSAxel Dörfler 
756b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
757b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
758b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
759b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
760b21d610eSAxel Dörfler }
761b21d610eSAxel Dörfler 
762b21d610eSAxel Dörfler 
763b21d610eSAxel Dörfler void
764a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
765a10cf76eSAxel Dörfler {
766a10cf76eSAxel Dörfler 	// move window on screen, if necessary
767a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
768a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
769a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
770a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
771a10cf76eSAxel Dörfler 	}
772a10cf76eSAxel Dörfler }
773a10cf76eSAxel Dörfler 
774a10cf76eSAxel Dörfler 
775a10cf76eSAxel Dörfler void
776a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
777a10cf76eSAxel Dörfler {
778abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
7795de171daSAxel Dörfler 	_UpdateActiveMode();
780a10cf76eSAxel Dörfler 
7816edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
7826edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
783a10cf76eSAxel Dörfler }
784a10cf76eSAxel Dörfler 
785a10cf76eSAxel Dörfler 
786a10cf76eSAxel Dörfler void
787a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
788a10cf76eSAxel Dörfler {
789a10cf76eSAxel Dörfler 	switch (message->what) {
790a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
7915de171daSAxel Dörfler 			_CheckApplyEnabled();
792a10cf76eSAxel Dörfler 			break;
793a10cf76eSAxel Dörfler 
794b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
795a10cf76eSAxel Dörfler 		{
796b21d610eSAxel Dörfler 			int32 deltaX = 0;
797b21d610eSAxel Dörfler 			int32 deltaY = 0;
798b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
799b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
800b21d610eSAxel Dörfler 
801b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
802b21d610eSAxel Dörfler 				break;
803b21d610eSAxel Dörfler 
804b21d610eSAxel Dörfler 			uint32 newColumns;
805b21d610eSAxel Dörfler 			uint32 newRows;
806b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
807b21d610eSAxel Dörfler 
808b21d610eSAxel Dörfler 			newColumns += deltaX;
809b21d610eSAxel Dörfler 			newRows += deltaY;
810b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
811b21d610eSAxel Dörfler 
812b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8135de171daSAxel Dörfler 			_CheckApplyEnabled();
814b21d610eSAxel Dörfler 			break;
815abc649b8SWaldemar Kornewald 		}
816b21d610eSAxel Dörfler 
817b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
818b21d610eSAxel Dörfler 		{
819b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
820b21d610eSAxel Dörfler 
821b21d610eSAxel Dörfler 			uint32 rows;
822b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
823b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
824b21d610eSAxel Dörfler 
825b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
826b21d610eSAxel Dörfler 			_CheckApplyEnabled();
827b21d610eSAxel Dörfler 			break;
828b21d610eSAxel Dörfler 		}
829b21d610eSAxel Dörfler 
830b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
831b21d610eSAxel Dörfler 		{
832b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
833b21d610eSAxel Dörfler 
834b21d610eSAxel Dörfler 			uint32 columns;
835b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
836b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
837b21d610eSAxel Dörfler 
838b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
839b21d610eSAxel Dörfler 			_CheckApplyEnabled();
840a10cf76eSAxel Dörfler 			break;
841a10cf76eSAxel Dörfler 		}
842a10cf76eSAxel Dörfler 
843a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
844a10cf76eSAxel Dörfler 		{
845a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
846a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
847a10cf76eSAxel Dörfler 
8485de171daSAxel Dörfler 			_CheckColorMenu();
8495de171daSAxel Dörfler 			_CheckRefreshMenu();
850a10cf76eSAxel Dörfler 
8515de171daSAxel Dörfler 			_UpdateMonitorView();
8525de171daSAxel Dörfler 			_UpdateRefreshControl();
853a10cf76eSAxel Dörfler 
8545de171daSAxel Dörfler 			_CheckApplyEnabled();
855a10cf76eSAxel Dörfler 			break;
856a10cf76eSAxel Dörfler 		}
857a10cf76eSAxel Dörfler 
858a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
859a10cf76eSAxel Dörfler 		{
860a10cf76eSAxel Dörfler 			message->FindInt32("space", (int32 *)&fSelected.space);
861a10cf76eSAxel Dörfler 
862a10cf76eSAxel Dörfler 			BString string;
863a10cf76eSAxel Dörfler 			string << fSelected.BitsPerPixel() << " Bits/Pixel";
864a10cf76eSAxel Dörfler 			fColorsMenu->Superitem()->SetLabel(string.String());
865a10cf76eSAxel Dörfler 
8665de171daSAxel Dörfler 			_CheckApplyEnabled();
867a10cf76eSAxel Dörfler 			break;
868a10cf76eSAxel Dörfler 		}
869a10cf76eSAxel Dörfler 
870a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
871a40498e2SWaldemar Kornewald 		{
872a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
873a10cf76eSAxel Dörfler 			fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
874a10cf76eSAxel Dörfler 				// revert "Other…" label - it might have had a refresh rate prefix
875a10cf76eSAxel Dörfler 
8765de171daSAxel Dörfler 			_CheckApplyEnabled();
877a10cf76eSAxel Dörfler 			break;
878a40498e2SWaldemar Kornewald 		}
879a10cf76eSAxel Dörfler 
880a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
881a10cf76eSAxel Dörfler 		{
88229e8a73aSAxel Dörfler 			// make sure menu shows something useful
8835de171daSAxel Dörfler 			_UpdateRefreshControl();
884a10cf76eSAxel Dörfler 
88529e8a73aSAxel Dörfler 			float min = 0, max = 999;
88629e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
88729e8a73aSAxel Dörfler 			if (min < gMinRefresh)
88829e8a73aSAxel Dörfler 				min = gMinRefresh;
88929e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
89029e8a73aSAxel Dörfler 				max = gMaxRefresh;
89129e8a73aSAxel Dörfler 
89270a2b1b5SAxel Dörfler 			monitor_info info;
89370a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
89470a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
89570a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
89670a2b1b5SAxel Dörfler 			}
89770a2b1b5SAxel Dörfler 
898c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
89970a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
90070a2b1b5SAxel Dörfler 				min, max);
901a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
902a10cf76eSAxel Dörfler 			break;
903a10cf76eSAxel Dörfler 		}
904a10cf76eSAxel Dörfler 
905a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
906a10cf76eSAxel Dörfler 		{
907a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
908a10cf76eSAxel Dörfler 			// select the refresh rate chosen
909a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
910a10cf76eSAxel Dörfler 
9115de171daSAxel Dörfler 			_UpdateRefreshControl();
9125de171daSAxel Dörfler 			_CheckApplyEnabled();
913a10cf76eSAxel Dörfler 			break;
914a10cf76eSAxel Dörfler 		}
915a10cf76eSAxel Dörfler 
916a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
917a10cf76eSAxel Dörfler 		{
918a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
919a10cf76eSAxel Dörfler 			int32 mode;
920a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
921a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
922a10cf76eSAxel Dörfler 
9235de171daSAxel Dörfler 			_CheckResolutionMenu();
9245de171daSAxel Dörfler 			_CheckApplyEnabled();
925a10cf76eSAxel Dörfler 			break;
926a10cf76eSAxel Dörfler 		}
927a10cf76eSAxel Dörfler 
928a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
929a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
9305de171daSAxel Dörfler 			_CheckApplyEnabled();
931a10cf76eSAxel Dörfler 			break;
932a10cf76eSAxel Dörfler 
933a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
934a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
9355de171daSAxel Dörfler 			_CheckApplyEnabled();
936a10cf76eSAxel Dörfler 			break;
937a10cf76eSAxel Dörfler 
938a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
939a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
9405de171daSAxel Dörfler 			_CheckApplyEnabled();
941a10cf76eSAxel Dörfler 			break;
942a10cf76eSAxel Dörfler 
943df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
9446f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
9456f095d6aSRyan Leavengood 				app_info info;
9466f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
9476f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
9486f095d6aSRyan Leavengood 			}
949df3f5bacSStephan Aßmus 			break;
950df3f5bacSStephan Aßmus 
951a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
952a10cf76eSAxel Dörfler 		{
9534be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
954a10cf76eSAxel Dörfler 			fSelected.width = 640;
955a10cf76eSAxel Dörfler 			fSelected.height = 480;
956a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
957a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
958a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
959a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
960a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
961a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
962a10cf76eSAxel Dörfler 
963b21d610eSAxel Dörfler 			// TODO: workspace defaults
964abc649b8SWaldemar Kornewald 
9655de171daSAxel Dörfler 			_UpdateControls();
966a10cf76eSAxel Dörfler 			break;
967a10cf76eSAxel Dörfler 		}
968a10cf76eSAxel Dörfler 
96910e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
970abc649b8SWaldemar Kornewald 			fTempScreenMode.Revert();
9715de171daSAxel Dörfler 			_UpdateActiveMode();
972abc649b8SWaldemar Kornewald 			break;
973abc649b8SWaldemar Kornewald 
974abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
975abc649b8SWaldemar Kornewald 		{
976abc649b8SWaldemar Kornewald 			fModified = false;
977199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
978abc649b8SWaldemar Kornewald 
979b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
980b21d610eSAxel Dörfler 			// number of workspaces
981b21d610eSAxel Dörfler 
982b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
983b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
984b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
985b21d610eSAxel Dörfler 
986a10cf76eSAxel Dörfler 			fScreenMode.Revert();
9875de171daSAxel Dörfler 			_UpdateActiveMode();
988a10cf76eSAxel Dörfler 			break;
989abc649b8SWaldemar Kornewald 		}
990a10cf76eSAxel Dörfler 
991a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
9925de171daSAxel Dörfler 			_Apply();
993a10cf76eSAxel Dörfler 			break;
994a10cf76eSAxel Dörfler 
995abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
996abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
997abc649b8SWaldemar Kornewald 			fModified = true;
9985de171daSAxel Dörfler 			_UpdateActiveMode();
999a10cf76eSAxel Dörfler 			break;
1000a10cf76eSAxel Dörfler 
1001a10cf76eSAxel Dörfler 		default:
1002a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1003a10cf76eSAxel Dörfler 			break;
1004a10cf76eSAxel Dörfler 	}
1005a10cf76eSAxel Dörfler }
1006a10cf76eSAxel Dörfler 
1007a10cf76eSAxel Dörfler 
100812580984SAxel Dörfler status_t
100912580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
101012580984SAxel Dörfler {
101112580984SAxel Dörfler 	BPath path;
101212580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
101312580984SAxel Dörfler 	if (status < B_OK)
101412580984SAxel Dörfler 		return status;
101512580984SAxel Dörfler 
101612580984SAxel Dörfler 	path.Append("kernel/drivers");
101712580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
101812580984SAxel Dörfler 	if (status < B_OK)
101912580984SAxel Dörfler 		return status;
102012580984SAxel Dörfler 
102112580984SAxel Dörfler 	path.Append("vesa");
102212580984SAxel Dörfler 	BFile file;
102312580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
102412580984SAxel Dörfler 	if (status < B_OK)
102512580984SAxel Dörfler 		return status;
102612580984SAxel Dörfler 
102712580984SAxel Dörfler 	char buffer[256];
102812580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
102912580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
103012580984SAxel Dörfler 
103112580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
103212580984SAxel Dörfler 	if (bytesWritten < B_OK)
103312580984SAxel Dörfler 		return bytesWritten;
103412580984SAxel Dörfler 
103512580984SAxel Dörfler 	return B_OK;
103612580984SAxel Dörfler }
103712580984SAxel Dörfler 
103812580984SAxel Dörfler 
1039b21d610eSAxel Dörfler BButton*
1040b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1041b21d610eSAxel Dörfler {
1042b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1043b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1044b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1045b21d610eSAxel Dörfler 
1046b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1047b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1048b21d610eSAxel Dörfler 
1049b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1050b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1051b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1052b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1053b21d610eSAxel Dörfler 
1054b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1055b21d610eSAxel Dörfler 	return button;
1056b21d610eSAxel Dörfler }
1057b21d610eSAxel Dörfler 
1058b21d610eSAxel Dörfler 
1059b21d610eSAxel Dörfler BButton*
1060b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1061b21d610eSAxel Dörfler {
1062b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1063b21d610eSAxel Dörfler }
1064b21d610eSAxel Dörfler 
1065b21d610eSAxel Dörfler 
1066a10cf76eSAxel Dörfler void
10675de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1068a10cf76eSAxel Dörfler {
106927c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
107027c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1071b21d610eSAxel Dörfler 
1072b21d610eSAxel Dörfler 	uint32 columns;
1073b21d610eSAxel Dörfler 	uint32 rows;
1074b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1075b21d610eSAxel Dörfler 
1076b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1077b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
10785de171daSAxel Dörfler 		|| fSelected != fOriginal);
1079a10cf76eSAxel Dörfler }
1080a10cf76eSAxel Dörfler 
1081a10cf76eSAxel Dörfler 
1082a10cf76eSAxel Dörfler void
10835de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1084abc649b8SWaldemar Kornewald {
1085b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1086b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1087b21d610eSAxel Dörfler 
1088abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1089abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1090abc649b8SWaldemar Kornewald }
1091abc649b8SWaldemar Kornewald 
1092abc649b8SWaldemar Kornewald 
1093abc649b8SWaldemar Kornewald void
109412966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
109512966d04SAxel Dörfler {
109612966d04SAxel Dörfler 	monitor_info info;
109712966d04SAxel Dörfler 	float diagonalInches;
109812966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
109912966d04SAxel Dörfler 
110012966d04SAxel Dörfler 	if (status != B_OK) {
110112966d04SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
110212966d04SAxel Dörfler 			fMonitorInfo->Hide();
110312966d04SAxel Dörfler 		return;
110412966d04SAxel Dörfler 	}
110512966d04SAxel Dörfler 
1106*1a8af605SAxel Dörfler 	char text[512];
110766ab1666SAxel Dörfler 	snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
110866ab1666SAxel Dörfler 		info.name[0] ? " " : "", info.name, diagonalInches);
110912966d04SAxel Dörfler 
111012966d04SAxel Dörfler 	fMonitorInfo->SetText(text);
111112966d04SAxel Dörfler 
111212966d04SAxel Dörfler 	if (fMonitorInfo->IsHidden())
111312966d04SAxel Dörfler 		fMonitorInfo->Show();
1114af8f9c31SAxel Dörfler 
1115*1a8af605SAxel Dörfler 	size_t length = 0;
1116*1a8af605SAxel Dörfler 	text[0] = 0;
1117*1a8af605SAxel Dörfler 
1118af8f9c31SAxel Dörfler 	if (info.min_horizontal_frequency != 0
1119af8f9c31SAxel Dörfler 		&& info.min_vertical_frequency != 0
1120af8f9c31SAxel Dörfler 		&& info.max_pixel_clock != 0) {
1121*1a8af605SAxel Dörfler 		length = snprintf(text, sizeof(text),
1122*1a8af605SAxel Dörfler 			"Horizonal Frequency:\t%lu - %lu kHz\n"
1123af8f9c31SAxel Dörfler 			"Vertical Frequency:\t%lu - %lu Hz\n\n"
1124*1a8af605SAxel Dörfler 			"Maximum Pixel Clock:\t%g MHz",
1125*1a8af605SAxel Dörfler 			info.min_horizontal_frequency, info.max_horizontal_frequency,
1126*1a8af605SAxel Dörfler 			info.min_vertical_frequency, info.max_vertical_frequency,
1127*1a8af605SAxel Dörfler 			info.max_pixel_clock / 1000.0);
1128af8f9c31SAxel Dörfler 	}
1129*1a8af605SAxel Dörfler 	if (info.serial_number[0] && length < sizeof(text)) {
1130*1a8af605SAxel Dörfler 		length += snprintf(text + length, sizeof(text) - length,
1131*1a8af605SAxel Dörfler 			"%sSerial no.: %s", length ? "\n\n" : "",
1132*1a8af605SAxel Dörfler 			info.serial_number);
1133*1a8af605SAxel Dörfler 		if (info.produced.week != 0 && info.produced.year != 0
1134*1a8af605SAxel Dörfler 			&& length < sizeof(text)) {
1135*1a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1136*1a8af605SAxel Dörfler 				"(%u/%u)", info.produced.week, info.produced.year);
1137*1a8af605SAxel Dörfler  		}
1138*1a8af605SAxel Dörfler 	}
1139*1a8af605SAxel Dörfler 	if (text[0])
1140*1a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
114112966d04SAxel Dörfler }
114212966d04SAxel Dörfler 
114312966d04SAxel Dörfler 
114412966d04SAxel Dörfler void
11455de171daSAxel Dörfler ScreenWindow::_Apply()
1146a10cf76eSAxel Dörfler {
1147abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
1148abc649b8SWaldemar Kornewald 	fTempScreenMode.UpdateOriginalModes();
114907184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
115007184a9eSAxel Dörfler 	if (status == B_OK) {
1151abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1152abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1153abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1154abc649b8SWaldemar Kornewald 		display_mode newMode;
1155abc649b8SWaldemar Kornewald 		BScreen screen(this);
1156abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1157abc649b8SWaldemar Kornewald 
1158abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1159abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1160abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1161abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1162abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1163abc649b8SWaldemar Kornewald 			}
1164199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1165199893c3SAxel Dörfler 		} else {
1166199893c3SAxel Dörfler 			if (current_workspace() == 0)
1167199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1168abc649b8SWaldemar Kornewald 		}
1169abc649b8SWaldemar Kornewald 
1170a10cf76eSAxel Dörfler 		fActive = fSelected;
1171a10cf76eSAxel Dörfler 
1172abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1173a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1174a10cf76eSAxel Dörfler 		window->Show();
117507184a9eSAxel Dörfler 	} else {
117607184a9eSAxel Dörfler 		char message[256];
117707184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
117807184a9eSAxel Dörfler 			"The screen mode could not be set:\n\t%s\n", screen_errors(status));
117907184a9eSAxel Dörfler 		BAlert* alert = new BAlert("Screen Alert", message, "Okay", NULL, NULL,
118007184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
118107184a9eSAxel Dörfler 		alert->Go();
1182a10cf76eSAxel Dörfler 	}
118307184a9eSAxel Dörfler }
118407184a9eSAxel Dörfler 
1185