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