Integrated Thomas Kurschel's RadeonScreen preferences app.

Major cleanup. All display_mode related stuff is now handled by the
new ScreenMode class, the screen preferences now only care about what
they control directly.
Fixed a lot of bugs.
Some changes in behaviour:
- the alert window that pops up after a screen change can now be confirmed
  with the enter key ("Keep" is now the default button), and be denied with
  the escape key.
- when you switch workspaces, the options will only be reverted to the
  current workspace's options, if you haven't changed them yet
- removed control flickering on mode changes (ie. when pressing "Revert"
  or "Defaults").
- the color pop-up now also shows the number of colors in that mode

Next on the list is: make it work under Haiku, improve visual appearance,
make it font sensitive, play with min/max refresh rates.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-06-22 14:58:36 +00:00
parent 5b6aece60e
commit 223706b2c3
12 changed files with 1416 additions and 629 deletions

View File

@ -32,23 +32,28 @@ AlertView::AlertView(BRect frame, char *name)
fBitmap = InitIcon();
BStringView *stringView = new BStringView(BRect(60, 20, 400, 36), NULL,
"Do you wish to keep these settings?");
"Do you wish to keep these settings?");
stringView->SetFont(be_bold_font);
stringView->ResizeToPreferred();
AddChild(stringView);
fCountdownView = new BStringView(BRect(60, 37, 400, 50), "countdown", B_EMPTY_STRING);
fCountdownView = new BStringView(BRect(60, 37, 400, 50), "countdown",
B_EMPTY_STRING);
UpdateCountdownView();
fCountdownView->ResizeToPreferred();
AddChild(fCountdownView);
BButton *button = new BButton(BRect(215, 59, 400, 190), "KeepButton", "Keep", new BMessage(BUTTON_KEEP_MSG));
BButton *button = new BButton(BRect(215, 59, 400, 190), "keep", "Keep",
new BMessage(BUTTON_KEEP_MSG));
button->ResizeToPreferred();
AddChild(button);
button = new BButton(BRect(130, 59, 400, 199), "RevertButton", "Revert", new BMessage(BUTTON_REVERT_MSG));
button = new BButton(BRect(130, 59, 400, 199), "revert", "Revert",
new BMessage(BUTTON_REVERT_MSG));
button->ResizeToPreferred();
AddChild(button);
SetEventMask(B_KEYBOARD_EVENTS);
}
@ -56,6 +61,9 @@ void
AlertView::AttachedToWindow()
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
if (BButton* button = dynamic_cast<BButton *>(FindView("keep")))
Window()->SetDefaultButton(button);
}
@ -84,6 +92,14 @@ AlertView::Pulse()
}
void
AlertView::KeyDown(const char* bytes, int32 numBytes)
{
if (numBytes == 1 && bytes[0] == B_ESCAPE)
Window()->PostMessage(BUTTON_REVERT_MSG);
}
void
AlertView::UpdateCountdownView()
{

View File

@ -25,6 +25,7 @@ class AlertView : public BView {
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void Pulse();
virtual void KeyDown(const char* bytes, int32 numBytes);
private:
void UpdateCountdownView();

View File

@ -13,10 +13,12 @@
#include "Constants.h"
#include <Window.h>
#include <Screen.h>
AlertWindow::AlertWindow(BRect frame, BMessenger target)
: BWindow(frame, "Revert", B_MODAL_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
AlertWindow::AlertWindow(BMessenger target)
: BWindow(BRect(100.0, 100.0, 400.0, 193.0), "Revert",
B_MODAL_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES),
fTarget(target)
{
@ -25,6 +27,11 @@ AlertWindow::AlertWindow(BRect frame, BMessenger target)
// the view displays a decrementing counter (until the user must take action)
SetPulseRate(1000000); // every second
// center window on screen
BScreen screen(this);
MoveTo((screen.Frame().Width() - Frame().Width()) / 2,
(screen.Frame().Height() - Frame().Height()) / 2);
}

View File

@ -22,7 +22,7 @@ class AlertView;
class AlertWindow : public BWindow {
public:
AlertWindow(BRect frame, BMessenger target);
AlertWindow(BMessenger target);
virtual void MessageReceived(BMessage *message);

View File

@ -22,6 +22,10 @@ static const uint32 POP_RESOLUTION_MSG = 'pres';
static const uint32 POP_COLORS_MSG = 'pclr';
static const uint32 POP_REFRESH_MSG = 'prfr';
static const uint32 POP_OTHER_REFRESH_MSG = 'porf';
static const uint32 POP_COMBINE_DISPLAYS_MSG = 'pcdi';
static const uint32 POP_SWAP_DISPLAYS_MSG = 'psdi';
static const uint32 POP_USE_LAPTOP_PANEL_MSG = 'pulp';
static const uint32 POP_TV_STANDARD_MSG = 'ptvs';
static const uint32 UPDATE_DESKTOP_COLOR_MSG = 'udsc';
static const uint32 UPDATE_DESKTOP_MSG = 'udsk';
static const uint32 SLIDER_MODIFICATION_MSG = 'sldm';

View File

@ -1,13 +1,17 @@
SubDir OBOS_TOP src prefs screen ;
UsePrivateHeaders [ FDirName graphics radeon ] ;
Preference Screen :
AlertView.cpp
AlertWindow.cpp
MonitorView.cpp
multimon.cpp
RefreshSlider.cpp
RefreshView.cpp
RefreshWindow.cpp
ScreenApplication.cpp
ScreenMode.cpp
ScreenSettings.cpp
ScreenWindow.cpp
Utility.cpp

View File

@ -1,10 +1,11 @@
#include <Window.h>
#include <cstdio>
#include "RefreshSlider.h"
#include "Constants.h"
#include <Window.h>
#include <stdio.h>
RefreshSlider::RefreshSlider(BRect frame)
:BSlider(frame, "Screen", "Refresh Rate:",
new BMessage(SLIDER_INVOKE_MSG), gMinRefresh * 10, gMaxRefresh * 10),
@ -41,26 +42,21 @@ RefreshSlider::DrawFocusMark()
void
RefreshSlider::KeyDown(const char *bytes, int32 numBytes)
{
switch (*bytes)
{
switch (*bytes) {
case B_LEFT_ARROW:
{
SetValue(Value() - 1);
Invoke();
break;
}
case B_RIGHT_ARROW:
{
SetValue(Value() + 1);
Invoke();
break;
}
default:
break;
}
@ -73,8 +69,7 @@ RefreshSlider::UpdateText() const
if (fStatus) {
sprintf(fStatus, "%.1f Hz", (float)Value() / 10);
return fStatus;
}
else
} else
return NULL;
}

View File

@ -0,0 +1,337 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include "ScreenMode.h"
#include <stdlib.h>
#include <stdio.h>
/* Note, this headers defines a *private* interface to the Radeon accelerant.
* It's a solution that works with the current BeOS interface that Haiku
* adopted.
* However, it's not a nice and clean solution. Don't use this header in any
* application if you can avoid it. No other driver is using this, or should
* be using this.
* It will be replaced as soon as we introduce an updated accelerant interface
* which may even happen before R1 hits the streets.
*/
#include "multimon.h" // the usual: DANGER WILL, ROBINSON!
static combine_mode
get_combine_mode(display_mode& mode)
{
if (mode.flags & B_SCROLL == 0)
return kCombineDisable;
if (mode.virtual_width == mode.timing.h_display * 2)
return kCombineHorizontally;
if (mode.virtual_height == mode.timing.v_display * 2)
return kCombineVertically;
return kCombineDisable;
}
static float
get_refresh_rate(display_mode& mode)
{
// we have to be catious as refresh rate cannot be controlled directly,
// so it suffers under rounding errors and hardware restrictions
return rint(10 * float(mode.timing.pixel_clock * 1000) /
float(mode.timing.h_total * mode.timing.v_total)) / 10.0;
}
/** helper to sort modes by resolution */
static int
compare_mode(const void* _mode1, const void* _mode2)
{
display_mode *mode1 = (display_mode *)_mode1;
display_mode *mode2 = (display_mode *)_mode2;
combine_mode combine1, combine2;
uint16 width1, width2, height1, height2;
combine1 = get_combine_mode(*mode1);
combine2 = get_combine_mode(*mode2);
width1 = mode1->virtual_width;
height1 = mode1->virtual_height;
width2 = mode2->virtual_width;
height2 = mode2->virtual_height;
if (combine1 == kCombineHorizontally)
width1 /= 2;
if (combine1 == kCombineVertically)
height1 /= 2;
if (combine2 == kCombineHorizontally)
width2 /= 2;
if (combine2 == kCombineVertically)
height2 /= 2;
if (width1 != width2)
return width1 - width2;
if (height1 != height2)
return height1 - height2;
return (int)(10 * get_refresh_rate(*mode1)
- 10 * get_refresh_rate(*mode2));
}
// #pragma mark -
int32
screen_mode::BitsPerPixel() const
{
switch (space) {
case B_RGB32: return 32;
case B_RGB24: return 24;
case B_RGB16: return 16;
case B_RGB15: return 15;
case B_CMAP8: return 8;
default: return 0;
}
}
bool
screen_mode::operator==(const screen_mode &other) const
{
return !(*this != other);
}
bool
screen_mode::operator!=(const screen_mode &other) const
{
return width != other.width || height != other.height
|| space != other.space || refresh != other.refresh
|| combine != other.combine
|| swap_displays != other.swap_displays
|| use_laptop_panel != other.use_laptop_panel
|| tv_standard != other.tv_standard;
}
void
screen_mode::SetTo(display_mode& mode)
{
width = mode.virtual_width;
height = mode.virtual_height;
space = (color_space)mode.space;
combine = get_combine_mode(mode);
refresh = get_refresh_rate(mode);
if (combine == kCombineHorizontally)
width /= 2;
else if (combine == kCombineVertically)
height /= 2;
swap_displays = false;
use_laptop_panel = false;
tv_standard = 0;
}
// #pragma mark -
ScreenMode::ScreenMode(BWindow* window)
:
fWindow(window),
fUpdatedMode(false)
{
BScreen screen(window);
if (screen.GetModeList(&fModeList, &fModeCount) == B_OK) {
// sort modes by resolution and refresh to make
// the resolution and refresh menu look nicer
qsort(fModeList, fModeCount, sizeof(display_mode), compare_mode);
} else {
fModeList = NULL;
fModeCount = 0;
}
}
ScreenMode::~ScreenMode()
{
free(fModeList);
}
status_t
ScreenMode::Set(screen_mode& mode)
{
if (!fUpdatedMode)
UpdateOriginalMode();
BScreen screen(fWindow);
SetSwapDisplays(&screen, mode.swap_displays);
SetUseLaptopPanel(&screen, mode.use_laptop_panel);
SetTVStandard(&screen, mode.tv_standard);
display_mode displayMode;
if (!GetDisplayMode(mode, displayMode))
return B_ENTRY_NOT_FOUND;
return screen.SetMode(&displayMode, true);
}
status_t
ScreenMode::Get(screen_mode& mode)
{
display_mode displayMode;
BScreen screen(fWindow);
if (screen.GetMode(&displayMode) != B_OK)
return B_ERROR;
mode.SetTo(displayMode);
if (GetSwapDisplays(&screen, &mode.swap_displays) != B_OK)
mode.swap_displays = false;
if (GetUseLaptopPanel(&screen, &mode.use_laptop_panel) != B_OK)
mode.use_laptop_panel = false;
if (GetTVStandard(&screen, &mode.tv_standard) != B_OK)
mode.tv_standard = 0;
return B_OK;
}
status_t
ScreenMode::Revert()
{
if (!fUpdatedMode)
return B_OK;
screen_mode current;
if (Get(current) && fOriginal == current)
return B_OK;
BScreen screen(fWindow);
SetSwapDisplays(&screen, fOriginal.swap_displays);
SetUseLaptopPanel(&screen, fOriginal.use_laptop_panel);
SetTVStandard(&screen, fOriginal.tv_standard);
return screen.SetMode(&fOriginalDisplayMode, true);
}
void
ScreenMode::UpdateOriginalMode()
{
BScreen screen(fWindow);
if (screen.GetMode(&fOriginalDisplayMode) == B_OK) {
fUpdatedMode = true;
Get(fOriginal);
}
}
bool
ScreenMode::SupportsColorSpace(screen_mode& mode, color_space space)
{
return false;
}
status_t
ScreenMode::GetRefreshLimits(screen_mode& mode, float& min, float& max)
{
return B_ERROR;
}
screen_mode
ScreenMode::ModeAt(int32 index)
{
if (index < 0)
index = 0;
else if (index >= (int32)fModeCount)
index = fModeCount - 1;
screen_mode mode;
mode.SetTo(fModeList[index]);
return mode;
}
int32
ScreenMode::CountModes()
{
return fModeCount;
}
bool
ScreenMode::GetDisplayMode(screen_mode& mode, display_mode& displayMode)
{
uint16 virtualWidth, virtualHeight;
int32 bestIndex = -1;
float bestDiff = 999;
virtualWidth = mode.combine == kCombineHorizontally ?
mode.width * 2 : mode.width;
virtualHeight = mode.combine == kCombineVertically ?
mode.height * 2 : mode.height;
// try to find mode in list provided by driver
for (uint32 i = 0; i < fModeCount; i++) {
if (fModeList[i].virtual_width != virtualWidth
|| fModeList[i].virtual_height != virtualHeight
|| (color_space)fModeList[i].space != mode.space)
continue;
float refresh = get_refresh_rate(fModeList[i]);
if (refresh == mode.refresh) {
// we have luck - we can use this mode directly
displayMode = fModeList[i];
displayMode.h_display_start = 0;
displayMode.v_display_start = 0;
return true;
}
float diff = fabs(refresh - mode.refresh);
if (diff < bestDiff) {
bestDiff = diff;
bestIndex = i;
}
}
// we didn't find the exact mode, but something very similar?
if (bestIndex == -1)
return false;
// now, we are better of using GMT formula, but
// as we don't have it, we just tune the pixel
// clock of the best mode.
displayMode = fModeList[bestIndex];
displayMode.h_display_start = 0;
displayMode.v_display_start = 0;
// after some fiddling, it looks like this is the formula
// used by the original panel (notice that / 10 happens before
// multiplying with refresh rate - this leads to different
// rounding)
displayMode.timing.pixel_clock = ((uint32)displayMode.timing.h_total
* displayMode.timing.v_total / 10 * int32(mode.refresh * 10)) / 1000;
return true;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2005, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef SCREEN_MODE_H
#define SCREEN_MODE_H
#include <Screen.h>
typedef enum {
kCombineDisable,
kCombineHorizontally,
kCombineVertically
} combine_mode;
struct screen_mode {
int32 width; // these reflect the corrected width/height,
int32 height; // taking the combine mode into account
color_space space;
float refresh;
combine_mode combine;
bool swap_displays;
bool use_laptop_panel;
uint32 tv_standard;
void SetTo(display_mode& mode);
int32 BitsPerPixel() const;
bool operator==(const screen_mode &otherMode) const;
bool operator!=(const screen_mode &otherMode) const;
};
class ScreenMode {
public:
ScreenMode(BWindow* window);
~ScreenMode();
status_t Set(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);
screen_mode ModeAt(int32 index);
int32 CountModes();
private:
bool GetDisplayMode(screen_mode& mode, display_mode& displayMode);
BWindow* fWindow;
display_mode* fModeList;
uint32 fModeCount;
bool fUpdatedMode;
display_mode fOriginalDisplayMode;
screen_mode fOriginal;
};
#endif /* SCREEN_MODE_H */

File diff suppressed because it is too large Load Diff

View File

@ -5,18 +5,22 @@
* Authors:
* Rafael Romo
* Stefano Ceccherini (burton666@libero.it)
* Thomas Kurschel
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef SCREEN_WINDOW_H
#define SCREEN_WINDOW_H
#include <Screen.h>
#include <Window.h>
#include "ScreenMode.h"
class BBox;
class BPopUpMenu;
class BMenuField;
class RefreshWindow;
class MonitorView;
class ScreenSettings;
@ -30,48 +34,49 @@ class ScreenWindow : public BWindow {
virtual bool QuitRequested();
virtual void MessageReceived(BMessage *message);
virtual void WorkspaceActivated(int32 ws, bool state);
virtual void FrameMoved(BPoint position);
virtual void ScreenChanged(BRect frame, color_space mode);
private:
void SetStateByMode();
void CheckApplyEnabled();
void CheckUpdateDisplayModes();
void CheckModesByResolution(const char*);
void ApplyMode();
ScreenSettings *fSettings;
void CheckResolutionMenu();
void CheckColorMenu();
void CheckRefreshMenu();
MonitorView *fMonitorView;
BPopUpMenu *fWorkspaceMenu;
BMenuField *fWorkspaceField;
BPopUpMenu *fWorkspaceCountMenu;
BMenuField *fWorkspaceCountField;
BPopUpMenu *fResolutionMenu;
BMenuField *fResolutionField;
BPopUpMenu *fColorsMenu;
BMenuField *fColorsField;
BPopUpMenu *fRefreshMenu;
BMenuField *fRefreshField;
BMenuItem *fCurrentWorkspaceItem;
BMenuItem *fAllWorkspacesItem;
BButton *fDefaultsButton;
BButton *fApplyButton;
BButton *fRevertButton;
void UpdateActiveMode();
void UpdateRefreshControl();
void UpdateMonitorView();
void UpdateControls();
BMenuItem *fInitialResolution;
BMenuItem *fInitialColors;
BMenuItem *fInitialRefresh;
BMenuItem *fOtherRefresh;
void Apply();
display_mode fInitialMode;
display_mode *fSupportedModes;
uint32 fTotalModes;
bool CanApply() const;
bool CanRevert() const;
float fMinRefresh;
float fMaxRefresh;
float fCustomRefresh;
float fInitialRefreshN;
ScreenSettings* fSettings;
MonitorView* fMonitorView;
BMenuItem* fAllWorkspacesItem;
BPopUpMenu* fResolutionMenu;
BMenuField* fResolutionField;
BPopUpMenu* fColorsMenu;
BMenuField* fColorsField;
BPopUpMenu* fRefreshMenu;
BMenuField* fRefreshField;
BMenuItem* fOtherRefresh;
BPopUpMenu* fCombineMenu;
BPopUpMenu* fSwapDisplaysMenu;
BPopUpMenu* fUseLaptopPanelMenu;
BPopUpMenu* fTVStandardMenu;
BButton* fDefaultsButton;
BButton* fApplyButton;
BButton* fRevertButton;
ScreenMode fScreenMode;
bool fChangingAllWorkspaces;
screen_mode fActive, fSelected, fOriginal;
};
#endif /* SCREEN_WINDOW_H */

View File

@ -0,0 +1,218 @@
/*
Copyright (c) 2002, Thomas Kurschel
Part of Radeon driver
Multi-Monitor Settings interface
*/
#include <OS.h>
#include "multimon.h"
#include "accelerant_ext.h"
#include <stdio.h>
#include <memory.h>
#include <Screen.h>
// prepare parameters so they recognized as tunneled settings
static void PrepareTunnel(
display_mode *mode, display_mode *low, display_mode *high )
{
memset( mode, 0, sizeof( *mode ));
// mark modes as settings tunnel
mode->space = low->space = high->space = 0;
low->virtual_width = 0xffff;
low->virtual_height = 0xffff;
high->virtual_width = 0;
high->virtual_height = 0;
mode->timing.pixel_clock = 0;
low->timing.pixel_clock = 'TKTK';
high->timing.pixel_clock = 'KTKT';
}
// retrieve value of setting "code"
static status_t GetSetting(
BScreen *screen, uint16 code, uint32 *setting )
{
display_mode mode, low, high;
status_t result;
result = TestMultiMonSupport( screen );
if( result != B_OK )
return result;
PrepareTunnel( &mode, &low, &high );
mode.h_display_start = code;
mode.v_display_start = 0;
result = screen->ProposeMode( &mode, &low, &high );
if( result != B_OK )
return result;
*setting = mode.timing.flags;
return B_OK;
}
// set setting "code" to "value"
static status_t SetSetting(
BScreen *screen, uint16 code, uint32 value )
{
display_mode mode, low, high;
status_t result;
result = TestMultiMonSupport( screen );
if( result != B_OK )
return result;
PrepareTunnel( &mode, &low, &high );
mode.h_display_start = code;
mode.v_display_start = 1;
mode.timing.flags = value;
return screen->ProposeMode( &mode, &low, &high );
}
// retrieve n-th supported value of setting "code"
static status_t GetNthSupportedSetting(
BScreen *screen, uint16 code, int32 idx, uint32 *setting )
{
display_mode mode, low, high;
status_t result;
result = TestMultiMonSupport( screen );
if( result != B_OK )
return result;
PrepareTunnel( &mode, &low, &high );
mode.h_display_start = code;
mode.v_display_start = 2;
mode.timing.flags = idx;
result = screen->ProposeMode( &mode, &low, &high );
if( result != B_OK )
return result;
*setting = mode.timing.flags;
return B_OK;
}
// get current Swap Displays settings
status_t GetSwapDisplays(
BScreen *screen, bool *swap )
{
status_t result;
uint32 tmp;
result = GetSetting( screen, ms_swap, &tmp );
if( result != B_OK )
return result;
*swap = tmp != 0;
return B_OK;
}
// set "Swap Displays"
status_t SetSwapDisplays(
BScreen *screen, bool swap )
{
return SetSetting( screen, ms_swap, swap );
}
// get current "Use Laptop Panel" settings
status_t GetUseLaptopPanel(
BScreen *screen, bool *use )
{
status_t result;
uint32 tmp;
result = GetSetting( screen, ms_use_laptop_panel, &tmp );
if( result != B_OK )
return result;
*use = tmp != 0;
return B_OK;
}
// set "Use Laptop Panel"
status_t SetUseLaptopPanel(
BScreen *screen, bool use )
{
return SetSetting( screen, ms_use_laptop_panel, use );
}
// get n-th supported TV standard
status_t GetNthSupportedTVStandard( BScreen *screen, int idx, uint32 *standard )
{
return GetNthSupportedSetting(
screen, ms_tv_standard, (int32)idx, standard );
}
// get current TV Standard settings
status_t GetTVStandard( BScreen *screen, uint32 *standard )
{
return GetSetting( screen, ms_tv_standard, standard );
}
// set TV Standard
status_t SetTVStandard( BScreen *screen, uint32 standard )
{
return SetSetting( screen, ms_tv_standard, standard );
}
// Verify existence of Multi-Monitor Settings Tunnel
status_t TestMultiMonSupport( BScreen *screen )
{
display_mode *mode_list;
display_mode low, high;
uint32 count;
status_t result;
// take any valid mode
result = screen->GetModeList( &mode_list, &count );
if( result != B_OK )
return result;
if( count < 1 )
return B_ERROR;
// set request bits
mode_list[0].timing.flags |= RADEON_MODE_MULTIMON_REQUEST;
mode_list[0].timing.flags &= ~RADEON_MODE_MULTIMON_REPLY;
low = high = mode_list[0];
result = screen->ProposeMode( &mode_list[0], &low, &high );
if( result != B_OK )
goto err;
// check reply bits
if( (mode_list[0].timing.flags & RADEON_MODE_MULTIMON_REQUEST) == 0 &&
(mode_list[0].timing.flags & RADEON_MODE_MULTIMON_REPLY) != 0 )
result = B_OK;
else
result = B_ERROR;
err:
delete mode_list;
return result;
}