* No longer ignores the screen refresh limits from the driver.

* Now builds under R5, but looks ugly (for testing only).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16877 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-25 20:10:34 +00:00
parent 7a3806ce87
commit 29e8a73a07
6 changed files with 197 additions and 179 deletions

View File

@ -1,5 +1,6 @@
SubDir HAIKU_TOP src preferences screen ;
SetSubDirSupportedPlatformsBeOSCompatible ;
AddSubDirSupportedPlatforms libbe_test ;
UsePrivateHeaders [ FDirName graphics radeon ] ;

View File

@ -1,48 +1,64 @@
#include <Alert.h>
#include <Application.h>
#include <Button.h>
#include <String.h>
#include <Window.h>
/*
* Copyright 2001-2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Rafael Romo
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
*/
#include "RefreshWindow.h"
#include "RefreshView.h"
#include "RefreshSlider.h"
#include "Constants.h"
RefreshWindow::RefreshWindow(BRect frame, int32 value)
: BWindow(frame, "Refresh Rate", B_MODAL_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES)
#include <Alert.h>
#include <Application.h>
#include <Button.h>
#include <String.h>
#include <Window.h>
RefreshWindow::RefreshWindow(BRect frame, float current, float min, float max)
: BWindow(frame, "Refresh Rate", B_MODAL_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE,
B_ALL_WORKSPACES)
{
BRect bounds(Bounds());
bounds.InsetBy(-1, -1);
fRefreshView = new RefreshView(bounds, "RefreshView");
AddChild(fRefreshView);
min = ceilf(min);
max = floorf(max);
BRect sliderRect;
BString maxRefresh;
maxRefresh << gMaxRefresh;
maxRefresh << (uint32)min;
BString minRefresh;
minRefresh << gMinRefresh;
minRefresh << (uint32)max;
sliderRect.Set(10.0, 35.0, 299.0, 60.0);
fRefreshSlider = new RefreshSlider(sliderRect);
fRefreshSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
fRefreshSlider->SetHashMarkCount((gMaxRefresh-gMinRefresh)/5+1);
fRefreshSlider->SetHashMarkCount(uint32(max - min) / 5 + 1);
fRefreshSlider->SetLimitLabels(minRefresh.String(), maxRefresh.String());
fRefreshSlider->SetKeyIncrementValue(1);
fRefreshSlider->SetValue(value);
fRefreshSlider->SetValue(rint(current * 10));
fRefreshSlider->SetSnoozeAmount(1);
fRefreshSlider->SetModificationMessage(new BMessage(SLIDER_MODIFICATION_MSG));
fRefreshView->AddChild(fRefreshSlider);
BRect ButtonRect(219.0, 97.0, 230.0, 120.0);
fDoneButton = new BButton(ButtonRect, "DoneButton", "Done",
new BMessage(BUTTON_DONE_MSG));
fDoneButton->ResizeToPreferred();
fDoneButton->MakeDefault(true);

View File

@ -1,24 +1,33 @@
#ifndef REFRESHWINDOW_H
#define REFRESHWINDOW_H
/*
* Copyright 2001-2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Rafael Romo
* Stefano Ceccherini (burton666@libero.it)
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef REFRESH_WINDOW_H
#define REFRESH_WINDOW_H
#include <Window.h>
#include "RefreshView.h"
#include "RefreshSlider.h"
class RefreshWindow : public BWindow
{
class RefreshWindow : public BWindow {
public:
RefreshWindow(BRect frame, float current, float min, float max);
public:
RefreshWindow(BRect frame, int32 value);
virtual void MessageReceived(BMessage *message);
virtual void WindowActivated(bool active);
virtual void MessageReceived(BMessage *message);
virtual void WindowActivated(bool active);
private:
RefreshView *fRefreshView;
RefreshSlider *fRefreshSlider;
BButton *fDoneButton;
BButton *fCancelButton;
private:
RefreshView *fRefreshView;
RefreshSlider *fRefreshSlider;
BButton *fDoneButton;
BButton *fCancelButton;
};
#endif
#endif // REFRESH_WINDOW_H

View File

@ -173,7 +173,7 @@ ScreenMode::~ScreenMode()
status_t
ScreenMode::Set(screen_mode& mode)
ScreenMode::Set(const screen_mode& mode)
{
if (!fUpdatedMode)
UpdateOriginalMode();
@ -243,16 +243,29 @@ ScreenMode::UpdateOriginalMode()
bool
ScreenMode::SupportsColorSpace(screen_mode& mode, color_space space)
ScreenMode::SupportsColorSpace(const screen_mode& mode, color_space space)
{
return false;
return true;
}
status_t
ScreenMode::GetRefreshLimits(screen_mode& mode, float& min, float& max)
ScreenMode::GetRefreshLimits(const screen_mode& mode, float& min, float& max)
{
return B_ERROR;
uint32 minClock, maxClock;
display_mode displayMode;
if (!GetDisplayMode(mode, displayMode))
return B_ERROR;
BScreen screen(fWindow);
if (screen.GetPixelClockLimits(&displayMode, &minClock, &maxClock) < B_OK)
return B_ERROR;
uint32 total = displayMode.timing.h_total * displayMode.timing.v_total;
min = minClock * 1000.0 / total;
max = maxClock * 1000.0 / total;
return B_OK;
}
@ -279,7 +292,7 @@ ScreenMode::CountModes()
bool
ScreenMode::GetDisplayMode(screen_mode& mode, display_mode& displayMode)
ScreenMode::GetDisplayMode(const screen_mode& mode, display_mode& displayMode)
{
uint16 virtualWidth, virtualHeight;
int32 bestIndex = -1;

View File

@ -41,20 +41,20 @@ class ScreenMode {
ScreenMode(BWindow* window);
~ScreenMode();
status_t Set(screen_mode& mode);
status_t Set(const screen_mode& mode);
status_t Get(screen_mode& mode);
status_t Revert();
void UpdateOriginalMode();
bool SupportsColorSpace(screen_mode& mode, color_space space);
status_t GetRefreshLimits(screen_mode& mode, float& min, float& max);
bool SupportsColorSpace(const screen_mode& mode, color_space space);
status_t GetRefreshLimits(const screen_mode& mode, float& min, float& max);
screen_mode ModeAt(int32 index);
int32 CountModes();
private:
bool GetDisplayMode(screen_mode& mode, display_mode& displayMode);
bool GetDisplayMode(const screen_mode& mode, display_mode& displayMode);
BWindow* fWindow;
display_mode* fModeList;

View File

@ -52,11 +52,6 @@
#include "multimon.h" // the usual: DANGER WILL, ROBINSON!
#define USE_FIXED_REFRESH
// define to use fixed standard refresh rates
// undefine to get standard refresh rates from driver
const char* kBackgroundsSignature = "application/x-vnd.haiku-backgrounds";
// list of officially supported colour spaces
@ -76,7 +71,6 @@ static const int32 kColorSpaceCount = sizeof(kColorSpaces) / sizeof(kColorSpaces
static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 };
static const int32 kRefreshRateCount = sizeof(kRefreshRates) / sizeof(kRefreshRates[0]);
// list of combine modes
static const struct {
combine_mode mode;
@ -88,6 +82,13 @@ static const struct {
};
static const int32 kCombineModeCount = sizeof(kCombineModes) / sizeof(kCombineModes[0]);
enum {
SHOW_COMBINE_FIELD = 0x01,
SHOW_SWAP_FIELD = 0x02,
SHOW_LAPTOP_PANEL_FIELD = 0x04,
SHOW_TV_STANDARD_FIELD = 0x08,
};
static BString
tv_standard_to_string(uint32 mode)
@ -146,12 +147,59 @@ screen_errors(status_t status)
}
}
enum {
SHOW_COMBINE_FIELD = 0x01,
SHOW_SWAP_FIELD = 0x02,
SHOW_LAPTOP_PANEL_FIELD = 0x04,
SHOW_TV_STANDARD_FIELD = 0x08,
};
static float
max_label_width(BMenuField* control, float widestLabel)
{
float labelWidth = control->StringWidth(control->Label());
if (widestLabel < labelWidth)
return labelWidth;
return widestLabel;
}
static BRect
stack_and_align_menu_fields(const BList& menuFields)
{
float widestLabel = 0.0;
int32 count = menuFields.CountItems();
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
widestLabel = max_label_width(menuField, widestLabel);
}
// add some room (but only if there is text at all)
if (widestLabel > 0.0)
widestLabel += 5.0;
// make all controls the same width
float widestField = 0.0;
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
menuField->SetAlignment(B_ALIGN_RIGHT);
menuField->SetDivider(widestLabel);
menuField->ResizeToPreferred();
widestField = max_c(menuField->Bounds().Width(), widestField);
}
// layout controls under each other, resize all to size
// of largest of them (they could still have different
// heights though)
BMenuField* topMenuField = (BMenuField*)menuFields.FirstItem();
BPoint leftTop = topMenuField->Frame().LeftTop();
BRect frame = topMenuField->Frame();
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
menuField->MoveTo(leftTop);
float height = menuField->Bounds().Height();
menuField->ResizeTo(widestField, height);
frame = frame | menuField->Frame();
leftTop.y += height + 5.0;
}
return frame;
}
// #pragma mark -
@ -246,7 +294,7 @@ ScreenWindow::ScreenWindow(ScreenSettings *settings)
fResolutionMenu->AddItem(new BMenuItem(name.String(), message));
}
BRect rect(0.0, 0.0, 30.0, 15.0);
BRect rect(0.0, 0.0, 200.0, 15.0);
// fResolutionField needs to be at the correct
// left-top offset, because all other menu fields
// will be layouted relative to it
@ -271,22 +319,36 @@ ScreenWindow::ScreenWindow(ScreenSettings *settings)
fRefreshMenu = new BPopUpMenu("refresh rate", true, true);
#ifdef USE_FIXED_REFRESH
for (int32 i = 0; i < kRefreshRateCount; ++i) {
BMessage *message;
float min, max;
if (fScreenMode.GetRefreshLimits(fActive, min, max) && min == max) {
// This is a special case for drivers that only support a single
// frequency, like the VESA driver
BString name;
name << kRefreshRates[i] << " Hz";
name << min << " Hz";
BMessage *message = new BMessage(POP_REFRESH_MSG);
message->AddFloat("refresh", kRefreshRates[i]);
message = new BMessage(POP_REFRESH_MSG);
message->AddFloat("refresh", min);
fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
fRefreshMenu->AddItem(item = new BMenuItem(name.String(), message));
item->SetEnabled(false);
} else {
for (int32 i = 0; i < kRefreshRateCount; ++i) {
BString name;
name << kRefreshRates[i] << " Hz";
message = new BMessage(POP_REFRESH_MSG);
message->AddFloat("refresh", kRefreshRates[i]);
fRefreshMenu->AddItem(new BMenuItem(name.String(), message));
}
message = new BMessage(POP_OTHER_REFRESH_MSG);
fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
fRefreshMenu->AddItem(fOtherRefresh);
}
#endif
BMessage *message = new BMessage(POP_OTHER_REFRESH_MSG);
fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message);
fRefreshMenu->AddItem(fOtherRefresh);
fRefreshField = new BMenuField(rect, "RefreshMenu", "Refresh Rate:", fRefreshMenu, true);
fControlsBox->AddChild(fRefreshField);
@ -497,67 +559,26 @@ ScreenWindow::CheckColorMenu()
}
/** Enable/disable refresh options according to current mode.
* Only needed when USE_FIXED_REFRESH is not defined.
*/
/** Enable/disable refresh options according to current mode. */
void
ScreenWindow::CheckRefreshMenu()
{
#ifndef USE_FIXED_REFRESH
// ToDo: does currently not compile!
for (int32 i = fRefreshMenu->CountItems() - 2; i >= 0; --i) {
delete fRefreshMenu->RemoveItem(i);
{
float min, max;
if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max)
return;
for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) {
BMenuItem* item = fRefreshMenu->ItemAt(i);
BMessage* message = item->Message();
float refresh;
if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK)
item->SetEnabled(refresh >= min && refresh <= max);
}
for (int32 i = 0; i < fModeListCount; ++i) {
if (virtualWidth == fModeList[i].virtual_width
&& virtualHeight == fModeList[i].virtual_height
&& combine == get_combine_mode(&fModeList[i])) {
BString name;
BMenuItem *item;
int32 refresh10 = get_refresh10(fModeList[i]);
refresh10_to_string(name, refresh10);
item = fRefreshMenu->FindItem(name.String());
if (item == NULL) {
BMessage *msg = new BMessage(POP_REFRESH_MSG);
msg->AddFloat("refresh", refresh);
fRefreshMenu->AddItem(new BMenuItem(name.String(), msg),
fRefreshMenu->CountItems() - 1);
}
}
}
#endif
// TBD: some drivers lack many refresh rates; still, they
// can be used by generating the mode manually
/*
for( i = 0; i < sizeof( refresh_list ) / sizeof( refresh_list[0] ); ++i ) {
BMenuItem *item;
bool supported = false;
for( j = 0; j < fModeListCount; ++j ) {
if( width == fModeList[j].virtual_width &&
height == fModeList[j].virtual_height &&
refresh_list[i].refresh * 10 == getModeRefresh10( &fModeList[j] ))
{
supported = true;
break;
}
}
item = fRefreshMenu->ItemAt( i );
if( item )
item->SetEnabled( supported );
}
*/
}
/** activate appropriate menu item according to selected refresh rate */
/** Activate appropriate menu item according to selected refresh rate */
void
ScreenWindow::UpdateRefreshControl()
@ -569,6 +590,7 @@ ScreenWindow::UpdateRefreshControl()
if (item) {
if (!item->IsMarked())
item->SetMarked(true);
// "Other…" items only contains a refresh rate when active
fOtherRefresh->SetLabel("Other…");
return;
@ -788,13 +810,20 @@ ScreenWindow::MessageReceived(BMessage* message)
case POP_OTHER_REFRESH_MSG:
{
// make sure menu shows something usefull
// make sure menu shows something useful
UpdateRefreshControl();
float min = 0, max = 999;
fScreenMode.GetRefreshLimits(fSelected, min, max);
if (min < gMinRefresh)
min = gMinRefresh;
if (max > gMaxRefresh)
max = gMaxRefresh;
BRect frame(Frame());
RefreshWindow *fRefreshWindow = new RefreshWindow(BRect(frame.left + 201.0,
frame.top + 34.0, frame.left + 509.0, frame.top + 169.0),
int32(fSelected.refresh * 10));
fSelected.refresh, min, max);
fRefreshWindow->Show();
break;
}
@ -988,7 +1017,11 @@ ScreenWindow::LayoutControls(uint32 flags)
+ backgroundsButtonHeight
+ 20.0;
#ifdef __HAIKU__
fScreenBox->MoveTo(10.0, 10.0 + fControlsBox->TopBorderOffset());
#else
fScreenBox->MoveTo(10.0, 10.0 + 3);
#endif
fScreenBox->ResizeTo(screenBoxWidth, screenBoxHeight);
float leftOffset = 10.0;
@ -1046,60 +1079,6 @@ ScreenWindow::LayoutControls(uint32 flags)
}
static float
max_label_width(BMenuField* control, float widestLabel)
{
float labelWidth = control->StringWidth(control->Label());
if (widestLabel < labelWidth)
return labelWidth;
return widestLabel;
}
static BRect
stack_and_align_menu_fields(const BList& menuFields)
{
float widestLabel = 0.0;
int32 count = menuFields.CountItems();
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
widestLabel = max_label_width(menuField, widestLabel);
}
// add some room (but only if there is text at all)
if (widestLabel > 0.0)
widestLabel += 5.0;
// make all controls the same width
float widestField = 0.0;
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
menuField->SetAlignment(B_ALIGN_RIGHT);
menuField->SetDivider(widestLabel);
menuField->ResizeToPreferred();
widestField = max_c(menuField->Bounds().Width(), widestField);
}
// layout controls under each other, resize all to size
// of largest of them (they could still have different
// heights though)
BMenuField* topMenuField = (BMenuField*)menuFields.FirstItem();
BPoint leftTop = topMenuField->Frame().LeftTop();
BRect frame = topMenuField->Frame();
for (int32 i = 0; i < count; i++) {
BMenuField* menuField = (BMenuField*)menuFields.ItemAtFast(i);
menuField->MoveTo(leftTop);
float height = menuField->Bounds().Height();
menuField->ResizeTo(widestField, height);
frame = frame | menuField->Frame();
leftTop.y += height + 5.0;
}
return frame;
}
BRect
ScreenWindow::LayoutMenuFields(uint32 flags, bool sideBySide)
{