[
  {
    "path": ".gitignore",
    "content": "forceblur.kwinscript\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Eon S. Jeon <esjeon@hyunmu.am>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "\nForce Blur\n==========\n\nA KWin script to force-enable KWin Blur effect on user-specified windows.\n\n![](image.png)\n\nThis is more useful than shell script hacks, because KWin script receives event\nnotification and window info from KWin. This can also fix tray-based apps,\nwhich loses blur hints when restored from system tray.\n\n\nSystem Requirement\n------------------\n\n* Operating System:\n  - (K)Ubuntu 18.10 or newer\n  - Fedora 29 or newer\n  - Arch Linux - kwin 5.14 or newer\n\n* Make sure you're using \"Blur\" desktop effect, which can be enabled through System Settings.\n\n* This script internally calls `xprop` command, which would be already installed\n  on your system.\n\n* X11 display server (the script does not support wayland applications)\n\n\nHow to Use\n----------\n\n1. Install the script.\n\n2. Run the following in terminal, to enable script configuration:\n\n        mkdir -p ~/.local/share/kservices5/\n        cp ~/.local/share/kwin/scripts/forceblur/metadata.desktop ~/.local/share/kservices5/forceblur.desktop\n\n3. Open `Kwin Scripts` page in `System Settings`.\n\n4. Enable `Force Blur` script by checking the checkbox next to it.\n\n5. Change script settings. Note that the script can only match with window classes.\n\n6. Click `OK` to enable the script.\n\n7. Whenever settings are changed, you must disable and re-enable the script.  \n   (Uncheck -> `Apply` -> Check -> `Apply`)\n\n\nGTK CSD Shadow\n--------------\n\nSome GTK applications render client-side shadows, which look ugly if blurred. To\nprevent this, you can enable \"**Blur only the content of window**\" option.\n\nThis works by updating the blur region info whenever a window is resized, so\nmight have some performance impacts. Use with caution.\n\n\nAuthors\n-------\n\n* Eon S. Jeon <esjeon@hyunmu.am> - main author\n* Aaron Miller (https://github.com/aaronm-cloudtek) - blacklist mode\n\n"
  },
  {
    "path": "contents/config/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kcfg xmlns=\"http://www.kde.org/standards/kcfg/1.0\"\n      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      xsi:schemaLocation=\"http://www.kde.org/standards/kcfg/1.0\n                          http://www.kde.org/standards/kcfg/1.0/kcfg.xsd\" >\n  <kcfgfile name=\"\"/>\n  <group name=\"\">\n    <entry name=\"patterns\" type=\"String\">\n      <label>Comma-separated list of window classes</label>\n        <default>yakuake\nurxvt\nkeepassxc</default>\n    </entry>\n    <entry name=\"blurMatching\" type=\"Bool\">\n      <default>true</default>\n    </entry>\n    <entry name=\"blurExceptMatching\" type=\"Bool\">\n      <default>false</default>\n    </entry>\n    <entry name=\"blurContent\" type=\"Bool\">\n      <default>false</default>\n    </entry>\n  </group>\n</kcfg>\n"
  },
  {
    "path": "contents/ui/config.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>ForceBlurConfigForm</class>\n <widget class=\"QWidget\" name=\"ForceBlurConfigForm\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>400</height>\n   </rect>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>400</width>\n    <height>350</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n   <item>\n    <widget class=\"QGroupBox\" name=\"groupMatching\">\n     <property name=\"title\">\n      <string>Window Matching</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"layoutMatching\">\n      <item>\n       <widget class=\"QLabel\" name=\"labelMatching\">\n        <property name=\"whatsThis\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;&amp;lt;&amp;lt;Example&amp;gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;yakuake&lt;/p&gt;&lt;p&gt;keepassxc&lt;/p&gt;&lt;p&gt;urxvt&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n        <property name=\"text\">\n         <string notr=\"true\">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter window class names, &lt;span style=&quot; text-decoration: underline;&quot;&gt;one per line&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QPlainTextEdit\" name=\"kcfg_patterns\">\n        <property name=\"toolTip\">\n         <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;\n&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;\np, li { white-space: pre-wrap; }\n&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Fira Sans Book'; font-size:11pt; font-weight:232; font-style:normal;&quot;&gt;\n&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Enter the class names of the windows you want to enable/disable blurring.&lt;/p&gt;\n&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;\n&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Class names can be obtained by using &lt;span style=&quot; font-weight:600;&quot;&gt;xprop&lt;/span&gt; utility in terminal. (xprop WM_CLASS)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"layoutMatchingMode\">\n        <item>\n         <widget class=\"QRadioButton\" name=\"kcfg_blurMatching\">\n          <property name=\"text\">\n           <string>Blur only matching</string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QRadioButton\" name=\"kcfg_blurExceptMatching\">\n          <property name=\"text\">\n           <string>Blur all except matching</string>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"groupOptions\">\n     <property name=\"title\">\n      <string>Options</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n      <item>\n       <widget class=\"QCheckBox\" name=\"kcfg_blurContent\">\n        <property name=\"toolTip\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enabling this option prevents blurring behind the non-content regions of window, like &lt;span style=&quot; font-weight:600;&quot;&gt;CSD shadows in GTK&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;This &lt;span style=&quot; text-decoration: underline;&quot;&gt;might&lt;/span&gt; cause performance issues and flickers, thus users should be careful about turning this on.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n        <property name=\"text\">\n         <string>Blur only the content of window</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n <buttongroups>\n  <buttongroup name=\"matchTypeGroup\"/>\n </buttongroups>\n</ui>\n"
  },
  {
    "path": "contents/ui/main.qml",
    "content": "import QtQuick 2.0\nimport org.kde.plasma.core 2.0 as PlasmaCore;\nimport org.kde.plasma.components 2.0 as Plasma;\nimport org.kde.kwin 2.0;\n\nItem {\n    id: root\n\n    readonly property var patterns: (\n        KWin.readConfig(\"patterns\", \"yakuake\\nurxvt\\nkeepassxc\")\n            .split(\"\\n\")\n            .map(function(rule) {\n                return rule.trim().toLowerCase();\n            })\n    )\n\n    readonly property var blurMatching: (\n        KWin.readConfig(\"blurMatching\", true)\n    )\n\n    readonly property var blurContent: (\n        KWin.readConfig(\"blurContent\", false)\n    )\n\n    PlasmaCore.DataSource {\n        id: shell\n        engine: 'executable'\n\n        connectedSources: []\n\n        function run(cmd) {\n            shell.connectSource(cmd);\n        }\n\n        onNewData: {\n            shell.disconnectSource(sourceName);\n        }\n    }\n\n    function onClientAdded(client) {\n        if (!shell) return;\n\n        var cls = client.resourceClass.toString().toLowerCase();\n        var name = client.resourceName.toString().toLowerCase();\n        var clsMatches = root.patterns.indexOf(cls) >= 0 || root.patterns.indexOf(name) >= 0;\n\n        if (clsMatches == root.blurMatching) {\n            if (root.blurContent) {\n                registerHintUpdater(client);\n            } else {\n                var wid = \"0x\" + client.windowId.toString(16);\n                shell.run(\"xprop -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION 0 -id \" + wid);\n            }\n        }\n    }\n\n    function registerHintUpdater(client) {\n        var prevWidth  = client.geometry.width;\n        var prevHeight = client.geometry.height;\n        var handler = function() {\n            try { if (!root) return; } catch(e) {\n                client.geometryChanged.disconnect(handler);\n                throw e;\n            }\n\n            root.onClientGeometryChanged(client, prevWidth, prevHeight);\n\n            prevWidth  = client.geometry.width;\n            prevHeight = client.geometry.height;\n        }\n\n        client.geometryChanged.connect(handler);\n        root.onClientGeometryChanged(client, 0, 0);\n    }\n\n    function onClientGeometryChanged(client, prevWidth, prevHeight) {\n        if (!shell) return;\n\n        /* Skip if window *size* isn't really changed */\n        if (client.geometry.width === prevWidth && client.geometry.height === prevHeight)\n            return;\n\n        var wid = \"0x\" + client.windowId.toString(16);\n        var region = \"0,0,\" + client.geometry.width + \",\" + client.geometry.height;\n        var cmd = \"xprop -id \" + wid + \" -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION \" + region\n        shell.run(cmd);\n    }\n\n    Component.onCompleted: {\n        console.log(\"FORCE-BLUR: starting the script\");\n        console.log(JSON.stringify(root.patterns));\n\n        var clients = workspace.clientList();\n        for (var i = 0; i < clients.length; i++) {\n            root.onClientAdded(clients[i]);\n        }\n\n        workspace.onClientAdded.connect(root.onClientAdded);\n    }\n}\n"
  },
  {
    "path": "install.sh",
    "content": "#!/bin/sh\nset -euf\n\nif [[ ! -f forceblur.kwinscript ]]; then\n\techo \"Error: can't find package file: $PWD/forceblur.kwinscript\"\n\techo \"Please run 'pack' first\"\n\texit 1\nfi >&2\n\nplasmapkg2 -i forceblur.kwinscript || plasmapkg2 -u forceblur.kwinscript\nmkdir -pv ~/.local/share/kservices5/\ncp -vf metadata.desktop ~/.local/share/kservices5/forceblur.desktop\n\n"
  },
  {
    "path": "metadata.desktop",
    "content": "[Desktop Entry]\nName=Force Blur\nComment=Force-enable Blur effect for certain windows\nIcon=preferences-system-windows-script-test\n\nX-Plasma-API=declarativescript\nX-Plasma-MainScript=ui/main.qml\n\nX-KDE-PluginInfo-Author=Eon S. Jeon\nX-KDE-PluginInfo-Email=esjeon@hyunmu.am\nX-KDE-PluginInfo-Name=forceblur\nX-KDE-PluginInfo-Version=0.6\nX-KDE-PluginInfo-License=MIT\n\nType=Service\nX-KDE-ServiceTypes=KWin/Script\n\nX-KDE-ConfigModule=kwin/effects/configs/kcm_kwin4_genericscripted\n"
  },
  {
    "path": "pack.sh",
    "content": "#!/bin/sh\nset -eu\n\nif ! type zip >&/dev/null; then\n\techo \"Error: Can't find 'zip' command.\"\n\techo \"       Please install 'zip' command first.\"\n\texit 1\nfi >&2\n\nfile=forceblur.kwinscript\nrm -rvf \"$file\"\nexec zip -r9 \"$file\" \\\n\tREADME.md \\\n\tLICENSE \\\n\tmetadata.desktop \\\n\tcontents \\\n"
  }
]