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