1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup bke
22  */
23 
24 #ifdef WIN32
25 #  include "BLI_winstuff.h"
26 #endif
27 
28 #include <math.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "MEM_guardedalloc.h"
33 
34 #include "DNA_defaults.h"
35 #include "DNA_gpencil_types.h"
36 #include "DNA_mask_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_text_types.h"
41 #include "DNA_view3d_types.h"
42 #include "DNA_workspace_types.h"
43 
44 #include "BLI_listbase.h"
45 #include "BLI_math_vector.h"
46 #include "BLI_mempool.h"
47 #include "BLI_rect.h"
48 #include "BLI_utildefines.h"
49 
50 #include "BLT_translation.h"
51 
52 #include "BKE_icons.h"
53 #include "BKE_idprop.h"
54 #include "BKE_idtype.h"
55 #include "BKE_lib_query.h"
56 #include "BKE_node.h"
57 #include "BKE_screen.h"
58 #include "BKE_workspace.h"
59 
screen_free_data(ID * id)60 static void screen_free_data(ID *id)
61 {
62   bScreen *screen = (bScreen *)id;
63   ARegion *region;
64 
65   /* No animdata here. */
66 
67   for (region = screen->regionbase.first; region; region = region->next) {
68     BKE_area_region_free(NULL, region);
69   }
70 
71   BLI_freelistN(&screen->regionbase);
72 
73   BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(screen));
74 
75   BKE_previewimg_free(&screen->preview);
76 
77   /* Region and timer are freed by the window manager. */
78   MEM_SAFE_FREE(screen->tool_tip);
79 }
80 
screen_foreach_id_dopesheet(LibraryForeachIDData * data,bDopeSheet * ads)81 static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
82 {
83   if (ads != NULL) {
84     BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
85     BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
86   }
87 }
88 
BKE_screen_foreach_id_screen_area(LibraryForeachIDData * data,ScrArea * area)89 void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
90 {
91   BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
92 
93   /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code.
94    * Will be for a later round of cleanup though... */
95   LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
96     switch (sl->spacetype) {
97       case SPACE_VIEW3D: {
98         View3D *v3d = (View3D *)sl;
99 
100         BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
101         BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
102 
103         if (v3d->localvd) {
104           BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
105         }
106         break;
107       }
108       case SPACE_GRAPH: {
109         SpaceGraph *sipo = (SpaceGraph *)sl;
110 
111         screen_foreach_id_dopesheet(data, sipo->ads);
112         break;
113       }
114       case SPACE_PROPERTIES: {
115         SpaceProperties *sbuts = (SpaceProperties *)sl;
116 
117         BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
118         break;
119       }
120       case SPACE_FILE:
121         break;
122       case SPACE_ACTION: {
123         SpaceAction *saction = (SpaceAction *)sl;
124 
125         screen_foreach_id_dopesheet(data, &saction->ads);
126         BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
127         break;
128       }
129       case SPACE_IMAGE: {
130         SpaceImage *sima = (SpaceImage *)sl;
131 
132         BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
133         BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
134         BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
135         break;
136       }
137       case SPACE_SEQ: {
138         SpaceSeq *sseq = (SpaceSeq *)sl;
139 
140         BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
141         break;
142       }
143       case SPACE_NLA: {
144         SpaceNla *snla = (SpaceNla *)sl;
145 
146         screen_foreach_id_dopesheet(data, snla->ads);
147         break;
148       }
149       case SPACE_TEXT: {
150         SpaceText *st = (SpaceText *)sl;
151 
152         BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
153         break;
154       }
155       case SPACE_SCRIPT: {
156         SpaceScript *scpt = (SpaceScript *)sl;
157 
158         BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
159         break;
160       }
161       case SPACE_OUTLINER: {
162         SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
163 
164         BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP);
165 
166         if (space_outliner->treestore != NULL) {
167           TreeStoreElem *tselem;
168           BLI_mempool_iter iter;
169 
170           BLI_mempool_iternew(space_outliner->treestore, &iter);
171           while ((tselem = BLI_mempool_iterstep(&iter))) {
172             BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP);
173           }
174         }
175         break;
176       }
177       case SPACE_NODE: {
178         SpaceNode *snode = (SpaceNode *)sl;
179 
180         const bool is_private_nodetree = snode->id != NULL &&
181                                          ntreeFromID(snode->id) == snode->nodetree;
182 
183         BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
184         BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
185 
186         BKE_LIB_FOREACHID_PROCESS(
187             data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
188 
189         LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
190           if (path == snode->treepath.first) {
191             /* first nodetree in path is same as snode->nodetree */
192             BKE_LIB_FOREACHID_PROCESS(data,
193                                       path->nodetree,
194                                       is_private_nodetree ? IDWALK_CB_EMBEDDED :
195                                                             IDWALK_CB_USER_ONE);
196           }
197           else {
198             BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
199           }
200 
201           if (path->nodetree == NULL) {
202             break;
203           }
204         }
205 
206         BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
207         break;
208       }
209       case SPACE_CLIP: {
210         SpaceClip *sclip = (SpaceClip *)sl;
211 
212         BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
213         BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
214         break;
215       }
216       default:
217         break;
218     }
219   }
220 }
221 
screen_foreach_id(ID * id,LibraryForeachIDData * data)222 static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
223 {
224   if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
225     bScreen *screen = (bScreen *)id;
226 
227     LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
228       BKE_screen_foreach_id_screen_area(data, area);
229     }
230   }
231 }
232 
233 IDTypeInfo IDType_ID_SCR = {
234     .id_code = ID_SCR,
235     .id_filter = 0,
236     .main_listbase_index = INDEX_ID_SCR,
237     .struct_size = sizeof(bScreen),
238     .name = "Screen",
239     .name_plural = "screens",
240     .translation_context = BLT_I18NCONTEXT_ID_SCREEN,
241     .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_MAKELOCAL | IDTYPE_FLAGS_NO_ANIMDATA,
242 
243     .init_data = NULL,
244     .copy_data = NULL,
245     .free_data = screen_free_data,
246     .make_local = NULL,
247     .foreach_id = screen_foreach_id,
248     .foreach_cache = NULL,
249 
250     .blend_write = NULL,
251     .blend_read_data = NULL,
252     .blend_read_lib = NULL,
253     .blend_read_expand = NULL,
254 };
255 
256 /* ************ Spacetype/regiontype handling ************** */
257 
258 /* keep global; this has to be accessible outside of windowmanager */
259 static ListBase spacetypes = {NULL, NULL};
260 
261 /* not SpaceType itself */
spacetype_free(SpaceType * st)262 static void spacetype_free(SpaceType *st)
263 {
264   ARegionType *art;
265   PanelType *pt;
266   HeaderType *ht;
267 
268   for (art = st->regiontypes.first; art; art = art->next) {
269     BLI_freelistN(&art->drawcalls);
270 
271     for (pt = art->paneltypes.first; pt; pt = pt->next) {
272       if (pt->rna_ext.free) {
273         pt->rna_ext.free(pt->rna_ext.data);
274       }
275 
276       BLI_freelistN(&pt->children);
277     }
278 
279     for (ht = art->headertypes.first; ht; ht = ht->next) {
280       if (ht->rna_ext.free) {
281         ht->rna_ext.free(ht->rna_ext.data);
282       }
283     }
284 
285     BLI_freelistN(&art->paneltypes);
286     BLI_freelistN(&art->headertypes);
287   }
288 
289   BLI_freelistN(&st->regiontypes);
290 }
291 
BKE_spacetypes_free(void)292 void BKE_spacetypes_free(void)
293 {
294   SpaceType *st;
295 
296   for (st = spacetypes.first; st; st = st->next) {
297     spacetype_free(st);
298   }
299 
300   BLI_freelistN(&spacetypes);
301 }
302 
BKE_spacetype_from_id(int spaceid)303 SpaceType *BKE_spacetype_from_id(int spaceid)
304 {
305   SpaceType *st;
306 
307   for (st = spacetypes.first; st; st = st->next) {
308     if (st->spaceid == spaceid) {
309       return st;
310     }
311   }
312   return NULL;
313 }
314 
BKE_regiontype_from_id_or_first(SpaceType * st,int regionid)315 ARegionType *BKE_regiontype_from_id_or_first(SpaceType *st, int regionid)
316 {
317   ARegionType *art;
318 
319   for (art = st->regiontypes.first; art; art = art->next) {
320     if (art->regionid == regionid) {
321       return art;
322     }
323   }
324 
325   printf(
326       "Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
327   return st->regiontypes.first;
328 }
329 
BKE_regiontype_from_id(SpaceType * st,int regionid)330 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
331 {
332   ARegionType *art;
333 
334   for (art = st->regiontypes.first; art; art = art->next) {
335     if (art->regionid == regionid) {
336       return art;
337     }
338   }
339   return NULL;
340 }
341 
BKE_spacetypes_list(void)342 const ListBase *BKE_spacetypes_list(void)
343 {
344   return &spacetypes;
345 }
346 
BKE_spacetype_register(SpaceType * st)347 void BKE_spacetype_register(SpaceType *st)
348 {
349   SpaceType *stype;
350 
351   /* sanity check */
352   stype = BKE_spacetype_from_id(st->spaceid);
353   if (stype) {
354     printf("error: redefinition of spacetype %s\n", stype->name);
355     spacetype_free(stype);
356     MEM_freeN(stype);
357   }
358 
359   BLI_addtail(&spacetypes, st);
360 }
361 
BKE_spacetype_exists(int spaceid)362 bool BKE_spacetype_exists(int spaceid)
363 {
364   return BKE_spacetype_from_id(spaceid) != NULL;
365 }
366 
367 /* ***************** Space handling ********************** */
368 
BKE_spacedata_freelist(ListBase * lb)369 void BKE_spacedata_freelist(ListBase *lb)
370 {
371   SpaceLink *sl;
372   ARegion *region;
373 
374   for (sl = lb->first; sl; sl = sl->next) {
375     SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
376 
377     /* free regions for pushed spaces */
378     for (region = sl->regionbase.first; region; region = region->next) {
379       BKE_area_region_free(st, region);
380     }
381 
382     BLI_freelistN(&sl->regionbase);
383 
384     if (st && st->free) {
385       st->free(sl);
386     }
387   }
388 
389   BLI_freelistN(lb);
390 }
391 
panel_list_copy(ListBase * newlb,const ListBase * lb)392 static void panel_list_copy(ListBase *newlb, const ListBase *lb)
393 {
394   BLI_listbase_clear(newlb);
395   BLI_duplicatelist(newlb, lb);
396 
397   /* copy panel pointers */
398   Panel *new_panel = newlb->first;
399   Panel *panel = lb->first;
400   for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
401     new_panel->activedata = NULL;
402     new_panel->runtime.custom_data_ptr = NULL;
403     panel_list_copy(&new_panel->children, &panel->children);
404   }
405 }
406 
BKE_area_region_copy(SpaceType * st,ARegion * region)407 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *region)
408 {
409   ARegion *newar = MEM_dupallocN(region);
410 
411   newar->prev = newar->next = NULL;
412   BLI_listbase_clear(&newar->handlers);
413   BLI_listbase_clear(&newar->uiblocks);
414   BLI_listbase_clear(&newar->panels_category);
415   BLI_listbase_clear(&newar->panels_category_active);
416   BLI_listbase_clear(&newar->ui_lists);
417   newar->visible = 0;
418   newar->gizmo_map = NULL;
419   newar->regiontimer = NULL;
420   newar->headerstr = NULL;
421   newar->draw_buffer = NULL;
422 
423   /* use optional regiondata callback */
424   if (region->regiondata) {
425     ARegionType *art = BKE_regiontype_from_id(st, region->regiontype);
426 
427     if (art && art->duplicate) {
428       newar->regiondata = art->duplicate(region->regiondata);
429     }
430     else if (region->flag & RGN_FLAG_TEMP_REGIONDATA) {
431       newar->regiondata = NULL;
432     }
433     else {
434       newar->regiondata = MEM_dupallocN(region->regiondata);
435     }
436   }
437 
438   panel_list_copy(&newar->panels, &region->panels);
439 
440   BLI_listbase_clear(&newar->ui_previews);
441   BLI_duplicatelist(&newar->ui_previews, &region->ui_previews);
442 
443   return newar;
444 }
445 
446 /* from lb2 to lb1, lb1 is supposed to be freed */
region_copylist(SpaceType * st,ListBase * lb1,ListBase * lb2)447 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
448 {
449   ARegion *region;
450 
451   /* to be sure */
452   BLI_listbase_clear(lb1);
453 
454   for (region = lb2->first; region; region = region->next) {
455     ARegion *arnew = BKE_area_region_copy(st, region);
456     BLI_addtail(lb1, arnew);
457   }
458 }
459 
460 /* lb1 should be empty */
BKE_spacedata_copylist(ListBase * lb1,ListBase * lb2)461 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
462 {
463   SpaceLink *sl;
464 
465   BLI_listbase_clear(lb1); /* to be sure */
466 
467   for (sl = lb2->first; sl; sl = sl->next) {
468     SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
469 
470     if (st && st->duplicate) {
471       SpaceLink *slnew = st->duplicate(sl);
472 
473       BLI_addtail(lb1, slnew);
474 
475       region_copylist(st, &slnew->regionbase, &sl->regionbase);
476     }
477   }
478 }
479 
480 /* facility to set locks for drawing to survive (render) threads accessing drawing data */
481 /* lock can become bitflag too */
482 /* should be replaced in future by better local data handling for threads */
BKE_spacedata_draw_locks(int set)483 void BKE_spacedata_draw_locks(int set)
484 {
485   SpaceType *st;
486 
487   for (st = spacetypes.first; st; st = st->next) {
488     ARegionType *art;
489 
490     for (art = st->regiontypes.first; art; art = art->next) {
491       if (set) {
492         art->do_lock = art->lock;
493       }
494       else {
495         art->do_lock = false;
496       }
497     }
498   }
499 }
500 
501 /**
502  * Version of #BKE_area_find_region_type that also works if \a slink
503  * is not the active space of \a area.
504  */
BKE_spacedata_find_region_type(const SpaceLink * slink,const ScrArea * area,int region_type)505 ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
506                                         const ScrArea *area,
507                                         int region_type)
508 {
509   const bool is_slink_active = slink == area->spacedata.first;
510   const ListBase *regionbase = (is_slink_active) ? &area->regionbase : &slink->regionbase;
511   ARegion *region = NULL;
512 
513   BLI_assert(BLI_findindex(&area->spacedata, slink) != -1);
514   for (region = regionbase->first; region; region = region->next) {
515     if (region->regiontype == region_type) {
516       break;
517     }
518   }
519 
520   /* Should really unit test this instead. */
521   BLI_assert(!is_slink_active || region == BKE_area_find_region_type(area, region_type));
522 
523   return region;
524 }
525 
526 static void (*spacedata_id_remap_cb)(struct ScrArea *area,
527                                      struct SpaceLink *sl,
528                                      ID *old_id,
529                                      ID *new_id) = NULL;
530 
BKE_spacedata_callback_id_remap_set(void (* func)(ScrArea * area,SpaceLink * sl,ID *,ID *))531 void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *sl, ID *, ID *))
532 {
533   spacedata_id_remap_cb = func;
534 }
535 
536 /* UNUSED!!! */
BKE_spacedata_id_unref(struct ScrArea * area,struct SpaceLink * sl,struct ID * id)537 void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
538 {
539   if (spacedata_id_remap_cb) {
540     spacedata_id_remap_cb(area, sl, id, NULL);
541   }
542 }
543 
544 /**
545  * Avoid bad-level calls to #WM_gizmomap_tag_refresh.
546  */
547 static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
548 
BKE_region_callback_refresh_tag_gizmomap_set(void (* callback)(struct wmGizmoMap *))549 void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
550 {
551   region_refresh_tag_gizmomap_callback = callback;
552 }
553 
BKE_screen_gizmo_tag_refresh(struct bScreen * screen)554 void BKE_screen_gizmo_tag_refresh(struct bScreen *screen)
555 {
556   if (region_refresh_tag_gizmomap_callback == NULL) {
557     return;
558   }
559 
560   ScrArea *area;
561   ARegion *region;
562   for (area = screen->areabase.first; area; area = area->next) {
563     for (region = area->regionbase.first; region; region = region->next) {
564       if (region->gizmo_map != NULL) {
565         region_refresh_tag_gizmomap_callback(region->gizmo_map);
566       }
567     }
568   }
569 }
570 
571 /**
572  * Avoid bad-level calls to #WM_gizmomap_delete.
573  */
574 static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
575 
BKE_region_callback_free_gizmomap_set(void (* callback)(struct wmGizmoMap *))576 void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
577 {
578   region_free_gizmomap_callback = callback;
579 }
580 
area_region_panels_free_recursive(Panel * panel)581 static void area_region_panels_free_recursive(Panel *panel)
582 {
583   MEM_SAFE_FREE(panel->activedata);
584 
585   LISTBASE_FOREACH_MUTABLE (Panel *, child_panel, &panel->children) {
586     area_region_panels_free_recursive(child_panel);
587   }
588 
589   MEM_freeN(panel);
590 }
591 
BKE_area_region_panels_free(ListBase * panels)592 void BKE_area_region_panels_free(ListBase *panels)
593 {
594   LISTBASE_FOREACH_MUTABLE (Panel *, panel, panels) {
595     /* Free custom data just for parent panels to avoid a double free. */
596     MEM_SAFE_FREE(panel->runtime.custom_data_ptr);
597     area_region_panels_free_recursive(panel);
598   }
599   BLI_listbase_clear(panels);
600 }
601 
602 /* not region itself */
BKE_area_region_free(SpaceType * st,ARegion * region)603 void BKE_area_region_free(SpaceType *st, ARegion *region)
604 {
605   uiList *uilst;
606 
607   if (st) {
608     ARegionType *art = BKE_regiontype_from_id(st, region->regiontype);
609 
610     if (art && art->free) {
611       art->free(region);
612     }
613 
614     if (region->regiondata) {
615       printf("regiondata free error\n");
616     }
617   }
618   else if (region->type && region->type->free) {
619     region->type->free(region);
620   }
621 
622   BKE_area_region_panels_free(&region->panels);
623 
624   for (uilst = region->ui_lists.first; uilst; uilst = uilst->next) {
625     if (uilst->dyn_data) {
626       uiListDyn *dyn_data = uilst->dyn_data;
627       if (dyn_data->items_filter_flags) {
628         MEM_freeN(dyn_data->items_filter_flags);
629       }
630       if (dyn_data->items_filter_neworder) {
631         MEM_freeN(dyn_data->items_filter_neworder);
632       }
633       MEM_freeN(dyn_data);
634     }
635     if (uilst->properties) {
636       IDP_FreeProperty(uilst->properties);
637     }
638   }
639 
640   if (region->gizmo_map != NULL) {
641     region_free_gizmomap_callback(region->gizmo_map);
642   }
643 
644   BLI_freelistN(&region->ui_lists);
645   BLI_freelistN(&region->ui_previews);
646   BLI_freelistN(&region->panels_category);
647   BLI_freelistN(&region->panels_category_active);
648 }
649 
650 /* not area itself */
BKE_screen_area_free(ScrArea * area)651 void BKE_screen_area_free(ScrArea *area)
652 {
653   SpaceType *st = BKE_spacetype_from_id(area->spacetype);
654   ARegion *region;
655 
656   for (region = area->regionbase.first; region; region = region->next) {
657     BKE_area_region_free(st, region);
658   }
659 
660   MEM_SAFE_FREE(area->global);
661   BLI_freelistN(&area->regionbase);
662 
663   BKE_spacedata_freelist(&area->spacedata);
664 
665   BLI_freelistN(&area->actionzones);
666 }
667 
BKE_screen_area_map_free(ScrAreaMap * area_map)668 void BKE_screen_area_map_free(ScrAreaMap *area_map)
669 {
670   for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
671     area_next = area->next;
672     BKE_screen_area_free(area);
673   }
674 
675   BLI_freelistN(&area_map->vertbase);
676   BLI_freelistN(&area_map->edgebase);
677   BLI_freelistN(&area_map->areabase);
678 }
679 
680 /** Free (or release) any data used by this screen (does not free the screen itself). */
BKE_screen_free(bScreen * screen)681 void BKE_screen_free(bScreen *screen)
682 {
683   screen_free_data(&screen->id);
684 }
685 
686 /* ***************** Screen edges & verts ***************** */
687 
BKE_screen_find_edge(const bScreen * screen,ScrVert * v1,ScrVert * v2)688 ScrEdge *BKE_screen_find_edge(const bScreen *screen, ScrVert *v1, ScrVert *v2)
689 {
690   ScrEdge *se;
691 
692   BKE_screen_sort_scrvert(&v1, &v2);
693   for (se = screen->edgebase.first; se; se = se->next) {
694     if (se->v1 == v1 && se->v2 == v2) {
695       return se;
696     }
697   }
698 
699   return NULL;
700 }
701 
BKE_screen_sort_scrvert(ScrVert ** v1,ScrVert ** v2)702 void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
703 {
704   ScrVert *tmp;
705 
706   if (*v1 > *v2) {
707     tmp = *v1;
708     *v1 = *v2;
709     *v2 = tmp;
710   }
711 }
712 
BKE_screen_remove_double_scrverts(bScreen * screen)713 void BKE_screen_remove_double_scrverts(bScreen *screen)
714 {
715   ScrVert *v1, *verg;
716   ScrEdge *se;
717   ScrArea *area;
718 
719   verg = screen->vertbase.first;
720   while (verg) {
721     if (verg->newv == NULL) { /* !!! */
722       v1 = verg->next;
723       while (v1) {
724         if (v1->newv == NULL) { /* !?! */
725           if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
726             /* printf("doublevert\n"); */
727             v1->newv = verg;
728           }
729         }
730         v1 = v1->next;
731       }
732     }
733     verg = verg->next;
734   }
735 
736   /* replace pointers in edges and faces */
737   se = screen->edgebase.first;
738   while (se) {
739     if (se->v1->newv) {
740       se->v1 = se->v1->newv;
741     }
742     if (se->v2->newv) {
743       se->v2 = se->v2->newv;
744     }
745     /* edges changed: so.... */
746     BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
747     se = se->next;
748   }
749   area = screen->areabase.first;
750   while (area) {
751     if (area->v1->newv) {
752       area->v1 = area->v1->newv;
753     }
754     if (area->v2->newv) {
755       area->v2 = area->v2->newv;
756     }
757     if (area->v3->newv) {
758       area->v3 = area->v3->newv;
759     }
760     if (area->v4->newv) {
761       area->v4 = area->v4->newv;
762     }
763     area = area->next;
764   }
765 
766   /* remove */
767   verg = screen->vertbase.first;
768   while (verg) {
769     v1 = verg->next;
770     if (verg->newv) {
771       BLI_remlink(&screen->vertbase, verg);
772       MEM_freeN(verg);
773     }
774     verg = v1;
775   }
776 }
777 
BKE_screen_remove_double_scredges(bScreen * screen)778 void BKE_screen_remove_double_scredges(bScreen *screen)
779 {
780   ScrEdge *verg, *se, *sn;
781 
782   /* compare */
783   verg = screen->edgebase.first;
784   while (verg) {
785     se = verg->next;
786     while (se) {
787       sn = se->next;
788       if (verg->v1 == se->v1 && verg->v2 == se->v2) {
789         BLI_remlink(&screen->edgebase, se);
790         MEM_freeN(se);
791       }
792       se = sn;
793     }
794     verg = verg->next;
795   }
796 }
797 
BKE_screen_remove_unused_scredges(bScreen * screen)798 void BKE_screen_remove_unused_scredges(bScreen *screen)
799 {
800   ScrEdge *se, *sen;
801   ScrArea *area;
802   int a = 0;
803 
804   /* sets flags when edge is used in area */
805   area = screen->areabase.first;
806   while (area) {
807     se = BKE_screen_find_edge(screen, area->v1, area->v2);
808     if (se == NULL) {
809       printf("error: area %d edge 1 doesn't exist\n", a);
810     }
811     else {
812       se->flag = 1;
813     }
814     se = BKE_screen_find_edge(screen, area->v2, area->v3);
815     if (se == NULL) {
816       printf("error: area %d edge 2 doesn't exist\n", a);
817     }
818     else {
819       se->flag = 1;
820     }
821     se = BKE_screen_find_edge(screen, area->v3, area->v4);
822     if (se == NULL) {
823       printf("error: area %d edge 3 doesn't exist\n", a);
824     }
825     else {
826       se->flag = 1;
827     }
828     se = BKE_screen_find_edge(screen, area->v4, area->v1);
829     if (se == NULL) {
830       printf("error: area %d edge 4 doesn't exist\n", a);
831     }
832     else {
833       se->flag = 1;
834     }
835     area = area->next;
836     a++;
837   }
838   se = screen->edgebase.first;
839   while (se) {
840     sen = se->next;
841     if (se->flag == 0) {
842       BLI_remlink(&screen->edgebase, se);
843       MEM_freeN(se);
844     }
845     else {
846       se->flag = 0;
847     }
848     se = sen;
849   }
850 }
851 
BKE_screen_remove_unused_scrverts(bScreen * screen)852 void BKE_screen_remove_unused_scrverts(bScreen *screen)
853 {
854   ScrVert *sv, *svn;
855   ScrEdge *se;
856 
857   /* we assume edges are ok */
858 
859   se = screen->edgebase.first;
860   while (se) {
861     se->v1->flag = 1;
862     se->v2->flag = 1;
863     se = se->next;
864   }
865 
866   sv = screen->vertbase.first;
867   while (sv) {
868     svn = sv->next;
869     if (sv->flag == 0) {
870       BLI_remlink(&screen->vertbase, sv);
871       MEM_freeN(sv);
872     }
873     else {
874       sv->flag = 0;
875     }
876     sv = svn;
877   }
878 }
879 
880 /* ***************** Utilities ********************** */
881 
882 /**
883  * Find a region of type \a region_type in the currently active space of \a area.
884  *
885  * \note This does _not_ work if the region to look up is not in the active
886  *       space. Use #BKE_spacedata_find_region_type if that may be the case.
887  */
BKE_area_find_region_type(const ScrArea * area,int region_type)888 ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
889 {
890   if (area) {
891     LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
892       if (region->regiontype == region_type) {
893         return region;
894       }
895     }
896   }
897 
898   return NULL;
899 }
900 
BKE_area_find_region_active_win(ScrArea * area)901 ARegion *BKE_area_find_region_active_win(ScrArea *area)
902 {
903   if (area) {
904     ARegion *region = BLI_findlink(&area->regionbase, area->region_active_win);
905     if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
906       return region;
907     }
908 
909     /* fallback to any */
910     return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
911   }
912   return NULL;
913 }
914 
BKE_area_find_region_xy(ScrArea * area,const int regiontype,int x,int y)915 ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
916 {
917   ARegion *region_found = NULL;
918   if (area) {
919     ARegion *region;
920     for (region = area->regionbase.first; region; region = region->next) {
921       if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
922         if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
923           region_found = region;
924           break;
925         }
926       }
927     }
928   }
929   return region_found;
930 }
931 
932 /**
933  * \note This is only for screen level regions (typically menus/popups).
934  */
BKE_screen_find_region_xy(bScreen * screen,const int regiontype,int x,int y)935 ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
936 {
937   ARegion *region_found = NULL;
938   LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
939     if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
940       if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
941         region_found = region;
942         break;
943       }
944     }
945   }
946   return region_found;
947 }
948 
949 /**
950  * \note Ideally we can get the area from the context,
951  * there are a few places however where this isn't practical.
952  */
BKE_screen_find_area_from_space(struct bScreen * screen,SpaceLink * sl)953 ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
954 {
955   ScrArea *area;
956 
957   for (area = screen->areabase.first; area; area = area->next) {
958     if (BLI_findindex(&area->spacedata, sl) != -1) {
959       break;
960     }
961   }
962 
963   return area;
964 }
965 
966 /**
967  * \note Using this function is generally a last resort, you really want to be
968  * using the context when you can - campbell
969  */
BKE_screen_find_big_area(bScreen * screen,const int spacetype,const short min)970 ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
971 {
972   ScrArea *area, *big = NULL;
973   int size, maxsize = 0;
974 
975   for (area = screen->areabase.first; area; area = area->next) {
976     if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
977       if (min <= area->winx && min <= area->winy) {
978         size = area->winx * area->winy;
979         if (size > maxsize) {
980           maxsize = size;
981           big = area;
982         }
983       }
984     }
985   }
986 
987   return big;
988 }
989 
BKE_screen_area_map_find_area_xy(const ScrAreaMap * areamap,const int spacetype,int x,int y)990 ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
991                                           const int spacetype,
992                                           int x,
993                                           int y)
994 {
995   LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
996     if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
997       if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
998         return area;
999       }
1000       break;
1001     }
1002   }
1003   return NULL;
1004 }
BKE_screen_find_area_xy(bScreen * screen,const int spacetype,int x,int y)1005 ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
1006 {
1007   return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
1008 }
1009 
BKE_screen_view3d_sync(View3D * v3d,struct Scene * scene)1010 void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
1011 {
1012   if (v3d->scenelock && v3d->localvd == NULL) {
1013     v3d->camera = scene->camera;
1014 
1015     if (v3d->camera == NULL) {
1016       ARegion *region;
1017 
1018       for (region = v3d->regionbase.first; region; region = region->next) {
1019         if (region->regiontype == RGN_TYPE_WINDOW) {
1020           RegionView3D *rv3d = region->regiondata;
1021           if (rv3d->persp == RV3D_CAMOB) {
1022             rv3d->persp = RV3D_PERSP;
1023           }
1024         }
1025       }
1026     }
1027   }
1028 }
1029 
BKE_screen_view3d_scene_sync(bScreen * screen,Scene * scene)1030 void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
1031 {
1032   /* are there cameras in the views that are not in the scene? */
1033   ScrArea *area;
1034   for (area = screen->areabase.first; area; area = area->next) {
1035     SpaceLink *sl;
1036     for (sl = area->spacedata.first; sl; sl = sl->next) {
1037       if (sl->spacetype == SPACE_VIEW3D) {
1038         View3D *v3d = (View3D *)sl;
1039         BKE_screen_view3d_sync(v3d, scene);
1040       }
1041     }
1042   }
1043 }
1044 
BKE_screen_view3d_shading_init(View3DShading * shading)1045 void BKE_screen_view3d_shading_init(View3DShading *shading)
1046 {
1047   const View3DShading *shading_default = DNA_struct_default_get(View3DShading);
1048   memcpy(shading, shading_default, sizeof(*shading));
1049 }
1050 
BKE_screen_find_main_region_at_xy(bScreen * screen,const int space_type,const int x,const int y)1051 ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
1052                                            const int space_type,
1053                                            const int x,
1054                                            const int y)
1055 {
1056   ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y);
1057   if (!area) {
1058     return NULL;
1059   }
1060   return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
1061 }
1062 
1063 /* magic zoom calculation, no idea what
1064  * it signifies, if you find out, tell me! -zr
1065  */
1066 
1067 /* simple, its magic dude!
1068  * well, to be honest, this gives a natural feeling zooming
1069  * with multiple keypad presses (ton)
1070  */
BKE_screen_view3d_zoom_to_fac(float camzoom)1071 float BKE_screen_view3d_zoom_to_fac(float camzoom)
1072 {
1073   return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
1074 }
1075 
BKE_screen_view3d_zoom_from_fac(float zoomfac)1076 float BKE_screen_view3d_zoom_from_fac(float zoomfac)
1077 {
1078   return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
1079 }
1080 
BKE_screen_is_fullscreen_area(const bScreen * screen)1081 bool BKE_screen_is_fullscreen_area(const bScreen *screen)
1082 {
1083   return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
1084 }
1085 
BKE_screen_is_used(const bScreen * screen)1086 bool BKE_screen_is_used(const bScreen *screen)
1087 {
1088   return (screen->winid != 0);
1089 }
1090 
BKE_screen_header_alignment_reset(bScreen * screen)1091 void BKE_screen_header_alignment_reset(bScreen *screen)
1092 {
1093   int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
1094   LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1095     LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1096       if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1097         if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
1098           region->alignment = RGN_ALIGN_TOP;
1099           continue;
1100         }
1101         region->alignment = alignment;
1102       }
1103       if (region->regiontype == RGN_TYPE_FOOTER) {
1104         if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
1105           region->alignment = RGN_ALIGN_BOTTOM;
1106           continue;
1107         }
1108         region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
1109       }
1110     }
1111   }
1112   screen->do_refresh = true;
1113 }
1114