xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision 25fd5c7b3558df58baee955efafec15fd2ceadae)
1a10cf76eSAxel Dörfler /*
2b21d610eSAxel Dörfler  * Copyright 2001-2009, Haiku.
3a10cf76eSAxel Dörfler  * Distributed under the terms of the MIT License.
4a10cf76eSAxel Dörfler  *
5a10cf76eSAxel Dörfler  * Authors:
6a10cf76eSAxel Dörfler  *		Rafael Romo
7a10cf76eSAxel Dörfler  *		Stefano Ceccherini (burton666@libero.it)
8a10cf76eSAxel Dörfler  *		Andrew Bachmann
9a10cf76eSAxel Dörfler  *		Thomas Kurschel
10a10cf76eSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
11df3f5bacSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
12b72c4836SAlexandre Deckner  *		Alexandre Deckner, alex@zappotek.com
13a10cf76eSAxel Dörfler  */
14a10cf76eSAxel Dörfler 
15a10cf76eSAxel Dörfler 
16b21d610eSAxel Dörfler #include "ScreenWindow.h"
17b21d610eSAxel Dörfler 
18b21d610eSAxel Dörfler #include <stdio.h>
19b21d610eSAxel Dörfler #include <stdlib.h>
20b21d610eSAxel Dörfler #include <string.h>
21b21d610eSAxel Dörfler 
22b21d610eSAxel Dörfler #include <Alert.h>
23b21d610eSAxel Dörfler #include <Application.h>
24b21d610eSAxel Dörfler #include <Box.h>
25b21d610eSAxel Dörfler #include <Button.h>
26b21d610eSAxel Dörfler #include <Directory.h>
27b21d610eSAxel Dörfler #include <File.h>
28b21d610eSAxel Dörfler #include <FindDirectory.h>
29b21d610eSAxel Dörfler #include <InterfaceDefs.h>
30b21d610eSAxel Dörfler #include <LayoutBuilder.h>
31b21d610eSAxel Dörfler #include <MenuBar.h>
32b21d610eSAxel Dörfler #include <MenuItem.h>
33b21d610eSAxel Dörfler #include <MenuField.h>
34b21d610eSAxel Dörfler #include <Messenger.h>
35b21d610eSAxel Dörfler #include <Path.h>
36b21d610eSAxel Dörfler #include <PopUpMenu.h>
37b21d610eSAxel Dörfler #include <Screen.h>
38b21d610eSAxel Dörfler #include <String.h>
39b21d610eSAxel Dörfler #include <StringView.h>
40b21d610eSAxel Dörfler #include <Roster.h>
41b21d610eSAxel Dörfler #include <Window.h>
42b21d610eSAxel Dörfler 
43b21d610eSAxel Dörfler #include <InterfacePrivate.h>
44b21d610eSAxel Dörfler 
45a10cf76eSAxel Dörfler #include "AlertWindow.h"
46a10cf76eSAxel Dörfler #include "Constants.h"
47a10cf76eSAxel Dörfler #include "RefreshWindow.h"
48a10cf76eSAxel Dörfler #include "MonitorView.h"
49a10cf76eSAxel Dörfler #include "ScreenSettings.h"
50a10cf76eSAxel Dörfler #include "Utility.h"
51a10cf76eSAxel Dörfler 
52a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
53a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
54a10cf76eSAxel Dörfler  * adopted.
55a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
56a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
57a10cf76eSAxel Dörfler  * be using this.
58a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
59a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
60a10cf76eSAxel Dörfler  */
61a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
62a10cf76eSAxel Dörfler 
63a10cf76eSAxel Dörfler 
6475c92c56SRyan Leavengood const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds";
65c5d80d47SAxel Dörfler 
66a10cf76eSAxel Dörfler // list of officially supported colour spaces
67a10cf76eSAxel Dörfler static const struct {
68a10cf76eSAxel Dörfler 	color_space	space;
69a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
70a10cf76eSAxel Dörfler 	const char*	label;
71a10cf76eSAxel Dörfler } kColorSpaces[] = {
729c1a9b92SAdrien Destugues 	{ B_CMAP8, 8, "8 bits/pixel, 256 colors" },
739c1a9b92SAdrien Destugues 	{ B_RGB15, 15, "15 bits/pixel, 32768 colors" },
749c1a9b92SAdrien Destugues 	{ B_RGB16, 16, "16 bits/pixel, 65536 colors" },
759c1a9b92SAdrien Destugues 	{ B_RGB24, 24, "24 bits/pixel, 16 Million colors" },
769c1a9b92SAdrien Destugues 	{ B_RGB32, 32, "32 bits/pixel, 16 Million colors" }
77a10cf76eSAxel Dörfler };
78b21d610eSAxel Dörfler static const int32 kColorSpaceCount
79b21d610eSAxel Dörfler 	= sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
80a10cf76eSAxel Dörfler 
81a10cf76eSAxel Dörfler // list of standard refresh rates
82a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
83b21d610eSAxel Dörfler static const int32 kRefreshRateCount
84b21d610eSAxel Dörfler 	= sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
85a10cf76eSAxel Dörfler 
86a10cf76eSAxel Dörfler // list of combine modes
87a10cf76eSAxel Dörfler static const struct {
88a10cf76eSAxel Dörfler 	combine_mode	mode;
89a10cf76eSAxel Dörfler 	const char		*name;
90a10cf76eSAxel Dörfler } kCombineModes[] = {
91a10cf76eSAxel Dörfler 	{ kCombineDisable, "disable" },
92a10cf76eSAxel Dörfler 	{ kCombineHorizontally, "horizontally" },
93a10cf76eSAxel Dörfler 	{ kCombineVertically, "vertically" }
94a10cf76eSAxel Dörfler };
95b21d610eSAxel Dörfler static const int32 kCombineModeCount
96b21d610eSAxel Dörfler 	= sizeof(kCombineModes) / sizeof(kCombineModes[0]);
9729e8a73aSAxel Dörfler 
98a10cf76eSAxel Dörfler 
99a10cf76eSAxel Dörfler static BString
100a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
101a10cf76eSAxel Dörfler {
102a10cf76eSAxel Dörfler 	switch (mode) {
103a10cf76eSAxel Dörfler 		case 0:		return "disabled";
104a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
105a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
106a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
107a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
108a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
109a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
110a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
111a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
112a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
113a10cf76eSAxel Dörfler 		default:
114a10cf76eSAxel Dörfler 		{
115a10cf76eSAxel Dörfler 			BString name;
116a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
117a10cf76eSAxel Dörfler 
118a10cf76eSAxel Dörfler 			return name;
119a10cf76eSAxel Dörfler 		}
120a10cf76eSAxel Dörfler 	}
121a10cf76eSAxel Dörfler }
122a10cf76eSAxel Dörfler 
123a10cf76eSAxel Dörfler 
124a10cf76eSAxel Dörfler static void
125a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
126a10cf76eSAxel Dörfler {
127a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
128a10cf76eSAxel Dörfler }
129a10cf76eSAxel Dörfler 
130a10cf76eSAxel Dörfler 
131a10cf76eSAxel Dörfler static void
132a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
133a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
134a10cf76eSAxel Dörfler {
1358bf23e3cSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3,
1368bf23e3cSAxel Dörfler 		refresh);
137a10cf76eSAxel Dörfler 	string.UnlockBuffer();
138a10cf76eSAxel Dörfler 
139a10cf76eSAxel Dörfler 	if (appendUnit)
140a10cf76eSAxel Dörfler 		string << " Hz";
141a10cf76eSAxel Dörfler }
142a10cf76eSAxel Dörfler 
143a10cf76eSAxel Dörfler 
14407184a9eSAxel Dörfler static const char*
14507184a9eSAxel Dörfler screen_errors(status_t status)
14607184a9eSAxel Dörfler {
14707184a9eSAxel Dörfler 	switch (status) {
14807184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
1499c1a9b92SAdrien Destugues 			return "Unknown mode";
15007184a9eSAxel Dörfler 		// TODO: add more?
15107184a9eSAxel Dörfler 
15207184a9eSAxel Dörfler 		default:
15307184a9eSAxel Dörfler 			return strerror(status);
15407184a9eSAxel Dörfler 	}
15507184a9eSAxel Dörfler }
15607184a9eSAxel Dörfler 
15729e8a73aSAxel Dörfler 
1583dfd20c0SStephan Aßmus //	#pragma mark -
1593dfd20c0SStephan Aßmus 
1603dfd20c0SStephan Aßmus 
1615a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings* settings)
162b21d610eSAxel Dörfler 	:
163b21d610eSAxel Dörfler 	BWindow(settings->WindowFrame(), "Screen", B_TITLED_WINDOW,
164b21d610eSAxel Dörfler 		B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS,
165b21d610eSAxel Dörfler 		B_ALL_WORKSPACES),
166199893c3SAxel Dörfler 	fBootWorkspaceApplied(false),
167a10cf76eSAxel Dörfler 	fScreenMode(this),
16861c5c89bSAxel Dörfler 	fUndoScreenMode(this),
169abc649b8SWaldemar Kornewald 	fModified(false)
170a10cf76eSAxel Dörfler {
171a10cf76eSAxel Dörfler 	BScreen screen(this);
172a10cf76eSAxel Dörfler 
17312580984SAxel Dörfler 	accelerant_device_info info;
174d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
175d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
17612580984SAxel Dörfler 		fIsVesa = true;
17712580984SAxel Dörfler 
1785de171daSAxel Dörfler 	_UpdateOriginal();
1791fc4cb1fSAxel Dörfler 	_BuildSupportedColorSpaces();
180a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
181a10cf76eSAxel Dörfler 
1825a78744bSAxel Dörfler 	fSettings = settings;
1835a78744bSAxel Dörfler 
1845a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
1855a78744bSAxel Dörfler 
1869c1a9b92SAdrien Destugues 	BPopUpMenu *popUpMenu = new BPopUpMenu("Current workspace", true, true);
1879c1a9b92SAdrien Destugues 	fAllWorkspacesItem = new BMenuItem("All workspaces",
188d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
1895a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
1909c1a9b92SAdrien Destugues 	BMenuItem *item = new BMenuItem("Current workspace",
191d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
192b72c4836SAlexandre Deckner 
1935a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
19427c43a2dSRene Gollent 	fAllWorkspacesItem->SetMarked(true);
1955a78744bSAxel Dörfler 
196b21d610eSAxel Dörfler 	BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL,
197b21d610eSAxel Dörfler 		popUpMenu, NULL);
1985a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
199a10cf76eSAxel Dörfler 
200a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
201a10cf76eSAxel Dörfler 
202b21d610eSAxel Dörfler 	BBox* screenBox = new BBox("screen box");
2038bf23e3cSAxel Dörfler 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 5.0);
204b21d610eSAxel Dörfler 	layout->SetInsets(10, 10, 10, 10);
205b21d610eSAxel Dörfler 	screenBox->SetLayout(layout);
206a10cf76eSAxel Dörfler 
20712966d04SAxel Dörfler 	fMonitorInfo = new BStringView("monitor info", "");
20812966d04SAxel Dörfler 	screenBox->AddChild(fMonitorInfo);
20912966d04SAxel Dörfler 
210df3f5bacSStephan Aßmus 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0), "monitor",
2116bda235aSStefano Ceccherini 		screen.Frame().IntegerWidth() + 1, screen.Frame().IntegerHeight() + 1);
212b21d610eSAxel Dörfler 	screenBox->AddChild(fMonitorView);
2135a78744bSAxel Dörfler 
214b21d610eSAxel Dörfler 	fColumnsControl = new BTextControl("Columns:", "0",
215b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceColumnsChanged));
216b21d610eSAxel Dörfler 	fRowsControl = new BTextControl("Rows:", "0",
217b21d610eSAxel Dörfler 		new BMessage(kMsgWorkspaceRowsChanged));
218b21d610eSAxel Dörfler 
219b21d610eSAxel Dörfler 	screenBox->AddChild(BLayoutBuilder::Grid<>(5.0, 5.0)
220b21d610eSAxel Dörfler 		.Add(new BStringView("", "Workspaces"), 0, 0, 3)
221b21d610eSAxel Dörfler 		.AddTextControl(fColumnsControl, 0, 1, B_ALIGN_RIGHT)
222b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 1)
223b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, false))
224b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(true, true))
225b21d610eSAxel Dörfler 			.End()
226b21d610eSAxel Dörfler 		.AddTextControl(fRowsControl, 0, 2, B_ALIGN_RIGHT)
227b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 0, 2, 2)
228b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, false))
229b21d610eSAxel Dörfler 			.Add(_CreateColumnRowButton(false, true))
230*25fd5c7bSAlex Wilson 			.End()
231*25fd5c7bSAlex Wilson 		.View());
232b21d610eSAxel Dörfler 
233b21d610eSAxel Dörfler 	fBackgroundsButton = new BButton("BackgroundsButton",
2349c1a9b92SAdrien Destugues 		"Set background" B_UTF8_ELLIPSIS,
235b21d610eSAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
236b21d610eSAxel Dörfler 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
237b21d610eSAxel Dörfler 	screenBox->AddChild(fBackgroundsButton);
238a10cf76eSAxel Dörfler 
239a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
240a10cf76eSAxel Dörfler 
241b21d610eSAxel Dörfler 	BBox* controlsBox = new BBox("controls box");
242b21d610eSAxel Dörfler 	controlsBox->SetLabel(workspaceMenuField);
243*25fd5c7bSAlex Wilson 	BGroupView* outerControlsView = new BGroupView(B_VERTICAL, 10.0);
244*25fd5c7bSAlex Wilson 	outerControlsView->GroupLayout()->SetInsets(10, 10, 10, 10);
245b21d610eSAxel Dörfler 	controlsBox->AddChild(outerControlsView);
246a10cf76eSAxel Dörfler 
247a10cf76eSAxel Dörfler 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
248a10cf76eSAxel Dörfler 
24966ab1666SAxel Dörfler 	uint16 maxWidth = 0;
25066ab1666SAxel Dörfler 	uint16 maxHeight = 0;
25166ab1666SAxel Dörfler 	uint16 previousWidth = 0;
25266ab1666SAxel Dörfler 	uint16 previousHeight = 0;
253a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
254a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
255a10cf76eSAxel Dörfler 
256a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
257a10cf76eSAxel Dörfler 			continue;
258a10cf76eSAxel Dörfler 
259a10cf76eSAxel Dörfler 		previousWidth = mode.width;
260a10cf76eSAxel Dörfler 		previousHeight = mode.height;
26166ab1666SAxel Dörfler 		if (maxWidth < mode.width)
26266ab1666SAxel Dörfler 			maxWidth = mode.width;
26366ab1666SAxel Dörfler 		if (maxHeight < mode.height)
26466ab1666SAxel Dörfler 			maxHeight = mode.height;
265a10cf76eSAxel Dörfler 
266a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_RESOLUTION_MSG);
267a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
268a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
269a10cf76eSAxel Dörfler 
270a10cf76eSAxel Dörfler 		BString name;
271a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
272a10cf76eSAxel Dörfler 
273a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
274a10cf76eSAxel Dörfler 	}
275a10cf76eSAxel Dörfler 
27666ab1666SAxel Dörfler 	fMonitorView->SetMaxResolution(maxWidth, maxHeight);
27766ab1666SAxel Dörfler 
278b21d610eSAxel Dörfler 	fResolutionField = new BMenuField("ResolutionMenu", "Resolution:",
279b21d610eSAxel Dörfler 		fResolutionMenu, NULL);
280a10cf76eSAxel Dörfler 
281f99cba9eSAxel Dörfler 	fColorsMenu = new BPopUpMenu("colors", true, false);
282a10cf76eSAxel Dörfler 
283a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
2841fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
2851fc4cb1fSAxel Dörfler 			continue;
2861fc4cb1fSAxel Dörfler 
287a10cf76eSAxel Dörfler 		BMessage* message = new BMessage(POP_COLORS_MSG);
288a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
289a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
290a10cf76eSAxel Dörfler 
2911fc4cb1fSAxel Dörfler 		BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message);
2921fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == screen.ColorSpace())
2931fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace = item;
2941fc4cb1fSAxel Dörfler 
2951fc4cb1fSAxel Dörfler 		fColorsMenu->AddItem(item);
296a10cf76eSAxel Dörfler 	}
297a10cf76eSAxel Dörfler 
298b21d610eSAxel Dörfler 	fColorsField = new BMenuField("ColorsMenu", "Colors:", fColorsMenu, NULL);
299a10cf76eSAxel Dörfler 
300a10cf76eSAxel Dörfler 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
301a10cf76eSAxel Dörfler 
30229e8a73aSAxel Dörfler 	BMessage *message;
30329e8a73aSAxel Dörfler 
30429e8a73aSAxel Dörfler 	float min, max;
30529e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
30629e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
30729e8a73aSAxel Dörfler 		// frequency, like the VESA driver
30829e8a73aSAxel Dörfler 		BString name;
30929e8a73aSAxel Dörfler 		name << min << " Hz";
31029e8a73aSAxel Dörfler 
31129e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
31229e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
31329e8a73aSAxel Dörfler 
31429e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
31529e8a73aSAxel Dörfler 		item->SetEnabled(false);
31629e8a73aSAxel Dörfler 	} else {
31770a2b1b5SAxel Dörfler 		monitor_info info;
31870a2b1b5SAxel Dörfler 		if (fScreenMode.GetMonitorInfo(info) == B_OK) {
31970a2b1b5SAxel Dörfler 			min = max_c(info.min_vertical_frequency, min);
32070a2b1b5SAxel Dörfler 			max = min_c(info.max_vertical_frequency, max);
32170a2b1b5SAxel Dörfler 		}
32270a2b1b5SAxel Dörfler 
323a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
32470a2b1b5SAxel Dörfler 			if (kRefreshRates[i] < min || kRefreshRates[i] > max)
32570a2b1b5SAxel Dörfler 				continue;
32670a2b1b5SAxel Dörfler 
327a10cf76eSAxel Dörfler 			BString name;
328a10cf76eSAxel Dörfler 			name << kRefreshRates[i] << " Hz";
329a10cf76eSAxel Dörfler 
33029e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
331a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
332a10cf76eSAxel Dörfler 
333a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
334a10cf76eSAxel Dörfler 		}
335a10cf76eSAxel Dörfler 
33629e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
337a10cf76eSAxel Dörfler 
338a10cf76eSAxel Dörfler 		fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
339a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
34029e8a73aSAxel Dörfler 	}
341a10cf76eSAxel Dörfler 
3429c1a9b92SAdrien Destugues 	fRefreshField = new BMenuField("RefreshMenu", "Refresh rate:",
343b21d610eSAxel Dörfler 		fRefreshMenu, NULL);
344b21d610eSAxel Dörfler 
34512580984SAxel Dörfler 	if (_IsVesa())
34612580984SAxel Dörfler 		fRefreshField->Hide();
347a10cf76eSAxel Dörfler 
348a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
349a10cf76eSAxel Dörfler 	{
350a10cf76eSAxel Dörfler 		bool dummy;
351a10cf76eSAxel Dörfler 		uint32 dummy32;
352a10cf76eSAxel Dörfler 		bool multiMonSupport;
353a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
354a10cf76eSAxel Dörfler 		bool tvStandardSupport;
355a10cf76eSAxel Dörfler 
356a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
357a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
358a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
359a10cf76eSAxel Dörfler 
360a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
361a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
362a10cf76eSAxel Dörfler 
363a10cf76eSAxel Dörfler 		fCombineMenu = new BPopUpMenu("CombineDisplays", true, true);
364a10cf76eSAxel Dörfler 
365a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
366a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
367a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
368a10cf76eSAxel Dörfler 
369d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
370d1516993SAxel Dörfler 				message));
371a10cf76eSAxel Dörfler 		}
372a10cf76eSAxel Dörfler 
373b21d610eSAxel Dörfler 		fCombineField = new BMenuField("CombineMenu",
3749c1a9b92SAdrien Destugues 			"Combine displays:", fCombineMenu, NULL);
375a10cf76eSAxel Dörfler 
376a10cf76eSAxel Dörfler 		if (!multiMonSupport)
377df3f5bacSStephan Aßmus 			fCombineField->Hide();
378a10cf76eSAxel Dörfler 
379a10cf76eSAxel Dörfler 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", true, true);
380a10cf76eSAxel Dörfler 
381a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
382a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
383a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
384a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("no", message));
385a10cf76eSAxel Dörfler 
386a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
387a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
388a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("yes", message));
389a10cf76eSAxel Dörfler 
3909c1a9b92SAdrien Destugues 		fSwapDisplaysField = new BMenuField("SwapMenu", "Swap displays:",
391b21d610eSAxel Dörfler 			fSwapDisplaysMenu, NULL);
392a10cf76eSAxel Dörfler 
393a10cf76eSAxel Dörfler 		if (!multiMonSupport)
394df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
395a10cf76eSAxel Dörfler 
396a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", true, true);
397a10cf76eSAxel Dörfler 
398a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
399a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
400a10cf76eSAxel Dörfler 		message->AddBool("use", false);
401a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("if needed", message));
402a10cf76eSAxel Dörfler 
403a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
404a10cf76eSAxel Dörfler 		message->AddBool("use", true);
405a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("always", message));
406a10cf76eSAxel Dörfler 
407b21d610eSAxel Dörfler 		fUseLaptopPanelField = new BMenuField("UseLaptopPanel",
4089c1a9b92SAdrien Destugues 			"Use laptop panel:", fUseLaptopPanelMenu, NULL);
409a10cf76eSAxel Dörfler 
410a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
411df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
412a10cf76eSAxel Dörfler 
413a10cf76eSAxel Dörfler 		fTVStandardMenu = new BPopUpMenu("TVStandard", true, true);
414a10cf76eSAxel Dörfler 
415a10cf76eSAxel Dörfler 		// arbitrary limit
416a10cf76eSAxel Dörfler 		uint32 i;
417a10cf76eSAxel Dörfler 		for (i = 0; i < 100; ++i) {
418a10cf76eSAxel Dörfler 			uint32 mode;
419a10cf76eSAxel Dörfler 			if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK)
420a10cf76eSAxel Dörfler 				break;
421a10cf76eSAxel Dörfler 
422a10cf76eSAxel Dörfler 			BString name = tv_standard_to_string(mode);
423a10cf76eSAxel Dörfler 
424a10cf76eSAxel Dörfler 			message = new BMessage(POP_TV_STANDARD_MSG);
425a10cf76eSAxel Dörfler 			message->AddInt32("tv_standard", mode);
426a10cf76eSAxel Dörfler 
427a10cf76eSAxel Dörfler 			fTVStandardMenu->AddItem(new BMenuItem(name.String(), message));
428a10cf76eSAxel Dörfler 		}
429a10cf76eSAxel Dörfler 
4309c1a9b92SAdrien Destugues 		fTVStandardField = new BMenuField("tv standard", "Video format:",
431b21d610eSAxel Dörfler 			fTVStandardMenu, NULL);
432df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
433a10cf76eSAxel Dörfler 
434b21d610eSAxel Dörfler 		if (!tvStandardSupport || i == 0)
435df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
436a10cf76eSAxel Dörfler 	}
437a10cf76eSAxel Dörfler 
438*25fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
439*25fd5c7bSAlex Wilson 		.AddGrid(5.0, 5.0)
440b21d610eSAxel Dörfler 			.AddMenuField(fResolutionField, 0, 0, B_ALIGN_RIGHT)
441b21d610eSAxel Dörfler 			.AddMenuField(fColorsField, 0, 1, B_ALIGN_RIGHT)
442b21d610eSAxel Dörfler 			.AddMenuField(fRefreshField, 0, 2, B_ALIGN_RIGHT)
443b21d610eSAxel Dörfler 			.AddMenuField(fCombineField, 0, 3, B_ALIGN_RIGHT)
444b21d610eSAxel Dörfler 			.AddMenuField(fSwapDisplaysField, 0, 4, B_ALIGN_RIGHT)
445b21d610eSAxel Dörfler 			.AddMenuField(fUseLaptopPanelField, 0, 5, B_ALIGN_RIGHT)
446*25fd5c7bSAlex Wilson 			.AddMenuField(fTVStandardField, 0, 6, B_ALIGN_RIGHT)
447*25fd5c7bSAlex Wilson 		.End();
448df3f5bacSStephan Aßmus 
449abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
450abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
451b21d610eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));*/
452a10cf76eSAxel Dörfler 
453b21d610eSAxel Dörfler 	fApplyButton = new BButton("ApplyButton", "Apply",
454df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
455df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
456*25fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(outerControlsView)
457b21d610eSAxel Dörfler 		.AddGlue()
458*25fd5c7bSAlex Wilson 			.AddGroup(B_HORIZONTAL)
459*25fd5c7bSAlex Wilson 			.AddGlue()
460*25fd5c7bSAlex Wilson 			.Add(fApplyButton);
461b21d610eSAxel Dörfler 
462b21d610eSAxel Dörfler 	fRevertButton = new BButton("RevertButton", "Revert",
463b21d610eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
464b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(false);
465b21d610eSAxel Dörfler 
466*25fd5c7bSAlex Wilson 	BLayoutBuilder::Group<>(this, B_VERTICAL, 10.0)
467b21d610eSAxel Dörfler 		.SetInsets(10, 10, 10, 10)
468b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
469b21d610eSAxel Dörfler 			.AddGroup(B_VERTICAL)
470*25fd5c7bSAlex Wilson 				.AddStrut(controlsBox->TopBorderOffset() - 1)
471b21d610eSAxel Dörfler 				.Add(screenBox)
472b21d610eSAxel Dörfler 			.End()
473b21d610eSAxel Dörfler 			.Add(controlsBox)
474b21d610eSAxel Dörfler 		.End()
475b21d610eSAxel Dörfler 		.AddGroup(B_HORIZONTAL, 10.0)
476b21d610eSAxel Dörfler 			.Add(fRevertButton)
477b21d610eSAxel Dörfler 			.AddGlue();
478b21d610eSAxel 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);
5029c1a9b92SAdrien Destugues 			(new BAlert("VesaAlert", warning.String(), "OK", 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
5141fc4cb1fSAxel Dörfler 	(some resolutions 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 {
5451fc4cb1fSAxel Dörfler 	int32 supportsAnything = false;
5461fc4cb1fSAxel Dörfler 	int32 index = 0;
5471fc4cb1fSAxel Dörfler 
548a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
5491fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
5501fc4cb1fSAxel Dörfler 			continue;
5511fc4cb1fSAxel Dörfler 
552a10cf76eSAxel Dörfler 		bool supported = false;
553a10cf76eSAxel Dörfler 
554a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
555a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
556a10cf76eSAxel Dörfler 
557a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
558a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5591fc4cb1fSAxel Dörfler 				&& kColorSpaces[i].space == mode.space
560a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
5611fc4cb1fSAxel Dörfler 				supportsAnything = true;
562a10cf76eSAxel Dörfler 				supported = true;
563a10cf76eSAxel Dörfler 				break;
564a10cf76eSAxel Dörfler 			}
565a10cf76eSAxel Dörfler 		}
566a10cf76eSAxel Dörfler 
5671fc4cb1fSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(index++);
568a10cf76eSAxel Dörfler 		if (item)
569a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
570a10cf76eSAxel Dörfler 	}
5711fc4cb1fSAxel Dörfler 
5721fc4cb1fSAxel Dörfler 	fColorsField->SetEnabled(supportsAnything);
5731fc4cb1fSAxel Dörfler 
5741fc4cb1fSAxel Dörfler 	if (!supportsAnything)
5751fc4cb1fSAxel Dörfler 		return;
5761fc4cb1fSAxel Dörfler 
5771fc4cb1fSAxel Dörfler 	// Make sure a valid item is selected
5781fc4cb1fSAxel Dörfler 
5791fc4cb1fSAxel Dörfler 	BMenuItem* item = fColorsMenu->FindMarked();
5801fc4cb1fSAxel Dörfler 	bool changed = false;
5811fc4cb1fSAxel Dörfler 
5821fc4cb1fSAxel Dörfler 	if (item != fUserSelectedColorSpace) {
5831fc4cb1fSAxel Dörfler 		if (fUserSelectedColorSpace != NULL
5841fc4cb1fSAxel Dörfler 			&& fUserSelectedColorSpace->IsEnabled()) {
5851fc4cb1fSAxel Dörfler 			fUserSelectedColorSpace->SetMarked(true);
5861fc4cb1fSAxel Dörfler 			item = fUserSelectedColorSpace;
5871fc4cb1fSAxel Dörfler 			changed = true;
5881fc4cb1fSAxel Dörfler 		}
5891fc4cb1fSAxel Dörfler 	}
5901fc4cb1fSAxel Dörfler 	if (item != NULL && !item->IsEnabled()) {
5911fc4cb1fSAxel Dörfler 		// find the next best item
5921fc4cb1fSAxel Dörfler 		int32 index = fColorsMenu->IndexOf(item);
5931fc4cb1fSAxel Dörfler 		bool found = false;
5941fc4cb1fSAxel Dörfler 
5951fc4cb1fSAxel Dörfler 		for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) {
5961fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
5971fc4cb1fSAxel Dörfler 			if (item->IsEnabled()) {
5981fc4cb1fSAxel Dörfler 				found = true;
5991fc4cb1fSAxel Dörfler 				break;
6001fc4cb1fSAxel Dörfler 			}
6011fc4cb1fSAxel Dörfler 		}
6021fc4cb1fSAxel Dörfler 		if (!found) {
6031fc4cb1fSAxel Dörfler 			// search backwards as well
6041fc4cb1fSAxel Dörfler 			for (int32 i = index - 1; i >= 0; i--) {
6051fc4cb1fSAxel Dörfler 				item = fColorsMenu->ItemAt(i);
6061fc4cb1fSAxel Dörfler 				if (item->IsEnabled())
6071fc4cb1fSAxel Dörfler 					break;
6081fc4cb1fSAxel Dörfler 			}
6091fc4cb1fSAxel Dörfler 		}
6101fc4cb1fSAxel Dörfler 
6111fc4cb1fSAxel Dörfler 		item->SetMarked(true);
6121fc4cb1fSAxel Dörfler 		changed = true;
6131fc4cb1fSAxel Dörfler 	}
6141fc4cb1fSAxel Dörfler 
6151fc4cb1fSAxel Dörfler 	if (changed) {
6161fc4cb1fSAxel Dörfler 		// Update selected space
6171fc4cb1fSAxel Dörfler 
6181fc4cb1fSAxel Dörfler 		BMessage* message = item->Message();
6191fc4cb1fSAxel Dörfler 		int32 space;
6201fc4cb1fSAxel Dörfler 		if (message->FindInt32("space", &space) == B_OK) {
6211fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
6221fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
6231fc4cb1fSAxel Dörfler 		}
6241fc4cb1fSAxel Dörfler 	}
625a10cf76eSAxel Dörfler }
626a10cf76eSAxel Dörfler 
627a10cf76eSAxel Dörfler 
6285de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
629a10cf76eSAxel Dörfler void
6305de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
631a10cf76eSAxel Dörfler {
63229e8a73aSAxel Dörfler 	float min, max;
63329e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
63429e8a73aSAxel Dörfler 		return;
635a10cf76eSAxel Dörfler 
63629e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
63729e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
63829e8a73aSAxel Dörfler 		BMessage* message = item->Message();
63929e8a73aSAxel Dörfler 		float refresh;
64029e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
64129e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
642a10cf76eSAxel Dörfler 	}
643a10cf76eSAxel Dörfler }
644a10cf76eSAxel Dörfler 
645a10cf76eSAxel Dörfler 
6465de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
647a10cf76eSAxel Dörfler void
6485de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
649a10cf76eSAxel Dörfler {
650a10cf76eSAxel Dörfler 	BString string;
651a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
652a10cf76eSAxel Dörfler 
653a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
654a10cf76eSAxel Dörfler 	if (item) {
655a10cf76eSAxel Dörfler 		if (!item->IsMarked())
656a10cf76eSAxel Dörfler 			item->SetMarked(true);
65729e8a73aSAxel Dörfler 
658a10cf76eSAxel Dörfler 		// "Other…" items only contains a refresh rate when active
659e6b421a9SJérôme Duval 		fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
660a10cf76eSAxel Dörfler 		return;
661a10cf76eSAxel Dörfler 	}
662a10cf76eSAxel Dörfler 
663a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
664a10cf76eSAxel Dörfler 
665a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
666a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
667a10cf76eSAxel Dörfler 
668a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
669a10cf76eSAxel Dörfler 
6709c1a9b92SAdrien Destugues 	string.Append("/other" B_UTF8_ELLIPSIS);
671a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
672a10cf76eSAxel Dörfler }
673a10cf76eSAxel Dörfler 
674a10cf76eSAxel Dörfler 
675a10cf76eSAxel Dörfler void
6765de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
677a10cf76eSAxel Dörfler {
678a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
679a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
680a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
681a10cf76eSAxel Dörfler 
682a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
683a10cf76eSAxel Dörfler }
684a10cf76eSAxel Dörfler 
685a10cf76eSAxel Dörfler 
686a10cf76eSAxel Dörfler void
6875de171daSAxel Dörfler ScreenWindow::_UpdateControls()
688a10cf76eSAxel Dörfler {
689b21d610eSAxel Dörfler 	_UpdateWorkspaceButtons();
690b21d610eSAxel Dörfler 
691a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
692a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
693a10cf76eSAxel Dörfler 		item->SetMarked(true);
694a10cf76eSAxel Dörfler 
695a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
696a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
697a10cf76eSAxel Dörfler 		item->SetMarked(true);
698a10cf76eSAxel Dörfler 
699a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
700a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
701a10cf76eSAxel Dörfler 
702a10cf76eSAxel Dörfler 		uint32 tvStandard;
703a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
704a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
705a10cf76eSAxel Dörfler 			if (!item->IsMarked())
706a10cf76eSAxel Dörfler 				item->SetMarked(true);
707a10cf76eSAxel Dörfler 			break;
708a10cf76eSAxel Dörfler 		}
709a10cf76eSAxel Dörfler 	}
710a10cf76eSAxel Dörfler 
7115de171daSAxel Dörfler 	_CheckResolutionMenu();
7125de171daSAxel Dörfler 	_CheckColorMenu();
7135de171daSAxel Dörfler 	_CheckRefreshMenu();
714a10cf76eSAxel Dörfler 
715a10cf76eSAxel Dörfler 	BString string;
716a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
717a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
718a10cf76eSAxel Dörfler 
719a10cf76eSAxel Dörfler 	if (item != NULL) {
720a10cf76eSAxel Dörfler 		if (!item->IsMarked())
721a10cf76eSAxel Dörfler 			item->SetMarked(true);
722a10cf76eSAxel Dörfler 	} else {
723a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
724a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
725a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
726a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
727a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
728a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
729a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
730a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
731a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
732a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
733a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
734a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
735a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
736a10cf76eSAxel Dörfler 		if (item)
737a10cf76eSAxel Dörfler 			item->SetMarked(true);
738a10cf76eSAxel Dörfler 
739a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
740a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
741a10cf76eSAxel Dörfler 	}
742a10cf76eSAxel Dörfler 
743a10cf76eSAxel Dörfler 	// mark active combine mode
744a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
745a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
746a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
747a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
748a10cf76eSAxel Dörfler 				item->SetMarked(true);
749a10cf76eSAxel Dörfler 			break;
750a10cf76eSAxel Dörfler 		}
751a10cf76eSAxel Dörfler 	}
752a10cf76eSAxel Dörfler 
753a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
754a10cf76eSAxel Dörfler 
7551fc4cb1fSAxel Dörfler 	for (int32 i = 0, index = 0; i <  kColorSpaceCount; i++) {
7561fc4cb1fSAxel Dörfler 		if ((fSupportedColorSpaces & (1 << i)) == 0)
7571fc4cb1fSAxel Dörfler 			continue;
7581fc4cb1fSAxel Dörfler 
7591fc4cb1fSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space) {
7601fc4cb1fSAxel Dörfler 			item = fColorsMenu->ItemAt(index);
761a10cf76eSAxel Dörfler 			break;
762a10cf76eSAxel Dörfler 		}
7631fc4cb1fSAxel Dörfler 
7641fc4cb1fSAxel Dörfler 		index++;
765a10cf76eSAxel Dörfler 	}
766a10cf76eSAxel Dörfler 
767a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
768a10cf76eSAxel Dörfler 		item->SetMarked(true);
769a10cf76eSAxel Dörfler 
7701fc4cb1fSAxel Dörfler 	_UpdateColorLabel();
7715de171daSAxel Dörfler 	_UpdateMonitorView();
7725de171daSAxel Dörfler 	_UpdateRefreshControl();
773a10cf76eSAxel Dörfler 
7745de171daSAxel Dörfler 	_CheckApplyEnabled();
775a10cf76eSAxel Dörfler }
776a10cf76eSAxel Dörfler 
777a10cf76eSAxel Dörfler 
77812580984SAxel Dörfler /*! Reflect active mode in chosen settings */
779a10cf76eSAxel Dörfler void
7805de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
781a10cf76eSAxel Dörfler {
78212580984SAxel Dörfler 	// Usually, this function gets called after a mode
783a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
784a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
785a10cf76eSAxel Dörfler 	// what kind of mode we actually got
786a10cf76eSAxel Dörfler 	fScreenMode.Get(fActive);
787a10cf76eSAxel Dörfler 	fSelected = fActive;
788a10cf76eSAxel Dörfler 
78912966d04SAxel Dörfler 	_UpdateMonitor();
7905de171daSAxel Dörfler 	_UpdateControls();
791a10cf76eSAxel Dörfler }
792a10cf76eSAxel Dörfler 
793a10cf76eSAxel Dörfler 
794a10cf76eSAxel Dörfler void
795b21d610eSAxel Dörfler ScreenWindow::_UpdateWorkspaceButtons()
796b21d610eSAxel Dörfler {
797b21d610eSAxel Dörfler 	uint32 columns;
798b21d610eSAxel Dörfler 	uint32 rows;
799b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
800b21d610eSAxel Dörfler 
801b21d610eSAxel Dörfler 	char text[32];
802b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", columns);
803b21d610eSAxel Dörfler 	fColumnsControl->SetText(text);
804b21d610eSAxel Dörfler 
805b21d610eSAxel Dörfler 	snprintf(text, sizeof(text), "%ld", rows);
806b21d610eSAxel Dörfler 	fRowsControl->SetText(text);
807b21d610eSAxel Dörfler 
808b21d610eSAxel Dörfler 	_GetColumnRowButton(true, false)->SetEnabled(columns != 1 && rows != 32);
809b21d610eSAxel Dörfler 	_GetColumnRowButton(true, true)->SetEnabled((columns + 1) * rows < 32);
810b21d610eSAxel Dörfler 	_GetColumnRowButton(false, false)->SetEnabled(rows != 1 && columns != 32);
811b21d610eSAxel Dörfler 	_GetColumnRowButton(false, true)->SetEnabled(columns * (rows + 1) < 32);
812b21d610eSAxel Dörfler }
813b21d610eSAxel Dörfler 
814b21d610eSAxel Dörfler 
815b21d610eSAxel Dörfler void
816a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
817a10cf76eSAxel Dörfler {
818a10cf76eSAxel Dörfler 	// move window on screen, if necessary
819a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
820a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
821a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
822a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
823a10cf76eSAxel Dörfler 	}
824a10cf76eSAxel Dörfler }
825a10cf76eSAxel Dörfler 
826a10cf76eSAxel Dörfler 
827a10cf76eSAxel Dörfler void
828a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
829a10cf76eSAxel Dörfler {
830abc649b8SWaldemar Kornewald 	fScreenMode.GetOriginalMode(fOriginal, workspace);
8315de171daSAxel Dörfler 	_UpdateActiveMode();
832a10cf76eSAxel Dörfler 
8336edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
8346edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
835a10cf76eSAxel Dörfler }
836a10cf76eSAxel Dörfler 
837a10cf76eSAxel Dörfler 
838a10cf76eSAxel Dörfler void
839a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
840a10cf76eSAxel Dörfler {
841a10cf76eSAxel Dörfler 	switch (message->what) {
842a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8435de171daSAxel Dörfler 			_CheckApplyEnabled();
844a10cf76eSAxel Dörfler 			break;
845a10cf76eSAxel Dörfler 
846b21d610eSAxel Dörfler 		case kMsgWorkspaceLayoutChanged:
847a10cf76eSAxel Dörfler 		{
848b21d610eSAxel Dörfler 			int32 deltaX = 0;
849b21d610eSAxel Dörfler 			int32 deltaY = 0;
850b21d610eSAxel Dörfler 			message->FindInt32("delta_x", &deltaX);
851b21d610eSAxel Dörfler 			message->FindInt32("delta_y", &deltaY);
852b21d610eSAxel Dörfler 
853b21d610eSAxel Dörfler 			if (deltaX == 0 && deltaY == 0)
854b21d610eSAxel Dörfler 				break;
855b21d610eSAxel Dörfler 
856b21d610eSAxel Dörfler 			uint32 newColumns;
857b21d610eSAxel Dörfler 			uint32 newRows;
858b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&newColumns, &newRows);
859b21d610eSAxel Dörfler 
860b21d610eSAxel Dörfler 			newColumns += deltaX;
861b21d610eSAxel Dörfler 			newRows += deltaY;
862b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, newRows);
863b21d610eSAxel Dörfler 
864b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
8655de171daSAxel Dörfler 			_CheckApplyEnabled();
866b21d610eSAxel Dörfler 			break;
867abc649b8SWaldemar Kornewald 		}
868b21d610eSAxel Dörfler 
869b21d610eSAxel Dörfler 		case kMsgWorkspaceColumnsChanged:
870b21d610eSAxel Dörfler 		{
871b21d610eSAxel Dörfler 			uint32 newColumns = strtoul(fColumnsControl->Text(), NULL, 10);
872b21d610eSAxel Dörfler 
873b21d610eSAxel Dörfler 			uint32 rows;
874b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(NULL, &rows);
875b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(newColumns, rows);
876b21d610eSAxel Dörfler 
877b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
878b21d610eSAxel Dörfler 			_CheckApplyEnabled();
879b21d610eSAxel Dörfler 			break;
880b21d610eSAxel Dörfler 		}
881b21d610eSAxel Dörfler 
882b21d610eSAxel Dörfler 		case kMsgWorkspaceRowsChanged:
883b21d610eSAxel Dörfler 		{
884b21d610eSAxel Dörfler 			uint32 newRows = strtoul(fRowsControl->Text(), NULL, 10);
885b21d610eSAxel Dörfler 
886b21d610eSAxel Dörfler 			uint32 columns;
887b21d610eSAxel Dörfler 			BPrivate::get_workspaces_layout(&columns, NULL);
888b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(columns, newRows);
889b21d610eSAxel Dörfler 
890b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
891b21d610eSAxel Dörfler 			_CheckApplyEnabled();
892a10cf76eSAxel Dörfler 			break;
893a10cf76eSAxel Dörfler 		}
894a10cf76eSAxel Dörfler 
895a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
896a10cf76eSAxel Dörfler 		{
897a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
898a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
899a10cf76eSAxel Dörfler 
9005de171daSAxel Dörfler 			_CheckColorMenu();
9015de171daSAxel Dörfler 			_CheckRefreshMenu();
902a10cf76eSAxel Dörfler 
9035de171daSAxel Dörfler 			_UpdateMonitorView();
9045de171daSAxel Dörfler 			_UpdateRefreshControl();
905a10cf76eSAxel Dörfler 
9065de171daSAxel Dörfler 			_CheckApplyEnabled();
907a10cf76eSAxel Dörfler 			break;
908a10cf76eSAxel Dörfler 		}
909a10cf76eSAxel Dörfler 
910a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
911a10cf76eSAxel Dörfler 		{
9121fc4cb1fSAxel Dörfler 			int32 space;
9131fc4cb1fSAxel Dörfler 			if (message->FindInt32("space", &space) != B_OK)
9141fc4cb1fSAxel Dörfler 				break;
915a10cf76eSAxel Dörfler 
9161fc4cb1fSAxel Dörfler 			int32 index;
9171fc4cb1fSAxel Dörfler 			if (message->FindInt32("index", &index) == B_OK
9181fc4cb1fSAxel Dörfler 				&& fColorsMenu->ItemAt(index) != NULL)
9191fc4cb1fSAxel Dörfler 				fUserSelectedColorSpace = fColorsMenu->ItemAt(index);
9201fc4cb1fSAxel Dörfler 
9211fc4cb1fSAxel Dörfler 			fSelected.space = (color_space)space;
9221fc4cb1fSAxel Dörfler 			_UpdateColorLabel();
923a10cf76eSAxel Dörfler 
9245de171daSAxel Dörfler 			_CheckApplyEnabled();
925a10cf76eSAxel Dörfler 			break;
926a10cf76eSAxel Dörfler 		}
927a10cf76eSAxel Dörfler 
928a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
929a40498e2SWaldemar Kornewald 		{
930a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
931a10cf76eSAxel Dörfler 			fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
9321fc4cb1fSAxel Dörfler 				// revert "Other…" label - it might have a refresh rate prefix
933a10cf76eSAxel Dörfler 
9345de171daSAxel Dörfler 			_CheckApplyEnabled();
935a10cf76eSAxel Dörfler 			break;
936a40498e2SWaldemar Kornewald 		}
937a10cf76eSAxel Dörfler 
938a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
939a10cf76eSAxel Dörfler 		{
94029e8a73aSAxel Dörfler 			// make sure menu shows something useful
9415de171daSAxel Dörfler 			_UpdateRefreshControl();
942a10cf76eSAxel Dörfler 
94329e8a73aSAxel Dörfler 			float min = 0, max = 999;
94429e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
94529e8a73aSAxel Dörfler 			if (min < gMinRefresh)
94629e8a73aSAxel Dörfler 				min = gMinRefresh;
94729e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
94829e8a73aSAxel Dörfler 				max = gMaxRefresh;
94929e8a73aSAxel Dörfler 
95070a2b1b5SAxel Dörfler 			monitor_info info;
95170a2b1b5SAxel Dörfler 			if (fScreenMode.GetMonitorInfo(info) == B_OK) {
95270a2b1b5SAxel Dörfler 				min = max_c(info.min_vertical_frequency, min);
95370a2b1b5SAxel Dörfler 				max = min_c(info.max_vertical_frequency, max);
95470a2b1b5SAxel Dörfler 			}
95570a2b1b5SAxel Dörfler 
956c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
95770a2b1b5SAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh,
95870a2b1b5SAxel Dörfler 				min, max);
959a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
960a10cf76eSAxel Dörfler 			break;
961a10cf76eSAxel Dörfler 		}
962a10cf76eSAxel Dörfler 
963a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
964a10cf76eSAxel Dörfler 		{
965a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
966a10cf76eSAxel Dörfler 			// select the refresh rate chosen
967a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
968a10cf76eSAxel Dörfler 
9695de171daSAxel Dörfler 			_UpdateRefreshControl();
9705de171daSAxel Dörfler 			_CheckApplyEnabled();
971a10cf76eSAxel Dörfler 			break;
972a10cf76eSAxel Dörfler 		}
973a10cf76eSAxel Dörfler 
974a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
975a10cf76eSAxel Dörfler 		{
976a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
977a10cf76eSAxel Dörfler 			int32 mode;
978a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
979a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
980a10cf76eSAxel Dörfler 
9815de171daSAxel Dörfler 			_CheckResolutionMenu();
9825de171daSAxel Dörfler 			_CheckApplyEnabled();
983a10cf76eSAxel Dörfler 			break;
984a10cf76eSAxel Dörfler 		}
985a10cf76eSAxel Dörfler 
986a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
987a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
9885de171daSAxel Dörfler 			_CheckApplyEnabled();
989a10cf76eSAxel Dörfler 			break;
990a10cf76eSAxel Dörfler 
991a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
992a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
9935de171daSAxel Dörfler 			_CheckApplyEnabled();
994a10cf76eSAxel Dörfler 			break;
995a10cf76eSAxel Dörfler 
996a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
997a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
9985de171daSAxel Dörfler 			_CheckApplyEnabled();
999a10cf76eSAxel Dörfler 			break;
1000a10cf76eSAxel Dörfler 
1001df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
10026f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
10036f095d6aSRyan Leavengood 				app_info info;
10046f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
10056f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
10066f095d6aSRyan Leavengood 			}
1007df3f5bacSStephan Aßmus 			break;
1008df3f5bacSStephan Aßmus 
1009a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
1010a10cf76eSAxel Dörfler 		{
10114be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
1012a10cf76eSAxel Dörfler 			fSelected.width = 640;
1013a10cf76eSAxel Dörfler 			fSelected.height = 480;
1014a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
1015a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
1016a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
1017a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
1018a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
1019a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
1020a10cf76eSAxel Dörfler 
1021b21d610eSAxel Dörfler 			// TODO: workspace defaults
1022abc649b8SWaldemar Kornewald 
10235de171daSAxel Dörfler 			_UpdateControls();
1024a10cf76eSAxel Dörfler 			break;
1025a10cf76eSAxel Dörfler 		}
1026a10cf76eSAxel Dörfler 
102710e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
102861c5c89bSAxel Dörfler 			fUndoScreenMode.Revert();
10295de171daSAxel Dörfler 			_UpdateActiveMode();
1030abc649b8SWaldemar Kornewald 			break;
1031abc649b8SWaldemar Kornewald 
1032abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
1033abc649b8SWaldemar Kornewald 		{
1034abc649b8SWaldemar Kornewald 			fModified = false;
1035199893c3SAxel Dörfler 			fBootWorkspaceApplied = false;
1036abc649b8SWaldemar Kornewald 
1037b21d610eSAxel Dörfler 			// ScreenMode::Revert() assumes that we first set the correct
1038b21d610eSAxel Dörfler 			// number of workspaces
1039b21d610eSAxel Dörfler 
1040b21d610eSAxel Dörfler 			BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns,
1041b21d610eSAxel Dörfler 				fOriginalWorkspacesRows);
1042b21d610eSAxel Dörfler 			_UpdateWorkspaceButtons();
1043b21d610eSAxel Dörfler 
1044a10cf76eSAxel Dörfler 			fScreenMode.Revert();
10455de171daSAxel Dörfler 			_UpdateActiveMode();
1046a10cf76eSAxel Dörfler 			break;
1047abc649b8SWaldemar Kornewald 		}
1048a10cf76eSAxel Dörfler 
1049a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
10505de171daSAxel Dörfler 			_Apply();
1051a10cf76eSAxel Dörfler 			break;
1052a10cf76eSAxel Dörfler 
1053abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
1054abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
1055abc649b8SWaldemar Kornewald 			fModified = true;
10565de171daSAxel Dörfler 			_UpdateActiveMode();
1057a10cf76eSAxel Dörfler 			break;
1058a10cf76eSAxel Dörfler 
1059a10cf76eSAxel Dörfler 		default:
1060a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
1061a10cf76eSAxel Dörfler 			break;
1062a10cf76eSAxel Dörfler 	}
1063a10cf76eSAxel Dörfler }
1064a10cf76eSAxel Dörfler 
1065a10cf76eSAxel Dörfler 
106612580984SAxel Dörfler status_t
106712580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
106812580984SAxel Dörfler {
106912580984SAxel Dörfler 	BPath path;
107012580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
107112580984SAxel Dörfler 	if (status < B_OK)
107212580984SAxel Dörfler 		return status;
107312580984SAxel Dörfler 
107412580984SAxel Dörfler 	path.Append("kernel/drivers");
107512580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
107612580984SAxel Dörfler 	if (status < B_OK)
107712580984SAxel Dörfler 		return status;
107812580984SAxel Dörfler 
107912580984SAxel Dörfler 	path.Append("vesa");
108012580984SAxel Dörfler 	BFile file;
108112580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
108212580984SAxel Dörfler 	if (status < B_OK)
108312580984SAxel Dörfler 		return status;
108412580984SAxel Dörfler 
108512580984SAxel Dörfler 	char buffer[256];
108612580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
108712580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
108812580984SAxel Dörfler 
108912580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
109012580984SAxel Dörfler 	if (bytesWritten < B_OK)
109112580984SAxel Dörfler 		return bytesWritten;
109212580984SAxel Dörfler 
109312580984SAxel Dörfler 	return B_OK;
109412580984SAxel Dörfler }
109512580984SAxel Dörfler 
109612580984SAxel Dörfler 
1097b21d610eSAxel Dörfler BButton*
1098b21d610eSAxel Dörfler ScreenWindow::_CreateColumnRowButton(bool columns, bool plus)
1099b21d610eSAxel Dörfler {
1100b21d610eSAxel Dörfler 	BMessage* message = new BMessage(kMsgWorkspaceLayoutChanged);
1101b21d610eSAxel Dörfler 	message->AddInt32("delta_x", columns ? (plus ? 1 : -1) : 0);
1102b21d610eSAxel Dörfler 	message->AddInt32("delta_y", !columns ? (plus ? 1 : -1) : 0);
1103b21d610eSAxel Dörfler 
1104b21d610eSAxel Dörfler 	BButton* button = new BButton(plus ? "+" : "-", message);
1105b21d610eSAxel Dörfler 	button->SetFontSize(be_plain_font->Size() * 0.9);
1106b21d610eSAxel Dörfler 
1107b21d610eSAxel Dörfler 	BSize size = button->MinSize();
1108b21d610eSAxel Dörfler 	size.width = button->StringWidth("+") + 16;
1109b21d610eSAxel Dörfler 	button->SetExplicitMinSize(size);
1110b21d610eSAxel Dörfler 	button->SetExplicitMaxSize(size);
1111b21d610eSAxel Dörfler 
1112b21d610eSAxel Dörfler 	fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)] = button;
1113b21d610eSAxel Dörfler 	return button;
1114b21d610eSAxel Dörfler }
1115b21d610eSAxel Dörfler 
1116b21d610eSAxel Dörfler 
1117b21d610eSAxel Dörfler BButton*
1118b21d610eSAxel Dörfler ScreenWindow::_GetColumnRowButton(bool columns, bool plus)
1119b21d610eSAxel Dörfler {
1120b21d610eSAxel Dörfler 	return fWorkspacesButtons[(columns ? 0 : 2) + (plus ? 1 : 0)];
1121b21d610eSAxel Dörfler }
1122b21d610eSAxel Dörfler 
1123b21d610eSAxel Dörfler 
1124a10cf76eSAxel Dörfler void
11251fc4cb1fSAxel Dörfler ScreenWindow::_BuildSupportedColorSpaces()
11261fc4cb1fSAxel Dörfler {
11271fc4cb1fSAxel Dörfler 	fSupportedColorSpaces = 0;
11281fc4cb1fSAxel Dörfler 
11291fc4cb1fSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
11301fc4cb1fSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
11311fc4cb1fSAxel Dörfler 			if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) {
11321fc4cb1fSAxel Dörfler 				fSupportedColorSpaces |= 1 << i;
11331fc4cb1fSAxel Dörfler 				break;
11341fc4cb1fSAxel Dörfler 			}
11351fc4cb1fSAxel Dörfler 		}
11361fc4cb1fSAxel Dörfler 	}
11371fc4cb1fSAxel Dörfler }
11381fc4cb1fSAxel Dörfler 
11391fc4cb1fSAxel Dörfler 
11401fc4cb1fSAxel Dörfler void
11415de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1142a10cf76eSAxel Dörfler {
114327c43a2dSRene Gollent 	fApplyButton->SetEnabled(fSelected != fActive
114427c43a2dSRene Gollent 		|| fAllWorkspacesItem->IsMarked());
1145b21d610eSAxel Dörfler 
1146b21d610eSAxel Dörfler 	uint32 columns;
1147b21d610eSAxel Dörfler 	uint32 rows;
1148b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&columns, &rows);
1149b21d610eSAxel Dörfler 
1150b21d610eSAxel Dörfler 	fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns
1151b21d610eSAxel Dörfler 		|| rows != fOriginalWorkspacesRows
11525de171daSAxel Dörfler 		|| fSelected != fOriginal);
1153a10cf76eSAxel Dörfler }
1154a10cf76eSAxel Dörfler 
1155a10cf76eSAxel Dörfler 
1156a10cf76eSAxel Dörfler void
11575de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1158abc649b8SWaldemar Kornewald {
1159b21d610eSAxel Dörfler 	BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns,
1160b21d610eSAxel Dörfler 		&fOriginalWorkspacesRows);
1161b21d610eSAxel Dörfler 
1162abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1163abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1164abc649b8SWaldemar Kornewald }
1165abc649b8SWaldemar Kornewald 
1166abc649b8SWaldemar Kornewald 
1167abc649b8SWaldemar Kornewald void
116812966d04SAxel Dörfler ScreenWindow::_UpdateMonitor()
116912966d04SAxel Dörfler {
117012966d04SAxel Dörfler 	monitor_info info;
117112966d04SAxel Dörfler 	float diagonalInches;
117212966d04SAxel Dörfler 	status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches);
117355030977SAxel Dörfler 	if (status == B_OK) {
11741a8af605SAxel Dörfler 		char text[512];
117566ab1666SAxel Dörfler 		snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor,
117666ab1666SAxel Dörfler 			info.name[0] ? " " : "", info.name, diagonalInches);
117712966d04SAxel Dörfler 
117812966d04SAxel Dörfler 		fMonitorInfo->SetText(text);
117912966d04SAxel Dörfler 
118012966d04SAxel Dörfler 		if (fMonitorInfo->IsHidden())
118112966d04SAxel Dörfler 			fMonitorInfo->Show();
118255030977SAxel Dörfler 	} else {
118355030977SAxel Dörfler 		if (!fMonitorInfo->IsHidden())
118455030977SAxel Dörfler 			fMonitorInfo->Hide();
118555030977SAxel Dörfler 	}
1186af8f9c31SAxel Dörfler 
118755030977SAxel Dörfler 	char text[512];
11881a8af605SAxel Dörfler 	size_t length = 0;
11891a8af605SAxel Dörfler 	text[0] = 0;
11901a8af605SAxel Dörfler 
119155030977SAxel Dörfler 	if (status == B_OK) {
1192af8f9c31SAxel Dörfler 		if (info.min_horizontal_frequency != 0
1193af8f9c31SAxel Dörfler 			&& info.min_vertical_frequency != 0
1194af8f9c31SAxel Dörfler 			&& info.max_pixel_clock != 0) {
11951a8af605SAxel Dörfler 			length = snprintf(text, sizeof(text),
11969c1a9b92SAdrien Destugues 				"Horizonal frequency:\t%lu - %lu kHz\n"
11979c1a9b92SAdrien Destugues 				"Vertical frequency:\t%lu - %lu Hz\n\n"
11989c1a9b92SAdrien Destugues 				"Maximum pixel clock:\t%g MHz",
11991a8af605SAxel Dörfler 				info.min_horizontal_frequency, info.max_horizontal_frequency,
12001a8af605SAxel Dörfler 				info.min_vertical_frequency, info.max_vertical_frequency,
12011a8af605SAxel Dörfler 				info.max_pixel_clock / 1000.0);
1202af8f9c31SAxel Dörfler 		}
12031a8af605SAxel Dörfler 		if (info.serial_number[0] && length < sizeof(text)) {
12041a8af605SAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
12051a8af605SAxel Dörfler 				"%sSerial no.: %s", length ? "\n\n" : "",
12061a8af605SAxel Dörfler 				info.serial_number);
12071a8af605SAxel Dörfler 			if (info.produced.week != 0 && info.produced.year != 0
12081a8af605SAxel Dörfler 				&& length < sizeof(text)) {
12091a8af605SAxel Dörfler 				length += snprintf(text + length, sizeof(text) - length,
12101a8af605SAxel Dörfler 					" (%u/%u)", info.produced.week, info.produced.year);
12111a8af605SAxel Dörfler 	 		}
12121a8af605SAxel Dörfler 		}
121355030977SAxel Dörfler 	}
121461c5c89bSAxel Dörfler 
121561c5c89bSAxel Dörfler 	// Add info about the graphics device
121661c5c89bSAxel Dörfler 
121761c5c89bSAxel Dörfler 	accelerant_device_info deviceInfo;
121861c5c89bSAxel Dörfler 	if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK
121961c5c89bSAxel Dörfler 		&& length < sizeof(text)) {
122061c5c89bSAxel Dörfler 		if (deviceInfo.name[0] && deviceInfo.chipset[0]) {
122161c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
122261c5c89bSAxel Dörfler 				"%s%s (%s)", length != 0 ? "\n\n" : "", deviceInfo.name,
122361c5c89bSAxel Dörfler 				deviceInfo.chipset);
122461c5c89bSAxel Dörfler 		} else if (deviceInfo.name[0] || deviceInfo.chipset[0]) {
122561c5c89bSAxel Dörfler 			length += snprintf(text + length, sizeof(text) - length,
122661c5c89bSAxel Dörfler 				"%s%s", length != 0 ? "\n\n" : "", deviceInfo.name[0]
122761c5c89bSAxel Dörfler 					? deviceInfo.name : deviceInfo.chipset);
122861c5c89bSAxel Dörfler 		}
122961c5c89bSAxel Dörfler 	}
123061c5c89bSAxel Dörfler 
12311a8af605SAxel Dörfler 	if (text[0])
12321a8af605SAxel Dörfler 		fMonitorView->SetToolTip(text);
123312966d04SAxel Dörfler }
123412966d04SAxel Dörfler 
123512966d04SAxel Dörfler 
123612966d04SAxel Dörfler void
12371fc4cb1fSAxel Dörfler ScreenWindow::_UpdateColorLabel()
12381fc4cb1fSAxel Dörfler {
12391fc4cb1fSAxel Dörfler 	BString string;
12409c1a9b92SAdrien Destugues 	string << fSelected.BitsPerPixel() << " bits/pixel";
12411fc4cb1fSAxel Dörfler 	fColorsMenu->Superitem()->SetLabel(string.String());
12421fc4cb1fSAxel Dörfler }
12431fc4cb1fSAxel Dörfler 
12441fc4cb1fSAxel Dörfler 
12451fc4cb1fSAxel Dörfler void
12465de171daSAxel Dörfler ScreenWindow::_Apply()
1247a10cf76eSAxel Dörfler {
1248abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
124961c5c89bSAxel Dörfler 	fUndoScreenMode.UpdateOriginalModes();
125061c5c89bSAxel Dörfler 
125107184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
125207184a9eSAxel Dörfler 	if (status == B_OK) {
1253abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1254abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1255abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1256abc649b8SWaldemar Kornewald 		display_mode newMode;
1257abc649b8SWaldemar Kornewald 		BScreen screen(this);
1258abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1259abc649b8SWaldemar Kornewald 
1260abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1261abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1262abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1263abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1264abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1265abc649b8SWaldemar Kornewald 			}
1266199893c3SAxel Dörfler 			fBootWorkspaceApplied = true;
1267199893c3SAxel Dörfler 		} else {
1268199893c3SAxel Dörfler 			if (current_workspace() == 0)
1269199893c3SAxel Dörfler 				fBootWorkspaceApplied = true;
1270abc649b8SWaldemar Kornewald 		}
1271abc649b8SWaldemar Kornewald 
1272a10cf76eSAxel Dörfler 		fActive = fSelected;
1273a10cf76eSAxel Dörfler 
1274abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1275a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1276a10cf76eSAxel Dörfler 		window->Show();
127707184a9eSAxel Dörfler 	} else {
127807184a9eSAxel Dörfler 		char message[256];
127907184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
128007184a9eSAxel Dörfler 			"The screen mode could not be set:\n\t%s\n", screen_errors(status));
12819c1a9b92SAdrien Destugues 		BAlert* alert = new BAlert("Screen Alert", message, "OK", NULL, NULL,
128207184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
128307184a9eSAxel Dörfler 		alert->Go();
1284a10cf76eSAxel Dörfler 	}
128507184a9eSAxel Dörfler }
128607184a9eSAxel Dörfler 
1287