Blender  V2.93
buttons_context.c
Go to the documentation of this file.
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) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "BLI_listbase.h"
30 #include "BLI_utildefines.h"
31 
32 #include "BLT_translation.h"
33 
34 #include "DNA_armature_types.h"
35 #include "DNA_brush_types.h"
36 #include "DNA_collection_types.h"
37 #include "DNA_linestyle_types.h"
38 #include "DNA_material_types.h"
39 #include "DNA_node_types.h"
40 #include "DNA_scene_types.h"
42 #include "DNA_world_types.h"
43 
44 #include "BKE_action.h"
45 #include "BKE_armature.h"
46 #include "BKE_context.h"
47 #include "BKE_layer.h"
48 #include "BKE_linestyle.h"
49 #include "BKE_material.h"
50 #include "BKE_modifier.h"
51 #include "BKE_object.h"
52 #include "BKE_paint.h"
53 #include "BKE_particle.h"
54 #include "BKE_screen.h"
55 
56 #include "RNA_access.h"
57 
58 #include "ED_buttons.h"
59 #include "ED_physics.h"
60 #include "ED_screen.h"
61 
62 #include "UI_interface.h"
63 #include "UI_resources.h"
64 
65 #include "WM_api.h"
66 
67 #include "buttons_intern.h" /* own include */
68 
70 {
71  for (int i = 0; i < path->len; i++) {
72  PointerRNA *ptr = &path->ptr[i];
73 
74  if (RNA_struct_is_a(ptr->type, type)) {
76  return CTX_RESULT_OK;
77  }
78  }
79 
81 }
82 
84 {
85  for (int i = 0; i < path->len; i++) {
86  PointerRNA *ptr = &path->ptr[i];
87 
88  if (RNA_struct_is_a(ptr->type, type)) {
89  return ptr;
90  }
91  }
92 
93  return NULL;
94 }
95 
96 /************************* Creating the Path ************************/
97 
99 {
100  PointerRNA *ptr = &path->ptr[path->len - 1];
101 
102  /* this one just verifies */
103  return RNA_struct_is_a(ptr->type, &RNA_Scene);
104 }
105 
107 {
108  PointerRNA *ptr = &path->ptr[path->len - 1];
109 
110  /* View Layer may have already been resolved in a previous call
111  * (e.g. in buttons_context_path_linestyle). */
113  return true;
114  }
115 
116  if (buttons_context_path_scene(path)) {
117  Scene *scene = path->ptr[path->len - 1].data;
118  ViewLayer *view_layer = (win->scene == scene) ? WM_window_get_active_view_layer(win) :
120 
121  RNA_pointer_create(&scene->id, &RNA_ViewLayer, view_layer, &path->ptr[path->len]);
122  path->len++;
123  return true;
124  }
125 
126  return false;
127 }
128 
129 /* note: this function can return true without adding a world to the path
130  * so the buttons stay visible, but be sure to check the ID type if a ID_WO */
132 {
133  PointerRNA *ptr = &path->ptr[path->len - 1];
134 
135  /* if we already have a (pinned) world, we're done */
136  if (RNA_struct_is_a(ptr->type, &RNA_World)) {
137  return true;
138  }
139  /* if we have a scene, use the scene's world */
140  if (buttons_context_path_scene(path)) {
141  Scene *scene = path->ptr[path->len - 1].data;
142  World *world = scene->world;
143 
144  if (world) {
145  RNA_id_pointer_create(&scene->world->id, &path->ptr[path->len]);
146  path->len++;
147  return true;
148  }
149 
150  return true;
151  }
152 
153  /* no path to a world possible */
154  return false;
155 }
156 
158  ButsContextPath *path,
159  wmWindow *window)
160 {
161  PointerRNA *ptr = &path->ptr[path->len - 1];
162 
163  /* if we already have a (pinned) collection, we're done */
165  return true;
166  }
167 
169 
170  /* if we have a view layer, use the view layer's active collection */
171  if (buttons_context_path_view_layer(path, window)) {
172  ViewLayer *view_layer = path->ptr[path->len - 1].data;
173  Collection *c = view_layer->active_collection->collection;
174 
175  /* Do not show collection tab for master collection. */
176  if (c == scene->master_collection) {
177  return false;
178  }
179 
180  if (c) {
181  RNA_id_pointer_create(&c->id, &path->ptr[path->len]);
182  path->len++;
183  return true;
184  }
185  }
186 
187  /* no path to a collection possible */
188  return false;
189 }
190 
192 {
193  PointerRNA *ptr = &path->ptr[path->len - 1];
194 
195  /* if we already have a (pinned) linestyle, we're done */
197  return true;
198  }
199  /* if we have a view layer, use the lineset's linestyle */
200  if (buttons_context_path_view_layer(path, window)) {
201  ViewLayer *view_layer = path->ptr[path->len - 1].data;
203  if (linestyle) {
204  RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]);
205  path->len++;
206  return true;
207  }
208  }
209 
210  /* no path to a linestyle possible */
211  return false;
212 }
213 
215 {
216  PointerRNA *ptr = &path->ptr[path->len - 1];
217 
218  /* if we already have a (pinned) object, we're done */
220  return true;
221  }
223  return false;
224  }
225 
226  ViewLayer *view_layer = ptr->data;
227  Object *ob = (view_layer->basact) ? view_layer->basact->object : NULL;
228 
229  if (ob) {
230  RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
231  path->len++;
232 
233  return true;
234  }
235 
236  /* no path to a object possible */
237  return false;
238 }
239 
241 {
242  PointerRNA *ptr = &path->ptr[path->len - 1];
243 
244  /* if we already have a data, we're done */
245  if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) {
246  return true;
247  }
248  if (RNA_struct_is_a(ptr->type, &RNA_Curve) &&
249  (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) {
250  return true;
251  }
252  if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) {
253  return true;
254  }
255  if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) {
256  return true;
257  }
258  if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) {
259  return true;
260  }
261  if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) {
262  return true;
263  }
264  if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) {
265  return true;
266  }
267  if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) {
268  return true;
269  }
270  if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) {
271  return true;
272  }
273  if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) {
274  return true;
275  }
276 #ifdef WITH_HAIR_NODES
277  if (RNA_struct_is_a(ptr->type, &RNA_Hair) && (type == -1 || type == OB_HAIR)) {
278  return true;
279  }
280 #endif
281 #ifdef WITH_POINT_CLOUD
282  if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) {
283  return true;
284  }
285 #endif
286  if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) {
287  return true;
288  }
289  /* try to get an object in the path, no pinning supported here */
290  if (buttons_context_path_object(path)) {
291  Object *ob = path->ptr[path->len - 1].data;
292 
293  if (ob && (type == -1 || type == ob->type)) {
294  RNA_id_pointer_create(ob->data, &path->ptr[path->len]);
295  path->len++;
296 
297  return true;
298  }
299  }
300 
301  /* no path to data possible */
302  return false;
303 }
304 
306 {
307  if (buttons_context_path_object(path)) {
308  Object *ob = path->ptr[path->len - 1].data;
309 
310  if (ELEM(ob->type,
311  OB_MESH,
312  OB_CURVE,
313  OB_FONT,
314  OB_SURF,
315  OB_LATTICE,
316  OB_GPENCIL,
317  OB_HAIR,
319  OB_VOLUME)) {
321  if (md != NULL) {
322  RNA_pointer_create(&ob->id, &RNA_Modifier, md, &path->ptr[path->len]);
323  path->len++;
324  }
325 
326  return true;
327  }
328  }
329 
330  return false;
331 }
332 
334 {
335  if (buttons_context_path_object(path)) {
336  Object *ob = path->ptr[path->len - 1].data;
337 
338  if (ob && ELEM(ob->type, OB_GPENCIL)) {
339  return true;
340  }
341  }
342 
343  return false;
344 }
345 
347 {
348  PointerRNA *ptr = &path->ptr[path->len - 1];
349 
350  /* if we already have a (pinned) material, we're done */
352  return true;
353  }
354  /* if we have an object, use the object material slot */
355  if (buttons_context_path_object(path)) {
356  Object *ob = path->ptr[path->len - 1].data;
357 
358  if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
359  Material *ma = BKE_object_material_get(ob, ob->actcol);
360  if (ma != NULL) {
361  RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
362  path->len++;
363  }
364  return true;
365  }
366  }
367 
368  /* no path to a material possible */
369  return false;
370 }
371 
373 {
374  /* if we have an armature, get the active bone */
376  bArmature *arm = path->ptr[path->len - 1].data;
377 
378  if (arm->edbo) {
379  if (arm->act_edbone) {
380  EditBone *edbo = arm->act_edbone;
381  RNA_pointer_create(&arm->id, &RNA_EditBone, edbo, &path->ptr[path->len]);
382  path->len++;
383  return true;
384  }
385  }
386  else {
387  if (arm->act_bone) {
388  RNA_pointer_create(&arm->id, &RNA_Bone, arm->act_bone, &path->ptr[path->len]);
389  path->len++;
390  return true;
391  }
392  }
393  }
394 
395  /* no path to a bone possible */
396  return false;
397 }
398 
400 {
401  PointerRNA *ptr = &path->ptr[path->len - 1];
402 
403  /* if we already have a (pinned) PoseBone, we're done */
405  return true;
406  }
407 
408  /* if we have an armature, get the active bone */
409  if (buttons_context_path_object(path)) {
410  Object *ob = path->ptr[path->len - 1].data;
411  bArmature *arm = ob->data; /* path->ptr[path->len-1].data - works too */
412 
413  if (ob->type != OB_ARMATURE || arm->edbo) {
414  return false;
415  }
416 
417  if (arm->act_bone) {
419  if (pchan) {
420  RNA_pointer_create(&ob->id, &RNA_PoseBone, pchan, &path->ptr[path->len]);
421  path->len++;
422  return true;
423  }
424  }
425  }
426 
427  /* no path to a bone possible */
428  return false;
429 }
430 
432 {
433  PointerRNA *ptr = &path->ptr[path->len - 1];
434 
435  /* if we already have (pinned) particle settings, we're done */
437  return true;
438  }
439  /* if we have an object, get the active particle system */
440  if (buttons_context_path_object(path)) {
441  Object *ob = path->ptr[path->len - 1].data;
442 
443  if (ob && ob->type == OB_MESH) {
444  ParticleSystem *psys = psys_get_current(ob);
445 
446  RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &path->ptr[path->len]);
447  path->len++;
448  return true;
449  }
450  }
451 
452  /* no path to a particle system possible */
453  return false;
454 }
455 
457 {
458  PointerRNA *ptr = &path->ptr[path->len - 1];
459 
460  /* if we already have a (pinned) brush, we're done */
461  if (RNA_struct_is_a(ptr->type, &RNA_Brush)) {
462  return true;
463  }
464  /* if we have a scene, use the toolsettings brushes */
465  if (buttons_context_path_scene(path)) {
466  Scene *scene = path->ptr[path->len - 1].data;
467 
468  Brush *br = NULL;
469  if (scene) {
470  wmWindow *window = CTX_wm_window(C);
471  ViewLayer *view_layer = WM_window_get_active_view_layer(window);
472  br = BKE_paint_brush(BKE_paint_get_active(scene, view_layer));
473  }
474 
475  if (br) {
476  RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
477  path->len++;
478 
479  return true;
480  }
481  }
482 
483  /* no path to a brush possible */
484  return false;
485 }
486 
488  ButsContextPath *path,
489  ButsContextTexture *ct)
490 {
491  PointerRNA *ptr = &path->ptr[path->len - 1];
492 
493  if (!ct) {
494  return false;
495  }
496 
497  /* if we already have a (pinned) texture, we're done */
499  return true;
500  }
501 
502  if (!ct->user) {
503  return false;
504  }
505 
506  ID *id = ct->user->id;
507 
508  if (id) {
509  if (GS(id->name) == ID_BR) {
511  }
512  else if (GS(id->name) == ID_PA) {
514  }
515  else if (GS(id->name) == ID_OB) {
517  }
518  else if (GS(id->name) == ID_LS) {
520  }
521  }
522 
523  if (ct->texture) {
524  RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
525  path->len++;
526  }
527 
528  return true;
529 }
530 
531 #ifdef WITH_FREESTYLE
532 static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *view_layer)
533 {
534  wmWindow *window = CTX_wm_window(C);
536 
537  /* if Freestyle is disabled in the scene */
538  if ((scene->r.mode & R_EDGE_FRS) == 0) {
539  return false;
540  }
541  /* if Freestyle is not in the Parameter Editor mode */
542  FreestyleConfig *config = &view_layer->freestyle_config;
543  if (config->mode != FREESTYLE_CONTROL_EDITOR_MODE) {
544  return false;
545  }
546  /* if the scene has already been pinned */
548  if (sbuts->pinid && sbuts->pinid == &scene->id) {
549  return false;
550  }
551  return true;
552 }
553 #endif
554 
556  const bContext *C, SpaceProperties *sbuts, ButsContextPath *path, int mainb, int flag)
557 {
558  /* Note we don't use CTX_data here, instead we get it from the window.
559  * Otherwise there is a loop reading the context that we are setting. */
560  wmWindow *window = CTX_wm_window(C);
562  ViewLayer *view_layer = WM_window_get_active_view_layer(window);
563 
564  memset(path, 0, sizeof(*path));
565  path->flag = flag;
566 
567  /* If some ID datablock is pinned, set the root pointer. */
568  if (sbuts->pinid) {
569  ID *id = sbuts->pinid;
570 
571  RNA_id_pointer_create(id, &path->ptr[0]);
572  path->len++;
573  }
574  /* No pinned root, use scene as initial root. */
575  else if (mainb != BCONTEXT_TOOL) {
576  RNA_id_pointer_create(&scene->id, &path->ptr[0]);
577  path->len++;
578 
579  if (!ELEM(mainb,
584  BCONTEXT_WORLD)) {
585  RNA_pointer_create(NULL, &RNA_ViewLayer, view_layer, &path->ptr[path->len]);
586  path->len++;
587  }
588  }
589 
590  /* now for each buttons context type, we try to construct a path,
591  * tracing back recursively */
592  bool found;
593  switch (mainb) {
594  case BCONTEXT_SCENE:
595  case BCONTEXT_RENDER:
596  case BCONTEXT_OUTPUT:
597  found = buttons_context_path_scene(path);
598  break;
599  case BCONTEXT_VIEW_LAYER:
600 #ifdef WITH_FREESTYLE
601  if (buttons_context_linestyle_pinnable(C, view_layer)) {
602  found = buttons_context_path_linestyle(path, window);
603  if (found) {
604  break;
605  }
606  }
607 #endif
608  found = buttons_context_path_view_layer(path, window);
609  break;
610  case BCONTEXT_WORLD:
611  found = buttons_context_path_world(path);
612  break;
613  case BCONTEXT_COLLECTION: /* This is for Line Art collection flags */
614  found = buttons_context_path_collection(C, path, window);
615  break;
616  case BCONTEXT_TOOL:
617  found = true;
618  break;
619  case BCONTEXT_OBJECT:
620  case BCONTEXT_PHYSICS:
621  case BCONTEXT_CONSTRAINT:
622  found = buttons_context_path_object(path);
623  break;
624  case BCONTEXT_MODIFIER:
625  found = buttons_context_path_modifier(path);
626  break;
627  case BCONTEXT_SHADERFX:
628  found = buttons_context_path_shaderfx(path);
629  break;
630  case BCONTEXT_DATA:
631  found = buttons_context_path_data(path, -1);
632  break;
633  case BCONTEXT_PARTICLE:
634  found = buttons_context_path_particle(path);
635  break;
636  case BCONTEXT_MATERIAL:
637  found = buttons_context_path_material(path);
638  break;
639  case BCONTEXT_TEXTURE:
640  found = buttons_context_path_texture(C, path, sbuts->texuser);
641  break;
642  case BCONTEXT_BONE:
643  found = buttons_context_path_bone(path);
644  if (!found) {
645  found = buttons_context_path_data(path, OB_ARMATURE);
646  }
647  break;
649  found = buttons_context_path_pose_bone(path);
650  break;
651  default:
652  found = false;
653  break;
654  }
655 
656  return found;
657 }
658 
659 static bool buttons_shading_context(const bContext *C, int mainb)
660 {
661  wmWindow *window = CTX_wm_window(C);
662  ViewLayer *view_layer = WM_window_get_active_view_layer(window);
663  Object *ob = OBACT(view_layer);
664 
666  return true;
667  }
668  if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA)) {
669  return true;
670  }
671 
672  return false;
673 }
674 
675 static int buttons_shading_new_context(const bContext *C, int flag)
676 {
677  wmWindow *window = CTX_wm_window(C);
678  ViewLayer *view_layer = WM_window_get_active_view_layer(window);
679  Object *ob = OBACT(view_layer);
680 
681  if (flag & (1 << BCONTEXT_MATERIAL)) {
682  return BCONTEXT_MATERIAL;
683  }
684  if (ob && ELEM(ob->type, OB_LAMP, OB_CAMERA) && (flag & (1 << BCONTEXT_DATA))) {
685  return BCONTEXT_DATA;
686  }
687  if (flag & (1 << BCONTEXT_WORLD)) {
688  return BCONTEXT_WORLD;
689  }
690 
691  return BCONTEXT_RENDER;
692 }
693 
695 {
696  if (!sbuts->path) {
697  sbuts->path = MEM_callocN(sizeof(ButsContextPath), "ButsContextPath");
698  }
699 
700  ButsContextPath *path = sbuts->path;
701 
702  int pflag = 0;
703  int flag = 0;
704 
705  /* Set scene path. */
706  buttons_context_path(C, sbuts, path, BCONTEXT_SCENE, pflag);
707 
709 
710  /* for each context, see if we can compute a valid path to it, if
711  * this is the case, we know we have to display the button */
712  for (int i = 0; i < BCONTEXT_TOT; i++) {
713  if (buttons_context_path(C, sbuts, path, i, pflag)) {
714  flag |= (1 << i);
715 
716  /* setting icon for data context */
717  if (i == BCONTEXT_DATA) {
718  PointerRNA *ptr = &path->ptr[path->len - 1];
719 
720  if (ptr->type) {
721  if (RNA_struct_is_a(ptr->type, &RNA_Light)) {
722  sbuts->dataicon = ICON_OUTLINER_DATA_LIGHT;
723  }
724  else {
725  sbuts->dataicon = RNA_struct_ui_icon(ptr->type);
726  }
727  }
728  else {
729  sbuts->dataicon = ICON_EMPTY_DATA;
730  }
731  }
732  }
733  }
734 
735  /* always try to use the tab that was explicitly
736  * set to the user, so that once that context comes
737  * back, the tab is activated again */
738  sbuts->mainb = sbuts->mainbuser;
739 
740  /* in case something becomes invalid, change */
741  if ((flag & (1 << sbuts->mainb)) == 0) {
742  if (sbuts->flag & SB_SHADING_CONTEXT) {
743  /* try to keep showing shading related buttons */
744  sbuts->mainb = buttons_shading_new_context(C, flag);
745  }
746  else if (flag & BCONTEXT_OBJECT) {
747  sbuts->mainb = BCONTEXT_OBJECT;
748  }
749  else {
750  for (int i = 0; i < BCONTEXT_TOT; i++) {
751  if (flag & (1 << i)) {
752  sbuts->mainb = i;
753  break;
754  }
755  }
756  }
757  }
758 
759  buttons_context_path(C, sbuts, path, sbuts->mainb, pflag);
760 
761  if (!(flag & (1 << sbuts->mainb))) {
762  if (flag & (1 << BCONTEXT_OBJECT)) {
763  sbuts->mainb = BCONTEXT_OBJECT;
764  }
765  else {
766  sbuts->mainb = BCONTEXT_SCENE;
767  }
768  }
769 
770  if (buttons_shading_context(C, sbuts->mainb)) {
771  sbuts->flag |= SB_SHADING_CONTEXT;
772  }
773  else {
774  sbuts->flag &= ~SB_SHADING_CONTEXT;
775  }
776 
777  sbuts->pathflag = flag;
778 }
779 
781 {
782  for (int i = 0; i < path->len; ++i) {
783  if (ptr->owner_id == path->ptr[i].owner_id) {
784  return true;
785  }
786  }
787  return false;
788 }
789 
791  const SpaceProperties *sbuts,
792  ScrArea *area)
793 {
794  ScrArea *active_area = CTX_wm_area(C);
795  const bool auto_sync = ED_area_has_shared_border(active_area, area) &&
797  return auto_sync || sbuts->outliner_sync == PROPERTIES_SYNC_ALWAYS;
798 }
799 
801  SpaceProperties *sbuts,
802  PointerRNA *ptr,
803  const int context)
804 {
805  ButsContextPath path;
806  if (buttons_context_path(C, sbuts, &path, context, 0) && is_pointer_in_path(&path, ptr)) {
807  sbuts->mainbuser = context;
808  sbuts->mainb = sbuts->mainbuser;
809  }
810 }
811 
812 /************************* Context Callback ************************/
813 
814 const char *buttons_context_dir[] = {
815  "texture_slot",
816  "scene",
817  "world",
818  "object",
819  "mesh",
820  "armature",
821  "lattice",
822  "curve",
823  "meta_ball",
824  "light",
825  "speaker",
826  "lightprobe",
827  "camera",
828  "material",
829  "material_slot",
830  "texture",
831  "texture_user",
832  "texture_user_property",
833  "bone",
834  "edit_bone",
835  "pose_bone",
836  "particle_system",
837  "particle_system_editable",
838  "particle_settings",
839  "cloth",
840  "soft_body",
841  "fluid",
842  "collision",
843  "brush",
844  "dynamic_paint",
845  "line_style",
846  "collection",
847  "gpencil",
848 #ifdef WITH_HAIR_NODES
849  "hair",
850 #endif
851 #ifdef WITH_POINT_CLOUD
852  "pointcloud",
853 #endif
854  "volume",
855  NULL,
856 };
857 
858 int /*eContextResult*/ buttons_context(const bContext *C,
859  const char *member,
861 {
863  if (sbuts && sbuts->path == NULL) {
864  /* path is cleared for SCREEN_OT_redo_last, when global undo does a file-read which clears the
865  * path (see lib_link_workspace_layout_restore). */
866  buttons_context_compute(C, sbuts);
867  }
868  ButsContextPath *path = sbuts ? sbuts->path : NULL;
869 
870  if (!path) {
872  }
873 
874  if (sbuts->mainb == BCONTEXT_TOOL) {
876  }
877 
878  /* here we handle context, getting data from precomputed path */
879  if (CTX_data_dir(member)) {
880  /* in case of new shading system we skip texture_slot, complex python
881  * UI script logic depends on checking if this is available */
882  if (sbuts->texuser) {
884  }
885  else {
887  }
888  return CTX_RESULT_OK;
889  }
890  if (CTX_data_equals(member, "scene")) {
891  /* Do not return one here if scene is not found in path,
892  * in this case we want to get default context scene! */
893  return set_pointer_type(path, result, &RNA_Scene);
894  }
895  if (CTX_data_equals(member, "world")) {
897  return CTX_RESULT_OK;
898  }
899  if (CTX_data_equals(member, "collection")) {
900  /* Do not return one here if collection is not found in path,
901  * in this case we want to get default context collection! */
902  return set_pointer_type(path, result, &RNA_Collection);
903  }
904  if (CTX_data_equals(member, "object")) {
906  return CTX_RESULT_OK;
907  }
908  if (CTX_data_equals(member, "mesh")) {
910  return CTX_RESULT_OK;
911  }
912  if (CTX_data_equals(member, "armature")) {
914  return CTX_RESULT_OK;
915  }
916  if (CTX_data_equals(member, "lattice")) {
918  return CTX_RESULT_OK;
919  }
920  if (CTX_data_equals(member, "curve")) {
922  return CTX_RESULT_OK;
923  }
924  if (CTX_data_equals(member, "meta_ball")) {
926  return CTX_RESULT_OK;
927  }
928  if (CTX_data_equals(member, "light")) {
930  return CTX_RESULT_OK;
931  }
932  if (CTX_data_equals(member, "camera")) {
934  return CTX_RESULT_OK;
935  }
936  if (CTX_data_equals(member, "speaker")) {
938  return CTX_RESULT_OK;
939  }
940  if (CTX_data_equals(member, "lightprobe")) {
942  return CTX_RESULT_OK;
943  }
944 #ifdef WITH_HAIR_NODES
945  if (CTX_data_equals(member, "hair")) {
947  return CTX_RESULT_OK;
948  }
949 #endif
950 #ifdef WITH_POINT_CLOUD
951  if (CTX_data_equals(member, "pointcloud")) {
953  return CTX_RESULT_OK;
954  }
955 #endif
956  if (CTX_data_equals(member, "volume")) {
958  return CTX_RESULT_OK;
959  }
960  if (CTX_data_equals(member, "material")) {
962  return CTX_RESULT_OK;
963  }
964  if (CTX_data_equals(member, "texture")) {
965  ButsContextTexture *ct = sbuts->texuser;
966 
967  if (ct) {
968  if (ct->texture == NULL) {
969  return CTX_RESULT_NO_DATA;
970  }
971 
973  }
974 
975  return CTX_RESULT_OK;
976  }
977  if (CTX_data_equals(member, "material_slot")) {
979 
980  if (ptr) {
981  Object *ob = ptr->data;
982 
983  if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) {
984  /* a valid actcol isn't ensured T27526. */
985  int matnr = ob->actcol - 1;
986  if (matnr < 0) {
987  matnr = 0;
988  }
989  CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]);
990  }
991  }
992 
993  return CTX_RESULT_OK;
994  }
995  if (CTX_data_equals(member, "texture_user")) {
996  ButsContextTexture *ct = sbuts->texuser;
997 
998  if (!ct) {
999  return CTX_RESULT_NO_DATA;
1000  }
1001 
1002  if (ct->user && ct->user->ptr.data) {
1003  ButsTextureUser *user = ct->user;
1004  CTX_data_pointer_set(result, user->ptr.owner_id, user->ptr.type, user->ptr.data);
1005  }
1006 
1007  return CTX_RESULT_OK;
1008  }
1009  if (CTX_data_equals(member, "texture_user_property")) {
1010  ButsContextTexture *ct = sbuts->texuser;
1011 
1012  if (!ct) {
1013  return CTX_RESULT_NO_DATA;
1014  }
1015 
1016  if (ct->user && ct->user->ptr.data) {
1017  ButsTextureUser *user = ct->user;
1019  }
1020 
1021  return CTX_RESULT_OK;
1022  }
1023  if (CTX_data_equals(member, "texture_node")) {
1024  ButsContextTexture *ct = sbuts->texuser;
1025 
1026  if (ct) {
1027  /* new shading system */
1028  if (ct->user && ct->user->node) {
1030  }
1031 
1032  return CTX_RESULT_OK;
1033  }
1034  return CTX_RESULT_NO_DATA;
1035  }
1036  if (CTX_data_equals(member, "texture_slot")) {
1037  ButsContextTexture *ct = sbuts->texuser;
1038  PointerRNA *ptr;
1039 
1040  /* Particles slots are used in both old and new textures handling. */
1041  if ((ptr = get_pointer_type(path, &RNA_ParticleSystem))) {
1042  ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;
1043 
1044  if (part) {
1046  result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]);
1047  }
1048  }
1049  else if (ct) {
1050  return CTX_RESULT_MEMBER_NOT_FOUND; /* new shading system */
1051  }
1052  else if ((ptr = get_pointer_type(path, &RNA_FreestyleLineStyle))) {
1053  FreestyleLineStyle *ls = ptr->data;
1054 
1055  if (ls) {
1057  result, &ls->id, &RNA_LineStyleTextureSlot, ls->mtex[(int)ls->texact]);
1058  }
1059  }
1060 
1061  return CTX_RESULT_OK;
1062  }
1063  if (CTX_data_equals(member, "bone")) {
1064  set_pointer_type(path, result, &RNA_Bone);
1065  return CTX_RESULT_OK;
1066  }
1067  if (CTX_data_equals(member, "edit_bone")) {
1069  return CTX_RESULT_OK;
1070  }
1071  if (CTX_data_equals(member, "pose_bone")) {
1073  return CTX_RESULT_OK;
1074  }
1075  if (CTX_data_equals(member, "particle_system")) {
1077  return CTX_RESULT_OK;
1078  }
1079  if (CTX_data_equals(member, "particle_system_editable")) {
1080  if (PE_poll((bContext *)C)) {
1082  }
1083  else {
1085  }
1086  return CTX_RESULT_OK;
1087  }
1088  if (CTX_data_equals(member, "particle_settings")) {
1089  /* only available when pinned */
1091 
1092  if (ptr && ptr->data) {
1094  return CTX_RESULT_OK;
1095  }
1096 
1097  /* get settings from active particle system instead */
1099 
1100  if (ptr && ptr->data) {
1101  ParticleSettings *part = ((ParticleSystem *)ptr->data)->part;
1103  return CTX_RESULT_OK;
1104  }
1105 
1107  return CTX_RESULT_OK;
1108  }
1109  if (CTX_data_equals(member, "cloth")) {
1111 
1112  if (ptr && ptr->data) {
1113  Object *ob = ptr->data;
1116  return CTX_RESULT_OK;
1117  }
1118  return CTX_RESULT_NO_DATA;
1119  }
1120  if (CTX_data_equals(member, "soft_body")) {
1122 
1123  if (ptr && ptr->data) {
1124  Object *ob = ptr->data;
1127  return CTX_RESULT_OK;
1128  }
1129  return CTX_RESULT_NO_DATA;
1130  }
1131 
1132  if (CTX_data_equals(member, "fluid")) {
1134 
1135  if (ptr && ptr->data) {
1136  Object *ob = ptr->data;
1139  return CTX_RESULT_OK;
1140  }
1141  return CTX_RESULT_NO_DATA;
1142  }
1143  if (CTX_data_equals(member, "collision")) {
1145 
1146  if (ptr && ptr->data) {
1147  Object *ob = ptr->data;
1150  return CTX_RESULT_OK;
1151  }
1152  return CTX_RESULT_NO_DATA;
1153  }
1154  if (CTX_data_equals(member, "brush")) {
1156  return CTX_RESULT_OK;
1157  }
1158  if (CTX_data_equals(member, "dynamic_paint")) {
1160 
1161  if (ptr && ptr->data) {
1162  Object *ob = ptr->data;
1165  return CTX_RESULT_OK;
1166  }
1167  return CTX_RESULT_NO_DATA;
1168  }
1169  if (CTX_data_equals(member, "line_style")) {
1171  return CTX_RESULT_OK;
1172  }
1173  if (CTX_data_equals(member, "gpencil")) {
1175  return CTX_RESULT_OK;
1176  }
1178 }
1179 
1180 /************************* Drawing the Path ************************/
1181 
1183 {
1185  return sbuts->mainb != BCONTEXT_TOOL;
1186 }
1187 
1188 static void buttons_panel_context_draw(const bContext *C, Panel *panel)
1189 {
1191  ButsContextPath *path = sbuts->path;
1192 
1193  if (!path) {
1194  return;
1195  }
1196 
1197  uiLayout *row = uiLayoutRow(panel->layout, true);
1199 
1200  bool first = true;
1201  for (int i = 0; i < path->len; i++) {
1202  PointerRNA *ptr = &path->ptr[i];
1203 
1204  /* Skip scene and view layer to save space. */
1205  if ((!ELEM(sbuts->mainb,
1210  BCONTEXT_WORLD) &&
1211  ptr->type == &RNA_Scene)) {
1212  continue;
1213  }
1214  if ((!ELEM(sbuts->mainb,
1219  BCONTEXT_WORLD) &&
1220  ptr->type == &RNA_ViewLayer)) {
1221  continue;
1222  }
1223 
1224  /* Add > triangle. */
1225  if (!first) {
1226  uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
1227  }
1228 
1229  if (ptr->data == NULL) {
1230  continue;
1231  }
1232 
1233  /* Add icon and name .*/
1234  int icon = RNA_struct_ui_icon(ptr->type);
1235  char namebuf[128];
1236  char *name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
1237 
1238  if (name) {
1239  uiItemLDrag(row, ptr, name, icon);
1240 
1241  if (name != namebuf) {
1242  MEM_freeN(name);
1243  }
1244  }
1245  else {
1246  uiItemL(row, "", icon);
1247  }
1248 
1249  first = false;
1250  }
1251 
1252  uiLayout *pin_row = uiLayoutRow(row, false);
1254  uiItemSpacer(pin_row);
1256  uiItemO(pin_row,
1257  "",
1258  (sbuts->flag & SB_PIN_CONTEXT) ? ICON_PINNED : ICON_UNPINNED,
1259  "BUTTONS_OT_toggle_pin");
1260 }
1261 
1263 {
1264  PanelType *pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
1265  strcpy(pt->idname, "PROPERTIES_PT_context");
1266  strcpy(pt->label, N_("Context")); /* XXX C panels unavailable through RNA bpy.types! */
1271  BLI_addtail(&art->paneltypes, pt);
1272 }
1273 
1275 {
1277  ButsContextPath *path = sbuts->path;
1278 
1279  if (path->len == 0) {
1280  return NULL;
1281  }
1282 
1283  for (int i = path->len - 1; i >= 0; i--) {
1284  PointerRNA *ptr = &path->ptr[i];
1285 
1286  /* pin particle settings instead of system, since only settings are an idblock*/
1287  if (sbuts->mainb == BCONTEXT_PARTICLE && sbuts->flag & SB_PIN_CONTEXT) {
1288  if (ptr->type == &RNA_ParticleSystem && ptr->data) {
1289  ParticleSystem *psys = ptr->data;
1290  return &psys->part->id;
1291  }
1292  }
1293 
1294  /* There is no valid image ID panel, Image Empty objects need this workaround.*/
1295  if (sbuts->mainb == BCONTEXT_DATA && sbuts->flag & SB_PIN_CONTEXT) {
1296  if (ptr->type == &RNA_Image && ptr->data) {
1297  continue;
1298  }
1299  }
1300 
1301  if (ptr->owner_id) {
1302  return ptr->owner_id;
1303  }
1304  }
1305 
1306  return NULL;
1307 }
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
Definition: context.c:672
struct SpaceProperties * CTX_wm_space_properties(const bContext *C)
Definition: context.c:809
bool CTX_data_equals(const char *member, const char *str)
Definition: context.c:623
void CTX_data_pointer_set(bContextDataResult *result, struct ID *id, StructRNA *type, void *data)
Definition: context.c:638
bool CTX_data_dir(const char *member)
Definition: context.c:628
@ CTX_RESULT_MEMBER_NOT_FOUND
Definition: BKE_context.h:86
@ CTX_RESULT_OK
Definition: BKE_context.h:83
@ CTX_RESULT_NO_DATA
Definition: BKE_context.h:90
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
struct ViewLayer * BKE_view_layer_default_view(const struct Scene *scene)
Blender kernel freestyle line style functionality.
FreestyleLineStyle * BKE_linestyle_active_from_view_layer(struct ViewLayer *view_layer)
Definition: linestyle.c:818
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
General operations, lookup, etc. for blender objects.
struct ModifierData * BKE_object_active_modifier(const struct Object *ob)
struct Paint * BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer)
Definition: paint.c:447
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:604
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition: particle.c:645
@ PANEL_TYPE_NO_HEADER
Definition: BKE_screen.h:298
@ PANEL_TYPE_NO_SEARCH
Definition: BKE_screen.h:307
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
#define UNUSED(x)
#define ELEM(...)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define N_(msgid)
@ ID_LS
Definition: DNA_ID_enums.h:87
@ ID_BR
Definition: DNA_ID_enums.h:81
@ ID_OB
Definition: DNA_ID_enums.h:59
@ ID_PA
Definition: DNA_ID_enums.h:82
Object groups, one object can be in many groups at once.
@ FREESTYLE_CONTROL_EDITOR_MODE
@ eModifierType_Cloth
@ eModifierType_Fluid
@ eModifierType_Collision
@ eModifierType_DynamicPaint
@ eModifierType_Softbody
#define OB_TYPE_SUPPORT_MATERIAL(_type)
@ OB_SPEAKER
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_POINTCLOUD
@ OB_HAIR
@ OB_VOLUME
@ OB_CURVE
@ OB_GPENCIL
@ OB_LIGHTPROBE
#define OBACT(_view_layer)
#define R_EDGE_FRS
@ SB_SHADING_CONTEXT
@ SB_PIN_CONTEXT
@ PROPERTIES_SYNC_ALWAYS
@ PROPERTIES_SYNC_AUTO
@ BCONTEXT_CONSTRAINT
@ BCONTEXT_COLLECTION
@ BCONTEXT_OUTPUT
@ BCONTEXT_VIEW_LAYER
@ BCONTEXT_MATERIAL
@ BCONTEXT_TOT
@ BCONTEXT_SHADERFX
@ BCONTEXT_MODIFIER
@ BCONTEXT_BONE
@ BCONTEXT_DATA
@ BCONTEXT_OBJECT
@ BCONTEXT_BONE_CONSTRAINT
@ BCONTEXT_PHYSICS
@ BCONTEXT_SCENE
@ BCONTEXT_WORLD
@ BCONTEXT_RENDER
@ BCONTEXT_TEXTURE
@ BCONTEXT_TOOL
@ BCONTEXT_PARTICLE
bool PE_poll(struct bContext *C)
Definition: particle_edit.c:95
bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b)
Definition: area.c:1900
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
StructRNA RNA_Bone
StructRNA RNA_Property
StructRNA RNA_MaterialSlot
StructRNA RNA_Node
StructRNA RNA_Collection
StructRNA RNA_Material
StructRNA RNA_Scene
StructRNA RNA_Armature
StructRNA RNA_CollisionModifier
StructRNA RNA_Modifier
StructRNA RNA_ViewLayer
StructRNA RNA_DynamicPaintModifier
StructRNA RNA_MetaBall
StructRNA RNA_Curve
StructRNA RNA_Mesh
StructRNA RNA_ParticleSystem
StructRNA RNA_Light
StructRNA RNA_Hair
StructRNA RNA_LightProbe
StructRNA RNA_EditBone
StructRNA RNA_GreasePencil
StructRNA RNA_Speaker
StructRNA RNA_ParticleSettingsTextureSlot
StructRNA RNA_PoseBone
StructRNA RNA_Object
StructRNA RNA_Camera
StructRNA RNA_FreestyleLineStyle
StructRNA RNA_World
StructRNA RNA_FluidModifier
StructRNA RNA_Brush
StructRNA RNA_PointCloud
StructRNA RNA_Volume
StructRNA RNA_LineStyleTextureSlot
StructRNA RNA_ClothModifier
StructRNA RNA_Texture
StructRNA RNA_SoftBodyModifier
StructRNA RNA_ParticleSettings
StructRNA RNA_Image
StructRNA RNA_Lattice
#define C
Definition: RandGen.cpp:39
@ UI_EMBOSS_NONE
Definition: UI_interface.h:108
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_RIGHT
void uiItemSpacer(uiLayout *layout)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon)
static bool buttons_context_path(const bContext *C, SpaceProperties *sbuts, ButsContextPath *path, int mainb, int flag)
static bool buttons_context_path_shaderfx(ButsContextPath *path)
static bool buttons_context_path_bone(ButsContextPath *path)
static bool buttons_context_path_scene(ButsContextPath *path)
static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
static bool buttons_context_path_data(ButsContextPath *path, int type)
const char * buttons_context_dir[]
static PointerRNA * get_pointer_type(ButsContextPath *path, StructRNA *type)
static bool buttons_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
void ED_buttons_set_context(const bContext *C, SpaceProperties *sbuts, PointerRNA *ptr, const int context)
ID * buttons_context_id_path(const bContext *C)
void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
void buttons_context_register(ARegionType *art)
static bool buttons_context_path_material(ButsContextPath *path)
static bool buttons_context_path_texture(const bContext *C, ButsContextPath *path, ButsContextTexture *ct)
static bool buttons_context_path_pose_bone(ButsContextPath *path)
static bool buttons_context_path_object(ButsContextPath *path)
static int buttons_shading_new_context(const bContext *C, int flag)
static bool buttons_context_path_particle(ButsContextPath *path)
bool ED_buttons_should_sync_with_outliner(const bContext *C, const SpaceProperties *sbuts, ScrArea *area)
static bool buttons_context_path_view_layer(ButsContextPath *path, wmWindow *win)
static bool buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
static bool buttons_shading_context(const bContext *C, int mainb)
static bool is_pointer_in_path(ButsContextPath *path, PointerRNA *ptr)
static bool buttons_context_path_brush(const bContext *C, ButsContextPath *path)
static bool buttons_context_path_collection(const bContext *C, ButsContextPath *path, wmWindow *window)
static bool buttons_context_path_world(ButsContextPath *path)
static void buttons_panel_context_draw(const bContext *C, Panel *panel)
static bool buttons_context_path_modifier(ButsContextPath *path)
void buttons_texture_context_compute(const struct bContext *C, struct SpaceProperties *sbuts)
Scene scene
FreestyleLineStyle linestyle
World world
#define GS(x)
Definition: iris.c:241
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static unsigned c
Definition: RandGen.cpp:97
static void area(int d1, int d2, int e1, int e2, float weights[2])
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:844
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
char * RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
Definition: rna_access.c:1049
int RNA_struct_ui_icon(const StructRNA *type)
Definition: rna_access.c:738
struct SELECTID_Context context
Definition: select_engine.c:47
ListBase paneltypes
Definition: BKE_screen.h:216
struct Object * object
char name[64]
PointerRNA ptr[8]
struct ButsTextureUser * user
struct Tex * texture
struct ID * id
struct bNodeTree * ntree
struct bNode * node
PointerRNA ptr
PropertyRNA * prop
struct MTex * mtex[18]
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
struct Collection * collection
struct bPose * pose
struct Material ** mat
void * data
void(* draw)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:266
bool(* poll)(const struct bContext *C, struct PanelType *pt)
Definition: BKE_screen.h:260
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:241
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:244
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:242
struct uiLayout * layout
struct MTex * mtex[18]
ParticleSettings * part
struct StructRNA * type
Definition: RNA_types.h:51
void * data
Definition: RNA_types.h:52
struct ID * owner_id
Definition: RNA_types.h:50
struct Collection * master_collection
struct RenderData r
struct World * world
struct FreestyleConfig freestyle_config
LayerCollection * active_collection
struct Base * basact
struct EditBone * act_edbone
ListBase * edbo
struct Scene * scene
PointerRNA * ptr
Definition: wm_files.c:3157
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Definition: wm_window.c:2286
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2249