Merge branch 'blender-v2.81-release'
[blender.git] / source / blender / windowmanager / intern / wm.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup wm
22  *
23  * Internal functions for managing UI registrable types (operator, UI and menu types)
24  *
25  * Also Blenders main event loop (WM_main)
26  */
27
28 #include <string.h>
29 #include <stddef.h>
30
31 #include "BLI_sys_types.h"
32
33 #include "DNA_windowmanager_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_blenlib.h"
39
40 #include "BKE_context.h"
41 #include "BKE_global.h"
42 #include "BKE_idprop.h"
43 #include "BKE_library.h"
44 #include "BKE_main.h"
45 #include "BKE_report.h"
46 #include "BKE_workspace.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50 #include "WM_message.h"
51 #include "wm_window.h"
52 #include "wm_event_system.h"
53 #include "wm_draw.h"
54 #include "wm.h"
55
56 #include "ED_screen.h"
57 #include "BKE_undo_system.h"
58
59 #ifdef WITH_PYTHON
60 #  include "BPY_extern.h"
61 #endif
62
63 /* ****************************************************** */
64
65 #define MAX_OP_REGISTERED 32
66
67 void WM_operator_free(wmOperator *op)
68 {
69
70 #ifdef WITH_PYTHON
71   if (op->py_instance) {
72     /* do this first in case there are any __del__ functions or
73      * similar that use properties */
74     BPY_DECREF_RNA_INVALIDATE(op->py_instance);
75   }
76 #endif
77
78   if (op->ptr) {
79     op->properties = op->ptr->data;
80     MEM_freeN(op->ptr);
81   }
82
83   if (op->properties) {
84     IDP_FreeProperty(op->properties);
85   }
86
87   if (op->reports && (op->reports->flag & RPT_FREE)) {
88     BKE_reports_clear(op->reports);
89     MEM_freeN(op->reports);
90   }
91
92   if (op->macro.first) {
93     wmOperator *opm, *opmnext;
94     for (opm = op->macro.first; opm; opm = opmnext) {
95       opmnext = opm->next;
96       WM_operator_free(opm);
97     }
98   }
99
100   MEM_freeN(op);
101 }
102
103 void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
104 {
105   op = op->next;
106   while (op != NULL) {
107     wmOperator *op_next = op->next;
108     BLI_remlink(&wm->operators, op);
109     WM_operator_free(op);
110     op = op_next;
111   }
112 }
113
114 /**
115  * Use with extreme care!,
116  * properties, customdata etc - must be compatible.
117  *
118  * \param op: Operator to assign the type to.
119  * \param ot: OperatorType to assign.
120  */
121 void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
122 {
123   /* not supported for Python */
124   BLI_assert(op->py_instance == NULL);
125
126   op->type = ot;
127   op->ptr->type = ot->srna;
128
129   /* ensure compatible properties */
130   if (op->properties) {
131     PointerRNA ptr;
132
133     WM_operator_properties_create_ptr(&ptr, ot);
134
135     WM_operator_properties_default(&ptr, false);
136
137     if (ptr.data) {
138       IDP_SyncGroupTypes(op->properties, ptr.data, true);
139     }
140
141     WM_operator_properties_free(&ptr);
142   }
143 }
144
145 static void wm_reports_free(wmWindowManager *wm)
146 {
147   BKE_reports_clear(&wm->reports);
148   WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
149 }
150
151 /* all operations get registered in the windowmanager here */
152 /* called on event handling by event_system.c */
153 void wm_operator_register(bContext *C, wmOperator *op)
154 {
155   wmWindowManager *wm = CTX_wm_manager(C);
156   int tot = 0;
157
158   BLI_addtail(&wm->operators, op);
159
160   /* only count registered operators */
161   while (op) {
162     wmOperator *op_prev = op->prev;
163     if (op->type->flag & OPTYPE_REGISTER) {
164       tot += 1;
165     }
166     if (tot > MAX_OP_REGISTERED) {
167       BLI_remlink(&wm->operators, op);
168       WM_operator_free(op);
169     }
170     op = op_prev;
171   }
172
173   /* so the console is redrawn */
174   WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
175   WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
176 }
177
178 void WM_operator_stack_clear(wmWindowManager *wm)
179 {
180   wmOperator *op;
181
182   while ((op = BLI_pophead(&wm->operators))) {
183     WM_operator_free(op);
184   }
185
186   WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
187 }
188
189 /**
190  * This function is needed in the case when an addon id disabled
191  * while a modal operator it defined is running.
192  */
193 void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
194 {
195   wmWindow *win;
196   for (win = wm->windows.first; win; win = win->next) {
197     ListBase *lb[2] = {&win->handlers, &win->modalhandlers};
198     for (int i = 0; i < ARRAY_SIZE(lb); i++) {
199       LISTBASE_FOREACH (wmEventHandler *, handler_base, lb[i]) {
200         if (handler_base->type == WM_HANDLER_TYPE_OP) {
201           wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
202           if (handler->op && handler->op->type == ot) {
203             /* don't run op->cancel because it needs the context,
204              * assume whoever unregisters the operator will cleanup */
205             handler->head.flag |= WM_HANDLER_DO_FREE;
206             WM_operator_free(handler->op);
207             handler->op = NULL;
208           }
209         }
210       }
211     }
212   }
213 }
214
215 /* ****************************************** */
216
217 void WM_keyconfig_reload(bContext *C)
218 {
219   if (CTX_py_init_get(C) && !G.background) {
220 #ifdef WITH_PYTHON
221     BPY_execute_string(C, (const char *[]){"bpy", NULL}, "bpy.utils.keyconfig_init()");
222 #endif
223   }
224 }
225
226 void WM_keyconfig_init(bContext *C)
227 {
228   wmWindowManager *wm = CTX_wm_manager(C);
229
230   /* create standard key configs */
231   if (wm->defaultconf == NULL) {
232     /* Keep lowercase to match the preset filename. */
233     wm->defaultconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT, false);
234   }
235   if (wm->addonconf == NULL) {
236     wm->addonconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " addon", false);
237   }
238   if (wm->userconf == NULL) {
239     wm->userconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " user", false);
240   }
241
242   /* initialize only after python init is done, for keymaps that
243    * use python operators */
244   if (CTX_py_init_get(C) && (wm->initialized & WM_KEYCONFIG_IS_INITIALIZED) == 0) {
245     /* create default key config, only initialize once,
246      * it's persistent across sessions */
247     if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) {
248       wm_window_keymap(wm->defaultconf);
249       ED_spacetypes_keymap(wm->defaultconf);
250
251       WM_keyconfig_reload(C);
252
253       wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT;
254     }
255
256     WM_keyconfig_update_tag(NULL, NULL);
257     WM_keyconfig_update(wm);
258
259     wm->initialized |= WM_KEYCONFIG_IS_INITIALIZED;
260   }
261 }
262
263 void WM_check(bContext *C)
264 {
265   Main *bmain = CTX_data_main(C);
266   wmWindowManager *wm = CTX_wm_manager(C);
267
268   /* wm context */
269   if (wm == NULL) {
270     wm = CTX_data_main(C)->wm.first;
271     CTX_wm_manager_set(C, wm);
272   }
273
274   if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
275     return;
276   }
277
278   if (!G.background) {
279     /* case: fileread */
280     if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
281       WM_keyconfig_init(C);
282       WM_autosave_init(wm);
283     }
284
285     /* case: no open windows at all, for old file reads */
286     wm_window_ghostwindows_ensure(wm);
287   }
288
289   if (wm->message_bus == NULL) {
290     wm->message_bus = WM_msgbus_create();
291   }
292
293   /* case: fileread */
294   /* note: this runs in bg mode to set the screen context cb */
295   if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
296     ED_screens_initialize(bmain, wm);
297     wm->initialized |= WM_WINDOW_IS_INITIALIZED;
298   }
299 }
300
301 void wm_clear_default_size(bContext *C)
302 {
303   wmWindowManager *wm = CTX_wm_manager(C);
304   wmWindow *win;
305
306   /* wm context */
307   if (wm == NULL) {
308     wm = CTX_data_main(C)->wm.first;
309     CTX_wm_manager_set(C, wm);
310   }
311
312   if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
313     return;
314   }
315
316   for (win = wm->windows.first; win; win = win->next) {
317     win->sizex = 0;
318     win->sizey = 0;
319     win->posx = 0;
320     win->posy = 0;
321   }
322 }
323
324 /* on startup, it adds all data, for matching */
325 void wm_add_default(Main *bmain, bContext *C)
326 {
327   wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
328   wmWindow *win;
329   bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
330   WorkSpace *workspace;
331   WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
332
333   CTX_wm_manager_set(C, wm);
334   win = wm_window_new(C, NULL);
335   win->scene = CTX_data_scene(C);
336   STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name);
337   BKE_workspace_active_set(win->workspace_hook, workspace);
338   BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
339   screen->winid = win->winid;
340
341   wm->winactive = win;
342   wm->file_saved = 1;
343   wm_window_make_drawable(wm, win);
344 }
345
346 /* context is allowed to be NULL, do not free wm itself (library.c) */
347 void wm_close_and_free(bContext *C, wmWindowManager *wm)
348 {
349   wmWindow *win;
350   wmOperator *op;
351   wmKeyConfig *keyconf;
352
353   if (wm->autosavetimer) {
354     wm_autosave_timer_ended(wm);
355   }
356
357   while ((win = BLI_pophead(&wm->windows))) {
358     /* prevent draw clear to use screen */
359     BKE_workspace_active_set(win->workspace_hook, NULL);
360     wm_window_free(C, wm, win);
361   }
362
363   while ((op = BLI_pophead(&wm->operators))) {
364     WM_operator_free(op);
365   }
366
367   while ((keyconf = BLI_pophead(&wm->keyconfigs))) {
368     WM_keyconfig_free(keyconf);
369   }
370
371   BLI_freelistN(&wm->queue);
372
373   if (wm->message_bus != NULL) {
374     WM_msgbus_destroy(wm->message_bus);
375   }
376
377   BLI_freelistN(&wm->paintcursors);
378
379   WM_drag_free_list(&wm->drags);
380
381   wm_reports_free(wm);
382
383   if (wm->undo_stack) {
384     BKE_undosys_stack_destroy(wm->undo_stack);
385     wm->undo_stack = NULL;
386   }
387
388   if (C && CTX_wm_manager(C) == wm) {
389     CTX_wm_manager_set(C, NULL);
390   }
391 }
392
393 void wm_close_and_free_all(bContext *C, ListBase *wmlist)
394 {
395   wmWindowManager *wm;
396
397   while ((wm = wmlist->first)) {
398     wm_close_and_free(C, wm);
399     BLI_remlink(wmlist, wm);
400     BKE_libblock_free_data(&wm->id, true);
401     MEM_freeN(wm);
402   }
403 }
404
405 void WM_main(bContext *C)
406 {
407   /* Single refresh before handling events.
408    * This ensures we don't run operators before the depsgraph has been evaluated. */
409   wm_event_do_refresh_wm_and_depsgraph(C);
410
411   while (1) {
412
413     /* get events from ghost, handle window events, add to window queues */
414     wm_window_process_events(C);
415
416     /* per window, all events to the window, screen, area and region handlers */
417     wm_event_do_handlers(C);
418
419     /* events have left notes about changes, we handle and cache it */
420     wm_event_do_notifiers(C);
421
422     /* execute cached changes draw */
423     wm_draw_update(C);
424   }
425 }