Skip to content

Preferences & Defaults

User preferences are stored in a struct called UserDef defined in DNA_userdef_types.h. We normally have access to the currently-loaded preferences as a global variable U.

Most user-facing preferences are just simple values in here, but you will also find the lists of themes, fonts, styles, keymaps, etc. You will also find members for per-space data, the experimental features flags, and a runtime->is_dirty keeping track if the preferences need saving.

Drawing Metrics

One type of data currently stored in the UserDef struct are drawing metrics. These probably should not be there as they are runtime values that can change constantly and are not directly user preferences.

There are two actual preferences, shown to users as "Resolution Scale" (ui_scale) and "Line Width" (ui_line_width), but these are not used directly for drawing the interface. Instead we use these values together, along with information about the monitor scale and DPI, to calculate other values:

  • U.dpi - Dots per inch of the currently-drawn monitor based on actual DPI and OS scale factors.
  • U.pixelsize - Best considered as "minimum feature size". The minimum size we should use when drawing dots or lines in the interface.
  • U.scale_factor - The actual scaling factor to use when drawing interface items. Best exposed as UI_SCALE_FAC
  • U.inv_scale_factor - the inverse of the above, usually used to make dealing with block "aspect" (also inversed) easier, better exposed as UI_INV_SCALE_FAC.
  • U.widget_unit - The size of a single square button in the interface, generally used as a factor when calculating some larger sizes like popup blocks, etc. Although used in many places as a convenient approximate stand-in for 20 x UI_SCALE_FAC this can lead to subtle scaling problems. This is because this value uses a combination of U.scale_factor and U.pixelsize (because button borders get thicker with "Wide Lines"). In almost all cases you want to calculate sizes based on U.scale_factor not on U.widget_unit.

These values are calculated in WM_window_set_dpi and this is done when changing the scale or fonts, and also between windows. These drawing metrics values are calculated between the drawing of each window because they might be on different monitors that differ in DPI or OS scale.

Adding New Preferences

If you add any new members to UserDef you must take care to maintain the 64-bit alignment by adding/changing padding as needed. Note that a failure to maintain alignment in this struct will probably result in a large flood of seemingly-unrelated errors in your development console. So if you ever make a small change and see a mountain of errors, just assume you have an alignment problem.

The default value of your new value should be set in userdef_default.c, even if zero. But note that failure to do so will just result in a default of zero without any real problems or errors, so you can usually ignore this until the end of your development process.

Versioning a New Preference

Adding a new member to UserDef will usually require you to add some versioning code, but not always. Blender is designed with forward compatibility in mind so that older versions will ignore unknown fields without failing. But what you need to deal with is newer versions of Blender loading an older version of the preferences. In this case Blender will just assume a value of zero. So if your default is zero you will find everything will work perfectly.

But if you want your value to have a non-zero value for a preference that has never been set you need to edit versioning_userdef.cc. Look for a comment like "Versioning code until next subversion bump goes here" and examine the code around there. For preferences that cannot ever be set by the user to zero, you can get away with some code like:

if (userdef->my_new_field == 0) {
  userdef->my_new_field = 200;
}

But if your new field can be properly set by the user to zero then you'll want to test against the blender version so that you don't override the user's setting. You would increase the BLENDER_FILE_SUBVERSION value, found in BKE_blender_version.h and then use it as the second argument in USER_VERSION_ATLEAST (shown below for Blender Version 4.4, subversion 9):

if (!USER_VERSION_ATLEAST(404, 9)) {
  userdef->my_new_field = 200;
}

Changing a Preference Default

Changing the default for a user preference is similar to above. If you just want to change the default value without changing any users' existing settings then simply set the new value in userdef_default.c.

But if you want to alter the user's setting to this new value then you'll also want to add code to versioning_userdef.cc. In the following we change only older prefs to use the new value only if it is set to the old default value:

if (!USER_VERSION_ATLEAST(404, 9)) {
  /* Increase the number of recently-used files if using the old default value. */
  if (userdef->recent_files == 20) {
    userdef->recent_files = 30;
  }
}