Merge branch 'master' into blender2.8
[blender.git] / source / blender / windowmanager / intern / wm.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/windowmanager/intern/wm.c
28  *  \ingroup wm
29  *
30  * Internal functions for managing UI registrable types (operator, UI and menu types)
31  *
32  * Also Blenders main event loop (WM_main)
33  */
34
35 #include <string.h>
36 #include <stddef.h>
37
38 #include "BLI_sys_types.h"
39
40 #include "DNA_windowmanager_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_utildefines.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_ghash.h"
47
48 #include "BKE_context.h"
49 #include "BKE_idprop.h"
50 #include "BKE_library.h"
51 #include "BKE_main.h"
52 #include "BKE_screen.h"
53 #include "BKE_report.h"
54 #include "BKE_global.h"
55 #include "BKE_workspace.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59 #include "WM_message.h"
60 #include "wm_window.h"
61 #include "wm_event_system.h"
62 #include "wm_draw.h"
63 #include "wm.h"
64
65 #include "ED_screen.h"
66 #include "BKE_undo_system.h"
67
68 #ifdef WITH_PYTHON
69 #include "BPY_extern.h"
70 #endif
71
72 /* ****************************************************** */
73
74 #define MAX_OP_REGISTERED   32
75
76 void WM_operator_free(wmOperator *op)
77 {
78
79 #ifdef WITH_PYTHON
80         if (op->py_instance) {
81                 /* do this first in case there are any __del__ functions or
82                  * similar that use properties */
83                 BPY_DECREF_RNA_INVALIDATE(op->py_instance);
84         }
85 #endif
86
87         if (op->ptr) {
88                 op->properties = op->ptr->data;
89                 MEM_freeN(op->ptr);
90         }
91
92         if (op->properties) {
93                 IDP_FreeProperty(op->properties);
94                 MEM_freeN(op->properties);
95         }
96
97         if (op->reports && (op->reports->flag & RPT_FREE)) {
98                 BKE_reports_clear(op->reports);
99                 MEM_freeN(op->reports);
100         }
101
102         if (op->macro.first) {
103                 wmOperator *opm, *opmnext;
104                 for (opm = op->macro.first; opm; opm = opmnext) {
105                         opmnext = opm->next;
106                         WM_operator_free(opm);
107                 }
108         }
109
110         MEM_freeN(op);
111 }
112
113 void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
114 {
115         op = op->next;
116         while (op != NULL) {
117                 wmOperator *op_next = op->next;
118                 BLI_remlink(&wm->operators, op);
119                 WM_operator_free(op);
120                 op = op_next;
121         }
122 }
123
124 /**
125  * Use with extreme care!,
126  * properties, customdata etc - must be compatible.
127  *
128  * \param op  Operator to assign the type to.
129  * \param ot  OperatorType to assign.
130  */
131 void WM_operator_type_set(wmOperator *op, wmOperatorType *ot)
132 {
133         /* not supported for Python */
134         BLI_assert(op->py_instance == NULL);
135
136         op->type = ot;
137         op->ptr->type = ot->srna;
138
139         /* ensure compatible properties */
140         if (op->properties) {
141                 PointerRNA ptr;
142
143                 WM_operator_properties_create_ptr(&ptr, ot);
144
145                 WM_operator_properties_default(&ptr, false);
146
147                 if (ptr.data) {
148                         IDP_SyncGroupTypes(op->properties, ptr.data, true);
149                 }
150
151                 WM_operator_properties_free(&ptr);
152         }
153 }
154
155 static void wm_reports_free(wmWindowManager *wm)
156 {
157         BKE_reports_clear(&wm->reports);
158         WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
159 }
160
161 /* all operations get registered in the windowmanager here */
162 /* called on event handling by event_system.c */
163 void wm_operator_register(bContext *C, wmOperator *op)
164 {
165         wmWindowManager *wm = CTX_wm_manager(C);
166         int tot = 0;
167
168         op->execution_area = CTX_wm_area(C);
169         op->execution_region = CTX_wm_region(C);
170
171         BLI_addtail(&wm->operators, op);
172
173         /* only count registered operators */
174         while (op) {
175                 wmOperator *op_prev = op->prev;
176                 if (op->type->flag & OPTYPE_REGISTER) {
177                         tot += 1;
178                 }
179                 if (tot > MAX_OP_REGISTERED) {
180                         BLI_remlink(&wm->operators, op);
181                         WM_operator_free(op);
182                 }
183                 op = op_prev;
184         }
185
186         /* so the console is redrawn */
187         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
188         WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
189 }
190
191
192 void WM_operator_stack_clear(wmWindowManager *wm)
193 {
194         wmOperator *op;
195
196         while ((op = BLI_pophead(&wm->operators))) {
197                 WM_operator_free(op);
198         }
199
200         WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
201 }
202
203 /**
204  * This function is needed in the case when an addon id disabled
205  * while a modal operator it defined is running.
206  */
207 void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
208 {
209         wmWindow *win;
210         for (win = wm->windows.first; win; win = win->next) {
211                 ListBase *lb[2] = {&win->handlers, &win->modalhandlers};
212                 wmEventHandler *handler;
213                 int i;
214
215                 for (i = 0; i < 2; i++) {
216                         for (handler = lb[i]->first; handler; handler = handler->next) {
217                                 if (handler->op && handler->op->type == ot) {
218                                         /* don't run op->cancel because it needs the context,
219                                          * assume whoever unregisters the operator will cleanup */
220                                         handler->flag |= WM_HANDLER_DO_FREE;
221                                         WM_operator_free(handler->op);
222                                         handler->op = NULL;
223                                 }
224                         }
225                 }
226         }
227 }
228
229 /* ************ uiListType handling ************** */
230
231 static GHash *uilisttypes_hash = NULL;
232
233 uiListType *WM_uilisttype_find(const char *idname, bool quiet)
234 {
235         uiListType *ult;
236
237         if (idname[0]) {
238                 ult = BLI_ghash_lookup(uilisttypes_hash, idname);
239                 if (ult) {
240                         return ult;
241                 }
242         }
243
244         if (!quiet) {
245                 printf("search for unknown uilisttype %s\n", idname);
246         }
247
248         return NULL;
249 }
250
251 bool WM_uilisttype_add(uiListType *ult)
252 {
253         BLI_ghash_insert(uilisttypes_hash, ult->idname, ult);
254         return 1;
255 }
256
257 void WM_uilisttype_freelink(uiListType *ult)
258 {
259         bool ok;
260
261         ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN);
262
263         BLI_assert(ok);
264         (void)ok;
265 }
266
267 /* called on initialize WM_init() */
268 void WM_uilisttype_init(void)
269 {
270         uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
271 }
272
273 void WM_uilisttype_free(void)
274 {
275         GHashIterator gh_iter;
276
277         GHASH_ITER (gh_iter, uilisttypes_hash) {
278                 uiListType *ult = BLI_ghashIterator_getValue(&gh_iter);
279                 if (ult->ext.free) {
280                         ult->ext.free(ult->ext.data);
281                 }
282         }
283
284         BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN);
285         uilisttypes_hash = NULL;
286 }
287
288 /* ************ MenuType handling ************** */
289
290 static GHash *menutypes_hash = NULL;
291
292 MenuType *WM_menutype_find(const char *idname, bool quiet)
293 {
294         MenuType *mt;
295
296         if (idname[0]) {
297                 mt = BLI_ghash_lookup(menutypes_hash, idname);
298                 if (mt)
299                         return mt;
300         }
301
302         if (!quiet)
303                 printf("search for unknown menutype %s\n", idname);
304
305         return NULL;
306 }
307
308 bool WM_menutype_add(MenuType *mt)
309 {
310         BLI_ghash_insert(menutypes_hash, mt->idname, mt);
311         return true;
312 }
313
314 void WM_menutype_freelink(MenuType *mt)
315 {
316         bool ok;
317
318         ok = BLI_ghash_remove(menutypes_hash, mt->idname, NULL, MEM_freeN);
319
320         BLI_assert(ok);
321         (void)ok;
322 }
323
324 /* called on initialize WM_init() */
325 void WM_menutype_init(void)
326 {
327         /* reserve size is set based on blender default setup */
328         menutypes_hash = BLI_ghash_str_new_ex("menutypes_hash gh", 512);
329 }
330
331 void WM_menutype_free(void)
332 {
333         GHashIterator gh_iter;
334
335         GHASH_ITER (gh_iter, menutypes_hash) {
336                 MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
337                 if (mt->ext.free) {
338                         mt->ext.free(mt->ext.data);
339                 }
340         }
341
342         BLI_ghash_free(menutypes_hash, NULL, MEM_freeN);
343         menutypes_hash = NULL;
344 }
345
346 bool WM_menutype_poll(bContext *C, MenuType *mt)
347 {
348         /* If we're tagged, only use compatible. */
349         if (mt->owner_id[0] != '\0') {
350                 const WorkSpace *workspace = CTX_wm_workspace(C);
351                 if (BKE_workspace_owner_id_check(workspace, mt->owner_id) == false) {
352                         return false;
353                 }
354         }
355
356         if (mt->poll != NULL) {
357                 return mt->poll(C, mt);
358         }
359         return true;
360 }
361
362 /* ****************************************** */
363
364 void WM_keymap_init(bContext *C)
365 {
366         wmWindowManager *wm = CTX_wm_manager(C);
367
368         /* create standard key configs */
369         if (!wm->defaultconf)
370                 wm->defaultconf = WM_keyconfig_new(wm, "Blender");
371         if (!wm->addonconf)
372                 wm->addonconf = WM_keyconfig_new(wm, "Blender Addon");
373         if (!wm->userconf)
374                 wm->userconf = WM_keyconfig_new(wm, "Blender User");
375
376         /* initialize only after python init is done, for keymaps that
377          * use python operators */
378         if (CTX_py_init_get(C) && (wm->initialized & WM_KEYMAP_IS_INITIALIZED) == 0) {
379                 /* create default key config, only initialize once,
380                  * it's persistent across sessions */
381                 if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) {
382                         wm_window_keymap(wm->defaultconf);
383                         ED_spacetypes_keymap(wm->defaultconf);
384
385                         wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT;
386                 }
387
388                 WM_keyconfig_update_tag(NULL, NULL);
389                 WM_keyconfig_update(wm);
390
391                 wm->initialized |= WM_KEYMAP_IS_INITIALIZED;
392         }
393 }
394
395 void WM_check(bContext *C)
396 {
397         Main *bmain = CTX_data_main(C);
398         wmWindowManager *wm = CTX_wm_manager(C);
399
400         /* wm context */
401         if (wm == NULL) {
402                 wm = CTX_data_main(C)->wm.first;
403                 CTX_wm_manager_set(C, wm);
404         }
405
406         if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
407                 return;
408         }
409
410         if (!G.background) {
411                 /* case: fileread */
412                 if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
413                         WM_keymap_init(C);
414                         WM_autosave_init(wm);
415                 }
416
417                 /* case: no open windows at all, for old file reads */
418                 wm_window_ghostwindows_ensure(wm);
419         }
420
421         if (wm->message_bus == NULL) {
422                 wm->message_bus = WM_msgbus_create();
423         }
424
425         /* case: fileread */
426         /* note: this runs in bg mode to set the screen context cb */
427         if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
428                 ED_screens_initialize(bmain, wm);
429                 wm->initialized |= WM_WINDOW_IS_INITIALIZED;
430         }
431 }
432
433 void wm_clear_default_size(bContext *C)
434 {
435         wmWindowManager *wm = CTX_wm_manager(C);
436         wmWindow *win;
437
438         /* wm context */
439         if (wm == NULL) {
440                 wm = CTX_data_main(C)->wm.first;
441                 CTX_wm_manager_set(C, wm);
442         }
443
444         if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
445                 return;
446         }
447
448         for (win = wm->windows.first; win; win = win->next) {
449                 win->sizex = 0;
450                 win->sizey = 0;
451                 win->posx = 0;
452                 win->posy = 0;
453         }
454
455 }
456
457 /* on startup, it adds all data, for matching */
458 void wm_add_default(Main *bmain, bContext *C)
459 {
460         wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
461         wmWindow *win;
462         bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
463         WorkSpace *workspace;
464         WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
465
466         CTX_wm_manager_set(C, wm);
467         win = wm_window_new(C);
468         win->scene = CTX_data_scene(C);
469         WM_window_set_active_workspace(win, workspace);
470         WM_window_set_active_layout(win, workspace, layout);
471         screen->winid = win->winid;
472
473         wm->winactive = win;
474         wm->file_saved = 1;
475         wm_window_make_drawable(wm, win);
476 }
477
478
479 /* context is allowed to be NULL, do not free wm itself (library.c) */
480 void wm_close_and_free(bContext *C, wmWindowManager *wm)
481 {
482         wmWindow *win;
483         wmOperator *op;
484         wmKeyConfig *keyconf;
485
486         if (wm->autosavetimer)
487                 wm_autosave_timer_ended(wm);
488
489         while ((win = BLI_pophead(&wm->windows))) {
490                 WM_window_set_active_workspace(win, NULL); /* prevent draw clear to use screen */
491                 wm_window_free(C, wm, win);
492         }
493
494         while ((op = BLI_pophead(&wm->operators))) {
495                 WM_operator_free(op);
496         }
497
498         while ((keyconf = BLI_pophead(&wm->keyconfigs))) {
499                 WM_keyconfig_free(keyconf);
500         }
501
502         BLI_freelistN(&wm->queue);
503
504         if (wm->message_bus != NULL) {
505                 WM_msgbus_destroy(wm->message_bus);
506         }
507
508         BLI_freelistN(&wm->paintcursors);
509
510         WM_drag_free_list(&wm->drags);
511
512         wm_reports_free(wm);
513
514         if (wm->undo_stack) {
515                 BKE_undosys_stack_destroy(wm->undo_stack);
516                 wm->undo_stack = NULL;
517         }
518
519         if (C && CTX_wm_manager(C) == wm) CTX_wm_manager_set(C, NULL);
520 }
521
522 void wm_close_and_free_all(bContext *C, ListBase *wmlist)
523 {
524         wmWindowManager *wm;
525
526         while ((wm = wmlist->first)) {
527                 wm_close_and_free(C, wm);
528                 BLI_remlink(wmlist, wm);
529                 BKE_libblock_free_data(&wm->id, true);
530                 MEM_freeN(wm);
531         }
532 }
533
534 void WM_main(bContext *C)
535 {
536         /* Single refresh before handling events.
537          * This ensures we don't run operators before the depsgraph has been evaluated. */
538         wm_event_do_refresh_wm_and_depsgraph(C);
539
540         while (1) {
541
542                 /* get events from ghost, handle window events, add to window queues */
543                 wm_window_process_events(C);
544
545                 /* per window, all events to the window, screen, area and region handlers */
546                 wm_event_do_handlers(C);
547
548                 /* events have left notes about changes, we handle and cache it */
549                 wm_event_do_notifiers(C);
550
551                 /* execute cached changes draw */
552                 wm_draw_update(C);
553         }
554 }
555
556