Avoid selecting an object in the outliner using a callback I am working on an extension for exporting particle systems in blender to glTF. As my engine doesn't support as much stuff as blender, I am creating a template which exposes the properties that I support and internally modified blender properties.
That template is made of two objects, a frontend one which will show the properties and an internal one (which later will probably be some more), which have the actual blender stuff.

I want to avoid the user selecting the Kuesa.Particles.Internal object, to avoid the user modifying the internal particle system properties or changing stuff, which may break the exporter.
Although the selection is disabled, this only works on the 3d viewport, but not on the outliner. Is there anyway to avoid the selection of something in the outliner? If not, I was thinking on using some kind of callback. When something is selected, check if it has a custom property type with value Kuesa.Particles.Internal and in that case, select the parent. How would I do something like that?
Using msgbus
Similarly to https://blender.stackexchange.com/a/163258/15543 which uses the message bus to capture when an object is made active
How to get an event when an object is selected?
By way of example the test is if the object trying to be made active has a name that starts with &quot;Cube&quot;  The user could break this test by renaming, so choose something more rigorous, perhaps a collection of pointers to objects kept on the scene, or as mentioned a custom property, and hide the custom properties panel.
Also FWIW as mentioned prior am not a great advocate for an &quot;exporter&quot; that modifies the blend.
import bpy
from mathutils import Vector, Matrix

handle = object()

# Triggers when an object is made active
subscribe_to = bpy.types.LayerObjects, &quot;active&quot; # 
    
def notify_test(context):
    ob = context.object
    #print(context.area) # always None
    if (ob and ob.name.startswith(&quot;Cube&quot;)):
        print(&quot;No select object:&quot;, ob.name)
        ob.select_set(False)
        context.view_layer.objects.active = ob.parent
        if ob.parent:
            ob.parent.select_set(True)

bpy.msgbus.subscribe_rna(
    key=subscribe_to,
    owner=handle,
    args=(bpy.context,),
    notify=notify_test,
)

bpy.msgbus.publish_rna(key=subscribe_to)