kwin- 插件加载绘制流程

1. 配置文件的作用具体是做什么的?

        相当于用户强制设置了特效的开关,对于没有写在配置文件里的特效,会检测默认加载值,确定是否加载。写在了文件里的会根据返回的值,来加载特效。

2. 为什么配置文件没有写,也可以加载插件?

        之所以配置文件没有写,特效也可以加载,是因为插件加载时,会先检测配置文件的内容,之后才会走默认加载逻辑,具体如下代码

LoadEffectFlags AbstractEffectLoader::readConfig(const QString &effectName, bool defaultValue) const
{
    Q_ASSERT(m_config);
    KConfigGroup plugins(m_config, QStringLiteral("Plugins"));

    const QString key = effectName + QStringLiteral("Enabled");

    // 如果配置文件内写了该插件
    if (plugins.hasKey(key)) {
        // we have a key in the config, so read the enabled state
        //如果键存在,读取其值。如果键不存在,使用 defaultValue 作为默认值。
        const bool load = plugins.readEntry(key, defaultValue);
        // 如果读取到的值(或默认值)为 true,返回 LoadEffectFlags,表示加载效果;否则,返回一个空的 LoadEffectFlags 对象。
        return load ? LoadEffectFlags(LoadEffectFlag::Load) : LoadEffectFlags();
    }
    // we don't have a key, so we just use the enabled by default value
    /*
    如果配置中没有找到该键,并且 defaultValue 为 true,返回 LoadEffectFlag::Load | LoadEffectFlag::CheckDefaultFunction,
    表示需要加载效果并调用默认检查函数;否则,返回一个空的 LoadEffectFlags 对象。
    */
    if (defaultValue) {
        return LoadEffectFlag::Load | LoadEffectFlag::CheckDefaultFunction;
    }
    return LoadEffectFlags();
}

文件说明:

  1. src/effectloader.h
    1. AbstractEffectLoader类

                描述效果加载器如何工作的接口。 AbstractEffectLoader指定了具体加载器必须实现的方法以及这些方法的预期行为。同时,它也为外部世界(即EffectsHandlerImpl)提供了一个接口。

使用这种抽象是因为有多种类型的效果需要加载:

  •  内置效果(Built-In Effects)
  • 脚本效果(Scripted Effects)
  • 二进制插件效果(Binary Plugin Effects)

        由于需要同时查询不同的存储库,因此使用同一个效果加载器来服务所有这些类型相当复杂。因此,想法是为每种类型提供一个实现,并有一个实现利用所有这些并组合加载过程。

/**
* @brief 同步加载给定名称@p name的效果。
*
* 加载效果时,不检查任何配置值或效果提供的任何默认启用函数。
*
* 加载器应执行以下检查:
* 如果效果已经加载,则不应再次加载。因此,加载器应跟踪已加载的效果以及其中哪些已被销毁。
* 加载器应检查效果是否受支持。如果效果表示不受支持,则不应加载。
*
* 如果效果成功加载,则必须发出effectLoaded(KWin::Effect,const QString&)信号。否则,加载器的用户无法获取加载的效果。
* 它不返回效果,因为queryAndLoadAll()是异步工作的,因此加载器的用户应为异步加载做好准备。
* @param name 要加载的效果的内部名称
* @return bool 如果效果可以加载,则返回@c true;如果出错,则返回@c false
* @see queryAndLoadAll()
* @see effectLoaded(KWin::Effect,const QString&)
*/
  virtual bool loadEffect(const QString &name) = 0;
  
  /**
* @brief 效果加载器应查询其存储中的所有可用效果并尝试加载它们。
*
* 效果加载器应以高度异步的方式执行此操作。如果需要进行输入/输出(IO)操作,则应在后台线程中执行,并使用队列来加载效果。
* 加载器应确保在一个事件循环中不加载超过一个效果。
* 加载效果必须在合成器线程中执行,因此会阻塞合成器。因此,在加载一个效果后,应先处理所有事件,以便合成器在需要时可以进行绘制传递。
* 为了简化此操作,可以使用EffectLoadQueue。这需要添加另一个具有自定义加载器特定类型以引用效果和LoadEffectFlags的loadEffect方法。
*
* 必须通过读取配置(readConfig())来确定LoadEffectFlags。如果设置了加载标志,则可以继续加载,并应用来自loadEffect(const QString &)的所有检查。
* 此外,如果设置了CheckDefaultFunction标志,并且效果提供了这样的方法,则应查询该方法以确定效果是否默认启用。
* 如果这样的方法返回@c false,则不应加载效果。如果效果没有提供在运行时查询是否默认启用的方法,则可以忽略该标志。
*
* 如果效果成功加载,则必须发出effectLoaded(KWin::Effect,const QString&)信号。
* @see loadEffect(const QString &)
* @see effectLoaded(KWin::Effect,const QString&)
*/
virtual void queryAndLoadAll() = 0;


