VM Preflet: Add support for device selection

* Enables swap file to be placed on non-boot partition
* Changes tied closely to recent kernel virtual memory change
This commit is contained in:
Hamish Morrison
2012-09-07 00:12:37 +00:00
committed by Alexander von Gluck IV
parent 5c69b8405b
commit b8838e91d9
7 changed files with 538 additions and 509 deletions
+4 -2
View File
@@ -1,14 +1,16 @@
SubDir HAIKU_TOP src preferences virtualmemory ; SubDir HAIKU_TOP src preferences virtualmemory ;
UsePrivateHeaders shared system ;
Preference VirtualMemory : Preference VirtualMemory :
VirtualMemory.cpp VirtualMemory.cpp
SettingsWindow.cpp SettingsWindow.cpp
Settings.cpp Settings.cpp
$(DRIVER_SETTINGS) $(DRIVER_SETTINGS)
: be $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS) : be libshared.a $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS)
: VirtualMemory.rdef : VirtualMemory.rdef
; ;
if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
SEARCH on [ FGristFiles driver_settings.c ] += SEARCH on [ FGristFiles driver_settings.c ] +=
+189 -176
View File
@@ -7,186 +7,179 @@
#include "Settings.h" #include "Settings.h"
#include <File.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Path.h>
#include <Volume.h>
#include <VolumeRoster.h>
#include <driver_settings.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <VolumeRoster.h>
static const char* kWindowSettingsFile = "VM_data"; #include <driver_settings.h>
static const char* kVirtualMemorySettings = "virtual_memory";
static const int64 kMegaByte = 1024 * 1024;
static const char* const kWindowSettingsFile = "VM_data";
static const char* const kVirtualMemorySettings = "virtual_memory";
static const off_t kMegaByte = 1024 * 1024;
Settings::Settings() Settings::Settings()
:
fPositionUpdated(false)
{ {
_ReadWindowSettings(); fDefaultSettings.enabled = true;
_ReadSwapSettings();
system_info sysInfo;
get_system_info(&sysInfo);
fDefaultSettings.size = (off_t)sysInfo.max_pages * B_PAGE_SIZE * 2;
fDefaultSettings.volume = dev_for_path("/boot");
} }
Settings::~Settings() void
Settings::SetSwapEnabled(bool enabled, bool revertable)
{ {
_WriteWindowSettings(); fCurrentSettings.enabled = enabled;
_WriteSwapSettings(); if (!revertable)
fInitialSettings.enabled = enabled;
}
void
Settings::SetSwapSize(off_t size, bool revertable)
{
fCurrentSettings.size = size;
if (!revertable)
fInitialSettings.size = size;
}
void
Settings::SetSwapVolume(dev_t volume, bool revertable)
{
fCurrentSettings.volume = volume;
if (!revertable)
fInitialSettings.volume = volume;
} }
void void
Settings::SetWindowPosition(BPoint position) Settings::SetWindowPosition(BPoint position)
{ {
if (position == fWindowPosition)
return;
fWindowPosition = position; fWindowPosition = position;
fPositionUpdated = true;
} }
void status_t
Settings::SetSwapEnabled(bool enabled) Settings::ReadWindowSettings()
{ {
fSwapEnabled = enabled;
}
void
Settings::SetSwapSize(off_t size)
{
fSwapSize = size;
}
void
Settings::SetSwapVolume(BVolume &volume)
{
if (volume.Device() == SwapVolume().Device()
|| volume.InitCheck() != B_OK)
return;
fSwapVolume.SetTo(volume.Device());
}
void
Settings::RevertSwapChanges()
{
fSwapEnabled = fInitialSwapEnabled;
fSwapSize = fInitialSwapSize;
fSwapVolume.SetTo(fInitialSwapVolume);
}
bool
Settings::IsRevertible()
{
return fSwapEnabled != fInitialSwapEnabled
|| fSwapSize != fInitialSwapSize
|| fSwapVolume.Device() != fInitialSwapVolume;
}
void
Settings::_ReadWindowSettings()
{
bool success = false;
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK)
if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint))
success = true;
}
if (!success)
fWindowPosition.Set(-1, -1);
}
void
Settings::_WriteWindowSettings()
{
if (!fPositionUpdated)
return;
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK)
return;
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) == B_OK)
file.Write(&fWindowPosition, sizeof(BPoint));
}
void
Settings::_ReadSwapSettings()
{
void* settings = load_driver_settings(kVirtualMemorySettings);
if (settings != NULL) {
SetSwapEnabled(get_driver_boolean_parameter(settings, "vm", false, false));
const char* swapSize = get_driver_parameter(settings, "swap_size", NULL, NULL);
SetSwapSize(swapSize ? atoll(swapSize) : 0);
#ifdef SWAP_VOLUME_IMPLEMENTED
// we need to hang onto this one
fBadVolName = strdup(get_driver_parameter(settings, "swap_volume", NULL, NULL));
BVolumeRoster volumeRoster;
BVolume temporaryVolume;
if (fBadVolName != NULL) {
status_t result = volumeRoster.GetNextVolume(&temporaryVolume);
char volumeName[B_FILE_NAME_LENGTH];
while (result != B_BAD_VALUE) {
temporaryVolume.GetName(volumeName);
if (strcmp(volumeName, fBadVolName) == 0
&& temporaryVolume.IsPersistent() && volumeName[0]) {
SetSwapVolume(temporaryVolume);
break;
}
result = volumeRoster.GetNextVolume(&temporaryVolume);
}
} else
volumeRoster.GetBootVolume(&fSwapVolume);
#endif
unload_driver_settings(settings);
} else
_SetSwapNull();
#ifndef SWAP_VOLUME_IMPLEMENTED
BVolumeRoster volumeRoster;
volumeRoster.GetBootVolume(&fSwapVolume);
#endif
fInitialSwapEnabled = fSwapEnabled;
fInitialSwapSize = fSwapSize;
fInitialSwapVolume = fSwapVolume.Device();
}
void
Settings::_WriteSwapSettings()
{
if (!IsRevertible())
return;
BPath path; BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return; return B_ERROR;
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_READ_ONLY) != B_OK)
return B_ERROR;
if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint))
return B_OK;
else
return B_ERROR;
}
status_t
Settings::WriteWindowSettings()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK)
return B_ERROR;
path.Append(kWindowSettingsFile);
BFile file;
if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE)
!= B_OK)
return B_ERROR;
file.Write(&fWindowPosition, sizeof(BPoint));
return B_OK;
}
status_t
Settings::ReadSwapSettings()
{
void* settings = load_driver_settings(kVirtualMemorySettings);
if (settings == NULL)
return kErrorSettingsNotFound;
const char* enabled = get_driver_parameter(settings, "vm", NULL, NULL);
const char* size = get_driver_parameter(settings, "swap_size", NULL, NULL);
const char* volume = get_driver_parameter(settings, "swap_volume_name",
NULL, NULL);
const char* device = get_driver_parameter(settings,
"swap_volume_device", NULL, NULL);
const char* filesystem = get_driver_parameter(settings,
"swap_volume_filesystem", NULL, NULL);
const char* capacity = get_driver_parameter(settings,
"swap_volume_capacity", NULL, NULL);
if (enabled == NULL || size == NULL || device == NULL || volume == NULL
|| capacity == NULL || filesystem == NULL)
return kErrorSettingsInvalid;
off_t volCapacity = atoll(capacity);
SetSwapEnabled(get_driver_boolean_parameter(settings,
"vm", false, false));
SetSwapSize(atoll(size));
unload_driver_settings(settings);
int32 bestScore = -1;
dev_t bestVol = -1;
BVolume vol;
fs_info volStat;
BVolumeRoster roster;
while (roster.GetNextVolume(&vol) == B_OK) {
if (!vol.IsPersistent() || vol.IsReadOnly() || vol.IsRemovable()
|| vol.IsShared())
continue;
if (fs_stat_dev(vol.Device(), &volStat) == 0) {
int32 score = 0;
if (strcmp(volume, volStat.volume_name) == 0)
score += 4;
if (strcmp(device, volStat.device_name) == 0)
score += 3;
if (volCapacity == volStat.total_blocks * volStat.block_size)
score += 2;
if (strcmp(filesystem, volStat.fsh_name) == 0)
score += 1;
if (score >= 4 && score > bestScore) {
bestVol = vol.Device();
bestScore = score;
}
}
}
SetSwapVolume(bestVol);
fInitialSettings = fCurrentSettings;
if (bestVol < 0)
return kErrorVolumeNotFound;
else
return B_OK;
}
status_t
Settings::WriteSwapSettings()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_ERROR;
path.Append("kernel/drivers"); path.Append("kernel/drivers");
path.Append(kVirtualMemorySettings); path.Append(kVirtualMemorySettings);
@@ -194,36 +187,56 @@ Settings::_WriteSwapSettings()
BFile file; BFile file;
if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE)
!= B_OK) != B_OK)
return; return B_ERROR;
char buffer[256]; fs_info info;
#ifdef SWAP_VOLUME_IMPLEMENTED fs_stat_dev(SwapVolume(), &info);
char volumeName[B_FILE_NAME_LENGTH] = {0};
if (SwapVolume().InitCheck() != B_NO_INIT) char buffer[1024];
SwapVolume().GetName(volumeName); snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %lld\n"
else if (fBadVolName) "swap_volume_name %s\nswap_volume_device %s\n"
strcpy(volumeName, fBadVolName); "swap_volume_filesystem %s\nswap_volume_capacity %lld\n",
snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %Ld\nswap_volume %s\n", SwapEnabled() ? "on" : "off", SwapSize(), info.volume_name,
SwapEnabled() ? "on" : "off", SwapSize(), info.device_name, info.fsh_name, info.total_blocks * info.block_size);
volumeName[0] ? volumeName : NULL);
#else
snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %Ld\n",
fSwapEnabled ? "on" : "off", fSwapSize);
#endif
file.Write(buffer, strlen(buffer)); file.Write(buffer, strlen(buffer));
return B_OK;
}
bool
Settings::IsRevertable()
{
return SwapEnabled() != fInitialSettings.enabled
|| SwapSize() != fInitialSettings.size
|| SwapVolume() != fInitialSettings.volume;
} }
void void
Settings::_SetSwapNull() Settings::RevertSwapSettings()
{ {
SetSwapEnabled(false); SetSwapEnabled(fInitialSettings.enabled);
BVolumeRoster volumeRoster; SetSwapSize(fInitialSettings.size);
BVolume temporaryVolume; SetSwapVolume(fInitialSettings.volume);
volumeRoster.GetBootVolume(&temporaryVolume);
SetSwapVolume(temporaryVolume);
SetSwapSize(0);
} }
bool
Settings::IsDefaultable()
{
return SwapEnabled() != fDefaultSettings.enabled
|| SwapSize() != fDefaultSettings.size
|| SwapVolume() != fDefaultSettings.volume;
}
void
Settings::DefaultSwapSettings(bool revertable)
{
SetSwapEnabled(fDefaultSettings.enabled);
SetSwapSize(fDefaultSettings.size);
SetSwapVolume(fDefaultSettings.volume);
if (!revertable)
fInitialSettings = fDefaultSettings;
}
+40 -31
View File
@@ -1,54 +1,63 @@
/* /*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2011, Hamish Morrison, [email protected]
* Distributed under the terms of the MIT License. * Copyright 2005, Axel Dörfler, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef SETTINGS_H #ifndef SETTINGS_H
#define SETTINGS_H #define SETTINGS_H
#include <stdio.h>
#include <stdlib.h>
#include <Point.h> #include <Point.h>
#include <Volume.h>
static const int32 kErrorSettingsNotFound = B_ERRORS_END + 1;
static const int32 kErrorSettingsInvalid = B_ERRORS_END + 2;
static const int32 kErrorVolumeNotFound = B_ERRORS_END + 3;
class Settings { class Settings {
public : public:
Settings(); Settings();
virtual ~Settings();
bool SwapEnabled() const
{ return fCurrentSettings.enabled; }
off_t SwapSize() const { return fCurrentSettings.size; }
dev_t SwapVolume() { return fCurrentSettings.volume; }
BPoint WindowPosition() const { return fWindowPosition; } BPoint WindowPosition() const { return fWindowPosition; }
void SetSwapEnabled(bool enabled,
bool revertable = true);
void SetSwapSize(off_t size, bool revertable = true);
void SetSwapVolume(dev_t volume,
bool revertable = true);
void SetWindowPosition(BPoint position); void SetWindowPosition(BPoint position);
bool SwapEnabled() const { return fSwapEnabled; } status_t ReadWindowSettings();
off_t SwapSize() const { return fSwapSize; } status_t WriteWindowSettings();
BVolume& SwapVolume() { return fSwapVolume; } status_t ReadSwapSettings();
void SetSwapEnabled(bool enabled); status_t WriteSwapSettings();
void SetSwapSize(off_t size);
void SetSwapVolume(BVolume& volume);
void RevertSwapChanges(); bool IsRevertable();
bool IsRevertible(); void RevertSwapSettings();
private: bool IsDefaultable();
void _ReadWindowSettings(); void DefaultSwapSettings(bool revertable = true);
void _WriteWindowSettings(); private:
struct SwapSettings {
void _ReadSwapSettings(); bool enabled;
void _WriteSwapSettings(); off_t size;
dev_t volume;
void _SetSwapNull(); };
BPoint fWindowPosition; BPoint fWindowPosition;
bool fSwapEnabled; SwapSettings fCurrentSettings;
off_t fSwapSize; SwapSettings fInitialSettings;
BVolume fSwapVolume; SwapSettings fDefaultSettings;
bool fInitialSwapEnabled;
off_t fInitialSwapSize;
dev_t fInitialSwapVolume;
bool fPositionUpdated;
const char* fBadVolName;
}; };
#endif /* SETTINGS_H */ #endif /* SETTINGS_H */
+246 -267
View File
@@ -6,7 +6,6 @@
#include "SettingsWindow.h" #include "SettingsWindow.h"
#include "Settings.h"
#include <Application.h> #include <Application.h>
#include <Alert.h> #include <Alert.h>
@@ -14,22 +13,25 @@
#include <Button.h> #include <Button.h>
#include <Catalog.h> #include <Catalog.h>
#include <CheckBox.h> #include <CheckBox.h>
#include <GroupLayout.h> #include <Directory.h>
#include <GroupLayoutBuilder.h> #include <FindDirectory.h>
#include <Locale.h> #include <LayoutBuilder.h>
#include <MenuItem.h>
#include <MenuField.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <Screen.h>
#include <StringForSize.h>
#include <StringView.h> #include <StringView.h>
#include <String.h> #include <String.h>
#include <Slider.h> #include <Slider.h>
#include <PopUpMenu.h> #include <system_info.h>
#include <MenuItem.h>
#include <MenuField.h>
#include <Screen.h>
#include <FindDirectory.h>
#include <Path.h>
#include <Volume.h> #include <Volume.h>
#include <VolumeRoster.h> #include <VolumeRoster.h>
#include <stdio.h> #include "Settings.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SettingsWindow" #define B_TRANSLATION_CONTEXT "SettingsWindow"
@@ -40,90 +42,70 @@ static const uint32 kMsgRevert = 'rvrt';
static const uint32 kMsgSliderUpdate = 'slup'; static const uint32 kMsgSliderUpdate = 'slup';
static const uint32 kMsgSwapEnabledUpdate = 'swen'; static const uint32 kMsgSwapEnabledUpdate = 'swen';
static const uint32 kMsgVolumeSelected = 'vlsl'; static const uint32 kMsgVolumeSelected = 'vlsl';
static const int64 kMegaByte = 1024 * 1024; static const off_t kMegaByte = 1024 * 1024;
static dev_t bootDev = -1;
class SizeSlider : public BSlider {
public:
SizeSlider(const char* name, const char* label,
BMessage* message, int32 min, int32 max, uint32 flags);
virtual ~SizeSlider();
virtual const char* UpdateText() const;
private:
mutable BString fText;
};
SizeSlider::SizeSlider(const char* name, const char* label, SizeSlider::SizeSlider(const char* name, const char* label,
BMessage* message, int32 min, int32 max, uint32 flags) BMessage* message, int32 min, int32 max, uint32 flags)
: BSlider(name, label, message, min, max, B_HORIZONTAL, B_BLOCK_THUMB, flags) :
BSlider(name, label, message, min, max, B_HORIZONTAL,
B_BLOCK_THUMB, flags)
{ {
rgb_color color = ui_color(B_CONTROL_HIGHLIGHT_COLOR); rgb_color color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
UseFillColor(true, &color); UseFillColor(true, &color);
} }
SizeSlider::~SizeSlider()
{
}
const char*
byte_string(int64 size)
{
double value = 1. * size;
static char string[256];
if (value < 1024)
snprintf(string, sizeof(string), B_TRANSLATE("%Ld B"), size);
else {
static const char *units[] = {
B_TRANSLATE_MARK("KB"),
B_TRANSLATE_MARK("MB"),
B_TRANSLATE_MARK("GB"),
NULL
};
int32 i = -1;
do {
value /= 1024.0;
i++;
} while (value >= 1024 && units[i + 1]);
off_t rounded = off_t(value * 100LL);
snprintf(string, sizeof(string), "%g %s", rounded / 100.0,
B_TRANSLATE_NOCOLLECT(units[i]));
}
return string;
}
const char* const char*
SizeSlider::UpdateText() const SizeSlider::UpdateText() const
{ {
fText = byte_string(Value() * kMegaByte); return string_for_size(Value() * kMegaByte, fText, sizeof(fText));
return fText.String();
} }
class VolumeMenuItem : public BMenuItem { VolumeMenuItem::VolumeMenuItem(BVolume volume, BMessage* message)
public: :
VolumeMenuItem(const char* label, BMessage* message, BVolume* volume); BMenuItem("", message),
BVolume* Volume() { return fVolume; } fVolume(volume)
private:
BVolume* fVolume;
};
VolumeMenuItem::VolumeMenuItem(const char* label, BMessage* message,
BVolume* volume)
: BMenuItem(label, message)
{ {
fVolume = volume; GenerateLabel();
}
void
VolumeMenuItem::MessageReceived(BMessage* message)
{
if (message->what == B_NODE_MONITOR) {
int32 code;
if (message->FindInt32("opcode", &code) == B_OK)
if (code == B_ENTRY_MOVED)
GenerateLabel();
}
}
void
VolumeMenuItem::GenerateLabel()
{
char name[B_FILE_NAME_LENGTH + 1];
fVolume.GetName(name);
BDirectory dir;
if (fVolume.GetRootDirectory(&dir) == B_OK) {
BEntry entry;
if (dir.GetEntry(&entry) == B_OK) {
BPath path;
if (entry.GetPath(&path) == B_OK) {
BString label;
label << name << " (" << path.Path() << ")";
SetLabel(label);
return;
}
}
}
SetLabel(name);
} }
@@ -131,81 +113,102 @@ SettingsWindow::SettingsWindow()
: :
BWindow(BRect(0, 0, 269, 172), B_TRANSLATE_SYSTEM_NAME("VirtualMemory"), BWindow(BRect(0, 0, 269, 172), B_TRANSLATE_SYSTEM_NAME("VirtualMemory"),
B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS
| B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS)
fLocked(false)
{ {
BView* view = new BGroupView(); bootDev = dev_for_path("/boot");
BAlignment align(B_ALIGN_LEFT, B_ALIGN_MIDDLE);
if (fSettings.ReadWindowSettings() == B_OK)
MoveTo(fSettings.WindowPosition());
else
CenterOnScreen();
status_t result = fSettings.ReadSwapSettings();
if (result == kErrorSettingsNotFound)
fSettings.DefaultSwapSettings(false);
else if (result == kErrorSettingsInvalid) {
int32 choice = (new BAlert("VirtualMemory",
B_TRANSLATE("The settings specified in the settings file "
"are invalid. You can load the defaults or quit."),
B_TRANSLATE("Load defaults"), B_TRANSLATE("Quit")))->Go();
if (choice == 1) {
be_app->PostMessage(B_QUIT_REQUESTED);
return;
}
fSettings.DefaultSwapSettings(false);
} else if (result == kErrorVolumeNotFound) {
int32 choice = (new BAlert("VirtualMemory",
B_TRANSLATE("The volume specified in the settings file "
"could not be found. You can use the boot volume or quit."),
B_TRANSLATE("Use boot volume"), B_TRANSLATE("Quit")))->Go();
if (choice == 1) {
be_app->PostMessage(B_QUIT_REQUESTED);
return;
}
fSettings.SetSwapVolume(bootDev, false);
}
fSwapEnabledCheckBox = new BCheckBox("enable swap", fSwapEnabledCheckBox = new BCheckBox("enable swap",
B_TRANSLATE("Enable virtual memory"), B_TRANSLATE("Enable virtual memory"),
new BMessage(kMsgSwapEnabledUpdate)); new BMessage(kMsgSwapEnabledUpdate));
fSwapEnabledCheckBox->SetExplicitAlignment(align);
BBox* box = new BBox("box", B_FOLLOW_LEFT_RIGHT); char sizeStr[16];
box->SetLabel(fSwapEnabledCheckBox);
system_info info; system_info info;
get_system_info(&info); get_system_info(&info);
BString string = B_TRANSLATE("Physical memory: "); BString string = B_TRANSLATE("Physical memory: ");
string << byte_string((off_t)info.max_pages * B_PAGE_SIZE); string << string_for_size(info.max_pages * B_PAGE_SIZE, sizeStr,
BStringView* memoryView = new BStringView("physical memory", string.String()); sizeof(sizeStr));
BStringView* memoryView = new BStringView("physical memory",
string.String());
memoryView->SetExplicitAlignment(align);
system_memory_info memInfo = {};
__get_system_info_etc(B_MEMORY_INFO, &memInfo, sizeof(memInfo));
string = B_TRANSLATE("Current swap file size: "); string = B_TRANSLATE("Current swap file size: ");
string << byte_string(fSettings.SwapSize()); string << string_for_size(memInfo.max_swap_space, sizeStr,
BStringView* swapfileView = new BStringView("current swap size", string.String()); sizeof(sizeStr));
BStringView* swapFileView = new BStringView("current swap size",
string.String());
swapFileView->SetExplicitAlignment(align);
BPopUpMenu* menu = new BPopUpMenu("invalid"); BPopUpMenu* menu = new BPopUpMenu("volume menu");
fVolumeMenuField = new BMenuField("volume menu field",
B_TRANSLATE("Use volume:"), menu);
fVolumeMenuField->SetExplicitAlignment(align);
// collect volumes BVolumeRoster roster;
// TODO: listen to volume changes! BVolume vol;
// TODO: accept dropped volumes while (roster.GetNextVolume(&vol) == B_OK) {
if (!vol.IsPersistent() || vol.IsReadOnly() || vol.IsRemovable()
BVolumeRoster volumeRoster; || vol.IsShared())
BVolume* volume = new BVolume();
char name[B_FILE_NAME_LENGTH];
while (volumeRoster.GetNextVolume(volume) == B_OK) {
if (!volume->IsPersistent() || volume->GetName(name) != B_OK || !name[0])
continue; continue;
VolumeMenuItem* item = new VolumeMenuItem(name, _AddVolumeMenuItem(vol.Device());
new BMessage(kMsgVolumeSelected), volume);
menu->AddItem(item);
volume = new BVolume();
} }
fVolumeMenuField = new BMenuField("volumes", B_TRANSLATE("Use volume:"), menu); watch_node(NULL, B_WATCH_MOUNT, this, this);
fSizeSlider = new SizeSlider("size slider", fSizeSlider = new SizeSlider("size slider",
B_TRANSLATE("Requested swap file size:"), new BMessage(kMsgSliderUpdate), B_TRANSLATE("Requested swap file size:"),
1, 1, B_WILL_DRAW | B_FRAME_EVENTS); new BMessage(kMsgSliderUpdate), 0, 0, B_WILL_DRAW | B_FRAME_EVENTS);
fSizeSlider->SetViewColor(255, 0, 255); fSizeSlider->SetViewColor(255, 0, 255);
fSizeSlider->SetExplicitAlignment(align);
fWarningStringView = new BStringView("", ""); fWarningStringView = new BStringView("warning",
fWarningStringView->SetAlignment(B_ALIGN_CENTER); B_TRANSLATE("Changes will take effect upon reboot."));
view->SetLayout(new BGroupLayout(B_HORIZONTAL)); BBox* box = new BBox("box");
view->AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) box->SetLabel(fSwapEnabledCheckBox);
.AddGroup(B_HORIZONTAL)
box->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, B_USE_DEFAULT_SPACING)
.Add(memoryView) .Add(memoryView)
.AddGlue() .Add(swapFileView)
.End()
.AddGroup(B_HORIZONTAL)
.Add(swapfileView)
.AddGlue()
.End()
#ifdef SWAP_VOLUME_IMPLEMENTED
.AddGroup(B_HORIZONTAL)
.Add(fVolumeMenuField) .Add(fVolumeMenuField)
.AddGlue()
.End()
#else
.AddGlue()
#endif
.Add(fSizeSlider) .Add(fSizeSlider)
.Add(fWarningStringView) .Add(fWarningStringView)
.SetInsets(10, 10, 10, 10) .SetInsets(10)
); .View());
box->AddChild(view);
fDefaultsButton = new BButton("defaults", B_TRANSLATE("Defaults"), fDefaultsButton = new BButton("defaults", B_TRANSLATE("Defaults"),
new BMessage(kMsgDefaults)); new BMessage(kMsgDefaults));
@@ -214,16 +217,14 @@ SettingsWindow::SettingsWindow()
new BMessage(kMsgRevert)); new BMessage(kMsgRevert));
fRevertButton->SetEnabled(false); fRevertButton->SetEnabled(false);
SetLayout(new BGroupLayout(B_HORIZONTAL)); BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
AddChild(BGroupLayoutBuilder(B_VERTICAL, 10)
.Add(box) .Add(box)
.AddGroup(B_HORIZONTAL, 10) .AddGroup(B_HORIZONTAL, 10)
.Add(fDefaultsButton) .Add(fDefaultsButton)
.Add(fRevertButton) .Add(fRevertButton)
.AddGlue() .AddGlue()
.End() .End()
.SetInsets(10, 10, 10, 10) .SetInsets(10);
);
BScreen screen; BScreen screen;
BRect screenFrame = screen.Frame(); BRect screenFrame = screen.Frame();
@@ -258,21 +259,37 @@ SettingsWindow::SettingsWindow()
} }
SettingsWindow::~SettingsWindow()
{
}
void void
SettingsWindow::MessageReceived(BMessage* message) SettingsWindow::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case B_NODE_MONITOR:
{
int32 opcode;
if (message->FindInt32("opcode", &opcode) != B_OK)
break;
dev_t device;
if (opcode == B_DEVICE_MOUNTED
&& message->FindInt32("new device", &device) == B_OK) {
BVolume vol(device);
if (!vol.IsPersistent() || vol.IsReadOnly()
|| vol.IsRemovable() || vol.IsShared()) {
break;
}
_AddVolumeMenuItem(device);
} else if (opcode == B_DEVICE_UNMOUNTED
&& message->FindInt32("device", &device) == B_OK) {
_RemoveVolumeMenuItem(device);
}
_Update();
break;
}
case kMsgRevert: case kMsgRevert:
fSettings.RevertSwapChanges(); fSettings.RevertSwapSettings();
_Update(); _Update();
break; break;
case kMsgDefaults: case kMsgDefaults:
_SetSwapDefaults(); fSettings.DefaultSwapSettings();
_Update(); _Update();
break; break;
case kMsgSliderUpdate: case kMsgSliderUpdate:
@@ -280,18 +297,15 @@ SettingsWindow::MessageReceived(BMessage* message)
_Update(); _Update();
break; break;
case kMsgVolumeSelected: case kMsgVolumeSelected:
fSettings.SetSwapVolume(*((VolumeMenuItem*)fVolumeMenuField->Menu() fSettings.SetSwapVolume(((VolumeMenuItem*)fVolumeMenuField
->FindMarked())->Volume()); ->Menu()->FindMarked())->Volume().Device());
_Update(); _Update();
break; break;
case kMsgSwapEnabledUpdate: case kMsgSwapEnabledUpdate:
{ {
int32 value; if (fSwapEnabledCheckBox->Value() == 0) {
if (message->FindInt32("be:value", &value) != B_OK) // print out warning, give the user the
break; // time to think about it :)
if (value == 0) {
// print out warning, give the user the time to think about it :)
// ToDo: maybe we want to remove this possibility in the GUI // ToDo: maybe we want to remove this possibility in the GUI
// as Be did, but I thought a proper warning could be helpful // as Be did, but I thought a proper warning could be helpful
// (for those that want to change that anyway) // (for those that want to change that anyway)
@@ -312,7 +326,7 @@ SettingsWindow::MessageReceived(BMessage* message)
} }
} }
fSettings.SetSwapEnabled(value != 0); fSettings.SetSwapEnabled(fSwapEnabledCheckBox->Value());
_Update(); _Update();
break; break;
} }
@@ -327,142 +341,107 @@ bool
SettingsWindow::QuitRequested() SettingsWindow::QuitRequested()
{ {
fSettings.SetWindowPosition(Frame().LeftTop()); fSettings.SetWindowPosition(Frame().LeftTop());
fSettings.WriteWindowSettings();
fSettings.WriteSwapSettings();
be_app->PostMessage(B_QUIT_REQUESTED); be_app->PostMessage(B_QUIT_REQUESTED);
return true; return true;
} }
status_t
SettingsWindow::_AddVolumeMenuItem(dev_t device)
{
if (_FindVolumeMenuItem(device) != NULL)
return B_ERROR;
VolumeMenuItem* item = new VolumeMenuItem(device,
new BMessage(kMsgVolumeSelected));
fs_info info;
if (fs_stat_dev(device, &info) == 0) {
node_ref node;
node.device = info.dev;
node.node = info.root;
AddHandler(item);
watch_node(&node, B_WATCH_NAME, item);
}
fVolumeMenuField->Menu()->AddItem(item);
return B_OK;
}
status_t
SettingsWindow::_RemoveVolumeMenuItem(dev_t device)
{
VolumeMenuItem* item = _FindVolumeMenuItem(device);
if (item != NULL) {
fVolumeMenuField->Menu()->RemoveItem(item);
delete item;
return B_OK;
} else
return B_ERROR;
}
VolumeMenuItem*
SettingsWindow::_FindVolumeMenuItem(dev_t device)
{
VolumeMenuItem* item = NULL;
int32 count = fVolumeMenuField->Menu()->CountItems();
for (int i = 0; i < count; i++) {
item = (VolumeMenuItem*)fVolumeMenuField->Menu()->ItemAt(i);
if (item->Volume().Device() == device)
return item;
}
return NULL;
}
void void
SettingsWindow::_Update() SettingsWindow::_Update()
{ {
if ((fSwapEnabledCheckBox->Value() != 0) != fSettings.SwapEnabled())
fSwapEnabledCheckBox->SetValue(fSettings.SwapEnabled()); fSwapEnabledCheckBox->SetValue(fSettings.SwapEnabled());
#ifdef SWAP_VOLUME_IMPLEMENTED VolumeMenuItem* item = _FindVolumeMenuItem(fSettings.SwapVolume());
if (fVolumeMenuField->IsEnabled() != fSettings.SwapEnabled()) if (item != NULL) {
fVolumeMenuField->SetEnabled(fSettings.SwapEnabled()); fSizeSlider->SetEnabled(true);
VolumeMenuItem* selectedVolumeItem = item->SetMarked(true);
(VolumeMenuItem*)fVolumeMenuField->Menu()->FindMarked(); BEntry swapFile;
if (selectedVolumeItem == NULL) { if (bootDev == item->Volume().Device())
VolumeMenuItem* currentVolumeItem; swapFile.SetTo("/var/swap");
int32 items = fVolumeMenuField->Menu()->CountItems(); else {
for (int32 index = 0; index < items; ++index) { BDirectory root;
currentVolumeItem = ((VolumeMenuItem*)fVolumeMenuField->Menu()->ItemAt(index)); item->Volume().GetRootDirectory(&root);
if (*(currentVolumeItem->fVolume) == fSettings.SwapVolume()) { swapFile.SetTo(&root, "swap");
currentVolumeItem->SetMarked(true);
break;
} }
}
} else if (*selectedVolumeItem->fVolume != fSettings.SwapVolume()) {
VolumeMenuItem* currentVolumeItem;
int32 items = fVolumeMenuField->Menu()->CountItems();
for (int32 index = 0; index < items; ++index) {
currentVolumeItem = ((VolumeMenuItem*)fVolumeMenuField->Menu()->ItemAt(index));
if (*(currentVolumeItem->fVolume) == fSettings.SwapVolume()) {
currentVolumeItem->SetMarked(true);
break;
}
}
}
#endif
fWarningStringView->SetText(""); off_t swapFileSize = 0;
fLocked = false; swapFile.GetSize(&swapFileSize);
if (fSettings.IsRevertible()) char sizeStr[16];
fWarningStringView->SetText(
B_TRANSLATE("Changes will take effect on restart!"));
if (fRevertButton->IsEnabled() != fSettings.IsRevertible())
fRevertButton->SetEnabled(fSettings.IsRevertible());
off_t minSize, maxSize; off_t freeSpace = item->Volume().FreeBytes() + swapFileSize;
if (_GetSwapFileLimits(minSize, maxSize) == B_OK) { off_t safeSpace = freeSpace - (off_t)(0.15 * freeSpace);
// round to nearest MB -- slider steps in whole MBs (safeSpace >>= 20) <<= 20;
off_t minSize = B_PAGE_SIZE + kMegaByte;
(minSize >>= 20) <<= 20; (minSize >>= 20) <<= 20;
(maxSize >>= 20) <<= 20;
BString minLabel, maxLabel; BString minLabel, maxLabel;
minLabel << byte_string(minSize); minLabel << string_for_size(minSize, sizeStr, sizeof(sizeStr));
maxLabel << byte_string(maxSize); maxLabel << string_for_size(safeSpace, sizeStr, sizeof(sizeStr));
if (minLabel != fSizeSlider->MinLimitLabel()
|| maxLabel != fSizeSlider->MaxLimitLabel()) {
fSizeSlider->SetLimitLabels(minLabel.String(), maxLabel.String()); fSizeSlider->SetLimitLabels(minLabel.String(), maxLabel.String());
fSizeSlider->SetLimits(minSize / kMegaByte, maxSize / kMegaByte); fSizeSlider->SetLimits(minSize / kMegaByte, safeSpace / kMegaByte);
}
} else if (fSettings.SwapEnabled()) {
fWarningStringView->SetText(
B_TRANSLATE("Insufficient space for a swap file."));
fLocked = true;
}
if (fSizeSlider->Value() != fSettings.SwapSize() / kMegaByte)
fSizeSlider->SetValue(fSettings.SwapSize() / kMegaByte); fSizeSlider->SetValue(fSettings.SwapSize() / kMegaByte);
if (fSizeSlider->IsEnabled() != fSettings.SwapEnabled() || fLocked) } else
{ fSizeSlider->SetEnabled(false);
fSizeSlider->SetEnabled(fSettings.SwapEnabled() && !fLocked);
fSettings.SetSwapSize((off_t)fSizeSlider->Value() * kMegaByte); bool revertable = fSettings.IsRevertable();
} if (revertable)
fWarningStringView->Show();
else
fWarningStringView->Hide();
fRevertButton->SetEnabled(revertable);
fDefaultsButton->SetEnabled(fSettings.IsDefaultable());
} }
status_t
SettingsWindow::_GetSwapFileLimits(off_t& minSize, off_t& maxSize)
{
minSize = kMegaByte;
// maximum size is the free space on the current volume
// (minus some safety offset, depending on the disk size)
off_t freeSpace = fSettings.SwapVolume().FreeBytes();
off_t safetyFreeSpace = fSettings.SwapVolume().Capacity() / 100;
if (safetyFreeSpace > 1024 * kMegaByte)
safetyFreeSpace = 1024 * kMegaByte;
// check if there already is a page file on this disk and
// adjust the free space accordingly
BPath path;
if (find_directory(B_COMMON_VAR_DIRECTORY, &path, false,
&fSettings.SwapVolume()) == B_OK) {
path.Append("swap");
BEntry swap(path.Path());
off_t size;
if (swap.GetSize(&size) == B_OK) {
// If swap file exists, forget about safety space;
// disk may have filled after creation of swap file.
safetyFreeSpace = 0;
freeSpace += size;
}
}
maxSize = freeSpace - safetyFreeSpace;
if (maxSize < minSize) {
maxSize = 0;
minSize = 0;
return B_ERROR;
}
return B_OK;
}
void
SettingsWindow::_SetSwapDefaults()
{
fSettings.SetSwapEnabled(true);
BVolumeRoster volumeRoster;
BVolume temporaryVolume;
volumeRoster.GetBootVolume(&temporaryVolume);
fSettings.SetSwapVolume(temporaryVolume);
system_info info;
get_system_info(&info);
off_t defaultSize = (off_t)info.max_pages * B_PAGE_SIZE;
off_t minSize, maxSize;
_GetSwapFileLimits(minSize, maxSize);
if (defaultSize > maxSize / 2)
defaultSize = maxSize / 2;
fSettings.SetSwapSize(defaultSize);
}
+46 -12
View File
@@ -1,33 +1,69 @@
/* /*
* Copyright 2005-2006, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2011, Hamish Morrison, [email protected]
* Distributed under the terms of the MIT License. * Copyright 2005-2006, Axel Dörfler, [email protected]
* All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef SETTINGS_WINDOW_H #ifndef SETTINGS_WINDOW_H
#define SETTINGS_WINDOW_H #define SETTINGS_WINDOW_H
#include <MenuItem.h>
#include <Slider.h>
#include <Volume.h>
#include <Window.h> #include <Window.h>
#include "Settings.h" #include "Settings.h"
class BStringView; class BStringView;
class BCheckBox; class BCheckBox;
class BSlider; class BSlider;
class BButton; class BButton;
class BMenuField; class BMenuField;
class SettingsWindow : public BWindow {
public:
SettingsWindow();
virtual ~SettingsWindow();
virtual bool QuitRequested(); class SizeSlider : public BSlider {
public:
SizeSlider(const char* name, const char* label,
BMessage* message, int32 min, int32 max,
uint32 flags);
virtual ~SizeSlider() {};
virtual const char* UpdateText() const;
private:
mutable char fText[128];
};
class VolumeMenuItem : public BMenuItem, public BHandler {
public:
VolumeMenuItem(BVolume volume, BMessage* message);
virtual ~VolumeMenuItem() {}
virtual BVolume Volume() { return fVolume; }
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
virtual void GenerateLabel();
private:
BVolume fVolume;
};
class SettingsWindow : public BWindow {
public:
SettingsWindow();
virtual ~SettingsWindow() {};
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
private:
status_t _AddVolumeMenuItem(dev_t device);
status_t _RemoveVolumeMenuItem(dev_t device);
VolumeMenuItem* _FindVolumeMenuItem(dev_t device);
private:
void _Update(); void _Update();
status_t _GetSwapFileLimits(off_t& minSize, off_t& maxSize);
void _SetSwapDefaults();
BCheckBox* fSwapEnabledCheckBox; BCheckBox* fSwapEnabledCheckBox;
BSlider* fSizeSlider; BSlider* fSizeSlider;
@@ -36,8 +72,6 @@ class SettingsWindow : public BWindow {
BStringView* fWarningStringView; BStringView* fWarningStringView;
BMenuField* fVolumeMenuField; BMenuField* fVolumeMenuField;
Settings fSettings; Settings fSettings;
bool fLocked;
}; };
#endif /* SETTINGS_WINDOW_H */ #endif /* SETTINGS_WINDOW_H */
@@ -8,6 +8,7 @@
#include "SettingsWindow.h" #include "SettingsWindow.h"
#include <Alert.h> #include <Alert.h>
#include <Catalog.h>
#include <TextView.h> #include <TextView.h>
+1 -10
View File
@@ -7,24 +7,15 @@
#include <Application.h> #include <Application.h>
#include <Catalog.h>
#include <Locale.h>
class VMSettings;
class VirtualMemory : public BApplication { class VirtualMemory : public BApplication {
public: public:
VirtualMemory(); VirtualMemory();
virtual ~VirtualMemory(); virtual ~VirtualMemory();
virtual void ReadyToRun(); virtual void ReadyToRun();
virtual void AboutRequested(); virtual void AboutRequested();
private:
void GetCurrentSettings(bool& enabled, off_t& size);
VMSettings *fSettings;
}; };
#endif /* VIRTUAL_MEMORY_H */ #endif /* VIRTUAL_MEMORY_H */