These variables track the wmWindow.event_queue state, however they were used in a way that wasn't correct. - check_drag & check_click from wmWindow.eventstate were used to track the click/drag status of events handled in wmWindow.event_queue. - Event's in the queue read from wmEvent.check_drag. - Once a drag action was detected, wmWindow.eventstate.check_drag was disabled. Disabling drag in the event state would not change the drag state for values already in the event queue. Simplify logic by moving these values into the window, so there is one place these variables are tracked.
		
			
				
	
	
		
			652 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			652 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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) 2007 Blender Foundation.
 | 
						|
 * All rights reserved.
 | 
						|
 */
 | 
						|
 | 
						|
/** \file
 | 
						|
 * \ingroup wm
 | 
						|
 *
 | 
						|
 * Internal functions for managing UI registrable types (operator, UI and menu types).
 | 
						|
 *
 | 
						|
 * Also Blender's main event loop (WM_main).
 | 
						|
 */
 | 
						|
 | 
						|
/* Allow using deprecated functionality for .blend file I/O. */
 | 
						|
#define DNA_DEPRECATED_ALLOW
 | 
						|
 | 
						|
#include <stddef.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "BLI_sys_types.h"
 | 
						|
 | 
						|
#include "DNA_windowmanager_types.h"
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "BLI_blenlib.h"
 | 
						|
#include "BLI_utildefines.h"
 | 
						|
 | 
						|
#include "BLT_translation.h"
 | 
						|
 | 
						|
#include "BKE_context.h"
 | 
						|
#include "BKE_global.h"
 | 
						|
#include "BKE_idprop.h"
 | 
						|
#include "BKE_idtype.h"
 | 
						|
#include "BKE_lib_id.h"
 | 
						|
#include "BKE_lib_query.h"
 | 
						|
#include "BKE_main.h"
 | 
						|
#include "BKE_report.h"
 | 
						|
#include "BKE_screen.h"
 | 
						|
#include "BKE_workspace.h"
 | 
						|
 | 
						|
#include "WM_api.h"
 | 
						|
#include "WM_message.h"
 | 
						|
#include "WM_types.h"
 | 
						|
#include "wm.h"
 | 
						|
#include "wm_draw.h"
 | 
						|
#include "wm_event_system.h"
 | 
						|
#include "wm_window.h"
 | 
						|
#ifdef WITH_XR_OPENXR
 | 
						|
#  include "wm_xr.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "BKE_undo_system.h"
 | 
						|
#include "ED_screen.h"
 | 
						|
 | 
						|
#ifdef WITH_PYTHON
 | 
						|
#  include "BPY_extern.h"
 | 
						|
#  include "BPY_extern_run.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "BLO_read_write.h"
 | 
						|
 | 
						|
/* ****************************************************** */
 | 
						|
 | 
						|
static void window_manager_free_data(ID *id)
 | 
						|
{
 | 
						|
  wm_close_and_free(NULL, (wmWindowManager *)id);
 | 
						|
}
 | 
						|
 | 
						|
static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = (wmWindowManager *)id;
 | 
						|
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE);
 | 
						|
 | 
						|
    /* This pointer can be NULL during old files reading, better be safe than sorry. */
 | 
						|
    if (win->workspace_hook != NULL) {
 | 
						|
      ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
 | 
						|
      BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP);
 | 
						|
      /* Allow callback to set a different workspace. */
 | 
						|
      BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
 | 
						|
    }
 | 
						|
    if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
 | 
						|
      LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
 | 
						|
        BKE_screen_foreach_id_screen_area(data, area);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
 | 
						|
{
 | 
						|
  BKE_screen_view3d_shading_blend_write(writer, &xr_data->session_settings.shading);
 | 
						|
}
 | 
						|
 | 
						|
