Ticket #1746: virtualmemory-changes.diff

File virtualmemory-changes.diff, 18.2 KB (added by hamish, 13 years ago)

UI support for changing the swap-file volume

  • src/preferences/virtualmemory/Settings.cpp

     
    11/*
    2  * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
    3  * Distributed under the terms of the MIT License.
     2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de
     3 * Copyright 2010-2011, Hamish Morrison, hamish@lavabit.com
     4 * All rights reserved. Distributed under the terms of the MIT License.
    45 */
    56
    67
     
    2122
    2223static const char* kWindowSettingsFile = "VM_data";
    2324static const char* kVirtualMemorySettings = "virtual_memory";
     25static const int64 kMegaByte = 1048576;
    2426
    2527
    2628Settings::Settings()
    2729    :
    28     fPositionUpdated(false),
    29     fSwapUpdated(false)
     30    fPositionUpdated(false)
    3031{
    3132    ReadWindowSettings();
    3233    ReadSwapSettings();
     
    5051        path.Append(kWindowSettingsFile);
    5152        BFile file;
    5253        if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK)
    53             // Now read in the data
    5454            if (file.Read(&fWindowPosition, sizeof(BPoint)) == sizeof(BPoint))
    5555                success = true;
    5656    }
     
    9292void
    9393Settings::ReadSwapSettings()
    9494{
    95     // read current swap settings from disk
    96     void* settings = load_driver_settings("virtual_memory");
     95    void* settings = load_driver_settings(kVirtualMemorySettings);
    9796    if (settings != NULL) {
    98         fSwapEnabled = get_driver_boolean_parameter(settings, "vm", false, false);
    99 
    100         const char* string = get_driver_parameter(settings, "swap_size", NULL, NULL);
    101         fSwapSize = string ? atoll(string) : 0;
    102 
    103         if (fSwapSize <= 0) {
    104             fSwapEnabled = false;
    105             fSwapSize = 0;
    106         }
     97        SetSwapEnabled(get_driver_boolean_parameter(settings, "vm", false, false));
     98        const char* swapSize = get_driver_parameter(settings, "swap_size", NULL, NULL);
     99        SetSwapSize(swapSize ? atoll(swapSize) : 0);
     100       
     101#ifdef SWAP_VOLUME_IMPLEMENTED
     102        // we need to hang onto this one
     103        fBadVolName = strdup(get_driver_parameter(settings, "swap_volume", NULL, NULL));
     104       
     105        BVolumeRoster volumeRoster;
     106        BVolume temporaryVolume;
     107       
     108        if (fBadVolName != NULL) {
     109            status_t result = volumeRoster.GetNextVolume(&temporaryVolume);
     110            char volumeName[B_FILE_NAME_LENGTH];
     111            while (result != B_BAD_VALUE) {
     112                temporaryVolume.GetName(volumeName);
     113                if (strcmp(volumeName, fBadVolName) == 0
     114                    && temporaryVolume.IsPersistent() && volumeName[0]) {
     115                    SetSwapVolume(temporaryVolume);
     116                    break;
     117                }
     118                result = volumeRoster.GetNextVolume(&temporaryVolume);
     119            }
     120        }   
     121#endif
    107122        unload_driver_settings(settings);
    108     } else {
    109         // settings are not available, try to find out what the kernel is up to
    110         // ToDo: introduce a kernel call for this!
    111         fSwapSize = 0;
     123    } else
     124        SetSwapNull();
    112125
    113         BPath path;
    114         if (find_directory(B_COMMON_VAR_DIRECTORY, &path) == B_OK) {
    115             path.Append("swap");
    116             BEntry swap(path.Path());
    117             if (swap.GetSize(&fSwapSize) != B_OK)
    118                 fSwapSize = 0;
    119         }
    120 
    121         fSwapEnabled = fSwapSize != 0;
    122     }
    123 
    124     // ToDo: read those as well
     126#ifndef SWAP_VOLUME_IMPLEMENTED
    125127    BVolumeRoster volumeRoster;
    126128    volumeRoster.GetBootVolume(&fSwapVolume);
     129#endif
    127130
    128131    fInitialSwapEnabled = fSwapEnabled;
    129132    fInitialSwapSize = fSwapSize;
     
    133136
    134137void
    135138Settings::WriteSwapSettings()
    136 {
    137     if (!SwapChanged())
     139{   
     140    if (!IsRevertible())
    138141        return;
    139142
    140143    BPath path;
     
    145148    path.Append(kVirtualMemorySettings);
    146149
    147150    BFile file;
    148     if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) != B_OK)
     151    if (file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE)
     152        != B_OK)
    149153        return;
    150 
     154   
    151155    char buffer[256];
     156#ifdef SWAP_VOLUME_IMPLEMENTED
     157    char volumeName[B_FILE_NAME_LENGTH] = {0};
     158    if (SwapVolume().InitCheck() != B_NO_INIT)
     159        SwapVolume().GetName(volumeName);
     160    else if (fBadVolName)
     161        strcpy(volumeName, fBadVolName);
     162    snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %Ld\nswap_volume %s\n",
     163        SwapEnabled() ? "on" : "off", SwapSize(),
     164        volumeName[0] ? volumeName : NULL);
     165#else
    152166    snprintf(buffer, sizeof(buffer), "vm %s\nswap_size %Ld\n",
    153167        fSwapEnabled ? "on" : "off", fSwapSize);
     168#endif
    154169
    155170    file.Write(buffer, strlen(buffer));
    156171}
     
    173188void
    174189Settings::SetSwapVolume(BVolume &volume)
    175190{
    176     if (volume.Device() == fSwapVolume.Device()
     191    if (volume.Device() == SwapVolume().Device()
    177192        || volume.InitCheck() != B_OK)
    178193        return;
    179194
     
    182197
    183198
    184199void
    185 Settings::SetSwapDefaults()
     200Settings::SetSwapNull()
    186201{
    187     fSwapEnabled = true;
    188 
     202    SetSwapEnabled(false);
    189203    BVolumeRoster volumeRoster;
    190     volumeRoster.GetBootVolume(&fSwapVolume);
    191 
    192     system_info info;
    193     get_system_info(&info);
    194     fSwapSize = (off_t)info.max_pages * B_PAGE_SIZE;
     204    BVolume temporaryVolume;
     205    volumeRoster.GetBootVolume(&temporaryVolume);
     206    SetSwapVolume(temporaryVolume);
     207    SetSwapSize(0);
    195208}
    196209
    197210
     
    205218
    206219
    207220bool
    208 Settings::IsDefaultable()
     221Settings::IsRevertible()
    209222{
    210223    return fSwapEnabled != fInitialSwapEnabled
    211         || fSwapSize != fInitialSwapSize;
    212 }
    213 
    214 
    215 bool
    216 Settings::SwapChanged()
    217 {
    218     return fSwapEnabled != fInitialSwapEnabled
    219224        || fSwapSize != fInitialSwapSize
    220225        || fSwapVolume.Device() != fInitialSwapVolume;
    221226}
    222 
  • src/preferences/virtualmemory/Settings.h

     
    2525        void SetSwapSize(off_t size);
    2626        void SetSwapVolume(BVolume& volume);
    2727
    28         void SetSwapDefaults();
    2928        void RevertSwapChanges();
    30         bool IsDefaultable();
    31         bool SwapChanged();
     29        bool IsRevertible();
    3230
    3331    private:
     32        void SetSwapNull();
    3433        void ReadWindowSettings();
    3534        void WriteWindowSettings();
    3635
     
    4746        off_t       fInitialSwapSize;
    4847        dev_t       fInitialSwapVolume;
    4948
    50         bool        fPositionUpdated, fSwapUpdated;
     49        bool        fPositionUpdated;
     50        const char* fBadVolName;
    5151};
    5252
    5353#endif  /* SETTINGS_H */
  • src/preferences/virtualmemory/SettingsWindow.cpp

     
    11/*
    2  * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
    3  * Distributed under the terms of the MIT License.
     2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de
     3 * Copyright 2010-2011, Hamish Morrison, hamish@lavabit.com
     4 * All rights reserved. Distributed under the terms of the MIT License.
    45 */
    56
    67
     
    3940static const uint32 kMsgRevert = 'rvrt';
    4041static const uint32 kMsgSliderUpdate = 'slup';
    4142static const uint32 kMsgSwapEnabledUpdate = 'swen';
     43static const uint32 kMsgVolumeSelected = 'vlsl';
     44static const int64 kMegaByte = 1048576;
    4245
    4346
    4447class SizeSlider : public BSlider {
     
    5457};
    5558
    5659
    57 static const int64 kMegaByte = 1048576;
     60SizeSlider::SizeSlider(const char* name, const char* label,
     61    BMessage* message, int32 min, int32 max, uint32 flags)
     62    : BSlider(name, label, message, min, max, B_HORIZONTAL, B_BLOCK_THUMB, flags)
     63{
     64    rgb_color color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
     65    UseFillColor(true, &color);
     66}
    5867
    5968
    60 const char *
     69SizeSlider::~SizeSlider()
     70{
     71}
     72
     73
     74const char*
    6175byte_string(int64 size)
    6276{
    6377    double value = 1. * size;
     
    8094        } while (value >= 1024 && units[i + 1]);
    8195
    8296        off_t rounded = off_t(value * 100LL);
    83         sprintf(string, "%g %s", rounded / 100.0,
     97        snprintf(string, sizeof(string), "%g %s", rounded / 100.0,
    8498            B_TRANSLATE_NOCOLLECT(units[i]));
    8599    }
    86100
     
    88102}
    89103
    90104
    91 //  #pragma mark -
    92 
    93 
    94 SizeSlider::SizeSlider(const char* name, const char* label,
    95     BMessage* message, int32 min, int32 max, uint32 flags)
    96     : BSlider(name, label, message, min, max, B_HORIZONTAL, B_BLOCK_THUMB, flags)
     105const char*
     106SizeSlider::UpdateText() const
    97107{
    98     rgb_color color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
    99     UseFillColor(true, &color);
     108    fText = byte_string(Value() * kMegaByte);
     109    return fText.String();
    100110}
    101111
    102112
    103 SizeSlider::~SizeSlider()
     113class VolumeMenuItem : public BMenuItem {
     114    public:
     115        VolumeMenuItem(const char* label, BMessage* message, BVolume* volume);
     116        virtual ~VolumeMenuItem();
     117        BVolume* fVolume;
     118};
     119
     120
     121VolumeMenuItem::VolumeMenuItem(const char* label, BMessage* message,
     122    BVolume* volume)
     123    : BMenuItem(label, message)
    104124{
     125    fVolume = volume;
    105126}
    106127
    107128
    108 const char *
    109 SizeSlider::UpdateText() const
     129VolumeMenuItem::~VolumeMenuItem()
    110130{
    111     fText = byte_string(Value() * kMegaByte);
    112 
    113     return fText.String();
    114131}
    115132
    116133
    117 //  #pragma mark -
    118 
    119 
    120134SettingsWindow::SettingsWindow()
    121     : BWindow(BRect(0, 0, 269, 172), B_TRANSLATE("VirtualMemory"),
     135    :
     136    BWindow(BRect(0, 0, 269, 172), B_TRANSLATE("VirtualMemory"),
    122137        B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS
    123             | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS)
     138        | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
     139    fLocked(false)
     140   
    124141{
    125142    BView* view = new BGroupView();
    126143
     
    142159    string << byte_string(fSettings.SwapSize());
    143160    BStringView* swapfileView = new BStringView("current swap size", string.String());
    144161
    145     BPopUpMenu* menu = new BPopUpMenu("volumes");
     162    BPopUpMenu* menu = new BPopUpMenu("invalid");
    146163
    147164    // collect volumes
    148165    // TODO: listen to volume changes!
    149166    // TODO: accept dropped volumes
    150167
    151168    BVolumeRoster volumeRoster;
    152     BVolume volume;
    153     while (volumeRoster.GetNextVolume(&volume) == B_OK) {
    154         char name[B_FILE_NAME_LENGTH];
    155         if (!volume.IsPersistent() || volume.GetName(name) != B_OK || !name[0])
     169    BVolume* volume = new BVolume();
     170    char name[B_FILE_NAME_LENGTH];
     171    while (volumeRoster.GetNextVolume(volume) == B_OK) {   
     172        if (!volume->IsPersistent() || volume->GetName(name) != B_OK || !name[0])
    156173            continue;
    157 
    158         BMenuItem* item = new BMenuItem(name, NULL);
     174        VolumeMenuItem* item = new VolumeMenuItem(name,
     175            new BMessage(kMsgVolumeSelected), volume);
    159176        menu->AddItem(item);
    160 
    161         if (volume.Device() == fSettings.SwapVolume().Device())
    162             item->SetMarked(true);
     177        volume = new BVolume();
    163178    }
    164179
    165     fVolumeMenuField = new BMenuField("devices", B_TRANSLATE("Use volume:"), menu);
     180    fVolumeMenuField = new BMenuField("volumes", B_TRANSLATE("Use volume:"), menu);
    166181   
    167     // When swap volume changing support is implemeneted, remove me:
     182#ifndef SWAP_VOLUME_IMPLEMENTED
    168183    fVolumeMenuField->SetEnabled(false);
     184#endif
    169185   
    170186    fSizeSlider = new SizeSlider("size slider",
    171187        B_TRANSLATE("Requested swap file size:"), new BMessage(kMsgSliderUpdate),
    172         0, 0, B_WILL_DRAW | B_FRAME_EVENTS);
     188        1, 1, B_WILL_DRAW | B_FRAME_EVENTS);
    173189    fSizeSlider->SetViewColor(255, 0, 255);
    174190
    175191    fWarningStringView = new BStringView("", "");
     
    195211    );
    196212    box->AddChild(view);
    197213
    198     // Add "Defaults" and "Revert" buttons
    199 
    200214    fDefaultsButton = new BButton("defaults", B_TRANSLATE("Defaults"),
    201215        new BMessage(kMsgDefaults));
    202     fDefaultsButton->SetEnabled(fSettings.IsDefaultable());
    203216
    204217    fRevertButton = new BButton("revert", B_TRANSLATE("Revert"),
    205218        new BMessage(kMsgRevert));
     
    216229        .SetInsets(10, 10, 10, 10)
    217230    );
    218231
    219     _Update();
    220 
    221232    BScreen screen;
    222233    BRect screenFrame = screen.Frame();
    223 
    224234    if (!screenFrame.Contains(fSettings.WindowPosition()))
    225235        CenterOnScreen();
    226236    else
    227237        MoveTo(fSettings.WindowPosition());
     238
     239#ifdef SWAP_VOLUME_IMPLEMENTED
     240    // Validate the volume specified in settings file
     241    status_t result = fSettings.SwapVolume().InitCheck();
     242
     243    if (result == B_NO_INIT) {
     244        int32 choice = (new BAlert("VirtualMemory", B_TRANSLATE(
     245            "The device specified in the settings file is invalid.\n"
     246            "You can keep the current setting or switch to the "
     247            "default swap device."),
     248            B_TRANSLATE("Keep"), B_TRANSLATE("Switch"), NULL,
     249            B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
     250        if (choice == 1) {
     251            BVolumeRoster volumeRoster;
     252            BVolume bootVolume;
     253            volumeRoster.GetBootVolume(&bootVolume);
     254            fSettings.SetSwapVolume(bootVolume);
     255        }
     256    }
     257#endif
     258
     259    _Update();
    228260}
    229261
    230262
     
    238270{
    239271    if ((fSwapEnabledCheckBox->Value() != 0) != fSettings.SwapEnabled())
    240272        fSwapEnabledCheckBox->SetValue(fSettings.SwapEnabled());
    241        
    242     if (fSizeSlider->IsEnabled() != fSettings.SwapEnabled())
    243         fSizeSlider->SetEnabled(fSettings.SwapEnabled());
    244    
     273
    245274#ifdef SWAP_VOLUME_IMPLEMENTED 
    246275    if (fVolumeMenuField->IsEnabled() != fSettings.SwapEnabled())
    247276        fVolumeMenuField->SetEnabled(fSettings.SwapEnabled());
     277    VolumeMenuItem* selectedVolumeItem =
     278        (VolumeMenuItem*)fVolumeMenuField->Menu()->FindMarked();
     279    if (selectedVolumeItem == NULL) {
     280        VolumeMenuItem* currentVolumeItem;
     281        int32 items = fVolumeMenuField->Menu()->CountItems();
     282        for (int32 index = 0; index < items; ++index) {
     283            currentVolumeItem = ((VolumeMenuItem*)fVolumeMenuField->Menu()->ItemAt(index));
     284            if (*(currentVolumeItem->fVolume) == fSettings.SwapVolume()) {
     285                currentVolumeItem->SetMarked(true);
     286                break;
     287            }
     288        }
     289    } else if (*selectedVolumeItem->fVolume != fSettings.SwapVolume()) {
     290        VolumeMenuItem* currentVolumeItem;
     291        int32 items = fVolumeMenuField->Menu()->CountItems();
     292        for (int32 index = 0; index < items; ++index) {
     293            currentVolumeItem = ((VolumeMenuItem*)fVolumeMenuField->Menu()->ItemAt(index));
     294            if (*(currentVolumeItem->fVolume) == fSettings.SwapVolume()) {
     295                currentVolumeItem->SetMarked(true);
     296                break;
     297            }
     298        }
     299    }
    248300#endif
    249301
     302    fWarningStringView->SetText("");
     303    fLocked = false;
     304   
     305    if (fSettings.IsRevertible())
     306            fWarningStringView->SetText(
     307                B_TRANSLATE("Changes will take effect on restart!"));
     308    if (fRevertButton->IsEnabled() != fSettings.IsRevertible())
     309        fRevertButton->SetEnabled(fSettings.IsRevertible());
     310   
    250311    off_t minSize, maxSize;
    251312    if (_GetSwapFileLimits(minSize, maxSize) == B_OK) {
     313        // round to nearest MB -- slider steps in whole MBs
     314        (minSize >>= 20) <<= 20;
     315        (maxSize >>= 20) <<= 20;
    252316        BString minLabel, maxLabel;
    253317        minLabel << byte_string(minSize);
    254318        maxLabel << byte_string(maxSize);
    255319        if (minLabel != fSizeSlider->MinLimitLabel()
    256320            || maxLabel != fSizeSlider->MaxLimitLabel()) {
    257321            fSizeSlider->SetLimitLabels(minLabel.String(), maxLabel.String());
    258 #ifdef __HAIKU__
    259322            fSizeSlider->SetLimits(minSize / kMegaByte, maxSize / kMegaByte);
    260 #endif
    261323        }
    262 
    263         if (fSizeSlider->Value() != fSettings.SwapSize() / kMegaByte)
    264             fSizeSlider->SetValue(fSettings.SwapSize() / kMegaByte);
    265     } else {
    266         // Not enough space on volume for a swap file. Make UI inoperable.
     324    } else if (fSettings.SwapEnabled()) {
    267325        fWarningStringView->SetText(
    268326            B_TRANSLATE("Insufficient space for a swap file."));
    269         fSwapEnabledCheckBox->SetEnabled(false);
    270         fSizeSlider->SetEnabled(false);
    271         // When swap volume is implemented, we'll want to keep the volume
    272         // menu field enabled so the user can get around the space issue
    273         // by selecting a different volume.
    274 #ifdef SWAP_VOLUME_IMPLEMENTED
    275         fVolumeMenuField->SetEnabled(true);
    276 #endif
     327        fLocked = true;
    277328    }
    278 
    279     // ToDo: set volume
    280 
    281     fDefaultsButton->SetEnabled(fSettings.IsDefaultable());
    282 
    283     bool changed = fSettings.SwapChanged();
    284     if (fRevertButton->IsEnabled() != changed) {
    285         fRevertButton->SetEnabled(changed);
    286         if (changed)
    287             fWarningStringView->SetText(
    288                 B_TRANSLATE("Changes will take effect on restart!"));
    289         else
    290             fWarningStringView->SetText("");
     329    if (fSizeSlider->Value() != fSettings.SwapSize() / kMegaByte)
     330        fSizeSlider->SetValue(fSettings.SwapSize() / kMegaByte);
     331    if (fSizeSlider->IsEnabled() != fSettings.SwapEnabled() || fLocked)
     332    {
     333        fSizeSlider->SetEnabled(fSettings.SwapEnabled() && !fLocked);
     334        fSettings.SetSwapSize((off_t)fSizeSlider->Value() * kMegaByte);
    291335    }
    292336}
    293337
     
    308352    // adjust the free space accordingly
    309353    BPath path;
    310354    if (find_directory(B_COMMON_VAR_DIRECTORY, &path, false,
    311             &fSettings.SwapVolume()) == B_OK) {
     355        &fSettings.SwapVolume()) == B_OK) {
    312356        path.Append("swap");
    313357        BEntry swap(path.Path());
    314358
     
    333377
    334378
    335379void
     380SettingsWindow::SetSwapDefaults()
     381{
     382    fSettings.SetSwapEnabled(true);
     383
     384    BVolumeRoster volumeRoster;
     385    BVolume temporaryVolume;
     386    volumeRoster.GetBootVolume(&temporaryVolume);
     387    fSettings.SetSwapVolume(temporaryVolume);
     388
     389    system_info info;
     390    get_system_info(&info);
     391   
     392    off_t defaultSize = (off_t)info.max_pages * B_PAGE_SIZE;
     393    off_t minSize, maxSize;
     394    _GetSwapFileLimits(minSize, maxSize);
     395   
     396    if (defaultSize > maxSize / 2)
     397        defaultSize = maxSize / 2;
     398       
     399    fSettings.SetSwapSize(defaultSize);
     400}
     401
     402
     403void
    336404SettingsWindow::MessageReceived(BMessage* message)
    337405{
    338406    switch (message->what) {
     
    341409            _Update();
    342410            break;
    343411        case kMsgDefaults:
    344             fSettings.SetSwapDefaults();
     412            SetSwapDefaults();
    345413            _Update();
    346414            break;
    347415        case kMsgSliderUpdate:
    348416            fSettings.SetSwapSize((off_t)fSizeSlider->Value() * kMegaByte);
    349417            _Update();
    350418            break;
     419        case kMsgVolumeSelected:
     420            fSettings.SetSwapVolume(*((VolumeMenuItem*)fVolumeMenuField->Menu()
     421                ->FindMarked())->fVolume);
     422            _Update();
     423            break;
    351424        case kMsgSwapEnabledUpdate:
    352425        {
    353426            int32 value;
     
    374447                }
    375448            }
    376449
    377             bool enabled = value != 0;
    378             fSettings.SetSwapEnabled(enabled);
    379             if (enabled && fSettings.SwapSize() == 0) {
    380                 off_t min;
    381                 off_t max;
    382                 _GetSwapFileLimits(min, max);
    383                 fSettings.SetSwapSize(min);
    384             }
     450            fSettings.SetSwapEnabled(value != 0);
    385451            _Update();
    386452            break;
    387453        }
  • src/preferences/virtualmemory/SettingsWindow.h

     
    2727    private:
    2828        void _Update();
    2929        status_t _GetSwapFileLimits(off_t& minSize, off_t& maxSize);
     30        void SetSwapDefaults();
    3031
    3132        BCheckBox*      fSwapEnabledCheckBox;
    3233        BSlider*        fSizeSlider;
     
    3536        BStringView*    fWarningStringView;
    3637        BMenuField*     fVolumeMenuField;
    3738        Settings        fSettings;
     39       
     40        bool fLocked;
    3841};
    3942
    4043#endif  /* SETTINGS_WINDOW_H */