/**
* @brief 检查由@p effectName标识的效果的配置。
*
* 对于每个效果,可能存在一个名为"<effectName>Enabled"的键。
* 如果存在这样的键,并且其值为@c true,则返回的标志将包含Load。如果键不存在,则@p defaultValue确定是否应加载效果。
* 如果@p defaultValue的值为@c true,则返回Load | CheckDefaultFunction,表示应加载效果并检查其默认启用函数;如果为@c false,则不返回任何加载标志。
*
* @param effectName 在配置中要查找的效果的名称
* @param defaultValue 效果是否默认启用
* @returns 标志,指示是否应加载效果以及如何加载效果
*/
 LoadEffectFlags readConfig(const QString &effectName, bool defaultValue) const;
  • AbstractEffectLoadQueue类

        这个类用于帮助排队加载特效(Effects)。

        加载一个特效必须在合成线程(compositor thread)中进行,因此在加载特效的过程中,合成器会被阻塞。为了避免合成器在加载所有特效的过程中被阻塞多个帧,我们需要将特效的加载过程排队处理。通过通过一个 QueuedConnection 调用 dequeue() 插槽(slot),队列可以确保在加载两个特效之间处理事件,从而避免合成器被阻塞。

        由于它需要是一个插槽(slot),队列必须继承自 QObject,但同时它也需要是模板类,因为加载特效的信息是特效加载器(Effect Loader)特有的。因此,有一个 AbstractEffectLoadQueue 提供纯虚函数插槽(slots),以及一个继承自 AbstractEffectLoadQueue 的模板类 EffectLoadQueue。

        队列的操作类似于普通队列,提供了 enqueue(入队)和 scheduleDequeue(计划出队)而不是直接的 dequeue(出队)

  • src/libkwineffects/kwineffects.h

        包含所有特效的基类:Effect

        所有KWin效果的基础类, 这是所有效果的基础类。通过重新实现此类的虚拟方法,您可以自定义窗口的绘制方式。这些虚拟方法用于绘制,并需要为实现自定义绘制而实现。为了响应状态变化(例如窗口关闭),效果应该为EffectsHandler发出的信号提供槽函数。

  • 链式调用

        此类的大多数方法都是以链式方式调用的。这意味着当效果A和B都处于活动状态时,首先会调用A::paintWindow(),然后在该方法内部(尽管是间接地)会调用B::paintWindow()。为了实现这一点,您需要从每个这样的方法中确保调用EffectsHandler类的对应方法(使用effects指针):

void MyEffect::postPaintScreen()
{

// 在此处执行您自己的处理

...

// 调用对应的EffectsHandler方法

effects->postPaintScreen();// effects指针指向全局的EffectsHandler对象,您可以使用它与窗口进行交互。
}
  • 绘制阶段

        窗口的绘制分为三个阶段:

        首先,是预绘制阶段,在此阶段,您可以指定窗口的绘制方式,例如它们将是半透明的或经过变换的。

        其次,是绘制阶段。在此阶段,实际进行绘制。您可以更改窗口的属性,如透明度,并对它们应用变换。您还可以自己在屏幕上绘制内容。

        最后,是后绘制阶段。在此阶段,您可以标记窗口、窗口的一部分甚至整个屏幕以进行重绘,从而创建动画。

        对于每个阶段,都有Screen()和Window()方法。窗口方法会为每个窗口调用,而屏幕方法通常只调用一次。

OpenGL

        如果EffectsHandler::isOpenGLCompositing()返回true,则效果可以使用OpenGL。当执行effect内部的代码时,OpenGL上下文可能并不总是当前的。框架确保在创建、销毁或重新配置效果以及绘制阶段期间,OpenGL上下文是当前的。所有具有当前OpenGL上下文的虚拟方法都有文档说明。如果要在绘制阶段之外执行OpenGL代码,例如响应全局快捷键,那么效果的任务就是使OpenGL上下文成为当前的:

effects->makeOpenGLContextCurrent();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值