static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = (wmWindowManager *)id;
 | 
						|
 | 
						|
  BLO_write_id_struct(writer, wmWindowManager, id_address, &wm->id);
 | 
						|
  BKE_id_blend_write(writer, &wm->id);
 | 
						|
  write_wm_xr_data(writer, &wm->xr);
 | 
						|
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
 | 
						|
    win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
 | 
						|
 | 
						|
    BLO_write_struct(writer, wmWindow, win);
 | 
						|
    BLO_write_struct(writer, WorkSpaceInstanceHook, win->workspace_hook);
 | 
						|
    BLO_write_struct(writer, Stereo3dFormat, win->stereo3d_format);
 | 
						|
 | 
						|
    BKE_screen_area_map_blend_write(writer, &win->global_areas);
 | 
						|
 | 
						|
    /* data is written, clear deprecated data again */
 | 
						|
    win->screen = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void direct_link_wm_xr_data(BlendDataReader *reader, wmXrData *xr_data)
 | 
						|
{
 | 
						|
  BKE_screen_view3d_shading_blend_read_data(reader, &xr_data->session_settings.shading);
 | 
						|
}
 | 
						|
 | 
						|
static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = (wmWindowManager *)id;
 | 
						|
 | 
						|
  id_us_ensure_real(&wm->id);
 | 
						|
  BLO_read_list(reader, &wm->windows);
 | 
						|
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    BLO_read_data_address(reader, &win->parent);
 | 
						|
 | 
						|
    WorkSpaceInstanceHook *hook = win->workspace_hook;
 | 
						|
    BLO_read_data_address(reader, &win->workspace_hook);
 | 
						|
 | 
						|
    /* This will be NULL for any pre-2.80 blend file. */
 | 
						|
    if (win->workspace_hook != NULL) {
 | 
						|
      /* We need to restore a pointer to this later when reading workspaces,
 | 
						|
       * so store in global oldnew-map.
 | 
						|
       * Note that this is only needed for versioning of older .blend files now.. */
 | 
						|
      BLO_read_data_globmap_add(reader, hook, win->workspace_hook);
 | 
						|
      /* Cleanup pointers to data outside of this data-block scope. */
 | 
						|
      win->workspace_hook->act_layout = NULL;
 | 
						|
      win->workspace_hook->temp_workspace_store = NULL;
 | 
						|
      win->workspace_hook->temp_layout_store = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    BKE_screen_area_map_blend_read_data(reader, &win->global_areas);
 | 
						|
 | 
						|
    win->ghostwin = NULL;
 | 
						|
    win->gpuctx = NULL;
 | 
						|
    win->eventstate = NULL;
 | 
						|
    win->cursor_keymap_status = NULL;
 | 
						|
    win->tweak = NULL;
 | 
						|
#ifdef WIN32
 | 
						|
    win->ime_data = NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
    BLI_listbase_clear(&win->event_queue);
 | 
						|
    BLI_listbase_clear(&win->handlers);
 | 
						|
    BLI_listbase_clear(&win->modalhandlers);
 | 
						|
    BLI_listbase_clear(&win->gesture);
 | 
						|
 | 
						|
    win->active = 0;
 | 
						|
 | 
						|
    win->cursor = 0;
 | 
						|
    win->lastcursor = 0;
 | 
						|
    win->modalcursor = 0;
 | 
						|
    win->grabcursor = 0;
 | 
						|
    win->addmousemove = true;
 | 
						|
    win->event_queue_check_click = 0;
 | 
						|
    win->event_queue_check_drag = 0;
 | 
						|
    BLO_read_data_address(reader, &win->stereo3d_format);
 | 
						|
 | 
						|
    /* Multi-view always fallback to anaglyph at file opening
 | 
						|
     * otherwise quad-buffer saved files can break Blender. */
 | 
						|
    if (win->stereo3d_format) {
 | 
						|
      win->stereo3d_format->display_mode = S3D_DISPLAY_ANAGLYPH;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  direct_link_wm_xr_data(reader, &wm->xr);
 | 
						|
 | 
						|
  BLI_listbase_clear(&wm->timers);
 | 
						|
  BLI_listbase_clear(&wm->operators);
 | 
						|
  BLI_listbase_clear(&wm->paintcursors);
 | 
						|
  BLI_listbase_clear(&wm->notifier_queue);
 | 
						|
  BKE_reports_init(&wm->reports, RPT_STORE);
 | 
						|
 | 
						|
  BLI_listbase_clear(&wm->keyconfigs);
 | 
						|
  wm->defaultconf = NULL;
 | 
						|
  wm->addonconf = NULL;
 | 
						|
  wm->userconf = NULL;
 | 
						|
  wm->undo_stack = NULL;
 | 
						|
 | 
						|
  wm->message_bus = NULL;
 | 
						|
 | 
						|
  wm->xr.runtime = NULL;
 | 
						|
 | 
						|
  BLI_listbase_clear(&wm->jobs);
 | 
						|
  BLI_listbase_clear(&wm->drags);
 | 
						|
 | 
						|
  wm->windrawable = NULL;
 | 
						|
  wm->winactive = NULL;
 | 
						|
  wm->initialized = 0;
 | 
						|
  wm->op_undo_depth = 0;
 | 
						|
  wm->is_interface_locked = 0;
 | 
						|
}
 | 
						|
 | 
						|
static void lib_link_wm_xr_data(BlendLibReader *reader, ID *parent_id, wmXrData *xr_data)
 | 
						|
{
 | 
						|
  BLO_read_id_address(reader, parent_id->lib, &xr_data->session_settings.base_pose_object);
 | 
						|
}
 | 
						|
 | 
						|
static void lib_link_workspace_instance_hook(BlendLibReader *reader,
 | 
						|
                                             WorkSpaceInstanceHook *hook,
 | 
						|
                                             ID *id)
 | 
						|
{
 | 
						|
  WorkSpace *workspace = BKE_workspace_active_get(hook);
 | 
						|
  BLO_read_id_address(reader, id->lib, &workspace);
 | 
						|
  BKE_workspace_active_set(hook, workspace);
 | 
						|
}
 | 
						|
 | 
						|
static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = (wmWindowManager *)id;
 | 
						|
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    if (win->workspace_hook) { /* NULL for old files */
 | 
						|
      lib_link_workspace_instance_hook(reader, win->workspace_hook, &wm->id);
 | 
						|
    }
 | 
						|
    BLO_read_id_address(reader, wm->id.lib, &win->scene);
 | 
						|
    /* deprecated, but needed for versioning (will be NULL'ed then) */
 | 
						|
    BLO_read_id_address(reader, NULL, &win->screen);
 | 
						|
 | 
						|
    LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
 | 
						|
      BKE_screen_area_blend_read_lib(reader, &wm->id, area);
 | 
						|
    }
 | 
						|
 | 
						|
    lib_link_wm_xr_data(reader, &wm->id, &wm->xr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
IDTypeInfo IDType_ID_WM = {
 | 
						|
    .id_code = ID_WM,
 | 
						|
    .id_filter = 0,
 | 
						|
    .main_listbase_index = INDEX_ID_WM,
 | 
						|
    .struct_size = sizeof(wmWindowManager),
 | 
						|
    .name = "WindowManager",
 | 
						|
    .name_plural = "window_managers",
 | 
						|
    .translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER,
 | 
						|
    .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_MAKELOCAL |
 | 
						|
             IDTYPE_FLAGS_NO_ANIMDATA,
 | 
						|
 | 
						|
    .init_data = NULL,
 | 
						|
    .copy_data = NULL,
 | 
						|
    .free_data = window_manager_free_data,
 | 
						|
    .make_local = NULL,
 | 
						|
    .foreach_id = window_manager_foreach_id,
 | 
						|
    .foreach_cache = NULL,
 | 
						|
    .owner_get = NULL,
 | 
						|
 | 
						|
    .blend_write = window_manager_blend_write,
 | 
						|
    .blend_read_data = window_manager_blend_read_data,
 | 
						|
    .blend_read_lib = window_manager_blend_read_lib,
 | 
						|
    .blend_read_expand = NULL,
 | 
						|
 | 
						|
    .blend_read_undo_preserve = NULL,
 | 
						|
 | 
						|
    .lib_override_apply_post = NULL,
 | 
						|
};
 | 
						|
 | 
						|
#define MAX_OP_REGISTERED 32
 | 
						|
 | 
						|
void WM_operator_free(wmOperator *op)
 | 
						|
{
 | 
						|
 | 
						|
#ifdef WITH_PYTHON
 | 
						|
  if (op->py_instance) {
 | 
						|
    /* Do this first in case there are any __del__ functions or similar that use properties. */
 | 
						|
    BPY_DECREF_RNA_INVALIDATE(op->py_instance);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if (op->ptr) {
 | 
						|
    op->properties = op->ptr->data;
 | 
						|
    MEM_freeN(op->ptr);
 | 
						|
  }
 | 
						|
 | 
						|
  if (op->properties) {
 | 
						|
    IDP_FreeProperty(op->properties);
 | 
						|
  }
 | 
						|
 | 
						|
  if (op->reports && (op->reports->flag & RPT_FREE)) {
 | 
						|
    BKE_reports_clear(op->reports);
 | 
						|
    MEM_freeN(op->reports);
 | 
						|
  }
 | 
						|
 | 
						|
  if (op->macro.first) {
 | 
						|
    wmOperator *opm, *opmnext;
 | 
						|
    for (opm = op->macro.first; opm; opm = opmnext) {
 | 
						|
      opmnext = opm->next;
 | 
						|
      WM_operator_free(opm);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MEM_freeN(op);
 | 
						|
}
 | 
						|
 | 
						|
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
 | 
						|
{
 | 
						|
  op = op->next;
 | 
						|
  while (op != NULL) {
 | 
						|
    wmOperator *op_next = op->next;
 | 
						|
    BLI_remlink(&wm->operators, op);
 | 
						|
    WM_operator_free(op);
 | 
						|
    op = op_next;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Use with extreme care!,
 | 
						|
 * properties, custom-data etc - must be compatible.
 | 
						|
 *
 | 
						|
 * \param op: Operator to assign the type to.
 | 
						|
 * \param ot: Operator type to assign.
 | 
						|
 */
 | 
						|
void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
 | 
						|
{
 | 
						|
  /* Not supported for Python. */
 | 
						|
  BLI_assert(op->py_instance == NULL);
 | 
						|
 | 
						|
  op->type = ot;
 | 
						|
  op->ptr->type = ot->srna;
 | 
						|
 | 
						|
  /* Ensure compatible properties. */
 | 
						|
  if (op->properties) {
 | 
						|
    PointerRNA ptr;
 | 
						|
    WM_operator_properties_create_ptr(&ptr, ot);
 | 
						|
 | 
						|
    WM_operator_properties_default(&ptr, false);
 | 
						|
 | 
						|
    if (ptr.data) {
 | 
						|
      IDP_SyncGroupTypes(op->properties, ptr.data, true);
 | 
						|
    }
 | 
						|
 | 
						|
    WM_operator_properties_free(&ptr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void wm_reports_free(wmWindowManager *wm)
 | 
						|
{
 | 
						|
  BKE_reports_clear(&wm->reports);
 | 
						|
  WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
 | 
						|
}
 | 
						|
 | 
						|
/* All operations get registered in the windowmanager here. */
 | 
						|
/* Called on event handling by event_system.c. */
 | 
						|
void wm_operator_register(bContext *C, wmOperator *op)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = CTX_wm_manager(C);
 | 
						|
  int tot = 0;
 | 
						|
 | 
						|
  BLI_addtail(&wm->operators, op);
 | 
						|
 | 
						|
  /* Only count registered operators. */
 | 
						|
  while (op) {
 | 
						|
    wmOperator *op_prev = op->prev;
 | 
						|
    if (op->type->flag & OPTYPE_REGISTER) {
 | 
						|
      tot += 1;
 | 
						|
    }
 | 
						|
    if (tot > MAX_OP_REGISTERED) {
 | 
						|
      BLI_remlink(&wm->operators, op);
 | 
						|
      WM_operator_free(op);
 | 
						|
    }
 | 
						|
    op = op_prev;
 | 
						|
  }
 | 
						|
 | 
						|
  /* So the console is redrawn. */
 | 
						|
  WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
 | 
						|
  WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void WM_operator_stack_clear(wmWindowManager *wm)
 | 
						|
{
 | 
						|
  wmOperator *op;
 | 
						|
 | 
						|
  while ((op = BLI_pophead(&wm->operators))) {
 | 
						|
    WM_operator_free(op);
 | 
						|
  }
 | 
						|
 | 
						|
  WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This function is needed in the case when an addon id disabled
 | 
						|
 * while a modal operator it defined is running.
 | 
						|
 */
 | 
						|
void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
 | 
						|
{
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    ListBase *lb[2] = {&win->handlers, &win->modalhandlers};
 | 
						|
    for (int i = 0; i < ARRAY_SIZE(lb); i++) {
 | 
						|
      LISTBASE_FOREACH (wmEventHandler *, handler_base, lb[i]) {
 | 
						|
        if (handler_base->type == WM_HANDLER_TYPE_OP) {
 | 
						|
          wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
 | 
						|
          if (handler->op && handler->op->type == ot) {
 | 
						|
            /* don't run op->cancel because it needs the context,
 | 
						|
             * assume whoever unregisters the operator will cleanup */
 | 
						|
            handler->head.flag |= WM_HANDLER_DO_FREE;
 | 
						|
            WM_operator_free(handler->op);
 | 
						|
            handler->op = NULL;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* ****************************************** */
 | 
						|
 | 
						|
void WM_keyconfig_reload(bContext *C)
 | 
						|
{
 | 
						|
  if (CTX_py_init_get(C) && !G.background) {
 | 
						|
#ifdef WITH_PYTHON
 | 
						|
    BPY_run_string_eval(C, (const char *[]){"bpy", NULL}, "bpy.utils.keyconfig_init()");
 | 
						|
#endif
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void WM_keyconfig_init(bContext *C)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = CTX_wm_manager(C);
 | 
						|
 | 
						|
  /* Create standard key configs. */
 | 
						|
  if (wm->defaultconf == NULL) {
 | 
						|
    /* Keep lowercase to match the preset filename. */
 | 
						|
    wm->defaultconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT, false);
 | 
						|
  }
 | 
						|
  if (wm->addonconf == NULL) {
 | 
						|
    wm->addonconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " addon", false);
 | 
						|
  }
 | 
						|
  if (wm->userconf == NULL) {
 | 
						|
    wm->userconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " user", false);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Initialize only after python init is done, for keymaps that use python operators. */
 | 
						|
  if (CTX_py_init_get(C) && (wm->initialized & WM_KEYCONFIG_IS_INIT) == 0) {
 | 
						|
    /* create default key config, only initialize once,
 | 
						|
     * it's persistent across sessions */
 | 
						|
    if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) {
 | 
						|
      wm_window_keymap(wm->defaultconf);
 | 
						|
      ED_spacetypes_keymap(wm->defaultconf);
 | 
						|
 | 
						|
      WM_keyconfig_reload(C);
 | 
						|
 | 
						|
      wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT;
 | 
						|
    }
 | 
						|
 | 
						|
    WM_keyconfig_update_tag(NULL, NULL);
 | 
						|
    WM_keyconfig_update(wm);
 | 
						|
 | 
						|
    wm->initialized |= WM_KEYCONFIG_IS_INIT;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void WM_check(bContext *C)
 | 
						|
{
 | 
						|
  Main *bmain = CTX_data_main(C);
 | 
						|
  wmWindowManager *wm = CTX_wm_manager(C);
 | 
						|
 | 
						|
  /* WM context. */
 | 
						|
  if (wm == NULL) {
 | 
						|
    wm = bmain->wm.first;
 | 
						|
    CTX_wm_manager_set(C, wm);
 | 
						|
  }
 | 
						|
 | 
						|
  if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Run before loading the keyconfig. */
 | 
						|
  if (wm->message_bus == NULL) {
 | 
						|
    wm->message_bus = WM_msgbus_create();
 | 
						|
  }
 | 
						|
 | 
						|
  if (!G.background) {
 | 
						|
    /* Case: fileread. */
 | 
						|
    if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
 | 
						|
      WM_keyconfig_init(C);
 | 
						|
      WM_autosave_init(wm);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Case: no open windows at all, for old file reads. */
 | 
						|
    wm_window_ghostwindows_ensure(wm);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Case: fileread. */
 | 
						|
  /* Note: this runs in background mode to set the screen context cb. */
 | 
						|
  if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
 | 
						|
    ED_screens_init(bmain, wm);
 | 
						|
    wm->initialized |= WM_WINDOW_IS_INIT;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void wm_clear_default_size(bContext *C)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = CTX_wm_manager(C);
 | 
						|
 | 
						|
  /* WM context. */
 | 
						|
  if (wm == NULL) {
 | 
						|
    wm = CTX_data_main(C)->wm.first;
 | 
						|
    CTX_wm_manager_set(C, wm);
 | 
						|
  }
 | 
						|
 | 
						|
  if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
 | 
						|
    win->sizex = 0;
 | 
						|
    win->sizey = 0;
 | 
						|
    win->posx = 0;
 | 
						|
    win->posy = 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* On startup, it adds all data, for matching. */
 | 
						|
void wm_add_default(Main *bmain, bContext *C)
 | 
						|
{
 | 
						|
  wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
 | 
						|
  wmWindow *win;
 | 
						|
  bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
 | 
						|
  WorkSpace *workspace;
 | 
						|
  WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
 | 
						|
 | 
						|
  CTX_wm_manager_set(C, wm);
 | 
						|
  win = wm_window_new(bmain, wm, NULL, false);
 | 
						|
  win->scene = CTX_data_scene(C);
 | 
						|
  STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name);
 | 
						|
  BKE_workspace_active_set(win->workspace_hook, workspace);
 | 
						|
  BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
 | 
						|
  screen->winid = win->winid;
 | 
						|
 | 
						|
  wm->winactive = win;
 | 
						|
  wm->file_saved = 1;
 | 
						|
  wm_window_make_drawable(wm, win);
 | 
						|
}
 | 
						|
 | 
						|
/* Context is allowed to be NULL, do not free wm itself (lib_id.c). */
 | 
						|
void wm_close_and_free(bContext *C, wmWindowManager *wm)
 | 
						|
{
 | 
						|
  if (wm->autosavetimer) {
 | 
						|
    wm_autosave_timer_ended(wm);
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef WITH_XR_OPENXR
 | 
						|
  /* May send notifier, so do before freeing notifier queue. */
 | 
						|
  wm_xr_exit(wm);
 | 
						|
#endif
 | 
						|
 | 
						|
  wmWindow *win;
 | 
						|
  while ((win = BLI_pophead(&wm->windows))) {
 | 
						|
    /* Prevent draw clear to use screen. */
 | 
						|
    BKE_workspace_active_set(win->workspace_hook, NULL);
 | 
						|
    wm_window_free(C, wm, win);
 | 
						|
  }
 | 
						|
 | 
						|
  wmOperator *op;
 | 
						|
  while ((op = BLI_pophead(&wm->operators))) {
 | 
						|
    WM_operator_free(op);
 | 
						|
  }
 | 
						|
 | 
						|
  wmKeyConfig *keyconf;
 | 
						|
  while ((keyconf = BLI_pophead(&wm->keyconfigs))) {
 | 
						|
    WM_keyconfig_free(keyconf);
 | 
						|
  }
 | 
						|
 | 
						|
  BLI_freelistN(&wm->notifier_queue);
 | 
						|
 | 
						|
  if (wm->message_bus != NULL) {
 | 
						|
    WM_msgbus_destroy(wm->message_bus);
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef WITH_PYTHON
 | 
						|
  BPY_callback_wm_free(wm);
 | 
						|
#endif
 | 
						|
  BLI_freelistN(&wm->paintcursors);
 | 
						|
 | 
						|
  WM_drag_free_list(&wm->drags);
 | 
						|
 | 
						|
  wm_reports_free(wm);
 | 
						|
 | 
						|
  if (wm->undo_stack) {
 | 
						|
    BKE_undosys_stack_destroy(wm->undo_stack);
 | 
						|
    wm->undo_stack = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (C && CTX_wm_manager(C) == wm) {
 | 
						|
    CTX_wm_manager_set(C, NULL);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
 | 
						|
{
 | 
						|
  wmWindowManager *wm;
 | 
						|
  while ((wm = wmlist->first)) {
 | 
						|
    wm_close_and_free(C, wm);
 | 
						|
    BLI_remlink(wmlist, wm);
 | 
						|
    BKE_libblock_free_data(&wm->id, true);
 | 
						|
    MEM_freeN(wm);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void WM_main(bContext *C)
 | 
						|
{
 | 
						|
  /* Single refresh before handling events.
 | 
						|
   * This ensures we don't run operators before the depsgraph has been evaluated. */
 | 
						|
  wm_event_do_refresh_wm_and_depsgraph(C);
 | 
						|
 | 
						|
  while (1) {
 | 
						|
 | 
						|
    /* Get events from ghost, handle window events, add to window queues. */
 | 
						|
    wm_window_process_events(C);
 | 
						|
 | 
						|
    /* Per window, all events to the window, screen, area and region handlers. */
 | 
						|
    wm_event_do_handlers(C);
 | 
						|
 | 
						|
    /* Wvents have left notes about changes, we handle and cache it. */
 | 
						|
    wm_event_do_notifiers(C);
 | 
						|
 | 
						|
    /* Wxecute cached changes draw. */
 | 
						|
    wm_draw_update(C);
 | 
						|
  }
 | 
						|
}
 |