Fix: VSE: Various crashes when sequencer scene is not initialized

Most of these crashes happen because it is assumed that the scene will
always be present even if we have an uninitialized `Editing`, which is
no longer the case with #140271.

- Fix crash when clicking and dragging in the scrub area by checking for
  valid `sequencer_scene` in `change_frame_poll`
- Fix crashes when selecting menu items by disabling them in the UI
  until a `sequencer_scene` is present
- Fix crashes running operators from the F3 menu by changing to more
  restrictive polls that check for `sequencer_scene`
- For good measure, check before dereferencing in
  `channels_displayed_get`, `active_seqbase_get`, and `editing_get`

Pull Request: https://projects.blender.org/blender/blender/pulls/145145
This commit is contained in:
John Kiril Swenson
2025-08-26 11:53:49 +02:00
committed by Falk David
parent 30d546cdca
commit 7bd19f7efb
9 changed files with 58 additions and 46 deletions

View File

@@ -930,30 +930,33 @@ class SEQUENCER_MT_strip_transform(Menu):
else:
layout.operator_context = 'INVOKE_REGION_WIN'
col = layout.column()
if has_preview:
layout.operator("transform.translate", text="Move")
layout.operator("transform.rotate", text="Rotate")
layout.operator("transform.resize", text="Scale")
col.operator("transform.translate", text="Move")
col.operator("transform.rotate", text="Rotate")
col.operator("transform.resize", text="Scale")
else:
layout.operator("transform.seq_slide", text="Move").view2d_edge_pan = True
layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND'
layout.operator("sequencer.slip", text="Slip Strip Contents")
col.operator("transform.seq_slide", text="Move").view2d_edge_pan = True
col.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND'
col.operator("sequencer.slip", text="Slip Strip Contents")
# TODO (for preview)
if has_sequencer:
layout.separator()
layout.operator("sequencer.snap")
layout.operator("sequencer.offset_clear")
col.separator()
col.operator("sequencer.snap")
col.operator("sequencer.offset_clear")
layout.separator()
col.separator()
if has_sequencer:
layout.operator_menu_enum("sequencer.swap", "side")
col.operator_menu_enum("sequencer.swap", "side")
layout.separator()
layout.operator("sequencer.gap_remove").all = False
layout.operator("sequencer.gap_remove", text="Remove Gaps (All)").all = True
layout.operator("sequencer.gap_insert")
col.separator()
col.operator("sequencer.gap_remove").all = False
col.operator("sequencer.gap_remove", text="Remove Gaps (All)").all = True
col.operator("sequencer.gap_insert")
col.enabled = bool(context.sequencer_scene)
class SEQUENCER_MT_strip_text(Menu):
@@ -991,31 +994,34 @@ class SEQUENCER_MT_strip_show_hide(Menu):
class SEQUENCER_MT_strip_animation(Menu):
bl_label = "Animation"
def draw(self, _context):
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("anim.keyframe_insert", text="Insert Keyframe")
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True
layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
layout.operator("anim.keyframe_delete_vse", text="Delete Keyframes...")
layout.operator("anim.keyframe_clear_vse", text="Clear Keyframes...")
col = layout.column()
col.operator("anim.keyframe_insert", text="Insert Keyframe")
col.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True
col.operator("anim.keying_set_active_set", text="Change Keying Set...")
col.operator("anim.keyframe_delete_vse", text="Delete Keyframes...")
col.operator("anim.keyframe_clear_vse", text="Clear Keyframes...")
col.enabled = bool(context.sequencer_scene)
class SEQUENCER_MT_strip_mirror(Menu):
bl_label = "Mirror"
def draw(self, _context):
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("transform.mirror", text="Interactive Mirror")
col = layout.column()
col.operator("transform.mirror", text="Interactive Mirror")
layout.separator()
col.separator()
for (space_name, space_id) in (("Global", 'GLOBAL'), ("Local", 'LOCAL')):
for axis_index, axis_name in enumerate("XY"):
props = layout.operator(
props = col.operator(
"transform.mirror",
text="{:s} {:s}".format(axis_name, iface_(space_name)),
translate=False,
@@ -1024,7 +1030,8 @@ class SEQUENCER_MT_strip_mirror(Menu):
props.orient_type = space_id
if space_id == 'GLOBAL':
layout.separator()
col.separator()
col.enabled = bool(context.sequencer_scene)
class SEQUENCER_MT_strip_input(Menu):
@@ -1283,16 +1290,18 @@ class SEQUENCER_MT_image(Menu):
class SEQUENCER_MT_image_transform(Menu):
bl_label = "Transform"
def draw(self, _context):
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("transform.translate")
layout.operator("transform.rotate")
layout.operator("transform.resize", text="Scale")
layout.separator()
layout.operator("transform.translate", text="Move Origin").translate_origin = True
col = layout.column()
col.operator("transform.translate")
col.operator("transform.rotate")
col.operator("transform.resize", text="Scale")
col.separator()
col.operator("transform.translate", text="Move Origin").translate_origin = True
col.enabled = bool(context.sequencer_scene)
class SEQUENCER_MT_image_clear(Menu):