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
17 /** \file
18 * \ingroup wm
19 *
20 * Operator Registry.
21 */
22
23 #include "MEM_guardedalloc.h"
24
25 #include "CLG_log.h"
26
27 #include "DNA_ID.h"
28 #include "DNA_scene_types.h"
29 #include "DNA_screen_types.h"
30 #include "DNA_userdef_types.h"
31 #include "DNA_windowmanager_types.h"
32
33 #include "BLT_translation.h"
34
35 #include "BLI_blenlib.h"
36 #include "BLI_ghash.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_context.h"
40 #include "BKE_idprop.h"
41
42 #include "RNA_access.h"
43 #include "RNA_define.h"
44 #include "RNA_enum_types.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "wm.h"
50 #include "wm_event_system.h"
51
52 #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
53
54 static void wm_operatortype_free_macro(wmOperatorType *ot);
55
56 /* -------------------------------------------------------------------- */
57 /** \name Operator Type Registry
58 * \{ */
59
60 static GHash *global_ops_hash = NULL;
61 /** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */
62 static int ot_prop_basic_count = -1;
63
WM_operatortype_find(const char * idname,bool quiet)64 wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
65 {
66 if (idname[0]) {
67 wmOperatorType *ot;
68
69 /* needed to support python style names without the _OT_ syntax */
70 char idname_bl[OP_MAX_TYPENAME];
71 WM_operator_bl_idname(idname_bl, idname);
72
73 ot = BLI_ghash_lookup(global_ops_hash, idname_bl);
74 if (ot) {
75 return ot;
76 }
77
78 if (!quiet) {
79 CLOG_INFO(
80 WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname);
81 }
82 }
83 else {
84 if (!quiet) {
85 CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator");
86 }
87 }
88
89 return NULL;
90 }
91
92 /* caller must free */
WM_operatortype_iter(GHashIterator * ghi)93 void WM_operatortype_iter(GHashIterator *ghi)
94 {
95 BLI_ghashIterator_init(ghi, global_ops_hash);
96 }
97
98 /** \name Operator Type Append
99 * \{ */
100
wm_operatortype_append__begin(void)101 static wmOperatorType *wm_operatortype_append__begin(void)
102 {
103 wmOperatorType *ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
104
105 BLI_assert(ot_prop_basic_count == -1);
106
107 ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
108 RNA_def_struct_property_tags(ot->srna, rna_enum_operator_property_tags);
109 /* Set the default i18n context now, so that opfunc can redefine it if needed! */
110 RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
111 ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
112
113 return ot;
114 }
wm_operatortype_append__end(wmOperatorType * ot)115 static void wm_operatortype_append__end(wmOperatorType *ot)
116 {
117 if (ot->name == NULL) {
118 CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
119 }
120 BLI_assert((ot->description == NULL) || (ot->description[0]));
121
122 /* Allow calling _begin without _end in operatortype creation. */
123 WM_operatortype_props_advanced_end(ot);
124
125 /* XXX All ops should have a description but for now allow them not to. */
126 RNA_def_struct_ui_text(
127 ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
128 RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
129
130 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
131 }
132
133 /* all ops in 1 list (for time being... needs evaluation later) */
WM_operatortype_append(void (* opfunc)(wmOperatorType *))134 void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
135 {
136 wmOperatorType *ot = wm_operatortype_append__begin();
137 opfunc(ot);
138 wm_operatortype_append__end(ot);
139 }
140
WM_operatortype_append_ptr(void (* opfunc)(wmOperatorType *,void *),void * userdata)141 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
142 {
143 wmOperatorType *ot = wm_operatortype_append__begin();
144 opfunc(ot, userdata);
145 wm_operatortype_append__end(ot);
146 }
147
148 /** \} */
149
150 /* called on initialize WM_exit() */
WM_operatortype_remove_ptr(wmOperatorType * ot)151 void WM_operatortype_remove_ptr(wmOperatorType *ot)
152 {
153 BLI_assert(ot == WM_operatortype_find(ot->idname, false));
154
155 RNA_struct_free(&BLENDER_RNA, ot->srna);
156
157 if (ot->last_properties) {
158 IDP_FreeProperty(ot->last_properties);
159 }
160
161 if (ot->macro.first) {
162 wm_operatortype_free_macro(ot);
163 }
164
165 BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
166
167 WM_keyconfig_update_operatortype();
168
169 MEM_freeN(ot);
170 }
171
WM_operatortype_remove(const char * idname)172 bool WM_operatortype_remove(const char *idname)
173 {
174 wmOperatorType *ot = WM_operatortype_find(idname, 0);
175
176 if (ot == NULL) {
177 return false;
178 }
179
180 WM_operatortype_remove_ptr(ot);
181
182 return true;
183 }
184
185 /* called on initialize WM_init() */
wm_operatortype_init(void)186 void wm_operatortype_init(void)
187 {
188 /* reserve size is set based on blender default setup */
189 global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);
190 }
191
operatortype_ghash_free_cb(wmOperatorType * ot)192 static void operatortype_ghash_free_cb(wmOperatorType *ot)
193 {
194 if (ot->last_properties) {
195 IDP_FreeProperty(ot->last_properties);
196 }
197
198 if (ot->macro.first) {
199 wm_operatortype_free_macro(ot);
200 }
201
202 if (ot->rna_ext.srna) {
203 /* python operator, allocs own string */
204 MEM_freeN((void *)ot->idname);
205 }
206
207 MEM_freeN(ot);
208 }
209
wm_operatortype_free(void)210 void wm_operatortype_free(void)
211 {
212 BLI_ghash_free(global_ops_hash, NULL, (GHashValFreeFP)operatortype_ghash_free_cb);
213 global_ops_hash = NULL;
214 }
215
216 /**
217 * Tag all operator-properties of \a ot defined after calling this, until
218 * the next #WM_operatortype_props_advanced_end call (if available), with
219 * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
220 *
221 * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
222 * all calls after the first one are ignored. Meaning all proprieties defined after the
223 * first call are tagged as advanced.
224 *
225 * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
226 * called for all operators during registration (see #wm_operatortype_append__end).
227 */
WM_operatortype_props_advanced_begin(wmOperatorType * ot)228 void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
229 {
230 if (ot_prop_basic_count == -1) {
231 /* Don't do anything if _begin was called before, but not _end */
232 ot_prop_basic_count = RNA_struct_count_properties(ot->srna);
233 }
234 }
235
236 /**
237 * Tags all operator-properties of \a ot defined since the first
238 * #WM_operatortype_props_advanced_begin call,
239 * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
240 *
241 * \note This is called for all operators during registration (see #wm_operatortype_append__end).
242 * So it does not need to be explicitly called in operator-type definition.
243 */
WM_operatortype_props_advanced_end(wmOperatorType * ot)244 void WM_operatortype_props_advanced_end(wmOperatorType *ot)
245 {
246 PointerRNA struct_ptr;
247 int counter = 0;
248
249 if (ot_prop_basic_count == -1) {
250 /* WM_operatortype_props_advanced_begin was not called. Don't do anything. */
251 return;
252 }
253
254 RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr);
255
256 RNA_STRUCT_BEGIN (&struct_ptr, prop) {
257 counter++;
258 if (counter > ot_prop_basic_count) {
259 WM_operatortype_prop_tag(prop, OP_PROP_TAG_ADVANCED);
260 }
261 }
262 RNA_STRUCT_END;
263
264 ot_prop_basic_count = -1;
265 }
266
267 /**
268 * Remove memory of all previously executed tools.
269 */
WM_operatortype_last_properties_clear_all(void)270 void WM_operatortype_last_properties_clear_all(void)
271 {
272 GHashIterator iter;
273
274 for (WM_operatortype_iter(&iter); (!BLI_ghashIterator_done(&iter));
275 (BLI_ghashIterator_step(&iter))) {
276 wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
277
278 if (ot->last_properties) {
279 IDP_FreeProperty(ot->last_properties);
280 ot->last_properties = NULL;
281 }
282 }
283 }
284
285 /** \} */
286
287 /* -------------------------------------------------------------------- */
288 /** \name Operator Macro Type
289 * \{ */
290
291 typedef struct {
292 int retval;
293 } MacroData;
294
wm_macro_start(wmOperator * op)295 static void wm_macro_start(wmOperator *op)
296 {
297 if (op->customdata == NULL) {
298 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData");
299 }
300 }
301
wm_macro_end(wmOperator * op,int retval)302 static int wm_macro_end(wmOperator *op, int retval)
303 {
304 if (retval & OPERATOR_CANCELLED) {
305 MacroData *md = op->customdata;
306
307 if (md->retval & OPERATOR_FINISHED) {
308 retval |= OPERATOR_FINISHED;
309 retval &= ~OPERATOR_CANCELLED;
310 }
311 }
312
313 /* if modal is ending, free custom data */
314 if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
315 if (op->customdata) {
316 MEM_freeN(op->customdata);
317 op->customdata = NULL;
318 }
319 }
320
321 return retval;
322 }
323
324 /* macro exec only runs exec calls */
wm_macro_exec(bContext * C,wmOperator * op)325 static int wm_macro_exec(bContext *C, wmOperator *op)
326 {
327 wmOperator *opm;
328 int retval = OPERATOR_FINISHED;
329
330 wm_macro_start(op);
331
332 for (opm = op->macro.first; opm; opm = opm->next) {
333
334 if (opm->type->exec) {
335 retval = opm->type->exec(C, opm);
336 OPERATOR_RETVAL_CHECK(retval);
337
338 if (retval & OPERATOR_FINISHED) {
339 MacroData *md = op->customdata;
340 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
341 }
342 else {
343 break; /* operator didn't finish, end macro */
344 }
345 }
346 else {
347 CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
348 }
349 }
350
351 return wm_macro_end(op, retval);
352 }
353
wm_macro_invoke_internal(bContext * C,wmOperator * op,const wmEvent * event,wmOperator * opm)354 static int wm_macro_invoke_internal(bContext *C,
355 wmOperator *op,
356 const wmEvent *event,
357 wmOperator *opm)
358 {
359 int retval = OPERATOR_FINISHED;
360
361 /* start from operator received as argument */
362 for (; opm; opm = opm->next) {
363 if (opm->type->invoke) {
364 retval = opm->type->invoke(C, opm, event);
365 }
366 else if (opm->type->exec) {
367 retval = opm->type->exec(C, opm);
368 }
369
370 OPERATOR_RETVAL_CHECK(retval);
371
372 BLI_movelisttolist(&op->reports->list, &opm->reports->list);
373
374 if (retval & OPERATOR_FINISHED) {
375 MacroData *md = op->customdata;
376 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
377 }
378 else {
379 break; /* operator didn't finish, end macro */
380 }
381 }
382
383 return wm_macro_end(op, retval);
384 }
385
wm_macro_invoke(bContext * C,wmOperator * op,const wmEvent * event)386 static int wm_macro_invoke(bContext *C, wmOperator *op, const wmEvent *event)
387 {
388 wm_macro_start(op);
389 return wm_macro_invoke_internal(C, op, event, op->macro.first);
390 }
391
wm_macro_modal(bContext * C,wmOperator * op,const wmEvent * event)392 static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
393 {
394 wmOperator *opm = op->opm;
395 int retval = OPERATOR_FINISHED;
396
397 if (opm == NULL) {
398 CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()");
399 }
400 else {
401 retval = opm->type->modal(C, opm, event);
402 OPERATOR_RETVAL_CHECK(retval);
403
404 /* if we're halfway through using a tool and cancel it, clear the options T37149. */
405 if (retval & OPERATOR_CANCELLED) {
406 WM_operator_properties_clear(opm->ptr);
407 }
408
409 /* if this one is done but it's not the last operator in the macro */
410 if ((retval & OPERATOR_FINISHED) && opm->next) {
411 MacroData *md = op->customdata;
412
413 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
414
415 retval = wm_macro_invoke_internal(C, op, event, opm->next);
416
417 /* if new operator is modal and also added its own handler */
418 if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) {
419 wmWindow *win = CTX_wm_window(C);
420 wmEventHandler_Op *handler;
421
422 handler = BLI_findptr(&win->modalhandlers, op, offsetof(wmEventHandler_Op, op));
423 if (handler) {
424 BLI_remlink(&win->modalhandlers, handler);
425 wm_event_free_handler(&handler->head);
426 }
427
428 /* if operator is blocking, grab cursor
429 * This may end up grabbing twice, but we don't care.
430 * */
431 if (op->opm->type->flag & OPTYPE_BLOCKING) {
432 int bounds[4] = {-1, -1, -1, -1};
433 int wrap = WM_CURSOR_WRAP_NONE;
434
435 if ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) ||
436 (op->opm->type->flag & OPTYPE_GRAB_CURSOR_XY)) {
437 wrap = WM_CURSOR_WRAP_XY;
438 }
439 else if (op->opm->type->flag & OPTYPE_GRAB_CURSOR_X) {
440 wrap = WM_CURSOR_WRAP_X;
441 }
442 else if (op->opm->type->flag & OPTYPE_GRAB_CURSOR_Y) {
443 wrap = WM_CURSOR_WRAP_Y;
444 }
445
446 if (wrap) {
447 ARegion *region = CTX_wm_region(C);
448 if (region) {
449 bounds[0] = region->winrct.xmin;
450 bounds[1] = region->winrct.ymax;
451 bounds[2] = region->winrct.xmax;
452 bounds[3] = region->winrct.ymin;
453 }
454 }
455
456 WM_cursor_grab_enable(win, wrap, false, bounds);
457 }
458 }
459 }
460 }
461
462 return wm_macro_end(op, retval);
463 }
464
wm_macro_cancel(bContext * C,wmOperator * op)465 static void wm_macro_cancel(bContext *C, wmOperator *op)
466 {
467 /* call cancel on the current modal operator, if any */
468 if (op->opm && op->opm->type->cancel) {
469 op->opm->type->cancel(C, op->opm);
470 }
471
472 wm_macro_end(op, OPERATOR_CANCELLED);
473 }
474
475 /* Names have to be static for now */
WM_operatortype_append_macro(const char * idname,const char * name,const char * description,int flag)476 wmOperatorType *WM_operatortype_append_macro(const char *idname,
477 const char *name,
478 const char *description,
479 int flag)
480 {
481 wmOperatorType *ot;
482 const char *i18n_context;
483
484 if (WM_operatortype_find(idname, true)) {
485 CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname);
486 return NULL;
487 }
488
489 ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
490 ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
491
492 ot->idname = idname;
493 ot->name = name;
494 ot->description = description;
495 ot->flag = OPTYPE_MACRO | flag;
496
497 ot->exec = wm_macro_exec;
498 ot->invoke = wm_macro_invoke;
499 ot->modal = wm_macro_modal;
500 ot->cancel = wm_macro_cancel;
501 ot->poll = NULL;
502
503 if (!ot->description) {
504 /* XXX All ops should have a description but for now allow them not to. */
505 ot->description = UNDOCUMENTED_OPERATOR_TIP;
506 }
507
508 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
509 RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
510 /* Use i18n context from rna_ext.srna if possible (py operators). */
511 i18n_context = ot->rna_ext.srna ? RNA_struct_translation_context(ot->rna_ext.srna) :
512 BLT_I18NCONTEXT_OPERATOR_DEFAULT;
513 RNA_def_struct_translation_context(ot->srna, i18n_context);
514 ot->translation_context = i18n_context;
515
516 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
517
518 return ot;
519 }
520
WM_operatortype_append_macro_ptr(void (* opfunc)(wmOperatorType *,void *),void * userdata)521 void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
522 {
523 wmOperatorType *ot;
524
525 ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
526 ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
527
528 ot->flag = OPTYPE_MACRO;
529 ot->exec = wm_macro_exec;
530 ot->invoke = wm_macro_invoke;
531 ot->modal = wm_macro_modal;
532 ot->cancel = wm_macro_cancel;
533 ot->poll = NULL;
534
535 if (!ot->description) {
536 ot->description = UNDOCUMENTED_OPERATOR_TIP;
537 }
538
539 /* Set the default i18n context now, so that opfunc can redefine it if needed! */
540 RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
541 ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
542 opfunc(ot, userdata);
543
544 RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
545 RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
546
547 BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
548 }
549
WM_operatortype_macro_define(wmOperatorType * ot,const char * idname)550 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
551 {
552 wmOperatorTypeMacro *otmacro = MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
553
554 BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
555
556 /* do this on first use, since operatordefinitions might have been not done yet */
557 WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname);
558 WM_operator_properties_sanitize(otmacro->ptr, 1);
559
560 BLI_addtail(&ot->macro, otmacro);
561
562 {
563 /* operator should always be found but in the event its not. don't segfault */
564 wmOperatorType *otsub = WM_operatortype_find(idname, 0);
565 if (otsub) {
566 RNA_def_pointer_runtime(
567 ot->srna, otsub->idname, otsub->srna, otsub->name, otsub->description);
568 }
569 }
570
571 return otmacro;
572 }
573
wm_operatortype_free_macro(wmOperatorType * ot)574 static void wm_operatortype_free_macro(wmOperatorType *ot)
575 {
576 wmOperatorTypeMacro *otmacro;
577
578 for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
579 if (otmacro->ptr) {
580 WM_operator_properties_free(otmacro->ptr);
581 MEM_freeN(otmacro->ptr);
582 }
583 }
584 BLI_freelistN(&ot->macro);
585 }
586
WM_operatortype_name(struct wmOperatorType * ot,struct PointerRNA * properties)587 const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
588 {
589 const char *name = NULL;
590
591 if (ot->get_name && properties) {
592 name = ot->get_name(ot, properties);
593 }
594
595 return (name && name[0]) ? name : RNA_struct_ui_name(ot->srna);
596 }
597
WM_operatortype_description(struct bContext * C,struct wmOperatorType * ot,struct PointerRNA * properties)598 char *WM_operatortype_description(struct bContext *C,
599 struct wmOperatorType *ot,
600 struct PointerRNA *properties)
601 {
602 if (ot->get_description && properties) {
603 char *description = ot->get_description(C, ot, properties);
604
605 if (description) {
606 if (description[0]) {
607 return description;
608 }
609 MEM_freeN(description);
610 }
611 }
612
613 const char *info = RNA_struct_ui_description(ot->srna);
614 if (info && info[0]) {
615 return BLI_strdup(info);
616 }
617 return NULL;
618 }
619
620 /**
621 * Use when we want a label, preferring the description.
622 */
WM_operatortype_description_or_name(struct bContext * C,struct wmOperatorType * ot,struct PointerRNA * properties)623 char *WM_operatortype_description_or_name(struct bContext *C,
624 struct wmOperatorType *ot,
625 struct PointerRNA *properties)
626 {
627 char *text = WM_operatortype_description(C, ot, properties);
628 if (text == NULL) {
629 const char *text_orig = WM_operatortype_name(ot, properties);
630 if (text_orig != NULL) {
631 text = BLI_strdup(text_orig);
632 }
633 }
634 return text;
635 }
636
637 /** \} */
638