xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 41f43d568fa1f2af68bd3209850cb0b349b49ff4)
1a10cf76eSAxel Dörfler /*
2a3fa81bdSJohn Scipione  * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3a10cf76eSAxel Dörfler  * Distributed under the terms of the MIT License.
4a10cf76eSAxel Dörfler  *
5a10cf76eSAxel Dörfler  * Authors:
6e1c88201SJohn Scipione  *		Stephan Aßmus, superstippi@gmx.de
7a10cf76eSAxel Dörfler  *		Andrew Bachmann
8e1c88201SJohn Scipione  *		Stefano Ceccherini, burton666@libero.it
9e1c88201SJohn Scipione  *		Alexandre Deckner, alex@zappotek.com
10e1c88201SJohn Scipione  *		Axel Dörfler, axeld@pinc-software.de
117e44de36SRene Gollent  *		Rene Gollent, rene@gollent.com
12a10cf76eSAxel Dörfler  *		Thomas Kurschel
13e1c88201SJohn Scipione  *		Rafael Romo
14e1c88201SJohn Scipione  *		John Scipione, jscipione@gmail.com
15a10cf76eSAxel Dörfler  */
16a10cf76eSAxel Dörfler 
17a10cf76eSAxel Dörfler 
18b21d610eSAxel Dörfler #include "ScreenWindow.h"
19b21d610eSAxel Dörfler 
20b21d610eSAxel Dörfler #include <stdio.h>
21b21d610eSAxel Dörfler #include <stdlib.h>
223aeed660SJérôme Duval #include <strings.h>
23b21d610eSAxel Dörfler 
24b21d610eSAxel Dörfler #include <Alert.h>
25b21d610eSAxel Dörfler #include <Application.h>
26b21d610eSAxel Dörfler #include <Box.h>
27b21d610eSAxel Dörfler #include <Button.h>
28c9e8f97aSAdrien Destugues #include <Catalog.h>
29e1c88201SJohn Scipione #include <ControlLook.h>
30b21d610eSAxel Dörfler #include <Directory.h>
31b21d610eSAxel Dörfler #include <File.h>
32b21d610eSAxel Dörfler #include <FindDirectory.h>
33b21d610eSAxel Dörfler #include <InterfaceDefs.h>
34b21d610eSAxel Dörfler #include <LayoutBuilder.h>
35b21d610eSAxel Dörfler #include <MenuBar.h>
36b21d610eSAxel Dörfler #include <MenuItem.h>
37b21d610eSAxel Dörfler #include <MenuField.h>
38b21d610eSAxel Dörfler #include <Messenger.h>
39b21d610eSAxel Dörfler #include <Path.h>
40b21d610eSAxel Dörfler #include <PopUpMenu.h>
41b21d610eSAxel Dörfler #include <Screen.h>
42e1c88201SJohn Scipione #include <SpaceLayoutItem.h>
43a3fa81bdSJohn Scipione #include <Spinner.h>
44b21d610eSAxel Dörfler #include <String.h>
45b21d610eSAxel Dörfler #include <StringView.h>
46b21d610eSAxel Dörfler #include <Roster.h>
47b21d610eSAxel Dörfler #include <Window.h>
48b21d610eSAxel Dörfler 
49b21d610eSAxel Dörfler #include <InterfacePrivate.h>
50b21d610eSAxel Dörfler 
51a10cf76eSAxel Dörfler #include "AlertWindow.h"
52a10cf76eSAxel Dörfler #include "Constants.h"
53a10cf76eSAxel Dörfler #include "RefreshWindow.h"
54a10cf76eSAxel Dörfler #include "MonitorView.h"
55a10cf76eSAxel Dörfler #include "ScreenSettings.h"
56a10cf76eSAxel Dörfler #include "Utility.h"
57a10cf76eSAxel Dörfler 
58a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
59a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
60a10cf76eSAxel Dörfler  * adopted.
61a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
62a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
63a10cf76eSAxel Dörfler  * be using this.
64a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
65a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
66a10cf76eSAxel Dörfler  */
67a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
68a10cf76eSAxel Dörfler 
69a10cf76eSAxel Dörfler 
70546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
71546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "Screen"
72c9e8f97aSAdrien Destugues 
73c9e8f97aSAdrien Destugues 
7475c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
75c5d80d47SAxel Dörfler 
76a10cf76eSAxel Dörfler // list of officially supported colour spaces
77a10cf76eSAxel Dörfler static const struct {
78a10cf76eSAxel Dörfler 	color_space	space;
79a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
80a10cf76eSAxel Dörfler 	const char*	label;
81a10cf76eSAxel Dörfler } kColorSpaces[] = {
8226747978SAdrien Destugues 	{ B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") },
83c9e8f97aSAdrien Destugues 	{ B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") },
84c9e8f97aSAdrien Destugues 	{ B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") },
85c9e8f97aSAdrien Destugues 	{ B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") },
86c9e8f97aSAdrien Destugues 	{ B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") }
87a10cf76eSAxel Dörfler };
88b21d610eSAxel Dörfler static const int32 kColorSpaceCount
89b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
90a10cf76eSAxel Dörfler 
91a10cf76eSAxel Dörfler // list of standard refresh rates
92a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
93b21d610eSAxel Dörfler static const int32 kRefreshRateCount
94b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
95a10cf76eSAxel Dörfler 
96a10cf76eSAxel Dörfler // list of combine modes
97a10cf76eSAxel Dörfler static const struct {
98a10cf76eSAxel Dörfler 	combine_mode	mode;
99a10cf76eSAxel Dörfler 	const char		*name;
100a10cf76eSAxel Dörfler } kCombineModes[] = {
101c9e8f97aSAdrien Destugues 	{ kCombineDisable, B_TRANSLATE("disable") },
102c9e8f97aSAdrien Destugues 	{ kCombineHorizontally, B_TRANSLATE("horizontally") },
103c9e8f97aSAdrien Destugues 	{ kCombineVertically, B_TRANSLATE("vertically") }
104a10cf76eSAxel Dörfler };
105b21d610eSAxel Dörfler static const int32 kCombineModeCount
106b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
10729e8a73aSAxel Dörfler 
108a10cf76eSAxel Dörfler 
109a10cf76eSAxel Dörfler static BString
110a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
111a10cf76eSAxel Dörfler {
112a10cf76eSAxel Dörfler 	switch (mode) {
113a10cf76eSAxel Dörfler 		case 0:		return "disabled";
114a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
115a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
116a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
117a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
118a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
119a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
120a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
121a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
122a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
123a10cf76eSAxel Dörfler 		default:
124a10cf76eSAxel Dörfler 		{
125a10cf76eSAxel Dörfler 			BString name;
126a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
127a10cf76eSAxel Dörfler 
128a10cf76eSAxel Dörfler 			return name;
129a10cf76eSAxel Dörfler 		}
130a10cf76eSAxel Dörfler 	}
131a10cf76eSAxel Dörfler }
132a10cf76eSAxel Dörfler 
133a10cf76eSAxel Dörfler 
134a10cf76eSAxel Dörfler static void
135a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
136a10cf76eSAxel Dörfler {
137a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
138a10cf76eSAxel Dörfler }
139a10cf76eSAxel Dörfler 
140a10cf76eSAxel Dörfler 
141a10cf76eSAxel Dörfler static void
142a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
143a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
144a10cf76eSAxel Dörfler {
1458bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1468bf23e3cSAxel Dörfler 		refresh);
147a10cf76eSAxel Dörfler 	string.UnlockBuffer();
148a10cf76eSAxel Dörfler 
149a10cf76eSAxel Dörfler 	if (appendUnit)
150551c9f15SSiarzhuk Zharski 		string << " " << B_TRANSLATE("Hz");
151a10cf76eSAxel Dörfler }
152a10cf76eSAxel Dörfler 
153a10cf76eSAxel Dörfler 
15407184a9eSAxel Dörfler static const char*
15507184a9eSAxel Dörfler screen_errors(status_t status)
15607184a9eSAxel Dörfler {
15707184a9eSAxel Dörfler 	switch (status) {
15807184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
159c9e8f97aSAdrien Destugues 			return B_TRANSLATE("Unknown mode");
16007184a9eSAxel Dörfler 		// TODO: add more?
16107184a9eSAxel Dörfler 
16207184a9eSAxel Dörfler 		default:
16307184a9eSAxel Dörfler 			return strerror(status);
16407184a9eSAxel Dörfler 	}
16507184a9eSAxel Dörfler }
16607184a9eSAxel Dörfler 
16729e8a73aSAxel Dörfler 
168a3fa81bdSJohn Scipione //	#pragma mark - ScreenWindow
1693dfd20c0SStephan Aßmus 
1703dfd20c0SStephan Aßmus 
1715a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
172b21d610eSAxel Dörfler 	:
173560ff447SJonas Sundström 	BWindow(settings->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Screen"),
174958e0ca5SJohn Scipione 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE
175958e0ca5SJohn Scipione 			| B_AUTO_UPDATE_SIZE_LIMITS, B_ALL_WORKSPACES),
1763f953a72SAxel Dörfler 	fIsVesa(false),
177199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
1787e44de36SRene Gollent 	fOtherRefresh(NULL),
179294a85aaSRene Gollent 	fScreenMode(this),
18061c5c89bSAxel Dörfler 	fUndoScreenMode(this),
181abc649b8SWaldemar Kornewald 	fModified(false)
182a10cf76eSAxel Dörfler {
183a10cf76eSAxel Dörfler 	BScreen screen(this);
184a10cf76eSAxel Dörfler 
18512580984SAxel Dörfler 	accelerant_device_info info;
186d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
187d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
18812580984SAxel Dörfler 		fIsVesa = true;
18912580984SAxel Dörfler 
1905de171daSAxel Dörfler 	_UpdateOriginal();
1911fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
192a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
193a10cf76eSAxel Dörfler 
1945a78744bSAxel Dörfler 	fSettings = settings;
1955a78744bSAxel Dörfler 
1965a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1975a78744bSAxel Dörfler 
198c9e8f97aSAdrien Destugues 	BPopUpMenu* popUpMenu = new BPopUpMenu(B_TRANSLATE("Current workspace"),
199c9e8f97aSAdrien Destugues 		true, true);
200c9e8f97aSAdrien Destugues 	fAllWorkspacesItem = new BMenuItem(B_TRANSLATE("All workspaces"),
201d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
2025a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
203c9e8f97aSAdrien Destugues 	BMenuItem *item = new BMenuItem(B_TRANSLATE("Current workspace"),
204d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
205b72c4836SAlexandre Deckner 
2065a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
20727c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
2085a78744bSAxel Dörfler 
209b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
21010dfe897SAxel Dörfler 		popUpMenu);
2115a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
212a10cf76eSAxel Dörfler 
213a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
214a10cf76eSAxel Dörfler 
215b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
216e1c88201SJohn Scipione 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, B_USE_SMALL_SPACING);
217e1c88201SJohn Scipione 	layout->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
218e1c88201SJohn Scipione 		B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING);
219b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
220a10cf76eSAxel Dörfler 
22112966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
222e1c88201SJohn Scipione 	fMonitorInfo->SetAlignment(B_ALIGN_CENTER);
22312966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
22412966d04SAxel Dörfler 
2258b46ee25SAdrien Destugues 	fDeviceInfo = new BStringView("monitor info", "");
2268b46ee25SAdrien Destugues 	fDeviceInfo->SetAlignment(B_ALIGN_CENTER);
2278b46ee25SAdrien Destugues 	screenBox->AddChild(fDeviceInfo);
2288b46ee25SAdrien Destugues 
229c9e8f97aSAdrien Destugues 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0),
230551c9f15SSiarzhuk Zharski 		"monitor", screen.Frame().IntegerWidth() + 1,
231c9e8f97aSAdrien Destugues 		screen.Frame().IntegerHeight() + 1);
232b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2335a78744bSAxel Dörfler 
234e1c88201SJohn Scipione 	BStringView* workspaces = new BStringView("workspaces",
235e1c88201SJohn Scipione 		B_TRANSLATE("Workspaces"));
236e1c88201SJohn Scipione 	workspaces->SetAlignment(B_ALIGN_CENTER);
237e1c88201SJohn Scipione 
238a3fa81bdSJohn Scipione 	fColumnsControl = new BSpinner("columns", B_TRANSLATE("Columns:"),
239b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
240a3fa81bdSJohn Scipione 	fColumnsControl->SetAlignment(B_ALIGN_RIGHT);
241a3fa81bdSJohn Scipione 	fColumnsControl->SetRange(1, 32);
242b21d610eSAxel Dörfler 
243a3fa81bdSJohn Scipione 	fRowsControl = new BSpinner("rows", B_TRANSLATE("Rows:"),
244a3fa81bdSJohn Scipione 		new BMessage(kMsgWorkspaceRowsChanged));
245a3fa81bdSJohn Scipione 	fRowsControl->SetAlignment(B_ALIGN_RIGHT);
246a3fa81bdSJohn Scipione 	fRowsControl->SetRange(1, 32);
247a3fa81bdSJohn Scipione 
248a3fa81bdSJohn Scipione 	uint32 columns;
249a3fa81bdSJohn Scipione 	uint32 rows;
250a3fa81bdSJohn Scipione 	BPrivate::get_workspaces_layout(&columns, &rows);
251a3fa81bdSJohn Scipione 	fColumnsControl->SetValue(columns);
252a3fa81bdSJohn Scipione 	fRowsControl->SetValue(rows);
253a3fa81bdSJohn Scipione 
254e1c88201SJohn Scipione 	screenBox->AddChild(BLayoutBuilder::Group<>()
255e1c88201SJohn Scipione 		.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
256e1c88201SJohn Scipione 			.Add(workspaces)
257a3fa81bdSJohn Scipione 			.AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
258e1c88201SJohn Scipione 				// columns
259e1c88201SJohn Scipione 				.Add(fColumnsControl->CreateLabelLayoutItem(), 0, 0)
260a3fa81bdSJohn Scipione 				.Add(fColumnsControl->CreateTextViewLayoutItem(), 1, 0)
261e1c88201SJohn Scipione 				// rows
262e1c88201SJohn Scipione 				.Add(fRowsControl->CreateLabelLayoutItem(), 0, 1)
263a3fa81bdSJohn Scipione 				.Add(fRowsControl->CreateTextViewLayoutItem(), 1, 1)
264b21d610eSAxel Dörfler 				.End()
26525fd5c7bSAlex Wilson 			.End()
26625fd5c7bSAlex Wilson 		.View());
267b21d610eSAxel Dörfler 
268b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
269c9e8f97aSAdrien Destugues 		B_TRANSLATE("Set background" B_UTF8_ELLIPSIS),
270b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
271b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
272b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
273a10cf76eSAxel Dörfler 
274a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
275a10cf76eSAxel Dörfler 
276b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
277b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
2786048f541SJohn Scipione 	BGroupView* outerControlsView = new BGroupView(B_VERTICAL);
2796048f541SJohn Scipione 	outerControlsView->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING,
2806048f541SJohn Scipione 		B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING);
281b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
282a10cf76eSAxel Dörfler 
283551c9f15SSiarzhuk Zharski 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
284a10cf76eSAxel Dörfler 
28566ab1666SAxel Dörfler 	uint16 maxWidth = 0;
28666ab1666SAxel Dörfler 	uint16 maxHeight = 0;
28766ab1666SAxel Dörfler 	uint16 previousWidth = 0;
28866ab1666SAxel Dörfler 	uint16 previousHeight = 0;
289a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
290a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
291a10cf76eSAxel Dörfler 
292a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
293a10cf76eSAxel Dörfler 			continue;
294a10cf76eSAxel Dörfler 
295a10cf76eSAxel Dörfler 		previousWidth = mode.width;
296a10cf76eSAxel Dörfler 		previousHeight = mode.height;
29766ab1666SAxel Dörfler 		if (maxWidth < mode.width)
29866ab1666SAxel Dörfler 			maxWidth = mode.width;
29966ab1666SAxel Dörfler 		if (maxHeight < mode.height)
30066ab1666SAxel Dörfler 			maxHeight = mode.height;
301a10cf76eSAxel Dörfler 
302a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
303a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
304a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
305a10cf76eSAxel Dörfler 
306a10cf76eSAxel Dörfler 		BString name;
307a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
308a10cf76eSAxel Dörfler 
309a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
310a10cf76eSAxel Dörfler 	}
311a10cf76eSAxel Dörfler 
31266ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
31366ab1666SAxel Dörfler 
314c9e8f97aSAdrien Destugues 	fResolutionField = new BMenuField("ResolutionMenu",
31510dfe897SAxel Dörfler 		B_TRANSLATE("Resolution:"), fResolutionMenu);
3166048f541SJohn Scipione 	fResolutionField->SetAlignment(B_ALIGN_RIGHT);
317a10cf76eSAxel Dörfler 
318551c9f15SSiarzhuk Zharski 	fColorsMenu = new BPopUpMenu("colors", true, false);
319a10cf76eSAxel Dörfler 
320a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
3211fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
3221fc4cb1fSAxel Dörfler 			continue;
3231fc4cb1fSAxel Dörfler 
324a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
325a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
326a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
327a10cf76eSAxel Dörfler 
3281fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
3291fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
3301fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
3311fc4cb1fSAxel Dörfler 
3321fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
333a10cf76eSAxel Dörfler 	}
334a10cf76eSAxel Dörfler 
335c9e8f97aSAdrien Destugues 	fColorsField = new BMenuField("ColorsMenu", B_TRANSLATE("Colors:"),
33610dfe897SAxel Dörfler 		fColorsMenu);
3376048f541SJohn Scipione 	fColorsField->SetAlignment(B_ALIGN_RIGHT);
338a10cf76eSAxel Dörfler 
339551c9f15SSiarzhuk Zharski 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
340a10cf76eSAxel Dörfler 
34129e8a73aSAxel Dörfler 	float min, max;
342ec495b30SRene Gollent 	if (fScreenMode.GetRefreshLimits(fActive, min, max) != B_OK) {
343ec495b30SRene Gollent 		// if we couldn't obtain the refresh limits, reset to the default
344ec495b30SRene Gollent 		// range. Constraints from detected monitors will fine-tune this
345ec495b30SRene Gollent 		// later.
346ec495b30SRene Gollent 		min = kRefreshRates[0];
347ec495b30SRene Gollent 		max = kRefreshRates[kRefreshRateCount - 1];
348ec495b30SRene Gollent 	}
349ec495b30SRene Gollent 
350ec495b30SRene Gollent 	if (min == max) {
35129e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
35229e8a73aSAxel Dörfler 		// frequency, like the VESA driver
35329e8a73aSAxel Dörfler 		BString name;
3547e44de36SRene Gollent 		refresh_rate_to_string(min, name);
355cf076964SRene Gollent 		BMessage *message = new BMessage(POP_REFRESH_MSG);
356cf076964SRene Gollent 		message->AddFloat("refresh", min);
357cf076964SRene Gollent 		BMenuItem *item = new BMenuItem(name.String(), message);
3580efb8b66SJerome Duval 		fRefreshMenu->AddItem(item);
35929e8a73aSAxel Dörfler 		item->SetEnabled(false);
36029e8a73aSAxel Dörfler 	} else {
36170a2b1b5SAxel Dörfler 		monitor_info info;
36270a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
36370a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
36470a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
36570a2b1b5SAxel Dörfler 		}
36670a2b1b5SAxel Dörfler 
367a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
36870a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
36970a2b1b5SAxel Dörfler 				continue;
37070a2b1b5SAxel Dörfler 
371a10cf76eSAxel Dörfler 			BString name;
372551c9f15SSiarzhuk Zharski 			name << kRefreshRates[i] << " " << B_TRANSLATE("Hz");
373a10cf76eSAxel Dörfler 
3740efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_REFRESH_MSG);
375a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
376a10cf76eSAxel Dörfler 
377a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
378a10cf76eSAxel Dörfler 		}
379a10cf76eSAxel Dörfler 
380c9e8f97aSAdrien Destugues 		fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS),
3810efb8b66SJerome Duval 			new BMessage(POP_OTHER_REFRESH_MSG));
382a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
38329e8a73aSAxel Dörfler 	}
384a10cf76eSAxel Dörfler 
385c9e8f97aSAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"),
38610dfe897SAxel Dörfler 		fRefreshMenu);
3876048f541SJohn Scipione 	fRefreshField->SetAlignment(B_ALIGN_RIGHT);
388b21d610eSAxel Dörfler 
38912580984SAxel Dörfler 	if (_IsVesa())
39012580984SAxel Dörfler 		fRefreshField->Hide();
391a10cf76eSAxel Dörfler 
392a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
393a10cf76eSAxel Dörfler 	{
394a10cf76eSAxel Dörfler 		bool dummy;
395a10cf76eSAxel Dörfler 		uint32 dummy32;
396a10cf76eSAxel Dörfler 		bool multiMonSupport;
397a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
398a10cf76eSAxel Dörfler 		bool tvStandardSupport;
399a10cf76eSAxel Dörfler 
400a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
401a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
402a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
403a10cf76eSAxel Dörfler 
404a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
405a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
406a10cf76eSAxel Dörfler 
407551c9f15SSiarzhuk Zharski 		fCombineMenu = new BPopUpMenu("CombineDisplays",
408c9e8f97aSAdrien Destugues 			true, true);
409a10cf76eSAxel Dörfler 
410a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
4110efb8b66SJerome Duval 			BMessage *message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
412a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
413a10cf76eSAxel Dörfler 
414d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
415d1516993SAxel Dörfler 				message));
416a10cf76eSAxel Dörfler 		}
417a10cf76eSAxel Dörfler 
418b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
41910dfe897SAxel Dörfler 			B_TRANSLATE("Combine displays:"), fCombineMenu);
4206048f541SJohn Scipione 		fCombineField->SetAlignment(B_ALIGN_RIGHT);
421a10cf76eSAxel Dörfler 
422a10cf76eSAxel Dörfler 		if (!multiMonSupport)
423df3f5bacSStephan Aßmus 			fCombineField->Hide();
424a10cf76eSAxel Dörfler 
425551c9f15SSiarzhuk Zharski 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays",
426c9e8f97aSAdrien Destugues 			true, true);
427a10cf76eSAxel Dörfler 
428a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
4290efb8b66SJerome Duval 		BMessage *message = new BMessage(POP_SWAP_DISPLAYS_MSG);
430a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
431c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message));
432a10cf76eSAxel Dörfler 
433a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
434a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
435c9e8f97aSAdrien Destugues 		fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message));
436a10cf76eSAxel Dörfler 
437c9e8f97aSAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu",
43810dfe897SAxel Dörfler 			B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu);
4396048f541SJohn Scipione 		fSwapDisplaysField->SetAlignment(B_ALIGN_RIGHT);
440a10cf76eSAxel Dörfler 
441a10cf76eSAxel Dörfler 		if (!multiMonSupport)
442df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
443a10cf76eSAxel Dörfler 
444551c9f15SSiarzhuk Zharski 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel",
445c9e8f97aSAdrien Destugues 			true, true);
446a10cf76eSAxel Dörfler 
447a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
448a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
449a10cf76eSAxel Dörfler 		message->AddBool("use", false);
450c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"),
451c9e8f97aSAdrien Destugues 			message));
452a10cf76eSAxel Dörfler 
453a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
454a10cf76eSAxel Dörfler 		message->AddBool("use", true);
455c9e8f97aSAdrien Destugues 		fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"),
456c9e8f97aSAdrien Destugues 			message));
457a10cf76eSAxel Dörfler 
458b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
45910dfe897SAxel Dörfler 			B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu);
4606048f541SJohn Scipione 		fUseLaptopPanelField->SetAlignment(B_ALIGN_RIGHT);
461a10cf76eSAxel Dörfler 
462a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
463df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
464a10cf76eSAxel Dörfler 
465551c9f15SSiarzhuk Zharski 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
466a10cf76eSAxel Dörfler 
467a10cf76eSAxel Dörfler 		// arbitrary limit
468a10cf76eSAxel Dörfler 		uint32 i;
469a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
470a10cf76eSAxel Dörfler 			uint32 mode;
471a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
472a10cf76eSAxel Dörfler 				break;
473a10cf76eSAxel Dörfler 
474a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
475a10cf76eSAxel Dörfler 
476a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
477a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
478a10cf76eSAxel Dörfler 
479a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
480a10cf76eSAxel Dörfler 		}
481a10cf76eSAxel Dörfler 
482c9e8f97aSAdrien Destugues 		fTVStandardField = new BMenuField("tv standard",
48310dfe897SAxel Dörfler 			B_TRANSLATE("Video format:"), fTVStandardMenu);
484df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
485a10cf76eSAxel Dörfler 
486b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
487df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
488a10cf76eSAxel Dörfler 	}
489a10cf76eSAxel Dörfler 
49025fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
4916048f541SJohn Scipione 		.AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
4926048f541SJohn Scipione 			.Add(fResolutionField->CreateLabelLayoutItem(), 0, 0)
4936048f541SJohn Scipione 			.Add(fResolutionField->CreateMenuBarLayoutItem(), 1, 0)
4946048f541SJohn Scipione 			.Add(fColorsField->CreateLabelLayoutItem(), 0, 1)
4956048f541SJohn Scipione 			.Add(fColorsField->CreateMenuBarLayoutItem(), 1, 1)
4966048f541SJohn Scipione 			.Add(fRefreshField->CreateLabelLayoutItem(), 0, 2)
4976048f541SJohn Scipione 			.Add(fRefreshField->CreateMenuBarLayoutItem(), 1, 2)
4986048f541SJohn Scipione 			.Add(fCombineField->CreateLabelLayoutItem(), 0, 3)
4996048f541SJohn Scipione 			.Add(fCombineField->CreateMenuBarLayoutItem(), 1, 3)
5006048f541SJohn Scipione 			.Add(fSwapDisplaysField->CreateLabelLayoutItem(), 0, 4)
5016048f541SJohn Scipione 			.Add(fSwapDisplaysField->CreateMenuBarLayoutItem(), 1, 4)
5026048f541SJohn Scipione 			.Add(fUseLaptopPanelField->CreateLabelLayoutItem(), 0, 5)
5036048f541SJohn Scipione 			.Add(fUseLaptopPanelField->CreateMenuBarLayoutItem(), 1, 5)
5046048f541SJohn Scipione 			.Add(fTVStandardField->CreateLabelLayoutItem(), 0, 6)
5056048f541SJohn Scipione 			.Add(fTVStandardField->CreateMenuBarLayoutItem(), 1, 6)
50625fd5c7bSAlex Wilson 		.End();
507df3f5bacSStephan Aßmus 
508abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
509abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
510b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
511a10cf76eSAxel Dörfler 
512c9e8f97aSAdrien Destugues 	fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"),
513df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
514df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
51525fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
516b21d610eSAxel Dörfler 		.AddGlue()
51725fd5c7bSAlex Wilson 		.AddGroup(B_HORIZONTAL)
51825fd5c7bSAlex Wilson 			.AddGlue()
51925fd5c7bSAlex Wilson 			.Add(fApplyButton);
520b21d610eSAxel Dörfler 
521c9e8f97aSAdrien Destugues 	fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"),
522b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
523b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
524b21d610eSAxel Dörfler 
5254666484fSJohn Scipione 	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
5264666484fSJohn Scipione 		.AddGroup(B_HORIZONTAL)
527a2cb1737SAdrien Destugues 			.AddGroup(B_VERTICAL, 0, 1)
52883cc66b3SJohn Scipione 				.AddStrut(floorf(controlsBox->TopBorderOffset()) - 1)
529b21d610eSAxel Dörfler 				.Add(screenBox)
53083cc66b3SJohn Scipione 				.End()
531a2cb1737SAdrien Destugues 			.Add(controlsBox, 2)
532b21d610eSAxel Dörfler 			.End()
5334666484fSJohn Scipione 		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
534b21d610eSAxel Dörfler 			.Add(fRevertButton)
5354666484fSJohn Scipione 			.AddGlue()
5364666484fSJohn Scipione 			.End()
5374666484fSJohn Scipione 		.SetInsets(B_USE_DEFAULT_SPACING);
538b21d610eSAxel Dörfler 
5395de171daSAxel Dörfler 	_UpdateControls();
54012966d04SAxel Dörfler 	_UpdateMonitor();
541a10cf76eSAxel Dörfler }
542a10cf76eSAxel Dörfler 
543a10cf76eSAxel Dörfler 
544a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
545a10cf76eSAxel Dörfler {
546a10cf76eSAxel Dörfler 	delete fSettings;
547a10cf76eSAxel Dörfler }
548a10cf76eSAxel Dörfler 
549a10cf76eSAxel Dörfler 
550a10cf76eSAxel Dörfler bool
551a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
552a10cf76eSAxel Dörfler {
553a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
554199893c3SAxel Dörfler 
555199893c3SAxel Dörfler 	// Write mode of workspace 0 (the boot workspace) to the vesa settings file
556199893c3SAxel Dörfler 	screen_mode vesaMode;
557199893c3SAxel Dörfler 	if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) {
558199893c3SAxel Dörfler 		status_t status = _WriteVesaModeFile(vesaMode);
55912580984SAxel Dörfler 		if (status < B_OK) {
560c9e8f97aSAdrien Destugues 			BString warning = B_TRANSLATE("Could not write VESA mode settings"
561c9e8f97aSAdrien Destugues 				" file:\n\t");
56212580984SAxel Dörfler 			warning << strerror(status);
563aed35104SHumdinger 			BAlert* alert = new BAlert(B_TRANSLATE("Warning"),
564aed35104SHumdinger 				warning.String(), B_TRANSLATE("OK"), NULL,
565aed35104SHumdinger 				NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
566aed35104SHumdinger 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
567aed35104SHumdinger 			alert->Go();
56812580984SAxel Dörfler 		}
56912580984SAxel Dörfler 	}
57012580984SAxel Dörfler 
571a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
572a10cf76eSAxel Dörfler 
573a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
574a10cf76eSAxel Dörfler }
575a10cf76eSAxel Dörfler 
576a10cf76eSAxel Dörfler 
5775de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5781fc4cb1fSAxel Dörfler 	(some resolutions may not be combinable due to memory restrictions).
579a10cf76eSAxel Dörfler */
580a10cf76eSAxel Dörfler void
5815de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
582a10cf76eSAxel Dörfler {
583a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
584a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
585a10cf76eSAxel Dörfler 
586a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
587a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
588a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
589a10cf76eSAxel Dörfler 			continue;
590a10cf76eSAxel Dörfler 
591a10cf76eSAxel Dörfler 		BString name;
592a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
593a10cf76eSAxel Dörfler 
594a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
595a10cf76eSAxel Dörfler 		if (item != NULL)
596a10cf76eSAxel Dörfler 			item->SetEnabled(true);
597a10cf76eSAxel Dörfler 	}
598a10cf76eSAxel Dörfler }
599a10cf76eSAxel Dörfler 
600a10cf76eSAxel Dörfler 
6015de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
6025de171daSAxel Dörfler 	(a color space is made active if there is any mode with
6035de171daSAxel Dörfler 	given resolution and this colour space; same applies for
6045de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
605a10cf76eSAxel Dörfler */
606a10cf76eSAxel Dörfler void
6075de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
608a10cf76eSAxel Dörfler {
6091fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
6101fc4cb1fSAxel Dörfler 	int32 index = 0;
6111fc4cb1fSAxel Dörfler 
612a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
6131fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
6141fc4cb1fSAxel Dörfler 			continue;
6151fc4cb1fSAxel Dörfler 
616a10cf76eSAxel Dörfler 		bool supported = false;
617a10cf76eSAxel Dörfler 
618a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
619a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
620a10cf76eSAxel Dörfler 
621a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
622a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
6231fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
624a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
6251fc4cb1fSAxel Dörfler 				supportsAnything = true;
626a10cf76eSAxel Dörfler 				supported = true;
627a10cf76eSAxel Dörfler 				break;
628a10cf76eSAxel Dörfler 			}
629a10cf76eSAxel Dörfler 		}
630a10cf76eSAxel Dörfler 
6311fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
632a10cf76eSAxel Dörfler 		if (item)
633a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
634a10cf76eSAxel Dörfler 	}
6351fc4cb1fSAxel Dörfler 
6361fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
6371fc4cb1fSAxel Dörfler 
6381fc4cb1fSAxel Dörfler 	if (!supportsAnything)
6391fc4cb1fSAxel Dörfler 		return;
6401fc4cb1fSAxel Dörfler 
6411fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
6421fc4cb1fSAxel Dörfler 
6431fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
6441fc4cb1fSAxel Dörfler 	bool changed = false;
6451fc4cb1fSAxel Dörfler 
6461fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
6471fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
6481fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
6491fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
6501fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
6511fc4cb1fSAxel Dörfler 			changed = true;
6521fc4cb1fSAxel Dörfler 		}
6531fc4cb1fSAxel Dörfler 	}
6541fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
6551fc4cb1fSAxel Dörfler 		// find the next best item
6561fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
6571fc4cb1fSAxel Dörfler 		bool found = false;
6581fc4cb1fSAxel Dörfler 
6591fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
6601fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
6611fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
6621fc4cb1fSAxel Dörfler 				found = true;
6631fc4cb1fSAxel Dörfler 				break;
6641fc4cb1fSAxel Dörfler 			}
6651fc4cb1fSAxel Dörfler 		}
6661fc4cb1fSAxel Dörfler 		if (!found) {
6671fc4cb1fSAxel Dörfler 			// search backwards as well
6681fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6691fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6701fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6711fc4cb1fSAxel Dörfler 					break;
6721fc4cb1fSAxel Dörfler 			}
6731fc4cb1fSAxel Dörfler 		}
6741fc4cb1fSAxel Dörfler 
6751fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6761fc4cb1fSAxel Dörfler 		changed = true;
6771fc4cb1fSAxel Dörfler 	}
6781fc4cb1fSAxel Dörfler 
6791fc4cb1fSAxel Dörfler 	if (changed) {
6801fc4cb1fSAxel Dörfler 		// Update selected space
6811fc4cb1fSAxel Dörfler 
6821fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6831fc4cb1fSAxel Dörfler 		int32 space;
6841fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6851fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6861fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6871fc4cb1fSAxel Dörfler 		}
6881fc4cb1fSAxel Dörfler 	}
689a10cf76eSAxel Dörfler }
690a10cf76eSAxel Dörfler 
691a10cf76eSAxel Dörfler 
6925de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
693a10cf76eSAxel Dörfler void
6945de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
695a10cf76eSAxel Dörfler {
69629e8a73aSAxel Dörfler 	float min, max;
69729e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
69829e8a73aSAxel Dörfler 		return;
699a10cf76eSAxel Dörfler 
70029e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
70129e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
70229e8a73aSAxel Dörfler 		BMessage* message = item->Message();
70329e8a73aSAxel Dörfler 		float refresh;
70429e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
70529e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
706a10cf76eSAxel Dörfler 	}
707a10cf76eSAxel Dörfler }
708a10cf76eSAxel Dörfler 
709a10cf76eSAxel Dörfler 
7105de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
711a10cf76eSAxel Dörfler void
7125de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
713a10cf76eSAxel Dörfler {
7147e44de36SRene Gollent 	for (int32 i = 0; i < fRefreshMenu->CountItems(); i++) {
7157e44de36SRene Gollent 		BMenuItem* item = fRefreshMenu->ItemAt(i);
7167e44de36SRene Gollent 		if (item->Message()->FindFloat("refresh") == fSelected.refresh) {
717a10cf76eSAxel Dörfler 			item->SetMarked(true);
71826747978SAdrien Destugues 			// "Other" items only contains a refresh rate when active
71926747978SAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
720a10cf76eSAxel Dörfler 			return;
721a10cf76eSAxel Dörfler 		}
7227e44de36SRene Gollent 	}
723a10cf76eSAxel Dörfler 
724a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
7257e44de36SRene Gollent 	if (fOtherRefresh != NULL) {
726a10cf76eSAxel Dörfler 		fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
727a10cf76eSAxel Dörfler 		fOtherRefresh->SetMarked(true);
728a10cf76eSAxel Dörfler 
7297e44de36SRene Gollent 		BString string;
7307e44de36SRene Gollent 		refresh_rate_to_string(fSelected.refresh, string);
731a10cf76eSAxel Dörfler 		fRefreshMenu->Superitem()->SetLabel(string.String());
732a10cf76eSAxel Dörfler 
733c9e8f97aSAdrien Destugues 		string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS));
734a10cf76eSAxel Dörfler 		fOtherRefresh->SetLabel(string.String());
735a10cf76eSAxel Dörfler 	}
7367e44de36SRene Gollent }
737a10cf76eSAxel Dörfler 
738a10cf76eSAxel Dörfler 
739a10cf76eSAxel Dörfler void
7405de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
741a10cf76eSAxel Dörfler {
742a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
743a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
744a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
745a10cf76eSAxel Dörfler 
746a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
747a10cf76eSAxel Dörfler }
748a10cf76eSAxel Dörfler 
749a10cf76eSAxel Dörfler 
750a10cf76eSAxel Dörfler void
7515de171daSAxel Dörfler ScreenWindow::_UpdateControls()
752a10cf76eSAxel Dörfler {
753b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
754b21d610eSAxel Dörfler 
755a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
756c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
757a10cf76eSAxel Dörfler 		item->SetMarked(true);
758a10cf76eSAxel Dörfler 
759a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
760c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
761a10cf76eSAxel Dörfler 		item->SetMarked(true);
762a10cf76eSAxel Dörfler 
763a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
764a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
765a10cf76eSAxel Dörfler 
766a10cf76eSAxel Dörfler 		uint32 tvStandard;
767a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
768a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
769a10cf76eSAxel Dörfler 			if (!item->IsMarked())
770a10cf76eSAxel Dörfler 				item->SetMarked(true);
771a10cf76eSAxel Dörfler 			break;
772a10cf76eSAxel Dörfler 		}
773a10cf76eSAxel Dörfler 	}
774a10cf76eSAxel Dörfler 
7755de171daSAxel Dörfler 	_CheckResolutionMenu();
7765de171daSAxel Dörfler 	_CheckColorMenu();
7775de171daSAxel Dörfler 	_CheckRefreshMenu();
778a10cf76eSAxel Dörfler 
779a10cf76eSAxel Dörfler 	BString string;
780a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
781a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
782a10cf76eSAxel Dörfler 
783a10cf76eSAxel Dörfler 	if (item != NULL) {
784a10cf76eSAxel Dörfler 		if (!item->IsMarked())
785a10cf76eSAxel Dörfler 			item->SetMarked(true);
786a10cf76eSAxel Dörfler 	} else {
787a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
788a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
789a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
790a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
791a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
792a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
793a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
794a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
795a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
796a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
797a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
798a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
799a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
800a10cf76eSAxel Dörfler 		if (item)
801a10cf76eSAxel Dörfler 			item->SetMarked(true);
802a10cf76eSAxel Dörfler 
803a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
804a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
805a10cf76eSAxel Dörfler 	}
806a10cf76eSAxel Dörfler 
807a10cf76eSAxel Dörfler 	// mark active combine mode
808a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
809a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
810a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
811c33a865cSJohn Scipione 			if (item != NULL && !item->IsMarked())
812a10cf76eSAxel Dörfler 				item->SetMarked(true);
813a10cf76eSAxel Dörfler 			break;
814a10cf76eSAxel Dörfler 		}
815a10cf76eSAxel Dörfler 	}
816a10cf76eSAxel Dörfler 
817a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
818a10cf76eSAxel Dörfler 
8191fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
8201fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
8211fc4cb1fSAxel Dörfler 			continue;
8221fc4cb1fSAxel Dörfler 
8231fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
8241fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
825a10cf76eSAxel Dörfler 			break;
826a10cf76eSAxel Dörfler 		}
8271fc4cb1fSAxel Dörfler 
8281fc4cb1fSAxel Dörfler 		index++;
829a10cf76eSAxel Dörfler 	}
830a10cf76eSAxel Dörfler 
831c33a865cSJohn Scipione 	if (item != NULL && !item->IsMarked())
832a10cf76eSAxel Dörfler 		item->SetMarked(true);
833a10cf76eSAxel Dörfler 
8341fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
8355de171daSAxel Dörfler 	_UpdateMonitorView();
8365de171daSAxel Dörfler 	_UpdateRefreshControl();
837a10cf76eSAxel Dörfler 
8385de171daSAxel Dörfler 	_CheckApplyEnabled();
839a10cf76eSAxel Dörfler }
840a10cf76eSAxel Dörfler 
841a10cf76eSAxel Dörfler 
84212580984SAxel Dörfler /*! Reflect active mode in chosen settings */
843a10cf76eSAxel Dörfler void
8445de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
845a10cf76eSAxel Dörfler {
846c491b5adSJohn Scipione 	_UpdateActiveMode(current_workspace());
847c491b5adSJohn Scipione }
848c491b5adSJohn Scipione 
849c491b5adSJohn Scipione 
850c491b5adSJohn Scipione void
851c491b5adSJohn Scipione ScreenWindow::_UpdateActiveMode(int32 workspace)
852c491b5adSJohn Scipione {
85312580984SAxel Dörfler 	// Usually, this function gets called after a mode
854a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
855a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
856a10cf76eSAxel Dörfler 	// what kind of mode we actually got
857c491b5adSJohn Scipione 	if (fScreenMode.Get(fActive, workspace) == B_OK) {
858a10cf76eSAxel Dörfler 		fSelected = fActive;
859a10cf76eSAxel Dörfler 
86012966d04SAxel Dörfler 		_UpdateMonitor();
861c491b5adSJohn Scipione 		_BuildSupportedColorSpaces();
8625de171daSAxel Dörfler 		_UpdateControls();
863a10cf76eSAxel Dörfler 	}
864c491b5adSJohn Scipione }
865a10cf76eSAxel Dörfler 
866a10cf76eSAxel Dörfler 
867a10cf76eSAxel Dörfler void
868b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
869b21d610eSAxel Dörfler {
870b21d610eSAxel Dörfler 	uint32 columns;
871b21d610eSAxel Dörfler 	uint32 rows;
872b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
873b21d610eSAxel Dörfler 
874a3fa81bdSJohn Scipione 	// Set the max values enabling/disabling the up/down arrows
875b21d610eSAxel Dörfler 
876a3fa81bdSJohn Scipione 	if (rows == 1)
877a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(32);
878a3fa81bdSJohn Scipione 	else if (rows == 2)
879a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(16);
880a3fa81bdSJohn Scipione 	else if (rows <= 4)
881a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(8);
882a3fa81bdSJohn Scipione 	else if (rows <= 8)
883a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(4);
884a3fa81bdSJohn Scipione 	else if (rows <= 16)
885a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(2);
886a3fa81bdSJohn Scipione 	else if (rows <= 32)
887a3fa81bdSJohn Scipione 		fColumnsControl->SetMaxValue(1);
888b21d610eSAxel Dörfler 
889a3fa81bdSJohn Scipione 	if (columns == 1)
890a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(32);
891a3fa81bdSJohn Scipione 	else if (columns == 2)
892a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(16);
893a3fa81bdSJohn Scipione 	else if (columns <= 4)
894a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(8);
895a3fa81bdSJohn Scipione 	else if (columns <= 8)
896a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(4);
897a3fa81bdSJohn Scipione 	else if (columns <= 16)
898a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(2);
899a3fa81bdSJohn Scipione 	else if (columns <= 32)
900a3fa81bdSJohn Scipione 		fRowsControl->SetMaxValue(1);
901b21d610eSAxel Dörfler }
902b21d610eSAxel Dörfler 
903b21d610eSAxel Dörfler 
904b21d610eSAxel Dörfler void
905a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
906a10cf76eSAxel Dörfler {
907a10cf76eSAxel Dörfler 	// move window on screen, if necessary
908a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
909a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
910a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
911a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
912a10cf76eSAxel Dörfler 	}
913a10cf76eSAxel Dörfler }
914a10cf76eSAxel Dörfler 
915a10cf76eSAxel Dörfler 
916a10cf76eSAxel Dörfler void
917a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
918a10cf76eSAxel Dörfler {
919c491b5adSJohn Scipione 	if (fScreenMode.GetOriginalMode(fOriginal, workspace) == B_OK) {
920c491b5adSJohn Scipione 		_UpdateActiveMode(workspace);
921a10cf76eSAxel Dörfler 
9226edaa0f6SStefano Ceccherini 		BMessage message(UPDATE_DESKTOP_COLOR_MSG);
9236edaa0f6SStefano Ceccherini 		PostMessage(&message, fMonitorView);
924a10cf76eSAxel Dörfler 	}
925c491b5adSJohn Scipione }
926a10cf76eSAxel Dörfler 
927a10cf76eSAxel Dörfler 
928a10cf76eSAxel Dörfler void
929a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
930a10cf76eSAxel Dörfler {
931a10cf76eSAxel Dörfler 	switch (message->what) {
932a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
9335de171daSAxel Dörfler 			_CheckApplyEnabled();
934a10cf76eSAxel Dörfler 			break;
935a10cf76eSAxel Dörfler 
936b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
937b21d610eSAxel Dörfler 		{
938a3fa81bdSJohn Scipione 			uint32 newColumns = (uint32)fColumnsControl->Value();
939b21d610eSAxel Dörfler 
940b21d610eSAxel Dörfler 			uint32 rows;
941b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
942b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
943b21d610eSAxel Dörfler 
944b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
945a3fa81bdSJohn Scipione 			fRowsControl->SetValue(rows);
946a3fa81bdSJohn Scipione 				// enables/disables up/down arrows
947b21d610eSAxel Dörfler 			_CheckApplyEnabled();
948a3fa81bdSJohn Scipione 
949b21d610eSAxel Dörfler 			break;
950b21d610eSAxel Dörfler 		}
951b21d610eSAxel Dörfler 
952b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
953b21d610eSAxel Dörfler 		{
954a3fa81bdSJohn Scipione 			uint32 newRows = (uint32)fRowsControl->Value();
955b21d610eSAxel Dörfler 
956b21d610eSAxel Dörfler 			uint32 columns;
957b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
958b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
959b21d610eSAxel Dörfler 
960b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
961a3fa81bdSJohn Scipione 			fColumnsControl->SetValue(columns);
962a3fa81bdSJohn Scipione 				// enables/disables up/down arrows
963b21d610eSAxel Dörfler 			_CheckApplyEnabled();
964a10cf76eSAxel Dörfler 			break;
965a10cf76eSAxel Dörfler 		}
966a10cf76eSAxel Dörfler 
967a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
968a10cf76eSAxel Dörfler 		{
969a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
970a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
971a10cf76eSAxel Dörfler 
9725de171daSAxel Dörfler 			_CheckColorMenu();
9735de171daSAxel Dörfler 			_CheckRefreshMenu();
974a10cf76eSAxel Dörfler 
9755de171daSAxel Dörfler 			_UpdateMonitorView();
9765de171daSAxel Dörfler 			_UpdateRefreshControl();
977a10cf76eSAxel Dörfler 
9785de171daSAxel Dörfler 			_CheckApplyEnabled();
979a10cf76eSAxel Dörfler 			break;
980a10cf76eSAxel Dörfler 		}
981a10cf76eSAxel Dörfler 
982a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
983a10cf76eSAxel Dörfler 		{
9841fc4cb1fSAxel Dörfler 			int32 space;
9851fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9861fc4cb1fSAxel Dörfler 				break;
987a10cf76eSAxel Dörfler 
9881fc4cb1fSAxel Dörfler 			int32 index;
9891fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9901fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9911fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9921fc4cb1fSAxel Dörfler 
9931fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9941fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
995a10cf76eSAxel Dörfler 
9965de171daSAxel Dörfler 			_CheckApplyEnabled();
997a10cf76eSAxel Dörfler 			break;
998a10cf76eSAxel Dörfler 		}
999a10cf76eSAxel Dörfler 
1000a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
1001a40498e2SWaldemar Kornewald 		{
1002a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
1003c9e8f97aSAdrien Destugues 			fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS));
10041fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
1005a10cf76eSAxel Dörfler 
10065de171daSAxel Dörfler 			_CheckApplyEnabled();
1007a10cf76eSAxel Dörfler 			break;
1008a40498e2SWaldemar Kornewald 		}
1009a10cf76eSAxel Dörfler 
1010a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
1011a10cf76eSAxel Dörfler 		{
101229e8a73aSAxel Dörfler 			// make sure menu shows something useful
10135de171daSAxel Dörfler 			_UpdateRefreshControl();
1014a10cf76eSAxel Dörfler 
101529e8a73aSAxel Dörfler 			float min = 0, max = 999;
101629e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
101729e8a73aSAxel Dörfler 			if (min < gMinRefresh)
101829e8a73aSAxel Dörfler 				min = gMinRefresh;
101929e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
102029e8a73aSAxel Dörfler 				max = gMaxRefresh;
102129e8a73aSAxel Dörfler 
102270a2b1b5SAxel Dörfler 			monitor_info info;
102370a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
102470a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
102570a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
102670a2b1b5SAxel Dörfler 			}
102770a2b1b5SAxel Dörfler 
1028c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
102970a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
103070a2b1b5SAxel Dörfler 				min, max);
1031a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
1032a10cf76eSAxel Dörfler 			break;
1033a10cf76eSAxel Dörfler 		}
1034a10cf76eSAxel Dörfler 
1035a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
1036a10cf76eSAxel Dörfler 		{
1037a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
1038a10cf76eSAxel Dörfler 			// select the refresh rate chosen
1039a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
1040a10cf76eSAxel Dörfler 
10415de171daSAxel Dörfler 			_UpdateRefreshControl();
10425de171daSAxel Dörfler 			_CheckApplyEnabled();
1043a10cf76eSAxel Dörfler 			break;
1044a10cf76eSAxel Dörfler 		}
1045a10cf76eSAxel Dörfler 
1046a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
1047a10cf76eSAxel Dörfler 		{
1048a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
1049a10cf76eSAxel Dörfler 			int32 mode;
1050a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
1051a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
1052a10cf76eSAxel Dörfler 
10535de171daSAxel Dörfler 			_CheckResolutionMenu();
10545de171daSAxel Dörfler 			_CheckApplyEnabled();
1055a10cf76eSAxel Dörfler 			break;
1056a10cf76eSAxel Dörfler 		}
1057a10cf76eSAxel Dörfler 
1058a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
1059a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
10605de171daSAxel Dörfler 			_CheckApplyEnabled();
1061a10cf76eSAxel Dörfler 			break;
1062a10cf76eSAxel Dörfler 
1063a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
1064a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
10655de171daSAxel Dörfler 			_CheckApplyEnabled();
1066a10cf76eSAxel Dörfler 			break;
1067a10cf76eSAxel Dörfler 
1068a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
1069a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
10705de171daSAxel Dörfler 			_CheckApplyEnabled();
1071a10cf76eSAxel Dörfler 			break;
1072a10cf76eSAxel Dörfler 
1073df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10746f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10756f095d6aSRyan Leavengood 				app_info info;
10766f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10776f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10786f095d6aSRyan Leavengood 			}
1079df3f5bacSStephan Aßmus 			break;
1080df3f5bacSStephan Aßmus 
1081a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1082a10cf76eSAxel Dörfler 		{
10834be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1084a10cf76eSAxel Dörfler 			fSelected.width = 640;
1085a10cf76eSAxel Dörfler 			fSelected.height = 480;
1086a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1087a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1088a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1089a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1090a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1091a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1092a10cf76eSAxel Dörfler 
1093b21d610eSAxel Dörfler 			// TODO: workspace defaults
1094abc649b8SWaldemar Kornewald 
10955de171daSAxel Dörfler 			_UpdateControls();
1096a10cf76eSAxel Dörfler 			break;
1097a10cf76eSAxel Dörfler 		}
1098a10cf76eSAxel Dörfler 
109910e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
110061c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
11015de171daSAxel Dörfler 			_UpdateActiveMode();
1102abc649b8SWaldemar Kornewald 			break;
1103abc649b8SWaldemar Kornewald 
1104abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1105abc649b8SWaldemar Kornewald 		{
1106abc649b8SWaldemar Kornewald 			fModified = false;
1107199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1108abc649b8SWaldemar Kornewald 
1109b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1110b21d610eSAxel Dörfler 			// number of workspaces
1111b21d610eSAxel Dörfler 
1112b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1113b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1114b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1115b21d610eSAxel Dörfler 
1116a10cf76eSAxel Dörfler 			fScreenMode.Revert();
11175de171daSAxel Dörfler 			_UpdateActiveMode();
1118a10cf76eSAxel Dörfler 			break;
1119abc649b8SWaldemar Kornewald 		}
1120a10cf76eSAxel Dörfler 
1121a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
11225de171daSAxel Dörfler 			_Apply();
1123a10cf76eSAxel Dörfler 			break;
1124a10cf76eSAxel Dörfler 
1125abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1126abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1127abc649b8SWaldemar Kornewald 			fModified = true;
11285de171daSAxel Dörfler 			_UpdateActiveMode();
1129a10cf76eSAxel Dörfler 			break;
1130a10cf76eSAxel Dörfler 
1131a10cf76eSAxel Dörfler 		default:
1132a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1133a10cf76eSAxel Dörfler 	}
1134a10cf76eSAxel Dörfler }
1135a10cf76eSAxel Dörfler 
1136a10cf76eSAxel Dörfler 
113712580984SAxel Dörfler status_t
113812580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
113912580984SAxel Dörfler {
114012580984SAxel Dörfler 	BPath path;
114112580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
114212580984SAxel Dörfler 	if (status < B_OK)
114312580984SAxel Dörfler 		return status;
114412580984SAxel Dörfler 
114512580984SAxel Dörfler 	path.Append("kernel/drivers");
114612580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
114712580984SAxel Dörfler 	if (status < B_OK)
114812580984SAxel Dörfler 		return status;
114912580984SAxel Dörfler 
115012580984SAxel Dörfler 	path.Append("vesa");
115112580984SAxel Dörfler 	BFile file;
115212580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
115312580984SAxel Dörfler 	if (status < B_OK)
115412580984SAxel Dörfler 		return status;
115512580984SAxel Dörfler 
115612580984SAxel Dörfler 	char buffer[256];
11575084d0d4SAlex Smith 	snprintf(buffer, sizeof(buffer), "mode %" B_PRId32 " %" B_PRId32 " %"
11585084d0d4SAlex Smith 		B_PRId32 "\n", mode.width, mode.height, mode.BitsPerPixel());
115912580984SAxel Dörfler 
116012580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
116112580984SAxel Dörfler 	if (bytesWritten < B_OK)
116212580984SAxel Dörfler 		return bytesWritten;
116312580984SAxel Dörfler 
116412580984SAxel Dörfler 	return B_OK;
116512580984SAxel Dörfler }
116612580984SAxel Dörfler 
116712580984SAxel Dörfler 
1168a10cf76eSAxel Dörfler void
11691fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11701fc4cb1fSAxel Dörfler {
11711fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11721fc4cb1fSAxel Dörfler 
11731fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11741fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11751fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11761fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11771fc4cb1fSAxel Dörfler 				break;
11781fc4cb1fSAxel Dörfler 			}
11791fc4cb1fSAxel Dörfler 		}
11801fc4cb1fSAxel Dörfler 	}
11811fc4cb1fSAxel Dörfler }
11821fc4cb1fSAxel Dörfler 
11831fc4cb1fSAxel Dörfler 
11841fc4cb1fSAxel Dörfler void
11855de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1186a10cf76eSAxel Dörfler {
118795ef5044SJanus 	bool applyEnabled = true;
118895ef5044SJanus 
118995ef5044SJanus 	if (fSelected == fActive) {
119095ef5044SJanus 		applyEnabled = false;
119195ef5044SJanus 		if (fAllWorkspacesItem->IsMarked()) {
119295ef5044SJanus 			screen_mode screenMode;
119395ef5044SJanus 			const int32 workspaceCount = count_workspaces();
119495ef5044SJanus 			for (int32 i = 0; i < workspaceCount; i++) {
119595ef5044SJanus 				fScreenMode.Get(screenMode, i);
119695ef5044SJanus 				if (screenMode != fSelected) {
119795ef5044SJanus 					applyEnabled = true;
119895ef5044SJanus 					break;
119995ef5044SJanus 				}
120095ef5044SJanus 			}
120195ef5044SJanus 		}
120295ef5044SJanus 	}
120395ef5044SJanus 
120495ef5044SJanus 	fApplyButton->SetEnabled(applyEnabled);
1205b21d610eSAxel Dörfler 
1206b21d610eSAxel Dörfler 	uint32 columns;
1207b21d610eSAxel Dörfler 	uint32 rows;
1208b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1209b21d610eSAxel Dörfler 
1210b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1211b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
12125de171daSAxel Dörfler 		|| fSelected != fOriginal);
1213a10cf76eSAxel Dörfler }
1214a10cf76eSAxel Dörfler 
1215a10cf76eSAxel Dörfler 
1216a10cf76eSAxel Dörfler void
12175de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1218abc649b8SWaldemar Kornewald {
1219b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1220b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1221b21d610eSAxel Dörfler 
1222abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1223abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1224abc649b8SWaldemar Kornewald }
1225abc649b8SWaldemar Kornewald 
1226abc649b8SWaldemar Kornewald 
1227abc649b8SWaldemar Kornewald void
122812966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
122912966d04SAxel Dörfler {
123012966d04SAxel Dörfler 	monitor_info info;
123112966d04SAxel Dörfler 	float diagonalInches;
123212966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
123355030977SAxel Dörfler 	if (status == B_OK) {
12341a8af605SAxel Dörfler 		char text[512];
123566ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
123666ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
123712966d04SAxel Dörfler 
123812966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
123912966d04SAxel Dörfler 
124012966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
124112966d04SAxel Dörfler 			fMonitorInfo->Show();
124255030977SAxel Dörfler 	} else {
124355030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
124455030977SAxel Dörfler 			fMonitorInfo->Hide();
124555030977SAxel Dörfler 	}
1246af8f9c31SAxel Dörfler 
12478b46ee25SAdrien Destugues 	// Add info about the graphics device
12488b46ee25SAdrien Destugues 
12498b46ee25SAdrien Destugues 	accelerant_device_info deviceInfo;
12508b46ee25SAdrien Destugues 
12518b46ee25SAdrien Destugues 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK) {
12528b46ee25SAdrien Destugues 		BString deviceString;
12538b46ee25SAdrien Destugues 
12548b46ee25SAdrien Destugues 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
12558b46ee25SAdrien Destugues 			deviceString.SetToFormat("%s (%s)", deviceInfo.name,
12568b46ee25SAdrien Destugues 				deviceInfo.chipset);
12578b46ee25SAdrien Destugues 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
12588b46ee25SAdrien Destugues 			deviceString
12598b46ee25SAdrien Destugues 				= deviceInfo.name[0] ? deviceInfo.name : deviceInfo.chipset;
12608b46ee25SAdrien Destugues 		}
12618b46ee25SAdrien Destugues 
12628b46ee25SAdrien Destugues 		fDeviceInfo->SetText(deviceString);
12638b46ee25SAdrien Destugues 	}
12648b46ee25SAdrien Destugues 
12658b46ee25SAdrien Destugues 
126655030977SAxel Dörfler 	char text[512];
12671a8af605SAxel Dörfler 	size_t length = 0;
12681a8af605SAxel Dörfler 	text[0] = 0;
12691a8af605SAxel Dörfler 
127055030977SAxel Dörfler 	if (status == B_OK) {
1271af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1272af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1273af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
12741a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
1275c9e8f97aSAdrien Destugues 				B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n"
12769c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
1277c9e8f97aSAdrien Destugues 				"Maximum pixel clock:\t%g MHz"),
12781a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12791a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12801a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1281af8f9c31SAxel Dörfler 		}
12821a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12831a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
1284c9e8f97aSAdrien Destugues 				B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "",
12851a8af605SAxel Dörfler 				info.serial_number);
12861a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12871a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12881a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12891a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12901a8af605SAxel Dörfler 			}
12911a8af605SAxel Dörfler 		}
129255030977SAxel Dörfler 	}
129361c5c89bSAxel Dörfler 
12941a8af605SAxel Dörfler 	if (text[0])
12951a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
129612966d04SAxel Dörfler }
129712966d04SAxel Dörfler 
129812966d04SAxel Dörfler 
129912966d04SAxel Dörfler void
13001fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
13011fc4cb1fSAxel Dörfler {
13021fc4cb1fSAxel Dörfler 	BString string;
1303551c9f15SSiarzhuk Zharski 	string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel");
13041fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
13051fc4cb1fSAxel Dörfler }
13061fc4cb1fSAxel Dörfler 
13071fc4cb1fSAxel Dörfler 
13081fc4cb1fSAxel Dörfler void
13095de171daSAxel Dörfler ScreenWindow::_Apply()
1310a10cf76eSAxel Dörfler {
1311abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
131261c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
131361c5c89bSAxel Dörfler 
131407184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
131507184a9eSAxel Dörfler 	if (status == B_OK) {
1316abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1317abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1318abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1319abc649b8SWaldemar Kornewald 		display_mode newMode;
1320abc649b8SWaldemar Kornewald 		BScreen screen(this);
1321abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1322abc649b8SWaldemar Kornewald 
1323abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1324abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
132595ef5044SJanus 			const int32 workspaceCount = count_workspaces();
132695ef5044SJanus 			for (int32 i = 0; i < workspaceCount; i++) {
1327abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1328abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1329abc649b8SWaldemar Kornewald 			}
1330199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1331199893c3SAxel Dörfler 		} else {
1332199893c3SAxel Dörfler 			if (current_workspace() == 0)
1333199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1334abc649b8SWaldemar Kornewald 		}
1335abc649b8SWaldemar Kornewald 
1336a10cf76eSAxel Dörfler 		fActive = fSelected;
1337a10cf76eSAxel Dörfler 
1338abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1339*41f43d56SAugustin Cavalier 		BAlert* window = new AlertWindow(this);
1340*41f43d56SAugustin Cavalier 		window->Go(NULL);
134107184a9eSAxel Dörfler 	} else {
134207184a9eSAxel Dörfler 		char message[256];
134307184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
1344c9e8f97aSAdrien Destugues 			B_TRANSLATE("The screen mode could not be set:\n\t%s\n"),
1345c9e8f97aSAdrien Destugues 			screen_errors(status));
1346551c9f15SSiarzhuk Zharski 		BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message,
1347c9e8f97aSAdrien Destugues 			B_TRANSLATE("OK"), NULL, NULL,
134807184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1349aed35104SHumdinger 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
135007184a9eSAxel Dörfler 		alert->Go();
1351a10cf76eSAxel Dörfler 	}
135207184a9eSAxel Dörfler }
1353