Cleanup in BLO API: rename 'append' funcs to 'link', since none do append, but only...
[blender-staging.git] / source / blender / windowmanager / intern / wm_operators.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_operators.c
28  *  \ingroup wm
29  *
30  * Functions for dealing with wmOperator, adding, removing, calling
31  * as well as some generic operators and shared operator properties.
32  */
33
34
35 #include <float.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <stddef.h>
40 #include <assert.h>
41 #include <errno.h>
42
43 #ifdef WIN32
44 #  include "GHOST_C-api.h"
45 #endif
46
47 #include "MEM_guardedalloc.h"
48
49 #include "DNA_ID.h"
50 #include "DNA_object_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_userdef_types.h"
54 #include "DNA_windowmanager_types.h"
55 #include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
56
57 #include "BLT_translation.h"
58
59 #include "PIL_time.h"
60
61 #include "BLI_blenlib.h"
62 #include "BLI_dial.h"
63 #include "BLI_dynstr.h" /*for WM_operator_pystring */
64 #include "BLI_linklist_stack.h"
65 #include "BLI_math.h"
66 #include "BLI_utildefines.h"
67 #include "BLI_ghash.h"
68
69 #include "BLO_readfile.h"
70
71 #include "BKE_appdir.h"
72 #include "BKE_autoexec.h"
73 #include "BKE_blender.h"
74 #include "BKE_brush.h"
75 #include "BKE_context.h"
76 #include "BKE_depsgraph.h"
77 #include "BKE_icons.h"
78 #include "BKE_idprop.h"
79 #include "BKE_image.h"
80 #include "BKE_library.h"
81 #include "BKE_library_query.h"
82 #include "BKE_global.h"
83 #include "BKE_main.h"
84 #include "BKE_material.h"
85 #include "BKE_report.h"
86 #include "BKE_scene.h"
87 #include "BKE_screen.h" /* BKE_ST_MAXNAME */
88 #include "BKE_unit.h"
89 #include "BKE_utildefines.h"
90
91 #include "BKE_idcode.h"
92
93 #include "BIF_glutil.h" /* for paint cursor */
94 #include "BLF_api.h"
95
96 #include "IMB_colormanagement.h"
97 #include "IMB_imbuf_types.h"
98 #include "IMB_imbuf.h"
99
100 #include "ED_numinput.h"
101 #include "ED_screen.h"
102 #include "ED_util.h"
103 #include "ED_view3d.h"
104
105 #include "GPU_material.h"
106
107 #include "RNA_access.h"
108 #include "RNA_define.h"
109 #include "RNA_enum_types.h"
110
111 #include "UI_interface.h"
112 #include "UI_interface_icons.h"
113 #include "UI_resources.h"
114
115 #include "WM_api.h"
116 #include "WM_types.h"
117
118 #include "wm.h"
119 #include "wm_draw.h"
120 #include "wm_event_system.h"
121 #include "wm_event_types.h"
122 #include "wm_files.h"
123 #include "wm_subwindow.h"
124 #include "wm_window.h"
125
126 static GHash *global_ops_hash = NULL;
127
128 #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
129
130 /* ************ operator API, exported ********** */
131
132
133 wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
134 {
135         if (idname[0]) {
136                 wmOperatorType *ot;
137
138                 /* needed to support python style names without the _OT_ syntax */
139                 char idname_bl[OP_MAX_TYPENAME];
140                 WM_operator_bl_idname(idname_bl, idname);
141
142                 ot = BLI_ghash_lookup(global_ops_hash, idname_bl);
143                 if (ot) {
144                         return ot;
145                 }
146
147                 if (!quiet) {
148                         printf("search for unknown operator '%s', '%s'\n", idname_bl, idname);
149                 }
150         }
151         else {
152                 if (!quiet) {
153                         printf("search for empty operator\n");
154                 }
155         }
156
157         return NULL;
158 }
159
160 /* caller must free */
161 void WM_operatortype_iter(GHashIterator *ghi)
162 {
163         BLI_ghashIterator_init(ghi, global_ops_hash);
164 }
165
166 /* all ops in 1 list (for time being... needs evaluation later) */
167 void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
168 {
169         wmOperatorType *ot;
170         
171         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
172         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
173         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
174         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
175         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
176         opfunc(ot);
177
178         if (ot->name == NULL) {
179                 fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
180                 ot->name = N_("Dummy Name");
181         }
182
183         /* XXX All ops should have a description but for now allow them not to. */
184         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
185         RNA_def_struct_identifier(ot->srna, ot->idname);
186
187         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
188 }
189
190 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
191 {
192         wmOperatorType *ot;
193
194         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
195         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
196         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
197         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
198         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
199         opfunc(ot, userdata);
200         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
201         RNA_def_struct_identifier(ot->srna, ot->idname);
202
203         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
204 }
205
206 /* ********************* macro operator ******************** */
207
208 typedef struct {
209         int retval;
210 } MacroData;
211
212 static void wm_macro_start(wmOperator *op)
213 {
214         if (op->customdata == NULL) {
215                 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData");
216         }
217 }
218
219 static int wm_macro_end(wmOperator *op, int retval)
220 {
221         if (retval & OPERATOR_CANCELLED) {
222                 MacroData *md = op->customdata;
223
224                 if (md->retval & OPERATOR_FINISHED) {
225                         retval |= OPERATOR_FINISHED;
226                         retval &= ~OPERATOR_CANCELLED;
227                 }
228         }
229
230         /* if modal is ending, free custom data */
231         if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
232                 if (op->customdata) {
233                         MEM_freeN(op->customdata);
234                         op->customdata = NULL;
235                 }
236         }
237
238         return retval;
239 }
240
241 /* macro exec only runs exec calls */
242 static int wm_macro_exec(bContext *C, wmOperator *op)
243 {
244         wmOperator *opm;
245         int retval = OPERATOR_FINISHED;
246         
247         wm_macro_start(op);
248
249         for (opm = op->macro.first; opm; opm = opm->next) {
250                 
251                 if (opm->type->exec) {
252                         retval = opm->type->exec(C, opm);
253                         OPERATOR_RETVAL_CHECK(retval);
254                 
255                         if (retval & OPERATOR_FINISHED) {
256                                 MacroData *md = op->customdata;
257                                 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
258                         }
259                         else {
260                                 break; /* operator didn't finish, end macro */
261                         }
262                 }
263                 else {
264                         printf("%s: '%s' cant exec macro\n", __func__, opm->type->idname);
265                 }
266         }
267         
268         return wm_macro_end(op, retval);
269 }
270
271 static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent *event, wmOperator *opm)
272 {
273         int retval = OPERATOR_FINISHED;
274
275         /* start from operator received as argument */
276         for (; opm; opm = opm->next) {
277                 if (opm->type->invoke)
278                         retval = opm->type->invoke(C, opm, event);
279                 else if (opm->type->exec)
280                         retval = opm->type->exec(C, opm);
281
282                 OPERATOR_RETVAL_CHECK(retval);
283
284                 BLI_movelisttolist(&op->reports->list, &opm->reports->list);
285                 
286                 if (retval & OPERATOR_FINISHED) {
287                         MacroData *md = op->customdata;
288                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
289                 }
290                 else {
291                         break; /* operator didn't finish, end macro */
292                 }
293         }
294
295         return wm_macro_end(op, retval);
296 }
297
298 static int wm_macro_invoke(bContext *C, wmOperator *op, const wmEvent *event)
299 {
300         wm_macro_start(op);
301         return wm_macro_invoke_internal(C, op, event, op->macro.first);
302 }
303
304 static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
305 {
306         wmOperator *opm = op->opm;
307         int retval = OPERATOR_FINISHED;
308         
309         if (opm == NULL)
310                 printf("%s: macro error, calling NULL modal()\n", __func__);
311         else {
312                 retval = opm->type->modal(C, opm, event);
313                 OPERATOR_RETVAL_CHECK(retval);
314
315                 /* if we're halfway through using a tool and cancel it, clear the options [#37149] */
316                 if (retval & OPERATOR_CANCELLED) {
317                         WM_operator_properties_clear(opm->ptr);
318                 }
319
320                 /* if this one is done but it's not the last operator in the macro */
321                 if ((retval & OPERATOR_FINISHED) && opm->next) {
322                         MacroData *md = op->customdata;
323
324                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
325
326                         retval = wm_macro_invoke_internal(C, op, event, opm->next);
327
328                         /* if new operator is modal and also added its own handler */
329                         if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) {
330                                 wmWindow *win = CTX_wm_window(C);
331                                 wmEventHandler *handler;
332
333                                 handler = BLI_findptr(&win->modalhandlers, op, offsetof(wmEventHandler, op));
334                                 if (handler) {
335                                         BLI_remlink(&win->modalhandlers, handler);
336                                         wm_event_free_handler(handler);
337                                 }
338
339                                 /* if operator is blocking, grab cursor
340                                  * This may end up grabbing twice, but we don't care.
341                                  * */
342                                 if (op->opm->type->flag & OPTYPE_BLOCKING) {
343                                         int bounds[4] = {-1, -1, -1, -1};
344                                         const bool wrap = (
345                                                 (U.uiflag & USER_CONTINUOUS_MOUSE) &&
346                                                 ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR)));
347
348                                         if (wrap) {
349                                                 ARegion *ar = CTX_wm_region(C);
350                                                 if (ar) {
351                                                         bounds[0] = ar->winrct.xmin;
352                                                         bounds[1] = ar->winrct.ymax;
353                                                         bounds[2] = ar->winrct.xmax;
354                                                         bounds[3] = ar->winrct.ymin;
355                                                 }
356                                         }
357
358                                         WM_cursor_grab_enable(win, wrap, false, bounds);
359                                 }
360                         }
361                 }
362         }
363
364         return wm_macro_end(op, retval);
365 }
366
367 static void wm_macro_cancel(bContext *C, wmOperator *op)
368 {
369         /* call cancel on the current modal operator, if any */
370         if (op->opm && op->opm->type->cancel) {
371                 op->opm->type->cancel(C, op->opm);
372         }
373
374         wm_macro_end(op, OPERATOR_CANCELLED);
375 }
376
377 /* Names have to be static for now */
378 wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag)
379 {
380         wmOperatorType *ot;
381         const char *i18n_context;
382         
383         if (WM_operatortype_find(idname, true)) {
384                 printf("%s: macro error: operator %s exists\n", __func__, idname);
385                 return NULL;
386         }
387         
388         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
389         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
390         
391         ot->idname = idname;
392         ot->name = name;
393         ot->description = description;
394         ot->flag = OPTYPE_MACRO | flag;
395         
396         ot->exec = wm_macro_exec;
397         ot->invoke = wm_macro_invoke;
398         ot->modal = wm_macro_modal;
399         ot->cancel = wm_macro_cancel;
400         ot->poll = NULL;
401
402         if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */
403                 ot->description = UNDOCUMENTED_OPERATOR_TIP;
404         
405         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
406         RNA_def_struct_identifier(ot->srna, ot->idname);
407         /* Use i18n context from ext.srna if possible (py operators). */
408         i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
409         RNA_def_struct_translation_context(ot->srna, i18n_context);
410         ot->translation_context = i18n_context;
411
412         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
413
414         return ot;
415 }
416
417 void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
418 {
419         wmOperatorType *ot;
420
421         ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
422         ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
423
424         ot->flag = OPTYPE_MACRO;
425         ot->exec = wm_macro_exec;
426         ot->invoke = wm_macro_invoke;
427         ot->modal = wm_macro_modal;
428         ot->cancel = wm_macro_cancel;
429         ot->poll = NULL;
430
431         if (!ot->description)
432                 ot->description = UNDOCUMENTED_OPERATOR_TIP;
433
434         /* Set the default i18n context now, so that opfunc can redefine it if needed! */
435         RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
436         ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
437         opfunc(ot, userdata);
438
439         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
440         RNA_def_struct_identifier(ot->srna, ot->idname);
441
442         BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
443 }
444
445 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
446 {
447         wmOperatorTypeMacro *otmacro = MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
448
449         BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
450
451         /* do this on first use, since operatordefinitions might have been not done yet */
452         WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname);
453         WM_operator_properties_sanitize(otmacro->ptr, 1);
454
455         BLI_addtail(&ot->macro, otmacro);
456
457         {
458                 /* operator should always be found but in the event its not. don't segfault */
459                 wmOperatorType *otsub = WM_operatortype_find(idname, 0);
460                 if (otsub) {
461                         RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna,
462                                                 otsub->name, otsub->description);
463                 }
464         }
465
466         return otmacro;
467 }
468
469 static void wm_operatortype_free_macro(wmOperatorType *ot)
470 {
471         wmOperatorTypeMacro *otmacro;
472         
473         for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
474                 if (otmacro->ptr) {
475                         WM_operator_properties_free(otmacro->ptr);
476                         MEM_freeN(otmacro->ptr);
477                 }
478         }
479         BLI_freelistN(&ot->macro);
480 }
481
482 void WM_operatortype_remove_ptr(wmOperatorType *ot)
483 {
484         BLI_assert(ot == WM_operatortype_find(ot->idname, false));
485
486         RNA_struct_free(&BLENDER_RNA, ot->srna);
487
488         if (ot->last_properties) {
489                 IDP_FreeProperty(ot->last_properties);
490                 MEM_freeN(ot->last_properties);
491         }
492
493         if (ot->macro.first)
494                 wm_operatortype_free_macro(ot);
495
496         BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL);
497
498         WM_keyconfig_update_operatortype();
499
500         MEM_freeN(ot);
501 }
502
503 bool WM_operatortype_remove(const char *idname)
504 {
505         wmOperatorType *ot = WM_operatortype_find(idname, 0);
506
507         if (ot == NULL)
508                 return false;
509
510         WM_operatortype_remove_ptr(ot);
511
512         return true;
513 }
514
515 /**
516  * Remove memory of all previously executed tools.
517  */
518 void WM_operatortype_last_properties_clear_all(void)
519 {
520         GHashIterator iter;
521
522         for (WM_operatortype_iter(&iter);
523              (!BLI_ghashIterator_done(&iter));
524              (BLI_ghashIterator_step(&iter)))
525         {
526                 wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
527
528                 if (ot->last_properties) {
529                         IDP_FreeProperty(ot->last_properties);
530                         MEM_freeN(ot->last_properties);
531                         ot->last_properties = NULL;
532                 }
533         }
534 }
535
536 /* SOME_OT_op -> some.op */
537 void WM_operator_py_idname(char *to, const char *from)
538 {
539         const char *sep = strstr(from, "_OT_");
540         if (sep) {
541                 int ofs = (sep - from);
542                 
543                 /* note, we use ascii tolower instead of system tolower, because the
544                  * latter depends on the locale, and can lead to idname mismatch */
545                 memcpy(to, from, sizeof(char) * ofs);
546                 BLI_str_tolower_ascii(to, ofs);
547
548                 to[ofs] = '.';
549                 BLI_strncpy(to + (ofs + 1), sep + 4, OP_MAX_TYPENAME - (ofs + 1));
550         }
551         else {
552                 /* should not happen but support just in case */
553                 BLI_strncpy(to, from, OP_MAX_TYPENAME);
554         }
555 }
556
557 /* some.op -> SOME_OT_op */
558 void WM_operator_bl_idname(char *to, const char *from)
559 {
560         if (from) {
561                 const char *sep = strchr(from, '.');
562
563                 if (sep) {
564                         int ofs = (sep - from);
565
566                         memcpy(to, from, sizeof(char) * ofs);
567                         BLI_str_toupper_ascii(to, ofs);
568                         strcpy(to + ofs, "_OT_");
569                         strcpy(to + (ofs + 4), sep + 1);
570                 }
571                 else {
572                         /* should not happen but support just in case */
573                         BLI_strncpy(to, from, OP_MAX_TYPENAME);
574                 }
575         }
576         else
577                 to[0] = 0;
578 }
579
580 /**
581  * Print a string representation of the operator, with the args that it runs so python can run it again.
582  *
583  * When calling from an existing wmOperator, better to use simple version:
584  * `WM_operator_pystring(C, op);`
585  *
586  * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators).
587  */
588 char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args,
589                               wmOperatorType *ot, PointerRNA *opptr)
590 {
591         char idname_py[OP_MAX_TYPENAME];
592
593         /* for building the string */
594         DynStr *dynstr = BLI_dynstr_new();
595         char *cstring;
596         char *cstring_args;
597
598         /* arbitrary, but can get huge string with stroke painting otherwise */
599         int max_prop_length = 10;
600
601         WM_operator_py_idname(idname_py, ot->idname);
602         BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py);
603
604         if (op && op->macro.first) {
605                 /* Special handling for macros, else we only get default values in this case... */
606                 wmOperator *opm;
607                 bool first_op = true;
608
609                 opm = macro_args ? op->macro.first : NULL;
610
611                 for (; opm; opm = opm->next) {
612                         PointerRNA *opmptr = opm->ptr;
613                         PointerRNA opmptr_default;
614                         if (opmptr == NULL) {
615                                 WM_operator_properties_create_ptr(&opmptr_default, opm->type);
616                                 opmptr = &opmptr_default;
617                         }
618
619                         cstring_args = RNA_pointer_as_string_id(C, opmptr);
620                         if (first_op) {
621                                 BLI_dynstr_appendf(dynstr, "%s=%s", opm->type->idname, cstring_args);
622                                 first_op = false;
623                         }
624                         else {
625                                 BLI_dynstr_appendf(dynstr, ", %s=%s", opm->type->idname, cstring_args);
626                         }
627                         MEM_freeN(cstring_args);
628
629                         if (opmptr == &opmptr_default) {
630                                 WM_operator_properties_free(&opmptr_default);
631                         }
632                 }
633         }
634         else {
635                 /* only to get the orginal props for comparisons */
636                 PointerRNA opptr_default;
637                 const bool macro_args_test = ot->macro.first ? macro_args : true;
638
639                 if (opptr == NULL) {
640                         WM_operator_properties_create_ptr(&opptr_default, ot);
641                         opptr = &opptr_default;
642                 }
643
644                 cstring_args = RNA_pointer_as_string_keywords(C, opptr, false, all_args, macro_args_test, max_prop_length);
645                 BLI_dynstr_append(dynstr, cstring_args);
646                 MEM_freeN(cstring_args);
647
648                 if (opptr == &opptr_default) {
649                         WM_operator_properties_free(&opptr_default);
650                 }
651         }
652
653         BLI_dynstr_append(dynstr, ")");
654
655         cstring = BLI_dynstr_get_cstring(dynstr);
656         BLI_dynstr_free(dynstr);
657         return cstring;
658 }
659
660 char *WM_operator_pystring(bContext *C, wmOperator *op,
661                            const bool all_args, const bool macro_args)
662 {
663         return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr);
664 }
665
666
667 /**
668  * \return true if the string was shortened
669  */
670 bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
671 {
672         const int str_len = strlen(str);
673         const char *parens_start = strchr(str, '(');
674
675         if (parens_start) {
676                 const int parens_start_pos = parens_start - str;
677                 const char *parens_end = strrchr(parens_start + 1, ')');
678
679                 if (parens_end) {
680                         const int parens_len = parens_end - parens_start;
681
682                         if (parens_len > str_len_max) {
683                                 const char *comma_first = strchr(parens_start, ',');
684
685                                 /* truncate after the first comma */
686                                 if (comma_first) {
687                                         const char end_str[] = " ... )";
688                                         const int end_str_len = sizeof(end_str) - 1;
689
690                                         /* leave a place for the first argument*/
691                                         const int new_str_len = (comma_first - parens_start) + 1;
692
693                                         if (str_len >= new_str_len + parens_start_pos + end_str_len + 1) {
694                                                 /* append " ... )" to the string after the comma */
695                                                 memcpy(str + new_str_len + parens_start_pos, end_str, end_str_len + 1);
696
697                                                 return true;
698                                         }
699                                 }
700                         }
701                 }
702         }
703
704         return false;
705 }
706
707 /* return NULL if no match is found */
708 #if 0
709 static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
710 {
711
712         /* loop over all context items and do 2 checks
713          *
714          * - see if the pointer is in the context.
715          * - see if the pointers ID is in the context.
716          */
717
718         /* don't get from the context store since this is normally set only for the UI and not usable elsewhere */
719         ListBase lb = CTX_data_dir_get_ex(C, false, true, true);
720         LinkData *link;
721
722         const char *member_found = NULL;
723         const char *member_id = NULL;
724
725         char *prop_str = NULL;
726         char *ret = NULL;
727
728
729         for (link = lb.first; link; link = link->next) {
730                 const char *identifier = link->data;
731                 PointerRNA ctx_item_ptr = {{0}} // CTX_data_pointer_get(C, identifier); // XXX, this isnt working
732
733                 if (ctx_item_ptr.type == NULL) {
734                         continue;
735                 }
736
737                 if (ptr->id.data == ctx_item_ptr.id.data) {
738                         if ((ptr->data == ctx_item_ptr.data) &&
739                             (ptr->type == ctx_item_ptr.type))
740                         {
741                                 /* found! */
742                                 member_found = identifier;
743                                 break;
744                         }
745                         else if (RNA_struct_is_ID(ctx_item_ptr.type)) {
746                                 /* we found a reference to this ID,
747                                  * so fallback to it if there is no direct reference */
748                                 member_id = identifier;
749                         }
750                 }
751         }
752
753         if (member_found) {
754                 prop_str = RNA_path_property_py(ptr, prop, index);
755                 if (prop_str) {
756                         ret = BLI_sprintfN("bpy.context.%s.%s", member_found, prop_str);
757                         MEM_freeN(prop_str);
758                 }
759         }
760         else if (member_id) {
761                 prop_str = RNA_path_struct_property_py(ptr, prop, index);
762                 if (prop_str) {
763                         ret = BLI_sprintfN("bpy.context.%s.%s", member_id, prop_str);
764                         MEM_freeN(prop_str);
765                 }
766         }
767
768         BLI_freelistN(&lb);
769
770         return ret;
771 }
772 #else
773
774 /* use hard coded checks for now */
775 static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
776 {
777         const char *member_id = NULL;
778
779         char *prop_str = NULL;
780         char *ret = NULL;
781
782         if (ptr->id.data) {
783
784 #define CTX_TEST_PTR_ID(C, member, idptr) \
785                 { \
786                         const char *ctx_member = member; \
787                         PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \
788                         if (ctx_item_ptr.id.data == idptr) { \
789                                 member_id = ctx_member; \
790                                 break; \
791                         } \
792                 } (void)0
793
794 #define CTX_TEST_PTR_ID_CAST(C, member, member_full, cast, idptr) \
795                 { \
796                         const char *ctx_member = member; \
797                         const char *ctx_member_full = member_full; \
798                         PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \
799                         if (ctx_item_ptr.id.data && cast(ctx_item_ptr.id.data) == idptr) { \
800                                 member_id = ctx_member_full; \
801                                 break; \
802                         } \
803                 } (void)0
804
805 #define CTX_TEST_PTR_DATA_TYPE(C, member, rna_type, rna_ptr, dataptr_cmp) \
806                 { \
807                         const char *ctx_member = member; \
808                         if (RNA_struct_is_a((ptr)->type, &(rna_type)) && (ptr)->data == (dataptr_cmp)) { \
809                                 member_id = ctx_member; \
810                                 break; \
811                         } \
812                 } (void)0
813
814                 switch (GS(((ID *)ptr->id.data)->name)) {
815                         case ID_SCE:
816                         {
817                                 CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
818                                 break;
819                         }
820                         case ID_OB:
821                         {
822                                 CTX_TEST_PTR_ID(C, "object", ptr->id.data);
823                                 break;
824                         }
825                         /* from rna_Main_objects_new */
826                         case OB_DATA_SUPPORT_ID_CASE:
827                         {
828 #define ID_CAST_OBDATA(id_pt) (((Object *)(id_pt))->data)
829                                 CTX_TEST_PTR_ID_CAST(C, "object", "object.data", ID_CAST_OBDATA, ptr->id.data);
830                                 break;
831 #undef ID_CAST_OBDATA
832                         }
833                         case ID_MA:
834                         {
835 #define ID_CAST_OBMATACT(id_pt) (give_current_material(((Object *)id_pt), ((Object *)id_pt)->actcol))
836                                 CTX_TEST_PTR_ID_CAST(C, "object", "object.active_material", ID_CAST_OBMATACT, ptr->id.data);
837                                 break;
838 #undef ID_CAST_OBMATACT
839                         }
840                         case ID_WO:
841                         {
842 #define ID_CAST_SCENEWORLD(id_pt) (((Scene *)(id_pt))->world)
843                                 CTX_TEST_PTR_ID_CAST(C, "scene", "scene.world", ID_CAST_SCENEWORLD, ptr->id.data);
844                                 break;
845 #undef ID_CAST_SCENEWORLD
846                         }
847                         case ID_SCR:
848                         {
849                                 CTX_TEST_PTR_ID(C, "screen", ptr->id.data);
850
851                                 CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C));
852                                 CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
853                                 CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
854
855                                 break;
856                         }
857                 }
858
859                 if (member_id) {
860                         prop_str = RNA_path_struct_property_py(ptr, prop, index);
861                         if (prop_str) {
862                                 ret = BLI_sprintfN("bpy.context.%s.%s", member_id, prop_str);
863                                 MEM_freeN(prop_str);
864                         }
865                 }
866 #undef CTX_TEST_PTR_ID
867 #undef CTX_TEST_PTR_ID_CAST
868         }
869
870         return ret;
871 }
872 #endif
873
874 char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
875 {
876         char *lhs, *rhs, *ret;
877
878         lhs = C ? wm_prop_pystring_from_context(C, ptr, prop, index) : NULL;
879
880         if (lhs == NULL) {
881                 /* fallback to bpy.data.foo[id] if we dont find in the context */
882                 lhs = RNA_path_full_property_py(ptr, prop, index);
883         }
884
885         if (!lhs) {
886                 return NULL;
887         }
888
889         rhs = RNA_property_as_string(C, ptr, prop, index, INT_MAX);
890         if (!rhs) {
891                 MEM_freeN(lhs);
892                 return NULL;
893         }
894
895         ret = BLI_sprintfN("%s = %s", lhs, rhs);
896         MEM_freeN(lhs);
897         MEM_freeN(rhs);
898         return ret;
899 }
900
901 void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
902 {
903         RNA_pointer_create(NULL, ot->srna, NULL, ptr);
904 }
905
906 void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
907 {
908         wmOperatorType *ot = WM_operatortype_find(opstring, 0);
909
910         if (ot)
911                 WM_operator_properties_create_ptr(ptr, ot);
912         else
913                 RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
914 }
915
916 /* similar to the function above except its uses ID properties
917  * used for keymaps and macros */
918 void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
919 {
920         if (*properties == NULL) {
921                 IDPropertyTemplate val = {0};
922                 *properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
923         }
924
925         if (*ptr == NULL) {
926                 *ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
927                 WM_operator_properties_create(*ptr, opstring);
928         }
929
930         (*ptr)->data = *properties;
931
932 }
933
934 void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
935 {
936         RNA_STRUCT_BEGIN (ptr, prop)
937         {
938                 switch (RNA_property_type(prop)) {
939                         case PROP_ENUM:
940                                 if (no_context)
941                                         RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
942                                 else
943                                         RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
944                                 break;
945                         case PROP_POINTER:
946                         {
947                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
948
949                                 /* recurse into operator properties */
950                                 if (RNA_struct_is_a(ptype, &RNA_OperatorProperties)) {
951                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
952                                         WM_operator_properties_sanitize(&opptr, no_context);
953                                 }
954                                 break;
955                         }
956                         default:
957                                 break;
958                 }
959         }
960         RNA_STRUCT_END;
961 }
962
963
964 /** set all props to their default,
965  * \param do_update Only update un-initialized props.
966  *
967  * \note, theres nothing specific to operators here.
968  * this could be made a general function.
969  */
970 bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update)
971 {
972         bool changed = false;
973         RNA_STRUCT_BEGIN (ptr, prop)
974         {
975                 switch (RNA_property_type(prop)) {
976                         case PROP_POINTER:
977                         {
978                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
979                                 if (ptype != &RNA_Struct) {
980                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
981                                         changed |= WM_operator_properties_default(&opptr, do_update);
982                                 }
983                                 break;
984                         }
985                         default:
986                                 if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
987                                         if (RNA_property_reset(ptr, prop, -1)) {
988                                                 changed = true;
989                                         }
990                                 }
991                                 break;
992                 }
993         }
994         RNA_STRUCT_END;
995
996         return changed;
997 }
998
999 /* remove all props without PROP_SKIP_SAVE */
1000 void WM_operator_properties_reset(wmOperator *op)
1001 {
1002         if (op->ptr->data) {
1003                 PropertyRNA *iterprop;
1004                 iterprop = RNA_struct_iterator_property(op->type->srna);
1005
1006                 RNA_PROP_BEGIN (op->ptr, itemptr, iterprop)
1007                 {
1008                         PropertyRNA *prop = itemptr.data;
1009
1010                         if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
1011                                 const char *identifier = RNA_property_identifier(prop);
1012                                 RNA_struct_idprops_unset(op->ptr, identifier);
1013                         }
1014                 }
1015                 RNA_PROP_END;
1016         }
1017 }
1018
1019 void WM_operator_properties_clear(PointerRNA *ptr)
1020 {
1021         IDProperty *properties = ptr->data;
1022
1023         if (properties) {
1024                 IDP_ClearProperty(properties);
1025         }
1026 }
1027
1028 void WM_operator_properties_free(PointerRNA *ptr)
1029 {
1030         IDProperty *properties = ptr->data;
1031
1032         if (properties) {
1033                 IDP_FreeProperty(properties);
1034                 MEM_freeN(properties);
1035                 ptr->data = NULL; /* just in case */
1036         }
1037 }
1038
1039 /* ************ default op callbacks, exported *********** */
1040
1041 void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op)
1042 {
1043         if (op->flag & OP_IS_INVOKE) {
1044                 Scene *scene = CTX_data_scene(C);
1045                 View3D *v3d = CTX_wm_view3d(C);
1046
1047                 const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL);
1048
1049                 /* always run, so the values are initialized,
1050                  * otherwise we may get differ behavior when (dia != 1.0) */
1051                 RNA_STRUCT_BEGIN (op->ptr, prop)
1052                 {
1053                         if (RNA_property_type(prop) == PROP_FLOAT) {
1054                                 PropertySubType pstype = RNA_property_subtype(prop);
1055                                 if (pstype == PROP_DISTANCE) {
1056                                         /* we don't support arrays yet */
1057                                         BLI_assert(RNA_property_array_check(prop) == false);
1058                                         /* initialize */
1059                                         if (!RNA_property_is_set_ex(op->ptr, prop, false)) {
1060                                                 const float value = RNA_property_float_get_default(op->ptr, prop) * dia;
1061                                                 RNA_property_float_set(op->ptr, prop, value);
1062                                         }
1063                                 }
1064                         }
1065                 }
1066                 RNA_STRUCT_END;
1067         }
1068 }
1069
1070 int WM_operator_smooth_viewtx_get(const wmOperator *op)
1071 {
1072         return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0;
1073 }
1074
1075 /* invoke callback, uses enum property named "type" */
1076 int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1077 {
1078         PropertyRNA *prop = op->type->prop;
1079         uiPopupMenu *pup;
1080         uiLayout *layout;
1081
1082         if (prop == NULL) {
1083                 printf("%s: %s has no enum property set\n", __func__, op->type->idname);
1084         }
1085         else if (RNA_property_type(prop) != PROP_ENUM) {
1086                 printf("%s: %s \"%s\" is not an enum property\n",
1087                        __func__, op->type->idname, RNA_property_identifier(prop));
1088         }
1089         else if (RNA_property_is_set(op->ptr, prop)) {
1090                 const int retval = op->type->exec(C, op);
1091                 OPERATOR_RETVAL_CHECK(retval);
1092                 return retval;
1093         }
1094         else {
1095                 pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
1096                 layout = UI_popup_menu_layout(pup);
1097                 /* set this so the default execution context is the same as submenus */
1098                 uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
1099                 uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
1100                 UI_popup_menu_end(C, pup);
1101                 return OPERATOR_INTERFACE;
1102         }
1103
1104         return OPERATOR_CANCELLED;
1105 }
1106
1107
1108 /* generic enum search invoke popup */
1109 static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
1110 {
1111         static char search[256] = "";
1112         wmEvent event;
1113         wmWindow *win = CTX_wm_window(C);
1114         uiBlock *block;
1115         uiBut *but;
1116         wmOperator *op = (wmOperator *)arg_op;
1117
1118         block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
1119         UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
1120
1121 #if 0 /* ok, this isn't so easy... */
1122         uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1123 #endif
1124         but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search),
1125                                   10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
1126
1127         /* fake button, it holds space for search items */
1128         uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
1129
1130         UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
1131
1132         wm_event_init_from_window(win, &event);
1133         event.type = EVT_BUT_OPEN;
1134         event.val = KM_PRESS;
1135         event.customdata = but;
1136         event.customdatafree = false;
1137         wm_event_add(win, &event);
1138
1139         return block;
1140 }
1141
1142
1143 int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1144 {
1145         UI_popup_block_invoke(C, wm_enum_search_menu, op);
1146         return OPERATOR_INTERFACE;
1147 }
1148
1149 /* Can't be used as an invoke directly, needs message arg (can be NULL) */
1150 int WM_operator_confirm_message_ex(bContext *C, wmOperator *op,
1151                                    const char *title, const int icon,
1152                                    const char *message)
1153 {
1154         uiPopupMenu *pup;
1155         uiLayout *layout;
1156         IDProperty *properties = op->ptr->data;
1157
1158         if (properties && properties->len)
1159                 properties = IDP_CopyProperty(op->ptr->data);
1160         else
1161                 properties = NULL;
1162
1163         pup = UI_popup_menu_begin(C, title, icon);
1164         layout = UI_popup_menu_layout(pup);
1165         uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0);
1166         UI_popup_menu_end(C, pup);
1167         
1168         return OPERATOR_INTERFACE;
1169 }
1170
1171 int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message)
1172 {
1173         return WM_operator_confirm_message_ex(C, op, IFACE_("OK?"), ICON_QUESTION, message);
1174 }
1175
1176 int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1177 {
1178         return WM_operator_confirm_message(C, op, NULL);
1179 }
1180
1181 /* op->invoke, opens fileselect if path property not set, otherwise executes */
1182 int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1183 {
1184         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1185                 return WM_operator_call_notest(C, op); /* call exec direct */
1186         }
1187         else {
1188                 WM_event_add_fileselect(C, op);
1189                 return OPERATOR_RUNNING_MODAL;
1190         }
1191 }
1192
1193 bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format)
1194 {
1195         PropertyRNA *prop;
1196         char filepath[FILE_MAX];
1197         /* dont NULL check prop, this can only run on ops with a 'filepath' */
1198         prop = RNA_struct_find_property(op->ptr, "filepath");
1199         RNA_property_string_get(op->ptr, prop, filepath);
1200         if (BKE_image_path_ensure_ext_from_imformat(filepath, im_format)) {
1201                 RNA_property_string_set(op->ptr, prop, filepath);
1202                 /* note, we could check for and update 'filename' here,
1203                  * but so far nothing needs this. */
1204                 return true;
1205         }
1206         return false;
1207 }
1208
1209 /* default properties for fileselect */
1210 void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort)
1211 {
1212         PropertyRNA *prop;
1213
1214         static EnumPropertyItem file_display_items[] = {
1215                 {FILE_DEFAULTDISPLAY, "FILE_DEFAULTDISPLAY", 0, "Default", "Automatically determine display type for files"},
1216                 {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
1217                 {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
1218                 {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
1219                 {0, NULL, 0, NULL, NULL}
1220         };
1221
1222         if (flag & WM_FILESEL_FILEPATH)
1223                 RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
1224
1225         if (flag & WM_FILESEL_DIRECTORY)
1226                 RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Directory of the file");
1227
1228         if (flag & WM_FILESEL_FILENAME)
1229                 RNA_def_string_file_name(ot->srna, "filename", NULL, FILE_MAX, "File Name", "Name of the file");
1230
1231         if (flag & WM_FILESEL_FILES)
1232                 RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
1233
1234         if (action == FILE_SAVE) {
1235                 /* note, this is only used to check if we should highlight the filename area red when the
1236                  * filepath is an existing file. */
1237                 prop = RNA_def_boolean(ot->srna, "check_existing", true, "Check Existing",
1238                                        "Check and warn on overwriting existing files");
1239                 RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1240         }
1241         
1242         prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", "");
1243         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1244         prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & FILE_TYPE_BLENDER_BACKUP) != 0, "Filter .blend files", "");
1245         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1246         prop = RNA_def_boolean(ot->srna, "filter_image", (filter & FILE_TYPE_IMAGE) != 0, "Filter image files", "");
1247         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1248         prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", "");
1249         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1250         prop = RNA_def_boolean(ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", "");
1251         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1252         prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", "");
1253         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1254         prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & FILE_TYPE_SOUND) != 0, "Filter sound files", "");
1255         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1256         prop = RNA_def_boolean(ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", "");
1257         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1258         prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", "");
1259         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1260         prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", "");
1261         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1262         prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
1263         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1264         prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
1265         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1266
1267         prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL,
1268                            "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
1269                            FILE_LOADLIB, FILE_SPECIAL);
1270         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1271
1272         if (flag & WM_FILESEL_RELPATH)
1273                 RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
1274
1275         if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) {
1276                 prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", "");
1277                 RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1278                 prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", "");
1279                 RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1280         }
1281
1282         prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
1283         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1284
1285         prop = RNA_def_enum(ot->srna, "sort_method", file_sort_items, sort, "File sorting mode", "");
1286         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1287
1288 }
1289
1290 static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
1291                                                     const EnumPropertyItem *select_actions)
1292 {
1293         RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
1294 }
1295
1296 void WM_operator_properties_select_action(wmOperatorType *ot, int default_action)
1297 {
1298         static EnumPropertyItem select_actions[] = {
1299                 {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
1300                 {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
1301                 {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
1302                 {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
1303                 {0, NULL, 0, NULL, NULL}
1304         };
1305
1306         wm_operator_properties_select_action_ex(ot, default_action, select_actions);
1307 }
1308
1309 /**
1310  * only SELECT/DESELECT
1311  */
1312 void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default_action)
1313 {
1314         static EnumPropertyItem select_actions[] = {
1315                 {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
1316                 {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
1317                 {0, NULL, 0, NULL, NULL}
1318         };
1319
1320         wm_operator_properties_select_action_ex(ot, default_action, select_actions);
1321 }
1322
1323 /**
1324  * Use for all select random operators.
1325  * Adds properties: percent, seed, action.
1326  */
1327 void WM_operator_properties_select_random(wmOperatorType *ot)
1328 {
1329         RNA_def_float_percentage(
1330                 ot->srna, "percent", 50.f, 0.0f, 100.0f,
1331                 "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
1332         RNA_def_int(
1333                 ot->srna, "seed", 0, 0, INT_MAX,
1334                 "Random Seed", "Seed for the random number generator", 0, 255);
1335
1336         WM_operator_properties_select_action_simple(ot, SEL_SELECT);
1337 }
1338
1339 void WM_operator_properties_select_all(wmOperatorType *ot)
1340 {
1341         WM_operator_properties_select_action(ot, SEL_TOGGLE);
1342 }
1343
1344 void WM_operator_properties_border(wmOperatorType *ot)
1345 {
1346         PropertyRNA *prop;
1347
1348         prop = RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1349         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1350         prop = RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1351         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1352         prop = RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1353         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1354         prop = RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1355         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1356 }
1357
1358 void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
1359 {
1360         rect->xmin = RNA_int_get(op->ptr, "xmin");
1361         rect->ymin = RNA_int_get(op->ptr, "ymin");
1362         rect->xmax = RNA_int_get(op->ptr, "xmax");
1363         rect->ymax = RNA_int_get(op->ptr, "ymax");
1364 }
1365
1366 void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
1367 {
1368         rcti rect_i;
1369         WM_operator_properties_border_to_rcti(op, &rect_i);
1370         BLI_rctf_rcti_copy(rect, &rect_i);
1371 }
1372
1373 void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend)
1374 {
1375         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
1376
1377         WM_operator_properties_border(ot);
1378
1379         if (extend) {
1380                 RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
1381         }
1382 }
1383
1384 void WM_operator_properties_mouse_select(wmOperatorType *ot)
1385 {
1386         PropertyRNA *prop;
1387         
1388         prop = RNA_def_boolean(ot->srna, "extend", false, "Extend",
1389                                "Extend selection instead of deselecting everything first");
1390         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1391         prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Remove from selection");
1392         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1393         prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle Selection", "Toggle the selection");
1394         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1395 }
1396
1397 void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
1398 {
1399         PropertyRNA *prop;
1400
1401         prop = RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX);
1402         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1403         prop = RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX);
1404         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1405         prop = RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX);
1406         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1407         prop = RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX);
1408         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1409         
1410         if (cursor) {
1411                 prop = RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX,
1412                                    "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX);
1413                 RNA_def_property_flag(prop, PROP_HIDDEN);
1414         }
1415 }
1416
1417
1418 /* op->poll */
1419 int WM_operator_winactive(bContext *C)
1420 {
1421         if (CTX_wm_window(C) == NULL) return 0;
1422         return 1;
1423 }
1424
1425 /* return false, if the UI should be disabled */
1426 bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
1427 {
1428         wmWindowManager *wm = CTX_wm_manager(C);
1429         Scene *scene = CTX_data_scene(C);
1430
1431         return !((ED_undo_is_valid(C, idname) == false) || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY));
1432 }
1433
1434 wmOperator *WM_operator_last_redo(const bContext *C)
1435 {
1436         wmWindowManager *wm = CTX_wm_manager(C);
1437         wmOperator *op;
1438
1439         /* only for operators that are registered and did an undo push */
1440         for (op = wm->operators.last; op; op = op->prev)
1441                 if ((op->type->flag & OPTYPE_REGISTER) && (op->type->flag & OPTYPE_UNDO))
1442                         break;
1443
1444         return op;
1445 }
1446
1447 /**
1448  * Use for drag & drop a path or name with operators invoke() function.
1449  */
1450 ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode)
1451 {
1452         ID *id = NULL;
1453         /* check input variables */
1454         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1455                 const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1456                 char path[FILE_MAX];
1457                 bool exists = false;
1458
1459                 RNA_string_get(op->ptr, "filepath", path);
1460
1461                 errno = 0;
1462
1463                 if (idcode == ID_IM) {
1464                         id = (ID *)BKE_image_load_exists_ex(path, &exists);
1465                 }
1466                 else {
1467                         BLI_assert(0);
1468                 }
1469
1470                 if (!id) {
1471                         BKE_reportf(op->reports, RPT_ERROR, "Cannot read %s '%s': %s",
1472                                     BKE_idcode_to_name(idcode), path,
1473                                     errno ? strerror(errno) : TIP_("unsupported format"));
1474                         return NULL;
1475                 }
1476
1477                 if (is_relative_path ) {
1478                         if (exists == false) {
1479                                 Main *bmain = CTX_data_main(C);
1480
1481                                 if (idcode == ID_IM) {
1482                                         BLI_path_rel(((Image *)id)->name, bmain->name);
1483                                 }
1484                                 else {
1485                                         BLI_assert(0);
1486                                 }
1487                         }
1488                 }
1489         }
1490         else if (RNA_struct_property_is_set(op->ptr, "name")) {
1491                 char name[MAX_ID_NAME - 2];
1492                 RNA_string_get(op->ptr, "name", name);
1493                 id = BKE_libblock_find_name(idcode, name);
1494                 if (!id) {
1495                         BKE_reportf(op->reports, RPT_ERROR, "%s '%s' not found",
1496                                     BKE_idcode_to_name(idcode), name);
1497                         return NULL;
1498                 }
1499                 id_us_plus(id);
1500         }
1501
1502         return id;
1503 }
1504
1505 static void wm_block_redo_cb(bContext *C, void *arg_op, int UNUSED(arg_event))
1506 {
1507         wmOperator *op = arg_op;
1508
1509         if (op == WM_operator_last_redo(C)) {
1510                 /* operator was already executed once? undo & repeat */
1511                 ED_undo_operator_repeat(C, op);
1512         }
1513         else {
1514                 /* operator not executed yet, call it */
1515                 ED_undo_push_op(C, op);
1516                 wm_operator_register(C, op);
1517
1518                 WM_operator_repeat(C, op);
1519         }
1520 }
1521
1522 static void wm_block_redo_cancel_cb(bContext *C, void *arg_op)
1523 {
1524         wmOperator *op = arg_op;
1525
1526         /* if operator never got executed, free it */
1527         if (op != WM_operator_last_redo(C))
1528                 WM_operator_free(op);
1529 }
1530
1531 static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
1532 {
1533         wmOperator *op = arg_op;
1534         uiBlock *block;
1535         uiLayout *layout;
1536         uiStyle *style = UI_style_get();
1537         int width = 15 * UI_UNIT_X;
1538
1539         block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
1540         UI_block_flag_disable(block, UI_BLOCK_LOOP);
1541         /* UI_BLOCK_NUMSELECT for layer buttons */
1542         UI_block_flag_enable(block, UI_BLOCK_NUMSELECT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
1543
1544         /* if register is not enabled, the operator gets freed on OPERATOR_FINISHED
1545          * ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */
1546         assert(op->type->flag & OPTYPE_REGISTER);
1547
1548         UI_block_func_handle_set(block, wm_block_redo_cb, arg_op);
1549         layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, 0, style);
1550
1551         if (op == WM_operator_last_redo(C))
1552                 if (!WM_operator_check_ui_enabled(C, op->type->name))
1553                         uiLayoutSetEnabled(layout, false);
1554
1555         if (op->type->flag & OPTYPE_MACRO) {
1556                 for (op = op->macro.first; op; op = op->next) {
1557                         uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
1558                 }
1559         }
1560         else {
1561                 uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
1562         }
1563         
1564         UI_block_bounds_set_popup(block, 4, 0, 0);
1565
1566         return block;
1567 }
1568
1569 typedef struct wmOpPopUp {
1570         wmOperator *op;
1571         int width;
1572         int height;
1573         int free_op;
1574 } wmOpPopUp;
1575
1576 /* Only invoked by OK button in popups created with wm_block_dialog_create() */
1577 static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
1578 {
1579         wmWindowManager *wm = CTX_wm_manager(C);
1580         wmWindow *win = CTX_wm_window(C);
1581
1582         wmOpPopUp *data = arg1;
1583         uiBlock *block = arg2;
1584
1585         WM_operator_call_ex(C, data->op, true);
1586
1587         /* let execute handle freeing it */
1588         //data->free_op = false;
1589         //data->op = NULL;
1590
1591         /* in this case, wm_operator_ui_popup_cancel wont run */
1592         MEM_freeN(data);
1593
1594         /* check window before 'block->handle' incase the
1595          * popup execution closed the window and freed the block. see T44688. */
1596         if (BLI_findindex(&wm->windows, win) != -1) {
1597                 UI_popup_block_close(C, win, block);
1598         }
1599 }
1600
1601 static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
1602 {
1603         wmOperator *op = op_ptr;
1604         if (op->type->check) {
1605                 if (op->type->check(C, op)) {
1606                         /* check for popup and re-layout buttons */
1607                         ARegion *ar_menu = CTX_wm_menu(C);
1608                         if (ar_menu) {
1609                                 ED_region_tag_refresh_ui(ar_menu);
1610                         }
1611                 }
1612         }
1613 }
1614
1615 /* Dialogs are popups that require user verification (click OK) before exec */
1616 static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
1617 {
1618         wmOpPopUp *data = userData;
1619         wmOperator *op = data->op;
1620         uiBlock *block;
1621         uiLayout *layout;
1622         uiStyle *style = UI_style_get();
1623
1624         block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
1625         UI_block_flag_disable(block, UI_BLOCK_LOOP);
1626
1627         /* intentionally don't use 'UI_BLOCK_MOVEMOUSE_QUIT', some dialogues have many items
1628          * where quitting by accident is very annoying */
1629         UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
1630
1631         layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
1632         
1633         UI_block_func_set(block, dialog_check_cb, op, NULL);
1634
1635         uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
1636         
1637         /* clear so the OK button is left alone */
1638         UI_block_func_set(block, NULL, NULL, NULL);
1639
1640         /* new column so as not to interfere with custom layouts [#26436] */
1641         {
1642                 uiBlock *col_block;
1643                 uiLayout *col;
1644                 uiBut *btn;
1645
1646                 col = uiLayoutColumn(layout, false);
1647                 col_block = uiLayoutGetBlock(col);
1648                 /* Create OK button, the callback of which will execute op */
1649                 btn = uiDefBut(col_block, UI_BTYPE_BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1650                 UI_but_func_set(btn, dialog_exec_cb, data, col_block);
1651         }
1652
1653         /* center around the mouse */
1654         UI_block_bounds_set_popup(block, 4, data->width / -2, data->height / 2);
1655
1656         return block;
1657 }
1658
1659 static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
1660 {
1661         wmOpPopUp *data = userData;
1662         wmOperator *op = data->op;
1663         uiBlock *block;
1664         uiLayout *layout;
1665         uiStyle *style = UI_style_get();
1666
1667         block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
1668         UI_block_flag_disable(block, UI_BLOCK_LOOP);
1669         UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
1670
1671         layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
1672
1673         /* since ui is defined the auto-layout args are not used */
1674         uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
1675
1676         UI_block_bounds_set_popup(block, 4, 0, 0);
1677
1678         return block;
1679 }
1680
1681 static void wm_operator_ui_popup_cancel(struct bContext *C, void *userData)
1682 {
1683         wmOpPopUp *data = userData;
1684         wmOperator *op = data->op;
1685
1686         if (op) {
1687                 if (op->type->cancel) {
1688                         op->type->cancel(C, op);
1689                 }
1690
1691                 if (data->free_op) {
1692                         WM_operator_free(op);
1693                 }
1694         }
1695
1696         MEM_freeN(data);
1697 }
1698
1699 static void wm_operator_ui_popup_ok(struct bContext *C, void *arg, int retval)
1700 {
1701         wmOpPopUp *data = arg;
1702         wmOperator *op = data->op;
1703
1704         if (op && retval > 0)
1705                 WM_operator_call_ex(C, op, true);
1706         
1707         MEM_freeN(data);
1708 }
1709
1710 int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
1711 {
1712         wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_ui_popup");
1713         data->op = op;
1714         data->width = width;
1715         data->height = height;
1716         data->free_op = true; /* if this runs and gets registered we may want not to free it */
1717         UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data);
1718         return OPERATOR_RUNNING_MODAL;
1719 }
1720
1721 /**
1722  * For use by #WM_operator_props_popup_call, #WM_operator_props_popup only.
1723  *
1724  * \note operator menu needs undo flag enabled, for redo callback */
1725 static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
1726                                       const bool do_call, const bool do_redo)
1727 {
1728         if ((op->type->flag & OPTYPE_REGISTER) == 0) {
1729                 BKE_reportf(op->reports, RPT_ERROR,
1730                             "Operator '%s' does not have register enabled, incorrect invoke function", op->type->idname);
1731                 return OPERATOR_CANCELLED;
1732         }
1733
1734         if (do_redo) {
1735                 if ((op->type->flag & OPTYPE_UNDO) == 0) {
1736                         BKE_reportf(op->reports, RPT_ERROR,
1737                                     "Operator '%s' does not have undo enabled, incorrect invoke function", op->type->idname);
1738                         return OPERATOR_CANCELLED;
1739                 }
1740         }
1741
1742         /* if we don't have global undo, we can't do undo push for automatic redo,
1743          * so we require manual OK clicking in this popup */
1744         if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
1745                 return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
1746
1747         UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op);
1748
1749         if (do_call)
1750                 wm_block_redo_cb(C, op, 0);
1751
1752         return OPERATOR_RUNNING_MODAL;
1753 }
1754
1755 /**
1756  * Same as #WM_operator_props_popup but don't use operator redo.
1757  * just wraps #WM_operator_props_dialog_popup.
1758  */
1759 int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1760 {
1761         return wm_operator_props_popup_ex(C, op, false, false);
1762 }
1763
1764 /**
1765  * Same as #WM_operator_props_popup but call the operator first,
1766  * This way - the button values correspond to the result of the operator.
1767  * Without this, first access to a button will make the result jump, see T32452.
1768  */
1769 int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1770 {
1771         return wm_operator_props_popup_ex(C, op, true, true);
1772 }
1773
1774 int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1775 {
1776         return wm_operator_props_popup_ex(C, op, false, true);
1777 }
1778
1779 int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int height)
1780 {
1781         wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup");
1782         
1783         data->op = op;
1784         data->width = width;
1785         data->height = height;
1786         data->free_op = true; /* if this runs and gets registered we may want not to free it */
1787
1788         /* op is not executed until popup OK but is clicked */
1789         UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data);
1790
1791         return OPERATOR_RUNNING_MODAL;
1792 }
1793
1794 int WM_operator_redo_popup(bContext *C, wmOperator *op)
1795 {
1796         /* CTX_wm_reports(C) because operator is on stack, not active in event system */
1797         if ((op->type->flag & OPTYPE_REGISTER) == 0) {
1798                 BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
1799                             "Operator redo '%s' does not have register enabled, incorrect invoke function", op->type->idname);
1800                 return OPERATOR_CANCELLED;
1801         }
1802         if (op->type->poll && op->type->poll(C) == 0) {
1803                 BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context", op->type->idname);
1804                 return OPERATOR_CANCELLED;
1805         }
1806         
1807         UI_popup_block_invoke(C, wm_block_create_redo, op);
1808
1809         return OPERATOR_CANCELLED;
1810 }
1811
1812 /* ***************** Debug menu ************************* */
1813
1814 static int wm_debug_menu_exec(bContext *C, wmOperator *op)
1815 {
1816         G.debug_value = RNA_int_get(op->ptr, "debug_value");
1817         ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
1818         WM_event_add_notifier(C, NC_WINDOW, NULL);
1819
1820         return OPERATOR_FINISHED;
1821 }
1822
1823 static int wm_debug_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1824 {
1825         RNA_int_set(op->ptr, "debug_value", G.debug_value);
1826         return WM_operator_props_dialog_popup(C, op, 9 * UI_UNIT_X, UI_UNIT_Y);
1827 }
1828
1829 static void WM_OT_debug_menu(wmOperatorType *ot)
1830 {
1831         ot->name = "Debug Menu";
1832         ot->idname = "WM_OT_debug_menu";
1833         ot->description = "Open a popup to set the debug level";
1834         
1835         ot->invoke = wm_debug_menu_invoke;
1836         ot->exec = wm_debug_menu_exec;
1837         ot->poll = WM_operator_winactive;
1838         
1839         RNA_def_int(ot->srna, "debug_value", 0, SHRT_MIN, SHRT_MAX, "Debug Value", "", -10000, 10000);
1840 }
1841
1842 /* ***************** Operator defaults ************************* */
1843 static int wm_operator_defaults_exec(bContext *C, wmOperator *op)
1844 {
1845         PointerRNA ptr = CTX_data_pointer_get_type(C, "active_operator", &RNA_Operator);
1846
1847         if (!ptr.data) {
1848                 BKE_report(op->reports, RPT_ERROR, "No operator in context");
1849                 return OPERATOR_CANCELLED;
1850         }
1851
1852         WM_operator_properties_reset((wmOperator *)ptr.data);
1853         return OPERATOR_FINISHED;
1854 }
1855
1856 /* used by operator preset menu. pre-2.65 this was a 'Reset' button */
1857 static void WM_OT_operator_defaults(wmOperatorType *ot)
1858 {
1859         ot->name = "Restore Defaults";
1860         ot->idname = "WM_OT_operator_defaults";
1861         ot->description = "Set the active operator to its default values";
1862
1863         ot->exec = wm_operator_defaults_exec;
1864
1865         ot->flag = OPTYPE_INTERNAL;
1866 }
1867
1868 /* ***************** Splash Screen ************************* */
1869
1870 static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
1871 {
1872         wmWindow *win = CTX_wm_window(C);
1873         UI_popup_block_close(C, win, arg_block);
1874 }
1875
1876 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
1877
1878 static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg))
1879 {
1880         ARegion *ar_menu = CTX_wm_menu(C);
1881         ED_region_tag_refresh_ui(ar_menu);
1882 }
1883
1884 static int wm_resource_check_prev(void)
1885 {
1886
1887         const char *res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true);
1888
1889         // if (res) printf("USER: %s\n", res);
1890
1891 #if 0 /* ignore the local folder */
1892         if (res == NULL) {
1893                 /* with a local dir, copying old files isn't useful since local dir get priority for config */
1894                 res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true);
1895         }
1896 #endif
1897
1898         // if (res) printf("LOCAL: %s\n", res);
1899         if (res) {
1900                 return false;
1901         }
1902         else {
1903                 return (BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL);
1904         }
1905 }
1906
1907 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg))
1908 {
1909         uiBlock *block;
1910         uiBut *but;
1911         uiLayout *layout, *split, *col;
1912         uiStyle *style = UI_style_get();
1913         const struct RecentFile *recent;
1914         int i;
1915         MenuType *mt = WM_menutype_find("USERPREF_MT_splash", true);
1916         char url[96];
1917         const char *version_suffix = NULL;
1918
1919 #ifndef WITH_HEADLESS
1920         extern char datatoc_splash_png[];
1921         extern int datatoc_splash_png_size;
1922
1923         extern char datatoc_splash_2x_png[];
1924         extern int datatoc_splash_2x_png_size;
1925         ImBuf *ibuf;
1926 #else
1927         ImBuf *ibuf = NULL;
1928 #endif
1929
1930 #ifdef WITH_BUILDINFO
1931         int label_delta = 0;
1932         int hash_width, date_width;
1933         char date_buf[128] = "\0";
1934         char hash_buf[128] = "\0";
1935         extern unsigned long build_commit_timestamp;
1936         extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[];
1937
1938         /* Builds made from tag only shows tag sha */
1939         BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash);
1940         BLI_snprintf(date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time);
1941         
1942         BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi);
1943         hash_width = (int)BLF_width(style->widgetlabel.uifont_id, hash_buf, sizeof(hash_buf)) + U.widget_unit;
1944         date_width = (int)BLF_width(style->widgetlabel.uifont_id, date_buf, sizeof(date_buf)) + U.widget_unit;
1945 #endif  /* WITH_BUILDINFO */
1946
1947 #ifndef WITH_HEADLESS
1948         if (U.pixelsize == 2) {
1949                 ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_2x_png,
1950                                              datatoc_splash_2x_png_size, IB_rect, NULL, "<splash screen>");
1951         }
1952         else {
1953                 ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png,
1954                                              datatoc_splash_png_size, IB_rect, NULL, "<splash screen>");
1955         }
1956 #endif
1957
1958         block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
1959
1960         /* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
1961          * with the OS when the splash shows, window clipping in this case gives
1962          * ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */
1963         UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
1964
1965         /* XXX splash scales with pixelsize, should become widget-units */
1966         but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */
1967         UI_but_func_set(but, wm_block_splash_close, block, NULL);
1968         UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
1969
1970         /* label for 'a' bugfix releases, or 'Release Candidate 1'...
1971          *  avoids recreating splash for version updates */
1972         if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
1973                 version_suffix = "Release Candidate";
1974         }
1975         else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
1976                 version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
1977         }
1978         if (version_suffix != NULL && version_suffix[0]) {
1979                 /* placed after the version number in the image,
1980                  * placing y is tricky to match baseline */
1981                 int x = 260 - (2 * UI_DPI_WINDOW_FAC);
1982                 int y = 242 + (4 * UI_DPI_WINDOW_FAC);
1983                 int w = 240;
1984
1985                 /* hack to have text draw 'text_sel' */
1986                 UI_block_emboss_set(block, UI_EMBOSS_NONE);
1987                 but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
1988                 /* XXX, set internal flag - UI_SELECT */
1989                 UI_but_flag_enable(but, 1);
1990                 UI_block_emboss_set(block, UI_EMBOSS);
1991         }
1992
1993 #ifdef WITH_BUILDINFO
1994         if (build_commit_timestamp != 0) {
1995                 uiDefBut(block, UI_BTYPE_LABEL, 0, date_buf, U.pixelsize * 494 - date_width, U.pixelsize * 270, date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
1996                 label_delta = 12;
1997         }
1998         uiDefBut(block, UI_BTYPE_LABEL, 0, hash_buf, U.pixelsize * 494 - hash_width, U.pixelsize * (270 - label_delta), hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
1999
2000         if (!STREQ(build_branch, "master")) {
2001                 char branch_buf[128] = "\0";
2002                 int branch_width;
2003                 BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
2004                 branch_width = (int)BLF_width(style->widgetlabel.uifont_id, branch_buf, sizeof(branch_buf)) + U.widget_unit;
2005                 uiDefBut(block, UI_BTYPE_LABEL, 0, branch_buf, U.pixelsize * 494 - branch_width, U.pixelsize * (258 - label_delta), branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
2006         }
2007 #endif  /* WITH_BUILDINFO */
2008         
2009         layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style);
2010         
2011         UI_block_emboss_set(block, UI_EMBOSS);
2012         /* show the splash menu (containing interaction presets), using python */
2013         if (mt) {
2014                 Menu menu = {NULL};
2015                 menu.layout = layout;
2016                 menu.type = mt;
2017                 mt->draw(C, &menu);
2018
2019 //              wmWindowManager *wm = CTX_wm_manager(C);
2020 //              uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE);
2021         }
2022         
2023         UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN);
2024         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
2025         
2026         split = uiLayoutSplit(layout, 0.0f, false);
2027         col = uiLayoutColumn(split, false);
2028         uiItemL(col, IFACE_("Links"), ICON_NONE);
2029 #if 0
2030         uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
2031                       "https://cloud.blender.org/join");
2032 #endif
2033         uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url",
2034                       "http://www.blender.org/foundation/donation-payment/");
2035         uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url",
2036                       "http://www.blender.org/about/credits/");
2037         BLI_snprintf(url, sizeof(url), "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d",
2038                      BLENDER_VERSION / 100, BLENDER_VERSION % 100);
2039         uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
2040         uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
2041                       "http://www.blender.org/manual");
2042         uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
2043         if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
2044                 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d"
2045                                                STRINGIFY(BLENDER_VERSION_CHAR) "_release",
2046                              BLENDER_VERSION / 100, BLENDER_VERSION % 100);
2047         }
2048         else {
2049                 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d_%d",
2050                              BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION);
2051         }
2052         uiItemStringO(col, IFACE_("Python API Reference"), ICON_URL, "WM_OT_url_open", "url", url);
2053         uiItemL(col, "", ICON_NONE);
2054
2055         col = uiLayoutColumn(split, false);
2056
2057         if (wm_resource_check_prev()) {
2058                 uiItemO(col, NULL, ICON_NEW, "WM_OT_copy_prev_settings");
2059                 uiItemS(col);
2060         }
2061
2062         uiItemL(col, IFACE_("Recent"), ICON_NONE);
2063         for (recent = G.recent_files.first, i = 0; (i < 5) && (recent); recent = recent->next, i++) {
2064                 const char *filename = BLI_path_basename(recent->filepath);
2065                 uiItemStringO(col, filename,
2066                               BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP,
2067                               "WM_OT_open_mainfile", "filepath", recent->filepath);
2068         }
2069
2070         uiItemS(col);
2071         uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session");
2072         uiItemL(col, "", ICON_NONE);
2073         
2074         mt = WM_menutype_find("USERPREF_MT_splash_footer", false);
2075         if (mt) {
2076                 Menu menu = {NULL};
2077                 menu.layout = uiLayoutColumn(layout, false);
2078                 menu.type = mt;
2079                 mt->draw(C, &menu);
2080         }
2081
2082         UI_block_bounds_set_centered(block, 0);
2083         
2084         return block;
2085 }
2086
2087 static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
2088 {
2089         UI_popup_block_invoke(C, wm_block_create_splash, NULL);
2090         
2091         return OPERATOR_FINISHED;
2092 }
2093
2094 static void WM_OT_splash(wmOperatorType *ot)
2095 {
2096         ot->name = "Splash Screen";
2097         ot->idname = "WM_OT_splash";
2098         ot->description = "Open the splash screen with release info";
2099         
2100         ot->invoke = wm_splash_invoke;
2101         ot->poll = WM_operator_winactive;
2102 }
2103
2104
2105 /* ***************** Search menu ************************* */
2106 static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_op))
2107 {
2108         static char search[256] = "";
2109         wmEvent event;
2110         wmWindow *win = CTX_wm_window(C);
2111         uiBlock *block;
2112         uiBut *but;
2113         
2114         block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
2115         UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
2116         
2117         but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
2118         UI_but_func_operator_search(but);
2119         
2120         /* fake button, it holds space for search items */
2121         uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
2122         
2123         UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
2124         
2125         wm_event_init_from_window(win, &event);
2126         event.type = EVT_BUT_OPEN;
2127         event.val = KM_PRESS;
2128         event.customdata = but;
2129         event.customdatafree = false;
2130         wm_event_add(win, &event);
2131         
2132         return block;
2133 }
2134
2135 static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
2136 {
2137         return OPERATOR_FINISHED;
2138 }
2139
2140 static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2141 {
2142         UI_popup_block_invoke(C, wm_block_search_menu, op);
2143         
2144         return OPERATOR_INTERFACE;
2145 }
2146
2147 /* op->poll */
2148 static int wm_search_menu_poll(bContext *C)
2149 {
2150         if (CTX_wm_window(C) == NULL) {
2151                 return 0;
2152         }
2153         else {
2154                 ScrArea *sa = CTX_wm_area(C);
2155                 if (sa) {
2156                         if (sa->spacetype == SPACE_CONSOLE) return 0;  /* XXX - so we can use the shortcut in the console */
2157                         if (sa->spacetype == SPACE_TEXT) return 0;     /* XXX - so we can use the spacebar in the text editor */
2158                 }
2159                 else {
2160                         Object *editob = CTX_data_edit_object(C);
2161                         if (editob && editob->type == OB_FONT) return 0;  /* XXX - so we can use the spacebar for entering text */
2162                 }
2163         }
2164         return 1;
2165 }
2166
2167 static void WM_OT_search_menu(wmOperatorType *ot)
2168 {
2169         ot->name = "Search Menu";
2170         ot->idname = "WM_OT_search_menu";
2171         ot->description = "Pop-up a search menu over all available operators in current context";
2172         
2173         ot->invoke = wm_search_menu_invoke;
2174         ot->exec = wm_search_menu_exec;
2175         ot->poll = wm_search_menu_poll;
2176 }
2177
2178 static int wm_call_menu_exec(bContext *C, wmOperator *op)
2179 {
2180         char idname[BKE_ST_MAXNAME];
2181         RNA_string_get(op->ptr, "name", idname);
2182
2183         return UI_popup_menu_invoke(C, idname, op->reports);
2184 }
2185
2186 static void WM_OT_call_menu(wmOperatorType *ot)
2187 {
2188         ot->name = "Call Menu";
2189         ot->idname = "WM_OT_call_menu";
2190         ot->description = "Call (draw) a pre-defined menu";
2191
2192         ot->exec = wm_call_menu_exec;
2193         ot->poll = WM_operator_winactive;
2194
2195         ot->flag = OPTYPE_INTERNAL;
2196
2197         RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
2198 }
2199
2200 static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2201 {
2202         char idname[BKE_ST_MAXNAME];
2203         RNA_string_get(op->ptr, "name", idname);
2204
2205         return UI_pie_menu_invoke(C, idname, event);
2206 }
2207
2208 static int wm_call_pie_menu_exec(bContext *C, wmOperator *op)
2209 {
2210         char idname[BKE_ST_MAXNAME];
2211         RNA_string_get(op->ptr, "name", idname);
2212
2213         return UI_pie_menu_invoke(C, idname, CTX_wm_window(C)->eventstate);
2214 }
2215
2216 static void WM_OT_call_menu_pie(wmOperatorType *ot)
2217 {
2218         ot->name = "Call Pie Menu";
2219         ot->idname = "WM_OT_call_menu_pie";
2220         ot->description = "Call (draw) a pre-defined pie menu";
2221
2222         ot->invoke = wm_call_pie_menu_invoke;
2223         ot->exec = wm_call_pie_menu_exec;
2224         ot->poll = WM_operator_winactive;
2225
2226         ot->flag = OPTYPE_INTERNAL;
2227
2228         RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
2229 }
2230
2231 /* ************ window / screen operator definitions ************** */
2232
2233 /* this poll functions is needed in place of WM_operator_winactive
2234  * while it crashes on full screen */
2235 static int wm_operator_winactive_normal(bContext *C)
2236 {
2237         wmWindow *win = CTX_wm_window(C);
2238
2239         if (win == NULL || win->screen == NULL || win->screen->state != SCREENNORMAL)
2240                 return 0;
2241
2242         return 1;
2243 }
2244
2245 static void WM_OT_window_duplicate(wmOperatorType *ot)
2246 {
2247         ot->name = "Duplicate Window";
2248         ot->idname = "WM_OT_window_duplicate";
2249         ot->description = "Duplicate the current Blender window";
2250                 
2251         ot->exec = wm_window_duplicate_exec;
2252         ot->poll = wm_operator_winactive_normal;
2253 }
2254
2255 static void WM_OT_save_homefile(wmOperatorType *ot)
2256 {
2257         ot->name = "Save Startup File";
2258         ot->idname = "WM_OT_save_homefile";
2259         ot->description = "Make the current file the default .blend file, includes preferences";
2260                 
2261         ot->invoke = WM_operator_confirm;
2262         ot->exec = wm_homefile_write_exec;
2263 }
2264
2265 static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
2266 {
2267         bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
2268         BLI_addtail(&U.autoexec_paths, path_cmp);
2269         return OPERATOR_FINISHED;
2270 }
2271
2272 static void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
2273 {
2274         ot->name = "Add Autoexec Path";
2275         ot->idname = "WM_OT_userpref_autoexec_path_add";
2276         ot->description = "Add path to exclude from autoexecution";
2277
2278         ot->exec = wm_userpref_autoexec_add_exec;
2279
2280         ot->flag = OPTYPE_INTERNAL;
2281 }
2282
2283 static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
2284 {
2285         const int index = RNA_int_get(op->ptr, "index");
2286         bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
2287         if (path_cmp) {
2288                 BLI_freelinkN(&U.autoexec_paths, path_cmp);
2289         }
2290         return OPERATOR_FINISHED;
2291 }
2292
2293 static void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
2294 {
2295         ot->name = "Remove Autoexec Path";
2296         ot->idname = "WM_OT_userpref_autoexec_path_remove";
2297         ot->description = "Remove path to exclude from autoexecution";
2298
2299         ot->exec = wm_userpref_autoexec_remove_exec;
2300
2301         ot->flag = OPTYPE_INTERNAL;
2302
2303         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
2304 }
2305
2306 static void WM_OT_save_userpref(wmOperatorType *ot)
2307 {
2308         ot->name = "Save User Settings";
2309         ot->idname = "WM_OT_save_userpref";
2310         ot->description = "Save user preferences separately, overrides startup file preferences";
2311         
2312         ot->invoke = WM_operator_confirm;
2313         ot->exec = wm_userpref_write_exec;
2314 }
2315
2316 static void WM_OT_read_history(wmOperatorType *ot)
2317 {
2318         ot->name = "Reload History File";
2319         ot->idname = "WM_OT_read_history";
2320         ot->description = "Reloads history and bookmarks";
2321
2322         ot->invoke = WM_operator_confirm;
2323         ot->exec = wm_history_file_read_exec;
2324
2325         /* this operator is only used for loading settings from a previous blender install */
2326         ot->flag = OPTYPE_INTERNAL;
2327 }
2328
2329 static void WM_OT_read_homefile(wmOperatorType *ot)
2330 {
2331         PropertyRNA *prop;
2332         ot->name = "Reload Start-Up File";
2333         ot->idname = "WM_OT_read_homefile";
2334         ot->description = "Open the default file (doesn't save the current file)";
2335         
2336         ot->invoke = WM_operator_confirm;
2337         ot->exec = wm_homefile_read_exec;
2338
2339         prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
2340                                         FILE_MAX, "File Path", 
2341                                         "Path to an alternative start-up file");
2342         RNA_def_property_flag(prop, PROP_HIDDEN);
2343
2344         /* So scripts can use an alternative start-up file without the UI */
2345         prop = RNA_def_boolean(ot->srna, "load_ui", true, "Load UI",
2346                                "Load user interface setup from the .blend file");
2347         RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
2348
2349         /* omit poll to run in background mode */
2350 }
2351
2352 static void WM_OT_read_factory_settings(wmOperatorType *ot)
2353 {
2354         ot->name = "Load Factory Settings";
2355         ot->idname = "WM_OT_read_factory_settings";
2356         ot->description = "Load default file and user preferences";
2357         
2358         ot->invoke = WM_operator_confirm;
2359         ot->exec = wm_homefile_read_exec;
2360         /* omit poll to run in background mode */
2361 }
2362
2363 /* *************** open file **************** */
2364
2365 /**
2366  * Wrap #WM_file_read, shared by file reading operators.
2367  */
2368 static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports,
2369                                 const bool autoexec_init)
2370 {
2371         bool success;
2372
2373         /* XXX wm in context is not set correctly after WM_file_read -> crash */
2374         /* do it before for now, but is this correct with multiple windows? */
2375         WM_event_add_notifier(C, NC_WINDOW, NULL);
2376
2377         if (autoexec_init) {
2378                 WM_file_autoexec_init(filepath);
2379         }
2380
2381         success = WM_file_read(C, filepath, reports);
2382
2383         return success;
2384 }
2385
2386 /* currently fits in a pointer */
2387 struct FileRuntime {
2388         bool is_untrusted;
2389 };
2390
2391 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2392 {
2393         const char *openname = G.main->name;
2394
2395         if (CTX_wm_window(C) == NULL) {
2396                 /* in rare cases this could happen, when trying to invoke in background
2397                  * mode on load for example. Don't use poll for this because exec()
2398                  * can still run without a window */
2399                 BKE_report(op->reports, RPT_ERROR, "Context window not set");
2400                 return OPERATOR_CANCELLED;
2401         }
2402
2403         /* if possible, get the name of the most recently used .blend file */
2404         if (G.recent_files.first) {
2405                 struct RecentFile *recent = G.recent_files.first;
2406                 openname = recent->filepath;
2407         }
2408
2409         RNA_string_set(op->ptr, "filepath", openname);
2410         wm_open_init_load_ui(op, true);
2411         wm_open_init_use_scripts(op, true);
2412         op->customdata = NULL;
2413
2414         WM_event_add_fileselect(C, op);
2415
2416         return OPERATOR_RUNNING_MODAL;
2417 }
2418
2419 static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
2420 {
2421         char filepath[FILE_MAX];
2422         bool success;
2423
2424         RNA_string_get(op->ptr, "filepath", filepath);
2425
2426         /* re-use last loaded setting so we can reload a file without changing */
2427         wm_open_init_load_ui(op, false);
2428         wm_open_init_use_scripts(op, false);
2429
2430         if (RNA_boolean_get(op->ptr, "load_ui"))
2431                 G.fileflags &= ~G_FILE_NO_UI;
2432         else
2433                 G.fileflags |= G_FILE_NO_UI;
2434                 
2435         if (RNA_boolean_get(op->ptr, "use_scripts"))
2436                 G.f |= G_SCRIPT_AUTOEXEC;
2437         else
2438                 G.f &= ~G_SCRIPT_AUTOEXEC;
2439         
2440         success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
2441
2442         /* for file open also popup for warnings, not only errors */
2443         BKE_report_print_level_set(op->reports, RPT_WARNING);
2444
2445         if (success) {
2446                 return OPERATOR_FINISHED;
2447         }
2448         else {
2449                 return OPERATOR_CANCELLED;
2450         }
2451 }
2452
2453 static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
2454 {
2455         struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2456         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
2457         bool is_untrusted = false;
2458         char path[FILE_MAX];
2459         char *lslash;
2460
2461         RNA_string_get(op->ptr, "filepath", path);
2462
2463         /* get the dir */
2464         lslash = (char *)BLI_last_slash(path);
2465         if (lslash) *(lslash + 1) = '\0';
2466
2467         if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
2468                 if (BKE_autoexec_match(path) == true) {
2469                         RNA_property_boolean_set(op->ptr, prop, false);
2470                         is_untrusted = true;
2471                 }
2472         }
2473
2474         if (file_info) {
2475                 file_info->is_untrusted = is_untrusted;
2476         }
2477
2478         return is_untrusted;
2479 }
2480
2481 static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
2482 {
2483         struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
2484         uiLayout *layout = op->layout;
2485         uiLayout *col = op->layout;
2486         const char *autoexec_text;
2487
2488         uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
2489
2490         col = uiLayoutColumn(layout, false);
2491         if (file_info->is_untrusted) {
2492                 autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
2493                 uiLayoutSetActive(col, false);
2494                 uiLayoutSetEnabled(col, false);
2495         }
2496         else {
2497                 autoexec_text = IFACE_("Trusted Source");
2498         }
2499
2500         uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
2501 }
2502
2503 static void WM_OT_open_mainfile(wmOperatorType *ot)
2504 {
2505         ot->name = "Open Blender File";
2506         ot->idname = "WM_OT_open_mainfile";
2507         ot->description = "Open a Blender file";
2508
2509         ot->invoke = wm_open_mainfile_invoke;
2510         ot->exec = wm_open_mainfile_exec;
2511         ot->check = wm_open_mainfile_check;
2512         ot->ui = wm_open_mainfile_ui;
2513         /* omit window poll so this can work in background mode */
2514
2515         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
2516                                        WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
2517
2518         RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
2519         RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
2520                         "Allow .blend file to execute scripts automatically, default available from system preferences");
2521 }
2522
2523
2524 /* *************** revert file **************** */
2525
2526 static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
2527 {
2528         bool success;
2529
2530         wm_open_init_use_scripts(op, false);
2531
2532         if (RNA_boolean_get(op->ptr, "use_scripts"))
2533                 G.f |= G_SCRIPT_AUTOEXEC;
2534         else
2535                 G.f &= ~G_SCRIPT_AUTOEXEC;
2536
2537         success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
2538
2539         if (success) {
2540                 return OPERATOR_FINISHED;
2541         }
2542         else {
2543                 return OPERATOR_CANCELLED;
2544         }
2545 }
2546
2547 static int wm_revert_mainfile_poll(bContext *UNUSED(C))
2548 {
2549         return G.relbase_valid;
2550 }
2551
2552 static void WM_OT_revert_mainfile(wmOperatorType *ot)
2553 {
2554         ot->name = "Revert";
2555         ot->idname = "WM_OT_revert_mainfile";
2556         ot->description = "Reload the saved file";
2557         ot->invoke = WM_operator_confirm;
2558
2559         RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
2560                         "Allow .blend file to execute scripts automatically, default available from system preferences");
2561
2562         ot->exec = wm_revert_mainfile_exec;
2563         ot->poll = wm_revert_mainfile_poll;
2564 }
2565
2566 /* **************** link/append *************** */
2567
2568 static int wm_link_append_poll(bContext *C)
2569 {
2570         if (WM_operator_winactive(C)) {
2571                 /* linking changes active object which is pretty useful in general,
2572                  * but which totally confuses edit mode (i.e. it becoming not so obvious
2573                  * to leave from edit mode and invalid tools in toolbar might be displayed)
2574                  * so disable link/append when in edit mode (sergey) */
2575                 if (CTX_data_edit_object(C))
2576                         return 0;
2577
2578                 return 1;
2579         }
2580
2581         return 0;
2582 }
2583
2584 static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2585 {
2586         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
2587                 return WM_operator_call_notest(C, op);
2588         }
2589         else {
2590                 /* XXX TODO solve where to get last linked library from */
2591                 if (G.lib[0] != '\0') {
2592                         RNA_string_set(op->ptr, "filepath", G.lib);
2593                 }
2594                 else if (G.relbase_valid) {
2595                         char path[FILE_MAX];
2596                         BLI_strncpy(path, G.main->name, sizeof(G.main->name));
2597                         BLI_parent_dir(path);
2598                         RNA_string_set(op->ptr, "filepath", path);
2599                 }
2600                 WM_event_add_fileselect(C, op);
2601                 return OPERATOR_RUNNING_MODAL;
2602         }
2603 }
2604
2605 static short wm_link_append_flag(wmOperator *op)
2606 {
2607         short flag = 0;
2608
2609         if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
2610         if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
2611         if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
2612         if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
2613         if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE;
2614
2615         return flag;
2616 }
2617
2618 /* Helper.
2619  *     if `name` is non-NULL, we assume a single-item link/append.
2620  *     else if `*todo_libraries` is NULL we assume first-run.
2621  */
2622 static void wm_link_append_do_libgroup(
2623         bContext *C, wmOperator *op, const char *root, const char *libname, char *group, char *name,
2624         const short flag, GSet **todo_libraries)
2625 {
2626         Main *bmain = CTX_data_main(C);
2627         Main *mainl;
2628         BlendHandle *bh;
2629         Library *lib;
2630
2631         char path[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
2632         int idcode;
2633         const bool is_first_run = (*todo_libraries == NULL);
2634
2635         BLI_assert(group);
2636         idcode = BKE_idcode_from_name(group);
2637
2638         bh = BLO_blendhandle_from_file(libname, op->reports);
2639
2640         if (bh == NULL) {
2641                 /* unlikely since we just browsed it, but possible
2642                  * error reports will have been made by BLO_blendhandle_from_file() */
2643                 return;
2644         }
2645
2646         /* here appending/linking starts */
2647         mainl = BLO_library_link_begin(bmain, &bh, libname);
2648         lib = mainl->curlib;
2649         BLI_assert(lib);
2650
2651         if (mainl->versionfile < 250) {
2652                 BKE_reportf(op->reports, RPT_WARNING,
2653                             "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
2654                             "be done! You may want to re-save your lib file with current Blender",
2655                             mainl->versionfile, mainl->subversionfile);
2656         }
2657
2658         if (name) {
2659                 BLO_library_link_named_part_ex(C, mainl, &bh, name, idcode, flag);
2660         }
2661         else {
2662                 if (is_first_run) {
2663                         *todo_libraries = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
2664                 }
2665
2666                 RNA_BEGIN (op->ptr, itemptr, "files")
2667                 {
2668                         char curr_libname[FILE_MAX];
2669                         int curr_idcode;
2670
2671                         RNA_string_get(&itemptr, "name", relname);
2672
2673                         BLI_join_dirfile(path, sizeof(path), root, relname);
2674
2675                         if (BLO_library_path_explode(path, curr_libname, &group, &name)) {
2676                                 if (!group || !name) {
2677                                         continue;
2678                                 }
2679
2680                                 curr_idcode = BKE_idcode_from_name(group);
2681
2682                                 if ((idcode == curr_idcode) && (BLI_path_cmp(curr_libname, libname) == 0)) {
2683                                         BLO_library_link_named_part_ex(C, mainl, &bh, name, idcode, flag);
2684                                 }
2685                                 else if (is_first_run) {
2686                                         BLI_join_dirfile(path, sizeof(path), curr_libname, group);
2687                                         if (!BLI_gset_haskey(*todo_libraries, path)) {
2688                                                 BLI_gset_insert(*todo_libraries, BLI_strdup(path));
2689                                         }
2690                                 }
2691                         }
2692                 }
2693                 RNA_END;
2694         }
2695         BLO_library_link_end(C, mainl, &bh, idcode, flag);
2696
2697         BLO_blendhandle_close(bh);
2698
2699         /* mark all library linked objects to be updated */
2700         BKE_main_lib_objects_recalc_all(bmain);
2701         IMB_colormanagement_check_file_config(bmain);
2702
2703         /* append, rather than linking */
2704         if ((flag & FILE_LINK) == 0) {
2705                 BLI_assert(BLI_findindex(&bmain->library, lib) != -1);
2706                 BKE_library_make_local(bmain, lib, true);
2707         }
2708 }
2709
2710 static int wm_link_append_exec(bContext *C, wmOperator *op)
2711 {
2712         Main *bmain = CTX_data_main(C);
2713         Scene *scene = CTX_data_scene(C);
2714         PropertyRNA *prop;
2715         char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
2716         char *group, *name;
2717         int totfiles = 0;
2718         short flag;
2719
2720         GSet *todo_libraries = NULL;
2721
2722         RNA_string_get(op->ptr, "filename", relname);
2723         RNA_string_get(op->ptr, "directory", root);
2724
2725         BLI_join_dirfile(path, sizeof(path), root, relname);
2726
2727         /* test if we have a valid data */
2728         if (!BLO_library_path_explode(path, libname, &group, &name)) {
2729                 BKE_report(op->reports, RPT_ERROR, "Not a library");
2730                 return OPERATOR_CANCELLED;
2731         }
2732         else if (!group) {
2733                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
2734                 return OPERATOR_CANCELLED;
2735         }
2736         else if (BLI_path_cmp(bmain->name, libname) == 0) {
2737                 BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
2738                 return OPERATOR_CANCELLED;
2739         }
2740
2741         /* check if something is indicated for append/link */
2742         prop = RNA_struct_find_property(op->ptr, "files");
2743         if (prop) {
2744                 totfiles = RNA_property_collection_length(op->ptr, prop);
2745                 if (totfiles == 0) {
2746                         if (!name) {
2747                                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
2748                                 return OPERATOR_CANCELLED;
2749                         }
2750                 }
2751         }
2752         else if (!name) {
2753                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
2754                 return OPERATOR_CANCELLED;
2755         }
2756
2757         flag = wm_link_append_flag(op);
2758
2759         /* sanity checks for flag */
2760         if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
2761                 /* TODO, user never gets this message */
2762                 BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2);
2763                 flag &= ~FILE_GROUP_INSTANCE;
2764         }
2765
2766         /* from here down, no error returns */
2767
2768         /* now we have or selected, or an indicated file */
2769         if (RNA_boolean_get(op->ptr, "autoselect"))
2770                 BKE_scene_base_deselect_all(scene);
2771         
2772         /* tag everything, all untagged data can be made local
2773          * its also generally useful to know what is new
2774          *
2775          * take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */
2776         BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1);
2777
2778         if (totfiles != 0) {
2779                 name = NULL;
2780         }
2781
2782         wm_link_append_do_libgroup(C, op, root, libname, group, name, flag, &todo_libraries);
2783
2784         if (todo_libraries) {
2785                 GSetIterator libs_it;
2786
2787                 GSET_ITER(libs_it, todo_libraries) {
2788                         char *libpath = (char *)BLI_gsetIterator_getKey(&libs_it);
2789
2790                         BLO_library_path_explode(libpath, libname, &group, NULL);
2791
2792                         wm_link_append_do_libgroup(C, op, root, libname, group, NULL, flag, &todo_libraries);
2793                 }
2794
2795                 BLI_gset_free(todo_libraries, MEM_freeN);
2796         }
2797
2798         /* important we unset, otherwise these object wont
2799          * link into other scenes from this blend file */
2800         BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false);
2801
2802         /* recreate dependency graph to include new objects */
2803         DAG_scene_relations_rebuild(bmain, scene);
2804         
2805         /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
2806         GPU_materials_free();
2807
2808         /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
2809         BLI_strncpy(G.lib, root, FILE_MAX);
2810
2811         WM_event_add_notifier(C, NC_WINDOW, NULL);
2812
2813         return OPERATOR_FINISHED;
2814 }
2815
2816 static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
2817 {
2818         PropertyRNA *prop;
2819
2820         /* better not save _any_ settings for this operator */
2821         /* properties */
2822         prop = RNA_def_boolean(ot->srna, "link", is_link,
2823                                "Link", "Link the objects or datablocks rather than appending");
2824         RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2825         prop = RNA_def_boolean(ot->srna, "autoselect", true,
2826                                "Select", "Select new objects");
2827         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2828         prop = RNA_def_boolean(ot->srna, "active_layer", true,
2829                                "Active Layer", "Put new objects on the active layer");
2830         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2831         prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
2832                                "Instance Groups", "Create Dupli-Group instances for each group");
2833         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2834 }
2835
2836 static void WM_OT_link(wmOperatorType *ot)
2837 {
2838         ot->name = "Link from Library";
2839         ot->idname = "WM_OT_link";
2840         ot->description = "Link from a Library .blend file";
2841         
2842         ot->invoke = wm_link_append_invoke;
2843         ot->exec = wm_link_append_exec;
2844         ot->poll = wm_link_append_poll;
2845         
2846         ot->flag |= OPTYPE_UNDO;
2847
2848         WM_operator_properties_filesel(
2849                 ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
2850                 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
2851                 FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
2852         
2853         wm_link_append_properties_common(ot, true);
2854 }
2855
2856 static void WM_OT_append(wmOperatorType *ot)
2857 {
2858         ot->name = "Append from Library";
2859         ot->idname = "WM_OT_append";
2860         ot->description = "Append from a Library .blend file";
2861
2862         ot->invoke = wm_link_append_invoke;
2863         ot->exec = wm_link_append_exec;
2864         ot->poll = wm_link_append_poll;
2865
2866         ot->flag |= OPTYPE_UNDO;
2867
2868         WM_operator_properties_filesel(
2869                 ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
2870                 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
2871                 FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
2872
2873         wm_link_append_properties_common(ot, false);
2874 }
2875
2876 /* *************** recover last session **************** */
2877
2878 void WM_recover_last_session(bContext *C, ReportList *reports)
2879 {
2880         char filepath[FILE_MAX];
2881         
2882         BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
2883         /* if reports==NULL, it's called directly without operator, we add a quick check here */
2884         if (reports || BLI_exists(filepath)) {
2885                 G.fileflags |= G_FILE_RECOVER;
2886                 
2887                 wm_file_read_opwrap(C, filepath, reports, true);
2888         
2889                 G.fileflags &= ~G_FILE_RECOVER;
2890                 
2891                 /* XXX bad global... fixme */
2892                 if (G.main->name[0])
2893                         G.file_loaded = 1;      /* prevents splash to show */
2894                 else {
2895                         G.relbase_valid = 0;
2896                         G.save_over = 0;    /* start with save preference untitled.blend */
2897                 }
2898
2899         }
2900 }
2901
2902 static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
2903 {
2904         WM_recover_last_session(C, op->reports);
2905         return OPERATOR_FINISHED;
2906 }
2907
2908 static void WM_OT_recover_last_session(wmOperatorType *ot)
2909 {
2910         ot->name = "Recover Last Session";
2911         ot->idname = "WM_OT_recover_last_session";
2912         ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
2913         ot->invoke = WM_operator_confirm;
2914         
2915         ot->exec = wm_recover_last_session_exec;
2916 }
2917
2918 /* *************** recover auto save **************** */
2919
2920 static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
2921 {
2922         char filepath[FILE_MAX];
2923         bool success;
2924
2925         RNA_string_get(op->ptr, "filepath", filepath);
2926
2927         G.fileflags |= G_FILE_RECOVER;
2928
2929         success = wm_file_read_opwrap(C, filepath, op->reports, true);
2930
2931         G.fileflags &= ~G_FILE_RECOVER;
2932         
2933         if (success) {
2934                 return OPERATOR_FINISHED;
2935         }
2936         else {
2937                 return OPERATOR_CANCELLED;
2938         }
2939 }
2940
2941 static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2942 {
2943         char filename[FILE_MAX];
2944
2945         wm_autosave_location(filename);
2946         RNA_string_set(op->ptr, "filepath", filename);
2947         WM_event_add_fileselect(C, op);
2948
2949         return OPERATOR_RUNNING_MODAL;
2950 }
2951
2952 static void WM_OT_recover_auto_save(wmOperatorType *ot)
2953 {
2954         ot->name = "Recover Auto Save";
2955         ot->idname = "WM_OT_recover_auto_save";
2956         ot->description = "Open an automatically saved file to recover it";
2957         
2958         ot->exec = wm_recover_auto_save_exec;
2959         ot->invoke = wm_recover_auto_save_invoke;
2960
2961         WM_operator_properties_filesel(ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
2962                                        WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
2963 }
2964
2965 /* *************** save file as **************** */
2966
2967 static void wm_filepath_default(char *filepath)
2968 {
2969         if (G.save_over == false) {
2970                 BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
2971         }
2972 }
2973
2974 static void save_set_compress(wmOperator *op)
2975 {
2976         PropertyRNA *prop;
2977
2978         prop = RNA_struct_find_property(op->ptr, "compress");
2979         if (!RNA_property_is_set(op->ptr, prop)) {
2980                 if (G.save_over) {  /* keep flag for existing file */
2981                         RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
2982                 }
2983                 else {  /* use userdef for new file */
2984                         RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
2985                 }
2986         }
2987 }
2988
2989 static void save_set_filepath(wmOperator *op)
2990 {
2991         PropertyRNA *prop;
2992         char name[FILE_MAX];
2993
2994         prop = RNA_struct_find_property(op->ptr, "filepath");
2995         if (!RNA_property_is_set(op->ptr, prop)) {
2996                 /* if not saved before, get the name of the most recently used .blend file */
2997                 if (G.main->name[0] == 0 && G.recent_files.first) {
2998                         struct RecentFile *recent = G.recent_files.first;
2999                         BLI_strncpy(name, recent->filepath, FILE_MAX);
3000                 }
3001                 else {
3002                         BLI_strncpy(name, G.main->name, FILE_MAX);
3003                 }
3004
3005                 wm_filepath_default(name);
3006                 RNA_property_string_set(op->ptr, prop, name);
3007         }
3008 }
3009
3010 static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3011 {
3012
3013         save_set_compress(op);
3014         save_set_filepath(op);
3015         
3016         WM_event_add_fileselect(C, op);
3017
3018         return OPERATOR_RUNNING_MODAL;
3019 }
3020
3021 /* function used for WM_OT_save_mainfile too */
3022 static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
3023 {
3024         char path[FILE_MAX];
3025         int fileflags;
3026
3027         save_set_compress(op);
3028         
3029         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
3030                 RNA_string_get(op->ptr, "filepath", path);
3031         }
3032         else {
3033                 BLI_strncpy(path, G.main->name, FILE_MAX);
3034                 wm_filepath_default(path);
3035         }
3036         
3037         fileflags = G.fileflags & ~G_FILE_USERPREFS;
3038
3039         /* set compression flag */
3040         BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
3041                          G_FILE_COMPRESS);
3042         BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
3043                          G_FILE_RELATIVE_REMAP);
3044         BKE_BIT_TEST_SET(fileflags,
3045                          (RNA_struct_property_is_set(op->ptr, "copy") &&
3046                           RNA_boolean_get(op->ptr, "copy")),
3047                          G_FILE_SAVE_COPY);
3048
3049 #ifdef USE_BMESH_SAVE_AS_COMPAT
3050         BKE_BIT_TEST_SET(fileflags,
3051                          (RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
3052                           RNA_boolean_get(op->ptr, "use_mesh_compat")),
3053                          G_FILE_MESH_COMPAT);
3054 #else
3055 #  error "don't remove by accident"
3056 #endif
3057
3058         if (wm_file_write(C, path, fileflags, op->reports) != 0)
3059                 return OPERATOR_CANCELLED;
3060
3061         WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
3062
3063         return OPERATOR_FINISHED;
3064 }
3065
3066 /* function used for WM_OT_save_mainfile too */
3067 static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
3068 {
3069         char filepath[FILE_MAX];
3070         RNA_string_get(op->ptr, "filepath", filepath);
3071         if (!BLO_has_bfile_extension(filepath)) {
3072                 /* some users would prefer BLI_replace_extension(),
3073                  * we keep getting nitpicking bug reports about this - campbell */
3074                 BLI_ensure_extension(filepath, FILE_MAX, ".blend");
3075                 RNA_string_set(op->ptr, "filepath", filepath);
3076                 return true;
3077         }
3078         return false;
3079 }
3080
3081 static void WM_OT_save_as_mainfile(wmOperatorType *ot)
3082 {
3083         PropertyRNA *prop;
3084
3085         ot->name = "Save As Blender File";
3086         ot->idname = "WM_OT_save_as_mainfile";
3087         ot->description = "Save the current file in the desired location";
3088         
3089         ot->invoke = wm_save_as_mainfile_invoke;
3090         ot->exec = wm_save_as_mainfile_exec;
3091         ot->check = blend_save_check;
3092         /* omit window poll so this can work in background mode */
3093
3094         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
3095                                        WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
3096         RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
3097         RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
3098                         "Remap relative paths when saving in a different directory");
3099         prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
3100                         "Save a copy of the actual working state but does not make saved file active");
3101         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
3102 #ifdef USE_BMESH_SAVE_AS_COMPAT
3103         RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
3104                         "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
3105                         "be lost (no implicit triangulation)");
3106 #endif
3107 }
3108
3109 /* *************** save file directly ******** */
3110
3111 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
3112 {
3113         int ret;
3114         
3115         /* cancel if no active window */
3116         if (CTX_wm_window(C) == NULL)
3117                 return OPERATOR_CANCELLED;
3118
3119         save_set_compress(op);
3120         save_set_filepath(op);
3121
3122         /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
3123          * enable the option to remap paths to avoid confusion [#37240] */
3124         if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
3125                 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
3126                 if (!RNA_property_is_set(op->ptr, prop)) {
3127                         RNA_property_boolean_set(op->ptr, prop, true);
3128                 }
3129         }
3130
3131         if (G.save_over) {
3132                 char path[FILE_MAX];
3133
3134                 RNA_string_get(op->ptr, "filepath", path);
3135                 if (BLI_exists(path)) {
3136                         ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
3137                 }
3138                 else {
3139                         ret = wm_save_as_mainfile_exec(C, op);
3140                 }
3141         }
3142         else {
3143                 WM_event_add_fileselect(C, op);
3144                 ret = OPERATOR_RUNNING_MODAL;
3145         }
3146         
3147         return ret;
3148 }
3149
3150 static void WM_OT_save_mainfile(wmOperatorType *ot)
3151 {
3152         ot->name = "Save Blender File";
3153         ot->idname = "WM_OT_save_mainfile";
3154         ot->description = "Save the current Blender file";
3155         
3156         ot->invoke = wm_save_mainfile_invoke;
3157         ot->exec = wm_save_as_mainfile_exec;
3158         ot->check = blend_save_check;
3159         /* omit window poll so this can work in background mode */
3160         
3161         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
3162                                        WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
3163         RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
3164         RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
3165                         "Remap relative paths when saving in a different directory");
3166 }
3167
3168 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
3169 {
3170         ot->name = "Toggle Window Fullscreen";
3171         ot->idname = "WM_OT_window_fullscreen_toggle";
3172        &nb