xref: /haiku/src/preferences/screen/ScreenWindow.cpp (revision e6b421a98eee762db7b1c0237e608356a2a26383)
1a10cf76eSAxel Dörfler /*
2b72c4836SAlexandre Deckner  * Copyright 2001-2008, 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 
16a10cf76eSAxel Dörfler #include "AlertWindow.h"
17a10cf76eSAxel Dörfler #include "Constants.h"
18a10cf76eSAxel Dörfler #include "RefreshWindow.h"
19a10cf76eSAxel Dörfler #include "MonitorView.h"
20a10cf76eSAxel Dörfler #include "ScreenSettings.h"
21a10cf76eSAxel Dörfler #include "ScreenWindow.h"
22a10cf76eSAxel Dörfler #include "Utility.h"
23a10cf76eSAxel Dörfler 
24a10cf76eSAxel Dörfler /* Note, this headers defines a *private* interface to the Radeon accelerant.
25a10cf76eSAxel Dörfler  * It's a solution that works with the current BeOS interface that Haiku
26a10cf76eSAxel Dörfler  * adopted.
27a10cf76eSAxel Dörfler  * However, it's not a nice and clean solution. Don't use this header in any
28a10cf76eSAxel Dörfler  * application if you can avoid it. No other driver is using this, or should
29a10cf76eSAxel Dörfler  * be using this.
30a10cf76eSAxel Dörfler  * It will be replaced as soon as we introduce an updated accelerant interface
31a10cf76eSAxel Dörfler  * which may even happen before R1 hits the streets.
32a10cf76eSAxel Dörfler  */
33a10cf76eSAxel Dörfler #include "multimon.h"	// the usual: DANGER WILL, ROBINSON!
34a10cf76eSAxel Dörfler 
3512580984SAxel Dörfler #include <Alert.h>
3612580984SAxel Dörfler #include <Application.h>
3712580984SAxel Dörfler #include <Box.h>
3812580984SAxel Dörfler #include <Button.h>
3912580984SAxel Dörfler #include <Directory.h>
4012580984SAxel Dörfler #include <File.h>
4112580984SAxel Dörfler #include <FindDirectory.h>
4212580984SAxel Dörfler #include <InterfaceDefs.h>
4312580984SAxel Dörfler #include <MenuBar.h>
4412580984SAxel Dörfler #include <MenuItem.h>
4512580984SAxel Dörfler #include <MenuField.h>
4612580984SAxel Dörfler #include <Messenger.h>
4712580984SAxel Dörfler #include <Path.h>
4812580984SAxel Dörfler #include <PopUpMenu.h>
4912580984SAxel Dörfler #include <Screen.h>
5012580984SAxel Dörfler #include <String.h>
5112580984SAxel Dörfler #include <Roster.h>
5212580984SAxel Dörfler #include <Window.h>
5312580984SAxel Dörfler 
5412580984SAxel Dörfler #include <stdio.h>
5512580984SAxel Dörfler #include <stdlib.h>
5612580984SAxel Dörfler #include <string.h>
5712580984SAxel Dörfler 
58a10cf76eSAxel Dörfler 
59c5d80d47SAxel Dörfler const char* kBackgroundsSignature = "application/x-vnd.haiku-backgrounds";
60c5d80d47SAxel Dörfler 
61a10cf76eSAxel Dörfler // list of officially supported colour spaces
62a10cf76eSAxel Dörfler static const struct {
63a10cf76eSAxel Dörfler 	color_space	space;
64a10cf76eSAxel Dörfler 	int32		bits_per_pixel;
65a10cf76eSAxel Dörfler 	const char*	label;
66a10cf76eSAxel Dörfler } kColorSpaces[] = {
67a10cf76eSAxel Dörfler 	{ B_CMAP8, 8, "8 Bits/Pixel, 256 Colors" },
68a10cf76eSAxel Dörfler 	{ B_RGB15, 15, "15 Bits/Pixel, 32768 Colors" },
69a10cf76eSAxel Dörfler 	{ B_RGB16, 16, "16 Bits/Pixel, 65536 Colors" },
70a10cf76eSAxel Dörfler 	{ B_RGB32, 32, "32 Bits/Pixel, 16 Million Colors" }
71a10cf76eSAxel Dörfler };
72a10cf76eSAxel Dörfler static const int32 kColorSpaceCount = sizeof(kColorSpaces) / sizeof(kColorSpaces[0]);
73a10cf76eSAxel Dörfler 
74a10cf76eSAxel Dörfler // list of standard refresh rates
75a796facfSAxel Dörfler static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
76a10cf76eSAxel Dörfler static const int32 kRefreshRateCount = sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
77a10cf76eSAxel Dörfler 
78a10cf76eSAxel Dörfler // list of combine modes
79a10cf76eSAxel Dörfler static const struct {
80a10cf76eSAxel Dörfler 	combine_mode	mode;
81a10cf76eSAxel Dörfler 	const char		*name;
82a10cf76eSAxel Dörfler } kCombineModes[] = {
83a10cf76eSAxel Dörfler 	{ kCombineDisable, "disable" },
84a10cf76eSAxel Dörfler 	{ kCombineHorizontally, "horizontally" },
85a10cf76eSAxel Dörfler 	{ kCombineVertically, "vertically" }
86a10cf76eSAxel Dörfler };
87a10cf76eSAxel Dörfler static const int32 kCombineModeCount = sizeof(kCombineModes) / sizeof(kCombineModes[0]);
88a10cf76eSAxel Dörfler 
8929e8a73aSAxel Dörfler enum {
9029e8a73aSAxel Dörfler 	SHOW_COMBINE_FIELD		= 0x01,
9129e8a73aSAxel Dörfler 	SHOW_SWAP_FIELD			= 0x02,
9229e8a73aSAxel Dörfler 	SHOW_LAPTOP_PANEL_FIELD	= 0x04,
9329e8a73aSAxel Dörfler 	SHOW_TV_STANDARD_FIELD	= 0x08,
9429e8a73aSAxel Dörfler };
9529e8a73aSAxel Dörfler 
96a10cf76eSAxel Dörfler 
97a10cf76eSAxel Dörfler static BString
98a10cf76eSAxel Dörfler tv_standard_to_string(uint32 mode)
99a10cf76eSAxel Dörfler {
100a10cf76eSAxel Dörfler 	switch (mode) {
101a10cf76eSAxel Dörfler 		case 0:		return "disabled";
102a10cf76eSAxel Dörfler 		case 1:		return "NTSC";
103a10cf76eSAxel Dörfler 		case 2:		return "NTSC Japan";
104a10cf76eSAxel Dörfler 		case 3:		return "PAL BDGHI";
105a10cf76eSAxel Dörfler 		case 4:		return "PAL M";
106a10cf76eSAxel Dörfler 		case 5:		return "PAL N";
107a10cf76eSAxel Dörfler 		case 6:		return "SECAM";
108a10cf76eSAxel Dörfler 		case 101:	return "NTSC 443";
109a10cf76eSAxel Dörfler 		case 102:	return "PAL 60";
110a10cf76eSAxel Dörfler 		case 103:	return "PAL NC";
111a10cf76eSAxel Dörfler 		default:
112a10cf76eSAxel Dörfler 		{
113a10cf76eSAxel Dörfler 			BString name;
114a10cf76eSAxel Dörfler 			name << "??? (" << mode << ")";
115a10cf76eSAxel Dörfler 
116a10cf76eSAxel Dörfler 			return name;
117a10cf76eSAxel Dörfler 		}
118a10cf76eSAxel Dörfler 	}
119a10cf76eSAxel Dörfler }
120a10cf76eSAxel Dörfler 
121a10cf76eSAxel Dörfler 
122a10cf76eSAxel Dörfler static void
123a10cf76eSAxel Dörfler resolution_to_string(screen_mode& mode, BString &string)
124a10cf76eSAxel Dörfler {
125a10cf76eSAxel Dörfler 	string << mode.width << " x " << mode.height;
126a10cf76eSAxel Dörfler }
127a10cf76eSAxel Dörfler 
128a10cf76eSAxel Dörfler 
129a10cf76eSAxel Dörfler static void
130a10cf76eSAxel Dörfler refresh_rate_to_string(float refresh, BString &string,
131a10cf76eSAxel Dörfler 	bool appendUnit = true, bool alwaysWithFraction = false)
132a10cf76eSAxel Dörfler {
133a10cf76eSAxel Dörfler 	snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3, refresh);
134a10cf76eSAxel Dörfler 	string.UnlockBuffer();
135a10cf76eSAxel Dörfler 
136a10cf76eSAxel Dörfler 	if (appendUnit)
137a10cf76eSAxel Dörfler 		string << " Hz";
138a10cf76eSAxel Dörfler }
139a10cf76eSAxel Dörfler 
140a10cf76eSAxel Dörfler 
14107184a9eSAxel Dörfler static const char*
14207184a9eSAxel Dörfler screen_errors(status_t status)
14307184a9eSAxel Dörfler {
14407184a9eSAxel Dörfler 	switch (status) {
14507184a9eSAxel Dörfler 		case B_ENTRY_NOT_FOUND:
14607184a9eSAxel Dörfler 			return "Unknown Mode";
14707184a9eSAxel Dörfler 		// TODO: add more?
14807184a9eSAxel Dörfler 
14907184a9eSAxel Dörfler 		default:
15007184a9eSAxel Dörfler 			return strerror(status);
15107184a9eSAxel Dörfler 	}
15207184a9eSAxel Dörfler }
15307184a9eSAxel Dörfler 
15429e8a73aSAxel Dörfler 
15529e8a73aSAxel Dörfler static float
15629e8a73aSAxel Dörfler max_label_width(BMenuField* control, float widestLabel)
15729e8a73aSAxel Dörfler {
15829e8a73aSAxel Dörfler 	float labelWidth = control->StringWidth(control->Label());
15929e8a73aSAxel Dörfler 	if (widestLabel < labelWidth)
16029e8a73aSAxel Dörfler 		return labelWidth;
16129e8a73aSAxel Dörfler 	return widestLabel;
16229e8a73aSAxel Dörfler }
16329e8a73aSAxel Dörfler 
16429e8a73aSAxel Dörfler 
16529e8a73aSAxel Dörfler static BRect
16629e8a73aSAxel Dörfler stack_and_align_menu_fields(const BList& menuFields)
16729e8a73aSAxel Dörfler {
16829e8a73aSAxel Dörfler 	float widestLabel = 0.0;
16929e8a73aSAxel Dörfler 	int32 count = menuFields.CountItems();
17029e8a73aSAxel Dörfler 	for (int32 i = 0; i < count; i++) {
17129e8a73aSAxel Dörfler 		BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
17229e8a73aSAxel Dörfler 		widestLabel = max_label_width(menuField, widestLabel);
17329e8a73aSAxel Dörfler 	}
17429e8a73aSAxel Dörfler 
17529e8a73aSAxel Dörfler 	// add some room (but only if there is text at all)
17629e8a73aSAxel Dörfler 	if (widestLabel > 0.0)
17729e8a73aSAxel Dörfler 		widestLabel += 5.0;
17829e8a73aSAxel Dörfler 
17929e8a73aSAxel Dörfler 	// make all controls the same width
180d1516993SAxel Dörfler 	float widestField = 0.0f;
18129e8a73aSAxel Dörfler 	for (int32 i = 0; i < count; i++) {
18229e8a73aSAxel Dörfler 		BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
183d1516993SAxel Dörfler 		if (widestField == 0.0f) {
184d1516993SAxel Dörfler 			widestField = menuField->StringWidth("9999 x 9999 WWW")
185d1516993SAxel Dörfler 				+ widestLabel;
186d1516993SAxel Dörfler 		}
18729e8a73aSAxel Dörfler 		menuField->SetAlignment(B_ALIGN_RIGHT);
18829e8a73aSAxel Dörfler 		menuField->SetDivider(widestLabel);
18929e8a73aSAxel Dörfler 		menuField->ResizeToPreferred();
19029e8a73aSAxel Dörfler 		widestField = max_c(menuField->Bounds().Width(), widestField);
19129e8a73aSAxel Dörfler 	}
19229e8a73aSAxel Dörfler 
19329e8a73aSAxel Dörfler 	// layout controls under each other, resize all to size
19429e8a73aSAxel Dörfler 	// of largest of them (they could still have different
19529e8a73aSAxel Dörfler 	// heights though)
19629e8a73aSAxel Dörfler 	BMenuField* topMenuField = (BMenuField*)menuFields.FirstItem();
19729e8a73aSAxel Dörfler 	BPoint leftTop = topMenuField->Frame().LeftTop();
19829e8a73aSAxel Dörfler 	BRect frame = topMenuField->Frame();
19929e8a73aSAxel Dörfler 
20029e8a73aSAxel Dörfler 	for (int32 i = 0; i < count; i++) {
20129e8a73aSAxel Dörfler 		BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
20229e8a73aSAxel Dörfler 		menuField->MoveTo(leftTop);
20329e8a73aSAxel Dörfler 		float height = menuField->Bounds().Height();
20429e8a73aSAxel Dörfler 		menuField->ResizeTo(widestField, height);
20529e8a73aSAxel Dörfler 		frame = frame | menuField->Frame();
20629e8a73aSAxel Dörfler 		leftTop.y += height + 5.0;
20729e8a73aSAxel Dörfler 	}
20829e8a73aSAxel Dörfler 
20929e8a73aSAxel Dörfler 	return frame;
21029e8a73aSAxel Dörfler }
211df3f5bacSStephan Aßmus 
212df3f5bacSStephan Aßmus 
2133dfd20c0SStephan Aßmus //	#pragma mark -
2143dfd20c0SStephan Aßmus 
2153dfd20c0SStephan Aßmus 
2165a78744bSAxel Dörfler ScreenWindow::ScreenWindow(ScreenSettings *settings)
2175a78744bSAxel Dörfler 	: BWindow(settings->WindowFrame(), "Screen", B_TITLED_WINDOW,
218a10cf76eSAxel Dörfler 		B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES),
21912580984SAxel Dörfler 	fIsVesa(false),
22012580984SAxel Dörfler 	fVesaApplied(false),
221a10cf76eSAxel Dörfler 	fScreenMode(this),
222abc649b8SWaldemar Kornewald 	fTempScreenMode(this),
223abc649b8SWaldemar Kornewald 	fModified(false)
224a10cf76eSAxel Dörfler {
225a10cf76eSAxel Dörfler 	BScreen screen(this);
226a10cf76eSAxel Dörfler 
22712580984SAxel Dörfler 	accelerant_device_info info;
228d1516993SAxel Dörfler 	if (screen.GetDeviceInfo(&info) == B_OK
229d1516993SAxel Dörfler 		&& !strcasecmp(info.chipset, "VESA"))
23012580984SAxel Dörfler 		fIsVesa = true;
23112580984SAxel Dörfler 
2325de171daSAxel Dörfler 	_UpdateOriginal();
233a10cf76eSAxel Dörfler 	fActive = fSelected = fOriginal;
234a10cf76eSAxel Dörfler 
235df3f5bacSStephan Aßmus 	BView *view = new BView(Bounds(), "ScreenView", B_FOLLOW_ALL, B_WILL_DRAW);
236a10cf76eSAxel Dörfler 	view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
237a10cf76eSAxel Dörfler 	AddChild(view);
238a10cf76eSAxel Dörfler 
2395a78744bSAxel Dörfler 	fSettings = settings;
2405a78744bSAxel Dörfler 
2415a78744bSAxel Dörfler 	// we need the "Current Workspace" first to get its height
2425a78744bSAxel Dörfler 
2435a78744bSAxel Dörfler 	BPopUpMenu *popUpMenu = new BPopUpMenu("Current Workspace", true, true);
244d1516993SAxel Dörfler 	fAllWorkspacesItem = new BMenuItem("All Workspaces",
245d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
2465a78744bSAxel Dörfler 	popUpMenu->AddItem(fAllWorkspacesItem);
247d1516993SAxel Dörfler 	BMenuItem *item = new BMenuItem("Current Workspace",
248d1516993SAxel Dörfler 		new BMessage(WORKSPACE_CHECK_MSG));
249b72c4836SAlexandre Deckner 
250b72c4836SAlexandre Deckner 	// TODO: since per workspace settings is unimplemented (Ticket #693)
251b72c4836SAlexandre Deckner 	// 		 we force the menu to "All Workspaces" for now
252b72c4836SAlexandre Deckner 	//if (_IsVesa()) {
25312580984SAxel Dörfler 		fAllWorkspacesItem->SetMarked(true);
25412580984SAxel Dörfler 		item->SetEnabled(false);
255b72c4836SAlexandre Deckner 	//} else
256b72c4836SAlexandre Deckner 	//	item->SetMarked(true);
257b72c4836SAlexandre Deckner 
2585a78744bSAxel Dörfler 	popUpMenu->AddItem(item);
2595a78744bSAxel Dörfler 
260df3f5bacSStephan Aßmus 	BMenuField* workspaceMenuField = new BMenuField(BRect(0, 0, 100, 15),
2615a78744bSAxel Dörfler 		"WorkspaceMenu", NULL, popUpMenu, true);
2625a78744bSAxel Dörfler 	workspaceMenuField->ResizeToPreferred();
263a10cf76eSAxel Dörfler 
264a10cf76eSAxel Dörfler 	// box on the left with workspace count and monitor view
265a10cf76eSAxel Dörfler 
2665a78744bSAxel Dörfler 	popUpMenu = new BPopUpMenu("", true, true);
267df3f5bacSStephan Aßmus 	fWorkspaceCountField = new BMenuField(BRect(0.0, 0.0, 50.0, 15.0),
268df3f5bacSStephan Aßmus 		"WorkspaceCountMenu", "Workspace count:", popUpMenu, true);
269d1516993SAxel Dörfler 	float labelWidth = fWorkspaceCountField->StringWidth(
270d1516993SAxel Dörfler 		fWorkspaceCountField->Label()) + 5.0;
271df3f5bacSStephan Aßmus 	fWorkspaceCountField->SetDivider(labelWidth);
272df3f5bacSStephan Aßmus 
273df3f5bacSStephan Aßmus 	fScreenBox = new BBox(BRect(0.0, 0.0, 100.0, 100.0), "left box");
274df3f5bacSStephan Aßmus 	fScreenBox->AddChild(fWorkspaceCountField);
275a10cf76eSAxel Dörfler 
276a10cf76eSAxel Dörfler 	for (int32 count = 1; count <= 32; count++) {
277a10cf76eSAxel Dörfler 		BString workspaceCount;
278a10cf76eSAxel Dörfler 		workspaceCount << count;
279a10cf76eSAxel Dörfler 
280a10cf76eSAxel Dörfler 		BMessage *message = new BMessage(POP_WORKSPACE_CHANGED_MSG);
281a10cf76eSAxel Dörfler 		message->AddInt32("workspace count", count);
282a10cf76eSAxel Dörfler 
283a10cf76eSAxel Dörfler 		popUpMenu->AddItem(new BMenuItem(workspaceCount.String(),
284a10cf76eSAxel Dörfler 			message));
285a10cf76eSAxel Dörfler 	}
286a10cf76eSAxel Dörfler 
2875a78744bSAxel Dörfler 	item = popUpMenu->ItemAt(count_workspaces() - 1);
288a10cf76eSAxel Dörfler 	if (item != NULL)
289a10cf76eSAxel Dörfler 		item->SetMarked(true);
290a10cf76eSAxel Dörfler 
291df3f5bacSStephan Aßmus 	fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0, 80.0), "monitor",
2925a78744bSAxel Dörfler 		screen.Frame().Width() + 1, screen.Frame().Height() + 1);
293df3f5bacSStephan Aßmus 	fScreenBox->AddChild(fMonitorView);
2945a78744bSAxel Dörfler 
295df3f5bacSStephan Aßmus 	view->AddChild(fScreenBox);
296a10cf76eSAxel Dörfler 
297a10cf76eSAxel Dörfler 	// box on the right with screen resolution, etc.
298a10cf76eSAxel Dörfler 
299df3f5bacSStephan Aßmus 	fControlsBox = new BBox(BRect(0.0, 0.0, 100.0, 100.0));
300df3f5bacSStephan Aßmus 	fControlsBox->SetLabel(workspaceMenuField);
301a10cf76eSAxel Dörfler 
302a10cf76eSAxel Dörfler 	fResolutionMenu = new BPopUpMenu("resolution", true, true);
303a10cf76eSAxel Dörfler 
304a10cf76eSAxel Dörfler 	uint16 previousWidth = 0, previousHeight = 0;
305a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
306a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
307a10cf76eSAxel Dörfler 
308a10cf76eSAxel Dörfler 		if (mode.width == previousWidth && mode.height == previousHeight)
309a10cf76eSAxel Dörfler 			continue;
310a10cf76eSAxel Dörfler 
311a10cf76eSAxel Dörfler 		previousWidth = mode.width;
312a10cf76eSAxel Dörfler 		previousHeight = mode.height;
313a10cf76eSAxel Dörfler 
314a10cf76eSAxel Dörfler 		BMessage *message = new BMessage(POP_RESOLUTION_MSG);
315a10cf76eSAxel Dörfler 		message->AddInt32("width", mode.width);
316a10cf76eSAxel Dörfler 		message->AddInt32("height", mode.height);
317a10cf76eSAxel Dörfler 
318a10cf76eSAxel Dörfler 		BString name;
319a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
320a10cf76eSAxel Dörfler 
321a10cf76eSAxel Dörfler 		fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
322a10cf76eSAxel Dörfler 	}
323a10cf76eSAxel Dörfler 
32429e8a73aSAxel Dörfler 	BRect rect(0.0, 0.0, 200.0, 15.0);
325df3f5bacSStephan Aßmus 	// fResolutionField needs to be at the correct
326df3f5bacSStephan Aßmus 	// left-top offset, because all other menu fields
327df3f5bacSStephan Aßmus 	// will be layouted relative to it
328df3f5bacSStephan Aßmus 	fResolutionField = new BMenuField(rect.OffsetToCopy(10.0, 30.0),
329d1516993SAxel Dörfler 		"ResolutionMenu", "Resolution:", fResolutionMenu, false);
330df3f5bacSStephan Aßmus 	fControlsBox->AddChild(fResolutionField);
331a10cf76eSAxel Dörfler 
332a10cf76eSAxel Dörfler 	fColorsMenu = new BPopUpMenu("colors", true, true);
333a10cf76eSAxel Dörfler 
334a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
335a10cf76eSAxel Dörfler 		BMessage *message = new BMessage(POP_COLORS_MSG);
336a10cf76eSAxel Dörfler 		message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel);
337a10cf76eSAxel Dörfler 		message->AddInt32("space", kColorSpaces[i].space);
338a10cf76eSAxel Dörfler 
339a10cf76eSAxel Dörfler 		fColorsMenu->AddItem(new BMenuItem(kColorSpaces[i].label, message));
340a10cf76eSAxel Dörfler 	}
341a10cf76eSAxel Dörfler 
342df3f5bacSStephan Aßmus 	rect.OffsetTo(B_ORIGIN);
343df3f5bacSStephan Aßmus 
344d1516993SAxel Dörfler 	fColorsField = new BMenuField(rect, "ColorsMenu", "Colors:", fColorsMenu,
345d1516993SAxel Dörfler 		false);
346df3f5bacSStephan Aßmus 	fControlsBox->AddChild(fColorsField);
347a10cf76eSAxel Dörfler 
348a10cf76eSAxel Dörfler 	fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
349a10cf76eSAxel Dörfler 
35029e8a73aSAxel Dörfler 	BMessage *message;
35129e8a73aSAxel Dörfler 
35229e8a73aSAxel Dörfler 	float min, max;
35329e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
35429e8a73aSAxel Dörfler 		// This is a special case for drivers that only support a single
35529e8a73aSAxel Dörfler 		// frequency, like the VESA driver
35629e8a73aSAxel Dörfler 		BString name;
35729e8a73aSAxel Dörfler 		name << min << " Hz";
35829e8a73aSAxel Dörfler 
35929e8a73aSAxel Dörfler 		message = new BMessage(POP_REFRESH_MSG);
36029e8a73aSAxel Dörfler 		message->AddFloat("refresh", min);
36129e8a73aSAxel Dörfler 
36229e8a73aSAxel Dörfler 		fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
36329e8a73aSAxel Dörfler 		item->SetEnabled(false);
36429e8a73aSAxel Dörfler 	} else {
365a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kRefreshRateCount; ++i) {
366a10cf76eSAxel Dörfler 			BString name;
367a10cf76eSAxel Dörfler 			name << kRefreshRates[i] << " Hz";
368a10cf76eSAxel Dörfler 
36929e8a73aSAxel Dörfler 			message = new BMessage(POP_REFRESH_MSG);
370a10cf76eSAxel Dörfler 			message->AddFloat("refresh", kRefreshRates[i]);
371a10cf76eSAxel Dörfler 
372a10cf76eSAxel Dörfler 			fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
373a10cf76eSAxel Dörfler 		}
374a10cf76eSAxel Dörfler 
37529e8a73aSAxel Dörfler 		message = new BMessage(POP_OTHER_REFRESH_MSG);
376a10cf76eSAxel Dörfler 
377a10cf76eSAxel Dörfler 		fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
378a10cf76eSAxel Dörfler 		fRefreshMenu->AddItem(fOtherRefresh);
37929e8a73aSAxel Dörfler 	}
380a10cf76eSAxel Dörfler 
381d1516993SAxel Dörfler 	fRefreshField = new BMenuField(rect, "RefreshMenu", "Refresh Rate:",
382d1516993SAxel Dörfler 		fRefreshMenu, false);
38312580984SAxel Dörfler 	if (_IsVesa())
38412580984SAxel Dörfler 		fRefreshField->Hide();
385df3f5bacSStephan Aßmus 	fControlsBox->AddChild(fRefreshField);
386a10cf76eSAxel Dörfler 
387df3f5bacSStephan Aßmus 	view->AddChild(fControlsBox);
388df3f5bacSStephan Aßmus 
389df3f5bacSStephan Aßmus 	uint32 controlsFlags = 0;
390a10cf76eSAxel Dörfler 
391a10cf76eSAxel Dörfler 	// enlarged area for multi-monitor settings
392a10cf76eSAxel Dörfler 	{
393a10cf76eSAxel Dörfler 		bool dummy;
394a10cf76eSAxel Dörfler 		uint32 dummy32;
395a10cf76eSAxel Dörfler 		bool multiMonSupport;
396a10cf76eSAxel Dörfler 		bool useLaptopPanelSupport;
397a10cf76eSAxel Dörfler 		bool tvStandardSupport;
398a10cf76eSAxel Dörfler 
399a10cf76eSAxel Dörfler 		multiMonSupport = TestMultiMonSupport(&screen) == B_OK;
400a10cf76eSAxel Dörfler 		useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK;
401a10cf76eSAxel Dörfler 		tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK;
402df3f5bacSStephan Aßmus 		if (multiMonSupport) {
403df3f5bacSStephan Aßmus 			controlsFlags |= SHOW_COMBINE_FIELD;
404df3f5bacSStephan Aßmus 			controlsFlags |= SHOW_SWAP_FIELD;
405df3f5bacSStephan Aßmus 		}
406df3f5bacSStephan Aßmus 		if (useLaptopPanelSupport)
407df3f5bacSStephan Aßmus 			controlsFlags |= SHOW_LAPTOP_PANEL_FIELD;
408a10cf76eSAxel Dörfler 
409a10cf76eSAxel Dörfler 		// even if there is no support, we still create all controls
410a10cf76eSAxel Dörfler 		// to make sure we don't access NULL pointers later on
411a10cf76eSAxel Dörfler 
412a10cf76eSAxel Dörfler 		fCombineMenu = new BPopUpMenu("CombineDisplays", true, true);
413a10cf76eSAxel Dörfler 
414a10cf76eSAxel Dörfler 		for (int32 i = 0; i < kCombineModeCount; i++) {
415a10cf76eSAxel Dörfler 			message = new BMessage(POP_COMBINE_DISPLAYS_MSG);
416a10cf76eSAxel Dörfler 			message->AddInt32("mode", kCombineModes[i].mode);
417a10cf76eSAxel Dörfler 
418d1516993SAxel Dörfler 			fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name,
419d1516993SAxel Dörfler 				message));
420a10cf76eSAxel Dörfler 		}
421a10cf76eSAxel Dörfler 
422df3f5bacSStephan Aßmus 		fCombineField = new BMenuField(rect, "CombineMenu",
423d1516993SAxel Dörfler 			"Combine Displays:", fCombineMenu, false);
424df3f5bacSStephan Aßmus 		fControlsBox->AddChild(fCombineField);
425a10cf76eSAxel Dörfler 
426a10cf76eSAxel Dörfler 		if (!multiMonSupport)
427df3f5bacSStephan Aßmus 			fCombineField->Hide();
428a10cf76eSAxel Dörfler 
429a10cf76eSAxel Dörfler 		fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", true, true);
430a10cf76eSAxel Dörfler 
431a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
432a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
433a10cf76eSAxel Dörfler 		message->AddBool("swap", false);
434a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("no", message));
435a10cf76eSAxel Dörfler 
436a10cf76eSAxel Dörfler 		message = new BMessage(POP_SWAP_DISPLAYS_MSG);
437a10cf76eSAxel Dörfler 		message->AddBool("swap", true);
438a10cf76eSAxel Dörfler 		fSwapDisplaysMenu->AddItem(new BMenuItem("yes", message));
439a10cf76eSAxel Dörfler 
440df3f5bacSStephan Aßmus 		fSwapDisplaysField = new BMenuField(rect, "SwapMenu", "Swap Displays:",
441d1516993SAxel Dörfler 			fSwapDisplaysMenu, false);
442a10cf76eSAxel Dörfler 
443df3f5bacSStephan Aßmus 		fControlsBox->AddChild(fSwapDisplaysField);
444a10cf76eSAxel Dörfler 		if (!multiMonSupport)
445df3f5bacSStephan Aßmus 			fSwapDisplaysField->Hide();
446a10cf76eSAxel Dörfler 
447a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", true, true);
448a10cf76eSAxel Dörfler 
449a10cf76eSAxel Dörfler 		// !order is important - we rely that boolean value == idx
450a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
451a10cf76eSAxel Dörfler 		message->AddBool("use", false);
452a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("if needed", message));
453a10cf76eSAxel Dörfler 
454a10cf76eSAxel Dörfler 		message = new BMessage(POP_USE_LAPTOP_PANEL_MSG);
455a10cf76eSAxel Dörfler 		message->AddBool("use", true);
456a10cf76eSAxel Dörfler 		fUseLaptopPanelMenu->AddItem(new BMenuItem("always", message));
457a10cf76eSAxel Dörfler 
458d1516993SAxel Dörfler 		fUseLaptopPanelField = new BMenuField(rect, "UseLaptopPanel",
459d1516993SAxel Dörfler 			"Use Laptop Panel:", fUseLaptopPanelMenu, false);
460a10cf76eSAxel Dörfler 
461df3f5bacSStephan Aßmus 		fControlsBox->AddChild(fUseLaptopPanelField);
462a10cf76eSAxel Dörfler 		if (!useLaptopPanelSupport)
463df3f5bacSStephan Aßmus 			fUseLaptopPanelField->Hide();
464a10cf76eSAxel Dörfler 
465a10cf76eSAxel Dörfler 		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 
482df3f5bacSStephan Aßmus 		fTVStandardField = new BMenuField(rect, "tv standard", "Video Format:",
483d1516993SAxel Dörfler 			fTVStandardMenu, false);
484df3f5bacSStephan Aßmus 		fTVStandardField->SetAlignment(B_ALIGN_RIGHT);
485a10cf76eSAxel Dörfler 
486df3f5bacSStephan Aßmus 		if (!tvStandardSupport || i == 0) {
487df3f5bacSStephan Aßmus 			fTVStandardField->Hide();
488df3f5bacSStephan Aßmus 		} else {
489df3f5bacSStephan Aßmus 			controlsFlags |= SHOW_TV_STANDARD_FIELD;
490a10cf76eSAxel Dörfler 		}
491a10cf76eSAxel Dörfler 
492df3f5bacSStephan Aßmus 		fControlsBox->AddChild(fTVStandardField);
493df3f5bacSStephan Aßmus 	}
494df3f5bacSStephan Aßmus 
495df3f5bacSStephan Aßmus 	BRect buttonRect(0.0, 0.0, 30.0, 10.0);
496df3f5bacSStephan Aßmus 	fBackgroundsButton = new BButton(buttonRect, "BackgroundsButton",
497d1516993SAxel Dörfler 		"Set Background"B_UTF8_ELLIPSIS,
498d1516993SAxel Dörfler 		new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG));
4993dfd20c0SStephan Aßmus 	fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9);
500df3f5bacSStephan Aßmus 	fScreenBox->AddChild(fBackgroundsButton);
501df3f5bacSStephan Aßmus 
502abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
503abc649b8SWaldemar Kornewald 	/* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults",
504a10cf76eSAxel Dörfler 		new BMessage(BUTTON_DEFAULTS_MSG));
505abc649b8SWaldemar Kornewald 	view->AddChild(fDefaultsButton); */
506a10cf76eSAxel Dörfler 
507df3f5bacSStephan Aßmus 	fRevertButton = new BButton(buttonRect, "RevertButton", "Revert",
508a10cf76eSAxel Dörfler 		new BMessage(BUTTON_REVERT_MSG));
509a10cf76eSAxel Dörfler 	fRevertButton->SetEnabled(false);
510a10cf76eSAxel Dörfler 	view->AddChild(fRevertButton);
511a10cf76eSAxel Dörfler 
512df3f5bacSStephan Aßmus 	fApplyButton = new BButton(buttonRect, "ApplyButton", "Apply",
513df3f5bacSStephan Aßmus 		new BMessage(BUTTON_APPLY_MSG));
514df3f5bacSStephan Aßmus 	fApplyButton->SetEnabled(false);
515abc649b8SWaldemar Kornewald 	fControlsBox->AddChild(fApplyButton);
5165a78744bSAxel Dörfler 
5175de171daSAxel Dörfler 	_UpdateControls();
518df3f5bacSStephan Aßmus 
5195de171daSAxel Dörfler 	_LayoutControls(controlsFlags);
520a10cf76eSAxel Dörfler }
521a10cf76eSAxel Dörfler 
522a10cf76eSAxel Dörfler 
523a10cf76eSAxel Dörfler ScreenWindow::~ScreenWindow()
524a10cf76eSAxel Dörfler {
525a10cf76eSAxel Dörfler 	delete fSettings;
526a10cf76eSAxel Dörfler }
527a10cf76eSAxel Dörfler 
528a10cf76eSAxel Dörfler 
529a10cf76eSAxel Dörfler bool
530a10cf76eSAxel Dörfler ScreenWindow::QuitRequested()
531a10cf76eSAxel Dörfler {
532a10cf76eSAxel Dörfler 	fSettings->SetWindowFrame(Frame());
53312580984SAxel Dörfler 	if (fVesaApplied) {
53412580984SAxel Dörfler 		status_t status = _WriteVesaModeFile(fSelected);
53512580984SAxel Dörfler 		if (status < B_OK) {
53612580984SAxel Dörfler 			BString warning = "Could not write VESA mode settings file:\n\t";
53712580984SAxel Dörfler 			warning << strerror(status);
53812580984SAxel Dörfler 			(new BAlert("VesaAlert", warning.String(), "Okay", NULL, NULL,
53912580984SAxel Dörfler 				B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
54012580984SAxel Dörfler 
54112580984SAxel Dörfler 		}
54212580984SAxel Dörfler 	}
54312580984SAxel Dörfler 
544a10cf76eSAxel Dörfler 	be_app->PostMessage(B_QUIT_REQUESTED);
545a10cf76eSAxel Dörfler 
546a10cf76eSAxel Dörfler 	return BWindow::QuitRequested();
547a10cf76eSAxel Dörfler }
548a10cf76eSAxel Dörfler 
549a10cf76eSAxel Dörfler 
5505de171daSAxel Dörfler /*!	Update resolution list according to combine mode
5515de171daSAxel Dörfler 	(some resolution may not be combinable due to memory restrictions)
552a10cf76eSAxel Dörfler */
553a10cf76eSAxel Dörfler void
5545de171daSAxel Dörfler ScreenWindow::_CheckResolutionMenu()
555a10cf76eSAxel Dörfler {
556a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fResolutionMenu->CountItems(); i++)
557a10cf76eSAxel Dörfler 		fResolutionMenu->ItemAt(i)->SetEnabled(false);
558a10cf76eSAxel Dörfler 
559a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fScreenMode.CountModes(); i++) {
560a10cf76eSAxel Dörfler 		screen_mode mode = fScreenMode.ModeAt(i);
561a10cf76eSAxel Dörfler 		if (mode.combine != fSelected.combine)
562a10cf76eSAxel Dörfler 			continue;
563a10cf76eSAxel Dörfler 
564a10cf76eSAxel Dörfler 		BString name;
565a10cf76eSAxel Dörfler 		name << mode.width << " x " << mode.height;
566a10cf76eSAxel Dörfler 
567a10cf76eSAxel Dörfler 		BMenuItem *item = fResolutionMenu->FindItem(name.String());
568a10cf76eSAxel Dörfler 		if (item != NULL)
569a10cf76eSAxel Dörfler 			item->SetEnabled(true);
570a10cf76eSAxel Dörfler 	}
571a10cf76eSAxel Dörfler }
572a10cf76eSAxel Dörfler 
573a10cf76eSAxel Dörfler 
5745de171daSAxel Dörfler /*!	Update color and refresh options according to current mode
5755de171daSAxel Dörfler 	(a color space is made active if there is any mode with
5765de171daSAxel Dörfler 	given resolution and this colour space; same applies for
5775de171daSAxel Dörfler 	refresh rate, though "Other…" is always possible)
578a10cf76eSAxel Dörfler */
579a10cf76eSAxel Dörfler void
5805de171daSAxel Dörfler ScreenWindow::_CheckColorMenu()
581a10cf76eSAxel Dörfler {
582a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kColorSpaceCount; i++) {
583a10cf76eSAxel Dörfler 		bool supported = false;
584a10cf76eSAxel Dörfler 
585a10cf76eSAxel Dörfler 		for (int32 j = 0; j < fScreenMode.CountModes(); j++) {
586a10cf76eSAxel Dörfler 			screen_mode mode = fScreenMode.ModeAt(j);
587a10cf76eSAxel Dörfler 
588a10cf76eSAxel Dörfler 			if (fSelected.width == mode.width
589a10cf76eSAxel Dörfler 				&& fSelected.height == mode.height
5905de171daSAxel Dörfler 				&& (kColorSpaces[i].space == mode.space
5915de171daSAxel Dörfler 					// advertize 24 bit mode as 32 bit to avoid confusion
5925de171daSAxel Dörfler 					|| (kColorSpaces[i].space == B_RGB32
5935de171daSAxel Dörfler 						&& mode.space == B_RGB24))
594a10cf76eSAxel Dörfler 				&& fSelected.combine == mode.combine) {
595a10cf76eSAxel Dörfler 				supported = true;
596a10cf76eSAxel Dörfler 				break;
597a10cf76eSAxel Dörfler 			}
598a10cf76eSAxel Dörfler 		}
599a10cf76eSAxel Dörfler 
600a10cf76eSAxel Dörfler 		BMenuItem* item = fColorsMenu->ItemAt(i);
601a10cf76eSAxel Dörfler 		if (item)
602a10cf76eSAxel Dörfler 			item->SetEnabled(supported);
603a10cf76eSAxel Dörfler 	}
604a10cf76eSAxel Dörfler }
605a10cf76eSAxel Dörfler 
606a10cf76eSAxel Dörfler 
6075de171daSAxel Dörfler /*!	Enable/disable refresh options according to current mode. */
608a10cf76eSAxel Dörfler void
6095de171daSAxel Dörfler ScreenWindow::_CheckRefreshMenu()
610a10cf76eSAxel Dörfler {
61129e8a73aSAxel Dörfler 	float min, max;
61229e8a73aSAxel Dörfler 	if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
61329e8a73aSAxel Dörfler 		return;
614a10cf76eSAxel Dörfler 
61529e8a73aSAxel Dörfler 	for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
61629e8a73aSAxel Dörfler 		BMenuItem* item = fRefreshMenu->ItemAt(i);
61729e8a73aSAxel Dörfler 		BMessage* message = item->Message();
61829e8a73aSAxel Dörfler 		float refresh;
61929e8a73aSAxel Dörfler 		if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
62029e8a73aSAxel Dörfler 			item->SetEnabled(refresh >= min && refresh <= max);
621a10cf76eSAxel Dörfler 	}
622a10cf76eSAxel Dörfler }
623a10cf76eSAxel Dörfler 
624a10cf76eSAxel Dörfler 
6255de171daSAxel Dörfler /*!	Activate appropriate menu item according to selected refresh rate */
626a10cf76eSAxel Dörfler void
6275de171daSAxel Dörfler ScreenWindow::_UpdateRefreshControl()
628a10cf76eSAxel Dörfler {
629a10cf76eSAxel Dörfler 	BString string;
630a10cf76eSAxel Dörfler 	refresh_rate_to_string(fSelected.refresh, string);
631a10cf76eSAxel Dörfler 
632a10cf76eSAxel Dörfler 	BMenuItem* item = fRefreshMenu->FindItem(string.String());
633a10cf76eSAxel Dörfler 	if (item) {
634a10cf76eSAxel Dörfler 		if (!item->IsMarked())
635a10cf76eSAxel Dörfler 			item->SetMarked(true);
63629e8a73aSAxel Dörfler 
637a10cf76eSAxel Dörfler 		// "Other…" items only contains a refresh rate when active
638*e6b421a9SJérôme Duval 		fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
639a10cf76eSAxel Dörfler 		return;
640a10cf76eSAxel Dörfler 	}
641a10cf76eSAxel Dörfler 
642a10cf76eSAxel Dörfler 	// this is a non-standard refresh rate
643a10cf76eSAxel Dörfler 
644a10cf76eSAxel Dörfler 	fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh);
645a10cf76eSAxel Dörfler 	fOtherRefresh->SetMarked(true);
646a10cf76eSAxel Dörfler 
647a10cf76eSAxel Dörfler 	fRefreshMenu->Superitem()->SetLabel(string.String());
648a10cf76eSAxel Dörfler 
649a10cf76eSAxel Dörfler 	string.Append("/Other" B_UTF8_ELLIPSIS);
650a10cf76eSAxel Dörfler 	fOtherRefresh->SetLabel(string.String());
651a10cf76eSAxel Dörfler }
652a10cf76eSAxel Dörfler 
653a10cf76eSAxel Dörfler 
654a10cf76eSAxel Dörfler void
6555de171daSAxel Dörfler ScreenWindow::_UpdateMonitorView()
656a10cf76eSAxel Dörfler {
657a10cf76eSAxel Dörfler 	BMessage updateMessage(UPDATE_DESKTOP_MSG);
658a10cf76eSAxel Dörfler 	updateMessage.AddInt32("width", fSelected.width);
659a10cf76eSAxel Dörfler 	updateMessage.AddInt32("height", fSelected.height);
660a10cf76eSAxel Dörfler 
661a10cf76eSAxel Dörfler 	PostMessage(&updateMessage, fMonitorView);
662a10cf76eSAxel Dörfler }
663a10cf76eSAxel Dörfler 
664a10cf76eSAxel Dörfler 
665a10cf76eSAxel Dörfler void
6665de171daSAxel Dörfler ScreenWindow::_UpdateControls()
667a10cf76eSAxel Dörfler {
668a10cf76eSAxel Dörfler 	BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays);
669a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
670a10cf76eSAxel Dörfler 		item->SetMarked(true);
671a10cf76eSAxel Dörfler 
672a10cf76eSAxel Dörfler 	item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel);
673a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
674a10cf76eSAxel Dörfler 		item->SetMarked(true);
675a10cf76eSAxel Dörfler 
676a10cf76eSAxel Dörfler 	for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) {
677a10cf76eSAxel Dörfler 		item = fTVStandardMenu->ItemAt(i);
678a10cf76eSAxel Dörfler 
679a10cf76eSAxel Dörfler 		uint32 tvStandard;
680a10cf76eSAxel Dörfler 		item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard);
681a10cf76eSAxel Dörfler 		if (tvStandard == fSelected.tv_standard) {
682a10cf76eSAxel Dörfler 			if (!item->IsMarked())
683a10cf76eSAxel Dörfler 				item->SetMarked(true);
684a10cf76eSAxel Dörfler 			break;
685a10cf76eSAxel Dörfler 		}
686a10cf76eSAxel Dörfler 	}
687a10cf76eSAxel Dörfler 
6885de171daSAxel Dörfler 	_CheckResolutionMenu();
6895de171daSAxel Dörfler 	_CheckColorMenu();
6905de171daSAxel Dörfler 	_CheckRefreshMenu();
691a10cf76eSAxel Dörfler 
692a10cf76eSAxel Dörfler 	BString string;
693a10cf76eSAxel Dörfler 	resolution_to_string(fSelected, string);
694a10cf76eSAxel Dörfler 	item = fResolutionMenu->FindItem(string.String());
695a10cf76eSAxel Dörfler 
696a10cf76eSAxel Dörfler 	if (item != NULL) {
697a10cf76eSAxel Dörfler 		if (!item->IsMarked())
698a10cf76eSAxel Dörfler 			item->SetMarked(true);
699a10cf76eSAxel Dörfler 	} else {
700a10cf76eSAxel Dörfler 		// this is bad luck - if mode has been set via screen references,
701a10cf76eSAxel Dörfler 		// this case cannot occur; there are three possible solutions:
702a10cf76eSAxel Dörfler 		// 1. add a new resolution to list
703a10cf76eSAxel Dörfler 		//    - we had to remove it as soon as a "valid" one is selected
704a10cf76eSAxel Dörfler 		//    - we don't know which frequencies/bit depths are supported
705a10cf76eSAxel Dörfler 		//    - as long as we haven't the GMT formula to create
706a10cf76eSAxel Dörfler 		//      parameters for any resolution given, we cannot
707a10cf76eSAxel Dörfler 		//      really set current mode - it's just not in the list
708a10cf76eSAxel Dörfler 		// 2. choose nearest resolution
709a10cf76eSAxel Dörfler 		//    - probably a good idea, but implies coding and testing
710a10cf76eSAxel Dörfler 		// 3. choose lowest resolution
711a10cf76eSAxel Dörfler 		//    - do you really think we are so lazy? yes, we are
712a10cf76eSAxel Dörfler 		item = fResolutionMenu->ItemAt(0);
713a10cf76eSAxel Dörfler 		if (item)
714a10cf76eSAxel Dörfler 			item->SetMarked(true);
715a10cf76eSAxel Dörfler 
716a10cf76eSAxel Dörfler 		// okay - at least we set menu label to active resolution
717a10cf76eSAxel Dörfler 		fResolutionMenu->Superitem()->SetLabel(string.String());
718a10cf76eSAxel Dörfler 	}
719a10cf76eSAxel Dörfler 
720a10cf76eSAxel Dörfler 	// mark active combine mode
721a10cf76eSAxel Dörfler 	for (int32 i = 0; i < kCombineModeCount; i++) {
722a10cf76eSAxel Dörfler 		if (kCombineModes[i].mode == fSelected.combine) {
723a10cf76eSAxel Dörfler 			item = fCombineMenu->ItemAt(i);
724a10cf76eSAxel Dörfler 			if (item && !item->IsMarked())
725a10cf76eSAxel Dörfler 				item->SetMarked(true);
726a10cf76eSAxel Dörfler 			break;
727a10cf76eSAxel Dörfler 		}
728a10cf76eSAxel Dörfler 	}
729a10cf76eSAxel Dörfler 
730a10cf76eSAxel Dörfler 	item = fColorsMenu->ItemAt(0);
731a10cf76eSAxel Dörfler 
732a10cf76eSAxel Dörfler 	for (int32 i = kColorSpaceCount; i-- > 0;) {
7335de171daSAxel Dörfler 		if (kColorSpaces[i].space == fSelected.space
7345de171daSAxel Dörfler 			|| (kColorSpaces[i].space == B_RGB32
7355de171daSAxel Dörfler 				&& fSelected.space == B_RGB24)) {
736a10cf76eSAxel Dörfler 			item = fColorsMenu->ItemAt(i);
737a10cf76eSAxel Dörfler 			break;
738a10cf76eSAxel Dörfler 		}
739a10cf76eSAxel Dörfler 	}
740a10cf76eSAxel Dörfler 
741a10cf76eSAxel Dörfler 	if (item && !item->IsMarked())
742a10cf76eSAxel Dörfler 		item->SetMarked(true);
743a10cf76eSAxel Dörfler 
744a10cf76eSAxel Dörfler 	string.Truncate(0);
7455de171daSAxel Dörfler 	uint32 bitsPerPixel = fSelected.BitsPerPixel();
7465de171daSAxel Dörfler 	// advertize 24 bit mode as 32 bit to avoid confusion
7475de171daSAxel Dörfler 	if (bitsPerPixel == 24)
7485de171daSAxel Dörfler 		bitsPerPixel = 32;
7495de171daSAxel Dörfler 
7505de171daSAxel Dörfler 	string << bitsPerPixel << " Bits/Pixel";
751a10cf76eSAxel Dörfler 	if (string != fColorsMenu->Superitem()->Label())
752a10cf76eSAxel Dörfler 		fColorsMenu->Superitem()->SetLabel(string.String());
753a10cf76eSAxel Dörfler 
7545de171daSAxel Dörfler 	_UpdateMonitorView();
7555de171daSAxel Dörfler 	_UpdateRefreshControl();
756a10cf76eSAxel Dörfler 
7575de171daSAxel Dörfler 	_CheckApplyEnabled();
758a10cf76eSAxel Dörfler }
759a10cf76eSAxel Dörfler 
760a10cf76eSAxel Dörfler 
76112580984SAxel Dörfler /*! Reflect active mode in chosen settings */
762a10cf76eSAxel Dörfler void
7635de171daSAxel Dörfler ScreenWindow::_UpdateActiveMode()
764a10cf76eSAxel Dörfler {
76512580984SAxel Dörfler 	// Usually, this function gets called after a mode
766a10cf76eSAxel Dörfler 	// has been set manually; still, as the graphics driver
767a10cf76eSAxel Dörfler 	// is free to fiddle with mode passed, we better ask
768a10cf76eSAxel Dörfler 	// what kind of mode we actually got
76912580984SAxel Dörfler 	if (!fVesaApplied)
770a10cf76eSAxel Dörfler 		fScreenMode.Get(fActive);
771a10cf76eSAxel Dörfler 	fSelected = fActive;
772a10cf76eSAxel Dörfler 
7735de171daSAxel Dörfler 	_UpdateControls();
774a10cf76eSAxel Dörfler }
775a10cf76eSAxel Dörfler 
776a10cf76eSAxel Dörfler 
777a10cf76eSAxel Dörfler void
778a10cf76eSAxel Dörfler ScreenWindow::ScreenChanged(BRect frame, color_space mode)
779a10cf76eSAxel Dörfler {
780a10cf76eSAxel Dörfler 	// move window on screen, if necessary
781a10cf76eSAxel Dörfler 	if (frame.right <= Frame().right
782a10cf76eSAxel Dörfler 		&& frame.bottom <= Frame().bottom) {
783a10cf76eSAxel Dörfler 		MoveTo((frame.Width() - Frame().Width()) / 2,
784a10cf76eSAxel Dörfler 			(frame.Height() - Frame().Height()) / 2);
785a10cf76eSAxel Dörfler 	}
786a10cf76eSAxel Dörfler }
787a10cf76eSAxel Dörfler 
788a10cf76eSAxel Dörfler 
789a10cf76eSAxel Dörfler void
790a10cf76eSAxel Dörfler ScreenWindow::WorkspaceActivated(int32 workspace, bool state)
791a10cf76eSAxel Dörfler {
792b72c4836SAlexandre Deckner 	if (!_IsVesa()) {
793abc649b8SWaldemar Kornewald 		fScreenMode.GetOriginalMode(fOriginal, workspace);
7945de171daSAxel Dörfler 		_UpdateActiveMode();
795b72c4836SAlexandre Deckner 	}
796a10cf76eSAxel Dörfler 
7976edaa0f6SStefano Ceccherini 	BMessage message(UPDATE_DESKTOP_COLOR_MSG);
7986edaa0f6SStefano Ceccherini 	PostMessage(&message, fMonitorView);
799a10cf76eSAxel Dörfler }
800a10cf76eSAxel Dörfler 
801a10cf76eSAxel Dörfler 
802a10cf76eSAxel Dörfler void
803a10cf76eSAxel Dörfler ScreenWindow::MessageReceived(BMessage* message)
804a10cf76eSAxel Dörfler {
805a10cf76eSAxel Dörfler 	switch (message->what) {
806a10cf76eSAxel Dörfler 		case WORKSPACE_CHECK_MSG:
8075de171daSAxel Dörfler 			_CheckApplyEnabled();
808a10cf76eSAxel Dörfler 			break;
809a10cf76eSAxel Dörfler 
810a10cf76eSAxel Dörfler 		case POP_WORKSPACE_CHANGED_MSG:
811a10cf76eSAxel Dörfler 		{
812abc649b8SWaldemar Kornewald 			// update checkpoint state
813a10cf76eSAxel Dörfler 			int32 index;
814abc649b8SWaldemar Kornewald 			if (message->FindInt32("index", &index) == B_OK) {
815a10cf76eSAxel Dörfler 				set_workspace_count(index + 1);
8165de171daSAxel Dörfler 				_CheckApplyEnabled();
817abc649b8SWaldemar Kornewald 			}
818a10cf76eSAxel Dörfler 			break;
819a10cf76eSAxel Dörfler 		}
820a10cf76eSAxel Dörfler 
821a10cf76eSAxel Dörfler 		case POP_RESOLUTION_MSG:
822a10cf76eSAxel Dörfler 		{
823a10cf76eSAxel Dörfler 			message->FindInt32("width", &fSelected.width);
824a10cf76eSAxel Dörfler 			message->FindInt32("height", &fSelected.height);
825a10cf76eSAxel Dörfler 
8265de171daSAxel Dörfler 			_CheckColorMenu();
8275de171daSAxel Dörfler 			_CheckRefreshMenu();
828a10cf76eSAxel Dörfler 
8295de171daSAxel Dörfler 			_UpdateMonitorView();
8305de171daSAxel Dörfler 			_UpdateRefreshControl();
831a10cf76eSAxel Dörfler 
8325de171daSAxel Dörfler 			_CheckApplyEnabled();
833a10cf76eSAxel Dörfler 			break;
834a10cf76eSAxel Dörfler 		}
835a10cf76eSAxel Dörfler 
836a10cf76eSAxel Dörfler 		case POP_COLORS_MSG:
837a10cf76eSAxel Dörfler 		{
838a10cf76eSAxel Dörfler 			message->FindInt32("space", (int32 *)&fSelected.space);
839a10cf76eSAxel Dörfler 
840a10cf76eSAxel Dörfler 			BString string;
841a10cf76eSAxel Dörfler 			string << fSelected.BitsPerPixel() << " Bits/Pixel";
842a10cf76eSAxel Dörfler 			fColorsMenu->Superitem()->SetLabel(string.String());
843a10cf76eSAxel Dörfler 
8445de171daSAxel Dörfler 			_CheckApplyEnabled();
845a10cf76eSAxel Dörfler 			break;
846a10cf76eSAxel Dörfler 		}
847a10cf76eSAxel Dörfler 
848a10cf76eSAxel Dörfler 		case POP_REFRESH_MSG:
849a40498e2SWaldemar Kornewald 		{
850a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
851a10cf76eSAxel Dörfler 			fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS);
852a10cf76eSAxel Dörfler 				// revert "Other…" label - it might have had a refresh rate prefix
853a10cf76eSAxel Dörfler 
8545de171daSAxel Dörfler 			_CheckApplyEnabled();
855a10cf76eSAxel Dörfler 			break;
856a40498e2SWaldemar Kornewald 		}
857a10cf76eSAxel Dörfler 
858a10cf76eSAxel Dörfler 		case POP_OTHER_REFRESH_MSG:
859a10cf76eSAxel Dörfler 		{
86029e8a73aSAxel Dörfler 			// make sure menu shows something useful
8615de171daSAxel Dörfler 			_UpdateRefreshControl();
862a10cf76eSAxel Dörfler 
86329e8a73aSAxel Dörfler 			float min = 0, max = 999;
86429e8a73aSAxel Dörfler 			fScreenMode.GetRefreshLimits(fSelected, min, max);
86529e8a73aSAxel Dörfler 			if (min < gMinRefresh)
86629e8a73aSAxel Dörfler 				min = gMinRefresh;
86729e8a73aSAxel Dörfler 			if (max > gMaxRefresh)
86829e8a73aSAxel Dörfler 				max = gMaxRefresh;
86929e8a73aSAxel Dörfler 
870c5d10f7aSAxel Dörfler 			RefreshWindow *fRefreshWindow = new RefreshWindow(
871c5d10f7aSAxel Dörfler 				fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh, min, max);
872a10cf76eSAxel Dörfler 			fRefreshWindow->Show();
873a10cf76eSAxel Dörfler 			break;
874a10cf76eSAxel Dörfler 		}
875a10cf76eSAxel Dörfler 
876a10cf76eSAxel Dörfler 		case SET_CUSTOM_REFRESH_MSG:
877a10cf76eSAxel Dörfler 		{
878a10cf76eSAxel Dörfler 			// user pressed "done" in "Other…" refresh dialog;
879a10cf76eSAxel Dörfler 			// select the refresh rate chosen
880a10cf76eSAxel Dörfler 			message->FindFloat("refresh", &fSelected.refresh);
881a10cf76eSAxel Dörfler 
8825de171daSAxel Dörfler 			_UpdateRefreshControl();
8835de171daSAxel Dörfler 			_CheckApplyEnabled();
884a10cf76eSAxel Dörfler 			break;
885a10cf76eSAxel Dörfler 		}
886a10cf76eSAxel Dörfler 
887a10cf76eSAxel Dörfler 		case POP_COMBINE_DISPLAYS_MSG:
888a10cf76eSAxel Dörfler 		{
889a10cf76eSAxel Dörfler 			// new combine mode has bee chosen
890a10cf76eSAxel Dörfler 			int32 mode;
891a10cf76eSAxel Dörfler 			if (message->FindInt32("mode", &mode) == B_OK)
892a10cf76eSAxel Dörfler 				fSelected.combine = (combine_mode)mode;
893a10cf76eSAxel Dörfler 
8945de171daSAxel Dörfler 			_CheckResolutionMenu();
8955de171daSAxel Dörfler 			_CheckApplyEnabled();
896a10cf76eSAxel Dörfler 			break;
897a10cf76eSAxel Dörfler 		}
898a10cf76eSAxel Dörfler 
899a10cf76eSAxel Dörfler 		case POP_SWAP_DISPLAYS_MSG:
900a10cf76eSAxel Dörfler 			message->FindBool("swap", &fSelected.swap_displays);
9015de171daSAxel Dörfler 			_CheckApplyEnabled();
902a10cf76eSAxel Dörfler 			break;
903a10cf76eSAxel Dörfler 
904a10cf76eSAxel Dörfler 		case POP_USE_LAPTOP_PANEL_MSG:
905a10cf76eSAxel Dörfler 			message->FindBool("use", &fSelected.use_laptop_panel);
9065de171daSAxel Dörfler 			_CheckApplyEnabled();
907a10cf76eSAxel Dörfler 			break;
908a10cf76eSAxel Dörfler 
909a10cf76eSAxel Dörfler 		case POP_TV_STANDARD_MSG:
910a10cf76eSAxel Dörfler 			message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard);
9115de171daSAxel Dörfler 			_CheckApplyEnabled();
912a10cf76eSAxel Dörfler 			break;
913a10cf76eSAxel Dörfler 
914df3f5bacSStephan Aßmus 		case BUTTON_LAUNCH_BACKGROUNDS_MSG:
9156f095d6aSRyan Leavengood 			if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) {
9166f095d6aSRyan Leavengood 				app_info info;
9176f095d6aSRyan Leavengood 				be_roster->GetAppInfo(kBackgroundsSignature, &info);
9186f095d6aSRyan Leavengood 				be_roster->ActivateApp(info.team);
9196f095d6aSRyan Leavengood 			}
920df3f5bacSStephan Aßmus 			break;
921df3f5bacSStephan Aßmus 
922a10cf76eSAxel Dörfler 		case BUTTON_DEFAULTS_MSG:
923a10cf76eSAxel Dörfler 		{
9244be51fe3SWaldemar Kornewald 			// TODO: get preferred settings of screen
925a10cf76eSAxel Dörfler 			fSelected.width = 640;
926a10cf76eSAxel Dörfler 			fSelected.height = 480;
927a10cf76eSAxel Dörfler 			fSelected.space = B_CMAP8;
928a10cf76eSAxel Dörfler 			fSelected.refresh = 60.0;
929a10cf76eSAxel Dörfler 			fSelected.combine = kCombineDisable;
930a10cf76eSAxel Dörfler 			fSelected.swap_displays = false;
931a10cf76eSAxel Dörfler 			fSelected.use_laptop_panel = false;
932a10cf76eSAxel Dörfler 			fSelected.tv_standard = 0;
933a10cf76eSAxel Dörfler 
934abc649b8SWaldemar Kornewald 			BMenuItem *item;
935abc649b8SWaldemar Kornewald 			item = fWorkspaceCountField->Menu()->ItemAt(3);
936abc649b8SWaldemar Kornewald 			if (item != NULL)
937abc649b8SWaldemar Kornewald 				item->SetMarked(true);
938abc649b8SWaldemar Kornewald 
9395de171daSAxel Dörfler 			_UpdateControls();
940a10cf76eSAxel Dörfler 			break;
941a10cf76eSAxel Dörfler 		}
942a10cf76eSAxel Dörfler 
94310e9b12fSWaldemar Kornewald 		case BUTTON_UNDO_MSG:
944abc649b8SWaldemar Kornewald 			fTempScreenMode.Revert();
9455de171daSAxel Dörfler 			_UpdateActiveMode();
946abc649b8SWaldemar Kornewald 			break;
947abc649b8SWaldemar Kornewald 
948abc649b8SWaldemar Kornewald 		case BUTTON_REVERT_MSG:
949abc649b8SWaldemar Kornewald 		{
950abc649b8SWaldemar Kornewald 			fModified = false;
951b72c4836SAlexandre Deckner 			fVesaApplied = false;
952abc649b8SWaldemar Kornewald 			BMenuItem *item;
953abc649b8SWaldemar Kornewald 			item = fWorkspaceCountField->Menu()->ItemAt(fOriginalWorkspaceCount - 1);
954abc649b8SWaldemar Kornewald 			if (item != NULL)
955abc649b8SWaldemar Kornewald 				item->SetMarked(true);
956abc649b8SWaldemar Kornewald 
957abc649b8SWaldemar Kornewald 			// ScreenMode::Revert() assumes that we first set the correct number
958abc649b8SWaldemar Kornewald 			// of workspaces
959b72c4836SAlexandre Deckner 
960b72c4836SAlexandre Deckner 			if (_IsVesa()) {
961b72c4836SAlexandre Deckner 				set_workspace_count(fOriginalWorkspaceCount);
962b72c4836SAlexandre Deckner 				fActive = fOriginal;
963b72c4836SAlexandre Deckner 				fSelected = fOriginal;
9645de171daSAxel Dörfler 				_UpdateControls();
965b72c4836SAlexandre Deckner 			} else {
966abc649b8SWaldemar Kornewald 				set_workspace_count(fOriginalWorkspaceCount);
967a10cf76eSAxel Dörfler 				fScreenMode.Revert();
9685de171daSAxel Dörfler 				_UpdateActiveMode();
969b72c4836SAlexandre Deckner 			}
970a10cf76eSAxel Dörfler 			break;
971abc649b8SWaldemar Kornewald 		}
972a10cf76eSAxel Dörfler 
973a10cf76eSAxel Dörfler 		case BUTTON_APPLY_MSG:
9745de171daSAxel Dörfler 			_Apply();
975a10cf76eSAxel Dörfler 			break;
976a10cf76eSAxel Dörfler 
977abc649b8SWaldemar Kornewald 		case MAKE_INITIAL_MSG:
978abc649b8SWaldemar Kornewald 			// user pressed "keep" in confirmation dialog
979abc649b8SWaldemar Kornewald 			fModified = true;
9805de171daSAxel Dörfler 			_UpdateActiveMode();
981a10cf76eSAxel Dörfler 			break;
982a10cf76eSAxel Dörfler 
983a10cf76eSAxel Dörfler 		default:
984a10cf76eSAxel Dörfler 			BWindow::MessageReceived(message);
985a10cf76eSAxel Dörfler 			break;
986a10cf76eSAxel Dörfler 	}
987a10cf76eSAxel Dörfler }
988a10cf76eSAxel Dörfler 
989a10cf76eSAxel Dörfler 
99012580984SAxel Dörfler status_t
99112580984SAxel Dörfler ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const
99212580984SAxel Dörfler {
99312580984SAxel Dörfler 	BPath path;
99412580984SAxel Dörfler 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
99512580984SAxel Dörfler 	if (status < B_OK)
99612580984SAxel Dörfler 		return status;
99712580984SAxel Dörfler 
99812580984SAxel Dörfler 	path.Append("kernel/drivers");
99912580984SAxel Dörfler 	status = create_directory(path.Path(), 0755);
100012580984SAxel Dörfler 	if (status < B_OK)
100112580984SAxel Dörfler 		return status;
100212580984SAxel Dörfler 
100312580984SAxel Dörfler 	path.Append("vesa");
100412580984SAxel Dörfler 	BFile file;
100512580984SAxel Dörfler 	status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE);
100612580984SAxel Dörfler 	if (status < B_OK)
100712580984SAxel Dörfler 		return status;
100812580984SAxel Dörfler 
100912580984SAxel Dörfler 	char buffer[256];
101012580984SAxel Dörfler 	snprintf(buffer, sizeof(buffer), "mode %ld %ld %ld\n",
101112580984SAxel Dörfler 		mode.width, mode.height, mode.BitsPerPixel());
101212580984SAxel Dörfler 
101312580984SAxel Dörfler 	ssize_t bytesWritten = file.Write(buffer, strlen(buffer));
101412580984SAxel Dörfler 	if (bytesWritten < B_OK)
101512580984SAxel Dörfler 		return bytesWritten;
101612580984SAxel Dörfler 
101712580984SAxel Dörfler 	return B_OK;
101812580984SAxel Dörfler }
101912580984SAxel Dörfler 
102012580984SAxel Dörfler 
1021b72c4836SAlexandre Deckner status_t
1022b72c4836SAlexandre Deckner ScreenWindow::_ReadVesaModeFile(screen_mode& mode) const
1023a10cf76eSAxel Dörfler {
1024b72c4836SAlexandre Deckner 	BPath path;
1025b72c4836SAlexandre Deckner 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
1026b72c4836SAlexandre Deckner 	if (status < B_OK)
1027b72c4836SAlexandre Deckner 		return status;
1028b72c4836SAlexandre Deckner 
1029b72c4836SAlexandre Deckner 	path.Append("kernel/drivers/vesa");
1030b72c4836SAlexandre Deckner 	BFile file;
1031b72c4836SAlexandre Deckner 	status = file.SetTo(path.Path(), B_READ_ONLY);
1032b72c4836SAlexandre Deckner 	if (status < B_OK)
1033b72c4836SAlexandre Deckner 		return status;
1034b72c4836SAlexandre Deckner 
1035b72c4836SAlexandre Deckner 	char buffer[256];
1036b72c4836SAlexandre Deckner 
1037b72c4836SAlexandre Deckner 	ssize_t bytesRead = file.Read(buffer, sizeof(buffer) - 1);
1038b72c4836SAlexandre Deckner 	if (bytesRead < B_OK) {
1039b72c4836SAlexandre Deckner 		return bytesRead;
1040b72c4836SAlexandre Deckner 	} else {
1041b72c4836SAlexandre Deckner 		buffer[bytesRead] = '\0';
1042a10cf76eSAxel Dörfler 	}
1043a10cf76eSAxel Dörfler 
1044b72c4836SAlexandre Deckner 	char ignore[256];
1045b72c4836SAlexandre Deckner 		// if the file is malformed, sscanf shouldn't crash
1046b72c4836SAlexandre Deckner 		// on reading a big string since we don't even read
1047b72c4836SAlexandre Deckner 		// as much from the file
1048b72c4836SAlexandre Deckner 	uint32 bitDepth = 0;
1049a10cf76eSAxel Dörfler 
10505de171daSAxel Dörfler 	if (sscanf(buffer, "%s %ld %ld %ld", ignore, &mode.width, &mode.height,
10515de171daSAxel Dörfler 			&bitDepth) != 4) {
10525de171daSAxel Dörfler 		return B_ERROR;
10535de171daSAxel Dörfler 	}
1054b72c4836SAlexandre Deckner 
1055b72c4836SAlexandre Deckner 	// TODO: check for valid width and height values
1056b72c4836SAlexandre Deckner 
1057b72c4836SAlexandre Deckner 	switch (bitDepth) {
1058b72c4836SAlexandre Deckner 		case 32:
1059b72c4836SAlexandre Deckner 			mode.space = B_RGB32;
1060b72c4836SAlexandre Deckner 			break;
1061b72c4836SAlexandre Deckner 		case 24:
1062b72c4836SAlexandre Deckner 			mode.space = B_RGB24;
1063b72c4836SAlexandre Deckner 			break;
1064b72c4836SAlexandre Deckner 		case 16:
1065b72c4836SAlexandre Deckner 			mode.space = B_RGB16;
1066b72c4836SAlexandre Deckner 			break;
1067b72c4836SAlexandre Deckner 		case 15:
1068b72c4836SAlexandre Deckner 			mode.space = B_RGB15;
1069b72c4836SAlexandre Deckner 			break;
1070b72c4836SAlexandre Deckner 		case 8:
1071b72c4836SAlexandre Deckner 			mode.space = B_CMAP8;
1072b72c4836SAlexandre Deckner 			break;
1073b72c4836SAlexandre Deckner 		default:
1074b72c4836SAlexandre Deckner 			// invalid value, we force it to B_RGB16 just in case
1075b72c4836SAlexandre Deckner 			mode.space = B_RGB16;
1076b72c4836SAlexandre Deckner 			return B_ERROR;
1077b72c4836SAlexandre Deckner 	}
10785de171daSAxel Dörfler 
1079b72c4836SAlexandre Deckner 	return B_OK;
1080a10cf76eSAxel Dörfler }
1081a10cf76eSAxel Dörfler 
1082a10cf76eSAxel Dörfler 
1083a10cf76eSAxel Dörfler void
10845de171daSAxel Dörfler ScreenWindow::_CheckApplyEnabled()
1085a10cf76eSAxel Dörfler {
1086b72c4836SAlexandre Deckner 	fApplyButton->SetEnabled(fSelected != fActive);
10875de171daSAxel Dörfler 	fRevertButton->SetEnabled(count_workspaces() != fOriginalWorkspaceCount
10885de171daSAxel Dörfler 		|| fSelected != fOriginal);
1089a10cf76eSAxel Dörfler }
1090a10cf76eSAxel Dörfler 
1091a10cf76eSAxel Dörfler 
1092a10cf76eSAxel Dörfler void
10935de171daSAxel Dörfler ScreenWindow::_UpdateOriginal()
1094abc649b8SWaldemar Kornewald {
1095abc649b8SWaldemar Kornewald 	fOriginalWorkspaceCount = count_workspaces();
1096abc649b8SWaldemar Kornewald 	fScreenMode.Get(fOriginal);
1097b72c4836SAlexandre Deckner 
1098b72c4836SAlexandre Deckner 	// If we are in vesa we overwrite fOriginal's resolution and bitdepth
1099b72c4836SAlexandre Deckner 	// with those found the vesa settings file. (if the file exists)
1100b72c4836SAlexandre Deckner 	if (_IsVesa())
1101b72c4836SAlexandre Deckner 		_ReadVesaModeFile(fOriginal);
1102b72c4836SAlexandre Deckner 
1103abc649b8SWaldemar Kornewald 	fScreenMode.UpdateOriginalModes();
1104abc649b8SWaldemar Kornewald }
1105abc649b8SWaldemar Kornewald 
1106abc649b8SWaldemar Kornewald 
1107abc649b8SWaldemar Kornewald void
11085de171daSAxel Dörfler ScreenWindow::_Apply()
1109a10cf76eSAxel Dörfler {
111012580984SAxel Dörfler 	if (_IsVesa()) {
111112580984SAxel Dörfler 		(new BAlert("VesaAlert",
11125de171daSAxel Dörfler 			"Haiku is using your video card in compatibility mode (VESA)."
1113b72c4836SAlexandre Deckner 			" Your settings will be applied on next startup.\n", "Okay", NULL, NULL, B_WIDTH_AS_USUAL,
111412580984SAxel Dörfler 			B_INFO_ALERT))->Go(NULL);
111512580984SAxel Dörfler 
111612580984SAxel Dörfler 		fVesaApplied = true;
111712580984SAxel Dörfler 		fActive = fSelected;
11185de171daSAxel Dörfler 		_UpdateControls();
111912580984SAxel Dörfler 		return;
112012580984SAxel Dörfler 	}
112112580984SAxel Dörfler 
1122abc649b8SWaldemar Kornewald 	// make checkpoint, so we can undo these changes
1123abc649b8SWaldemar Kornewald 	fTempScreenMode.UpdateOriginalModes();
112407184a9eSAxel Dörfler 	status_t status = fScreenMode.Set(fSelected);
112507184a9eSAxel Dörfler 	if (status == B_OK) {
1126abc649b8SWaldemar Kornewald 		// use the mode that has eventually been set and
1127abc649b8SWaldemar Kornewald 		// thus we know to be working; it can differ from
1128abc649b8SWaldemar Kornewald 		// the mode selected by user due to hardware limitation
1129abc649b8SWaldemar Kornewald 		display_mode newMode;
1130abc649b8SWaldemar Kornewald 		BScreen screen(this);
1131abc649b8SWaldemar Kornewald 		screen.GetMode(&newMode);
1132abc649b8SWaldemar Kornewald 
1133abc649b8SWaldemar Kornewald 		if (fAllWorkspacesItem->IsMarked()) {
1134abc649b8SWaldemar Kornewald 			int32 originatingWorkspace = current_workspace();
1135abc649b8SWaldemar Kornewald 			for (int32 i = 0; i < count_workspaces(); i++) {
1136abc649b8SWaldemar Kornewald 				if (i != originatingWorkspace)
1137abc649b8SWaldemar Kornewald 					screen.SetMode(i, &newMode, true);
1138abc649b8SWaldemar Kornewald 			}
1139abc649b8SWaldemar Kornewald 		}
1140abc649b8SWaldemar Kornewald 
1141a10cf76eSAxel Dörfler 		fActive = fSelected;
1142a10cf76eSAxel Dörfler 
1143abc649b8SWaldemar Kornewald 		// TODO: only show alert when this is an unknown mode
1144a10cf76eSAxel Dörfler 		BWindow* window = new AlertWindow(this);
1145a10cf76eSAxel Dörfler 		window->Show();
114607184a9eSAxel Dörfler 	} else {
114707184a9eSAxel Dörfler 		char message[256];
114807184a9eSAxel Dörfler 		snprintf(message, sizeof(message),
114907184a9eSAxel Dörfler 			"The screen mode could not be set:\n\t%s\n", screen_errors(status));
115007184a9eSAxel Dörfler 		BAlert* alert = new BAlert("Screen Alert", message, "Okay", NULL, NULL,
115107184a9eSAxel Dörfler 			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
115207184a9eSAxel Dörfler 		alert->Go();
1153a10cf76eSAxel Dörfler 	}
115407184a9eSAxel Dörfler }
115507184a9eSAxel Dörfler 
1156df3f5bacSStephan Aßmus 
1157df3f5bacSStephan Aßmus void
11585de171daSAxel Dörfler ScreenWindow::_LayoutControls(uint32 flags)
1159df3f5bacSStephan Aßmus {
1160df3f5bacSStephan Aßmus 	// layout the screen box and its controls
1161df3f5bacSStephan Aßmus 	fWorkspaceCountField->ResizeToPreferred();
1162df3f5bacSStephan Aßmus 
1163df3f5bacSStephan Aßmus 	float monitorViewHeight = fMonitorView->Bounds().Height();
1164df3f5bacSStephan Aßmus 	float workspaceFieldHeight = fWorkspaceCountField->Bounds().Height();
1165df3f5bacSStephan Aßmus 	float backgroundsButtonHeight = fBackgroundsButton->Bounds().Height();
1166df3f5bacSStephan Aßmus 
1167df3f5bacSStephan Aßmus 	float screenBoxWidth = fWorkspaceCountField->Bounds().Width() + 20.0;
11685de171daSAxel Dörfler 	float screenBoxHeight = monitorViewHeight + 5.0 + workspaceFieldHeight + 5.0
11695de171daSAxel Dörfler 		+ backgroundsButtonHeight + 20.0;
1170df3f5bacSStephan Aßmus 
117129e8a73aSAxel Dörfler #ifdef __HAIKU__
1172df3f5bacSStephan Aßmus 	fScreenBox->MoveTo(10.0, 10.0 + fControlsBox->TopBorderOffset());
117329e8a73aSAxel Dörfler #else
117429e8a73aSAxel Dörfler 	fScreenBox->MoveTo(10.0, 10.0 + 3);
117529e8a73aSAxel Dörfler #endif
1176df3f5bacSStephan Aßmus 	fScreenBox->ResizeTo(screenBoxWidth, screenBoxHeight);
1177df3f5bacSStephan Aßmus 
1178df3f5bacSStephan Aßmus 	float leftOffset = 10.0;
1179df3f5bacSStephan Aßmus 	float topOffset = 10.0;
1180df3f5bacSStephan Aßmus 	fMonitorView->MoveTo(leftOffset, topOffset);
1181df3f5bacSStephan Aßmus 	fMonitorView->ResizeTo(screenBoxWidth - 20.0, monitorViewHeight);
1182df3f5bacSStephan Aßmus 	fMonitorView->SetResizingMode(B_FOLLOW_ALL);
1183df3f5bacSStephan Aßmus 	topOffset += monitorViewHeight + 5.0;
1184df3f5bacSStephan Aßmus 
1185df3f5bacSStephan Aßmus 	fWorkspaceCountField->MoveTo(leftOffset, topOffset);
1186df3f5bacSStephan Aßmus 	fWorkspaceCountField->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
1187df3f5bacSStephan Aßmus 	topOffset += workspaceFieldHeight + 5.0;
1188df3f5bacSStephan Aßmus 
1189df3f5bacSStephan Aßmus 	fBackgroundsButton->MoveTo(leftOffset, topOffset);
1190df3f5bacSStephan Aßmus 	fBackgroundsButton->ResizeTo(screenBoxWidth - 20.0, backgroundsButtonHeight);
1191df3f5bacSStephan Aßmus 	fBackgroundsButton->SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
1192df3f5bacSStephan Aßmus 
1193df3f5bacSStephan Aßmus 	fControlsBox->MoveTo(fScreenBox->Frame().right + 10.0, 10.0);
1194df3f5bacSStephan Aßmus 
1195df3f5bacSStephan Aßmus 	// layout the right side
11964008594dSWaldemar Kornewald 	fApplyButton->ResizeToPreferred();
11975de171daSAxel Dörfler 	BRect controlsRect = _LayoutMenuFields(flags);
1198df3f5bacSStephan Aßmus 	controlsRect.InsetBy(-10.0, -10.0);
11994008594dSWaldemar Kornewald 	controlsRect.bottom += 8 + fApplyButton->Bounds().Height();
1200df3f5bacSStephan Aßmus 	// adjust size of controls box and move aligned buttons along
1201df3f5bacSStephan Aßmus 	float xDiff = controlsRect.right - fControlsBox->Bounds().right;
1202df3f5bacSStephan Aßmus 	float yDiff = controlsRect.bottom - fControlsBox->Bounds().bottom;
1203df3f5bacSStephan Aßmus 	if (yDiff < 0.0) {
1204df3f5bacSStephan Aßmus 		// don't shrink vertically
1205df3f5bacSStephan Aßmus 		yDiff = 0.0;
1206df3f5bacSStephan Aßmus 	}
1207df3f5bacSStephan Aßmus 
1208df3f5bacSStephan Aßmus 	fControlsBox->ResizeBy(xDiff, yDiff);
1209df3f5bacSStephan Aßmus 
1210df3f5bacSStephan Aßmus 	// align bottom of boxen
1211df3f5bacSStephan Aßmus 	float boxBottomDiff = fControlsBox->Frame().bottom - fScreenBox->Frame().bottom;
1212df3f5bacSStephan Aßmus 	if (boxBottomDiff > 0)
1213df3f5bacSStephan Aßmus 		fScreenBox->ResizeBy(0.0, boxBottomDiff);
1214df3f5bacSStephan Aßmus 	else
1215df3f5bacSStephan Aßmus 		fControlsBox->ResizeBy(0.0, -boxBottomDiff);
1216df3f5bacSStephan Aßmus 
1217df3f5bacSStephan Aßmus 	BRect boxFrame = fScreenBox->Frame() | fControlsBox->Frame();
1218df3f5bacSStephan Aßmus 
1219df3f5bacSStephan Aßmus 	// layout rest of buttons
1220abc649b8SWaldemar Kornewald 	// TODO: we don't support getting the screen's preferred settings
1221abc649b8SWaldemar Kornewald //	fDefaultsButton->ResizeToPreferred();
1222abc649b8SWaldemar Kornewald //	fDefaultsButton->MoveTo(boxFrame.left, boxFrame.bottom + 8);
1223df3f5bacSStephan Aßmus 
1224df3f5bacSStephan Aßmus 	fRevertButton->ResizeToPreferred();
1225abc649b8SWaldemar Kornewald 	fRevertButton->MoveTo(boxFrame.left, boxFrame.bottom + 8);
1226abc649b8SWaldemar Kornewald //	fRevertButton->MoveTo(fDefaultsButton->Frame().right + 10,
1227abc649b8SWaldemar Kornewald //						  fDefaultsButton->Frame().top);
1228df3f5bacSStephan Aßmus 
12294008594dSWaldemar Kornewald 	// Apply button was already resized above
1230abc649b8SWaldemar Kornewald 	float resolutionFieldRight = fResolutionField->Frame().right;
1231abc649b8SWaldemar Kornewald 	fApplyButton->MoveTo(resolutionFieldRight - fApplyButton->Bounds().Width(),
12324008594dSWaldemar Kornewald 		fControlsBox->Bounds().bottom - fApplyButton->Bounds().Height() - 10);
1233df3f5bacSStephan Aßmus 
1234abc649b8SWaldemar Kornewald 	ResizeTo(boxFrame.right + 10, fRevertButton->Frame().bottom + 10);
1235df3f5bacSStephan Aßmus }
1236df3f5bacSStephan Aßmus 
1237df3f5bacSStephan Aßmus 
1238df3f5bacSStephan Aßmus BRect
12395de171daSAxel Dörfler ScreenWindow::_LayoutMenuFields(uint32 flags, bool sideBySide)
1240df3f5bacSStephan Aßmus {
1241df3f5bacSStephan Aßmus 	BList menuFields;
1242df3f5bacSStephan Aßmus 	menuFields.AddItem((void*)fResolutionField);
1243df3f5bacSStephan Aßmus 	menuFields.AddItem((void*)fColorsField);
1244df3f5bacSStephan Aßmus 	menuFields.AddItem((void*)fRefreshField);
1245df3f5bacSStephan Aßmus 
1246df3f5bacSStephan Aßmus 	BRect frame;
1247df3f5bacSStephan Aßmus 
1248df3f5bacSStephan Aßmus 	if (sideBySide)
1249df3f5bacSStephan Aßmus 		frame = stack_and_align_menu_fields(menuFields);
1250df3f5bacSStephan Aßmus 
1251df3f5bacSStephan Aßmus 	if (sideBySide)
1252df3f5bacSStephan Aßmus 		menuFields.MakeEmpty();
1253df3f5bacSStephan Aßmus 
1254df3f5bacSStephan Aßmus 	if (flags & SHOW_COMBINE_FIELD)
1255df3f5bacSStephan Aßmus 		menuFields.AddItem((void*)fCombineField);
1256df3f5bacSStephan Aßmus 	if (flags & SHOW_SWAP_FIELD)
1257df3f5bacSStephan Aßmus 		menuFields.AddItem((void*)fSwapDisplaysField);
1258df3f5bacSStephan Aßmus 	if (flags & SHOW_LAPTOP_PANEL_FIELD)
1259df3f5bacSStephan Aßmus 		menuFields.AddItem((void*)fUseLaptopPanelField);
1260df3f5bacSStephan Aßmus 	if (flags & SHOW_TV_STANDARD_FIELD)
1261df3f5bacSStephan Aßmus 		menuFields.AddItem((void*)fTVStandardField);
1262df3f5bacSStephan Aßmus 
1263df3f5bacSStephan Aßmus 	if (sideBySide) {
1264df3f5bacSStephan Aßmus 		if (menuFields.CountItems() > 0) {
1265df3f5bacSStephan Aßmus 			((BMenuField*)menuFields.FirstItem())->MoveTo(frame.right + 8.0, frame.top);
1266df3f5bacSStephan Aßmus 			frame = frame | stack_and_align_menu_fields(menuFields);
1267df3f5bacSStephan Aßmus 		}
1268df3f5bacSStephan Aßmus 	} else {
1269df3f5bacSStephan Aßmus 		frame = stack_and_align_menu_fields(menuFields);
1270df3f5bacSStephan Aßmus 	}
1271df3f5bacSStephan Aßmus 
1272df3f5bacSStephan Aßmus 	return frame;
1273df3f5bacSStephan Aßmus }
1274df3f5bacSStephan Aßmus 
1275