This adds the ability to switch between different application-configurations without interfering with Blender's normal operation. This commit doesn't include any templates, so its mostly to allow collaboration for the Blender 101 project and other custom configurations. Application templates can be installed & selected from the file menu. Other details: - The `bl_app_template_utils` module handles template activation (similar to `addon_utils`). - The `bl_app_override` module is a general module to assist scripts overriding parts of Blender in reversible way. See docs: https://docs.blender.org/manual/en/dev/advanced/app_templates.html See patch: D2565
352 lines
7.6 KiB
C
352 lines
7.6 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/blenkernel/intern/blender.c
|
|
* \ingroup bke
|
|
*
|
|
* Application level startup/shutdown functionality.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_string.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_callbacks.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
#include "IMB_moviecache.h"
|
|
|
|
#include "BKE_blender.h" /* own include */
|
|
#include "BKE_blender_version.h" /* own include */
|
|
#include "BKE_blendfile.h"
|
|
#include "BKE_brush.h"
|
|
#include "BKE_cachefile.h"
|
|
#include "BKE_context.h"
|
|
#include "BKE_depsgraph.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_idprop.h"
|
|
#include "BKE_image.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_report.h"
|
|
#include "BKE_scene.h"
|
|
#include "BKE_screen.h"
|
|
#include "BKE_sequencer.h"
|
|
|
|
#include "RE_pipeline.h"
|
|
#include "RE_render_ext.h"
|
|
|
|
#include "BLF_api.h"
|
|
|
|
|
|
Global G;
|
|
UserDef U;
|
|
|
|
char versionstr[48] = "";
|
|
|
|
/* ********** free ********** */
|
|
|
|
/* only to be called on exit blender */
|
|
void BKE_blender_free(void)
|
|
{
|
|
/* samples are in a global list..., also sets G.main->sound->sample NULL */
|
|
BKE_main_free(G.main);
|
|
G.main = NULL;
|
|
|
|
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
|
|
|
|
IMB_exit();
|
|
BKE_cachefiles_exit();
|
|
BKE_images_exit();
|
|
DAG_exit();
|
|
|
|
BKE_brush_system_exit();
|
|
RE_texture_rng_exit();
|
|
|
|
BLI_callback_global_finalize();
|
|
|
|
BKE_sequencer_cache_destruct();
|
|
IMB_moviecache_destruct();
|
|
|
|
free_nodesystem();
|
|
}
|
|
|
|
void BKE_blender_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion)
|
|
{
|
|
const char *prefix = v_prefix ? "v" : "";
|
|
|
|
if (include_subversion && subversion > 0) {
|
|
BLI_snprintf(version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
|
|
}
|
|
else {
|
|
BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
|
|
}
|
|
}
|
|
|
|
void BKE_blender_globals_init(void)
|
|
{
|
|
memset(&G, 0, sizeof(Global));
|
|
|
|
U.savetime = 1;
|
|
|
|
G.main = BKE_main_new();
|
|
|
|
strcpy(G.ima, "//");
|
|
|
|
BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
|
|
|
|
#ifndef WITH_PYTHON_SECURITY /* default */
|
|
G.f |= G_SCRIPT_AUTOEXEC;
|
|
#else
|
|
G.f &= ~G_SCRIPT_AUTOEXEC;
|
|
#endif
|
|
}
|
|
|
|
void BKE_blender_globals_clear(void)
|
|
{
|
|
BKE_main_free(G.main); /* free all lib data */
|
|
|
|
G.main = NULL;
|
|
}
|
|
|
|
/***/
|
|
|
|
static void keymap_item_free(wmKeyMapItem *kmi)
|
|
{
|
|
if (kmi->properties) {
|
|
IDP_FreeProperty(kmi->properties);
|
|
MEM_freeN(kmi->properties);
|
|
}
|
|
if (kmi->ptr)
|
|
MEM_freeN(kmi->ptr);
|
|
}
|
|
|
|
void BKE_blender_userdef_set_data(UserDef *userdef)
|
|
{
|
|
/* only here free userdef themes... */
|
|
BKE_blender_userdef_free_data(&U);
|
|
U = *userdef;
|
|
}
|
|
|
|
static void userdef_free_keymaps(UserDef *userdef)
|
|
{
|
|
for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
|
|
km_next = km->next;
|
|
for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
|
|
if (kmdi->add_item) {
|
|
keymap_item_free(kmdi->add_item);
|
|
MEM_freeN(kmdi->add_item);
|
|
}
|
|
if (kmdi->remove_item) {
|
|
keymap_item_free(kmdi->remove_item);
|
|
MEM_freeN(kmdi->remove_item);
|
|
}
|
|
}
|
|
|
|
for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
|
|
keymap_item_free(kmi);
|
|
}
|
|
|
|
BLI_freelistN(&km->diff_items);
|
|
BLI_freelistN(&km->items);
|
|
|
|
MEM_freeN(km);
|
|
}
|
|
BLI_listbase_clear(&userdef->user_keymaps);
|
|
}
|
|
|
|
static void userdef_free_addons(UserDef *userdef)
|
|
{
|
|
for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
|
|
addon_next = addon->next;
|
|
if (addon->prop) {
|
|
IDP_FreeProperty(addon->prop);
|
|
MEM_freeN(addon->prop);
|
|
}
|
|
MEM_freeN(addon);
|
|
}
|
|
BLI_listbase_clear(&userdef->addons);
|
|
}
|
|
|
|
/**
|
|
* When loading a new userdef from file,
|
|
* or when exiting Blender.
|
|
*/
|
|
void BKE_blender_userdef_free_data(UserDef *userdef)
|
|
{
|
|
#define U _invalid_access_ /* ensure no accidental global access */
|
|
#ifdef U /* quiet warning */
|
|
#endif
|
|
|
|
userdef_free_keymaps(userdef);
|
|
userdef_free_addons(userdef);
|
|
|
|
for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
|
|
BLF_unload_id(font->blf_id);
|
|
}
|
|
|
|
BLF_default_set(-1);
|
|
|
|
BLI_freelistN(&userdef->autoexec_paths);
|
|
|
|
BLI_freelistN(&userdef->uistyles);
|
|
BLI_freelistN(&userdef->uifonts);
|
|
BLI_freelistN(&userdef->themes);
|
|
|
|
#undef U
|
|
}
|
|
|
|
/**
|
|
* Handle changes in settings that need refreshing.
|
|
*/
|
|
void BKE_blender_userdef_refresh(void)
|
|
{
|
|
/* prevent accidents */
|
|
if (U.pixelsize == 0) U.pixelsize = 1;
|
|
|
|
BLF_default_dpi(U.pixelsize * U.dpi);
|
|
U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
|
|
|
|
}
|
|
|
|
/**
|
|
* Write U from userdef.
|
|
* This function defines which settings a template will override for the user preferences.
|
|
*/
|
|
void BKE_blender_userdef_set_app_template(UserDef *userdef)
|
|
{
|
|
/* TODO:
|
|
* - keymaps
|
|
* - various minor settings (add as needed).
|
|
*/
|
|
|
|
#define LIST_OVERRIDE(id) { \
|
|
BLI_freelistN(&U.id); \
|
|
BLI_movelisttolist(&U.id, &userdef->id); \
|
|
} ((void)0)
|
|
|
|
#define MEMCPY_OVERRIDE(id) \
|
|
memcpy(U.id, userdef->id, sizeof(U.id));
|
|
|
|
/* for some types we need custom free functions */
|
|
userdef_free_addons(&U);
|
|
userdef_free_keymaps(&U);
|
|
|
|
LIST_OVERRIDE(uistyles);
|
|
LIST_OVERRIDE(uifonts);
|
|
LIST_OVERRIDE(themes);
|
|
LIST_OVERRIDE(addons);
|
|
LIST_OVERRIDE(user_keymaps);
|
|
|
|
MEMCPY_OVERRIDE(light);
|
|
|
|
MEMCPY_OVERRIDE(font_path_ui);
|
|
MEMCPY_OVERRIDE(font_path_ui_mono);
|
|
|
|
#undef LIST_OVERRIDE
|
|
#undef MEMCPY_OVERRIDE
|
|
}
|
|
|
|
/* ***************** testing for break ************* */
|
|
|
|
static void (*blender_test_break_cb)(void) = NULL;
|
|
|
|
void BKE_blender_callback_test_break_set(void (*func)(void))
|
|
{
|
|
blender_test_break_cb = func;
|
|
}
|
|
|
|
|
|
int BKE_blender_test_break(void)
|
|
{
|
|
if (!G.background) {
|
|
if (blender_test_break_cb)
|
|
blender_test_break_cb();
|
|
}
|
|
|
|
return (G.is_break == true);
|
|
}
|
|
|
|
|
|
/** \name Blender's AtExit
|
|
*
|
|
* \note Don't use MEM_mallocN so functions can be registered at any time.
|
|
* \{ */
|
|
|
|
static struct AtExitData {
|
|
struct AtExitData *next;
|
|
|
|
void (*func)(void *user_data);
|
|
void *user_data;
|
|
} *g_atexit = NULL;
|
|
|
|
void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
|
|
{
|
|
struct AtExitData *ae = malloc(sizeof(*ae));
|
|
ae->next = g_atexit;
|
|
ae->func = func;
|
|
ae->user_data = user_data;
|
|
g_atexit = ae;
|
|
}
|
|
|
|
void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
|
|
{
|
|
struct AtExitData *ae = g_atexit;
|
|
struct AtExitData **ae_p = &g_atexit;
|
|
|
|
while (ae) {
|
|
if ((ae->func == func) && (ae->user_data == user_data)) {
|
|
*ae_p = ae->next;
|
|
free(ae);
|
|
return;
|
|
}
|
|
ae_p = &ae;
|
|
ae = ae->next;
|
|
}
|
|
}
|
|
|
|
void BKE_blender_atexit(void)
|
|
{
|
|
struct AtExitData *ae = g_atexit, *ae_next;
|
|
while (ae) {
|
|
ae_next = ae->next;
|
|
|
|
ae->func(ae->user_data);
|
|
|
|
free(ae);
|
|
ae = ae_next;
|
|
}
|
|
g_atexit = NULL;
|
|
}
|
|
|
|
/** \} */
|